merge GVariant parser

This commit is contained in:
Ryan Lortie 2010-03-21 12:31:46 -05:00
parent 2a209cb251
commit bf4dbdbf0e
7 changed files with 2473 additions and 17 deletions

View File

@ -2894,7 +2894,14 @@ g_variant_builder_end
g_variant_builder_open
g_variant_builder_close
<SUBSECTION>
G_VARIANT_PARSE_ERROR
g_variant_parse
g_variant_new_parsed_va
g_variant_new_parsed
<SUBSECTION Private>
g_variant_parser_get_error
g_variant_type_checked_
</SECTION>

View File

@ -179,6 +179,7 @@ libglib_2_0_la_SOURCES = \
gvariant-core.h \
gvariant-core.c \
gvariant-internal.h \
gvariant-parser.c \
gvariant-serialiser.h \
gvariant-serialiser.c \
gvarianttypeinfo.h \

View File

@ -1794,6 +1794,13 @@ g_variant_new_from_data
g_variant_get_normal_form
g_variant_byteswap
#endif
#if IN_FILE(__G_VARIANT_PARSER_C__)
g_variant_new_parsed
g_variant_new_parsed_va
g_variant_parse
g_variant_parser_get_error_quark
#endif
#endif
#if IN_HEADER(__G_VARIANT_TYPE_INFO_H__)

2185
glib/gvariant-parser.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1454,31 +1454,31 @@ g_variant_print_string (GVariant *value,
/* Nested maybes:
*
* Consider the case of the type "mmi". In this case we could
* write "Just Just 4", but "4" alone is totally unambiguous,
* so we try to drop "Just" where possible.
* write "just just 4", but "4" alone is totally unambiguous,
* so we try to drop "just" where possible.
*
* We have to be careful not to always drop "Just", though,
* since "Nothing" needs to be distinguishable from "Just
* Nothing". The case where we need to ensure we keep the
* "Just" is actually exactly the case where we have a nested
* We have to be careful not to always drop "just", though,
* since "nothing" needs to be distinguishable from "just
* nothing". The case where we need to ensure we keep the
* "just" is actually exactly the case where we have a nested
* Nothing.
*
* Instead of searching for that nested Nothing, we just print
* the contained value into a separate string and see if we
* end up with "Nothing" at the end of it. If so, we need to
* add "Just" at our level.
* end up with "nothing" at the end of it. If so, we need to
* add "just" at our level.
*/
element = g_variant_get_child_value (value, 0);
printed_child = g_variant_print (element, FALSE);
g_variant_unref (element);
if (g_str_has_suffix (printed_child, "Nothing"))
g_string_append (string, "Just ");
if (g_str_has_suffix (printed_child, "nothing"))
g_string_append (string, "just ");
g_string_append (string, printed_child);
g_free (printed_child);
}
else
g_string_append (string, "Nothing");
g_string_append (string, "nothing");
break;
@ -1633,7 +1633,11 @@ g_variant_print_string (GVariant *value,
const gchar *str = g_variant_get_string (value, NULL);
gchar *escaped = g_strescape (str, NULL);
g_string_append_printf (string, "\'%s\'", escaped);
/* use double quotes only if a ' is in the string */
if (strchr (str, '\''))
g_string_append_printf (string, "\"%s\"", escaped);
else
g_string_append_printf (string, "'%s'", escaped);
g_free (escaped);
}

View File

@ -176,6 +176,9 @@ struct _GVariantBuilder {
gsize x[16];
};
#define G_VARIANT_PARSE_ERROR (g_variant_parser_get_error_quark ())
GQuark g_variant_parser_get_error_quark (void);
GVariantBuilder * g_variant_builder_new (const GVariantType *type);
void g_variant_builder_unref (GVariantBuilder *builder);
GVariantBuilder * g_variant_builder_ref (GVariantBuilder *builder);
@ -206,6 +209,16 @@ void g_variant_get_va (GVarian
va_list *app);
GVariant * g_variant_parse (const GVariantType *type,
const gchar *text,
const gchar *limit,
const gchar **endptr,
GError **error);
GVariant * g_variant_new_parsed (const gchar *format,
...);
GVariant * g_variant_new_parsed_va (const gchar *format,
va_list *app);
G_END_DECLS
#endif /* __G_VARIANT_H__ */

