diff options
Diffstat (limited to 'runtime/tools/xcmdsrv_client.c')
-rw-r--r-- | runtime/tools/xcmdsrv_client.c | 584 |
1 files changed, 0 insertions, 584 deletions
diff --git a/runtime/tools/xcmdsrv_client.c b/runtime/tools/xcmdsrv_client.c deleted file mode 100644 index a0e6211a1d..0000000000 --- a/runtime/tools/xcmdsrv_client.c +++ /dev/null @@ -1,584 +0,0 @@ -/* 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> - -#define __ARGS(x) x - -/* Client API */ -char * sendToVim __ARGS((Display *dpy, char *name, char *cmd, int asKeys, int *code)); - -#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: - */ - -static int x_error_check __ARGS((Display *dpy, XErrorEvent *error_event)); -static int AppendPropCarefully __ARGS((Display *display, - Window window, Atom property, char *value, int length)); -static Window LookupName __ARGS((Display *dpy, char *name, - int delete, char **loose)); -static int SendInit __ARGS((Display *dpy)); -static char *SendEventProc __ARGS((Display *dpy, XEvent *eventPtr, - int expect, int *code)); -static int IsSerialName __ARGS((char *name)); - -/* 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 * -sendToVim(dpy, name, cmd, asKeys, code) - 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 */ -{ - 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 -SendInit(dpy) - Display *dpy; -{ - 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 -LookupName(dpy, name, delete, loose) - 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 - 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 * -SendEventProc(dpy, eventPtr, expected, code) - Display *dpy; - XEvent *eventPtr; /* Information about event. */ - int expected; /* The one were waiting for */ - int *code; /* Return code. 0 => OK */ -{ - 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. - * Also, throw away commands that we cant process anyway. - */ - - 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 -AppendPropCarefully(dpy, window, property, value, length) - Display *dpy; /* Display on which to operate. */ - Window window; /* Window whose property is to - * be modified. */ - Atom property; /* Name of property. */ - char *value; /* Characters to append to property. */ - int length; /* How much to append */ -{ - 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 -x_error_check(dpy, error_event) - Display *dpy; - XErrorEvent *error_event; -{ - 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 -IsSerialName(str) - char *str; -{ - int len = strlen(str); - - return (len > 1 && isdigit(str[len - 1])); -} |