Merge remote branch 'gvdb/master'
[platform/upstream/glib.git] / glib / gshell.c
index 4bae260..d3b76f4 100644 (file)
  * Boston, MA 02111-1307, USA.
  */
 
-#include "glib.h"
+#include "config.h"
+
 #include <string.h>
 
+#include "glib.h"
+
 #ifdef _
 #warning "FIXME remove gettext hack"
 #endif
 
-#define _(x) x
+#include "glibintl.h"
+#include "galias.h"
+
+/**
+ * SECTION: shell
+ * @title: Shell-related Utilities
+ * @short_description: shell-like commandline handling
+ **/
+
+/**
+ * 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.
+ **/
 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;
+  return g_quark_from_static_string ("g-shell-error-quark");
 }
 
 /* Single quotes preserve the literal string exactly. escape
@@ -46,7 +69,7 @@ g_shell_error_quark (void)
  * Otherwise double quotes preserve things literally.
  */
 
-gboolean 
+static gboolean 
 unquote_string_inplace (gchar* str, gchar** end, GError** err)
 {
   gchar* dest;
@@ -63,8 +86,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 +176,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;
@@ -198,7 +221,7 @@ g_shell_quote (const gchar *unquoted_string)
     {
       /* Replace literal ' with a close ', a \', and a open ' */
       if (*p == '\'')
-        g_string_append (dest, "'\''");
+        g_string_append (dest, "'\\''");
       else
         g_string_append_c (dest, *p);
 
@@ -223,7 +246,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
@@ -231,6 +254,13 @@ g_shell_quote (const gchar *unquoted_string)
  * newlines. The return value must be freed with g_free(). Possible
  * errors are in the #G_SHELL_ERROR domain.
  * 
+ * Shell quoting rules are a bit strange. Single quotes preserve the
+ * literal string exactly. escape sequences are not allowed; not even
+ * \' - if you want a ' in the quoted text, you have to do something
+ * like 'foo'\''bar'.  Double quotes allow $, `, ", \, and newline to
+ * be escaped with backslash. Otherwise double quotes preserve things
+ * literally.
+ *
  * Return value: an unquoted string
  **/
 gchar*
@@ -248,7 +278,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'
@@ -296,6 +326,7 @@ g_shell_unquote (const gchar *quoted_string,
         }
     }
 
+  g_free (unquoted);
   return g_string_free (retval, FALSE);
   
  error:
@@ -379,7 +410,7 @@ static inline void
 ensure_token (GString **token)
 {
   if (*token == NULL)
-    *token = g_string_new ("");
+    *token = g_string_new (NULL);
 }
 
 static void
@@ -402,10 +433,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 == '\\')
@@ -441,7 +474,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';
@@ -505,6 +538,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;
     }
 
@@ -516,7 +557,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
@@ -532,10 +573,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;
     }
@@ -572,9 +613,9 @@ tokenize_command_line (const gchar *command_line,
  * contains none of the unsupported shell expansions. If the input
  * does contain such expansions, they are passed through
  * literally. Possible errors are those from the #G_SHELL_ERROR
- * domain.
+ * domain. Free the returned vector with g_strfreev().
  * 
- * Return value: TRUE on success, FALSE if error set
+ * Return value: %TRUE on success, %FALSE if error set
  **/
 gboolean
 g_shell_parse_argv (const gchar *command_line,
@@ -649,3 +690,6 @@ g_shell_parse_argv (const gchar *command_line,
   
   return FALSE;
 }
+
+#define __G_SHELL_C__
+#include "galiasdef.c"