View File

@ -2742,7 +2742,7 @@ do_failed_test (const gchar *pattern)
static void
test_invalid_varargs (void)
{
if (do_failed_test ("*not a valid GVariant format string*"))
if (do_failed_test ("*GVariant format string*"))
{
g_variant_new ("z");
abort ();
@ -2790,7 +2790,7 @@ test_varargs (void)
g_variant_new_double (37.5))));
check_and_free (g_variant_new ("(ma{sv}m(a{sv})ma{sv}ii)",
NULL, FALSE, NULL, &array, 7777, 8888),
"(Nothing, Nothing, {'size': <(800, 600)>, "
"(nothing, nothing, {'size': <(800, 600)>, "
"'title': <'Test case'>, "
"'temperature': <37.5>}, "
"7777, 8888)");
@ -2802,7 +2802,7 @@ test_varargs (void)
FALSE, TRUE, 321,
TRUE, FALSE, 321,
TRUE, TRUE, 123),
"(123, Nothing, 123, Nothing, Just Nothing, 123)");
"(123, nothing, 123, nothing, just nothing, 123)");
check_and_free (g_variant_new ("(ybnixd)",
'a', 1, 22, 33, (guint64) 44, 5.5),
@ -3047,7 +3047,7 @@ test_varargs (void)
gdouble dval;
gint32 hval;
/* test all 'Nothing' */
/* test all 'nothing' */
value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
FALSE, 'a',
FALSE, TRUE,
@ -3144,7 +3144,7 @@ test_varargs (void)
g_variant_unref (value);
/* test all 'Just' */
/* test all 'just' */
value = g_variant_new ("(mymbmnmqmimumxmtmhmdmv)",
TRUE, 'a',
TRUE, TRUE,
@ -3455,6 +3455,242 @@ test_gv_byteswap ()
g_free (string);
}
static void
test_parser (void)
{
TreeInstance *tree;
GVariant *parsed;
GVariant *value;
gchar *pt, *p;
gchar *res;
tree = tree_instance_new (NULL, 3);
value = tree_instance_get_gvariant (tree);
tree_instance_free (tree);
pt = g_variant_print (value, TRUE);
p = g_variant_print (value, FALSE);
parsed = g_variant_parse (NULL, pt, NULL, NULL, NULL);
res = g_variant_print (parsed, FALSE);
g_assert_cmpstr (p, ==, res);
g_variant_unref (parsed);
g_free (res);
parsed = g_variant_parse (g_variant_get_type (value), p,
NULL, NULL, NULL);
res = g_variant_print (parsed, TRUE);
g_assert_cmpstr (pt, ==, res);
g_variant_unref (parsed);
g_free (res);
g_variant_unref (value);
g_free (pt);
g_free (p);
}
static void
test_parses (void)
{
gint i;
for (i = 0; i < 100; i++)
{
test_parser ();
}
/* mini test */
{
gchar str[256];
GVariant *val;
gchar *p, *p2;
for (i = 0; i < 256; i++)
str[i] = i + 1;
val = g_variant_new_string (str);
p = g_variant_print (val, FALSE);
g_variant_unref (val);
val = g_variant_parse (NULL, p, NULL, NULL, NULL);
p2 = g_variant_print (val, FALSE);
g_assert_cmpstr (str, ==, g_variant_get_string (val, NULL));
g_assert_cmpstr (p, ==, p2);
g_variant_unref (val);
g_free (p2);
g_free (p);
}
/* another mini test */
{
const gchar *end;
GVariant *value;
value = g_variant_parse (G_VARIANT_TYPE_INT32, "1 2 3", NULL, &end, NULL);
g_assert_cmpint (g_variant_get_int32 (value), ==, 1);
/* make sure endptr returning works */
g_assert_cmpstr (end, ==, " 2 3");
g_variant_unref (value);
}
g_variant_type_info_assert_no_infos ();
}
static void
test_parse_failures (void)
{
const gchar *test[] = {
"[1, 2,", "6:", "expected value",
"", "0:", "expected value",
"(1, 2,", "6:", "expected value",
"<1", "2:", "expected `>'",
"[]", "0-2:", "unable to infer",
"(,", "1:", "expected value",
"[4,'']", "1-2,3-5:", "common type",
"[4, '', 5]", "1-2,4-6:", "common type",
"['', 4, 5]", "1-3,5-6:", "common type",
"[4, 5, '']", "1-2,7-9:", "common type",
"[[4], [], ['']]", "1-4,10-14:", "common type",
"[[], [4], ['']]", "5-8,10-14:", "common type",
"just", "4:", "expected value",
"nothing", "0-7:", "unable to infer",
"just [4, '']", "6-7,9-11:", "common type",
"[[4,'']]", "2-3,4-6:", "common type",
"([4,''],)", "2-3,4-6:", "common type",
"(4)", "2:", "`,'",
"{}", "0-2:", "unable to infer",
"{[1,2],[3,4]}", "0-13:", "basic types",
"{[1,2]:[3,4]}", "0-13:", "basic types",
"justt", "0-5:", "unknown keyword",
"nothng", "0-6:", "unknown keyword",
"uint33", "0-6:", "unknown keyword",
"@mi just ''", "9-11:", "can not parse as",
"@ai ['']", "5-7:", "can not parse as",
"@(i) ('',)", "6-8:", "can not parse as",
"[[], 5]", "1-3,5-6:", "common type",
"[[5], 5]", "1-4,6-7:", "common type",
"5 5", "2:", "expected end of input",
"[5, [5, '']]", "5-6,8-10:", "common type",
"@i just 5", "3-9:", "can not parse as",
"@i nothing", "3-10:", "can not parse as",
"@i []", "3-5:", "can not parse as",
"@i ()", "3-5:", "can not parse as",
"@ai (4,)", "4-8:", "can not parse as",
"@(i) []", "5-7:", "can not parse as",
"(5 5)", "3:", "expected `,'",
"[5 5]", "3:", "expected `,' or `]'",
"(5, 5 5)", "6:", "expected `,' or `)'",
"[5, 5 5]", "6:", "expected `,' or `]'",
"<@i []>", "4-6:", "can not parse as",
"<[5 5]>", "4:", "expected `,' or `]'",
"{[4,''],5}", "2-3,4-6:", "common type",
"{5,[4,'']}", "4-5,6-8:", "common type",
"@i {1,2}", "3-8:", "can not parse as",
"{@i '', 5}", "4-6:", "can not parse as",
"{5, @i ''}", "7-9:", "can not parse as",
"@ai {}", "4-6:", "can not parse as",
"{@i '': 5}", "4-6:", "can not parse as",
"{5: @i ''}", "7-9:", "can not parse as",
"{<4,5}", "3:", "expected `>'",
"{4,<5}", "5:", "expected `>'",
"{4,5,6}", "4:", "expected `}'",
"{5 5}", "3:", "expected `:' or `,'",
"{4: 5: 6}", "5:", "expected `,' or `}'",
"{4:5,<6:7}", "7:", "expected `>'",
"{4:5,6:<7}", "9:", "expected `>'",
"{4:5,6 7}", "7:", "expected `:'",
"@o 'foo'", "3-8:", "object path",
"@g 'zzz'", "3-8:", "signature",
"@i true", "3-7:", "can not parse as",
"@z 4", "0-2:", "invalid type",
"@a* []", "0-3:", "definite",
"@ai [3 3]", "7:", "expected `,' or `]'",
"18446744073709551616", "0-20:", "too big for any type",
"-18446744073709551616", "0-21:", "too big for any type",
"byte 256", "5-8:", "out of range for type",
"byte -1", "5-7:", "out of range for type",
"int16 32768", "6-11:", "out of range for type",
"int16 -32769", "6-12:", "out of range for type",
"uint16 -1", "7-9:", "out of range for type",
"uint16 65536", "7-12:", "out of range for type",
"2147483648", "0-10:", "out of range for type",
"-2147483649", "0-11:", "out of range for type",
"uint32 -1", "7-9:", "out of range for type",
"uint32 4294967296", "7-17:", "out of range for type",
"@x 9223372036854775808", "3-22:", "out of range for type",
"@x -9223372036854775809", "3-23:", "out of range for type",
"@t -1", "3-5:", "out of range for type",
"@t 18446744073709551616", "3-23:", "too big for any type",
"handle 2147483648", "7-17:", "out of range for type",
"handle -2147483649", "7-18:", "out of range for type",
"1.798e308", "0-9:", "too big for any type",
"37.5a488", "4-5:", "invalid character",
"0x7ffgf", "5-6:", "invalid character",
"07758", "4-5:", "invalid character",
"123a5", "3-4:", "invalid character",
"@ai 123", "4-7:", "can not parse as",
"'\"\\'", "0-4:", "unterminated string",
"'\"\\'\\", "0-5:", "unterminated string",
"boolean 4", "8-9:", "can not parse as",
"int32 true", "6-10:", "can not parse as",
"[double 5, int32 5]", "1-9,11-18:", "common type",
"string 4", "7-8:", "can not parse as"
};
gint i;
for (i = 0; i < G_N_ELEMENTS (test); i += 3)
{
GError *error = NULL;
GVariant *value;
value = g_variant_parse (NULL, test[i], NULL, NULL, &error);
g_assert (value == NULL);
if (!strstr (error->message, test[i+2]))
g_error ("test %d: Can't find `%s' in `%s'", i / 3,
test[i+2], error->message);
if (!g_str_has_prefix (error->message, test[i+1]))
g_error ("test %d: Expected location `%s' in `%s'", i / 3,
test[i+1], error->message);
g_error_free (error);
}
}
static void
test_parse_positional (void)
{
GVariant *value;
check_and_free (g_variant_new_parsed ("[('one', 1), (%s, 2),"
" ('three', %i)]", "two", 3),
"[('one', 1), ('two', 2), ('three', 3)]");
value = g_variant_new_parsed ("[('one', 1), (%s, 2),"
" ('three', %u)]", "two", 3);
g_assert (g_variant_is_of_type (value, G_VARIANT_TYPE ("a(su)")));
check_and_free (value, "[('one', 1), ('two', 2), ('three', 3)]");
if (do_failed_test ("*GVariant format string*"))
{
g_variant_new_parsed ("%z");
abort ();
}
if (do_failed_test ("*can not parse as*"))
{
g_variant_new_parsed ("uint32 %i", 2);
abort ();
}
if (do_failed_test ("*expected GVariant of type `i'*"))
{
g_variant_new_parsed ("%@i", g_variant_new_uint32 (2));
abort ();
}
}
int
main (int argc, char **argv)
{
@ -3489,6 +3725,9 @@ main (int argc, char **argv)
g_test_add_func ("/gvariant/builder-memory", test_builder_memory);
g_test_add_func ("/gvariant/hashing", test_hashing);
g_test_add_func ("/gvariant/byteswap", test_gv_byteswap);
g_test_add_func ("/gvariant/parser", test_parses);
g_test_add_func ("/gvariant/parse-failures", test_parse_failures);
g_test_add_func ("/gvariant/parse-positional", test_parse_positional);
return g_test_run ();
}