[glib/gsettings] improved API for format/type string scanning
- From: Ryan Lortie <ryanl src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [glib/gsettings] improved API for format/type string scanning
- Date: Thu, 27 Aug 2009 17:10:42 +0000 (UTC)
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]