Mercurial > gnulib
annotate lib/w32spawn.h @ 30235:d2d89737e596
Enable use of shell scripts as executables in mingw.
author | Bruno Haible <bruno@clisp.org> |
---|---|
date | Mon, 29 Sep 2008 15:13:25 +0200 |
parents | 49d1cc4454bf |
children | e70e12db795d |
rev | line source |
---|---|
24627 | 1 /* Auxiliary functions for the creation of subprocesses. Native Woe32 API. |
30235
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
2 Copyright (C) 2003, 2006-2008 Free Software Foundation, Inc. |
24627 | 3 Written by Bruno Haible <bruno@clisp.org>, 2003. |
4 | |
29000
49d1cc4454bf
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
27635
diff
changeset
|
5 This program is free software: you can redistribute it and/or modify |
24627 | 6 it under the terms of the GNU General Public License as published by |
29000
49d1cc4454bf
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
27635
diff
changeset
|
7 the Free Software Foundation; either version 3 of the License, or |
49d1cc4454bf
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
27635
diff
changeset
|
8 (at your option) any later version. |
24627 | 9 |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
29000
49d1cc4454bf
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
27635
diff
changeset
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
24627 | 17 |
18 /* Get declarations of the Win32 API functions. */ | |
19 #define WIN32_LEAN_AND_MEAN | |
20 #include <windows.h> | |
21 | |
22 /* Get _get_osfhandle() and _open_osfhandle(). */ | |
23 #include <io.h> | |
24 | |
25 #include <stdbool.h> | |
27635
0bd3697b93f0
* doc/gnulib-tool.texi (Initial import): Update to match current
Paul Eggert <eggert@cs.ucla.edu>
parents:
27306
diff
changeset
|
26 #include <string.h> |
24627 | 27 #include <errno.h> |
28 | |
29 #include "xalloc.h" | |
30 | |
31 /* Duplicates a file handle, making the copy uninheritable. */ | |
32 static int | |
33 dup_noinherit (int fd) | |
34 { | |
35 HANDLE curr_process = GetCurrentProcess (); | |
36 HANDLE old_handle = (HANDLE) _get_osfhandle (fd); | |
37 HANDLE new_handle; | |
38 int nfd; | |
39 | |
40 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */ | |
41 old_handle, /* SourceHandle */ | |
42 curr_process, /* TargetProcessHandle */ | |
43 (PHANDLE) &new_handle, /* TargetHandle */ | |
44 (DWORD) 0, /* DesiredAccess */ | |
45 FALSE, /* InheritHandle */ | |
46 DUPLICATE_SAME_ACCESS)) /* Options */ | |
47 error (EXIT_FAILURE, 0, _("DuplicateHandle failed with error code 0x%08x"), | |
48 GetLastError ()); | |
49 | |
50 nfd = _open_osfhandle ((long) new_handle, O_BINARY); | |
51 if (nfd < 0) | |
52 error (EXIT_FAILURE, errno, _("_open_osfhandle failed")); | |
53 | |
54 return nfd; | |
55 } | |
56 | |
57 /* Prepares an argument vector before calling spawn(). | |
58 Note that spawn() does not by itself call the command interpreter | |
59 (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : | |
60 ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); | |
61 GetVersionEx(&v); | |
62 v.dwPlatformId == VER_PLATFORM_WIN32_NT; | |
63 }) ? "cmd.exe" : "command.com"). | |
64 Instead it simply concatenates the arguments, separated by ' ', and calls | |
65 CreateProcess(). We must quote the arguments since Win32 CreateProcess() | |
66 interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a | |
67 special way: | |
68 - Space and tab are interpreted as delimiters. They are not treated as | |
69 delimiters if they are surrounded by double quotes: "...". | |
70 - Unescaped double quotes are removed from the input. Their only effect is | |
71 that within double quotes, space and tab are treated like normal | |
72 characters. | |
73 - Backslashes not followed by double quotes are not special. | |
74 - But 2*n+1 backslashes followed by a double quote become | |
75 n backslashes followed by a double quote (n >= 0): | |
76 \" -> " | |
77 \\\" -> \" | |
78 \\\\\" -> \\" | |
79 */ | |
80 #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" | |
81 #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" | |
82 static char ** | |
83 prepare_spawn (char **argv) | |
84 { | |
85 size_t argc; | |
86 char **new_argv; | |
87 size_t i; | |
88 | |
89 /* Count number of arguments. */ | |
90 for (argc = 0; argv[argc] != NULL; argc++) | |
91 ; | |
92 | |
93 /* Allocate new argument vector. */ | |
30235
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
94 new_argv = XNMALLOC (1 + argc + 1, char *); |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
95 |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
96 /* Add an element upfront that can be used when argv[0] turns out to be a |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
97 script, not a program. |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
98 On Unix, this would be "/bin/sh". On native Windows, "sh" is actually |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
99 "sh.exe". We have to omit the directory part and rely on the search in |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
100 PATH, because the mingw "mount points" are not visible inside Win32 |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
101 CreateProcess(). */ |
d2d89737e596
Enable use of shell scripts as executables in mingw.
Bruno Haible <bruno@clisp.org>
parents:
29000
diff
changeset
|
102 *new_argv++ = "sh.exe"; |
24627 | 103 |
104 /* Put quoted arguments into the new argument vector. */ | |
105 for (i = 0; i < argc; i++) | |
106 { | |
107 const char *string = argv[i]; | |
108 | |
109 if (string[0] == '\0') | |
110 new_argv[i] = xstrdup ("\"\""); | |
111 else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) | |
112 { | |
113 bool quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); | |
114 size_t length; | |
115 unsigned int backslashes; | |
116 const char *s; | |
117 char *quoted_string; | |
118 char *p; | |
119 | |
120 length = 0; | |
121 backslashes = 0; | |
122 if (quote_around) | |
123 length++; | |
124 for (s = string; *s != '\0'; s++) | |
125 { | |
126 char c = *s; | |
127 if (c == '"') | |
128 length += backslashes + 1; | |
129 length++; | |
130 if (c == '\\') | |
131 backslashes++; | |
132 else | |
133 backslashes = 0; | |
134 } | |
135 if (quote_around) | |
136 length += backslashes + 1; | |
137 | |
138 quoted_string = (char *) xmalloc (length + 1); | |
139 | |
140 p = quoted_string; | |
141 backslashes = 0; | |
142 if (quote_around) | |
143 *p++ = '"'; | |
144 for (s = string; *s != '\0'; s++) | |
145 { | |
146 char c = *s; | |
147 if (c == '"') | |
148 { | |
149 unsigned int j; | |
150 for (j = backslashes + 1; j > 0; j--) | |
151 *p++ = '\\'; | |
152 } | |
153 *p++ = c; | |
154 if (c == '\\') | |
155 backslashes++; | |
156 else | |
157 backslashes = 0; | |
158 } | |
159 if (quote_around) | |
160 { | |
161 unsigned int j; | |
162 for (j = backslashes; j > 0; j--) | |
163 *p++ = '\\'; | |
164 *p++ = '"'; | |
165 } | |
166 *p = '\0'; | |
167 | |
168 new_argv[i] = quoted_string; | |
169 } | |
170 else | |
171 new_argv[i] = (char *) string; | |
172 } | |
173 new_argv[argc] = NULL; | |
174 | |
175 return new_argv; | |
176 } |