[runtime] Rename most System.Reflection.MonoX classes to RuntimeX for consistency...
[mono-project.git] / mono / eglib / gshell.c
blob6839eee3fd32825c10520312ac3c53e65eb1c8ec
1 /*
2 * Shell utility functions.
4 * Author:
5 * Gonzalo Paniagua Javier (gonzalo@novell.com
7 * (C) 2006 Novell, Inc.
9 * Permission is hereby granted, free of charge, to any person obtaining
10 * a copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #include "config.h"
29 #include <stdio.h>
30 #include <glib.h>
32 static int
33 split_cmdline (const gchar *cmdline, GPtrArray *array, GError **gerror)
35 gchar *ptr;
36 gchar c;
37 gboolean escaped = FALSE, fresh = TRUE;
38 gchar quote_char = '\0';
39 GString *str;
41 str = g_string_new ("");
42 ptr = (gchar *) cmdline;
43 while ((c = *ptr++) != '\0') {
44 if (escaped) {
46 * \CHAR is only special inside a double quote if CHAR is
47 * one of: $`"\ and newline
49 if (quote_char == '\"'){
50 if (!(c == '$' || c == '`' || c == '"' || c == '\\'))
51 g_string_append_c (str, '\\');
52 g_string_append_c (str, c);
53 } else {
54 if (!g_ascii_isspace (c))
55 g_string_append_c (str, c);
57 escaped = FALSE;
58 } else if (quote_char) {
59 if (c == quote_char) {
60 quote_char = '\0';
61 if (fresh && (g_ascii_isspace (*ptr) || *ptr == '\0')){
62 g_ptr_array_add (array, g_string_free (str, FALSE));
63 str = g_string_new ("");
65 } else if (c == '\\'){
66 escaped = TRUE;
67 } else
68 g_string_append_c (str, c);
69 } else if (g_ascii_isspace (c)) {
70 if (str->len > 0) {
71 g_ptr_array_add (array, g_string_free (str, FALSE));
72 str = g_string_new ("");
74 } else if (c == '\\') {
75 escaped = TRUE;
76 } else if (c == '\'' || c == '"') {
77 fresh = str->len == 0;
78 quote_char = c;
79 } else {
80 g_string_append_c (str, c);
84 if (escaped) {
85 if (gerror)
86 *gerror = g_error_new (G_LOG_DOMAIN, 0, "Unfinished escape.");
87 g_string_free (str, TRUE);
88 return -1;
91 if (quote_char) {
92 if (gerror)
93 *gerror = g_error_new (G_LOG_DOMAIN, 0, "Unfinished quote.");
94 g_string_free (str, TRUE);
95 return -1;
98 if (str->len > 0) {
99 g_ptr_array_add (array, g_string_free (str, FALSE));
100 } else {
101 g_string_free (str, TRUE);
103 g_ptr_array_add (array, NULL);
104 return 0;
107 gboolean
108 g_shell_parse_argv (const gchar *command_line, gint *argcp, gchar ***argvp, GError **gerror)
110 GPtrArray *array;
111 gint argc;
112 gchar **argv;
114 g_return_val_if_fail (command_line, FALSE);
115 g_return_val_if_fail (gerror == NULL || *gerror == NULL, FALSE);
117 array = g_ptr_array_new();
118 if (split_cmdline (command_line, array, gerror)) {
119 g_ptr_array_add (array, NULL);
120 g_strfreev ((gchar **) array->pdata);
121 g_ptr_array_free (array, FALSE);
122 return FALSE;
125 argc = array->len;
126 argv = (gchar **) array->pdata;
128 if (argc == 1) {
129 g_strfreev (argv);
130 g_ptr_array_free (array, FALSE);
131 return FALSE;
134 if (argcp) {
135 *argcp = array->len - 1;
138 if (argvp) {
139 *argvp = argv;
140 } else {
141 g_strfreev (argv);
144 g_ptr_array_free (array, FALSE);
145 return TRUE;
148 gchar *
149 g_shell_quote (const gchar *unquoted_string)
151 GString *result = g_string_new ("'");
152 const gchar *p;
154 for (p = unquoted_string; *p; p++){
155 if (*p == '\'')
156 g_string_append (result, "'\\'");
157 g_string_append_c (result, *p);
159 g_string_append_c (result, '\'');
160 return g_string_free (result, FALSE);
163 gchar *
164 g_shell_unquote (const gchar *quoted_string, GError **gerror)
166 GString *result;
167 const char *p;
168 int do_unquote = 0;
170 if (quoted_string == NULL)
171 return NULL;
173 /* Quickly try to determine if we need to unquote or not */
174 for (p = quoted_string; *p; p++){
175 if (*p == '\'' || *p == '"' || *p == '\\'){
176 do_unquote = 1;
177 break;
181 if (!do_unquote)
182 return g_strdup (quoted_string);
184 /* We do need to unquote */
185 result = g_string_new ("");
186 for (p = quoted_string; *p; p++){
188 if (*p == '\''){
189 /* Process single quote, not even \ is processed by glib's version */
190 for (p++; *p; p++){
191 if (*p == '\'')
192 break;
193 g_string_append_c (result, *p);
195 if (!*p){
196 g_set_error (gerror, 0, 0, "Open quote");
197 return NULL;
199 } else if (*p == '"'){
200 /* Process double quote, allows some escaping */
201 for (p++; *p; p++){
202 if (*p == '"')
203 break;
204 if (*p == '\\'){
205 p++;
206 if (*p == 0){
207 g_set_error (gerror, 0, 0, "Open quote");
208 return NULL;
210 switch (*p){
211 case '$':
212 case '"':
213 case '\\':
214 case '`':
215 break;
216 default:
217 g_string_append_c (result, '\\');
218 break;
221 g_string_append_c (result, *p);
223 if (!*p){
224 g_set_error (gerror, 0, 0, "Open quote");
225 return NULL;
227 } else if (*p == '\\'){
228 char c = *(++p);
229 if (!(c == '$' || c == '"' || c == '\\' || c == '`' || c == '\'' || c == 0 ))
230 g_string_append_c (result, '\\');
231 if (c == 0)
232 break;
233 else
234 g_string_append_c (result, c);
235 } else
236 g_string_append_c (result, *p);
238 return g_string_free (result, FALSE);
241 #if JOINT_TEST
243 * This test is designed to be built with the 2 glib/eglib to compare
246 char *args [] = {
247 "\\",
248 "\"Foo'bar\"",
249 "'foo'",
250 "'fo\'b'",
251 "'foo\"bar'",
252 "'foo' dingus bar",
253 "'foo' 'bar' 'baz'",
254 "\"foo\" 'bar' \"baz\"",
255 "\"f\\$\\\'",
256 "\"\\",
257 "\\\\",
258 "'\\\\'",
259 "\"f\\$\"\\\"\\\\", // /\\\"\\\\"
260 "'f\\$'\\\"\\\\",
261 "'f\\$\\\\'",
262 NULL
267 main ()
269 char **s = args;
270 int i;
272 while (*s){
273 char *r1 = g_shell_unquote (*s, NULL);
274 char *r2 = g2_shell_unquote (*s, NULL);
275 char *ok = r1 == r2 ? "ok" : (r1 != NULL && r2 != NULL && strcmp (r1, r2) == 0) ? "ok" : "fail";
277 printf ("%s [%s] -> [%s] - [%s]\n", ok, *s, r1, r2);
278 s++;
280 return;
281 char buffer [10];
282 buffer [0] = '\"';
283 buffer [1] = '\\';
284 buffer [3] = '\"';
285 buffer [4] = 0;
287 for (i = 32; i < 255; i++){
288 buffer [2] = i;
289 printf ("%d [%s] -> [%s]\n", i, buffer, g_shell_unquote (buffer, NULL));
292 #endif