Mercurial > hg > xemacs-beta
annotate lib-src/winclient.c @ 5797:a1808d52a34a
If the position of a window's cached point is deleted, use buffer point instead
src/ChangeLog addition:
2014-06-17 Aidan Kehoe <kehoea@parhasard.net>
* extents.h:
* window.c:
* window.c (unshow_buffer):
* window.c (Fset_window_buffer):
Use extents, rather than markers, for the window buffer point
cache, so that when the text containing that window buffer point
is deleted, the window display code uses the buffer's actual point
instead of the position that the marker had been moved to.
Fixes Michael Heinrich's problem of
http://mid.gmane.org/6zr42uxtf5.fsf@elektra.science-computing.de ,
introduced by Ben's patch of
https://bitbucket.org/xemacs/xemacs/commits/047d37eb70d70f43803 .
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Tue, 17 Jun 2014 20:55:45 +0100 |
parents | 308d34e9f07d |
children | 68639fb08af8 |
rev | line source |
---|---|
853 | 1 /* DDE client for XEmacs. |
2 Copyright (C) 2002 Alastair J. Houghton | |
3 | |
4 This file is part of XEmacs. | |
5 | |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
6 XEmacs is free software: you can redistribute it and/or modify it |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
7 under the terms of the GNU General Public License as published by the |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
8 Free Software Foundation, either version 3 of the License, or (at your |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
9 option) any later version. |
853 | 10 |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
14 for more details. |
853 | 15 |
5402
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
16 You should have received a copy of the GNU General Public License |
308d34e9f07d
Changed bulk of GPLv2 or later files identified by script
Mats Lidell <matsl@xemacs.org>
parents:
5030
diff
changeset
|
17 along with XEmacs. If not, see <http://www.gnu.org/licenses/>. */ |
853 | 18 |
19 /* Synched up with: Not in FSF. */ | |
20 | |
21 /* -- Includes -------------------------------------------------------------- */ | |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 # include <config.h> | |
25 #endif | |
2993 | 26 #include <windows.h> |
27 #include <ddeml.h> | |
853 | 28 #include <stdlib.h> |
29 #include <stdio.h> | |
30 #include <ctype.h> | |
31 #include <errno.h> | |
32 | |
5030 | 33 #ifdef __CYGWIN__ |
34 #include <stdlib.h> | |
35 #include <unistd.h> | |
36 #endif | |
37 | |
853 | 38 static void error (const char* s1, const char* s2); |
39 static void fatal (const char *s1, const char *s2); | |
40 static void * xmalloc (size_t size); | |
41 static char * getNextArg (const char **ptr, unsigned *len); | |
42 | |
43 /* -- Post-Include Defines -------------------------------------------------- */ | |
44 | |
45 /* Timeouts & delays */ | |
5030 | 46 #define CONNECT_RETRIES 20 |
853 | 47 #define CONNECT_DELAY 500 /* ms */ |
48 #define TRANSACTION_TIMEOUT 5000 /* ms */ | |
49 #define MAX_INPUT_IDLE_WAIT INFINITE /* ms */ | |
50 | |
51 /* DDE Strings */ | |
52 #define SERVICE_NAME "XEmacs" | |
53 #define TOPIC_NAME "System" | |
54 #define COMMAND_FORMAT "[open(\"%s%s\")]" | |
55 | |
56 /* XEmacs program name */ | |
5030 | 57 #define GENERIC_PROGRAM EMACS_PROGNAME ".exe" |
58 #define VERSIONED_PROGRAM EMACS_PROGNAME "-" EMACS_VERSION ".exe" | |
853 | 59 |
60 /* -- Constants ------------------------------------------------------------- */ | |
61 | |
62 /* -- Global Variables ------------------------------------------------------ */ | |
63 | |
64 HINSTANCE hInstance; | |
65 DWORD idInst = 0; | |
66 | |
67 /* -- Function Declarations ------------------------------------------------- */ | |
68 | |
69 HDDEDATA CALLBACK ddeCallback (UINT uType, UINT uFmt, HCONV hconv, | |
70 HSZ hsz1, HSZ hsz2, HDDEDATA hdata, | |
71 DWORD dwData1, DWORD dwData2); | |
72 | |
73 int WINAPI WinMain (HINSTANCE hInst, | |
74 HINSTANCE hPrev, | |
75 LPSTR lpCmdLine, | |
76 int nCmdShow); | |
77 | |
78 static HCONV openConversation (void); | |
79 static void closeConversation (HCONV hConv); | |
80 static int doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2); | |
81 static int parseCommandLine (HCONV hConv, LPSTR lpszCommandLine); | |
82 | |
83 /* -- Function Definitions -------------------------------------------------- */ | |
84 | |
85 /* | |
86 * Name : ddeCallback | |
87 * Function: Gets called by DDEML. | |
88 * | |
89 */ | |
90 | |
91 HDDEDATA CALLBACK | |
92 ddeCallback (UINT uType, UINT uFmt, HCONV hconv, | |
93 HSZ hsz1, HSZ hsz2, HDDEDATA hdata, | |
94 DWORD dwData1, DWORD dwData2) | |
95 { | |
96 return (HDDEDATA) NULL; | |
97 } | |
98 | |
99 /* | |
100 * Name : WinMain | |
101 * Function: The program's entry point function. | |
102 * | |
103 */ | |
104 | |
105 int WINAPI | |
106 WinMain (HINSTANCE hInst, | |
107 HINSTANCE hPrev, | |
108 LPSTR lpCmdLine, | |
109 int nCmdShow) | |
110 { | |
111 HCONV hConv; | |
112 int ret = 0; | |
113 UINT uiRet; | |
5030 | 114 |
853 | 115 /* Initialise the DDEML library */ |
116 uiRet = DdeInitialize (&idInst, | |
117 (PFNCALLBACK) ddeCallback, | |
118 APPCMD_CLIENTONLY | |
119 |CBF_FAIL_ALLSVRXACTIONS, | |
120 0); | |
121 | |
122 if (uiRet != DMLERR_NO_ERROR) | |
123 { | |
124 MessageBox (NULL, "Could not initialise DDE management library.", | |
125 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
126 | |
127 return 1; | |
128 } | |
129 | |
130 /* Open a conversation */ | |
131 hConv = openConversation (); | |
132 | |
133 if (hConv) | |
134 { | |
135 /* OK. Next, we need to parse the command line. */ | |
136 ret = parseCommandLine (hConv, lpCmdLine); | |
137 | |
138 /* Close the conversation */ | |
139 closeConversation (hConv); | |
140 } | |
5030 | 141 |
853 | 142 DdeUninitialize (idInst); |
143 | |
144 return ret; | |
145 } | |
146 | |
147 /* | |
148 * Name : openConversation | |
149 * Function: Start a conversation. | |
150 * | |
151 */ | |
152 | |
153 static HCONV | |
154 openConversation (void) | |
155 { | |
156 HSZ hszService = NULL, hszTopic = NULL; | |
157 HCONV hConv = NULL; | |
158 | |
159 /* Get the application (service) name */ | |
160 hszService = DdeCreateStringHandle (idInst, | |
161 SERVICE_NAME, | |
162 CP_WINANSI); | |
163 | |
164 if (!hszService) | |
165 { | |
166 MessageBox (NULL, "Could not create string handle for service.", | |
167 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
168 | |
169 goto error; | |
170 } | |
5030 | 171 |
853 | 172 /* Get the topic name */ |
173 hszTopic = DdeCreateStringHandle (idInst, | |
174 TOPIC_NAME, | |
175 CP_WINANSI); | |
176 | |
177 if (!hszTopic) | |
178 { | |
179 MessageBox (NULL, "Could not create string handle for topic.", | |
180 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
181 | |
182 goto error; | |
183 } | |
184 | |
185 /* Try to connect */ | |
186 hConv = DdeConnect (idInst, hszService, hszTopic, NULL); | |
187 | |
188 if (!hConv) | |
189 { | |
190 STARTUPINFO sti; | |
191 PROCESS_INFORMATION pi; | |
192 int n; | |
5030 | 193 |
853 | 194 /* Try to start the program */ |
195 ZeroMemory (&sti, sizeof (sti)); | |
196 sti.cb = sizeof (sti); | |
5030 | 197 if (!CreateProcess (NULL, GENERIC_PROGRAM, NULL, NULL, FALSE, 0, |
198 NULL, NULL, &sti, &pi) && | |
199 !CreateProcess (NULL, VERSIONED_PROGRAM, NULL, NULL, FALSE, 0, | |
853 | 200 NULL, NULL, &sti, &pi)) |
201 { | |
202 MessageBox (NULL, "Could not start process.", | |
203 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
204 | |
205 goto error; | |
206 } | |
207 | |
208 /* Wait for the process to enter an idle state */ | |
209 WaitForInputIdle (pi.hProcess, MAX_INPUT_IDLE_WAIT); | |
210 | |
211 /* Close the handles */ | |
212 CloseHandle (pi.hThread); | |
213 CloseHandle (pi.hProcess); | |
5030 | 214 |
853 | 215 /* Try to connect */ |
4464
61aff09a7589
Increase DDE connection retries because waiting for XEmacs to start
Vin Shelton <acs@xemacs.org>
parents:
2993
diff
changeset
|
216 for (n = 0; n < CONNECT_RETRIES; n++) |
853 | 217 { |
218 Sleep (CONNECT_DELAY); | |
5030 | 219 |
853 | 220 hConv = DdeConnect (idInst, hszService, hszTopic, NULL); |
221 | |
222 if (hConv) | |
223 break; | |
224 } | |
225 | |
226 if (!hConv) | |
227 { | |
228 /* Still couldn't connect. */ | |
229 MessageBox (NULL, "Could not connect to DDE server.", | |
230 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
231 | |
232 goto error; | |
233 } | |
234 } | |
235 | |
236 /* Release the string handles */ | |
237 DdeFreeStringHandle (idInst, hszService); | |
238 DdeFreeStringHandle (idInst, hszTopic); | |
239 | |
240 return hConv; | |
5030 | 241 |
853 | 242 error: |
243 if (hConv) | |
244 DdeDisconnect (hConv); | |
245 if (hszService) | |
246 DdeFreeStringHandle (idInst, hszService); | |
247 if (hszTopic) | |
248 DdeFreeStringHandle (idInst, hszTopic); | |
249 | |
250 return NULL; | |
251 } | |
252 | |
253 /* | |
254 * Name : closeConversation | |
255 * Function: Close a conversation. | |
256 * | |
257 */ | |
258 | |
259 static void | |
260 closeConversation (HCONV hConv) | |
261 { | |
262 /* Shut down */ | |
263 DdeDisconnect (hConv); | |
264 } | |
265 | |
266 /* | |
267 * Name : doFile | |
268 * Function: Process a file. | |
269 * | |
270 */ | |
271 | |
272 int | |
273 doFile (HCONV hConv, LPSTR lpszFileName1, LPSTR lpszFileName2) | |
274 { | |
275 char *buf = NULL; | |
276 unsigned len; | |
5030 | 277 |
853 | 278 /* Calculate the buffer length */ |
279 len = strlen (lpszFileName1) + strlen (lpszFileName2) | |
280 + strlen (COMMAND_FORMAT); | |
5030 | 281 |
853 | 282 /* Allocate a buffer */ |
283 buf = (char *) xmalloc (len); | |
284 | |
285 if (!buf) | |
286 { | |
287 MessageBox (NULL, "Not enough memory.", | |
288 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
289 | |
290 return 1; | |
291 } | |
292 | |
293 /* Build the command */ | |
294 len = wsprintf (buf, COMMAND_FORMAT, lpszFileName1, lpszFileName2); | |
5030 | 295 len++; |
853 | 296 |
297 /* OK. We're connected. Send the message. */ | |
298 DdeClientTransaction (buf, len, hConv, NULL, | |
299 0, XTYP_EXECUTE, TRANSACTION_TIMEOUT, NULL); | |
300 | |
301 free (buf); | |
5030 | 302 |
853 | 303 return 0; |
304 } | |
305 | |
306 /* | |
307 * Name : getNextArg | |
308 * Function: Retrieve the next command line argument. | |
309 * | |
310 */ | |
311 | |
312 static char * | |
313 getNextArg (const char **ptr, unsigned *len) | |
314 { | |
315 int in_quotes = 0, quit = 0, all_in_quotes = 0; | |
316 const char *p = *ptr, *start; | |
317 char *buf = NULL; | |
318 unsigned length = 0; | |
319 | |
320 /* Skip whitespace */ | |
321 while (*p && isspace (*p)) | |
322 p++; | |
323 | |
324 /* If this is the end, return NULL */ | |
325 if (!*p) | |
326 return NULL; | |
5030 | 327 |
853 | 328 /* Remember where we are */ |
329 start = p; | |
5030 | 330 |
853 | 331 /* Find the next whitespace character outside quotes */ |
332 if (*p == '"') | |
333 all_in_quotes = 1; | |
5030 | 334 |
853 | 335 while (*p && !quit) |
336 { | |
337 switch (*p) | |
338 { | |
339 case '"': | |
340 in_quotes = 1 - in_quotes; | |
341 p++; | |
342 break; | |
343 | |
344 case '\\': | |
345 if (!in_quotes) | |
346 all_in_quotes = 0; | |
5030 | 347 |
853 | 348 p++; |
349 | |
350 if (!*p) | |
351 break; | |
352 | |
353 p++; | |
354 break; | |
355 | |
356 default: | |
357 if (isspace (*p) && !in_quotes) | |
358 quit = 1; | |
359 else if (!in_quotes) | |
360 all_in_quotes = 0; | |
361 | |
362 if (!quit) | |
363 p++; | |
364 } | |
365 } | |
366 | |
367 /* Work out the length */ | |
368 length = p - start; | |
369 | |
370 /* Strip quotes if the argument is completely quoted */ | |
371 if (all_in_quotes) | |
372 { | |
373 start++; | |
374 length -= 2; | |
375 } | |
5030 | 376 |
853 | 377 /* Copy */ |
378 buf = (char *) xmalloc (length + 1); | |
379 | |
380 if (!buf) | |
381 return NULL; | |
5030 | 382 |
853 | 383 strncpy (buf, start, length); |
384 buf[length] = '\0'; | |
385 | |
386 /* Return the pointer and length */ | |
387 *ptr = p; | |
388 *len = length; | |
389 | |
390 return buf; | |
391 } | |
392 | |
393 /* | |
394 * Name : parseCommandLine | |
395 * Function: Process the command line. This program accepts a list of strings | |
396 * : (which may contain wildcards) representing filenames. | |
397 * | |
398 */ | |
399 | |
400 int | |
401 parseCommandLine (HCONV hConv, LPSTR lpszCommandLine) | |
402 { | |
403 char *fullpath, *filepart; | |
404 char *arg; | |
405 unsigned len, pathlen; | |
406 int ret = 0; | |
407 HANDLE hFindFile = NULL; | |
408 WIN32_FIND_DATA wfd; | |
409 | |
410 /* Retrieve arguments */ | |
411 while ((arg = getNextArg ((const char**)&lpszCommandLine, &len)) != NULL) | |
412 { | |
5030 | 413 fullpath = NULL; |
414 #ifdef __CYGWIN__ | |
415 /* If the filename is not an absolute path, | |
416 add the current directory to the pathname */ | |
417 if (*arg != '/') | |
418 { | |
419 len = pathconf(".", _PC_PATH_MAX); | |
420 fullpath = (char *) xmalloc (len+1); | |
421 if (!fullpath) | |
422 { | |
423 MessageBox (NULL, "Not enough memory.", "winclient", | |
424 MB_ICONEXCLAMATION | MB_OK); | |
425 ret = 1; | |
426 break; | |
427 } | |
428 if (!getcwd(fullpath, (size_t)len)) | |
429 { | |
430 MessageBox (NULL, "Could not retrieve current directory.", | |
431 "winclient", MB_ICONEXCLAMATION | MB_OK); | |
432 ret = 1; | |
433 break; | |
434 } | |
435 /* Append trailing slash */ | |
436 strcat(fullpath, "/"); | |
437 ret = doFile (hConv, fullpath, arg); | |
438 } | |
439 else | |
440 { | |
441 /* The arg has already been expanded, so pass it as it is */ | |
442 ret = doFile (hConv, "", arg); | |
443 } | |
444 #else | |
853 | 445 /* First find the canonical path name */ |
446 fullpath = filepart = NULL; | |
447 pathlen = GetFullPathName (arg, 0, fullpath, &filepart); | |
448 | |
449 fullpath = (char *) xmalloc (pathlen); | |
450 | |
451 if (!fullpath) | |
452 { | |
453 MessageBox (NULL, "Not enough memory.", "winclient", | |
454 MB_ICONEXCLAMATION | MB_OK); | |
455 ret = 1; | |
456 break; | |
457 } | |
458 | |
459 GetFullPathName (arg, pathlen, fullpath, &filepart); | |
460 | |
461 /* Find the first matching file */ | |
462 hFindFile = FindFirstFile (arg, &wfd); | |
463 | |
464 if (hFindFile == INVALID_HANDLE_VALUE) | |
465 ret = doFile (hConv, fullpath, ""); | |
466 else | |
467 { | |
468 /* Chop off the file part from the full path name */ | |
469 if (filepart) | |
470 *filepart = '\0'; | |
471 | |
472 /* For each matching file */ | |
473 do | |
474 { | |
475 /* Process it */ | |
476 ret = doFile (hConv, fullpath, wfd.cFileName); | |
477 | |
478 if (ret) | |
479 break; | |
480 } | |
481 while (FindNextFile (hFindFile, &wfd)); | |
482 | |
483 FindClose (hFindFile); | |
484 } | |
5030 | 485 #endif |
853 | 486 /* Release the path name buffers */ |
5030 | 487 if (fullpath) |
488 free (fullpath); | |
853 | 489 free (arg); |
490 | |
491 if (ret) | |
492 break; | |
493 } | |
494 | |
495 return ret; | |
496 } | |
497 | |
498 static void | |
499 fatal (const char *s1, const char *s2) | |
500 { | |
501 error (s1, s2); | |
502 exit (1); | |
503 } | |
504 | |
505 /* Print error message. `s1' is printf control string, `s2' is arg for it. */ | |
506 static void | |
507 error (const char* s1, const char* s2) | |
508 { | |
509 fprintf (stderr, "winclient: "); | |
510 fprintf (stderr, s1, s2); | |
511 fprintf (stderr, "\n"); | |
512 } | |
513 | |
514 /* Like malloc but get fatal error if memory is exhausted. */ | |
515 | |
516 static void * | |
517 xmalloc (size_t size) | |
518 { | |
519 void *result = malloc (size); | |
520 if (result == NULL) | |
521 fatal ("virtual memory exhausted", (char *) 0); | |
522 return result; | |
523 } |