[glib/gsettings] improved API for format/type string scanning



commit f7721d228db0a5ba4faa8afac3065756323c65e8
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Aug 27 13:06:13 2009 -0400

    improved API for format/type string scanning

 glib/gvariant-parser.c               |    4 +-
 glib/gvariant-util.c                 |    2 +-
 glib/gvariant-valist.c               |  210 ++++++++++++++++++----------------
 glib/gvariant.h                      |    4 +-
 glib/gvarianttype.c                  |   77 ++++++-------
 glib/gvarianttype.h                  |    5 +-
 glib/tests/gvariant-printer-parser.c |    2 +-
 7 files changed, 158 insertions(+), 146 deletions(-)
---
diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c
index a577e73..ebd9cf5 100644
--- a/glib/gvariant-parser.c
+++ b/glib/gvariant-parser.c
@@ -2126,11 +2126,11 @@ g_variant_parse (const gchar         *text,
         text++;
 
       if (*text)
-        g_set_error_literal (error, 0, 0, "trailing text after value");
+        g_set_error (error, 0, 0, "%s", "trailing text after value");
     }
   else
     {
-      g_set_error_literal (error, 0, 0, parse_error.error);
+      g_set_error (error, 0, 0, "%s", parse_error.error);
       g_free (parse_error.error);
     }
 
diff --git a/glib/gvariant-util.c b/glib/gvariant-util.c
index 44f511c..1cde86c 100644
--- a/glib/gvariant-util.c
+++ b/glib/gvariant-util.c
@@ -459,7 +459,7 @@ g_variant_is_signature (const gchar *string)
 
   /* make sure each type string is well-formed */
   while (*string)
-    if (!g_variant_type_string_scan (&string, NULL))
+    if (!g_variant_type_string_scan (string, NULL, &string))
       return FALSE;
 
   return TRUE;
diff --git a/glib/gvariant-valist.c b/glib/gvariant-valist.c
index cc79d46..641cebe 100644
--- a/glib/gvariant-valist.c
+++ b/glib/gvariant-valist.c
@@ -18,17 +18,25 @@
 
 /**
  * g_variant_format_string_scan:
- * @format_string: a pass-by-reference pointer to the start of a
- *                 possible format string
- * @returns: %TRUE if a format string was scanned
- *
- * Checks the string pointed to by @format_string for starting with a
- * properly formed #GVariant varargs format string.  If a format
- * string is fount, @format_string is updated to point to the first
- * character following the format string and %TRUE is returned.
- *
- * If no valid format string is found, %FALSE is returned and the
- * state of the @format_string pointer is undefined.
+ * @string: a string that may be prefixed with a format string
+ * @limit: a pointer to the end of @string
+ * @endptr: location to store the end pointer, or %NULL
+ * @returns: %TRUE if there was a valid format string
+ *
+ * Checks the string pointed to by @string for starting with a properly
+ * formed #GVariant varargs format string.  If no valid format string is
+ * found then %FALSE is returned.
+ *
+ * If @string does start with a valid format string and @endptr is
+ * non-%NULL then it is updated to point to the first character after
+ * the format string.  If @endptr is %NULL and there is any character
+ * following the format string then this call returns %FALSE.  Another
+ * way of saying this is that if @endptr is %NULL then @string is
+ * checked to contain exactly one valid format string and nothing else.
+ *
+ * If @limit is non-%NULL then @limit (and any charater after it) will
+ * not be accessed and the effect is otherwise equivalent to if the
+ * character at @limit were nul.
  *
  * All valid #GVariantType strings are also valid format strings.  See
  * g_variant_type_string_is_valid().
@@ -56,129 +64,131 @@
  * and g_variant_get().
  **/
 gboolean
