[8654b5] | 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 | |
---|
[7716999] | 41 | #include <run.h> |
---|
[8654b5] | 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> |
---|
[739993] | 48 | //WinMainCRTStartup() { mainCRTStartup(); } |
---|
[8654b5] | 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 | } |
---|
[739993] | 86 | /* at this point, execpath is defined, as are argv[] and execname */ |
---|
[8654b5] | 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 */ |
---|
[0500da] | 99 | // if (compact_invocation) |
---|
| 100 | // strip_exe(execname); |
---|
[8654b5] | 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; |
---|
[739993] | 132 | |
---|
[8654b5] | 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, |
---|
[739993] | 156 | * then set emacs_dir environment variable |
---|
[8654b5] | 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 | } |
---|