X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/baf7eeb5d3483498700e49358b379c0c16886e26..e4dec765ecde99c3338f14539a24fdc7591ef6f5:/nt/cmdproxy.c diff --git a/nt/cmdproxy.c b/nt/cmdproxy.c index 18705af47f..267e00acc9 100644 --- a/nt/cmdproxy.c +++ b/nt/cmdproxy.c @@ -90,7 +90,7 @@ fail (char * msg, ...) vfprintf (stderr, msg, args); va_end (args); - exit (1); + exit (-1); } void @@ -366,12 +366,18 @@ console_event_handler (DWORD event) return TRUE; } +/* Change from normal usage; return value indicates whether spawn + succeeded or failed - program return code is returned separately. */ int -spawn (char * progname, char * cmdline) +spawn (char * progname, char * cmdline, char * dir, int * retcode) { - DWORD rc = 0xff; + BOOL success = FALSE; SECURITY_ATTRIBUTES sec_attrs; STARTUPINFO start; + /* In theory, passing NULL for the environment block to CreateProcess + is the same as passing the value of GetEnvironmentStrings, but + doing this explicitly seems to cure problems running DOS programs + in some cases. */ char * envblock = GetEnvironmentStrings (); sec_attrs.nLength = sizeof (sec_attrs); @@ -382,11 +388,13 @@ spawn (char * progname, char * cmdline) start.cb = sizeof (start); if (CreateProcess (progname, cmdline, &sec_attrs, NULL, TRUE, - 0, envblock, NULL, &start, &child)) + 0, envblock, dir, &start, &child)) { + success = TRUE; /* wait for completion and pass on return code */ WaitForSingleObject (child.hProcess, INFINITE); - GetExitCodeProcess (child.hProcess, &rc); + if (retcode) + GetExitCodeProcess (child.hProcess, (DWORD *)retcode); CloseHandle (child.hThread); CloseHandle (child.hProcess); child.hProcess = NULL; @@ -394,7 +402,7 @@ spawn (char * progname, char * cmdline) FreeEnvironmentStrings (envblock); - return (int) rc; + return success; } /* Return size of current environment block. */ @@ -424,12 +432,16 @@ main (int argc, char ** argv) int num_pass_through_args; char modname[MAX_PATH]; char path[MAX_PATH]; + char dir[MAX_PATH]; interactive = TRUE; SetConsoleCtrlHandler ((PHANDLER_ROUTINE) console_event_handler, TRUE); + if (!GetCurrentDirectory (sizeof (dir), dir)) + fail ("error: GetCurrentDirectory failed\n"); + /* We serve double duty: we can be called either as a proxy for the real shell (that is, because we are defined to be the user shell), or in our role as a helper application for running DOS programs. @@ -445,16 +457,29 @@ main (int argc, char ** argv) if (!GetModuleFileName (NULL, modname, sizeof (modname))) fail ("error: GetModuleFileName failed\n"); + /* Change directory to location of .exe so startup directory can be + deleted. */ + progname = strrchr (modname, '\\'); + *progname = '\0'; + SetCurrentDirectory (modname); + *progname = '\\'; + /* Although Emacs always sets argv[0] to an absolute pathname, we might get run in other ways as well, so convert argv[0] to an - absolute name before comparing to the module name. */ + absolute name before comparing to the module name. Don't get + caught out by mixed short and long names. */ + GetShortPathName (modname, modname, sizeof (modname)); + path[0] = '\0'; if (!SearchPath (NULL, argv[0], ".exe", sizeof (path), path, &progname) + || !GetShortPathName (path, path, sizeof (path)) || stricmp (modname, path) != 0) { /* We are being used as a helper to run a DOS app; just pass command line to DOS app without change. */ /* TODO: fill in progname. */ - return spawn (NULL, GetCommandLine ()); + if (spawn (NULL, GetCommandLine (), dir, &rc)) + return rc; + fail ("Could not run %s\n", GetCommandLine ()); } /* Process command line. If running interactively (-c or /c not @@ -486,21 +511,21 @@ main (int argc, char ** argv) passed on to real shell if used (only really of benefit for interactive use, but allow for batch use as well). Accept / as switch char for compatability with cmd.exe. */ - if ( ((*argv)[0] == '-' || (*argv)[0] == '/') && (*argv)[1] != '\0' ) + if (((*argv)[0] == '-' || (*argv)[0] == '/') && (*argv)[1] != '\0') { - if ( ((*argv)[1] == 'c') && ((*argv)[2] == '\0') ) + if (((*argv)[1] == 'c' || (*argv)[1] == 'C') && ((*argv)[2] == '\0')) { if (--argc == 0) fail ("error: expecting arg for %s\n", *argv); cmdline = *(++argv); interactive = FALSE; } - else if ( ((*argv)[1] == 'i') && ((*argv)[2] == '\0') ) + else if (((*argv)[1] == 'i' || (*argv)[1] == 'I') && ((*argv)[2] == '\0')) { if (cmdline) warn ("warning: %s ignored because of -c\n", *argv); } - else if ( ((*argv)[1] == 'e') && ((*argv)[2] == ':') ) + else if (((*argv)[1] == 'e' || (*argv)[1] == 'E') && ((*argv)[2] == ':')) { int requested_envsize = atoi (*argv + 3); /* Enforce a reasonable minimum size, as above. */ @@ -533,7 +558,7 @@ main (int argc, char ** argv) #else /* Probably a mistake for there to be extra args; not fatal. */ if (argc > 0) - warn ("warning: extra args ignored after %s\n", argv[-1]); + warn ("warning: extra args ignored after '%s'\n", argv[-1]); #endif pass_through_args[num_pass_through_args] = NULL; @@ -568,10 +593,12 @@ main (int argc, char ** argv) } } + pass_to_shell: if (need_shell) { char * p; int extra_arg_space = 0; + int run_command_dot_com; progname = getenv ("COMSPEC"); if (!progname) @@ -583,6 +610,10 @@ main (int argc, char ** argv) if (progname == NULL || strchr (progname, '\\') == NULL) fail ("error: the program %s could not be found.\n", getenv ("COMSPEC")); + /* Need to set environment size when running command.com. */ + run_command_dot_com = + (stricmp (strrchr (progname, '\\'), "command.com") == 0); + /* Work out how much extra space is required for pass_through_args. */ for (argv = pass_through_args; *argv != NULL; ++argv) @@ -609,22 +640,28 @@ main (int argc, char ** argv) for (argv = pass_through_args; *argv != NULL; ++argv) p += wsprintf (p, " %s", *argv); - /* Always set environment size to something reasonable. */ - wsprintf(p, " /e:%d /c %s", envsize, cmdline); + if (run_command_dot_com) + wsprintf(p, " /e:%d /c %s", envsize, cmdline); + else + wsprintf(p, " /c %s", cmdline); cmdline = buf; } else { - /* Provide dir arg expected by command.com when first started - interactively (the "command search path"). cmd.exe does - not require it, but accepts it silently - presumably other - DOS compatible shells do the same. To avoid potential - problems with spaces in command dir (which cannot be quoted - - command.com doesn't like it), we always use the 8.3 form. */ - GetShortPathName (progname, path, sizeof (path)); - p = strrchr (path, '\\'); - /* Trailing slash is acceptable, so always leave it. */ - *(++p) = '\0'; + if (run_command_dot_com) + { + /* Provide dir arg expected by command.com when first + started interactively (the "command search path"). To + avoid potential problems with spaces in command dir + (which cannot be quoted - command.com doesn't like it), + we always use the 8.3 form. */ + GetShortPathName (progname, path, sizeof (path)); + p = strrchr (path, '\\'); + /* Trailing slash is acceptable, so always leave it. */ + *(++p) = '\0'; + } + else + path[0] = '\0'; cmdline = p = alloca (strlen (progname) + extra_arg_space + strlen (path) + 13); @@ -637,9 +674,8 @@ main (int argc, char ** argv) for (argv = pass_through_args; *argv != NULL; ++argv) p += wsprintf (p, " %s", *argv); - /* Always set environment size to something reasonable - again - cmd.exe ignores this silently. */ - wsprintf (p, " /e:%d", envsize); + if (run_command_dot_com) + wsprintf (p, " /e:%d", envsize); } } @@ -649,7 +685,16 @@ main (int argc, char ** argv) if (!cmdline) cmdline = progname; - rc = spawn (progname, cmdline); + if (spawn (progname, cmdline, dir, &rc)) + return rc; - return rc; + if (!need_shell) + { + need_shell = TRUE; + goto pass_to_shell; + } + + fail ("Could not run %s\n", progname); + + return 0; }