X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgshell.c;h=a1c7e791f2a2e4e160c5251bb60b3ea849a2e056;hb=1cbdbef77209fe82239bd10f062425491cf256ae;hp=87ebaff6fb4a246249b6236d33f385cb32575052;hpb=4a298b0fc6ee5d77656e8c016cff04f280b95a3c;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gshell.c b/glib/gshell.c index 87ebaff..a1c7e79 100644 --- a/glib/gshell.c +++ b/glib/gshell.c @@ -20,23 +20,50 @@ * Boston, MA 02111-1307, USA. */ -#include "glib.h" +#include "config.h" + #include -#ifdef _ -#warning "FIXME remove gettext hack" -#endif +#include "gshell.h" +#include "gslist.h" +#include "gstrfuncs.h" +#include "gstring.h" +#include "gtestutils.h" #include "glibintl.h" +#include "gthread.h" -GQuark -g_shell_error_quark (void) -{ - static GQuark quark = 0; - if (quark == 0) - quark = g_quark_from_static_string ("g-shell-error-quark"); - return quark; -} +/** + * SECTION:shell + * @title: Shell-related Utilities + * @short_description: shell-like commandline handling + * + * GLib provides the functions g_shell_quote() and g_shell_unquote() + * to handle shell-like quoting in strings. The function g_shell_parse_argv() + * parses a string similar to the way a POSIX shell (/bin/sh) would. + * + * Note that string handling in shells has many obscure and historical + * corner-cases which these functions do not necessarily reproduce. They + * are good enough in practice, though. + */ + +/** + * G_SHELL_ERROR: + * + * Error domain for shell functions. Errors in this domain will be from + * the #GShellError enumeration. See #GError for information on error + * domains. + **/ + +/** + * GShellError: + * @G_SHELL_ERROR_BAD_QUOTING: Mismatched or otherwise mangled quoting. + * @G_SHELL_ERROR_EMPTY_STRING: String to be parsed was empty. + * @G_SHELL_ERROR_FAILED: Some other error. + * + * Error codes returned by shell functions. + **/ +G_DEFINE_QUARK (g-shell-error-quark, g_shell_error) /* Single quotes preserve the literal string exactly. escape * sequences are not allowed; not even \' - if you want a ' @@ -63,8 +90,8 @@ unquote_string_inplace (gchar* str, gchar** end, GError** err) if (!(*s == '"' || *s == '\'')) { - if (err) - *err = g_error_new(G_SHELL_ERROR, + g_set_error_literal (err, + G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING, _("Quoted text doesn't begin with a quotation mark")); *end = str; @@ -153,8 +180,8 @@ unquote_string_inplace (gchar* str, gchar** end, GError** err) *dest = '\0'; - if (err) - *err = g_error_new(G_SHELL_ERROR, + g_set_error_literal (err, + G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING, _("Unmatched quotation mark in command line or other shell-quoted text")); *end = s; @@ -172,7 +199,7 @@ unquote_string_inplace (gchar* str, gchar** end, GError** err) * quoting style used is undefined (single or double quotes may be * used). * - * Return value: quoted string + * Returns: quoted string **/ gchar* g_shell_quote (const gchar *unquoted_string) @@ -223,7 +250,7 @@ g_shell_quote (const gchar *unquoted_string) * would produce (the variables, backticks, etc. will be passed * through literally instead of being expanded). This function is * guaranteed to succeed if applied to the result of - * g_shell_quote(). If it fails, it returns NULL and sets the + * g_shell_quote(). If it fails, it returns %NULL and sets the * error. The @quoted_string need not actually contain quoted or * escaped text; g_shell_unquote() simply goes through the string and * unquotes/unescapes anything that the shell would. Both single and @@ -238,7 +265,7 @@ g_shell_quote (const gchar *unquoted_string) * be escaped with backslash. Otherwise double quotes preserve things * literally. * - * Return value: an unquoted string + * Returns: an unquoted string **/ gchar* g_shell_unquote (const gchar *quoted_string, @@ -255,7 +282,7 @@ g_shell_unquote (const gchar *quoted_string, start = unquoted; end = unquoted; - retval = g_string_new (""); + retval = g_string_new (NULL); /* The loop allows cases such as * "foo"blah blah'bar'woo foo"baz"la la la\'\''foo' @@ -303,6 +330,7 @@ g_shell_unquote (const gchar *quoted_string, } } + g_free (unquoted); return g_string_free (retval, FALSE); error: @@ -386,7 +414,7 @@ static inline void ensure_token (GString **token) { if (*token == NULL) - *token = g_string_new (""); + *token = g_string_new (NULL); } static void @@ -409,10 +437,12 @@ tokenize_command_line (const gchar *command_line, const gchar *p; GString *current_token = NULL; GSList *retval = NULL; - + gboolean quoted; + current_quote = '\0'; + quoted = FALSE; p = command_line; - + while (*p) { if (current_quote == '\\') @@ -448,7 +478,7 @@ tokenize_command_line (const gchar *command_line, { if (*p == current_quote && /* check that it isn't an escaped double quote */ - !(current_quote == '"' && p != command_line && *(p - 1) == '\\')) + !(current_quote == '"' && quoted)) { /* close the quote */ current_quote = '\0'; @@ -496,12 +526,30 @@ tokenize_command_line (const gchar *command_line, g_string_append_c (current_token, *p); /* FALL THRU */ - - case '#': case '\\': current_quote = *p; break; + case '#': + if (p == command_line) + { /* '#' was the first char */ + current_quote = *p; + break; + } + switch(*(p-1)) + { + case ' ': + case '\n': + case '\0': + current_quote = *p; + break; + default: + ensure_token (¤t_token); + g_string_append_c (current_token, *p); + break; + } + break; + default: /* Combines rules 4) and 6) - if we have a token, append to it, * otherwise create a new token. @@ -512,6 +560,14 @@ tokenize_command_line (const gchar *command_line, } } + /* We need to count consecutive backslashes mod 2, + * to detect escaped doublequotes. + */ + if (*p != '\\') + quoted = FALSE; + else + quoted = !quoted; + ++p; } @@ -523,7 +579,7 @@ tokenize_command_line (const gchar *command_line, g_set_error (error, G_SHELL_ERROR, G_SHELL_ERROR_BAD_QUOTING, - _("Text ended just after a '\' character." + _("Text ended just after a '\\' character." " (The text was '%s')"), command_line); else @@ -539,10 +595,10 @@ tokenize_command_line (const gchar *command_line, if (retval == NULL) { - g_set_error (error, - G_SHELL_ERROR, - G_SHELL_ERROR_EMPTY_STRING, - _("Text was empty (or contained only whitespace)")); + g_set_error_literal (error, + G_SHELL_ERROR, + G_SHELL_ERROR_EMPTY_STRING, + _("Text was empty (or contained only whitespace)")); goto error; } @@ -554,12 +610,8 @@ tokenize_command_line (const gchar *command_line, error: g_assert (error == NULL || *error != NULL); - - if (retval) - { - g_slist_foreach (retval, (GFunc)g_free, NULL); - g_slist_free (retval); - } + + g_slist_free_full (retval, g_free); return NULL; } @@ -567,9 +619,10 @@ tokenize_command_line (const gchar *command_line, /** * g_shell_parse_argv: * @command_line: command line to parse - * @argcp: return location for number of args - * @argvp: return location for array of args - * @error: return location for error + * @argcp: (out) (optional): return location for number of args, or %NULL + * @argvp: (out) (optional) (array length=argcp zero-terminated=1): return + * location for array of args, or %NULL + * @error: (optional): return location for error, or %NULL * * Parses a command line into an argument vector, in much the same way * the shell would, but without many of the expansions the shell would @@ -581,7 +634,7 @@ tokenize_command_line (const gchar *command_line, * literally. Possible errors are those from the #G_SHELL_ERROR * domain. Free the returned vector with g_strfreev(). * - * Return value: TRUE on success, FALSE if error set + * Returns: %TRUE on success, %FALSE if error set **/ gboolean g_shell_parse_argv (const gchar *command_line, @@ -634,8 +687,7 @@ g_shell_parse_argv (const gchar *command_line, ++i; } - g_slist_foreach (tokens, (GFunc)g_free, NULL); - g_slist_free (tokens); + g_slist_free_full (tokens, g_free); if (argcp) *argcp = argc; @@ -651,8 +703,7 @@ g_shell_parse_argv (const gchar *command_line, g_assert (error == NULL || *error != NULL); g_strfreev (argv); - g_slist_foreach (tokens, (GFunc) g_free, NULL); - g_slist_free (tokens); + g_slist_free_full (tokens, g_free); return FALSE; }