Mercurial > vim
annotate runtime/tools/xcmdsrv_client.c @ 29603:8f01d250793a v9.0.0142
patch 9.0.0142: crash when adding and removing virtual text
Commit: https://github.com/vim/vim/commit/2f83cc4cfa56750c91eb6daa8fde319bca032d18
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Aug 5 11:45:17 2022 +0100
patch 9.0.0142: crash when adding and removing virtual text
Problem: Crash when adding and removing virtual text. (Ben Jackson)
Solution: Check that the text of the text property still exists.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Fri, 05 Aug 2022 13:00:03 +0200 |
parents | bdda48f01a68 |
children | 1629cc65d78d |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * X-Windows communication 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 * Client for sending commands to an '+xcmdsrv' enabled vim. | |
11 * This is mostly a de-Vimified version of if_xcmdsrv.c in vim. | |
12 * See that file for a protocol specification. | |
13 * | |
14 * You can make a test program with a Makefile like: | |
15 * xcmdsrv_client: xcmdsrv_client.c | |
16 * cc -o $@ -g -DMAIN -I/usr/X11R6/include -L/usr/X11R6/lib $< -lX11 | |
17 * | |
18 */ | |
19 | |
20 #include <stdio.h> | |
21 #include <string.h> | |
22 #ifdef HAVE_SELECT | |
23 #include <sys/time.h> | |
24 #include <sys/types.h> | |
25 #include <unistd.h> | |
26 #else | |
27 #include <sys/poll.h> | |
28 #endif | |
29 #include <X11/Intrinsic.h> | |
30 #include <X11/Xatom.h> | |
31 | |
32 /* Client API */ | |
7807
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
33 char * sendToVim(Display *dpy, char *name, char *cmd, int asKeys, int *code); |
7 | 34 |
35 #ifdef MAIN | |
36 /* A sample program */ | |
37 main(int argc, char **argv) | |
38 { | |
39 char *res; | |
40 int code; | |
41 | |
42 if (argc == 4) | |
43 { | |
44 if ((res = sendToVim(XOpenDisplay(NULL), argv[2], argv[3], | |
45 argv[1][0] != 'e', &code)) != NULL) | |
46 { | |
47 if (code) | |
48 printf("Error code returned: %d\n", code); | |
49 puts(res); | |
50 } | |
51 exit(0); | |
52 } | |
53 else | |
54 fprintf(stderr, "Usage: %s {k|e} <server> <command>", argv[0]); | |
55 | |
56 exit(1); | |
57 } | |
58 #endif | |
59 | |
60 /* | |
61 * Maximum size property that can be read at one time by | |
62 * this module: | |
63 */ | |
64 | |
65 #define MAX_PROP_WORDS 100000 | |
66 | |
67 /* | |
68 * Forward declarations for procedures defined later in this file: | |
69 */ | |
70 | |
7807
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
71 static int x_error_check(Display *dpy, XErrorEvent *error_event); |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
72 static int AppendPropCarefully(Display *display, |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
73 Window window, Atom property, char *value, int length); |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
74 static Window LookupName(Display *dpy, char *name, |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
75 int delete, char **loose); |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
76 static int SendInit(Display *dpy); |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
77 static char *SendEventProc(Display *dpy, XEvent *eventPtr, |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
78 int expect, int *code); |
1a5d34492798
commit https://github.com/vim/vim/commit/d99df423c559d85c17779b3685426c489554908c
Christian Brabandt <cb@256bit.org>
parents:
7
diff
changeset
|
79 static int IsSerialName(char *name); |
7 | 80 |
81 /* Private variables */ | |
82 static Atom registryProperty = None; | |
83 static Atom commProperty = None; | |
84 static Window commWindow = None; | |
85 static int got_x_error = FALSE; | |
86 | |
87 | |
88 /* | |
89 * sendToVim -- | |
90 * Send to an instance of Vim via the X display. | |
91 * | |
92 * Results: | |
93 * A string with the result or NULL. Caller must free if non-NULL | |
94 */ | |
95 | |
96 char * | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
97 sendToVim( |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
98 Display *dpy, /* Where to send. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
99 char *name, /* Where to send. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
100 char *cmd, /* What to send. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
101 int asKeys, /* Interpret as keystrokes or expr ? */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
102 int *code) /* Return code. 0 => OK */ |
7 | 103 { |
104 Window w; | |
105 Atom *plist; | |
106 XErrorHandler old_handler; | |
107 #define STATIC_SPACE 500 | |
108 char *property, staticSpace[STATIC_SPACE]; | |
109 int length; | |
110 int res; | |
111 static int serial = 0; /* Running count of sent commands. | |
112 * Used to give each command a | |
113 * different serial number. */ | |
114 XEvent event; | |
115 XPropertyEvent *e = (XPropertyEvent *)&event; | |
116 time_t start; | |
117 char *result; | |
118 char *loosename = NULL; | |
119 | |
120 if (commProperty == None && dpy != NULL) | |
121 { | |
122 if (SendInit(dpy) < 0) | |
123 return NULL; | |
124 } | |
125 | |
126 /* | |
127 * Bind the server name to a communication window. | |
128 * | |
129 * Find any survivor with a serialno attached to the name if the | |
130 * original registrant of the wanted name is no longer present. | |
131 * | |
132 * Delete any lingering names from dead editors. | |
133 */ | |
134 | |
135 old_handler = XSetErrorHandler(x_error_check); | |
136 while (TRUE) | |
137 { | |
138 got_x_error = FALSE; | |
139 w = LookupName(dpy, name, 0, &loosename); | |
140 /* Check that the window is hot */ | |
141 if (w != None) | |
142 { | |
143 plist = XListProperties(dpy, w, &res); | |
144 XSync(dpy, False); | |
145 if (plist != NULL) | |
146 XFree(plist); | |
147 if (got_x_error) | |
148 { | |
149 LookupName(dpy, loosename ? loosename : name, | |
150 /*DELETE=*/TRUE, NULL); | |
151 continue; | |
152 } | |
153 } | |
154 break; | |
155 } | |
156 if (w == None) | |
157 { | |
158 fprintf(stderr, "no registered server named %s\n", name); | |
159 return NULL; | |
160 } | |
161 else if (loosename != NULL) | |
162 name = loosename; | |
163 | |
164 /* | |
165 * Send the command to target interpreter by appending it to the | |
166 * comm window in the communication window. | |
167 */ | |
168 | |
169 length = strlen(name) + strlen(cmd) + 10; | |
170 if (length <= STATIC_SPACE) | |
171 property = staticSpace; | |
172 else | |
173 property = (char *) malloc((unsigned) length); | |
174 | |
175 serial++; | |
176 sprintf(property, "%c%c%c-n %s%c-s %s", | |
177 0, asKeys ? 'k' : 'c', 0, name, 0, cmd); | |
178 if (name == loosename) | |
179 free(loosename); | |
180 if (!asKeys) | |
181 { | |
182 /* Add a back reference to our comm window */ | |
183 sprintf(property + length, "%c-r %x %d", 0, (uint) commWindow, serial); | |
184 length += strlen(property + length + 1) + 1; | |
185 } | |
186 | |
187 res = AppendPropCarefully(dpy, w, commProperty, property, length + 1); | |
188 if (length > STATIC_SPACE) | |
189 free(property); | |
190 if (res < 0) | |
191 { | |
192 fprintf(stderr, "Failed to send command to the destination program\n"); | |
193 return NULL; | |
194 } | |
195 | |
196 if (asKeys) /* There is no answer for this - Keys are sent async */ | |
197 return NULL; | |
198 | |
199 | |
200 /* | |
201 * Enter a loop processing X events & pooling chars until we see the result | |
202 */ | |
203 | |
204 #define SEND_MSEC_POLL 50 | |
205 | |
206 time(&start); | |
207 while ((time((time_t *) 0) - start) < 60) | |
208 { | |
209 /* Look out for the answer */ | |
210 #ifndef HAVE_SELECT | |
211 struct pollfd fds; | |
212 | |
213 fds.fd = ConnectionNumber(dpy); | |
214 fds.events = POLLIN; | |
215 if (poll(&fds, 1, SEND_MSEC_POLL) < 0) | |
216 break; | |
217 #else | |
218 fd_set fds; | |
219 struct timeval tv; | |
220 | |
221 tv.tv_sec = 0; | |
222 tv.tv_usec = SEND_MSEC_POLL * 1000; | |
223 FD_ZERO(&fds); | |
224 FD_SET(ConnectionNumber(dpy), &fds); | |
225 if (select(ConnectionNumber(dpy) + 1, &fds, NULL, NULL, &tv) < 0) | |
226 break; | |
227 #endif | |
228 while (XEventsQueued(dpy, QueuedAfterReading) > 0) | |
229 { | |
230 XNextEvent(dpy, &event); | |
231 if (event.type == PropertyNotify && e->window == commWindow) | |
232 if ((result = SendEventProc(dpy, &event, serial, code)) != NULL) | |
233 return result; | |
234 } | |
235 } | |
236 return NULL; | |
237 } | |
238 | |
239 | |
240 /* | |
241 * SendInit -- | |
242 * This procedure is called to initialize the | |
243 * communication channels for sending commands and | |
244 * receiving results. | |
245 */ | |
246 | |
247 static int | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
248 SendInit(Display *dpy) |
7 | 249 { |
250 XErrorHandler old_handler; | |
251 | |
252 /* | |
253 * Create the window used for communication, and set up an | |
254 * event handler for it. | |
255 */ | |
256 old_handler = XSetErrorHandler(x_error_check); | |
257 got_x_error = FALSE; | |
258 | |
259 commProperty = XInternAtom(dpy, "Comm", False); | |
260 /* Change this back to "InterpRegistry" to talk to tk processes */ | |
261 registryProperty = XInternAtom(dpy, "VimRegistry", False); | |
262 | |
263 if (commWindow == None) | |
264 { | |
265 commWindow = | |
266 XCreateSimpleWindow(dpy, XDefaultRootWindow(dpy), | |
267 getpid(), 0, 10, 10, 0, | |
268 WhitePixel(dpy, DefaultScreen(dpy)), | |
269 WhitePixel(dpy, DefaultScreen(dpy))); | |
270 XSelectInput(dpy, commWindow, PropertyChangeMask); | |
271 } | |
272 | |
273 XSync(dpy, False); | |
274 (void) XSetErrorHandler(old_handler); | |
275 | |
276 return got_x_error ? -1 : 0; | |
277 } | |
278 | |
279 /* | |
280 * LookupName -- | |
281 * Given an interpreter name, see if the name exists in | |
282 * the interpreter registry for a particular display. | |
283 * | |
284 * Results: | |
285 * If the given name is registered, return the ID of | |
286 * the window associated with the name. If the name | |
287 * isn't registered, then return 0. | |
288 */ | |
289 | |
290 static Window | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
291 LookupName( |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
292 Display *dpy, /* Display whose registry to check. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
293 char *name, /* Name of an interpreter. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
294 int delete, /* If non-zero, delete info about name. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
295 char **loose) /* Do another search matching -999 if not found |
7 | 296 Return result here if a match is found */ |
297 { | |
298 unsigned char *regProp, *entry; | |
299 unsigned char *p; | |
300 int result, actualFormat; | |
301 unsigned long numItems, bytesAfter; | |
302 Atom actualType; | |
303 Window returnValue; | |
304 | |
305 /* | |
306 * Read the registry property. | |
307 */ | |
308 | |
309 regProp = NULL; | |
310 result = XGetWindowProperty(dpy, RootWindow(dpy, 0), registryProperty, 0, | |
311 MAX_PROP_WORDS, False, XA_STRING, &actualType, | |
312 &actualFormat, &numItems, &bytesAfter, | |
313 ®Prop); | |
314 | |
315 if (actualType == None) | |
316 return 0; | |
317 | |
318 /* | |
319 * If the property is improperly formed, then delete it. | |
320 */ | |
321 | |
322 if ((result != Success) || (actualFormat != 8) || (actualType != XA_STRING)) | |
323 { | |
324 if (regProp != NULL) | |
325 XFree(regProp); | |
326 XDeleteProperty(dpy, RootWindow(dpy, 0), registryProperty); | |
327 return 0; | |
328 } | |
329 | |
330 /* | |
331 * Scan the property for the desired name. | |
332 */ | |
333 | |
334 returnValue = None; | |
335 entry = NULL; /* Not needed, but eliminates compiler warning. */ | |
336 for (p = regProp; (p - regProp) < numItems; ) | |
337 { | |
338 entry = p; | |
339 while ((*p != 0) && (!isspace(*p))) | |
340 p++; | |
341 if ((*p != 0) && (strcasecmp(name, p + 1) == 0)) | |
342 { | |
343 sscanf(entry, "%x", (uint*) &returnValue); | |
344 break; | |
345 } | |
346 while (*p != 0) | |
347 p++; | |
348 p++; | |
349 } | |
350 | |
351 if (loose != NULL && returnValue == None && !IsSerialName(name)) | |
352 { | |
353 for (p = regProp; (p - regProp) < numItems; ) | |
354 { | |
355 entry = p; | |
356 while ((*p != 0) && (!isspace(*p))) | |
357 p++; | |
358 if ((*p != 0) && IsSerialName(p + 1) | |
359 && (strncmp(name, p + 1, strlen(name)) == 0)) | |
360 { | |
361 sscanf(entry, "%x", (uint*) &returnValue); | |
362 *loose = strdup(p + 1); | |
363 break; | |
364 } | |
365 while (*p != 0) | |
366 p++; | |
367 p++; | |
368 } | |
369 } | |
370 | |
371 /* | |
372 * Delete the property, if that is desired (copy down the | |
373 * remainder of the registry property to overlay the deleted | |
374 * info, then rewrite the property). | |
375 */ | |
376 | |
377 if ((delete) && (returnValue != None)) | |
378 { | |
379 int count; | |
380 | |
381 while (*p != 0) | |
382 p++; | |
383 p++; | |
384 count = numItems - (p-regProp); | |
385 if (count > 0) | |
386 memcpy(entry, p, count); | |
387 XChangeProperty(dpy, RootWindow(dpy, 0), registryProperty, XA_STRING, | |
388 8, PropModeReplace, regProp, | |
389 (int) (numItems - (p-entry))); | |
390 XSync(dpy, False); | |
391 } | |
392 | |
393 XFree(regProp); | |
394 return returnValue; | |
395 } | |
396 | |
397 static char * | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
398 SendEventProc( |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
399 Display *dpy, |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
400 XEvent *eventPtr, /* Information about event. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
401 int expected, /* The one were waiting for */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
402 int *code) /* Return code. 0 => OK */ |
7 | 403 { |
404 unsigned char *propInfo; | |
405 unsigned char *p; | |
406 int result, actualFormat; | |
407 int retCode; | |
408 unsigned long numItems, bytesAfter; | |
409 Atom actualType; | |
410 | |
411 if ((eventPtr->xproperty.atom != commProperty) | |
412 || (eventPtr->xproperty.state != PropertyNewValue)) | |
413 { | |
414 return; | |
415 } | |
416 | |
417 /* | |
418 * Read the comm property and delete it. | |
419 */ | |
420 | |
421 propInfo = NULL; | |
422 result = XGetWindowProperty(dpy, commWindow, commProperty, 0, | |
423 MAX_PROP_WORDS, True, XA_STRING, &actualType, | |
424 &actualFormat, &numItems, &bytesAfter, | |
425 &propInfo); | |
426 | |
427 /* | |
428 * If the property doesn't exist or is improperly formed | |
429 * then ignore it. | |
430 */ | |
431 | |
432 if ((result != Success) || (actualType != XA_STRING) | |
433 || (actualFormat != 8)) | |
434 { | |
435 if (propInfo != NULL) | |
436 { | |
437 XFree(propInfo); | |
438 } | |
439 return; | |
440 } | |
441 | |
442 /* | |
443 * Several commands and results could arrive in the property at | |
444 * one time; each iteration through the outer loop handles a | |
445 * single command or result. | |
446 */ | |
447 | |
448 for (p = propInfo; (p - propInfo) < numItems; ) | |
449 { | |
450 /* | |
451 * Ignore leading NULs; each command or result starts with a | |
452 * NUL so that no matter how badly formed a preceding command | |
453 * is, we'll be able to tell that a new command/result is | |
454 * starting. | |
455 */ | |
456 | |
457 if (*p == 0) | |
458 { | |
459 p++; | |
460 continue; | |
461 } | |
462 | |
463 if ((*p == 'r') && (p[1] == 0)) | |
464 { | |
465 int serial, gotSerial; | |
466 char *res; | |
467 | |
468 /* | |
469 * This is a reply to some command that we sent out. Iterate | |
470 * over all of its options. Stop when we reach the end of the | |
471 * property or something that doesn't look like an option. | |
472 */ | |
473 | |
474 p += 2; | |
475 gotSerial = 0; | |
476 res = ""; | |
477 retCode = 0; | |
478 while (((p-propInfo) < numItems) && (*p == '-')) | |
479 { | |
480 switch (p[1]) | |
481 { | |
482 case 'r': | |
483 if (p[2] == ' ') | |
484 res = p + 3; | |
485 break; | |
486 case 's': | |
487 if (sscanf(p + 2, " %d", &serial) == 1) | |
488 gotSerial = 1; | |
489 break; | |
490 case 'c': | |
491 if (sscanf(p + 2, " %d", &retCode) != 1) | |
492 retCode = 0; | |
493 break; | |
494 } | |
495 while (*p != 0) | |
496 p++; | |
497 p++; | |
498 } | |
499 | |
500 if (!gotSerial) | |
501 continue; | |
502 | |
503 if (code != NULL) | |
504 *code = retCode; | |
505 return serial == expected ? strdup(res) : NULL; | |
506 } | |
507 else | |
508 { | |
509 /* | |
510 * Didn't recognize this thing. Just skip through the next | |
511 * null character and try again. | |
25402 | 512 * Also, throw away commands that we can't process anyway. |
7 | 513 */ |
514 | |
515 while (*p != 0) | |
516 p++; | |
517 p++; | |
518 } | |
519 } | |
520 XFree(propInfo); | |
521 } | |
522 | |
523 /* | |
524 * AppendPropCarefully -- | |
525 * | |
526 * Append a given property to a given window, but set up | |
527 * an X error handler so that if the append fails this | |
528 * procedure can return an error code rather than having | |
529 * Xlib panic. | |
530 * | |
531 * Return: | |
532 * 0 on OK - -1 on error | |
533 *-------------------------------------------------------------- | |
534 */ | |
535 | |
536 static int | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
537 AppendPropCarefully( |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
538 Display *dpy, /* Display on which to operate. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
539 Window window, /* Window whose property is to |
7 | 540 * be modified. */ |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
541 Atom property, /* Name of property. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
542 char *value, /* Characters to append to property. */ |
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
543 int length) /* How much to append */ |
7 | 544 { |
545 XErrorHandler old_handler; | |
546 | |
547 old_handler = XSetErrorHandler(x_error_check); | |
548 got_x_error = FALSE; | |
549 XChangeProperty(dpy, window, property, XA_STRING, 8, | |
550 PropModeAppend, value, length); | |
551 XSync(dpy, False); | |
552 (void) XSetErrorHandler(old_handler); | |
553 return got_x_error ? -1 : 0; | |
554 } | |
555 | |
556 | |
557 /* | |
558 * Another X Error handler, just used to check for errors. | |
559 */ | |
560 /* ARGSUSED */ | |
561 static int | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
562 x_error_check(Display *dpy, XErrorEvent *error_event) |
7 | 563 { |
564 got_x_error = TRUE; | |
565 return 0; | |
566 } | |
567 | |
568 /* | |
569 * Check if "str" looks like it had a serial number appended. | |
570 * Actually just checks if the name ends in a digit. | |
571 */ | |
572 static int | |
7837
33ba2adb6065
commit https://github.com/vim/vim/commit/b638a7be952544ceb03052c25b84224577a6494b
Christian Brabandt <cb@256bit.org>
parents:
7807
diff
changeset
|
573 IsSerialName(char *str) |
7 | 574 { |
575 int len = strlen(str); | |
576 | |
577 return (len > 1 && isdigit(str[len - 1])); | |
578 } |