1 /* Test of system-quote module.
2 Copyright (C) 2012-2014 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 <http://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
42 #define EXPECTED_DATA_FILE "t-sq-data.tmp"
47 check_one (enum system_command_interpreter interpreter, const char *prog,
55 output_len = system_quote_length (interpreter, input);
57 output = system_quote (interpreter, input);
58 ASSERT (strlen (output) == output_len);
60 ASSERT (output_len <= sizeof (buf) - 2);
61 memset (buf, '\0', output_len + 1);
62 buf[output_len + 1] = '%';
63 bufend = system_quote_copy (buf, interpreter, input);
64 ASSERT (bufend == buf + output_len);
65 ASSERT (memcmp (buf, output, output_len + 1) == 0);
66 ASSERT (buf[output_len + 1] == '%');
68 /* Store INPUT in EXPECTED_DATA_FILE, for verification by the child
71 FILE *fp = fopen (EXPECTED_DATA_FILE, "wb");
74 if (fwrite (input, 1, strlen (input), fp) != strlen (input))
80 /* Invoke the child process through system() and popen(). */
84 sprintf (command, "%s %s", prog, output);
93 int exitcode = system (command);
96 fprintf (stderr, "for input = |%s|: system() command failed with status %d: %s\n",
97 input, exitcode, command);
102 FILE *fp = popen (command, "r");
103 int exitcode = pclose (fp);
106 fprintf (stderr, "for input = |%s|: popen() command failed with status %d: %s\n",
107 input, exitcode, command);
112 #ifdef WINDOWS_NATIVE
113 case SCI_WINDOWS_CREATEPROCESS:
115 PROCESS_INFORMATION pinfo;
117 sinfo.cb = sizeof (STARTUPINFO);
118 sinfo.lpReserved = NULL;
119 sinfo.lpDesktop = NULL;
120 sinfo.lpTitle = NULL;
121 sinfo.cbReserved2 = 0;
122 sinfo.lpReserved2 = NULL;
123 sinfo.dwFlags = STARTF_USESTDHANDLES;
124 sinfo.hStdInput = GetStdHandle (STD_INPUT_HANDLE);
125 sinfo.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
126 sinfo.hStdError = GetStdHandle (STD_ERROR_HANDLE);
128 if (CreateProcess (NULL, command, NULL, NULL, TRUE, 0, NULL, NULL,
132 CloseHandle (pinfo.hThread);
133 if (WaitForSingleObject (pinfo.hProcess, INFINITE) == WAIT_OBJECT_0)
135 if (GetExitCodeProcess (pinfo.hProcess, &exitcode))
139 fprintf (stderr, "for input = |%s|: CreateProcess() command failed with status %d: %s\n",
140 input, exitcode, command);
146 fprintf (stderr, "for input = |%s|: GetExitCodeProcess failed, GetLastError() = %u\n",
147 input, GetLastError ());
153 fprintf (stderr, "for input = |%s|: WaitForSingleObject failed\n",
157 CloseHandle (pinfo.hProcess);
161 fprintf (stderr, "for input = |%s|: CreateProcess failed, GetLastError() = %u\n",
162 input, GetLastError ());
177 check_all (enum system_command_interpreter interpreter,
178 bool windows_cmd_limitations,
181 /* Check the system_quote_length, system_quote_copy, system_quote
186 /* Empty argument. */
187 check_one (interpreter, prog, "");
189 /* Identifier or number. */
190 check_one (interpreter, prog, "foo");
191 check_one (interpreter, prog, "phr0ck");
193 /* Whitespace would be interpreted as argument separator by the shell. */
194 check_one (interpreter, prog, "foo\tbar");
195 if (!windows_cmd_limitations)
197 check_one (interpreter, prog, "foo\nbar");
198 check_one (interpreter, prog, "foo\rbar");
200 check_one (interpreter, prog, "foo bar");
202 /* '!' at the beginning of argv[0] would introduce a negated command. */
203 check_one (interpreter, prog, "!foo");
205 /* '"' would be interpreted as the start of a string. */
206 check_one (interpreter, prog, "\"foo\"bar");
208 /* '#' at the beginning of an argument would be interpreted as the start
210 check_one (interpreter, prog, "#foo");
212 /* '$' at the beginning of an argument would be interpreted as a variable
214 check_one (interpreter, prog, "$foo");
216 /* '&' at the beginning of an argument would be interpreted as a background
218 check_one (interpreter, prog, "&");
220 /* "'" would be interpreted as the start of a string. */
221 check_one (interpreter, prog, "'foo'bar");
223 /* '(' at the beginning of argv[0] would introduce a subshell command. */
224 check_one (interpreter, prog, "(");
226 /* ')' at the beginning of an argument would be interpreted as the end of
228 check_one (interpreter, prog, ")");
230 /* '*' would be interpreted as a wildcard character. */
231 check_one (interpreter, prog, "*");
232 check_one (interpreter, prog, "*foo");
234 /* ';' at the beginning of an argument would be interpreted as an empty
235 statement in argv[0] and as the end of the command otherwise. */
236 check_one (interpreter, prog, ";");
237 check_one (interpreter, prog, "foo;");
239 /* '<' would be interpreted as a redirection of stdin. */
240 check_one (interpreter, prog, "<");
242 /* '=' inside argv[0] would be interpreted as an environment variable
244 check_one (interpreter, prog, "foo=bar");
246 /* '>' would be interpreted as a redirection of stdout. */
247 check_one (interpreter, prog, ">");
249 /* '?' would be interpreted as a wildcard character. */
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, "??????????");
260 check_one (interpreter, prog, "foo?bar");
262 /* '^' would be interpreted in old /bin/sh, e.g. SunOS 4.1.4. */
263 check_one (interpreter, prog, "^");
265 /* "[...]" would be interpreted as a wildcard pattern. */
266 check_one (interpreter, prog, "[");
267 check_one (interpreter, prog, "]");
269 /* '\' would be interpreted as an escape character. */
270 check_one (interpreter, prog, "\\foo");
272 /* '`' would be interpreted as the start of a command substitution. */
273 check_one (interpreter, prog, "`foo");
275 /* '{' at the beginning of argv[0] would introduce a complex command. */
276 check_one (interpreter, prog, "{");
278 /* '|' at the beginning of an argument would be interpreted as a pipe
280 check_one (interpreter, prog, "|");
282 /* '}' at the beginning of an argument would be interpreted as the end of
284 check_one (interpreter, prog, "}");
286 /* '~' at the beginning of an argument would be interpreted as a reference
287 to a user's home directory. */
288 check_one (interpreter, prog, "~");
289 check_one (interpreter, prog, "~foo");
291 /* A string that contains both ' and ". */
292 check_one (interpreter, prog, "foo'bar\"baz");
294 /* '%' is used for environment variable references in Windows cmd.exe. */
295 check_one (interpreter, prog, "%");
296 check_one (interpreter, prog, "%%");
297 check_one (interpreter, prog, "%foo%");
298 check_one (interpreter, prog, "%PATH%");
300 /* All other characters don't need quoting. */
301 for (c = 1; c <= UCHAR_MAX; c++)
302 if (strchr ("\t\n\r !\"#$&'()*;<=>?^[\\]`{|}~", c) == NULL)
311 check_one (interpreter, prog, s);
317 main (int argc, char *argv[])
321 set_program_name (argv[0]);
325 fprintf (stderr, "%s: need 1 argument\n", argv[0]);
330 #ifdef WINDOWS_NATIVE
331 /* Make PROG suitable for native Windows system calls and cmd.exe:
332 Replace '/' with '\\'. */
335 for (p = prog; *p != '\0'; p++)
341 #ifdef WINDOWS_NATIVE
342 check_all (SCI_SYSTEM, true, prog); /* equivalent to SCI_WINDOWS_CMD */
343 check_all (SCI_WINDOWS_CREATEPROCESS, false, prog);
344 check_all (SCI_WINDOWS_CMD, true, prog);
346 check_all (SCI_SYSTEM, false, prog); /* equivalent to SCI_POSIX_SH */
350 unlink (EXPECTED_DATA_FILE);