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