This is a patch that replaces the usage of batch files in favor
of direct invokation of the command interpreter on windows.
It is a 'standalone' implementation of
'construct_command_argv_internal(),
that takes advantage of the fact that unlike on other systems
the os function to invoke the subprocess takes a flat line anyway.
Short summary:
- New 'construct_command_argv_internal()' (jobs.c) for WINDOWS32.
Its supposed to handle these cases:
* direct commands
-> line is passed to CreateProcess as is.
* comspec shell
-> line is passed as: %COMSPEC% /c line here ...
* sh shell
-> line is quoted and passed as: sh -c "line here ..."
Within the line " and \ are escaped with \
- New 'make_command_line()' (win32\sub_proc.c), as 'simplistic' as
5 lines can be ;)
- Presets for the "SHELL" variable (main.c, variable.c) were removed.
Instead the decision is made in place. (Should be fine for msys that
sets "SHELL" in the environment, I hope cygwin does too)
After all, I cant promise that everthing will go with no further
adjustments, this would be subject of testing.
One difference I've seen so far, but since the new version looked
better to me, I left it:
--- makefile:
SHELL = sh
all:
echo "!" back\\slash "!"
--- cvs make:
echo "!" back\\slash "!"
! backslash !
--- patched make:
echo "!" back\\slash "!"
! back\slash !
--- grischka
diff -urw ../make/glob/glob.c ./glob/glob.c
--- ../make/glob/glob.c Fri Mar 10 03:20:46 2006
+++ ./glob/glob.c Mon May 01 18:42:34 2006
@@ -187,6 +187,7 @@
# endif
# ifndef __SASC
# ifdef WINDOWS32
+# include <malloc.h>
static void *
my_realloc (void *p, unsigned int n)
# else
diff -urw ../make/job.c ./job.c
--- ../make/job.c Mon Apr 10 00:09:24 2006
+++ ./job.c Tue May 02 03:55:42 2006
@@ -2181,6 +2181,244 @@
#endif /* On Amiga */
+
+#ifdef WINDOWS32
+/* **************************************************************** */
+/* Return a new string which is a quoted version of STRING to be
+ passed by sh -c "string" */
+
+static char *
+sh_dbl_quote (char *string)
+{
+ register int c, n;
+ char *result, *r, *s;
+ n = 3; /* two quotes and \0 */
+ for (s = string; 0 != (c = *s); s++)
+ {
+ ++n;
+ if (c == '\"' || c == '\\')
+ ++n;
+ }
+ result = r = xmalloc (n);
+ *r++ = '\"';
+ for (s = string; 0 != (c = *s); s++)
+ {
+ if (c == '\"' || c == '\\')
+ *r++ = '\\';
+ *r++ = c;
+ }
+ *r++ = '\"';
+ *r = '\0';
+ return result;
+}
+
+static char *
+basename(char *file)
+{
+ char *c;
+ c = strchr(file, 0);
+ while (c > file && c[-1] != '\\' && c[-1] != '/')
+ --c;
+ return c;
+}
+
+char *add_string(char **ps, const char *s2)
+{
+ int l1, lsep, l2, lall;
+ char *s1 = *ps;
+ l1 = s1 ? strlen(s1) : 0;
+ l2 = s2 ? strlen(s2) : 0;
+ lsep = l1 && l2;
+ lall = l1 + lsep + l2;
+ s1 = xrealloc(s1, lall + 1);
+ if (s1) {
+ if (lsep)
+ s1[l1] = ' ';
+ if (l2)
+ memcpy(s1 + l1 + lsep, s2, l2);
+ s1[lall] = 0;
+ }
+ return *ps = s1;
+}
+
+static char **
+construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr)
+ char *line, **restp;
+ char *shell, *ifs;
+ char **batch_filename_ptr;
+{
+
+ static const char sh_switch_dos[] = "/c";
+ static const char sh_chars_dos[] = "|&<>();,";
+ static const char *sh_cmds_dos[] = {
+ "break", "call", "cd", "chcp", "chdir", "cls",
+ "copy", "ctty", "date", "del", "dir", "echo",
+ "erase", "exit", "for", "goto", "if", "if", "md",
+ "mkdir", "path", "pause", "prompt", "rd", "rem",
+ "ren", "rename", "rmdir", "set", "shift", "time",
+ "type", "ver", "verify", "vol", ":", 0 };
+
+ static const char sh_switch_sh[] = "-c";
+ static const char sh_chars_sh[] = "#;\"*?[]&|<>(){}$`^";
+ static const char *sh_cmds_sh[] = {
+ "cd", "eval", "exec", "exit", "login",
+ "logout", "set", "umask", "wait", "while", "for",
+ "case", "if", ":", ".", "break", "continue",
+ "export", "read", "readonly", "shift", "times",
+ "trap", "switch", "test",
+#ifdef BATCH_MODE_ONLY_SHELL
+ "echo",
+#endif
+ 0 };
+
+ char **new_argv;
+ char *arg0;
+ char *arg1;
+
+ const char **sh_cmds;
+ const char *sh_chars;
+ const char *sh_switch;
+ const char *sh_exe;
+
+ char *a, *c, *e;
+ int slow, sh_unix;
+
+#if 0
+ printf("ccai:shell : %s\n", shell);
+ printf("ccai:line : %s\n", line);
+#endif
+
+ if (shell && shell[0]) {
+ sh_exe = shell;
+ c = basename(shell);
+ sh_unix = strstr(c, "sh") || strstr(c, "SH");
+ } else {
+ e = getenv("COMSPEC");
+ if (e) {
+ sh_exe = basename(e);
+ } else {
+ sh_exe = "cmd.exe";
+ }
+ sh_unix = 0;
+ }
+
+ if (sh_unix) {
+ sh_cmds = sh_cmds_sh;
+ sh_chars = sh_chars_sh;
+ sh_switch = sh_switch_sh;
+ } else {
+ sh_cmds = sh_cmds_dos;
+ sh_chars = sh_chars_dos;
+ sh_switch = sh_switch_dos;
+ }
+
+ slow = 0;
+
+ /* trim left */
+ while (isspace(*line))
+ ++line;
+
+ /* check for end_of_line, special chars and continuation on next line */
+ c = line;
+ while (c[0])
+ {
+ /* bachslash + newline are replaced by a single space */
+ if (c[0] == '\\' && c[1] == '\n')
+ {
+ a = c;
+ while (a > line && isspace(a[-1]))
+ --a;
+ *a++ = ' ';
+ c += 2;
+ while (isspace(*c))
+ ++c;
+ c = strcpy(a, c);
+ continue;
+ }
+
+ /* newline ends this command */
+ if (c[0] == '\n')
+ {
+ if (restp)
+ *restp = c+1;
+ break;
+ }
+
+ /* special char require the command processor */
+ if (strchr(sh_chars, c[0]))
+ slow = 1;
+
+ ++c;
+ }
+
+ /* trim right */
+ while (c > line && isspace(c[-1]))
+ --c;
+ *c = 0;
+
+ /* nothing to do? */
+ if (0 == line[0])
+ return NULL;
+
+ /* get first arg */
+ a = e = line;
+ if ('\"' == *e) {
+ ++e, ++a;
+ while (*e && '\"' != *e)
+ ++e;
+ } else {
+ while (*e && !isspace(*e))
+ ++e;
+ }
+
+ /* make first token */
+ arg0 = savestring(a, e-a);
+
+ /* check if first arg is a built-in shell command */
+ while (*sh_cmds) {
+ if (0 == stricmp (*sh_cmds, arg0)) {
+ slow = 1;
+ break;
+ }
+ ++ sh_cmds;
+ }
+
+ arg1 = NULL;
+ if (slow) {
+ if (sh_unix)
+ line = sh_dbl_quote(line);
+ free(arg0);
+ arg0 = xstrdup(sh_exe);
+ add_string(&arg1, arg0);
+ add_string(&arg1, sh_switch);
+ add_string(&arg1, line);
+ if (sh_unix)
+ free(line);
+ } else {
+ add_string(&arg1, line);
+ }
+
+/*
+ On windows we do not need a real argv vector, since we pass
+ a flat line to CreateProcess anyway. So here arg0 is the
+ first token, as it will be looked up in the PATH, eventually.
+ arg1 is the line, as the invoked program will see it with
+ GetCommandLine().
+
+ How the target program will see it in the main()'s argv
+ is left to the startup code that it uses.
+*/
+ new_argv = (char **) xmalloc(3 * sizeof(char *));
+ new_argv[0] = arg0;
+ new_argv[1] = arg1;
+ new_argv[2] = 0;
+ return new_argv;
+}
+
+/* **************************************************************** */
+#else /* !WINDOWS32 */
+/* **************************************************************** */
+
#ifndef VMS
/* Figure out the argument list necessary to run LINE as a command. Try to
avoid using a shell. This routine handles only ' quoting, and " quoting
@@ -2194,7 +2432,6 @@
SHELL is the shell to use, or nil to use the default shell.
IFS is the value of $IFS, or nil (meaning the default). */
-
static char **
construct_command_argv_internal (char *line, char **restp, char *shell,
char *ifs, char **batch_filename_ptr)
@@ -2906,6 +3143,7 @@
return new_argv;
}
#endif /* !VMS */
+#endif /* !WINDOWS32 */
/* Figure out the argument list necessary to run LINE as a command. Try to
avoid using a shell. This routine handles only ' quoting, and " quoting
diff -urw ../make/main.c ./main.c
--- ../make/main.c Mon Apr 10 00:09:24 2006
+++ ./main.c Mon May 01 18:13:12 2006
@@ -1390,7 +1390,7 @@
}
}
-#ifdef WINDOWS32
+#if 0//gr def WINDOWS32
/*
* THIS BLOCK OF CODE MUST COME AFTER chdir() CALL ABOVE IN ORDER
* TO NOT CONFUSE THE DEPENDENCY CHECKING CODE IN implicit.c.
@@ -1602,7 +1602,7 @@
read_makefiles
= read_all_makefiles (makefiles == 0 ? 0 : makefiles->list);
-#ifdef WINDOWS32
+#if 0//grdef WINDOWS32
/* look one last time after reading all Makefiles */
if (no_default_sh_exe)
no_default_sh_exe = !find_and_set_default_shell(NULL);
diff -urw ../make/make.h ./make.h
--- ../make/make.h Mon Apr 10 00:09:24 2006
+++ ./make.h Sat Apr 29 18:19:56 2006
@@ -328,7 +328,7 @@
# include <fcntl.h>
# include <malloc.h>
# define pipe(_p) _pipe((_p), 512, O_BINARY)
-# define kill(_pid,_sig) w32_kill((_pid),(_sig))
+# define kill(_pid,_sig) w32_kill(_pid,_sig)
void sync_Path_environment (void);
int kill (int pid, int sig);
diff -urw ../make/variable.c ./variable.c
--- ../make/variable.c Mon Apr 10 00:09:24 2006
+++ ./variable.c Mon May 01 18:13:12 2006
@@ -791,6 +791,7 @@
#endif
+#ifndef WINDOWS32 //gr
/* This won't override any definition, but it will provide one if there
isn't one there. */
v = define_variable ("SHELL", 5, default_shell, o_default, 0);
@@ -808,6 +809,7 @@
v->value = xstrdup (default_shell);
}
#endif
+#endif
/* Make sure MAKEFILES gets exported if it is set. */
v = define_variable ("MAKEFILES", 9, "", o_default, 0);
@@ -1166,7 +1168,7 @@
}
else
#endif /* __MSDOS__ */
-#ifdef WINDOWS32
+#if 0//gr def WINDOWS32
if ((origin == o_file || origin == o_override || origin == o_command)
&& streq (varname, "SHELL"))
{
diff -urw ../make/w32/subproc/sub_proc.c ./w32/subproc/sub_proc.c
--- ../make/w32/subproc/sub_proc.c Fri Mar 10 03:20:46 2006
+++ ./w32/subproc/sub_proc.c Tue May 02 15:24:22 2006
@@ -948,6 +948,22 @@
* command line for the executable.
*/
+#if 1
+static char *
+make_command_line( char *shell_name, char *full_exec_path, char **argv)
+{
+ char *add_string(char **pp, const char *s);
+ char *line = NULL;
+ add_string(&line, shell_name);
+ add_string(&line, argv[1]);
+#if 0
+ printf("line: %s\n", line);
+ fflush(stdout);
+#endif
+ return line;
+}
+
+#else
static char *
make_command_line( char *shell_name, char *full_exec_path, char **argv)
{
@@ -1173,6 +1189,8 @@
return command_line;
}
+#endif
+
/*
* Description: Given an argv and optional envp, launch the process
* using the default stdin, stdout, and stderr handles.
_______________________________________________
Make-w32 mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/make-w32