[glib/gvariant] Change string handling for GVariant varargs
- From: Ryan Lortie <ryanl src gnome org>
- To: svn-commits-list gnome org
- Subject: [glib/gvariant] Change string handling for GVariant varargs
- Date: Sun, 14 Jun 2009 13:14:38 -0400 (EDT)
commit febc0a74d6770a35e533e9fd415b327b24707d5e
Author: Ryan Lortie <desrt desrt ca>
Date: Sun Jun 14 13:12:43 2009 -0400
Change string handling for GVariant varargs
format string "s" now means "allocated string" (ie: must be freed)
"&s" is now how you get the string out of the serialised data
also add "&as" to mean a gchar ** (free with g_strfreev) and
"&a&s" to mean a const gchar ** (free with g_free).
glib/gvariant-valist.c | 145 +++++++++++++++++++++++++++-----
glib/tests/.gitignore | 1 +
glib/tests/Makefile.am | 3 +
glib/tests/gvariant-varargs-strings.c | 62 ++++++++++++++
glib/tests/gvariant-varargs.c | 8 +-
5 files changed, 192 insertions(+), 27 deletions(-)
---
diff --git a/glib/gvariant-valist.c b/glib/gvariant-valist.c
index 16a629f..e31a11c 100644
--- a/glib/gvariant-valist.c
+++ b/glib/gvariant-valist.c
@@ -41,6 +41,11 @@
* character. No wildcard type is a fixed-width type. Like '@', '&'
* characters may not be nested.
*
+ * Additionally, any array of fixed-width types may be prefixed with a
+ * '&'.
+ *
+ * Additionally, '&s', '&as' and '&a&s' may appear.
+ *
* No '@' or '&' character, however, may appear as part of an array
* type.
*
@@ -107,6 +112,26 @@ g_variant_format_string_scan (const gchar **format_string)
const gchar *start;
start = *format_string;
+
+ if (start[0] == 's') /* '&s' */
+ {
+ *format_string = start + 1;
+ return TRUE;
+ }
+ else if (start[0] == 'a')
+ {
+ if (start[1] == 's') /* '&as' */
+ {
+ *format_string = start + 2;
+ return TRUE;
+ }
+ else if (start[1] == '&' && start[2] == 's') /* '&a&s' */
+ {
+ *format_string = start + 3;
+ return TRUE;
+ }
+ }
+
if (!g_variant_type_string_scan (format_string, NULL))
return FALSE;
@@ -229,24 +254,53 @@ g_variant_valist_new (const gchar **format_string,
case '&':
{
- GVariantType *type;
+ const gchar *string = (*format_string + 1);
gconstpointer ptr;
- GVariant *value;
- gsize n_items;
-
- type = g_variant_format_string_get_type (format_string);
- g_assert (g_variant_type_is_concrete (type));
+ gint n_items = 0;
ptr = va_arg (*app, gconstpointer);
- if (g_variant_type_is_in_class (type, G_VARIANT_TYPE_CLASS_ARRAY))
- n_items = va_arg (*app, gsize);
- else
- n_items = 0;
- value = g_variant_load_fixed (type, ptr, n_items);
- g_variant_type_free (type);
+ switch (*string++)
+ {
+ case 's': /* '&s' */
+ /* for building, just the same as normal 's' */
+ *format_string += 2;
+ return g_variant_new_string (ptr);
+
+ case 'a':
+ n_items = va_arg (*app, gint);
+
+ if (string[1] == 's') /* '&as' */
+ {
+ *format_string += 3;
+ return g_variant_new_strv (va_arg (*app, const gchar **), n_items);
+ }
+
+ if (string[1] == '&' && string[2] == 's') /* '&a&s' */
+ {
+ *format_string += 4;
+ return g_variant_new_strv (va_arg (*app, const gchar **), n_items);
+ }
+
+ if (n_items < 0)
+ g_error ("size of -1 can only be specified for string arrays");
+
+ /* fall through */
+
+ default:
+ {
+ GVariantType *type;
+ GVariant *value;
+
+ type = g_variant_format_string_get_type (format_string);
+ g_assert (g_variant_type_is_concrete (type));
- return value;
+ value = g_variant_load_fixed (type, ptr, n_items);
+ g_variant_type_free (type);
+
+ return value;
+ }
+ }
}
case 'a':
@@ -540,12 +594,15 @@ g_variant_valist_get (GVariant *value,
case 'o':
case 'g':
{
- const gchar **ptr = va_arg (*app, const gchar **);
+ gchar **ptr = va_arg (*app, gchar **);
if (ptr)
{
+ if (free && *ptr)
+ g_free (*ptr);
+
if (value)
- *ptr = g_variant_get_string (value, NULL);
+ *ptr = g_variant_dup_string (value, NULL);
else
*ptr = NULL;
}
@@ -619,14 +676,30 @@ g_variant_valist_get (GVariant *value,
case '&':
{
- gconstpointer *ptr;
- gsize *n_items;
+ /* this can be 'const gchar *' but also 'gchar **' so
+ * we lose a little type safety here...
+ * but srsly, it's varargs!
+ */
+ gpointer *ptr;
+
+ ptr = va_arg (*app, gpointer *);
- ptr = va_arg (*app, gconstpointer *);
+ if ((*format_string)[1] == 's') /* '&s' */
+ {
+ /* cannot just get_data() like below.
+ * might not be nul-terminated */
+ if (ptr)
+ {
+ if (value)
+ *ptr = (gpointer) g_variant_get_string (value, NULL);
+ else
+ *ptr = NULL;
+ }
+ }
- if ((*format_string)[1] == 'a') /* '&a..' */
+ else if ((*format_string)[1] == 'a') /* '&a..' */
{
- n_items = va_arg (*app, gsize *);
+ gint *n_items = va_arg (*app, gint *);
if (n_items)
{
@@ -639,10 +712,36 @@ g_variant_valist_get (GVariant *value,
if (ptr)
{
- if (value)
- *ptr = g_variant_get_data (value);
+ if ((*format_string)[1] == 'a' &&
+ (*format_string)[2] == 's')
+ {
+ if (free && *ptr)
+ g_strfreev (*ptr);
+
+ if (value)
+ *ptr = g_variant_dup_strv (value, NULL);
+ else
+ *ptr = NULL;
+ }
+ else if ((*format_string)[1] == 'a' &&
+ (*format_string)[2] == '&' &&
+ (*format_string)[3] == 's')
+ {
+ if (free && *ptr)
+ g_free (*ptr);
+
+ if (value)
+ *ptr = g_variant_get_strv (value, NULL);
+ else
+ *ptr = NULL;
+ }
else
- *ptr = NULL;
+ {
+ if (value)
+ *ptr = (gpointer) g_variant_get_data (value);
+ else
+ *ptr = NULL;
+ }
}
g_variant_format_string_scan (format_string);
diff --git a/glib/tests/.gitignore b/glib/tests/.gitignore
index ba59ff2..93dc95b 100644
--- a/glib/tests/.gitignore
+++ b/glib/tests/.gitignore
@@ -17,3 +17,4 @@ gvariant-markup
gvariant-random
gvariant-serialiser
gvariant-varargs
+gvariant-varargs-strings
diff --git a/glib/tests/Makefile.am b/glib/tests/Makefile.am
index b6475c3..90b6ca1 100644
--- a/glib/tests/Makefile.am
+++ b/glib/tests/Makefile.am
@@ -65,6 +65,9 @@ gvariant_serialiser_LDADD = $(progs_ldadd)
TEST_PROGS += gvariant-varargs
gvariant_varargs_LDADD = $(progs_ldadd)
+TEST_PROGS += gvariant-varargs-strings
+gvariant_varargs_strings_LDADD = $(progs_ldadd)
+
TEST_PROGS += hostutils
hostutils_LDADD = $(progs_ldadd)
diff --git a/glib/tests/gvariant-varargs-strings.c b/glib/tests/gvariant-varargs-strings.c
new file mode 100644
index 0000000..46b9573
--- /dev/null
+++ b/glib/tests/gvariant-varargs-strings.c
@@ -0,0 +1,62 @@
+#include <glib.h>
+
+static void
+check (gchar **a, const gchar *expected)
+{
+ gchar *actual;
+
+ actual = g_strjoinv (",", a);
+ g_assert_cmpstr (actual, ==, expected);
+ g_free (actual);
+}
+
+static void
+test (void)
+{
+ const gchar *array[] = {"one", "two", "three", "four", NULL};
+ GVariant *one, *two;
+ gchar **a;
+ gint num;
+
+ one = g_variant_new_strv (array, -1);
+ two = g_variant_new_strv (array, 3);
+
+ g_variant_get (one, "&as", &a, &num);
+ g_assert_cmpint (num, ==, 4);
+ check (a, "one,two,three,four");
+ g_strfreev (a);
+
+ g_variant_get (two, "&as", &a, &num);
+ g_assert_cmpint (num, ==, 3);
+ check (a, "one,two,three");
+ g_strfreev (a);
+
+ g_variant_get (one, "&a&s", &a, &num);
+ g_assert_cmpint (num, ==, 4);
+ check (a, "one,two,three,four");
+ g_free (a);
+
+ g_variant_get (two, "&a&s", &a, &num);
+ g_assert_cmpint (num, ==, 3);
+ check (a, "one,two,three");
+ g_free (a);
+
+ g_variant_unref (one);
+
+ g_variant_get (two, "&as", &a, &num);
+ g_variant_unref (two);
+
+ g_assert_cmpint (num, ==, 3);
+ check (a, "one,two,three");
+ g_strfreev (a);
+}
+
+int
+main (int argc, char **argv)
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/gvariant/varargs-strings", test);
+
+ return g_test_run ();
+}
diff --git a/glib/tests/gvariant-varargs.c b/glib/tests/gvariant-varargs.c
index 318d91b..f0d0621 100644
--- a/glib/tests/gvariant-varargs.c
+++ b/glib/tests/gvariant-varargs.c
@@ -47,7 +47,7 @@ make_value (void)
g_variant_new_object_path ("/usr/local"),
g_variant_new ("()"),
g_variant_new ("(bbb)", TRUE, FALSE, TRUE),
- fixed_struct, fixed_struct, (gsize) 3,
+ fixed_struct, fixed_struct, 3,
"i'm gone",
g_variant_new_uint16 (44444),
g_variant_new_uint16 (22222),
@@ -70,7 +70,7 @@ make_value (void)
g_variant_new_object_path ("/usr/local"),
g_variant_new ("()"),
g_variant_new ("(bbb)", TRUE, FALSE, TRUE),
- fixed_struct, fixed_struct, (gsize) 3,
+ fixed_struct, fixed_struct, 3,
NULL, NULL, NULL, NULL, NULL, NULL,
ebuilder2, NULL, NULL);
@@ -88,7 +88,7 @@ make_value (void)
g_variant_new_object_path ("/usr/local"),
g_variant_new ("()"),
g_variant_new ("(bbb)", TRUE, FALSE, TRUE),
- fixed_struct, fixed_struct, (gsize) 3,
+ fixed_struct, fixed_struct, 3,
NULL, NULL, NULL, NULL, NULL, NULL,
ebuilder3, NULL, NULL);
@@ -100,7 +100,7 @@ test_iterate (void)
{
GVariant *maybe_one, *maybe_two, *maybe_three, *maybe_four, *maybe_five;
GVariant *one, *two, *three, *four, *five, *six, *seven = (gpointer) 0xcccccccc, *eight;
- struct structure *fixed_array; gsize fixed_array_size;
+ struct structure *fixed_array; gint fixed_array_size;
struct structure *maybe_fixed_struct, *fixed_struct;
const gchar *string, *maybe_string;
GVariantIter maybe_array, array;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]