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