| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | /* vi:set ts=8 sts=4 sw=4:
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * VIM - Vi IMproved	by Bram Moolenaar | 
					
						
							|  |  |  |  * X-Windows communication by Flemming Madsen | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Do ":help uganda"  in Vim to read copying and usage conditions. | 
					
						
							|  |  |  |  * Do ":help credits" in Vim to see a list of people who contributed. | 
					
						
							|  |  |  |  * See README.txt for an overview of the Vim source code. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Client for sending commands to an '+xcmdsrv' enabled vim. | 
					
						
							|  |  |  |  * This is mostly a de-Vimified version of if_xcmdsrv.c in vim. | 
					
						
							|  |  |  |  * See that file for a protocol specification. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You can make a test program with a Makefile like: | 
					
						
							|  |  |  |  *  xcmdsrv_client: xcmdsrv_client.c | 
					
						
							|  |  |  |  *	cc -o $@ -g -DMAIN -I/usr/X11R6/include -L/usr/X11R6/lib $< -lX11 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #ifdef HAVE_SELECT
 | 
					
						
							|  |  |  | #include <sys/time.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | #include <sys/poll.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #include <X11/Intrinsic.h>
 | 
					
						
							|  |  |  | #include <X11/Xatom.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Client API */ | 
					
						
							| 
									
										
										
										
											2016-01-29 23:20:40 +01:00
										 |  |  | char * sendToVim(Display *dpy, char *name, char *cmd, int asKeys, int *code); | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #ifdef MAIN
 | 
					
						
							|  |  |  | /* A sample program */ | 
					
						
							|  |  |  | main(int argc, char **argv) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     char    *res; | 
					
						
							|  |  |  |     int	    code; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (argc == 4) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if ((res = sendToVim(XOpenDisplay(NULL), argv[2], argv[3], | 
					
						
							|  |  |  | 			     argv[1][0] != 'e', &code)) != NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    if (code) | 
					
						
							|  |  |  | 		printf("Error code returned: %d\n", code); | 
					
						
							|  |  |  | 	    puts(res); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	exit(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  | 	fprintf(stderr, "Usage: %s {k|e} <server> <command>", argv[0]); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     exit(1); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Maximum size property that can be read at one time by | 
					
						
							|  |  |  |  * this module: | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MAX_PROP_WORDS 100000
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Forward declarations for procedures defined later in this file: | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-29 23:20:40 +01:00
										 |  |  | static int	x_error_check(Display *dpy, XErrorEvent *error_event); | 
					
						
							|  |  |  | static int	AppendPropCarefully(Display *display, | 
					
						
							|  |  |  | 		    Window window, Atom property, char *value, int length); | 
					
						
							|  |  |  | static Window	LookupName(Display *dpy, char *name, | 
					
						
							|  |  |  | 		    int delete, char **loose); | 
					
						
							|  |  |  | static int	SendInit(Display *dpy); | 
					
						
							|  |  |  | static char	*SendEventProc(Display *dpy, XEvent *eventPtr, | 
					
						
							|  |  |  | 				      int expect, int *code); | 
					
						
							|  |  |  | static int	IsSerialName(char *name); | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* Private variables */ | 
					
						
							|  |  |  | static Atom	registryProperty = None; | 
					
						
							|  |  |  | static Atom	commProperty = None; | 
					
						
							|  |  |  | static Window	commWindow = None; | 
					
						
							|  |  |  | static int	got_x_error = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * sendToVim -- | 
					
						
							|  |  |  |  *	Send to an instance of Vim via the X display. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Results: | 
					
						
							|  |  |  |  *	A string with the result or NULL. Caller must free if non-NULL | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     char * | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | sendToVim( | 
					
						
							|  |  |  |     Display	*dpy,			/* Where to send. */ | 
					
						
							|  |  |  |     char	*name,			/* Where to send. */ | 
					
						
							|  |  |  |     char	*cmd,			/* What to send. */ | 
					
						
							|  |  |  |     int		asKeys,			/* Interpret as keystrokes or expr ? */ | 
					
						
							|  |  |  |     int		*code)			/* Return code. 0 => OK */ | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     Window	    w; | 
					
						
							|  |  |  |     Atom	    *plist; | 
					
						
							|  |  |  |     XErrorHandler   old_handler; | 
					
						
							|  |  |  | #define STATIC_SPACE 500
 | 
					
						
							|  |  |  |     char	    *property, staticSpace[STATIC_SPACE]; | 
					
						
							|  |  |  |     int		    length; | 
					
						
							|  |  |  |     int		    res; | 
					
						
							|  |  |  |     static int	    serial = 0;	/* Running count of sent commands.
 | 
					
						
							|  |  |  | 				 * Used to give each command a | 
					
						
							|  |  |  | 				 * different serial number. */ | 
					
						
							|  |  |  |     XEvent	    event; | 
					
						
							|  |  |  |     XPropertyEvent  *e = (XPropertyEvent *)&event; | 
					
						
							|  |  |  |     time_t	    start; | 
					
						
							|  |  |  |     char	    *result; | 
					
						
							|  |  |  |     char	    *loosename = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (commProperty == None && dpy != NULL) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if (SendInit(dpy) < 0) | 
					
						
							|  |  |  | 	    return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Bind the server name to a communication window. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Find any survivor with a serialno attached to the name if the | 
					
						
							|  |  |  |      * original registrant of the wanted name is no longer present. | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * Delete any lingering names from dead editors. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     old_handler = XSetErrorHandler(x_error_check); | 
					
						
							|  |  |  |     while (TRUE) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	got_x_error = FALSE; | 
					
						
							|  |  |  | 	w = LookupName(dpy, name, 0, &loosename); | 
					
						
							|  |  |  | 	/* Check that the window is hot */ | 
					
						
							|  |  |  | 	if (w != None) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    plist = XListProperties(dpy, w, &res); | 
					
						
							|  |  |  | 	    XSync(dpy, False); | 
					
						
							|  |  |  | 	    if (plist != NULL) | 
					
						
							|  |  |  | 		XFree(plist); | 
					
						
							|  |  |  | 	    if (got_x_error) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		LookupName(dpy, loosename ? loosename : name, | 
					
						
							|  |  |  | 			   /*DELETE=*/TRUE, NULL); | 
					
						
							|  |  |  | 		continue; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (w == None) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	fprintf(stderr, "no registered server named %s\n", name); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     else if (loosename != NULL) | 
					
						
							|  |  |  | 	name = loosename; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Send the command to target interpreter by appending it to the | 
					
						
							|  |  |  |      * comm window in the communication window. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     length = strlen(name) + strlen(cmd) + 10; | 
					
						
							|  |  |  |     if (length <= STATIC_SPACE) | 
					
						
							|  |  |  | 	property = staticSpace; | 
					
						
							|  |  |  |     else | 
					
						
							|  |  |  | 	property = (char *) malloc((unsigned) length); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     serial++; | 
					
						
							|  |  |  |     sprintf(property, "%c%c%c-n %s%c-s %s", | 
					
						
							|  |  |  | 		      0, asKeys ? 'k' : 'c', 0, name, 0, cmd); | 
					
						
							|  |  |  |     if (name == loosename) | 
					
						
							|  |  |  | 	free(loosename); | 
					
						
							|  |  |  |     if (!asKeys) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	/* Add a back reference to our comm window */ | 
					
						
							|  |  |  | 	sprintf(property + length, "%c-r %x %d", 0, (uint) commWindow, serial); | 
					
						
							|  |  |  | 	length += strlen(property + length + 1) + 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     res = AppendPropCarefully(dpy, w, commProperty, property, length + 1); | 
					
						
							|  |  |  |     if (length > STATIC_SPACE) | 
					
						
							|  |  |  | 	free(property); | 
					
						
							|  |  |  |     if (res < 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	fprintf(stderr, "Failed to send command to the destination program\n"); | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (asKeys) /* There is no answer for this - Keys are sent async */ | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Enter a loop processing X events & pooling chars until we see the result | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define SEND_MSEC_POLL 50
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     time(&start); | 
					
						
							|  |  |  |     while ((time((time_t *) 0) - start) < 60) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	/* Look out for the answer */ | 
					
						
							|  |  |  | #ifndef HAVE_SELECT
 | 
					
						
							|  |  |  | 	struct pollfd   fds; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fds.fd = ConnectionNumber(dpy); | 
					
						
							|  |  |  | 	fds.events = POLLIN; | 
					
						
							|  |  |  | 	if (poll(&fds, 1, SEND_MSEC_POLL) < 0) | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  | 	fd_set	    fds; | 
					
						
							|  |  |  | 	struct timeval  tv; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tv.tv_sec = 0; | 
					
						
							|  |  |  | 	tv.tv_usec =  SEND_MSEC_POLL * 1000; | 
					
						
							|  |  |  | 	FD_ZERO(&fds); | 
					
						
							|  |  |  | 	FD_SET(ConnectionNumber(dpy), &fds); | 
					
						
							|  |  |  | 	if (select(ConnectionNumber(dpy) + 1, &fds, NULL, NULL, &tv) < 0) | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 	while (XEventsQueued(dpy, QueuedAfterReading) > 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    XNextEvent(dpy, &event); | 
					
						
							|  |  |  | 	    if (event.type == PropertyNotify && e->window == commWindow) | 
					
						
							|  |  |  | 		if ((result = SendEventProc(dpy, &event, serial, code)) != NULL) | 
					
						
							|  |  |  | 		    return result; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * SendInit -- | 
					
						
							|  |  |  |  *	This procedure is called to initialize the | 
					
						
							|  |  |  |  *	communication channels for sending commands and | 
					
						
							|  |  |  |  *	receiving results. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | SendInit(Display *dpy) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     XErrorHandler old_handler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Create the window used for communication, and set up an | 
					
						
							|  |  |  |      * event handler for it. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     old_handler = XSetErrorHandler(x_error_check); | 
					
						
							|  |  |  |     got_x_error = FALSE; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     commProperty = XInternAtom(dpy, "Comm", False); | 
					
						
							|  |  |  |     /* Change this back to "InterpRegistry" to talk to tk processes */ | 
					
						
							|  |  |  |     registryProperty = XInternAtom(dpy, "VimRegistry", False); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (commWindow == None) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	commWindow = | 
					
						
							|  |  |  | 	    XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), | 
					
						
							|  |  |  | 				getpid(), 0, 10, 10, 0, | 
					
						
							|  |  |  | 				WhitePixel(dpy, DefaultScreen(dpy)), | 
					
						
							|  |  |  | 				WhitePixel(dpy, DefaultScreen(dpy))); | 
					
						
							|  |  |  | 	XSelectInput(dpy, commWindow, PropertyChangeMask); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XSync(dpy, False); | 
					
						
							|  |  |  |     (void) XSetErrorHandler(old_handler); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return got_x_error ? -1 : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * LookupName -- | 
					
						
							|  |  |  |  *	Given an interpreter name, see if the name exists in | 
					
						
							|  |  |  |  *	the interpreter registry for a particular display. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Results: | 
					
						
							|  |  |  |  *	If the given name is registered, return the ID of | 
					
						
							|  |  |  |  *	the window associated with the name.  If the name | 
					
						
							|  |  |  |  *	isn't registered, then return 0. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static Window | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | LookupName( | 
					
						
							|  |  |  |     Display *dpy,	/* Display whose registry to check. */ | 
					
						
							|  |  |  |     char *name,		/* Name of an interpreter. */ | 
					
						
							|  |  |  |     int delete,		/* If non-zero, delete info about name. */ | 
					
						
							|  |  |  |     char **loose)	/* Do another search matching -999 if not found
 | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 			   Return result here if a match is found */ | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned char   *regProp, *entry; | 
					
						
							|  |  |  |     unsigned char   *p; | 
					
						
							|  |  |  |     int		    result, actualFormat; | 
					
						
							|  |  |  |     unsigned long   numItems, bytesAfter; | 
					
						
							|  |  |  |     Atom	    actualType; | 
					
						
							|  |  |  |     Window	    returnValue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Read the registry property. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     regProp = NULL; | 
					
						
							|  |  |  |     result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0, | 
					
						
							|  |  |  | 				MAX_PROP_WORDS, False, XA_STRING, &actualType, | 
					
						
							|  |  |  | 				&actualFormat, &numItems, &bytesAfter, | 
					
						
							|  |  |  | 				®Prop); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (actualType == None) | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If the property is improperly formed, then delete it. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((result != Success) || (actualFormat != 8) || (actualType != XA_STRING)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if (regProp != NULL) | 
					
						
							|  |  |  | 	    XFree(regProp); | 
					
						
							|  |  |  | 	XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Scan the property for the desired name. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     returnValue = None; | 
					
						
							|  |  |  |     entry = NULL;	/* Not needed, but eliminates compiler warning. */ | 
					
						
							|  |  |  |     for (p = regProp; (p - regProp) < numItems; ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	entry = p; | 
					
						
							|  |  |  | 	while ((*p != 0) && (!isspace(*p))) | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	if ((*p != 0) && (strcasecmp(name, p + 1) == 0)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    sscanf(entry, "%x", (uint*) &returnValue); | 
					
						
							|  |  |  | 	    break; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while (*p != 0) | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	p++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (loose != NULL && returnValue == None && !IsSerialName(name)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	for (p = regProp; (p - regProp) < numItems; ) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    entry = p; | 
					
						
							|  |  |  | 	    while ((*p != 0) && (!isspace(*p))) | 
					
						
							|  |  |  | 		p++; | 
					
						
							|  |  |  | 	    if ((*p != 0) && IsSerialName(p + 1) | 
					
						
							|  |  |  | 		    && (strncmp(name, p + 1, strlen(name)) == 0)) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		sscanf(entry, "%x", (uint*) &returnValue); | 
					
						
							|  |  |  | 		*loose = strdup(p + 1); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 	    while (*p != 0) | 
					
						
							|  |  |  | 		p++; | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Delete the property, if that is desired (copy down the | 
					
						
							|  |  |  |      * remainder of the registry property to overlay the deleted | 
					
						
							|  |  |  |      * info, then rewrite the property). | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((delete) && (returnValue != None)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	int count; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (*p != 0) | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	p++; | 
					
						
							|  |  |  | 	count = numItems - (p-regProp); | 
					
						
							|  |  |  | 	if (count > 0) | 
					
						
							|  |  |  | 	    memcpy(entry, p, count); | 
					
						
							|  |  |  | 	XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, | 
					
						
							|  |  |  | 			8, PropModeReplace, regProp, | 
					
						
							|  |  |  | 			(int) (numItems - (p-entry))); | 
					
						
							|  |  |  | 	XSync(dpy, False); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     XFree(regProp); | 
					
						
							|  |  |  |     return returnValue; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static char * | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | SendEventProc( | 
					
						
							|  |  |  |     Display	   *dpy, | 
					
						
							|  |  |  |     XEvent	    *eventPtr,		/* Information about event. */ | 
					
						
							|  |  |  |     int		    expected,		/* The one were waiting for */ | 
					
						
							|  |  |  |     int		    *code)		/* Return code. 0 => OK */ | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     unsigned char   *propInfo; | 
					
						
							|  |  |  |     unsigned char   *p; | 
					
						
							|  |  |  |     int		    result, actualFormat; | 
					
						
							|  |  |  |     int		    retCode; | 
					
						
							|  |  |  |     unsigned long   numItems, bytesAfter; | 
					
						
							|  |  |  |     Atom	    actualType; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((eventPtr->xproperty.atom != commProperty) | 
					
						
							|  |  |  | 	    || (eventPtr->xproperty.state != PropertyNewValue)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Read the comm property and delete it. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     propInfo = NULL; | 
					
						
							|  |  |  |     result = XGetWindowProperty(dpy, commWindow, commProperty, 0, | 
					
						
							|  |  |  | 				MAX_PROP_WORDS, True, XA_STRING, &actualType, | 
					
						
							|  |  |  | 				&actualFormat, &numItems, &bytesAfter, | 
					
						
							|  |  |  | 				&propInfo); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * If the property doesn't exist or is improperly formed | 
					
						
							|  |  |  |      * then ignore it. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if ((result != Success) || (actualType != XA_STRING) | 
					
						
							|  |  |  | 	    || (actualFormat != 8)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	if (propInfo != NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    XFree(propInfo); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /*
 | 
					
						
							|  |  |  |      * Several commands and results could arrive in the property at | 
					
						
							|  |  |  |      * one time;  each iteration through the outer loop handles a | 
					
						
							|  |  |  |      * single command or result. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (p = propInfo; (p - propInfo) < numItems; ) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * Ignore leading NULs; each command or result starts with a | 
					
						
							|  |  |  | 	 * NUL so that no matter how badly formed a preceding command | 
					
						
							|  |  |  | 	 * is, we'll be able to tell that a new command/result is | 
					
						
							|  |  |  | 	 * starting. | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (*p == 0) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	    continue; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((*p == 'r') && (p[1] == 0)) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    int	    serial, gotSerial; | 
					
						
							|  |  |  | 	    char  *res; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    /*
 | 
					
						
							|  |  |  | 	     * This is a reply to some command that we sent out.  Iterate | 
					
						
							|  |  |  | 	     * over all of its options.  Stop when we reach the end of the | 
					
						
							|  |  |  | 	     * property or something that doesn't look like an option. | 
					
						
							|  |  |  | 	     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    p += 2; | 
					
						
							|  |  |  | 	    gotSerial = 0; | 
					
						
							|  |  |  | 	    res = ""; | 
					
						
							|  |  |  | 	    retCode = 0; | 
					
						
							|  |  |  | 	    while (((p-propInfo) < numItems) && (*p == '-')) | 
					
						
							|  |  |  | 	    { | 
					
						
							|  |  |  | 		switch (p[1]) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 		    case 'r': | 
					
						
							|  |  |  | 			if (p[2] == ' ') | 
					
						
							|  |  |  | 			    res = p + 3; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    case 's': | 
					
						
							|  |  |  | 			if (sscanf(p + 2, " %d", &serial) == 1) | 
					
						
							|  |  |  | 			    gotSerial = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		    case 'c': | 
					
						
							|  |  |  | 			if (sscanf(p + 2, " %d", &retCode) != 1) | 
					
						
							|  |  |  | 			    retCode = 0; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		while (*p != 0) | 
					
						
							|  |  |  | 		    p++; | 
					
						
							|  |  |  | 		p++; | 
					
						
							|  |  |  | 	    } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if (!gotSerial) | 
					
						
							|  |  |  | 		continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    if (code != NULL) | 
					
						
							|  |  |  | 		*code = retCode; | 
					
						
							|  |  |  | 	    return serial == expected ? strdup(res) : NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	    /*
 | 
					
						
							|  |  |  | 	     * Didn't recognize this thing.  Just skip through the next | 
					
						
							|  |  |  | 	     * null character and try again. | 
					
						
							| 
									
										
										
										
											2021-07-28 20:10:16 +02:00
										 |  |  | 	     * Also, throw away commands that we can't process anyway. | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 	     */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	    while (*p != 0) | 
					
						
							|  |  |  | 		p++; | 
					
						
							|  |  |  | 	    p++; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     XFree(propInfo); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * AppendPropCarefully -- | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Append a given property to a given window, but set up | 
					
						
							|  |  |  |  *	an X error handler so that if the append fails this | 
					
						
							|  |  |  |  *	procedure can return an error code rather than having | 
					
						
							|  |  |  |  *	Xlib panic. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Return: | 
					
						
							|  |  |  |  *	0 on OK - -1 on error | 
					
						
							|  |  |  |  *-------------------------------------------------------------- | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | AppendPropCarefully( | 
					
						
							|  |  |  |     Display *dpy,		/* Display on which to operate. */ | 
					
						
							|  |  |  |     Window window,		/* Window whose property is to
 | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | 				 * be modified. */ | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  |     Atom property,		/* Name of property. */ | 
					
						
							|  |  |  |     char *value,		/* Characters  to append to property. */ | 
					
						
							|  |  |  |     int  length)		/* How much to append */ | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     XErrorHandler old_handler; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     old_handler = XSetErrorHandler(x_error_check); | 
					
						
							|  |  |  |     got_x_error = FALSE; | 
					
						
							|  |  |  |     XChangeProperty(dpy, window, property, XA_STRING, 8, | 
					
						
							|  |  |  | 		    PropModeAppend, value, length); | 
					
						
							|  |  |  |     XSync(dpy, False); | 
					
						
							|  |  |  |     (void) XSetErrorHandler(old_handler); | 
					
						
							|  |  |  |     return got_x_error ? -1 : 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Another X Error handler, just used to check for errors. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | /* ARGSUSED */ | 
					
						
							|  |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | x_error_check(Display *dpy, XErrorEvent *error_event) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     got_x_error = TRUE; | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Check if "str" looks like it had a serial number appended. | 
					
						
							|  |  |  |  * Actually just checks if the name ends in a digit. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  |     static int | 
					
						
							| 
									
										
										
										
											2016-01-30 21:29:58 +01:00
										 |  |  | IsSerialName(char *str) | 
					
						
							| 
									
										
										
										
											2004-06-13 20:20:40 +00:00
										 |  |  | { | 
					
						
							|  |  |  |     int len = strlen(str); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (len > 1 && isdigit(str[len - 1])); | 
					
						
							|  |  |  | } |