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