-g_variant_format_string_scan (const gchar **format_string)
+g_variant_format_string_scan (const gchar  *string,
+                              const gchar  *limit,
+                              const gchar **endptr)
 {
-  switch (*(*format_string)++)
-  {
-    case '\0':
-      return FALSE;
+  const gchar *start;
+
+  if (string == limit || *string == '\0')
+    return FALSE;
 
+  switch (*string++)
+    {
     case '(':
-      while (**format_string != ')')
-        if (!g_variant_format_string_scan (format_string))
+      while (string == limit || *string != ')')
+        if (!g_variant_format_string_scan (string, limit, &string))
           return FALSE;
 
-      (*format_string)++; /* ')' */
-
-      return TRUE;
+      string++;
+      break;
 
     case '{':
-      if (**format_string == '\0')
-        return FALSE;
-
-      /* key may only be a basic type.  three posibilities for that:
-       */
-      if (strchr ("bynqiuxtdsog?", **format_string))
-        *format_string += 1;
-
-      else if ((*format_string)[0] == '@' &&
-               strchr ("bynqiuxtdsog?", (*format_string)[1]))
-        *format_string += 2;
+      if (string != limit && (*string == '@' || *string == '&'))
+        string++;
 
-      else if ((*format_string)[0] == '&' &&
-               strchr ("bynqiuxtdsog", (*format_string)[1]))
-        *format_string += 2;
-
-      else
-        return FALSE;
-
-      if (!g_variant_format_string_scan (format_string))    /* value */
+      if (string == limit || *string == '\0' ||                    /* { */
+          !strchr ("bynqiuxtdsog?", *string++) ||                  /* key */
+          !g_variant_format_string_scan (string, limit, &string) ||/* value */
+          string == limit || *string++ != '}')                     /* } */
         return FALSE;
 
-      if (*(*format_string)++ != '}')
-        return FALSE;
-
-      return TRUE;
+      break;
 
     case 'm':
-      return g_variant_format_string_scan (format_string);
+      return g_variant_format_string_scan (string, limit, endptr); /* tcall */
 
     case 'a':
     case '@':
-      return g_variant_type_string_scan (format_string, NULL);
+      return g_variant_type_string_scan (string, limit, endptr);   /* tcall */
 
     case '&':
-      {
-        const gchar *start;
+      start = string;
 
-        start = *format_string;
-
-        if (start[0] == 's') /* '&s' */
-          {
-            *format_string = start + 1;
-            return TRUE;
-          }
+      if (!g_variant_type_string_scan (string, limit, &string))
+        return FALSE;
 
-        if (!g_variant_type_string_scan (format_string, NULL))
-          return FALSE;
+      if (start + 1 == string && *start == 's')
+        break;
 
-        if (*start == 'a')
-          start++;
+      if (*start == 'a')
+        start++;
 
-        while (start != *format_string)
-          if (!strchr ("bynqiuxtd(){}", *start++))
-            return FALSE;
+      while (start != string)
+        if (!strchr ("bynqiuxtd(){}", *start++))
+          return FALSE;
 
-        return TRUE;
-      }
+      break;
 
     case '^':
-      {
-        if (*((*format_string)++) != 'a')
-          return FALSE;
+      if (string == limit || *string++ != 'a')
+        return FALSE;
 
-        if (**format_string == '&')
-          (*format_string)++;
+      if (string != limit && *string == '&')
+        string++;
 
-        return *((*format_string)++) == 's';
-      }
+      if (string == limit || *string++ != 's')
+        return FALSE;
+
+      break;
 
     case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
     case 'x': case 't': case 'd': case 's': case 'o': case 'g':
     case 'v': case '*': case '?': case 'r':
-      return TRUE;
+      break;
 
     default:
       return FALSE;
   }
-}
 
-#if 0
-static gboolean
-g_variant_format_string_is_valid (const gchar *format_string)
-{
-  return g_variant_format_string_scan (&format_string) &&
-         *format_string == '\0';
+  if (endptr != NULL)
+    *endptr = string;
+  else
+    {
+      if (string != limit && *string != '\0')
+        return FALSE;
+    }
+
+  return TRUE;
 }
-#endif
 
+/**
+ * g_variant_format_string_scan_type:
+ * @string: a string that may be prefixed with a format string
+ * @limit: a pointer to the end of @string
+ * @endptr: location to store the end pointer, or %NULL
+ * @returns: a #GVariantType if there was a valid format string
+ *
+ * If @string starts with a valid format string then this function will
+ * return the type that the format string corresponds to.  Otherwise
+ * this function returns %NULL.
+ *
+ * The returned type must be freed by the caller.
+ *
+ * This function is otherwise exactly like
+ * g_variant_format_string_scan().
+ **/
 static GVariantType *
-g_variant_format_string_get_type (const gchar **format_string)
+g_variant_format_string_scan_type (const gchar  *string,
+                                   const gchar  *limit,
+                                   const gchar **endptr)
 {
-  const gchar *src;
+  const gchar *my_end;
   gchar *dest;
   gchar *new;
 
-  src = *format_string;
-  if G_UNLIKELY (!g_variant_format_string_scan (format_string))
-    g_error ("format string is invalid");
+  if (endptr == NULL)
+    endptr = &my_end;
+
+  if (!g_variant_format_string_scan (string, limit, endptr))
+    return NULL;
 
-  dest = new = g_malloc (*format_string - src + 1);
-  while (src != *format_string)
+  dest = new = g_malloc (*endptr - string + 1);
+  while (string != *endptr)
     {
-      if (*src != '@' && *src != '&' && *src != '^')
-        *dest++ = *src;
-      src++;
+      if (*string != '@' && *string != '&' && *string != '^')
+        *dest++ = *string;
+      string++;
     }
   *dest = '\0';
 
@@ -247,7 +257,7 @@ g_variant_valist_new (const gchar **format_string,
     case '*':
     case '?':
     case 'r':
-      g_variant_format_string_scan (format_string);
+      g_variant_format_string_scan (*format_string, NULL, format_string);
       return va_arg (*app, GVariant *);
 
     case '^':
@@ -299,7 +309,8 @@ g_variant_valist_new (const gchar **format_string,
               GVariantType *type;
               GVariant *value;
 
-              type = g_variant_format_string_get_type (format_string);
+              type = g_variant_format_string_scan_type (*format_string,
+                                                        NULL, format_string);
               g_assert (g_variant_type_is_concrete (type));
 
               value = g_variant_load_fixed (type, ptr, n_items);
@@ -311,7 +322,7 @@ g_variant_valist_new (const gchar **format_string,
       }
 
     case 'a':
-      g_variant_format_string_scan (format_string);
+      g_variant_format_string_scan (*format_string, NULL, format_string);
       return g_variant_builder_end (va_arg (*app, GVariantBuilder *));
 
     case 'm':
@@ -322,7 +333,8 @@ g_variant_valist_new (const gchar **format_string,
         GVariant *value;
 
         string = (*format_string) + 1;
-        type = g_variant_format_string_get_type (format_string);
+        type = g_variant_format_string_scan_type (*format_string,
+                                                  NULL, format_string);
         builder = g_variant_builder_new (G_VARIANT_TYPE_CLASS_MAYBE, type);
         g_variant_type_free (type);
 
@@ -379,7 +391,8 @@ g_variant_valist_new (const gchar **format_string,
                   GVariantType *type;
                   gsize n_items;
 
-                  type = g_variant_format_string_get_type (&string);
+                  type = g_variant_format_string_scan_type (string,
+                                                            NULL, NULL);
                   g_assert (g_variant_type_is_concrete (type));
 
                   if (g_variant_type_is_in_class (type,
@@ -655,7 +668,7 @@ g_variant_valist_get (GVariant     *value,
               *ptr = NULL;
           }
 
-        g_variant_format_string_scan (format_string);
+        g_variant_format_string_scan (*format_string, NULL, format_string);
         return;
       }
 
@@ -677,7 +690,7 @@ g_variant_valist_get (GVariant     *value,
               }
           }
 
-        g_variant_format_string_scan (format_string);
+        g_variant_format_string_scan (*format_string, NULL, format_string);
         return;
       }
 
@@ -771,7 +784,7 @@ g_variant_valist_get (GVariant     *value,
               *ptr = NULL;
           }
 
-        g_variant_format_string_scan (format_string);
+        g_variant_format_string_scan (*format_string, NULL, format_string);
         return;
       }
 
@@ -796,7 +809,8 @@ g_variant_valist_get (GVariant     *value,
                 *ptr = just != NULL;
               }
             else
-              g_variant_format_string_scan (format_string);
+              g_variant_format_string_scan (*format_string,
+                                            NULL, format_string);
           }
         else
           g_variant_valist_get (just, free, format_string, app);
@@ -1326,7 +1340,7 @@ g_variant_get_va (GVariant     *value,
   g_assert (value != NULL);
 
   fmt = *format_string;
-  type = g_variant_format_string_get_type (&fmt);
+  type = g_variant_format_string_scan_type (fmt, NULL, &fmt);
   g_assert (g_variant_matches (value, type));
   g_variant_type_free (type);
 
diff --git a/glib/gvariant.h b/glib/gvariant.h
index d408642..71d5b9e 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -48,7 +48,9 @@ void                            g_variant_get                           (GVarian
                                                                          const gchar          *format_string,
                                                                          ...);
 
-gboolean                        g_variant_format_string_scan            (const gchar         **format_string);
+gboolean                        g_variant_format_string_scan            (const gchar          *string,
+                                                                         const gchar          *end,
+                                                                         const gchar         **endptr);
 GVariant                       *g_variant_new_va                        (gpointer              must_be_null,
                                                                          const gchar         **format_string,
                                                                          va_list              *app);
diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
index 8569aea..c2a793f 100644
--- a/glib/gvarianttype.c
+++ b/glib/gvarianttype.c
@@ -98,81 +98,79 @@ g_variant_type_check (const GVariantType *type)
 {
   const gchar *type_string = (const gchar *) type;
 
-  return g_variant_type_string_scan (&type_string, NULL);
+  return g_variant_type_string_scan (type_string, NULL, &type_string);
 }
 #endif
 
 /**
  * g_variant_type_string_scan:
- * @type_string: a pointer to any string
+ * @string: a pointer to any string
  * @limit: the end of @string, or %NULL
+ * @endptr: location to store the end pointer, or %NULL
  * @returns: %TRUE if a valid type string was found
  *
  * Scan for a single complete and valid #GVariantType type string in
- * @type_string.  The memory pointed to by @limit (or bytes beyond it)
+ * @string.  The memory pointed to by @limit (or bytes beyond it)
  * is never accessed.
  *
- * If a valid type string is found, @type_string is updated to point
+ * If a valid type string is found, @endptr is updated to point
  * to the first character past the end of the string that was found
  * and %TRUE is returned.
  *
- * If there is no valid type string starting at @type_string, or if
- * the type string does not end before @limit then %FALSE is returned
- * and the state of the @type_string pointer is undefined.
+ * If there is no valid type string starting at @string, or if
+ * the type string does not end before @limit then %FALSE is returned.
  *
  * For the simple case of checking if a string is a valid type string,
  * see g_variant_type_string_is_valid().
  **/
 gboolean
-g_variant_type_string_scan (const gchar **type_string,
-                            const gchar  *limit)
+g_variant_type_string_scan (const gchar  *string,
+                            const gchar  *limit,
+                            const gchar **endptr)
 {
-  if (*type_string == limit)
+  if (string == limit || *string == '\0')
     return FALSE;
 
-  switch (*(*type_string)++)
-  {
-    case '\0':
-      return FALSE;
-
+  switch (*string++)
+    {
     case '(':
-      while (*type_string != limit && **type_string != ')')
-        if (!g_variant_type_string_scan (type_string, limit))
+      while (string == limit || *string != ')')
+        if (!g_variant_type_string_scan (string, limit, &string))
           return FALSE;
 
-      if (*type_string == limit)
-        return FALSE;
-
-      (*type_string)++; /* ')' */
-
-      return TRUE;
+      string++;
+      break;
 
     case '{':
-      if (*type_string == limit || **type_string == '\0')
-        return FALSE;
-
-      if (!strchr ("bynqiuxtdsog?", *(*type_string)++))        /* key */
+      if (string == limit || *string == '\0' ||                    /* { */
+          !strchr ("bynqiuxtdsog?", *string++) ||                  /* key */
+          !g_variant_type_string_scan (string, limit, &string) ||  /* value */
+          string == limit || *string++ != '}')                     /* } */
         return FALSE;
 
-      if (!g_variant_type_string_scan (type_string, limit))    /* value */
-        return FALSE;
-
-      if (*type_string == limit || *(*type_string)++ != '}')
-        return FALSE;
-
-      return TRUE;
+      break;
 
     case 'm': case 'a':
-      return g_variant_type_string_scan (type_string, limit);  /* tailcall */
+      return g_variant_type_string_scan (string, limit, endptr);   /* tcall */
 
     case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
     case 'x': case 't': case 'd': case 's': case 'o': case 'g':
     case 'v': case 'r': case '*': case '?':
-      return TRUE;
+      break;
 
     default:
       return FALSE;
-  }
+    }
+
+  if (endptr != NULL)
+    *endptr = string;
+  else
+    {
+      if (string != limit && *string != '\0')
+        return FALSE;
+    }
+
+  return TRUE;
 }
 
 /**
@@ -187,10 +185,7 @@ g_variant_type_string_scan (const gchar **type_string,
 gboolean
 g_variant_type_string_is_valid (const gchar *type_string)
 {
-  if (!g_variant_type_string_scan (&type_string, NULL))
-    return FALSE;
-
-  if (*type_string != '\0')
+  if (!g_variant_type_string_scan (type_string, NULL, NULL))
     return FALSE;
 
   return TRUE;
diff --git a/glib/gvarianttype.h b/glib/gvarianttype.h
index 8fe2ce0..092685e 100644
--- a/glib/gvarianttype.h
+++ b/glib/gvarianttype.h
@@ -253,8 +253,9 @@ G_BEGIN_DECLS
 
 /* type string checking */
 gboolean                        g_variant_type_string_is_valid          (const gchar         *type_string);
-gboolean                        g_variant_type_string_scan              (const gchar        **type_string,
-                                                                         const gchar         *limit);
+gboolean                        g_variant_type_string_scan              (const gchar         *type_string,
+                                                                         const gchar         *limit,
+                                                                         const gchar        **endptr);
 
 /* create/destroy */
 void                            g_variant_type_free                     (GVariantType        *type);
diff --git a/glib/tests/gvariant-printer-parser.c b/glib/tests/gvariant-printer-parser.c
index 0099cde..4d6cfc0 100644
--- a/glib/tests/gvariant-printer-parser.c
+++ b/glib/tests/gvariant-printer-parser.c
@@ -31,7 +31,7 @@ const char *verbatim_tests[] = {
 
   "[[3, 4], [5, 6]]",
 
-  "<(@y0x04, @x-16, 6.0, 3.141, \"Hello\", <<<<<5>>>>>)>",
+  "<(@y 0x04, @x -16, 6.0, 3.141, \"Hello\", <<<<<5>>>>>)>",
 
   "([true, false, false, true, false], [(), ()])",
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]