Branch data Line data Source code
1 : : /* gshell.c - Shell-related utilities
2 : : *
3 : : * Copyright 2000 Red Hat, Inc.
4 : : * g_execvpe implementation based on GNU libc execvp:
5 : : * Copyright 1991, 92, 95, 96, 97, 98, 99 Free Software Foundation, Inc.
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2.1 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General Public License
20 : : * along with this library; if not, see <http://www.gnu.org/licenses/>.
21 : : */
22 : :
23 : : #include "config.h"
24 : :
25 : : #include <string.h>
26 : :
27 : : #include "gshell.h"
28 : :
29 : : #include "gslist.h"
30 : : #include "gstrfuncs.h"
31 : : #include "gstring.h"
32 : : #include "gtestutils.h"
33 : : #include "glibintl.h"
34 : : #include "gthread.h"
35 : :
36 : : /**
37 : : * G_SHELL_ERROR:
38 : : *
39 : : * Error domain for shell functions.
40 : : *
41 : : * Errors in this domain will be from the #GShellError enumeration.
42 : : *
43 : : * See #GError for information on error domains.
44 : : **/
45 : :
46 : : /**
47 : : * GShellError:
48 : : * @G_SHELL_ERROR_BAD_QUOTING: Mismatched or otherwise mangled quoting.
49 : : * @G_SHELL_ERROR_EMPTY_STRING: String to be parsed was empty.
50 : : * @G_SHELL_ERROR_FAILED: Some other error.
51 : : *
52 : : * Error codes returned by shell functions.
53 : : **/
54 [ + + ]: 21 : G_DEFINE_QUARK (g-shell-error-quark, g_shell_error)
55 : :
56 : : /* Single quotes preserve the literal string exactly. escape
57 : : * sequences are not allowed; not even \' - if you want a '
58 : : * in the quoted text, you have to do something like 'foo'\''bar'
59 : : *
60 : : * Double quotes allow $ ` " \ and newline to be escaped with backslash.
61 : : * Otherwise double quotes preserve things literally.
62 : : */
63 : :
64 : : static gboolean
65 : 211 : unquote_string_inplace (gchar* str, gchar** end, GError** err)
66 : : {
67 : : gchar* dest;
68 : : gchar* s;
69 : : gchar quote_char;
70 : :
71 : 211 : g_return_val_if_fail(end != NULL, FALSE);
72 : 211 : g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
73 : 211 : g_return_val_if_fail(str != NULL, FALSE);
74 : :
75 : 211 : dest = s = str;
76 : :
77 : 211 : quote_char = *s;
78 : :
79 [ + + - + ]: 211 : if (!(*s == '"' || *s == '\''))
80 : : {
81 : 0 : g_set_error_literal (err,
82 : : G_SHELL_ERROR,
83 : : G_SHELL_ERROR_BAD_QUOTING,
84 : : _("Quoted text doesn’t begin with a quotation mark"));
85 : 0 : *end = str;
86 : 0 : return FALSE;
87 : : }
88 : :
89 : : /* Skip the initial quote mark */
90 : 211 : ++s;
91 : :
92 [ + + ]: 211 : if (quote_char == '"')
93 : : {
94 [ + + ]: 124 : while (*s)
95 : : {
96 : 123 : g_assert(s > dest); /* loop invariant */
97 : :
98 [ + + + ]: 123 : switch (*s)
99 : : {
100 : 19 : case '"':
101 : : /* End of the string, return now */
102 : 19 : *dest = '\0';
103 : 19 : ++s;
104 : 19 : *end = s;
105 : 19 : return TRUE;
106 : : break;
107 : :
108 : 11 : case '\\':
109 : : /* Possible escaped quote or \ */
110 : 11 : ++s;
111 [ + + ]: 11 : switch (*s)
112 : : {
113 : 8 : case '"':
114 : : case '\\':
115 : : case '`':
116 : : case '$':
117 : : case '\n':
118 : 8 : *dest = *s;
119 : 8 : ++s;
120 : 8 : ++dest;
121 : 8 : break;
122 : :
123 : 3 : default:
124 : : /* not an escaped char */
125 : 3 : *dest = '\\';
126 : 3 : ++dest;
127 : : /* ++s already done. */
128 : 3 : break;
129 : : }
130 : 11 : break;
131 : :
132 : 93 : default:
133 : 93 : *dest = *s;
134 : 93 : ++dest;
135 : 93 : ++s;
136 : 93 : break;
137 : : }
138 : :
139 : 104 : g_assert(s > dest); /* loop invariant */
140 : : }
141 : : }
142 : : else
143 : : {
144 [ + + ]: 7978 : while (*s)
145 : : {
146 : 7976 : g_assert(s > dest); /* loop invariant */
147 : :
148 [ + + ]: 7976 : if (*s == '\'')
149 : : {
150 : : /* End of the string, return now */
151 : 189 : *dest = '\0';
152 : 189 : ++s;
153 : 189 : *end = s;
154 : 189 : return TRUE;
155 : : }
156 : : else
157 : : {
158 : 7787 : *dest = *s;
159 : 7787 : ++dest;
160 : 7787 : ++s;
161 : : }
162 : :
163 : 7787 : g_assert(s > dest); /* loop invariant */
164 : : }
165 : : }
166 : :
167 : : /* If we reach here this means the close quote was never encountered */
168 : :
169 : 3 : *dest = '\0';
170 : :
171 : 3 : g_set_error_literal (err,
172 : : G_SHELL_ERROR,
173 : : G_SHELL_ERROR_BAD_QUOTING,
174 : : _("Unmatched quotation mark in command line or other shell-quoted text"));
175 : 3 : *end = s;
176 : 3 : return FALSE;
177 : : }
178 : :
179 : : /**
180 : : * g_shell_quote:
181 : : * @unquoted_string: (type filename): a literal string
182 : : *
183 : : * Quotes a string so that the shell (/bin/sh) will interpret the
184 : : * quoted string to mean @unquoted_string.
185 : : *
186 : : * If you pass a filename to the shell, for example, you should first
187 : : * quote it with this function.
188 : : *
189 : : * The return value must be freed with g_free().
190 : : *
191 : : * The quoting style used is undefined (single or double quotes may be
192 : : * used).
193 : : *
194 : : * Returns: (type filename) (transfer full): quoted string
195 : : **/
196 : : gchar*
197 : 152 : g_shell_quote (const gchar *unquoted_string)
198 : : {
199 : : /* We always use single quotes, because the algorithm is cheesier.
200 : : * We could use double if we felt like it, that might be more
201 : : * human-readable.
202 : : */
203 : :
204 : : const gchar *p;
205 : : GString *dest;
206 : :
207 : 152 : g_return_val_if_fail (unquoted_string != NULL, NULL);
208 : :
209 : 152 : dest = g_string_new ("'");
210 : :
211 : 152 : p = unquoted_string;
212 : :
213 : : /* could speed this up a lot by appending chunks of text at a
214 : : * time.
215 : : */
216 [ + + ]: 7567 : while (*p)
217 : : {
218 : : /* Replace literal ' with a close ', a \', and an open ' */
219 [ + + ]: 7415 : if (*p == '\'')
220 [ + - ]: 8 : g_string_append (dest, "'\\''");
221 : : else
222 [ + - ]: 7411 : g_string_append_c (dest, *p);
223 : :
224 : 7415 : ++p;
225 : : }
226 : :
227 : : /* close the quote */
228 : : g_string_append_c (dest, '\'');
229 : :
230 : 152 : return g_string_free (dest, FALSE);
231 : : }
232 : :
233 : : /**
234 : : * g_shell_unquote:
235 : : * @quoted_string: (type filename): shell-quoted string
236 : : * @error: error return location or NULL
237 : : *
238 : : * Unquotes a string as the shell (/bin/sh) would.
239 : : *
240 : : * This function only handles quotes; if a string contains file globs,
241 : : * arithmetic operators, variables, backticks, redirections, or other
242 : : * special-to-the-shell features, the result will be different from the
243 : : * result a real shell would produce (the variables, backticks, etc.
244 : : * will be passed through literally instead of being expanded).
245 : : *
246 : : * This function is guaranteed to succeed if applied to the result of
247 : : * g_shell_quote(). If it fails, it returns %NULL and sets the
248 : : * error.
249 : : *
250 : : * The @quoted_string need not actually contain quoted or escaped text;
251 : : * g_shell_unquote() simply goes through the string and unquotes/unescapes
252 : : * anything that the shell would. Both single and double quotes are
253 : : * handled, as are escapes including escaped newlines.
254 : : *
255 : : * The return value must be freed with g_free().
256 : : *
257 : : * Possible errors are in the %G_SHELL_ERROR domain.
258 : : *
259 : : * Shell quoting rules are a bit strange. Single quotes preserve the
260 : : * literal string exactly. escape sequences are not allowed; not even
261 : : * `\'` - if you want a `'` in the quoted text, you have to do something
262 : : * like `'foo'\''bar'`. Double quotes allow `$`, ```, `"`, `\`, and
263 : : * newline to be escaped with backslash. Otherwise double quotes
264 : : * preserve things literally.
265 : : *
266 : : * Returns: (type filename): an unquoted string
267 : : **/
268 : : gchar*
269 : 1188 : g_shell_unquote (const gchar *quoted_string,
270 : : GError **error)
271 : : {
272 : : gchar *unquoted;
273 : : gchar *end;
274 : : gchar *start;
275 : : GString *retval;
276 : :
277 : 1188 : g_return_val_if_fail (quoted_string != NULL, NULL);
278 : :
279 : 1188 : unquoted = g_strdup (quoted_string);
280 : :
281 : 1188 : start = unquoted;
282 : 1188 : end = unquoted;
283 : 1188 : retval = g_string_new (NULL);
284 : :
285 : : /* The loop allows cases such as
286 : : * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo'
287 : : */
288 [ + + ]: 3570 : while (*start)
289 : : {
290 : : /* Append all non-quoted chars, honoring backslash escape
291 : : */
292 : :
293 [ + + + + : 12424 : while (*start && !(*start == '"' || *start == '\''))
+ + ]
294 : : {
295 [ + + ]: 11227 : if (*start == '\\')
296 : : {
297 : : /* all characters can get escaped by backslash,
298 : : * except newline, which is removed if it follows
299 : : * a backslash outside of quotes
300 : : */
301 : :
302 : 11 : ++start;
303 [ + - ]: 11 : if (*start)
304 : : {
305 [ + + ]: 11 : if (*start != '\n')
306 [ + - ]: 10 : g_string_append_c (retval, *start);
307 : 11 : ++start;
308 : : }
309 : : }
310 : : else
311 : : {
312 [ + - ]: 11216 : g_string_append_c (retval, *start);
313 : 11216 : ++start;
314 : : }
315 : : }
316 : :
317 [ + + ]: 1197 : if (*start)
318 : : {
319 [ + + ]: 211 : if (!unquote_string_inplace (start, &end, error))
320 : : {
321 : 3 : goto error;
322 : : }
323 : : else
324 : : {
325 : : g_string_append (retval, start);
326 : 208 : start = end;
327 : : }
328 : : }
329 : : }
330 : :
331 : 1185 : g_free (unquoted);
332 : 1185 : return g_string_free (retval, FALSE);
333 : :
334 : 3 : error:
335 : 3 : g_assert (error == NULL || *error != NULL);
336 : :
337 : 3 : g_free (unquoted);
338 : 3 : g_string_free (retval, TRUE);
339 : 3 : return NULL;
340 : : }
341 : :
342 : : /* g_parse_argv() does a semi-arbitrary weird subset of the way
343 : : * the shell parses a command line. We don't do variable expansion,
344 : : * don't understand that operators are tokens, don't do tilde expansion,
345 : : * don't do command substitution, no arithmetic expansion, IFS gets ignored,
346 : : * don't do filename globs, don't remove redirection stuff, etc.
347 : : *
348 : : * READ THE UNIX98 SPEC on "Shell Command Language" before changing
349 : : * the behavior of this code.
350 : : *
351 : : * Steps to parsing the argv string:
352 : : *
353 : : * - tokenize the string (but since we ignore operators,
354 : : * our tokenization may diverge from what the shell would do)
355 : : * note that tokenization ignores the internals of a quoted
356 : : * word and it always splits on spaces, not on IFS even
357 : : * if we used IFS. We also ignore "end of input indicator"
358 : : * (I guess this is control-D?)
359 : : *
360 : : * Tokenization steps, from UNIX98 with operator stuff removed,
361 : : * are:
362 : : *
363 : : * 1) "If the current character is backslash, single-quote or
364 : : * double-quote (\, ' or ") and it is not quoted, it will affect
365 : : * quoting for subsequent characters up to the end of the quoted
366 : : * text. The rules for quoting are as described in Quoting
367 : : * . During token recognition no substitutions will be actually
368 : : * performed, and the result token will contain exactly the
369 : : * characters that appear in the input (except for newline
370 : : * character joining), unmodified, including any embedded or
371 : : * enclosing quotes or substitution operators, between the quote
372 : : * mark and the end of the quoted text. The token will not be
373 : : * delimited by the end of the quoted field."
374 : : *
375 : : * 2) "If the current character is an unquoted newline character,
376 : : * the current token will be delimited."
377 : : *
378 : : * 3) "If the current character is an unquoted blank character, any
379 : : * token containing the previous character is delimited and the
380 : : * current character will be discarded."
381 : : *
382 : : * 4) "If the previous character was part of a word, the current
383 : : * character will be appended to that word."
384 : : *
385 : : * 5) "If the current character is a "#", it and all subsequent
386 : : * characters up to, but excluding, the next newline character
387 : : * will be discarded as a comment. The newline character that
388 : : * ends the line is not considered part of the comment. The
389 : : * "#" starts a comment only when it is at the beginning of a
390 : : * token. Since the search for the end-of-comment does not
391 : : * consider an escaped newline character specially, a comment
392 : : * cannot be continued to the next line."
393 : : *
394 : : * 6) "The current character will be used as the start of a new word."
395 : : *
396 : : *
397 : : * - for each token (word), perform portions of word expansion, namely
398 : : * field splitting (using default whitespace IFS) and quote
399 : : * removal. Field splitting may increase the number of words.
400 : : * Quote removal does not increase the number of words.
401 : : *
402 : : * "If the complete expansion appropriate for a word results in an
403 : : * empty field, that empty field will be deleted from the list of
404 : : * fields that form the completely expanded command, unless the
405 : : * original word contained single-quote or double-quote characters."
406 : : * - UNIX98 spec
407 : : *
408 : : *
409 : : */
410 : :
411 : : static inline void
412 : 19182 : ensure_token (GString **token)
413 : : {
414 [ + + ]: 19182 : if (*token == NULL)
415 : 1158 : *token = g_string_new (NULL);
416 : 19182 : }
417 : :
418 : : static void
419 : 1172 : delimit_token (GString **token,
420 : : GSList **retval)
421 : : {
422 [ + + ]: 1172 : if (*token == NULL)
423 : 14 : return;
424 : :
425 : 1158 : *retval = g_slist_prepend (*retval, g_string_free (*token, FALSE));
426 : :
427 : 1158 : *token = NULL;
428 : : }
429 : :
430 : : static GSList*
431 : 422 : tokenize_command_line (const gchar *command_line,
432 : : GError **error)
433 : : {
434 : : gchar current_quote;
435 : : const gchar *p;
436 : 422 : GString *current_token = NULL;
437 : 422 : GSList *retval = NULL;
438 : : gboolean quoted;
439 : :
440 : 422 : current_quote = '\0';
441 : 422 : quoted = FALSE;
442 : 422 : p = command_line;
443 : :
444 [ + + ]: 20410 : while (*p)
445 : : {
446 [ + + ]: 19990 : if (current_quote == '\\')
447 : : {
448 [ + + ]: 6 : if (*p == '\n')
449 : : {
450 : : /* we append nothing; backslash-newline become nothing */
451 : : }
452 : : else
453 : : {
454 : : /* we append the backslash and the current char,
455 : : * to be interpreted later after tokenization
456 : : */
457 : 5 : ensure_token (¤t_token);
458 [ + - ]: 5 : g_string_append_c (current_token, '\\');
459 [ + - ]: 5 : g_string_append_c (current_token, *p);
460 : : }
461 : :
462 : 6 : current_quote = '\0';
463 : : }
464 [ + + ]: 19984 : else if (current_quote == '#')
465 : : {
466 : : /* Discard up to and including next newline */
467 [ + + + + ]: 26 : while (*p && *p != '\n')
468 : 23 : ++p;
469 : :
470 : 3 : current_quote = '\0';
471 : :
472 [ + + ]: 3 : if (*p == '\0')
473 : 2 : break;
474 : : }
475 [ + + ]: 19981 : else if (current_quote)
476 : : {
477 [ + + + + ]: 7774 : if (*p == current_quote &&
478 : : /* check that it isn't an escaped double quote */
479 [ + + ]: 7 : !(current_quote == '"' && quoted))
480 : : {
481 : : /* close the quote */
482 : 174 : current_quote = '\0';
483 : : }
484 : :
485 : : /* Everything inside quotes, and the close quote,
486 : : * gets appended literally.
487 : : */
488 : :
489 : 7774 : ensure_token (¤t_token);
490 [ + - ]: 7774 : g_string_append_c (current_token, *p);
491 : : }
492 : : else
493 : : {
494 [ - + + + : 12207 : switch (*p)
+ + ]
495 : : {
496 : 0 : case '\n':
497 : 0 : delimit_token (¤t_token, &retval);
498 : 0 : break;
499 : :
500 : 794 : case ' ':
501 : : case '\t':
502 : : /* If the current token contains the previous char, delimit
503 : : * the current token. A nonzero length
504 : : * token should always contain the previous char.
505 : : */
506 [ + + ]: 794 : if (current_token &&
507 [ + - ]: 750 : current_token->len > 0)
508 : : {
509 : 750 : delimit_token (¤t_token, &retval);
510 : : }
511 : :
512 : : /* discard all unquoted blanks (don't add them to a token) */
513 : 794 : break;
514 : :
515 : :
516 : : /* single/double quotes are appended to the token,
517 : : * escapes are maybe appended next time through the loop,
518 : : * comment chars are never appended.
519 : : */
520 : :
521 : 176 : case '\'':
522 : : case '"':
523 : 176 : ensure_token (¤t_token);
524 [ + - ]: 176 : g_string_append_c (current_token, *p);
525 : :
526 : : G_GNUC_FALLTHROUGH;
527 : 183 : case '\\':
528 : 183 : current_quote = *p;
529 : 183 : break;
530 : :
531 : 4 : case '#':
532 [ + + ]: 4 : if (p == command_line)
533 : : { /* '#' was the first char */
534 : 2 : current_quote = *p;
535 : 2 : break;
536 : : }
537 [ + + ]: 2 : switch(*(p-1))
538 : : {
539 : 1 : case ' ':
540 : : case '\n':
541 : : case '\0':
542 : 1 : current_quote = *p;
543 : 1 : break;
544 : 1 : default:
545 : 1 : ensure_token (¤t_token);
546 [ + - ]: 1 : g_string_append_c (current_token, *p);
547 : 1 : break;
548 : : }
549 : 2 : break;
550 : :
551 : 11226 : default:
552 : : /* Combines rules 4) and 6) - if we have a token, append to it,
553 : : * otherwise create a new token.
554 : : */
555 : 11226 : ensure_token (¤t_token);
556 [ + - ]: 11226 : g_string_append_c (current_token, *p);
557 : 11226 : break;
558 : : }
559 : : }
560 : :
561 : : /* We need to count consecutive backslashes mod 2,
562 : : * to detect escaped doublequotes.
563 : : */
564 [ + + ]: 19988 : if (*p != '\\')
565 : 19977 : quoted = FALSE;
566 : : else
567 : 11 : quoted = !quoted;
568 : :
569 : 19988 : ++p;
570 : : }
571 : :
572 : 422 : delimit_token (¤t_token, &retval);
573 : :
574 [ + + ]: 422 : if (current_quote)
575 : : {
576 [ + + ]: 3 : if (current_quote == '\\')
577 : 1 : g_set_error (error,
578 : : G_SHELL_ERROR,
579 : : G_SHELL_ERROR_BAD_QUOTING,
580 : : _("Text ended just after a “\\” character."
581 : : " (The text was “%s”)"),
582 : : command_line);
583 : : else
584 : 2 : g_set_error (error,
585 : : G_SHELL_ERROR,
586 : : G_SHELL_ERROR_BAD_QUOTING,
587 : : _("Text ended before matching quote was found for %c."
588 : : " (The text was “%s”)"),
589 : : current_quote, command_line);
590 : :
591 : 3 : goto error;
592 : : }
593 : :
594 [ + + ]: 419 : if (retval == NULL)
595 : : {
596 : 4 : g_set_error_literal (error,
597 : : G_SHELL_ERROR,
598 : : G_SHELL_ERROR_EMPTY_STRING,
599 : : _("Text was empty (or contained only whitespace)"));
600 : :
601 : 4 : goto error;
602 : : }
603 : :
604 : : /* we appended backward */
605 : 415 : retval = g_slist_reverse (retval);
606 : :
607 : 415 : return retval;
608 : :
609 : 7 : error:
610 : 7 : g_assert (error == NULL || *error != NULL);
611 : :
612 : 7 : g_slist_free_full (retval, g_free);
613 : :
614 : 7 : return NULL;
615 : : }
616 : :
617 : : /**
618 : : * g_shell_parse_argv:
619 : : * @command_line: (type filename): command line to parse
620 : : * @argcp: (out) (optional): return location for number of args
621 : : * @argvp: (out) (optional) (array length=argcp zero-terminated=1) (element-type filename):
622 : : * return location for array of args
623 : : * @error: (optional): return location for error
624 : : *
625 : : * Parses a command line into an argument vector, in much the same way
626 : : * the shell would, but without many of the expansions the shell would
627 : : * perform (variable expansion, globs, operators, filename expansion,
628 : : * etc. are not supported).
629 : : *
630 : : * The results are defined to be the same as those you would get from
631 : : * a UNIX98 `/bin/sh`, as long as the input contains none of the
632 : : * unsupported shell expansions. If the input does contain such expansions,
633 : : * they are passed through literally.
634 : : *
635 : : * Possible errors are those from the %G_SHELL_ERROR domain.
636 : : *
637 : : * In particular, if @command_line is an empty string (or a string containing
638 : : * only whitespace), %G_SHELL_ERROR_EMPTY_STRING will be returned. It’s
639 : : * guaranteed that @argvp will be a non-empty array if this function returns
640 : : * successfully.
641 : : *
642 : : * Free the returned vector with g_strfreev().
643 : : *
644 : : * Returns: %TRUE on success, %FALSE if error set
645 : : **/
646 : : gboolean
647 : 422 : g_shell_parse_argv (const gchar *command_line,
648 : : gint *argcp,
649 : : gchar ***argvp,
650 : : GError **error)
651 : : {
652 : : /* Code based on poptParseArgvString() from libpopt */
653 : 422 : gint argc = 0;
654 : 422 : gchar **argv = NULL;
655 : 422 : GSList *tokens = NULL;
656 : : gint i;
657 : : GSList *tmp_list;
658 : :
659 : 422 : g_return_val_if_fail (command_line != NULL, FALSE);
660 : :
661 : 422 : tokens = tokenize_command_line (command_line, error);
662 [ + + ]: 422 : if (tokens == NULL)
663 : 7 : return FALSE;
664 : :
665 : : /* Because we can't have introduced any new blank space into the
666 : : * tokens (we didn't do any new expansions), we don't need to
667 : : * perform field splitting. If we were going to honor IFS or do any
668 : : * expansions, we would have to do field splitting on each word
669 : : * here. Also, if we were going to do any expansion we would need to
670 : : * remove any zero-length words that didn't contain quotes
671 : : * originally; but since there's no expansion we know all words have
672 : : * nonzero length, unless they contain quotes.
673 : : *
674 : : * So, we simply remove quotes, and don't do any field splitting or
675 : : * empty word removal, since we know there was no way to introduce
676 : : * such things.
677 : : */
678 : :
679 : 415 : argc = g_slist_length (tokens);
680 : 415 : argv = g_new0 (gchar*, argc + 1);
681 : 415 : i = 0;
682 : 415 : tmp_list = tokens;
683 [ + + ]: 1567 : while (tmp_list)
684 : : {
685 : 1152 : argv[i] = g_shell_unquote (tmp_list->data, error);
686 : :
687 : : /* Since we already checked that quotes matched up in the
688 : : * tokenizer, this shouldn't be possible to reach I guess.
689 : : */
690 [ - + ]: 1152 : if (argv[i] == NULL)
691 : 0 : goto failed;
692 : :
693 [ + - ]: 1152 : tmp_list = g_slist_next (tmp_list);
694 : 1152 : ++i;
695 : : }
696 : :
697 : 415 : g_slist_free_full (tokens, g_free);
698 : :
699 : 415 : g_assert (argc > 0);
700 : 415 : g_assert (argv != NULL && argv[0] != NULL);
701 : :
702 [ + + ]: 415 : if (argcp)
703 : 313 : *argcp = argc;
704 : :
705 [ + - ]: 415 : if (argvp)
706 : 415 : *argvp = argv;
707 : : else
708 : 0 : g_strfreev (argv);
709 : :
710 : 415 : return TRUE;
711 : :
712 : 0 : failed:
713 : :
714 : 0 : g_assert (error == NULL || *error != NULL);
715 : 0 : g_strfreev (argv);
716 : 0 : g_slist_free_full (tokens, g_free);
717 : :
718 : 0 : return FALSE;
719 : : }
|