1 /* Test of system-quote module.
2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, see <https://www.gnu.org/licenses/>. */
17 /* Written by Bruno Haible <bruno@clisp.org>, 2012. */
22 #include "system-quote.h"
24 #if (defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__
25 # define WINDOWS_NATIVE
35 # define WIN32_LEAN_AND_MEAN
41 #define EXPECTED_DATA_FILE "t-sq-data.tmp"
46 check_one (enum system_command_interpreter interpreter
, const char *prog
,
54 output_len
= system_quote_length (interpreter
, input
);
56 output
= system_quote (interpreter
, input
);
57 ASSERT (strlen (output
) == output_len
);
59 ASSERT (output_len
<= sizeof (buf
) - 2);
60 memset (buf
, '\0', output_len
+ 1);
61 buf
[output_len
+ 1] = '%';
62 bufend
= system_quote_copy (buf
, interpreter
, input
);
63 ASSERT (bufend
== buf
+ output_len
);
64 ASSERT (memcmp (buf
, output
, output_len
+ 1) == 0);
65 ASSERT (buf
[output_len
+ 1] == '%');
67 /* Store INPUT in EXPECTED_DATA_FILE, for verification by the child
70 FILE *fp
= fopen (EXPECTED_DATA_FILE
, "wb");
73 if (fwrite (input
, 1, strlen (input
), fp
) != strlen (input
))
79 /* Invoke the child process through system() and popen(). */
83 sprintf (command
, "%s %s", prog
, output
);
92 int exitcode
= system (command
);
95 fprintf (stderr
, "for input = |%s|: system() command failed with status %d: %s\n",
96 input
, exitcode
, command
);
101 FILE *fp
= popen (command
, "r");
102 int exitcode
= pclose (fp
);
105 fprintf (stderr
, "for input = |%s|: popen() command failed with status %d: %s\n",
106 input
, exitcode
, command
);
111 #ifdef WINDOWS_NATIVE
112 case SCI_WINDOWS_CREATEPROCESS
:
114 PROCESS_INFORMATION pinfo
;
116 sinfo
.cb
= sizeof (STARTUPINFO
);
117 sinfo
.lpReserved
= NULL
;
118 sinfo
.lpDesktop
= NULL
;
119 sinfo
.lpTitle
= NULL
;
120 sinfo
.cbReserved2
= 0;
121 sinfo
.lpReserved2
= NULL
;
122 sinfo
.dwFlags
= STARTF_USESTDHANDLES
;
123 sinfo
.hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
124 sinfo
.hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
125 sinfo
.hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
127 if (CreateProcess (NULL
, command
, NULL
, NULL
, TRUE
, 0, NULL
, NULL
,
131 CloseHandle (pinfo
.hThread
);
132 if (WaitForSingleObject (pinfo
.hProcess
, INFINITE
) == WAIT_OBJECT_0
)
134 if (GetExitCodeProcess (pinfo
.hProcess
, &exitcode
))
138 fprintf (stderr
, "for input = |%s|: CreateProcess() command failed with status %d: %s\n",
139 input
, exitcode
, command
);
145 fprintf (stderr
, "for input = |%s|: GetExitCodeProcess failed, GetLastError() = %u\n",
146 input
, GetLastError ());
152 fprintf (stderr
, "for input = |%s|: WaitForSingleObject failed\n",
156 CloseHandle (pinfo
.hProcess
);
160 fprintf (stderr
, "for input = |%s|: CreateProcess failed, GetLastError() = %u\n",
161 input
, GetLastError ());
176 check_all (enum system_command_interpreter interpreter
,
177 bool windows_cmd_limitations
,
180 /* Check the system_quote_length, system_quote_copy, system_quote
185 /* Empty argument. */
186 check_one (interpreter
, prog
, "");
188 /* Identifier or number. */
189 check_one (interpreter
, prog
, "foo");
190 check_one (interpreter
, prog
, "phr0ck");
192 /* Whitespace would be interpreted as argument separator by the shell. */
193 check_one (interpreter
, prog
, "foo\tbar");
194 if (!windows_cmd_limitations
)
196 check_one (interpreter
, prog
, "foo\nbar");
197 check_one (interpreter
, prog
, "foo\rbar");
199 check_one (interpreter
, prog
, "foo bar");
201 /* '!' at the beginning of argv[0] would introduce a negated command. */
202 check_one (interpreter
, prog
, "!foo");
204 /* '"' would be interpreted as the start of a string. */
205 check_one (interpreter
, prog
, "\"foo\"bar");
207 /* '#' at the beginning of an argument would be interpreted as the start
209 check_one (interpreter
, prog
, "#foo");
211 /* '$' at the beginning of an argument would be interpreted as a variable
213 check_one (interpreter
, prog
, "$foo");
215 /* '&' at the beginning of an argument would be interpreted as a background
217 check_one (interpreter
, prog
, "&");
219 /* "'" would be interpreted as the start of a string. */
220 check_one (interpreter
, prog
, "'foo'bar");
222 /* '(' at the beginning of argv[0] would introduce a subshell command. */
223 check_one (interpreter
, prog
, "(");
225 /* ')' at the beginning of an argument would be interpreted as the end of
227 check_one (interpreter
, prog
, ")");
229 /* '*' would be interpreted as a wildcard character. */
230 check_one (interpreter
, prog
, "*");
231 check_one (interpreter
, prog
, "*foo");
233 /* ';' at the beginning of an argument would be interpreted as an empty
234 statement in argv[0] and as the end of the command otherwise. */
235 check_one (interpreter
, prog
, ";");
236 check_one (interpreter
, prog
, "foo;");
238 /* '<' would be interpreted as a redirection of stdin. */
239 check_one (interpreter
, prog
, "<");
241 /* '=' inside argv[0] would be interpreted as an environment variable
243 check_one (interpreter
, prog
, "foo=bar");
245 /* '>' would be interpreted as a redirection of stdout. */
246 check_one (interpreter
, prog
, ">");
248 /* '?' would be interpreted as a wildcard character. */
249 check_one (interpreter
, prog
, "?");
250 check_one (interpreter
, prog
, "??");
251 check_one (interpreter
, prog
, "???");
252 check_one (interpreter
, prog
, "????");
253 check_one (interpreter
, prog
, "?????");
254 check_one (interpreter
, prog
, "??????");
255 check_one (interpreter
, prog
, "???????");
256 check_one (interpreter
, prog
, "????????");
257 check_one (interpreter
, prog
, "?????????");
258 check_one (interpreter
, prog
, "??????????");
259 check_one (interpreter
, prog
, "foo?bar");
261 /* '^' would be interpreted in old /bin/sh, e.g. SunOS 4.1.4. */
262 check_one (interpreter
, prog
, "^");
264 /* "[...]" would be interpreted as a wildcard pattern. */
265 check_one (interpreter
, prog
, "[");
266 check_one (interpreter
, prog
, "]");
268 /* '\' would be interpreted as an escape character. */
269 check_one (interpreter
, prog
, "\\foo");
271 /* '`' would be interpreted as the start of a command substitution. */
272 check_one (interpreter
, prog
, "`foo");
274 /* '{' at the beginning of argv[0] would introduce a complex command. */
275 check_one (interpreter
, prog
, "{");
277 /* '|' at the beginning of an argument would be interpreted as a pipe
279 check_one (interpreter
, prog
, "|");
281 /* '}' at the beginning of an argument would be interpreted as the end of
283 check_one (interpreter
, prog
, "}");
285 /* '~' at the beginning of an argument would be interpreted as a reference
286 to a user's home directory. */
287 check_one (interpreter
, prog
, "~");
288 check_one (interpreter
, prog
, "~foo");
290 /* A string that contains both ' and ". */
291 check_one (interpreter
, prog
, "foo'bar\"baz");
293 /* '%' is used for environment variable references in Windows cmd.exe. */
294 check_one (interpreter
, prog
, "%");
295 check_one (interpreter
, prog
, "%%");
296 check_one (interpreter
, prog
, "%foo%");
297 check_one (interpreter
, prog
, "%PATH%");
299 /* All other characters don't need quoting. */
300 for (c
= 1; c
<= UCHAR_MAX
; c
++)
301 if (strchr ("\t\n\r !\"#$&'()*;<=>?^[\\]`{|}~", c
) == NULL
)
310 check_one (interpreter
, prog
, s
);
316 main (int argc
, char *argv
[])
322 fprintf (stderr
, "%s: need 1 argument\n", argv
[0]);
327 #ifdef WINDOWS_NATIVE
328 /* Make PROG suitable for native Windows system calls and cmd.exe:
329 Replace '/' with '\\'. */
332 for (p
= prog
; *p
!= '\0'; p
++)
338 #ifdef WINDOWS_NATIVE
339 check_all (SCI_SYSTEM
, true, prog
); /* equivalent to SCI_WINDOWS_CMD */
340 check_all (SCI_WINDOWS_CREATEPROCESS
, false, prog
);
341 check_all (SCI_WINDOWS_CMD
, true, prog
);
343 check_all (SCI_SYSTEM
, false, prog
); /* equivalent to SCI_POSIX_SH */
347 unlink (EXPECTED_DATA_FILE
);