From 19878998bc386db78614f1c92ff8524a81479c7b Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Wed, 20 Jul 2011 13:11:19 +0200 Subject: [PATCH] GVariant: better support for object path arrays Add G_VARIANT_TYPE_OBJECT_PATH_ARRAY along with accessor functions g_variant_new_objv, g_variant_get_objv and g_variant_dup_objv. Also add support for '^ao' and '^a&o' format strings for g_variant_new() and g_variant_get(). https://bugzilla.gnome.org/show_bug.cgi?id=654955 --- docs/reference/glib/glib-sections.txt | 4 + docs/reference/glib/gvariant-varargs.xml | 39 ++++++- glib/glib.symbols | 3 + glib/gvariant.c | 168 +++++++++++++++++++++++++++++-- glib/gvariant.h | 6 ++ glib/gvarianttype.h | 7 ++ glib/tests/gvariant.c | 53 ++++++++++ 7 files changed, 270 insertions(+), 10 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 3a0160d..0c581d2 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -2940,6 +2940,7 @@ G_VARIANT_TYPE_UNIT G_VARIANT_TYPE_DICT_ENTRY G_VARIANT_TYPE_DICTIONARY G_VARIANT_TYPE_STRING_ARRAY +G_VARIANT_TYPE_OBJECT_PATH_ARRAY G_VARIANT_TYPE_BYTESTRING G_VARIANT_TYPE_BYTESTRING_ARRAY G_VARIANT_TYPE_VARDICT @@ -3030,6 +3031,7 @@ g_variant_new_signature g_variant_is_signature g_variant_new_variant g_variant_new_strv +g_variant_new_objv g_variant_new_bytestring g_variant_new_bytestring_array @@ -3049,6 +3051,8 @@ g_variant_dup_string g_variant_get_variant g_variant_get_strv g_variant_dup_strv +g_variant_get_objv +g_variant_dup_objv g_variant_get_bytestring g_variant_dup_bytestring g_variant_get_bytestring_array diff --git a/docs/reference/glib/gvariant-varargs.xml b/docs/reference/glib/gvariant-varargs.xml index 2aac40b..1b15156 100644 --- a/docs/reference/glib/gvariant-varargs.xml +++ b/docs/reference/glib/gvariant-varargs.xml @@ -46,8 +46,8 @@ '&s' '&o', '&g', '^as', - '^a&s', '^ay', '^&ay', '^aay' - or '^a&ay'. + '^a&s', '^ao', '^a&o','^ay', + '^&ay', '^aay' or '^a&ay'. @@ -1022,6 +1022,41 @@ value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo")); + ^ao + + + + + + equivalent to g_variant_new_objv() + + + + + equivalent to g_variant_dup_objv() + + + + + + + + + ^a&o + + + + + + equivalent to g_variant_get_objv() + + + + + + + + ^ay diff --git a/glib/glib.symbols b/glib/glib.symbols index df978ec..dfb6748 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -1447,6 +1447,7 @@ g_variant_new_signature g_variant_is_signature g_variant_new_variant g_variant_new_strv +g_variant_new_objv g_variant_new_bytestring g_variant_new_bytestring_array g_variant_get_boolean @@ -1464,6 +1465,8 @@ g_variant_dup_string g_variant_get_variant g_variant_get_strv g_variant_dup_strv +g_variant_get_objv +g_variant_dup_objv g_variant_get_bytestring g_variant_dup_bytestring g_variant_get_bytestring_array diff --git a/glib/gvariant.c b/glib/gvariant.c index 26fa949..d7e9daf 100644 --- a/glib/gvariant.c +++ b/glib/gvariant.c @@ -1453,6 +1453,141 @@ g_variant_dup_strv (GVariant *value, } /** + * g_variant_new_objv: + * @strv: (array length=length) (element-type utf8): an array of strings + * @length: the length of @strv, or -1 + * @returns: (transfer none): a new floating #GVariant instance + * + * Constructs an array of object paths #GVariant from the given array of + * strings. + * + * Each string must be a valid #GVariant object path; see + * g_variant_is_object_path(). + * + * If @length is -1 then @strv is %NULL-terminated. + * + * Since: 2.30 + **/ +GVariant * +g_variant_new_objv (const gchar * const *strv, + gssize length) +{ + GVariant **strings; + gsize i; + + g_return_val_if_fail (length == 0 || strv != NULL, NULL); + + if (length < 0) + length = g_strv_length ((gchar **) strv); + + strings = g_new (GVariant *, length); + for (i = 0; i < length; i++) + strings[i] = g_variant_ref_sink (g_variant_new_object_path (strv[i])); + + return g_variant_new_from_children (G_VARIANT_TYPE_OBJECT_PATH_ARRAY, + strings, length, TRUE); +} + +/** + * g_variant_get_objv: + * @value: an array of object paths #GVariant + * @length: (out) (allow-none): the length of the result, or %NULL + * @returns: (array length=length zero-terminated=1) (transfer container): an array of constant + * strings + * + * Gets the contents of an array of object paths #GVariant. This call + * makes a shallow copy; the return result should be released with + * g_free(), but the individual strings must not be modified. + * + * If @length is non-%NULL then the number of elements in the result + * is stored there. In any case, the resulting array will be + * %NULL-terminated. + * + * For an empty array, @length will be set to 0 and a pointer to a + * %NULL pointer will be returned. + * + * Since: 2.30 + **/ +const gchar ** +g_variant_get_objv (GVariant *value, + gsize *length) +{ + const gchar **strv; + gsize n; + gsize i; + + TYPE_CHECK (value, G_VARIANT_TYPE_OBJECT_PATH_ARRAY, NULL); + + g_variant_get_data (value); + n = g_variant_n_children (value); + strv = g_new (const gchar *, n + 1); + + for (i = 0; i < n; i++) + { + GVariant *string; + + string = g_variant_get_child_value (value, i); + strv[i] = g_variant_get_string (string, NULL); + g_variant_unref (string); + } + strv[i] = NULL; + + if (length) + *length = n; + + return strv; +} + +/** + * g_variant_dup_objv: + * @value: an array of object paths #GVariant + * @length: (out) (allow-none): the length of the result, or %NULL + * @returns: (array length=length zero-terminated=1) (transfer full): an array of strings + * + * Gets the contents of an array of object paths #GVariant. This call + * makes a deep copy; the return result should be released with + * g_strfreev(). + * + * If @length is non-%NULL then the number of elements in the result + * is stored there. In any case, the resulting array will be + * %NULL-terminated. + * + * For an empty array, @length will be set to 0 and a pointer to a + * %NULL pointer will be returned. + * + * Since: 2.30 + **/ +gchar ** +g_variant_dup_objv (GVariant *value, + gsize *length) +{ + gchar **strv; + gsize n; + gsize i; + + TYPE_CHECK (value, G_VARIANT_TYPE_OBJECT_PATH_ARRAY, NULL); + + n = g_variant_n_children (value); + strv = g_new (gchar *, n + 1); + + for (i = 0; i < n; i++) + { + GVariant *string; + + string = g_variant_get_child_value (value, i); + strv[i] = g_variant_dup_string (string, NULL); + g_variant_unref (string); + } + strv[i] = NULL; + + if (length) + *length = n; + + return strv; +} + + +/** * g_variant_new_bytestring: * @string: (array zero-terminated=1): a normal nul-terminated string in no particular encoding * @returns: (transfer none): a floating reference to a new bytestring #GVariant instance @@ -3373,8 +3508,8 @@ g_variant_format_string_scan (const gchar *string, break; /* '^a&ay' */ } - else if (c == 's') - break; /* '^a&s' */ + else if (c == 's' || c == 'o') + break; /* '^a&s', '^a&o' */ } else if (c == 'a') @@ -3383,8 +3518,8 @@ g_variant_format_string_scan (const gchar *string, break; /* '^aay' */ } - else if (c == 's') - break; /* '^as' */ + else if (c == 's' || c == 'o') + break; /* '^as', '^ao' */ else if (c == 'y') break; /* '^ay' */ @@ -3586,9 +3721,9 @@ g_variant_valist_free_nnp (const gchar *str, break; case '^': - if (str[2] != '&') /* '^as' */ + if (str[2] != '&') /* '^as', '^ao' */ g_strfreev (ptr); - else /* '^a&s' */ + else /* '^a&s', '^a&o' */ g_free (ptr); break; @@ -3709,10 +3844,16 @@ g_variant_valist_new_nnp (const gchar **str, { gboolean constant; guint arrays; + gchar type; + + type = g_variant_scan_convenience (str, &constant, &arrays); - if (g_variant_scan_convenience (str, &constant, &arrays) == 's') + if (type == 's') return g_variant_new_strv (ptr, -1); + if (type == 'o') + return g_variant_new_objv (ptr, -1); + if (arrays > 1) return g_variant_new_bytestring_array (ptr, -1); @@ -3780,8 +3921,11 @@ g_variant_valist_get_nnp (const gchar **str, { gboolean constant; guint arrays; + gchar type; + + type = g_variant_scan_convenience (str, &constant, &arrays); - if (g_variant_scan_convenience (str, &constant, &arrays) == 's') + if (type == 's') { if (constant) return g_variant_get_strv (value, NULL); @@ -3789,6 +3933,14 @@ g_variant_valist_get_nnp (const gchar **str, return g_variant_dup_strv (value, NULL); } + else if (type == 'o') + { + if (constant) + return g_variant_get_objv (value, NULL); + else + return g_variant_dup_objv (value, NULL); + } + else if (arrays > 1) { if (constant) diff --git a/glib/gvariant.h b/glib/gvariant.h index f4f49bc..7f3af98 100644 --- a/glib/gvariant.h +++ b/glib/gvariant.h @@ -86,6 +86,8 @@ gboolean g_variant_is_signature (const g GVariant * g_variant_new_variant (GVariant *value); GVariant * g_variant_new_strv (const gchar * const *strv, gssize length); +GVariant * g_variant_new_objv (const gchar * const *strv, + gssize length); GVariant * g_variant_new_bytestring (const gchar *string); GVariant * g_variant_new_bytestring_array (const gchar * const *strv, gssize length); @@ -109,6 +111,10 @@ const gchar ** g_variant_get_strv (GVarian gsize *length); gchar ** g_variant_dup_strv (GVariant *value, gsize *length); +const gchar ** g_variant_get_objv (GVariant *value, + gsize *length); +gchar ** g_variant_dup_objv (GVariant *value, + gsize *length); const gchar * g_variant_get_bytestring (GVariant *value); gchar * g_variant_dup_bytestring (GVariant *value, gsize *length); diff --git a/glib/gvarianttype.h b/glib/gvarianttype.h index 5c686dd..be9555e 100644 --- a/glib/gvarianttype.h +++ b/glib/gvarianttype.h @@ -239,6 +239,13 @@ typedef struct _GVariantType GVariantType; #define G_VARIANT_TYPE_STRING_ARRAY ((const GVariantType *) "as") /** + * G_VARIANT_TYPE_OBJECT_PATH_ARRAY: + * + * The type of an array of object paths. + **/ +#define G_VARIANT_TYPE_OBJECT_PATH_ARRAY ((const GVariantType *) "ao") + +/** * G_VARIANT_TYPE_BYTESTRING: * * The type of an array of bytes. This type is commonly used to pass diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c index 3d30a89..e943bb2 100644 --- a/glib/tests/gvariant.c +++ b/glib/tests/gvariant.c @@ -3023,6 +3023,59 @@ test_varargs (void) } { + const gchar *strvector[] = {"/hello", "/world", NULL}; + const gchar *test_strs[] = {"/foo", "/bar", "/baz" }; + GVariantBuilder builder; + GVariantIter *array; + GVariantIter tuple; + const gchar **strv; + gchar **my_strv; + GVariant *value; + gchar *str; + gint i; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_OBJECT_PATH_ARRAY); + g_variant_builder_add (&builder, "o", "/foo"); + g_variant_builder_add (&builder, "o", "/bar"); + g_variant_builder_add (&builder, "o", "/baz"); + value = g_variant_new("(ao^ao^a&o)", &builder, strvector, strvector); + g_variant_iter_init (&tuple, value); + g_variant_iter_next (&tuple, "ao", &array); + + i = 0; + while (g_variant_iter_loop (array, "o", &str)) + g_assert_cmpstr (str, ==, test_strs[i++]); + g_assert (i == 3); + + g_variant_iter_free (array); + + /* start over */ + g_variant_iter_init (&tuple, value); + g_variant_iter_next (&tuple, "ao", &array); + + i = 0; + while (g_variant_iter_loop (array, "&o", &str)) + g_assert_cmpstr (str, ==, test_strs[i++]); + g_assert (i == 3); + + g_variant_iter_free (array); + + g_variant_iter_next (&tuple, "^a&o", &strv); + g_variant_iter_next (&tuple, "^ao", &my_strv); + + g_assert_cmpstr (strv[0], ==, "/hello"); + g_assert_cmpstr (strv[1], ==, "/world"); + g_assert (strv[2] == NULL); + g_assert_cmpstr (my_strv[0], ==, "/hello"); + g_assert_cmpstr (my_strv[1], ==, "/world"); + g_assert (my_strv[2] == NULL); + + g_variant_unref (value); + g_strfreev (my_strv); + g_free (strv); + } + + { const gchar *strvector[] = { "i", "ii", "iii", "iv", "v", "vi", NULL }; GVariantBuilder builder; GVariantIter iter; -- 2.7.4