vfprintf (stderr, msg, args);
va_end (args);
- exit (1);
+ exit (-1);
}
void
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);
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;
FreeEnvironmentStrings (envblock);
- return (int) rc;
+ return success;
}
/* Return size of current environment block. */
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.
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
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. */
#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;
}
}
+ pass_to_shell:
if (need_shell)
{
char * p;
int extra_arg_space = 0;
+ int run_command_dot_com;
progname = getenv ("COMSPEC");
if (!progname)
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)
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);
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);
}
}
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;
}