1 /* Quoting for a system command.
2 Copyright (C) 2012 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2012.
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3 of the License, or
8 (at your option) any later version.
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.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21 #include "system-quote.h"
30 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
31 /* The native Windows CreateProcess() function interprets characters like
32 ' ', '\t', '\\', '"' (but not '<' and '>') in a special way:
33 - Space and tab are interpreted as delimiters. They are not treated as
34 delimiters if they are surrounded by double quotes: "...".
35 - Unescaped double quotes are removed from the input. Their only effect is
36 that within double quotes, space and tab are treated like normal
38 - Backslashes not followed by double quotes are not special.
39 - But 2*n+1 backslashes followed by a double quote become
40 n backslashes followed by a double quote (n >= 0):
44 - '*' characters may get expanded or lead to a failure with error code
47 # 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*"
48 # 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"
49 /* The native Windows cmd.exe command interpreter also interprets:
50 - '\n', '\r' as a command terminator - no way to escape it,
51 - '<', '>' as redirections,
52 - '|' as pipe operator,
53 - '%var%' as a reference to the environment variable VAR (uppercase),
54 even inside quoted strings,
55 - '&' '[' ']' '{' '}' '^' '=' ';' '!' '\'' '+' ',' '`' '~' for other
56 purposes, according to
57 <http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true>
58 We quote a string like '%var%' by putting the '%' characters outside of
59 double-quotes and the rest of the string inside double-quotes: %"var"%.
60 This is guaranteed to not be a reference to an environment variable.
62 # define CMD_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!%&'*+,;<=>[]^`{|}~"
63 # define CMD_FORBIDDEN_CHARS "\n\r"
67 system_quote_length (enum system_command_interpreter interpreter,
72 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
76 return shell_quote_length (string);
78 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
79 case SCI_WINDOWS_CREATEPROCESS:
81 size_t len = strlen (string);
83 (len == 0 || strpbrk (string, SHELL_SPECIAL_CHARS) != NULL);
84 size_t backslashes = 0;
89 for (; len > 0; string++, len--)
94 length += backslashes + 1;
101 length += backslashes + 1;
106 case SCI_WINDOWS_CMD:
108 size_t len = strlen (string);
110 (len == 0 || strpbrk (string, CMD_SPECIAL_CHARS) != NULL);
111 size_t backslashes = 0;
116 for (; len > 0; string++, len--)
121 length += backslashes + 1;
123 length += backslashes + 2;
130 length += backslashes + 1;
136 /* Invalid interpreter. */
142 system_quote_copy (char *p,
143 enum system_command_interpreter interpreter,
148 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
152 return shell_quote_copy (p, string);
154 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
155 case SCI_WINDOWS_CREATEPROCESS:
157 size_t len = strlen (string);
159 (len == 0 || strpbrk (string, SHELL_SPECIAL_CHARS) != NULL);
160 size_t backslashes = 0;
164 for (; len > 0; string++, len--)
172 for (j = backslashes + 1; j > 0; j--)
185 for (j = backslashes; j > 0; j--)
194 case SCI_WINDOWS_CMD:
196 size_t len = strlen (string);
198 (len == 0 || strpbrk (string, CMD_SPECIAL_CHARS) != NULL);
199 size_t backslashes = 0;
203 for (; len > 0; string++, len--)
211 for (j = backslashes + 1; j > 0; j--)
218 for (j = backslashes; j > 0; j--)
234 for (j = backslashes; j > 0; j--)
244 /* Invalid interpreter. */
250 system_quote (enum system_command_interpreter interpreter,
255 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
259 return shell_quote (string);
261 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
262 case SCI_WINDOWS_CREATEPROCESS:
264 case SCI_WINDOWS_CMD:
266 size_t length = system_quote_length (interpreter, string);
267 char *quoted = XNMALLOC (length, char);
268 system_quote_copy (quoted, interpreter, string);
274 /* Invalid interpreter. */
280 system_quote_argv (enum system_command_interpreter interpreter,
291 for (argp = argv; ; )
293 length += system_quote_length (interpreter, *argp) + 1;
299 command = XNMALLOC (length, char);
302 for (argp = argv; ; )
304 p = system_quote_copy (p, interpreter, *argp);