/* Proxy shell designed for use with Emacs on Windows 95 and NT.
- Copyright (C) 1997, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
- 2008, 2009, 2010 Free Software Foundation, Inc.
+ Copyright (C) 1997, 2001-2012 Free Software Foundation, Inc.
Accepts subset of Unix sh(1) command-line options, for compatibility
with elisp code written for Unix. When possible, executes external
#include <malloc.h> /* alloca */
#include <stdlib.h> /* getenv */
#include <string.h> /* strlen */
+#include <ctype.h> /* isspace, isalpha */
/* We don't want to include stdio.h because we are already duplicating
lots of it here */
char curdir[MAX_PATH];
char *p, *path;
const char *fname;
- int i;
/* At least partial absolute path specified; search there. */
if ((isalpha (prog[0]) && prog[1] == ':') ||
return NULL;
}
+/* Try to decode the given command line the way cmd would do it. On
+ success, return 1 with cmdline dequoted. Otherwise, when we've
+ found constructs only cmd can properly interpret, return 0 and
+ leave cmdline unchanged. */
+int
+try_dequote_cmdline (char* cmdline)
+{
+ /* Dequoting can only subtract characters, so the length of the
+ original command line is a bound on the amount of scratch space
+ we need. This length, in turn, is bounded by the 32k
+ CreateProces limit. */
+ char * old_pos = cmdline;
+ char * new_cmdline = alloca (strlen(cmdline));
+ char * new_pos = new_cmdline;
+ char c;
+
+ enum {
+ NORMAL,
+ AFTER_CARET,
+ INSIDE_QUOTE
+ } state = NORMAL;
+
+ while ((c = *old_pos++))
+ {
+ switch (state)
+ {
+ case NORMAL:
+ switch(c)
+ {
+ case '"':
+ *new_pos++ = c;
+ state = INSIDE_QUOTE;
+ break;
+ case '^':
+ state = AFTER_CARET;
+ break;
+ case '<': case '>':
+ case '&': case '|':
+ case '(': case ')':
+ case '%': case '!':
+ /* We saw an unquoted shell metacharacter and we don't
+ understand it. Bail out. */
+ return 0;
+ default:
+ *new_pos++ = c;
+ break;
+ }
+ break;
+ case AFTER_CARET:
+ *new_pos++ = c;
+ state = NORMAL;
+ break;
+ case INSIDE_QUOTE:
+ switch (c)
+ {
+ case '"':
+ *new_pos++ = c;
+ state = NORMAL;
+ break;
+ case '%':
+ case '!':
+ /* Variable substitution inside quote. Bail out. */
+ return 0;
+ default:
+ *new_pos++ = c;
+ break;
+ }
+ break;
+ }
+ }
+
+ /* We were able to dequote the entire string. Copy our scratch
+ buffer on top of the original buffer and return success. */
+ memcpy (cmdline, new_cmdline, new_pos - new_cmdline);
+ cmdline[new_pos - new_cmdline] = '\0';
+ return 1;
+}
+
/*****************************************************************/
#if 0
execute the command directly ourself. */
if (cmdline)
{
- /* If no redirection or piping, and if program can be found, then
- run program directly. Otherwise invoke a real shell. */
-
- static char copout_chars[] = "|<>&";
-
- if (strpbrk (cmdline, copout_chars) == NULL)
- {
- const char *args;
-
- /* The program name is the first token of cmdline. Since
- filenames cannot legally contain embedded quotes, the value
- of escape_char doesn't matter. */
- args = cmdline;
- if (!get_next_token (path, &args))
- fail ("error: no program name specified.\n");
-
- canon_filename (path);
- progname = make_absolute (path);
-
- /* If we found the program, run it directly (if not found it
- might be an internal shell command, so don't fail). */
- if (progname != NULL)
- need_shell = FALSE;
- }
+ const char *args;
+
+ /* The program name is the first token of cmdline. Since
+ filenames cannot legally contain embedded quotes, the value
+ of escape_char doesn't matter. */
+ args = cmdline;
+ if (!get_next_token (path, &args))
+ fail ("error: no program name specified.\n");
+
+ canon_filename (path);
+ progname = make_absolute (path);
+
+ /* If we found the program and the rest of the command line does
+ not contain unquoted shell metacharacters, run the program
+ directly (if not found it might be an internal shell command,
+ so don't fail). */
+ if (progname != NULL && try_dequote_cmdline (cmdline))
+ need_shell = FALSE;
+ else
+ progname = NULL;
}
pass_to_shell:
return 0;
}
-/* arch-tag: 88678d93-07ac-4e2f-ad63-d4a740ca69ac
- (do not change this comment) */