Mercurial > hg > xemacs-beta
comparison lib-src/run.c @ 388:aabb7f5b1c81 r21-2-9
Import from CVS: tag r21-2-9
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:09:42 +0200 |
parents | |
children | 74fd4e045ea6 |
comparison
equal
deleted
inserted
replaced
387:f892a9d0bb8d | 388:aabb7f5b1c81 |
---|---|
1 /* run -- Wrapper program for console mode programs under Windows(TM) | |
2 * Copyright (C) 1998 Charles S. Wilson | |
3 * | |
4 * This program is free software; you can redistribute it and/or | |
5 * modify it under the terms of the GNU General Public License | |
6 * as published by the Free Software Foundation; either version 2 | |
7 * of the License, or (at your option) any later version. | |
8 * | |
9 * This program is distributed in the hope that it will be useful, | |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 * GNU General Public License for more details. | |
13 * | |
14 * You should have received a copy of the GNU General Public License | |
15 * along with this program; if not, write to the Free Software | |
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
17 */ | |
18 | |
19 /* | |
20 * This program is based on the runemacs.c distributed with XEmacs 21.0 | |
21 * | |
22 * Simple program to start gnu-win32 X11 programs (and native XEmacs) | |
23 * with its console window hidden. | |
24 * | |
25 * This program is provided purely for convenience, since most users will | |
26 * use XEmacs in windowing (GUI) mode, and will not want to have an extra | |
27 * console window lying around. Ditto for desktop shortcuts to gnu-win32 | |
28 * X11 executables. | |
29 */ | |
30 | |
31 | |
32 #define WIN32 | |
33 | |
34 #include <windows.h> | |
35 #include <string.h> | |
36 #include <malloc.h> | |
37 #include <stdlib.h> | |
38 #include <stdio.h> | |
39 #include <stdarg.h> | |
40 | |
41 #include "run.h" | |
42 | |
43 #if defined(__CYGWIN__) | |
44 #include <sys/types.h> | |
45 #include <sys/stat.h> | |
46 #include <sys/cygwin.h> | |
47 #include <sys/unistd.h> | |
48 WinMainCRTStartup() { mainCRTStartup(); } | |
49 #else | |
50 #include <direct.h> | |
51 #endif | |
52 | |
53 | |
54 char buffer[1024]; | |
55 | |
56 int WINAPI | |
57 WinMain (HINSTANCE hSelf, HINSTANCE hPrev, LPSTR cmdline, int nShow) | |
58 { | |
59 int wait_for_child = FALSE; | |
60 int compact_invocation = FALSE; | |
61 DWORD ret_code = 0; | |
62 | |
63 | |
64 char execname[FILENAME_MAX]; | |
65 char execpath[MAX_PATH]; | |
66 char* argv[MAX_ARGS+1]; /* leave extra slot for compact_invocation argv[0] */ | |
67 int argc; | |
68 int i,j; | |
69 char exec[MAX_PATH + FILENAME_MAX + 100]; | |
70 char cmdline2[MAX_ARGS * MAX_PATH]; | |
71 | |
72 compact_invocation = get_exec_name_and_path(execname,execpath); | |
73 | |
74 if (compact_invocation) | |
75 { | |
76 argv[0] = execname; | |
77 argc = parse_cmdline_to_arg_array(&(argv[1]),cmdline); | |
78 argc++; | |
79 } | |
80 else | |
81 { | |
82 argc = parse_cmdline_to_arg_array(argv,cmdline); | |
83 if (argc >= 1) | |
84 strcpy(execname,argv[0]); | |
85 } | |
86 /* at this point, execpath is defined, as are argv[] and execname */ | |
87 #ifdef DEBUG | |
88 j = sprintf(buffer,"\nexecname : %s\nexecpath : %s\n",execname,execpath); | |
89 for (i = 0; i < argc; i++) | |
90 j += sprintf(buffer+j,"argv[%d]\t: %s\n",i,argv[i]); | |
91 Trace((buffer)); | |
92 #endif | |
93 | |
94 if (execname == NULL) | |
95 error("you must supply a program name to run"); | |
96 | |
97 #if defined(__CYGWIN__) | |
98 /* this insures that we search for symlinks before .exe's */ | |
99 if (compact_invocation) | |
100 strip_exe(execname); | |
101 #endif | |
102 | |
103 process_execname(exec,execname,execpath); | |
104 Trace(("exec\t%s\nexecname\t%s\nexecpath\t%s\n", | |
105 exec,execname,execpath)); | |
106 | |
107 wait_for_child = build_cmdline(cmdline2,exec,argc,argv); | |
108 Trace((cmdline2)); | |
109 | |
110 xemacs_special(exec); | |
111 ret_code = start_child(cmdline2,wait_for_child); | |
112 if (compact_invocation) | |
113 for (i = 1; i < argc; i++) // argv[0] was not malloc'ed | |
114 free(argv[i]); | |
115 else | |
116 for (i = 0; i < argc; i++) | |
117 free(argv[i]); | |
118 return (int) ret_code; | |
119 } | |
120 int start_child(char* cmdline, int wait_for_child) | |
121 { | |
122 STARTUPINFO start; | |
123 SECURITY_ATTRIBUTES sec_attrs; | |
124 SECURITY_DESCRIPTOR sec_desc; | |
125 PROCESS_INFORMATION child; | |
126 int retval; | |
127 | |
128 memset (&start, 0, sizeof (start)); | |
129 start.cb = sizeof (start); | |
130 start.dwFlags = STARTF_USESHOWWINDOW; | |
131 start.wShowWindow = SW_HIDE; | |
132 | |
133 sec_attrs.nLength = sizeof (sec_attrs); | |
134 sec_attrs.lpSecurityDescriptor = NULL; | |
135 sec_attrs.bInheritHandle = FALSE; | |
136 | |
137 if (CreateProcess (NULL, cmdline, &sec_attrs, NULL, TRUE, 0, | |
138 NULL, NULL, &start, &child)) | |
139 { | |
140 if (wait_for_child) | |
141 { | |
142 WaitForSingleObject (child.hProcess, INFINITE); | |
143 GetExitCodeProcess (child.hProcess, &retval); | |
144 } | |
145 CloseHandle (child.hThread); | |
146 CloseHandle (child.hProcess); | |
147 } | |
148 else | |
149 error("could not start %s",cmdline); | |
150 return retval; | |
151 } | |
152 void xemacs_special(char* exec) | |
153 { | |
154 /* | |
155 * if we're trying to run xemacs, AND this file was in %emacs_dir%\bin, | |
156 * then set emacs_dir environment variable | |
157 */ | |
158 char* p; | |
159 char* p2; | |
160 char exec2[MAX_PATH + FILENAME_MAX + 100]; | |
161 char tmp[MAX_PATH + FILENAME_MAX + 100]; | |
162 strcpy(exec2,exec); | |
163 /* this depends on short-circuit evaluation */ | |
164 if ( ((p = strrchr(exec2,'\\')) && stricmp(p,"\\xemacs") == 0) || | |
165 ((p = strrchr(exec2,'/')) && stricmp(p,"/xemacs") == 0) || | |
166 ((p = strrchr(exec2,'\\')) && stricmp(p,"\\xemacs.exe") == 0) || | |
167 ((p = strrchr(exec2,'/')) && stricmp(p,"/xemacs.exe") == 0) ) | |
168 { | |
169 if ( ((p2 = strrchr(p, '\\')) && stricmp(p2, "\\bin") == 0) || | |
170 ((p2 = strrchr(p, '/')) && stricmp(p2, "/bin") == 0) ) | |
171 { | |
172 *p2 = '\0'; | |
173 #if defined(__CYGWIN__) | |
174 CYGWIN_CONV_TO_POSIX_PATH((exec2,tmp)); | |
175 strcpy(exec2,tmp); | |
176 #else /* NATIVE xemacs DOS-style paths with forward slashes */ | |
177 for (p = exec2; *p; p++) | |
178 if (*p == '\\') *p = '/'; | |
179 #endif | |
180 SetEnvironmentVariable ("emacs_dir", exec2); | |
181 } | |
182 } | |
183 } | |
184 int build_cmdline(char* new_cmdline, char* exec, int argc, char* argv[]) | |
185 { | |
186 int retval = FALSE; | |
187 int first_arg = 1; | |
188 int i; | |
189 int char_cnt = 0; | |
190 /* | |
191 * look for "-wait" as first true argument; we'll apply that ourselves | |
192 */ | |
193 if ((argc >= 2) && (stricmp(argv[1],"-wait") == 0)) | |
194 { | |
195 retval = TRUE; | |
196 first_arg++; | |
197 } | |
198 | |
199 char_cnt = strlen(exec); | |
200 for (i = first_arg; i < argc; i++) | |
201 char_cnt += strlen(argv[i]); | |
202 if (char_cnt > MAX_ARGS*MAX_PATH) /* then we ran out of room */ | |
203 error("command line too long -\n%s",new_cmdline); | |
204 | |
205 strcpy(new_cmdline,exec); | |
206 for (i = first_arg; i < argc; i++) | |
207 { | |
208 strcat(new_cmdline," "); | |
209 strcat(new_cmdline,argv[i]); | |
210 } | |
211 return retval; | |
212 } | |
213 /* process exec_arg : if it | |
214 * NATIVE: | |
215 * 1) starts with '\\' or '/', it's a root-path and leave it alone | |
216 * 2) starts with 'x:\\' or 'x:/', it's a root-path and leave it alone | |
217 * 3) starts with '.\\' or './', two possible meanings: | |
218 * 1) exec is in the current directory | |
219 * 2) exec in same directory as this program | |
220 * 4) otherwise, search path (and _prepend_ "." to the path!!!) | |
221 * 5) convert all '/' to '\\' | |
222 * CYGWIN | |
223 * 1) starts with '\\' or '/', it's a root-path and leave it alone | |
224 * 2) starts with 'x:\\' or 'x:/', it's a root-path and leave it alone | |
225 * 3) starts with '.\\' or './', two possible meanings: | |
226 * 1) exec is in the current directory | |
227 * 2) exec in same directory as this program | |
228 * 4) otherwise, search path (and _prepend_ "." to the path!!!) | |
229 * 5) convert to cygwin-style path to resolve symlinks within the pathspec | |
230 * 6) check filename: if it's a symlink, resolve it by peeking inside | |
231 * 7) convert to win32-style path+filename since we're using Windows | |
232 * createProcess() to launch | |
233 */ | |
234 void process_execname(char *exec, const char* execname,const char* execpath ) | |
235 { | |
236 char* orig_pathlist; | |
237 char* pathlist; | |
238 char exec_tmp[MAX_PATH + FILENAME_MAX + 100]; | |
239 char exec_tmp2[MAX_PATH + FILENAME_MAX + 100]; | |
240 char buf[MAX_PATH + FILENAME_MAX + 100]; | |
241 int i,j; | |
242 | |
243 int len = 0; | |
244 /* | |
245 * STARTS WITH / or \ | |
246 * execpath NOT used | |
247 */ | |
248 if ((execname[0] == '\\') || (execname[0] == '/')) | |
249 { | |
250 #if defined(__CYGWIN__) | |
251 strcpy(exec_tmp,execname); | |
252 #else | |
253 exec_tmp[0] = ((char) (_getdrive() + ((int) 'A') - 1)); | |
254 exec_tmp[1] = ':'; | |
255 exec_tmp[2] = '\0'; | |
256 strcat(exec_tmp,execname); | |
257 #endif | |
258 Trace(("/ -\nexec_tmp\t%s\nexecname\t%s\nexecpath\t%s\n", | |
259 exec_tmp,execname,execpath)); | |
260 if (! fileExistsMulti(exec_tmp2,NULL,exec_tmp,exts,NUM_EXTENSIONS) ) | |
261 { | |
262 j = 0; | |
263 for (i = 0; i < NUM_EXTENSIONS; i++) | |
264 j += sprintf(buf + j," [%d]: %s\n",i+1,exts[i]); | |
265 error("Couldn't locate %s\nI tried appending the following " | |
266 "extensions: \n%s",exec_tmp,buf); | |
267 } | |
268 Trace((exec_tmp2)); | |
269 } | |
270 /* | |
271 * STARTS WITH x:\ or x:/ | |
272 * execpath NOT used | |
273 */ | |
274 else if ((strlen(execname) > 3) && // avoid boundary errors | |
275 (execname[1] == ':') && | |
276 ((execname[2] == '\\') || (execname[2] == '/'))) | |
277 { | |
278 strcpy(exec_tmp,execname); | |
279 Trace(("x: -\nexec_tmp\t%s\nexecname\t%s\nexecpath\t%s\n", | |
280 exec_tmp,execname,execpath)); | |
281 if (! fileExistsMulti(exec_tmp2,NULL,exec_tmp,exts,NUM_EXTENSIONS) ) | |
282 { | |
283 j = 0; | |
284 for (i = 0; i < NUM_EXTENSIONS; i++) | |
285 j += sprintf(buf + j," [%d]: %s\n",i+1,exts[i]); | |
286 error("Couldn't locate %s\nI tried appending the following " | |
287 "extensions: \n%s",exec_tmp,buf); | |
288 } | |
289 Trace((exec_tmp2)); | |
290 } | |
291 /* | |
292 * STARTS WITH ./ or .\ | |
293 */ | |
294 else if ((execname[0] == '.') && | |
295 ((execname[1] == '\\') || (execname[1] == '/'))) | |
296 { | |
297 if (((char*) getcwd(exec_tmp,MAX_PATH))==NULL) | |
298 error("can't find current working directory"); | |
299 if (! fileExistsMulti(exec_tmp2,exec_tmp,&(execname[2]), | |
300 exts,NUM_EXTENSIONS) ) | |
301 if (! fileExistsMulti(exec_tmp2,execpath,&(execname[2]), | |
302 exts,NUM_EXTENSIONS) ) | |
303 { | |
304 j = 0; | |
305 for (i = 0; i < NUM_EXTENSIONS; i++) | |
306 j += sprintf(buf + j," [%d]: %s\n",i+1,exts[i]); | |
307 error("Couldn't locate %s\n" | |
308 "I looked in the following directories:\n [1]: %s\n [2]: %s\n" | |
309 "I also tried appending the following " | |
310 "extensions: \n%s",execname,exec_tmp,execpath,buf); | |
311 } | |
312 Trace((exec_tmp2)); | |
313 } | |
314 /* | |
315 * OTHERWISE, SEARCH PATH (prepend '.' and run.exe's directory) | |
316 * can't use fileExistsMulti because we want to search entire path | |
317 * for exts[0], then for exts[1], etc. | |
318 */ | |
319 else | |
320 { | |
321 orig_pathlist = getenv("PATH"); | |
322 if ((pathlist = malloc (strlen(orig_pathlist) | |
323 + strlen(".") | |
324 + strlen(execpath)+ 3)) == NULL) | |
325 error("internal error - out of memory"); | |
326 strcpy(pathlist,"."); | |
327 strcat(pathlist,SEP_CHARS); | |
328 strcat(pathlist,execpath); | |
329 strcat(pathlist,SEP_CHARS); | |
330 strcat(pathlist,orig_pathlist); | |
331 | |
332 Trace((pathlist)); | |
333 for (i = 0; i < NUM_EXTENSIONS; i++) | |
334 { | |
335 strcpy(exec_tmp,execname); | |
336 strcat(exec_tmp,exts[i]); | |
337 pfopen(exec_tmp2,exec_tmp,pathlist); | |
338 if (fileExists(NULL,NULL,exec_tmp2)) | |
339 break; | |
340 exec_tmp2[0] = '\0'; | |
341 } | |
342 Trace(("exec_tmp\t%s\npathlist\t%s\n",exec_tmp2,pathlist)); | |
343 | |
344 free(pathlist); | |
345 if (exec_tmp2[0] == '\0') | |
346 { | |
347 j = 0; | |
348 for (i = 0; i < NUM_EXTENSIONS; i++) | |
349 j += sprintf(buf + j," [%d]: %s\n",i+1,exts[i]); | |
350 error("Couldn't find %s anywhere.\n" | |
351 "I even looked in the PATH \n" | |
352 "I also tried appending the following " | |
353 "extensions: \n%s",execname,buf); | |
354 } | |
355 } | |
356 /* | |
357 * At this point, we know that exec_tmp2 contains a filename | |
358 * and we know that exec_tmp2 exists. | |
359 */ | |
360 #if defined(__CYGWIN__) | |
361 { | |
362 struct stat stbuf; | |
363 char sym_link_name[MAX_PATH+1]; | |
364 char real_name[MAX_PATH+1]; | |
365 char dummy[MAX_PATH+1]; | |
366 | |
367 strcpy(exec_tmp,exec_tmp2); | |
368 | |
369 CYGWIN_CONV_TO_POSIX_PATH((exec_tmp,sym_link_name)); | |
370 Trace((sym_link_name)); | |
371 | |
372 if (lstat(sym_link_name, &stbuf) == 0) | |
373 { | |
374 if ((stbuf.st_mode & S_IFLNK) == S_IFLNK) | |
375 { | |
376 if (readlink(sym_link_name, real_name, sizeof(real_name)) == -1) | |
377 error("problem reading symbolic link for %s",exec_tmp); | |
378 else | |
379 { | |
380 // if realname starts with '/' it's a rootpath | |
381 if (real_name[0] == '/') | |
382 strcpy(exec_tmp2,real_name); | |
383 else // otherwise, it's relative to the symlink's location | |
384 { | |
385 CYGWIN_SPLIT_PATH((sym_link_name,exec_tmp2,dummy)); | |
386 if (!endsWith(exec_tmp2,PATH_SEP_CHAR_STR)) | |
387 strcat(exec_tmp2,PATH_SEP_CHAR_STR); | |
388 strcat(exec_tmp2,real_name); | |
389 } | |
390 } | |
391 } | |
392 else /* NOT a symlink */ | |
393 strcpy(exec_tmp2, sym_link_name); | |
394 } | |
395 else | |
396 error("can't locate executable - %s",sym_link_name); | |
397 } | |
398 CYGWIN_CONV_TO_FULL_WIN32_PATH((exec_tmp2,exec)); | |
399 #else | |
400 strcpy (exec, exec_tmp2); | |
401 #endif | |
402 } | |
403 int endsWith(const char* s1, const char* s2) | |
404 { | |
405 int len1; | |
406 int len2; | |
407 int retval = FALSE; | |
408 len1 = strlen(s1); | |
409 len2 = strlen(s2); | |
410 if (len1 - len2 >= 0) | |
411 if (stricmp(&(s1[len1-len2]),s2) == 0) | |
412 retval = TRUE; | |
413 return retval; | |
414 }void strip_exe(char* s) | |
415 { | |
416 if ((strlen(s) > 4) && // long enough to have .exe extension | |
417 // second part not evaluated (short circuit) if exec_arg too short | |
418 (stricmp(&(s[strlen(s)-4]),".exe") == 0)) | |
419 s[strlen(s)-4] = '\0'; | |
420 } | |
421 void error(char* fmt, ...) | |
422 { | |
423 char buf[4096]; | |
424 int j; | |
425 va_list args; | |
426 va_start(args, fmt); | |
427 j = sprintf(buf, "Error: "); | |
428 j += vsprintf(buf + j,fmt,args); | |
429 j += sprintf(buf + j,"\n"); | |
430 va_end(args); | |
431 MessageBox(NULL, buf, "Run.exe", MB_ICONSTOP); | |
432 exit(1); | |
433 } | |
434 void message(char* fmt, ...) | |
435 { | |
436 char buf[10000]; | |
437 int j; | |
438 va_list args; | |
439 va_start(args, fmt); | |
440 j = vsprintf(buf,fmt,args); | |
441 j += sprintf(buf + j,"\n"); | |
442 va_end(args); | |
443 MessageBox(NULL, buf, "Run.exe Message", MB_ICONSTOP); | |
444 } | |
445 void Trace_(char* fmt, ...) | |
446 { | |
447 char buf[10000]; | |
448 int j; | |
449 va_list args; | |
450 va_start(args, fmt); | |
451 j = vsprintf(buf,fmt,args); | |
452 j += sprintf(buf + j,"\n"); | |
453 va_end(args); | |
454 MessageBox(NULL, buf, "Run.exe DEBUG", MB_ICONSTOP); | |
455 } | |
456 /* | |
457 * Uses system info to determine the path used to invoke run | |
458 * Also attempts to deduce the target execname if "compact_invocation" | |
459 * method was used. | |
460 * | |
461 * returns TRUE if compact_invocation method was used | |
462 * (and target execname was deduced successfully) | |
463 * otherwise returns FALSE, and execname == run or run.exe | |
464 */ | |
465 int get_exec_name_and_path(char* execname, char* execpath) | |
466 { | |
467 char modname[MAX_PATH]; | |
468 char* tmp_execname; | |
469 char* p; | |
470 int retval = FALSE; | |
471 | |
472 if (!GetModuleFileName (NULL, modname, MAX_PATH)) | |
473 error("internal error - can't find my own name"); | |
474 if ((p = strrchr (modname, '\\')) == NULL) | |
475 error("internal error - my own name has no path\n%s",modname); | |
476 tmp_execname = p + 1; | |
477 p[0] = '\0'; | |
478 // if invoked by a name like "runxemacs" then strip off | |
479 // the "run" and let "xemacs" be execname. | |
480 // To check for this, make that: | |
481 // 1) first three chars are "run" | |
482 // 2) but the string doesn't end there, or start ".exe" | |
483 // Also, set "compact_invocation" TRUE | |
484 if ( ((tmp_execname[0] == 'r') || (tmp_execname[0] == 'R')) && | |
485 ((tmp_execname[1] == 'u') || (tmp_execname[1] == 'U')) && | |
486 ((tmp_execname[2] == 'n') || (tmp_execname[2] == 'N')) && | |
487 ((tmp_execname[3] != '.') && (tmp_execname[3] != '\0')) ) | |
488 { | |
489 tmp_execname += 3; | |
490 retval = TRUE; | |
491 } | |
492 else | |
493 tmp_execname = NULL; | |
494 | |
495 if (tmp_execname == NULL) | |
496 strcpy(execname,""); | |
497 else | |
498 strcpy(execname,tmp_execname); | |
499 #if defined(__CYGWIN__) | |
500 CYGWIN_CONV_TO_POSIX_PATH((modname,execpath)); | |
501 #else | |
502 strcpy(execpath,modname); | |
503 #endif | |
504 return retval; | |
505 } | |
506 /* | |
507 * works like strtok, but: | |
508 * double quotes (") suspends tokenizing until closing " reached | |
509 * CYGWIN ONLY: | |
510 * additionally, backslash escapes next character, even if that | |
511 * next character is a delimiter. Or a double quote. | |
512 * WARNING: this means that backslash may NOT be a delimiter | |
513 */ | |
514 char* my_strtok(char* s, const char* delim, char** lasts) | |
515 { | |
516 char *spanp; | |
517 int c, sc; | |
518 char *tok; | |
519 | |
520 if ((s == NULL) && ((s = *lasts) == NULL)) | |
521 return NULL; | |
522 /* Skip leading delimiters */ | |
523 cont: | |
524 c = *s++; | |
525 for (spanp = (char *)delim; (sc = *spanp++) != 0;) { | |
526 if (c == sc) | |
527 goto cont; | |
528 } | |
529 if (c == 0) { /* no non-delimiter characters */ | |
530 *lasts = NULL; | |
531 return (NULL); | |
532 } | |
533 tok = s - 1; | |
534 /* | |
535 * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). | |
536 * Note that delim must have one NUL; we stop if we see that, too. | |
537 * If we see a double quote, continue until next double quote, then | |
538 * start scanning for delimiters again. | |
539 * CYGWIN ONLY: if we see a backslash, just copy next character - | |
540 * don't consider it as a delimiter even if it is in delim string. | |
541 */ | |
542 for (;;) { | |
543 /* if this c is ", then scan until we find next " */ | |
544 if (c == '\"') | |
545 while ((c = *s++) != '\"') | |
546 if (c == 0) /* oops, forgot to close the ", clean up & return */ | |
547 { | |
548 s = NULL; | |
549 *lasts = s; | |
550 return (tok); | |
551 } | |
552 #if defined(__CYGWIN__) | |
553 if (c == '\\') | |
554 { | |
555 c = *s++; /* skip the backslash */ | |
556 if (c == 0) /* if escaped character is end-of-string, clean up & return */ | |
557 { | |
558 s = NULL; | |
559 *lasts = s; | |
560 return (tok); | |
561 } | |
562 c = *s++; /* otherwise, skip the escaped character */ | |
563 } | |
564 #endif | |
565 spanp = (char *)delim; | |
566 do { | |
567 if ((sc = *spanp++) == c) { | |
568 if (c == 0) | |
569 s = NULL; | |
570 else | |
571 s[-1] = 0; | |
572 *lasts = s; | |
573 return (tok); | |
574 } | |
575 } while (sc != 0); | |
576 c = *s++; | |
577 } | |
578 /* NOTREACHED */ | |
579 } | |
580 int parse_cmdline_to_arg_array(char* argv[MAX_ARGS], char* cmdline) | |
581 { | |
582 char seps[] = " \t\n"; | |
583 char* token; | |
584 int argc = 0; | |
585 char* lasts; | |
586 | |
587 token = my_strtok(cmdline, seps, &lasts); | |
588 while ((token != NULL) && (argc < MAX_ARGS)) | |
589 { | |
590 if ((argv[argc] = malloc(strlen(token)+1)) == NULL) | |
591 { | |
592 error("internal error - out of memory"); | |
593 } | |
594 strcpy(argv[argc++],token); | |
595 token = my_strtok(NULL,seps,&lasts); | |
596 } | |
597 if (argc >= MAX_ARGS) | |
598 error("too many arguments on commandline\n%s",cmdline); | |
599 return argc; | |
600 } | |
601 /* Taken from pfopen.c by David Engel (5-Jul-97). | |
602 * Original comments appear below. Superseded by next comment block. | |
603 * | |
604 * Written and released to the public domain by David Engel. | |
605 * | |
606 * This function attempts to open a file which may be in any of | |
607 * several directories. It is particularly useful for opening | |
608 * configuration files. For example, PROG.EXE can easily open | |
609 * PROG.CFG (which is kept in the same directory) by executing: | |
610 * | |
611 * cfg_file = pfopen("PROG.CFG", "r", getenv("PATH")); | |
612 * | |
613 * NULL is returned if the file can't be opened. | |
614 */ | |
615 | |
616 /* | |
617 * This function attempts to locate a file which may be in any of | |
618 * several directories. Unlike the original pfopen, it does not | |
619 * return a FILE pointer to the opened file, but rather returns | |
620 * the fully-qualified filename of the first match found. Returns | |
621 * empty string if not found. | |
622 */ | |
623 char *pfopen(char *retval, const char *name, const char *dirs) | |
624 { | |
625 char *ptr; | |
626 char *tdirs; | |
627 char returnval[MAX_PATH + FILENAME_MAX + 100]; | |
628 char *recursive_name; | |
629 int foundit = FALSE; | |
630 | |
631 returnval[0] = '\0'; | |
632 | |
633 if (dirs == NULL || dirs[0] == '\0') | |
634 return NULL; | |
635 | |
636 if ((tdirs = malloc(strlen(dirs)+1)) == NULL) | |
637 return NULL; | |
638 | |
639 strcpy(tdirs, dirs); | |
640 | |
641 for (ptr = strtok(tdirs, SEP_CHARS); (foundit == FALSE) && ptr != NULL; | |
642 ptr = strtok(NULL, SEP_CHARS)) | |
643 { | |
644 foundit = fileExists(returnval,ptr,name); | |
645 } | |
646 | |
647 free(tdirs); | |
648 if (!foundit) | |
649 retval[0] = '\0'; | |
650 else | |
651 strcpy(retval,returnval); | |
652 return retval; | |
653 } | |
654 int fileExistsMulti(char* fullname, const char* path, | |
655 const char* name_noext, const char* exts[], | |
656 const int extcnt) | |
657 { | |
658 char tryName[MAX_PATH + FILENAME_MAX]; | |
659 int i = 0; | |
660 int retval = FALSE; | |
661 fullname[0] = '\0'; | |
662 for (i = 0; i < extcnt; i++) | |
663 { | |
664 strcpy(tryName,name_noext); | |
665 strcat(tryName,exts[i]); | |
666 if (fileExists(fullname, path, tryName) == TRUE) | |
667 { | |
668 retval = TRUE; | |
669 break; | |
670 } | |
671 fullname[0] = '\0'; | |
672 } | |
673 return retval; | |
674 } | |
675 int fileExists(char* fullname, const char* path, const char* name) | |
676 { | |
677 int retval = FALSE; | |
678 FILE* file; | |
679 size_t len; | |
680 char work[FILENAME_MAX]; | |
681 char work2[MAX_PATH + FILENAME_MAX + 100]; | |
682 if (path != NULL) | |
683 { | |
684 strcpy(work, path); | |
685 len = strlen(work); | |
686 if (len && work[len-1] != '/' && work[len-1] != '\\') | |
687 strcat(work, PATH_SEP_CHAR_STR); | |
688 } | |
689 else | |
690 work[0]='\0'; | |
691 | |
692 strcat(work, name); | |
693 #if defined(__CYGWIN__) | |
694 CYGWIN_CONV_TO_POSIX_PATH((work, work2)); | |
695 #else | |
696 strcpy(work2,work); | |
697 #endif | |
698 | |
699 #ifdef DEBUGALL | |
700 Trace(("looking for...\t%s\n",work2)); | |
701 #endif | |
702 | |
703 file = fopen(work2, "rb"); | |
704 if (file != NULL) | |
705 { | |
706 if (fullname != NULL) | |
707 strcpy(fullname,work2); | |
708 retval = TRUE; | |
709 fclose(file); | |
710 } | |
711 return retval; | |
712 } |