Remap more eglib symbols
[mono.git] / eglib / src / gshell.c
1 /*
2  * Shell utility functions.
3  *
4  * Author:
5  *   Gonzalo Paniagua Javier (gonzalo@novell.com
6  *
7  * (C) 2006 Novell, Inc.
8  *
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:
16  *
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  *
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.
27  */
28 #include <stdio.h>
29 #include <glib.h>
30
31 static int
32 split_cmdline (const gchar *cmdline, GPtrArray *array, GError **error)
33 {
34         gchar *ptr;
35         gchar c;
36         gboolean escaped = FALSE;
37         gchar quote_char = '\0';
38         GString *str;
39
40         str = g_string_new ("");
41         ptr = (gchar *) cmdline;
42         while ((c = *ptr++) != '\0') {
43                 if (escaped) {
44                         /*
45                          * \CHAR is only special inside a double quote if CHAR is
46                          * one of: $`"\ and newline
47                          */
48                         if (quote_char == '\"'){
49                                 if (!(c == '$' || c == '`' || c == '"' || c == '\\'))
50                                         g_string_append_c (str, '\\');
51                                 g_string_append_c (str, c);
52                         } else {
53                                 if (!g_ascii_isspace (c))
54                                         g_string_append_c (str, c);
55                         }
56                         escaped = FALSE;
57                 } else if (quote_char) {
58                         if (c == quote_char) {
59                                 quote_char = '\0';
60                                 g_ptr_array_add (array, g_string_free (str, FALSE));
61                                 str = g_string_new ("");
62                         } else if (c == '\\'){
63                                 escaped = TRUE;
64                         } else 
65                                 g_string_append_c (str, c);
66                 } else if (g_ascii_isspace (c)) {
67                         if (str->len > 0) {
68                                 g_ptr_array_add (array, g_string_free (str, FALSE));
69                                 str = g_string_new ("");
70                         }
71                 } else if (c == '\\') {
72                         escaped = TRUE;
73                 } else if (c == '\'' || c == '"') {
74                         quote_char = c;
75                 } else {
76                         g_string_append_c (str, c);
77                 }
78         }
79
80         if (escaped) {
81                 if (error)
82                         *error = g_error_new (G_LOG_DOMAIN, 0, "Unfinished escape.");
83                 g_string_free (str, TRUE);
84                 return -1;
85         }
86
87         if (quote_char) {
88                 if (error)
89                         *error = g_error_new (G_LOG_DOMAIN, 0, "Unfinished quote.");
90                 g_string_free (str, TRUE);
91                 return -1;
92         }
93
94         if (str->len > 0) {
95                 g_ptr_array_add (array, g_string_free (str, FALSE));
96         } else {
97                 g_string_free (str, TRUE);
98         }
99         g_ptr_array_add (array, NULL);
100         return 0;
101 }
102
103 gboolean
104 g_shell_parse_argv (const gchar *command_line, gint *argcp, gchar ***argvp, GError **error)
105 {
106         GPtrArray *array;
107         gint argc;
108         gchar **argv;
109
110         g_return_val_if_fail (command_line, FALSE);
111         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
112
113         array = g_ptr_array_new();
114         if (split_cmdline (command_line, array, error)) {
115                 g_ptr_array_add (array, NULL);
116                 g_strfreev ((gchar **) array->pdata);
117                 g_ptr_array_free (array, FALSE);
118                 return FALSE;
119         }
120
121         argc = array->len;
122         argv = (gchar **) array->pdata;
123
124         if (argc == 1) {
125                 g_strfreev (argv);
126                 g_ptr_array_free (array, FALSE);
127                 return FALSE;
128         }
129
130         if (argcp) {
131                 *argcp = array->len - 1;
132         }
133
134         if (argvp) {
135                 *argvp = argv;
136         } else {
137                 g_strfreev (argv);
138         }
139
140         g_ptr_array_free (array, FALSE);
141         return TRUE;
142 }
143
144 gchar *
145 g_shell_quote (const gchar *unquoted_string)
146 {
147         GString *result = g_string_new ("'");
148         const gchar *p;
149         
150         for (p = unquoted_string; *p; p++){
151                 if (*p == '\'')
152                         g_string_append (result, "'\\'");
153                 g_string_append_c (result, *p);
154         }
155         g_string_append_c (result, '\'');
156         return g_string_free (result, FALSE);
157 }
158
159 gchar *
160 g_shell_unquote (const gchar *quoted_string, GError **error)
161 {
162         GString *result;
163         const char *p;
164         int do_unquote = 0;
165
166         if (quoted_string == NULL)
167                 return NULL;
168         
169         /* Quickly try to determine if we need to unquote or not */
170         for (p = quoted_string; *p; p++){
171                 if (*p == '\'' || *p == '"' || *p == '\\'){
172                         do_unquote = 1;
173                         break;
174                 }
175         }
176         
177         if (!do_unquote)
178                 return g_strdup (quoted_string);
179
180         /* We do need to unquote */
181         result = g_string_new ("");
182         for (p = quoted_string; *p; p++){
183
184                 if (*p == '\''){
185                         /* Process single quote, not even \ is processed by glib's version */
186                         for (p++; *p; p++){
187                                 if (*p == '\'')
188                                         break;
189                                 g_string_append_c (result, *p);
190                         }
191                         if (!*p){
192                                 g_set_error (error, 0, 0, "Open quote");
193                                 return NULL;
194                         }
195                 } else if (*p == '"'){
196                         /* Process double quote, allows some escaping */
197                         for (p++; *p; p++){
198                                 if (*p == '"')
199                                         break;
200                                 if (*p == '\\'){
201                                         p++;
202                                         if (*p == 0){
203                                                 g_set_error (error, 0, 0, "Open quote");
204                                                 return NULL;
205                                         }
206                                         switch (*p){
207                                         case '$':
208                                         case '"':
209                                         case '\\':
210                                         case '`':
211                                                 break;
212                                         default:
213                                                 g_string_append_c (result, '\\');
214                                                 break;
215                                         }
216                                 } 
217                                 g_string_append_c (result, *p);
218                         }
219                         if (!*p){
220                                 g_set_error (error, 0, 0, "Open quote");
221                                 return NULL;
222                         }
223                 } else if (*p == '\\'){
224                         char c = *(++p);
225                         if (!(c == '$' || c == '"' || c == '\\' || c == '`' || c == 0))
226                                 g_string_append_c (result, '\\');
227                         if (c == 0)
228                                 break;
229                         else
230                                 g_string_append_c (result, c);
231                 } else
232                         g_string_append_c (result, *p);
233         }
234         return g_string_free (result, FALSE);
235 }
236
237 #if JOINT_TEST
238 /*
239  * This test is designed to be built with the 2 glib/eglib to compare
240  */
241
242 char *args [] = {
243         "\\",
244         "\"Foo'bar\"",
245         "'foo'",
246         "'fo\'b'",
247         "'foo\"bar'",
248         "'foo' dingus bar",
249         "'foo' 'bar' 'baz'",
250         "\"foo\" 'bar' \"baz\"",
251         "\"f\\$\\\'",
252         "\"\\",
253         "\\\\",
254         "'\\\\'",
255         "\"f\\$\"\\\"\\\\", //  /\\\"\\\\"
256         "'f\\$'\\\"\\\\", 
257         "'f\\$\\\\'", 
258         NULL
259 };
260
261
262 int
263 main ()
264 {
265         char **s = args;
266         int i;
267         
268         while (*s){
269                 char *r1 = g_shell_unquote (*s, NULL);
270                 char *r2 = g2_shell_unquote (*s, NULL);
271                 char *ok = r1 == r2 ? "ok" : (r1 != NULL && r2 != NULL && strcmp (r1, r2) == 0) ? "ok" : "fail";
272                 
273                 printf ("%s [%s] -> [%s] - [%s]\n", ok, *s, r1, r2);
274                 s++;
275         }
276         return;
277         char buffer [10];
278         buffer [0] = '\"';
279         buffer [1] = '\\';
280         buffer [3] = '\"';
281         buffer [4] = 0;
282         
283         for (i = 32; i < 255; i++){
284                 buffer [2] = i;
285                 printf ("%d [%s] -> [%s]\n", i, buffer, g_shell_unquote (buffer, NULL));
286         }
287 }
288 #endif