1 /* vi:set ts=8 sts=4 sw=4: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * X command server by Flemming Madsen 5 * 6 * Do ":help uganda" in Vim to read copying and usage conditions. 7 * Do ":help credits" in Vim to see a list of people who contributed. 8 * See README.txt for an overview of the Vim source code. 9 * 10 * if_xcmdsrv.c: Functions for passing commands through an X11 display. 11 * 12 */ 13 14 #include "vim.h" 15 #include "version.h" 16 17 #if defined(FEAT_CLIENTSERVER) || defined(PROTO) 18 19 # ifdef FEAT_X11 20 # include <X11/Intrinsic.h> 21 # include <X11/Xatom.h> 22 # endif 23 24 # if defined(HAVE_SYS_SELECT_H) && \ 25 (!defined(HAVE_SYS_TIME_H) || defined(SYS_SELECT_WITH_SYS_TIME)) 26 # include <sys/select.h> 27 # endif 28 29 # ifndef HAVE_SELECT 30 # ifdef HAVE_SYS_POLL_H 31 # include <sys/poll.h> 32 # else 33 # ifdef HAVE_POLL_H 34 # include <poll.h> 35 # endif 36 # endif 37 # endif 38 39 /* 40 * This file provides procedures that implement the command server functionality 41 * of Vim when in contact with an X11 server. 42 * 43 * Adapted from TCL/TK's send command in tkSend.c of the tk 3.6 distribution. 44 * Adapted for use in Vim by Flemming Madsen. Protocol changed to that of tk 4 45 */ 46 47 /* 48 * Copyright (c) 1989-1993 The Regents of the University of California. 49 * All rights reserved. 50 * 51 * Permission is hereby granted, without written agreement and without 52 * license or royalty fees, to use, copy, modify, and distribute this 53 * software and its documentation for any purpose, provided that the 54 * above copyright notice and the following two paragraphs appear in 55 * all copies of this software. 56 * 57 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR 58 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT 59 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF 60 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 61 * 62 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 63 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 64 * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 65 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO 66 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 67 */ 68 69 70 /* 71 * When a result is being awaited from a sent command, one of 72 * the following structures is present on a list of all outstanding 73 * sent commands. The information in the structure is used to 74 * process the result when it arrives. You're probably wondering 75 * how there could ever be multiple outstanding sent commands. 76 * This could happen if Vim instances invoke each other recursively. 77 * It's unlikely, but possible. 78 */ 79 80 typedef struct PendingCommand 81 { 82 int serial; /* Serial number expected in result. */ 83 int code; /* Result Code. 0 is OK */ 84 char_u *result; /* String result for command (malloc'ed). 85 * NULL means command still pending. */ 86 struct PendingCommand *nextPtr; 87 /* Next in list of all outstanding commands. 88 * NULL means end of list. */ 89 } PendingCommand; 90 91 static PendingCommand *pendingCommands = NULL; 92 /* List of all commands currently 93 * being waited for. */ 94 95 /* 96 * The information below is used for communication between processes 97 * during "send" commands. Each process keeps a private window, never 98 * even mapped, with one property, "Comm". When a command is sent to 99 * an interpreter, the command is appended to the comm property of the 100 * communication window associated with the interp's process. Similarly, 101 * when a result is returned from a sent command, it is also appended 102 * to the comm property. 103 * 104 * Each command and each result takes the form of ASCII text. For a 105 * command, the text consists of a nul character followed by several 106 * nul-terminated ASCII strings. The first string consists of the 107 * single letter "c" for an expression, or "k" for keystrokes. Subsequent 108 * strings have the form "option value" where the following options are 109 * supported: 110 * 111 * -r commWindow serial 112 * 113 * This option means that a response should be sent to the window 114 * whose X identifier is "commWindow" (in hex), and the response should 115 * be identified with the serial number given by "serial" (in decimal). 116 * If this option isn't specified then the send is asynchronous and 117 * no response is sent. 118 * 119 * -n name 120 * "Name" gives the name of the application for which the command is 121 * intended. This option must be present. 122 * 123 * -s script 124 * "Script" is the script to be executed. This option must be 125 * present. Taken as a series of keystrokes in a "k" command where 126 * <Key>'s are expanded 127 * 128 * The options may appear in any order. The -n and -s options must be 129 * present, but -r may be omitted for asynchronous RPCs. For compatibility 130 * with future releases that may add new features, there may be additional 131 * options present; as long as they start with a "-" character, they will 132 * be ignored. 133 * 134 * A result also consists of a zero character followed by several null- 135 * terminated ASCII strings. The first string consists of the single 136 * letter "r". Subsequent strings have the form "option value" where 137 * the following options are supported: 138 * 139 * -s serial 140 * Identifies the command for which this is the result. It is the 141 * same as the "serial" field from the -s option in the command. This 142 * option must be present. 143 * 144 * -r result 145 * "Result" is the result string for the script, which may be either 146 * a result or an error message. If this field is omitted then it 147 * defaults to an empty string. 148 * 149 * -c code 150 * 0: for OK. This is the default. 151 * 1: for error: Result is the last error 152 * 153 * -i errorInfo 154 * -e errorCode 155 * Not applicable for Vim 156 * 157 * Options may appear in any order, and only the -s option must be 158 * present. As with commands, there may be additional options besides 159 * these; unknown options are ignored. 160 */ 161 162 /* 163 * Maximum size property that can be read at one time by 164 * this module: 165 */ 166 167 #define MAX_PROP_WORDS 100000 168 169 struct ServerReply 170 { 171 Window id; 172 garray_T strings; 173 }; 174 static garray_T serverReply = { 0, 0, 0, 0, 0 }; 175 enum ServerReplyOp { SROP_Find, SROP_Add, SROP_Delete }; 176 177 typedef int (*EndCond) __ARGS((void *)); 178 179 /* 180 * Forward declarations for procedures defined later in this file: 181 */ 182 183 static Window LookupName __ARGS((Display *dpy, char_u *name, int delete, char_u **loose)); 184 static int SendInit __ARGS((Display *dpy)); 185 static int DoRegisterName __ARGS((Display *dpy, char_u *name)); 186 static void DeleteAnyLingerer __ARGS((Display *dpy, Window w)); 187 static int GetRegProp __ARGS((Display *dpy, char_u **regPropp, long_u *numItemsp, int domsg)); 188 static int WaitForPend __ARGS((void *p)); 189 static int WaitForReply __ARGS((void *p)); 190 static int WindowValid __ARGS((Display *dpy, Window w)); 191 static void ServerWait __ARGS((Display *dpy, Window w, EndCond endCond, void *endData, int localLoop, int seconds)); 192 static struct ServerReply *ServerReplyFind __ARGS((Window w, enum ServerReplyOp op)); 193 static int AppendPropCarefully __ARGS((Display *display, Window window, Atom property, char_u *value, int length)); 194 static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event)); 195 static int IsSerialName __ARGS((char_u *name)); 196 197 /* Private variables for the "server" functionality */ 198 static Atom registryProperty = None; 199 static Atom vimProperty = None; 200 static int got_x_error = FALSE; 201 202 static char_u *empty_prop = (char_u *)""; /* empty GetRegProp() result */ 203 204 /* 205 * Associate an ASCII name with Vim. Try real hard to get a unique one. 206 * Returns FAIL or OK. 207 */ 208 int 209 serverRegisterName(dpy, name) 210 Display *dpy; /* display to register with */ 211 char_u *name; /* the name that will be used as a base */ 212 { 213 int i; 214 int res; 215 char_u *p = NULL; 216 217 res = DoRegisterName(dpy, name); 218 if (res < 0) 219 { 220 i = 1; 221 do 222 { 223 if (res < -1 || i >= 1000) 224 { 225 MSG_ATTR(_("Unable to register a command server name"), 226 hl_attr(HLF_W)); 227 return FAIL; 228 } 229 if (p == NULL) 230 p = alloc(STRLEN(name) + 10); 231 if (p == NULL) 232 { 233 res = -10; 234 continue; 235 } 236 sprintf((char *)p, "%s%d", name, i++); 237 res = DoRegisterName(dpy, p); 238 } 239 while (res < 0) 240 ; 241 vim_free(p); 242 } 243 return OK; 244 } 245 246 static int 247 DoRegisterName(dpy, name) 248 Display *dpy; 249 char_u *name; 250 { 251 Window w; 252 XErrorHandler old_handler; 253 #define MAX_NAME_LENGTH 100 254 char_u propInfo[MAX_NAME_LENGTH + 20]; 255 256 if (commProperty == None) 257 { 258 if (SendInit(dpy) < 0) 259 return -2; 260 } 261 262 /* 263 * Make sure the name is unique, and append info about it to 264 * the registry property. It's important to lock the server 265 * here to prevent conflicting changes to the registry property. 266 * WARNING: Do not step through this while debugging, it will hangup the X 267 * server! 268 */ 269 XGrabServer(dpy); 270 w = LookupName(dpy, name, FALSE, NULL); 271 if (w != (Window)0) 272 { 273 Status status; 274 int dummyInt; 275 unsigned int dummyUns; 276 Window dummyWin; 277 278 /* 279 * The name is currently registered. See if the commWindow 280 * associated with the name exists. If not, or if the commWindow 281 * is *our* commWindow, then just unregister the old name (this 282 * could happen if an application dies without cleaning up the 283 * registry). 284 */ 285 old_handler = XSetErrorHandler(x_error_check); 286 status = XGetGeometry(dpy, w, &dummyWin, &dummyInt, &dummyInt, 287 &dummyUns, &dummyUns, &dummyUns, &dummyUns); 288 (void)XSetErrorHandler(old_handler); 289 if (status != Success && w != commWindow) 290 { 291 XUngrabServer(dpy); 292 XFlush(dpy); 293 return -1; 294 } 295 (void)LookupName(dpy, name, /*delete=*/TRUE, NULL); 296 } 297 sprintf((char *)propInfo, "%x %.*s", (int_u)commWindow, 298 MAX_NAME_LENGTH, name); 299 old_handler = XSetErrorHandler(x_error_check); 300 got_x_error = FALSE; 301 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8, 302 PropModeAppend, propInfo, STRLEN(propInfo) + 1); 303 XUngrabServer(dpy); 304 XSync(dpy, False); 305 (void)XSetErrorHandler(old_handler); 306 307 if (!got_x_error) 308 { 309 #ifdef FEAT_EVAL 310 set_vim_var_string(VV_SEND_SERVER, name, -1); 311 #endif 312 serverName = vim_strsave(name); 313 #ifdef FEAT_TITLE 314 need_maketitle = TRUE; 315 #endif 316 return 0; 317 } 318 return -2; 319 } 320 321 #if defined(FEAT_GUI) || defined(PROTO) 322 /* 323 * Clean out new ID from registry and set it as comm win. 324 * Change any registered window ID. 325 */ 326 void 327 serverChangeRegisteredWindow(dpy, newwin) 328 Display *dpy; /* Display to register with */ 329 Window newwin; /* Re-register to this ID */ 330 { 331 char_u propInfo[MAX_NAME_LENGTH + 20]; 332 333 commWindow = newwin; 334 335 /* Always call SendInit() here, to make sure commWindow is marked as a Vim 336 * window. */ 337 if (SendInit(dpy) < 0) 338 return; 339 340 /* WARNING: Do not step through this while debugging, it will hangup the X 341 * server! */ 342 XGrabServer(dpy); 343 DeleteAnyLingerer(dpy, newwin); 344 if (serverName != NULL) 345 { 346 /* Reinsert name if we was already registered */ 347 (void)LookupName(dpy, serverName, /*delete=*/TRUE, NULL); 348 sprintf((char *)propInfo, "%x %.*s", 349 (int_u)newwin, MAX_NAME_LENGTH, serverName); 350 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 8, 351 PropModeAppend, (char_u *)propInfo, 352 STRLEN(propInfo) + 1); 353 } 354 XUngrabServer(dpy); 355 } 356 #endif 357 358 /* 359 * Send to an instance of Vim via the X display. 360 * Returns 0 for OK, negative for an error. 361 */ 362 int 363 serverSendToVim(dpy, name, cmd, result, server, asExpr, localLoop, silent) 364 Display *dpy; /* Where to send. */ 365 char_u *name; /* Where to send. */ 366 char_u *cmd; /* What to send. */ 367 char_u **result; /* Result of eval'ed expression */ 368 Window *server; /* Actual ID of receiving app */ 369 Bool asExpr; /* Interpret as keystrokes or expr ? */ 370 Bool localLoop; /* Throw away everything but result */ 371 int silent; /* don't complain about no server */ 372 { 373 Window w; 374 char_u *property; 375 int length; 376 int res; 377 static int serial = 0; /* Running count of sent commands. 378 * Used to give each command a 379 * different serial number. */ 380 PendingCommand pending; 381 char_u *loosename = NULL; 382 383 if (result != NULL) 384 *result = NULL; 385 if (name == NULL || *name == NUL) 386 name = (char_u *)"GVIM"; /* use a default name */ 387 388 if (commProperty == None && dpy != NULL) 389 { 390 if (SendInit(dpy) < 0) 391 return -1; 392 } 393 394 /* Execute locally if no display or target is ourselves */ 395 if (dpy == NULL || (serverName != NULL && STRICMP(name, serverName) == 0)) 396 { 397 if (asExpr) 398 { 399 char_u *ret; 400 401 ret = eval_client_expr_to_string(cmd); 402 if (result != NULL) 403 { 404 if (ret == NULL) 405 *result = vim_strsave((char_u *)_(e_invexprmsg)); 406 else 407 *result = ret; 408 } 409 else 410 vim_free(ret); 411 return ret == NULL ? -1 : 0; 412 } 413 else 414 server_to_input_buf(cmd); 415 return 0; 416 } 417 418 /* 419 * Bind the server name to a communication window. 420 * 421 * Find any survivor with a serialno attached to the name if the 422 * original registrant of the wanted name is no longer present. 423 * 424 * Delete any lingering names from dead editors. 425 */ 426 while (TRUE) 427 { 428 w = LookupName(dpy, name, FALSE, &loosename); 429 /* Check that the window is hot */ 430 if (w != None) 431 { 432 if (!WindowValid(dpy, w)) 433 { 434 LookupName(dpy, loosename ? loosename : name, 435 /*DELETE=*/TRUE, NULL); 436 continue; 437 } 438 } 439 break; 440 } 441 if (w == None) 442 { 443 if (!silent) 444 EMSG2(_(e_noserver), name); 445 return -1; 446 } 447 else if (loosename != NULL) 448 name = loosename; 449 if (server != NULL) 450 *server = w; 451 452 /* 453 * Send the command to target interpreter by appending it to the 454 * comm window in the communication window. 455 */ 456 length = STRLEN(name) + STRLEN(cmd) + 10; 457 property = (char_u *)alloc((unsigned) length + 30); 458 459 sprintf((char *)property, "%c%c%c-n %s%c-s %s", 460 0, asExpr ? 'c' : 'k', 0, name, 0, cmd); 461 if (name == loosename) 462 vim_free(loosename); 463 /* Add a back reference to our comm window */ 464 serial++; 465 sprintf((char *)property + length, "%c-r %x %d", 466 0, (int_u)commWindow, serial); 467 length += STRLEN(property + length + 1) + 1; 468 469 res = AppendPropCarefully(dpy, w, commProperty, property, length + 1); 470 vim_free(property); 471 if (res < 0) 472 { 473 EMSG(_("E248: Failed to send command to the destination program")); 474 return -1; 475 } 476 477 if (!asExpr) /* There is no answer for this - Keys are sent async */ 478 return 0; 479 480 /* 481 * Register the fact that we're waiting for a command to 482 * complete (this is needed by SendEventProc and by 483 * AppendErrorProc to pass back the command's results). 484 */ 485 pending.serial = serial; 486 pending.code = 0; 487 pending.result = NULL; 488 pending.nextPtr = pendingCommands; 489 pendingCommands = &pending; 490 491 ServerWait(dpy, w, WaitForPend, &pending, localLoop, 600); 492 493 /* 494 * Unregister the information about the pending command 495 * and return the result. 496 */ 497 if (pendingCommands == &pending) 498 pendingCommands = pending.nextPtr; 499 else 500 { 501 PendingCommand *pcPtr; 502 503 for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) 504 if (pcPtr->nextPtr == &pending) 505 { 506 pcPtr->nextPtr = pending.nextPtr; 507 break; 508 } 509 } 510 if (result != NULL) 511 *result = pending.result; 512 else 513 vim_free(pending.result); 514 515 return pending.code == 0 ? 0 : -1; 516 } 517 518 static int 519 WaitForPend(p) 520 void *p; 521 { 522 PendingCommand *pending = (PendingCommand *) p; 523 return pending->result != NULL; 524 } 525 526 /* 527 * Return TRUE if window "w" exists and has a "Vim" property on it. 528 */ 529 static int 530 WindowValid(dpy, w) 531 Display *dpy; 532 Window w; 533 { 534 XErrorHandler old_handler; 535 Atom *plist; 536 int numProp; 537 int i; 538 539 old_handler = XSetErrorHandler(x_error_check); 540 got_x_error = 0; 541 plist = XListProperties(dpy, w, &numProp); 542 XSync(dpy, False); 543 XSetErrorHandler(old_handler); 544 if (plist == NULL || got_x_error) 545 return FALSE; 546 547 for (i = 0; i < numProp; i++) 548 if (plist[i] == vimProperty) 549 { 550 XFree(plist); 551 return TRUE; 552 } 553 XFree(plist); 554 return FALSE; 555 } 556 557 /* 558 * Enter a loop processing X events & polling chars until we see a result 559 */ 560 static void 561 ServerWait(dpy, w, endCond, endData, localLoop, seconds) 562 Display *dpy; 563 Window w; 564 EndCond endCond; 565 void *endData; 566 int localLoop; 567 int seconds; 568 { 569 time_t start; 570 time_t now; 571 time_t lastChk = 0; 572 XEvent event; 573 XPropertyEvent *e = (XPropertyEvent *)&event; 574 # define SEND_MSEC_POLL 50 575 576 time(&start); 577 while (endCond(endData) == 0) 578 { 579 time(&now); 580 if (seconds >= 0 && (now - start) >= seconds) 581 break; 582 if (now != lastChk) 583 { 584 lastChk = now; 585 if (!WindowValid(dpy, w)) 586 break; 587 /* 588 * Sometimes the PropertyChange event doesn't come. 589 * This can be seen in eg: vim -c 'echo remote_expr("gvim", "3+2")' 590 */ 591 serverEventProc(dpy, NULL); 592 } 593 if (localLoop) 594 { 595 /* Just look out for the answer without calling back into Vim */ 596 #ifndef HAVE_SELECT 597 struct pollfd fds; 598 599 fds.fd = ConnectionNumber(dpy); 600 fds.events = POLLIN; 601 if (poll(&fds, 1, SEND_MSEC_POLL) < 0) 602 break; 603 #else 604 fd_set fds; 605 struct timeval tv; 606 607 tv.tv_sec = 0; 608 tv.tv_usec = SEND_MSEC_POLL * 1000; 609 FD_ZERO(&fds); 610 FD_SET(ConnectionNumber(dpy), &fds); 611 if (select(ConnectionNumber(dpy) + 1, &fds, NULL, NULL, &tv) < 0) 612 break; 613 #endif 614 while (XEventsQueued(dpy, QueuedAfterReading) > 0) 615 { 616 XNextEvent(dpy, &event); 617 if (event.type == PropertyNotify && e->window == commWindow) 618 serverEventProc(dpy, &event); 619 } 620 } 621 else 622 { 623 if (got_int) 624 break; 625 ui_delay((long)SEND_MSEC_POLL, TRUE); 626 ui_breakcheck(); 627 } 628 } 629 } 630 631 632 /* 633 * Fetch a list of all the Vim instance names currently registered for the 634 * display. 635 * 636 * Returns a newline separated list in allocated memory or NULL. 637 */ 638 char_u * 639 serverGetVimNames(dpy) 640 Display *dpy; 641 { 642 char_u *regProp; 643 char_u *entry; 644 char_u *p; 645 long_u numItems; 646 int_u w; 647 garray_T ga; 648 649 if (registryProperty == None) 650 { 651 if (SendInit(dpy) < 0) 652 return NULL; 653 } 654 ga_init2(&ga, 1, 100); 655 656 /* 657 * Read the registry property. 658 */ 659 if (GetRegProp(dpy, ®Prop, &numItems, TRUE) == FAIL) 660 return NULL; 661 662 /* 663 * Scan all of the names out of the property. 664 */ 665 ga_init2(&ga, 1, 100); 666 for (p = regProp; (p - regProp) < numItems; p++) 667 { 668 entry = p; 669 while (*p != 0 && !isspace(*p)) 670 p++; 671 if (*p != 0) 672 { 673 w = None; 674 sscanf((char *)entry, "%x", &w); 675 if (WindowValid(dpy, (Window)w)) 676 { 677 ga_concat(&ga, p + 1); 678 ga_concat(&ga, (char_u *)"\n"); 679 } 680 while (*p != 0) 681 p++; 682 } 683 } 684 if (regProp != empty_prop) 685 XFree(regProp); 686 ga_append(&ga, NUL); 687 return ga.ga_data; 688 } 689 690 /* ---------------------------------------------------------- 691 * Reply stuff 692 */ 693 694 static struct ServerReply * 695 ServerReplyFind(w, op) 696 Window w; 697 enum ServerReplyOp op; 698 { 699 struct ServerReply *p; 700 struct ServerReply e; 701 int i; 702 703 p = (struct ServerReply *) serverReply.ga_data; 704 for (i = 0; i < serverReply.ga_len; i++, p++) 705 if (p->id == w) 706 break; 707 if (i >= serverReply.ga_len) 708 p = NULL; 709 710 if (p == NULL && op == SROP_Add) 711 { 712 if (serverReply.ga_growsize == 0) 713 ga_init2(&serverReply, sizeof(struct ServerReply), 1); 714 if (ga_grow(&serverReply, 1) == OK) 715 { 716 p = ((struct ServerReply *) serverReply.ga_data) 717 + serverReply.ga_len; 718 e.id = w; 719 ga_init2(&e.strings, 1, 100); 720 memcpy(p, &e, sizeof(e)); 721 serverReply.ga_len++; 722 serverReply.ga_room--; 723 } 724 } 725 else if (p != NULL && op == SROP_Delete) 726 { 727 ga_clear(&p->strings); 728 mch_memmove(p, p + 1, (serverReply.ga_len - i - 1) * sizeof(*p)); 729 serverReply.ga_len--; 730 serverReply.ga_room++; 731 } 732 733 return p; 734 } 735 736 /* 737 * Convert string to windowid. 738 * Issue an error if the id is invalid. 739 */ 740 Window 741 serverStrToWin(str) 742 char_u *str; 743 { 744 unsigned id = None; 745 746 sscanf((char *)str, "0x%x", &id); 747 if (id == None) 748 EMSG2(_("E573: Invalid server id used: %s"), str); 749 750 return (Window)id; 751 } 752 753 /* 754 * Send a reply string to client with id "name". 755 * Return -1 if the window is invalid. 756 */ 757 int 758 serverSendReply(name, str) 759 char_u *name; 760 char_u *str; 761 { 762 char_u *property; 763 int length; 764 int res; 765 Display *dpy = X_DISPLAY; 766 Window win = serverStrToWin(name); 767 768 if (commProperty == None) 769 { 770 if (SendInit(dpy) < 0) 771 return -2; 772 } 773 if (!WindowValid(dpy, win)) 774 return -1; 775 776 length = STRLEN(str) + 7; 777 if ((property = (char_u *)alloc((unsigned) length + 30)) != NULL) 778 { 779 sprintf((char *)property, "%c%c%c-n %s%c-w %x", 780 0, 'n', 0, str, 0, (unsigned int)commWindow); 781 length += STRLEN(property + length); 782 res = AppendPropCarefully(dpy, win, commProperty, property, length + 1); 783 vim_free(property); 784 return res; 785 } 786 return -1; 787 } 788 789 static int 790 WaitForReply(p) 791 void *p; 792 { 793 Window *w = (Window *) p; 794 return ServerReplyFind(*w, SROP_Find) != NULL; 795 } 796 797 /* 798 * Wait for replies from id (win) 799 * Return 0 and the malloc'ed string when a reply is available. 800 * Return -1 if the window becomes invalid while waiting. 801 */ 802 int 803 serverReadReply(dpy, win, str, localLoop) 804 Display *dpy; 805 Window win; 806 char_u **str; 807 int localLoop; 808 { 809 int len; 810 char_u *s; 811 struct ServerReply *p; 812 813 ServerWait(dpy, win, WaitForReply, &win, localLoop, -1); 814 815 if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0) 816 { 817 *str = vim_strsave(p->strings.ga_data); 818 len = STRLEN(*str) + 1; 819 if (len < p->strings.ga_len) 820 { 821 s = (char_u *) p->strings.ga_data; 822 mch_memmove(s, s + len, p->strings.ga_len - len); 823 p->strings.ga_room += len; 824 p->strings.ga_len -= len; 825 } 826 else 827 { 828 /* Last string read. Remove from list */ 829 ga_clear(&p->strings); 830 ServerReplyFind(win, SROP_Delete); 831 } 832 return 0; 833 } 834 return -1; 835 } 836 837 /* 838 * Check for replies from id (win). 839 * Return TRUE and a non-malloc'ed string if there is. Else return FALSE. 840 */ 841 int 842 serverPeekReply(dpy, win, str) 843 Display *dpy; 844 Window win; 845 char_u **str; 846 { 847 struct ServerReply *p; 848 849 if ((p = ServerReplyFind(win, SROP_Find)) != NULL && p->strings.ga_len > 0) 850 { 851 if (str != NULL) 852 *str = p->strings.ga_data; 853 return 1; 854 } 855 if (!WindowValid(dpy, win)) 856 return -1; 857 return 0; 858 } 859 860 861 /* 862 * Initialize the communication channels for sending commands and receiving 863 * results. 864 */ 865 static int 866 SendInit(dpy) 867 Display *dpy; 868 { 869 XErrorHandler old_handler; 870 871 /* 872 * Create the window used for communication, and set up an 873 * event handler for it. 874 */ 875 old_handler = XSetErrorHandler(x_error_check); 876 got_x_error = FALSE; 877 878 if (commProperty == None) 879 commProperty = XInternAtom(dpy, "Comm", False); 880 if (vimProperty == None) 881 vimProperty = XInternAtom(dpy, "Vim", False); 882 if (registryProperty == None) 883 registryProperty = XInternAtom(dpy, "VimRegistry", False); 884 885 if (commWindow == None) 886 { 887 commWindow = XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), 888 getpid(), 0, 10, 10, 0, 889 WhitePixel(dpy, DefaultScreen(dpy)), 890 WhitePixel(dpy, DefaultScreen(dpy))); 891 XSelectInput(dpy, commWindow, PropertyChangeMask); 892 /* WARNING: Do not step through this while debugging, it will hangup 893 * the X server! */ 894 XGrabServer(dpy); 895 DeleteAnyLingerer(dpy, commWindow); 896 XUngrabServer(dpy); 897 } 898 899 /* Make window recognizable as a vim window */ 900 XChangeProperty(dpy, commWindow, vimProperty, XA_STRING, 901 8, PropModeReplace, (char_u *)VIM_VERSION_SHORT, 902 (int)STRLEN(VIM_VERSION_SHORT) + 1); 903 904 XSync(dpy, False); 905 (void)XSetErrorHandler(old_handler); 906 907 return got_x_error ? -1 : 0; 908 } 909 910 /* 911 * Given a server name, see if the name exists in the registry for a 912 * particular display. 913 * 914 * If the given name is registered, return the ID of the window associated 915 * with the name. If the name isn't registered, then return 0. 916 * 917 * Side effects: 918 * If the registry property is improperly formed, then it is deleted. 919 * If "delete" is non-zero, then if the named server is found it is 920 * removed from the registry property. 921 */ 922 static Window 923 LookupName(dpy, name, delete, loose) 924 Display *dpy; /* Display whose registry to check. */ 925 char_u *name; /* Name of a server. */ 926 int delete; /* If non-zero, delete info about name. */ 927 char_u **loose; /* Do another search matching -999 if not found 928 Return result here if a match is found */ 929 { 930 char_u *regProp, *entry; 931 char_u *p; 932 long_u numItems; 933 int_u returnValue; 934 935 /* 936 * Read the registry property. 937 */ 938 if (GetRegProp(dpy, ®Prop, &numItems, FALSE) == FAIL) 939 return 0; 940 941 /* 942 * Scan the property for the desired name. 943 */ 944 returnValue = (int_u)None; 945 entry = NULL; /* Not needed, but eliminates compiler warning. */ 946 for (p = regProp; (p - regProp) < numItems; ) 947 { 948 entry = p; 949 while (*p != 0 && !isspace(*p)) 950 p++; 951 if (*p != 0 && STRICMP(name, p + 1) == 0) 952 { 953 sscanf((char *)entry, "%x", &returnValue); 954 break; 955 } 956 while (*p != 0) 957 p++; 958 p++; 959 } 960 961 if (loose != NULL && returnValue == (int_u)None && !IsSerialName(name)) 962 { 963 for (p = regProp; (p - regProp) < numItems; ) 964 { 965 entry = p; 966 while (*p != 0 && !isspace(*p)) 967 p++; 968 if (*p != 0 && IsSerialName(p + 1) 969 && STRNICMP(name, p + 1, STRLEN(name)) == 0) 970 { 971 sscanf((char *)entry, "%x", &returnValue); 972 *loose = vim_strsave(p + 1); 973 break; 974 } 975 while (*p != 0) 976 p++; 977 p++; 978 } 979 } 980 981 /* 982 * Delete the property, if that is desired (copy down the 983 * remainder of the registry property to overlay the deleted 984 * info, then rewrite the property). 985 */ 986 if (delete && returnValue != (int_u)None) 987 { 988 int count; 989 990 while (*p != 0) 991 p++; 992 p++; 993 count = numItems - (p - regProp); 994 if (count > 0) 995 memcpy(entry, p, count); 996 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, 997 8, PropModeReplace, regProp, 998 (int)(numItems - (p - entry))); 999 XSync(dpy, False); 1000 } 1001 1002 if (regProp != empty_prop) 1003 XFree(regProp); 1004 return (Window)returnValue; 1005 } 1006 1007 /* 1008 * Delete any lingering occurences of window id. We promise that any 1009 * occurences is not ours since it is not yet put into the registry (by us) 1010 * 1011 * This is necessary in the following scenario: 1012 * 1. There is an old windowid for an exit'ed vim in the registry 1013 * 2. We get that id for our commWindow but only want to send, not register. 1014 * 3. The window will mistakenly be regarded valid because of own commWindow 1015 */ 1016 static void 1017 DeleteAnyLingerer(dpy, win) 1018 Display *dpy; /* Display whose registry to check. */ 1019 Window win; /* Window to remove */ 1020 { 1021 char_u *regProp, *entry = NULL; 1022 char_u *p; 1023 long_u numItems; 1024 Window wwin; 1025 1026 /* 1027 * Read the registry property. 1028 */ 1029 if (GetRegProp(dpy, ®Prop, &numItems, FALSE) == FAIL) 1030 return; 1031 1032 /* Scan the property for the window id. */ 1033 for (p = regProp; (p - regProp) < numItems; ) 1034 { 1035 if (*p != 0) 1036 { 1037 sscanf((char *)p, "%x", (int_u *)&wwin); 1038 if (wwin == win) 1039 { 1040 int lastHalf; 1041 1042 /* Copy down the remainder to delete entry */ 1043 entry = p; 1044 while (*p != 0) 1045 p++; 1046 p++; 1047 lastHalf = numItems - (p - regProp); 1048 if (lastHalf > 0) 1049 memcpy(entry, p, lastHalf); 1050 numItems = (entry - regProp) + lastHalf; 1051 p = entry; 1052 continue; 1053 } 1054 } 1055 while (*p != 0) 1056 p++; 1057 p++; 1058 } 1059 1060 if (entry != NULL) 1061 { 1062 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, 1063 XA_STRING, 8, PropModeReplace, regProp, 1064 (int)(p - regProp)); 1065 XSync(dpy, False); 1066 } 1067 1068 if (regProp != empty_prop) 1069 XFree(regProp); 1070 } 1071 1072 /* 1073 * Read the registry property. Delete it when it's formatted wrong. 1074 * Return the property in "regPropp". "empty_prop" is used when it doesn't 1075 * exist yet. 1076 * Return OK when successful. 1077 */ 1078 static int 1079 GetRegProp(dpy, regPropp, numItemsp, domsg) 1080 Display *dpy; 1081 char_u **regPropp; 1082 long_u *numItemsp; 1083 int domsg; /* When TRUE give error message. */ 1084 { 1085 int result, actualFormat; 1086 long_u bytesAfter; 1087 Atom actualType; 1088 1089 *regPropp = NULL; 1090 result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0L, 1091 (long)MAX_PROP_WORDS, False, 1092 XA_STRING, &actualType, 1093 &actualFormat, numItemsp, &bytesAfter, 1094 regPropp); 1095 1096 if (actualType == None) 1097 { 1098 /* No prop yet. Logically equal to the empty list */ 1099 *numItemsp = 0; 1100 *regPropp = empty_prop; 1101 return OK; 1102 } 1103 1104 /* If the property is improperly formed, then delete it. */ 1105 if (result != Success || actualFormat != 8 || actualType != XA_STRING) 1106 { 1107 if (*regPropp != NULL) 1108 XFree(*regPropp); 1109 XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty); 1110 if (domsg) 1111 EMSG(_("E251: VIM instance registry property is badly formed. Deleted!")); 1112 return FAIL; 1113 } 1114 return OK; 1115 } 1116 1117 /* 1118 * This procedure is invoked by the varous X event loops throughout Vims when 1119 * a property changes on the communication window. This procedure reads the 1120 * property and handles command requests and responses. 1121 */ 1122 void 1123 serverEventProc(dpy, eventPtr) 1124 Display *dpy; 1125 XEvent *eventPtr; /* Information about event. */ 1126 { 1127 char_u *propInfo; 1128 char_u *p; 1129 int result, actualFormat, code; 1130 long_u numItems, bytesAfter; 1131 Atom actualType; 1132 1133 if (eventPtr != NULL) 1134 { 1135 if (eventPtr->xproperty.atom != commProperty 1136 || eventPtr->xproperty.state != PropertyNewValue) 1137 return; 1138 } 1139 1140 /* 1141 * Read the comm property and delete it. 1142 */ 1143 propInfo = NULL; 1144 result = XGetWindowProperty(dpy, commWindow, commProperty, 0L, 1145 (long)MAX_PROP_WORDS, True, 1146 XA_STRING, &actualType, 1147 &actualFormat, &numItems, &bytesAfter, 1148 &propInfo); 1149 1150 /* If the property doesn't exist or is improperly formed then ignore it. */ 1151 if (result != Success || actualType != XA_STRING || actualFormat != 8) 1152 { 1153 if (propInfo != NULL) 1154 XFree(propInfo); 1155 return; 1156 } 1157 1158 /* 1159 * Several commands and results could arrive in the property at 1160 * one time; each iteration through the outer loop handles a 1161 * single command or result. 1162 */ 1163 for (p = propInfo; (p - propInfo) < numItems; ) 1164 { 1165 /* 1166 * Ignore leading NULs; each command or result starts with a 1167 * NUL so that no matter how badly formed a preceding command 1168 * is, we'll be able to tell that a new command/result is 1169 * starting. 1170 */ 1171 if (*p == 0) 1172 { 1173 p++; 1174 continue; 1175 } 1176 1177 if ((*p == 'c' || *p == 'k') && (p[1] == 0)) 1178 { 1179 Window resWindow; 1180 char_u *name, *script, *serial, *end, *res; 1181 Bool asKeys = *p == 'k'; 1182 garray_T reply; 1183 1184 /* 1185 * This is an incoming command from some other application. 1186 * Iterate over all of its options. Stop when we reach 1187 * the end of the property or something that doesn't look 1188 * like an option. 1189 */ 1190 p += 2; 1191 name = NULL; 1192 resWindow = None; 1193 serial = (char_u *)""; 1194 script = NULL; 1195 while (p - propInfo < numItems && *p == '-') 1196 { 1197 switch (p[1]) 1198 { 1199 case 'r': 1200 end = skipwhite(p + 2); 1201 resWindow = 0; 1202 while (vim_isxdigit(*end)) 1203 { 1204 resWindow = 16 * resWindow + (long_u)hex2nr(*end); 1205 ++end; 1206 } 1207 if (end == p + 2 || *end != ' ') 1208 resWindow = None; 1209 else 1210 { 1211 p = serial = end + 1; 1212 clientWindow = resWindow; /* Remember in global */ 1213 } 1214 break; 1215 case 'n': 1216 if (p[2] == ' ') 1217 name = p + 3; 1218 break; 1219 case 's': 1220 if (p[2] == ' ') 1221 script = p + 3; 1222 break; 1223 } 1224 while (*p != 0) 1225 p++; 1226 p++; 1227 } 1228 1229 if (script == NULL || name == NULL) 1230 continue; 1231 1232 /* 1233 * Initialize the result property, so that we're ready at any 1234 * time if we need to return an error. 1235 */ 1236 if (resWindow != None) 1237 { 1238 ga_init2(&reply, 1, 100); 1239 ga_grow(&reply, 50); 1240 sprintf(reply.ga_data, "%cr%c-s %s%c-r ", 0, 0, serial, 0); 1241 reply.ga_len = 10 + STRLEN(serial); 1242 reply.ga_room -= reply.ga_len; 1243 } 1244 res = NULL; 1245 if (serverName != NULL && STRICMP(name, serverName) == 0) 1246 { 1247 if (asKeys) 1248 server_to_input_buf(script); 1249 else 1250 res = eval_client_expr_to_string(script); 1251 } 1252 if (resWindow != None) 1253 { 1254 if (res != NULL) 1255 ga_concat(&reply, res); 1256 else if (asKeys == 0) 1257 { 1258 ga_concat(&reply, (char_u *)_(e_invexprmsg)); 1259 ga_append(&reply, 0); 1260 ga_concat(&reply, (char_u *)"-c 1"); 1261 } 1262 ga_append(&reply, NUL); 1263 (void)AppendPropCarefully(dpy, resWindow, commProperty, 1264 reply.ga_data, reply.ga_len); 1265 } 1266 vim_free(res); 1267 } 1268 else if (*p == 'r' && p[1] == 0) 1269 { 1270 int serial, gotSerial; 1271 char_u *res; 1272 PendingCommand *pcPtr; 1273 1274 /* 1275 * This is a reply to some command that we sent out. Iterate 1276 * over all of its options. Stop when we reach the end of the 1277 * property or something that doesn't look like an option. 1278 */ 1279 p += 2; 1280 gotSerial = 0; 1281 res = (char_u *)""; 1282 code = 0; 1283 while ((p-propInfo) < numItems && *p == '-') 1284 { 1285 switch (p[1]) 1286 { 1287 case 'r': 1288 if (p[2] == ' ') 1289 res = p + 3; 1290 break; 1291 case 's': 1292 if (sscanf((char *)p + 2, " %d", &serial) == 1) 1293 gotSerial = 1; 1294 break; 1295 case 'c': 1296 if (sscanf((char *)p + 2, " %d", &code) != 1) 1297 code = 0; 1298 break; 1299 } 1300 while (*p != 0) 1301 p++; 1302 p++; 1303 } 1304 1305 if (!gotSerial) 1306 continue; 1307 1308 /* 1309 * Give the result information to anyone who's 1310 * waiting for it. 1311 */ 1312 for (pcPtr = pendingCommands; pcPtr != NULL; pcPtr = pcPtr->nextPtr) 1313 { 1314 if (serial != pcPtr->serial || pcPtr->result != NULL) 1315 continue; 1316 1317 pcPtr->code = code; 1318 if (res != NULL) 1319 pcPtr->result = vim_strsave(res); 1320 else 1321 pcPtr->result = vim_strsave((char_u *)""); 1322 break; 1323 } 1324 } 1325 else if (*p == 'n' && p[1] == 0) 1326 { 1327 Window win = 0; 1328 unsigned int u; 1329 int gotWindow; 1330 char_u *str; 1331 char_u winstr[30]; 1332 struct ServerReply *r; 1333 1334 /* 1335 * This is a (n)otification. Sent with serverreply_send in VimL. 1336 * Execute any autocommand and save it for later retrieval 1337 */ 1338 p += 2; 1339 gotWindow = 0; 1340 str = (char_u *)""; 1341 while ((p-propInfo) < numItems && *p == '-') 1342 { 1343 switch (p[1]) 1344 { 1345 case 'n': 1346 if (p[2] == ' ') 1347 str = p + 3; 1348 break; 1349 case 'w': 1350 if (sscanf((char *)p + 2, " %x", &u) == 1) 1351 { 1352 win = u; 1353 gotWindow = 1; 1354 } 1355 break; 1356 } 1357 while (*p != 0) 1358 p++; 1359 p++; 1360 } 1361 1362 if (!gotWindow) 1363 continue; 1364 if ((r = ServerReplyFind(win, SROP_Add)) != NULL) 1365 { 1366 ga_concat(&(r->strings), str); 1367 ga_append(&(r->strings), NUL); 1368 } 1369 #ifdef FEAT_AUTOCMD 1370 sprintf((char *)winstr, "0x%x", (unsigned int)win); 1371 apply_autocmds(EVENT_REMOTEREPLY, winstr, str, TRUE, curbuf); 1372 #endif 1373 1374 } 1375 else 1376 { 1377 /* 1378 * Didn't recognize this thing. Just skip through the next 1379 * null character and try again. 1380 * Even if we get an 'r'(eply) we will throw it away as we 1381 * never specify (and thus expect) one 1382 */ 1383 while (*p != 0) 1384 p++; 1385 p++; 1386 } 1387 } 1388 XFree(propInfo); 1389 } 1390 1391 /* 1392 * Append a given property to a given window, but set up an X error handler so 1393 * that if the append fails this procedure can return an error code rather 1394 * than having Xlib panic. 1395 * Return: 0 for OK, -1 for error 1396 */ 1397 static int 1398 AppendPropCarefully(dpy, window, property, value, length) 1399 Display *dpy; /* Display on which to operate. */ 1400 Window window; /* Window whose property is to be modified. */ 1401 Atom property; /* Name of property. */ 1402 char_u *value; /* Characters to append to property. */ 1403 int length; /* How much to append */ 1404 { 1405 XErrorHandler old_handler; 1406 1407 old_handler = XSetErrorHandler(x_error_check); 1408 got_x_error = FALSE; 1409 XChangeProperty(dpy, window, property, XA_STRING, 8, 1410 PropModeAppend, value, length); 1411 XSync(dpy, False); 1412 (void) XSetErrorHandler(old_handler); 1413 return got_x_error ? -1 : 0; 1414 } 1415 1416 1417 /* 1418 * Another X Error handler, just used to check for errors. 1419 */ 1420 /* ARGSUSED */ 1421 static int 1422 x_error_check(dpy, error_event) 1423 Display *dpy; 1424 XErrorEvent *error_event; 1425 { 1426 got_x_error = TRUE; 1427 return 0; 1428 } 1429 1430 /* 1431 * Check if "str" looks like it had a serial number appended. 1432 * Actually just checks if the name ends in a digit. 1433 */ 1434 static int 1435 IsSerialName(str) 1436 char_u *str; 1437 { 1438 int len = STRLEN(str); 1439 1440 return (len > 1 && vim_isdigit(str[len - 1])); 1441 } 1442 #endif /* FEAT_CLIENTSERVER */ 1443