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__
32 /* The native Windows CreateProcess() function interprets characters like
33 ' ', '\t', '\\', '"' (but not '<' and '>') in a special way:
34 - Space and tab are interpreted as delimiters. They are not treated as
35 delimiters if they are surrounded by double quotes: "...".
36 - Unescaped double quotes are removed from the input. Their only effect is
37 that within double quotes, space and tab are treated like normal
39 - Backslashes not followed by double quotes are not special.
40 - But 2*n+1 backslashes followed by a double quote become
41 n backslashes followed by a double quote (n >= 0):
45 - '*' characters may get expanded or lead to a failure with error code
48 # 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*"
49 # 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"
51 /* Copies the quoted string to p and returns the number of bytes needed.
52 If p is non-NULL, there must be room for system_quote_length (string)
55 windows_createprocess_quote (char *p, const char *string)
57 size_t len = strlen (string);
59 (len == 0 || strpbrk (string, SHELL_SPECIAL_CHARS) != NULL);
60 size_t backslashes = 0;
73 for (; len > 0; string++, len--)
81 for (j = backslashes + 1; j > 0; j--)
94 for (j = backslashes; j > 0; j--)
102 /* The native Windows cmd.exe command interpreter also interprets:
103 - '\n', '\r' as a command terminator - no way to escape it,
104 - '<', '>' as redirections,
105 - '|' as pipe operator,
106 - '%var%' as a reference to the environment variable VAR (uppercase),
107 even inside quoted strings,
108 - '&' '[' ']' '{' '}' '^' '=' ';' '!' '\'' '+' ',' '`' '~' for other
109 purposes, according to
110 <http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cmd.mspx?mfr=true>
111 We quote a string like '%var%' by putting the '%' characters outside of
112 double-quotes and the rest of the string inside double-quotes: %"var"%.
113 This is guaranteed to not be a reference to an environment variable.
115 # 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!%&'*+,;<=>[]^`{|}~"
116 # define CMD_FORBIDDEN_CHARS "\n\r"
118 /* Copies the quoted string to p and returns the number of bytes needed.
119 If p is non-NULL, there must be room for system_quote_length (string)
122 windows_cmd_quote (char *p, const char *string)
124 size_t len = strlen (string);
126 (len == 0 || strpbrk (string, CMD_SPECIAL_CHARS) != NULL);
127 size_t backslashes = 0;
140 for (; len > 0; string++, len--)
148 for (j = backslashes + 1; j > 0; j--)
155 for (j = backslashes; j > 0; j--)
171 for (j = backslashes; j > 0; j--)
181 system_quote_length (enum system_command_interpreter interpreter,
186 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
190 return shell_quote_length (string);
192 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
193 case SCI_WINDOWS_CREATEPROCESS:
194 return windows_createprocess_quote (NULL, string);
197 case SCI_WINDOWS_CMD:
198 return windows_cmd_quote (NULL, string);
202 /* Invalid interpreter. */
208 system_quote_copy (char *p,
209 enum system_command_interpreter interpreter,
214 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
218 return shell_quote_copy (p, string);
220 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
221 case SCI_WINDOWS_CREATEPROCESS:
222 p += windows_createprocess_quote (p, string);
227 case SCI_WINDOWS_CMD:
228 p += windows_cmd_quote (p, string);
234 /* Invalid interpreter. */
240 system_quote (enum system_command_interpreter interpreter,
245 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
249 return shell_quote (string);
251 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
252 case SCI_WINDOWS_CREATEPROCESS:
254 case SCI_WINDOWS_CMD:
256 size_t length = system_quote_length (interpreter, string);
257 char *quoted = XNMALLOC (length, char);
258 system_quote_copy (quoted, interpreter, string);
264 /* Invalid interpreter. */
270 system_quote_argv (enum system_command_interpreter interpreter,
281 for (argp = argv; ; )
283 length += system_quote_length (interpreter, *argp) + 1;
289 command = XNMALLOC (length, char);
292 for (argp = argv; ; )
294 p = system_quote_copy (p, interpreter, *argp);