2 * Copyright © 2009, 2010 Codethink Limited
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Ryan Lortie <desrt@desrt.ca>
31 #include "gstrfuncs.h"
32 #include "gtestutils.h"
34 #include "gvarianttype.h"
38 * designed by ryan lortie and william hua
39 * designed in itb-229 and at ghazi's, 2009.
43 * G_VARIANT_PARSE_ERROR:
45 * Error domain for GVariant text format parsing. Specific error codes
46 * are not currently defined for this domain. See #GError for
47 * information on error domains.
51 * @G_VARIANT_PARSE_ERROR_FAILED: generic error (unused)
52 * @G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED: a non-basic #GVariantType was given where a basic type was expected
53 * @G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE: cannot infer the #GVariantType
54 * @G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED: an indefinite #GVariantType was given where a definite type was expected
55 * @G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END: extra data after parsing finished
56 * @G_VARIANT_PARSE_ERROR_INVALID_CHARACTER: invalid character in number or unicode escape
57 * @G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING: not a valid #GVariant format string
58 * @G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH: not a valid object path
59 * @G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE: not a valid type signature
60 * @G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING: not a valid #GVariant type string
61 * @G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE: could not find a common type for array entries
62 * @G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE: the numerical value is out of range of the given type
63 * @G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG: the numerical value is out of range for any type
64 * @G_VARIANT_PARSE_ERROR_TYPE_ERROR: cannot parse as variant of the specified type
65 * @G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN: an unexpected token was encountered
66 * @G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD: an unknown keyword was encountered
67 * @G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT: unterminated string constant
68 * @G_VARIANT_PARSE_ERROR_VALUE_EXPECTED: no value given
70 * Error codes returned by parsing text-format GVariants.
73 g_variant_parser_get_error_quark (void)
75 static GQuark the_quark;
78 the_quark = g_quark_from_static_string ("g-variant-parse-error-quark");
89 parser_set_error_va (GError **error,
96 GString *msg = g_string_new (NULL);
98 if (location->start == location->end)
99 g_string_append_printf (msg, "%d", location->start);
101 g_string_append_printf (msg, "%d-%d", location->start, location->end);
105 g_assert (other->start != other->end);
106 g_string_append_printf (msg, ",%d-%d", other->start, other->end);
108 g_string_append_c (msg, ':');
110 g_string_append_vprintf (msg, format, ap);
111 g_set_error_literal (error, G_VARIANT_PARSE_ERROR, code, msg->str);
112 g_string_free (msg, TRUE);
116 parser_set_error (GError **error,
125 va_start (ap, format);
126 parser_set_error_va (error, location, other, code, format, ap);
141 token_stream_set_error (TokenStream *stream,
151 ref.start = stream->this - stream->start;
154 ref.end = stream->stream - stream->start;
158 va_start (ap, format);
159 parser_set_error_va (error, &ref, NULL, code, format, ap);
164 token_stream_prepare (TokenStream *stream)
169 if (stream->this != NULL)
172 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
175 if (stream->stream == stream->end || *stream->stream == '\0')
177 stream->this = stream->stream;
181 switch (stream->stream[0])
183 case '-': case '+': case '.': case '0': case '1': case '2':
184 case '3': case '4': case '5': case '6': case '7': case '8':
186 for (end = stream->stream; end != stream->end; end++)
187 if (!g_ascii_isalnum (*end) &&
188 *end != '-' && *end != '+' && *end != '.')
193 if (stream->stream[1] == '\'' || stream->stream[1] == '"')
195 for (end = stream->stream + 2; end != stream->end; end++)
196 if (*end == stream->stream[1] || *end == '\0' ||
197 (*end == '\\' && (++end == stream->end || *end == '\0')))
200 if (end != stream->end && *end)
207 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
208 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
209 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
210 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
212 for (end = stream->stream; end != stream->end; end++)
213 if (!g_ascii_isalnum (*end))
218 for (end = stream->stream + 1; end != stream->end; end++)
219 if (*end == stream->stream[0] || *end == '\0' ||
220 (*end == '\\' && (++end == stream->end || *end == '\0')))
223 if (end != stream->end && *end)
228 /* stop at the first space, comma, colon or unmatched bracket.
229 * deals nicely with cases like (%i, %i) or {%i: %i}.
231 for (end = stream->stream + 1;
232 end != stream->end && *end != ',' &&
233 *end != ':' && *end != '>' && !g_ascii_isspace (*end);
236 if (*end == '(' || *end == '{')
239 else if ((*end == ')' || *end == '}') && !brackets--)
245 end = stream->stream + 1;
249 stream->this = stream->stream;
250 stream->stream = end;
254 token_stream_next (TokenStream *stream)
260 token_stream_peek (TokenStream *stream,
263 token_stream_prepare (stream);
265 return stream->this[0] == first_char;
269 token_stream_peek2 (TokenStream *stream,
273 token_stream_prepare (stream);
275 return stream->this[0] == first_char &&
276 stream->this[1] == second_char;
280 token_stream_is_keyword (TokenStream *stream)
282 token_stream_prepare (stream);
284 return g_ascii_isalpha (stream->this[0]) &&
285 g_ascii_isalpha (stream->this[1]);
289 token_stream_is_numeric (TokenStream *stream)
291 token_stream_prepare (stream);
293 return (g_ascii_isdigit (stream->this[0]) ||
294 stream->this[0] == '-' ||
295 stream->this[0] == '+' ||
296 stream->this[0] == '.');
300 token_stream_consume (TokenStream *stream,
303 gint length = strlen (token);
305 token_stream_prepare (stream);
307 if (stream->stream - stream->this == length &&
308 memcmp (stream->this, token, length) == 0)
310 token_stream_next (stream);
318 token_stream_require (TokenStream *stream,
320 const gchar *purpose,
324 if (!token_stream_consume (stream, token))
326 token_stream_set_error (stream, error, FALSE,
327 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
328 "expected `%s'%s", token, purpose);
336 token_stream_assert (TokenStream *stream,
339 gboolean correct_token;
341 correct_token = token_stream_consume (stream, token);
342 g_assert (correct_token);
346 token_stream_get (TokenStream *stream)
350 token_stream_prepare (stream);
352 result = g_strndup (stream->this, stream->stream - stream->this);
358 token_stream_start_ref (TokenStream *stream,
361 token_stream_prepare (stream);
362 ref->start = stream->this - stream->start;
366 token_stream_end_ref (TokenStream *stream,
369 ref->end = stream->stream - stream->start;
373 pattern_copy (gchar **out,
378 while (**in == 'a' || **in == 'm' || **in == 'M')
379 *(*out)++ = *(*in)++;
383 if (**in == '(' || **in == '{')
386 else if (**in == ')' || **in == '}')
389 *(*out)++ = *(*in)++;
395 pattern_coalesce (const gchar *left,
401 /* the length of the output is loosely bound by the sum of the input
402 * lengths, not simply the greater of the two lengths.
404 * (*(iii)) + ((iii)*) ((iii)(iii))
408 out = result = g_malloc (strlen (left) + strlen (right));
410 while (*left && *right)
420 const gchar **one = &left, **the_other = &right;
423 if (**one == '*' && **the_other != ')')
425 pattern_copy (&out, the_other);
429 else if (**one == 'M' && **the_other == 'm')
431 *out++ = *(*the_other)++;
434 else if (**one == 'M' && **the_other != 'm')
439 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
441 *out++ = *(*the_other)++;
445 else if (**one == 'S' && strchr ("sog", **the_other))
447 *out++ = *(*the_other)++;
451 else if (one == &left)
453 one = &right, the_other = &left;
473 typedef struct _AST AST;
474 typedef gchar * (*get_pattern_func) (AST *ast,
476 typedef GVariant * (*get_value_func) (AST *ast,
477 const GVariantType *type,
479 typedef GVariant * (*get_base_value_func) (AST *ast,
480 const GVariantType *type,
482 typedef void (*free_func) (AST *ast);
486 gchar * (* get_pattern) (AST *ast,
488 GVariant * (* get_value) (AST *ast,
489 const GVariantType *type,
491 GVariant * (* get_base_value) (AST *ast,
492 const GVariantType *type,
494 void (* free) (AST *ast);
499 const ASTClass *class;
500 SourceRef source_ref;
504 ast_get_pattern (AST *ast,
507 return ast->class->get_pattern (ast, error);
511 ast_get_value (AST *ast,
512 const GVariantType *type,
515 return ast->class->get_value (ast, type, error);
521 ast->class->free (ast);
525 ast_set_error (AST *ast,
534 va_start (ap, format);
535 parser_set_error_va (error, &ast->source_ref,
536 other_ast ? & other_ast->source_ref : NULL,
543 ast_type_error (AST *ast,
544 const GVariantType *type,
549 typestr = g_variant_type_dup_string (type);
550 ast_set_error (ast, error, NULL,
551 G_VARIANT_PARSE_ERROR_TYPE_ERROR,
552 "can not parse as value of type `%s'",
560 ast_resolve (AST *ast,
567 pattern = ast_get_pattern (ast, error);
572 /* choose reasonable defaults
574 * 1) favour non-maybe values where possible
575 * 2) default type for strings is 's'
576 * 3) default type for integers is 'i'
578 for (i = 0; pattern[i]; i++)
582 ast_set_error (ast, error, NULL,
583 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
584 "unable to infer type");
600 pattern[j++] = pattern[i];
605 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
612 static AST *parse (TokenStream *stream,
617 ast_array_append (AST ***array,
621 if ((*n_items & (*n_items - 1)) == 0)
622 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
624 (*array)[(*n_items)++] = ast;
628 ast_array_free (AST **array,
633 for (i = 0; i < n_items; i++)
639 ast_array_get_pattern (AST **array,
646 pattern = ast_get_pattern (array[0], error);
651 for (i = 1; i < n_items; i++)
655 tmp = ast_get_pattern (array[i], error);
663 merged = pattern_coalesce (pattern, tmp);
668 /* set coalescence implies pairwise coalescence (i think).
669 * we should therefore be able to trace the failure to a single
680 /* if 'j' reaches 'i' then we failed to find the pair */
683 tmp2 = ast_get_pattern (array[j], NULL);
684 g_assert (tmp2 != NULL);
686 m = pattern_coalesce (tmp, tmp2);
692 /* we found a conflict between 'i' and 'j'.
694 * report the error. note: 'j' is first.
696 ast_set_error (array[j], error, array[i],
697 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
698 "unable to find a common type");
722 maybe_get_pattern (AST *ast,
725 Maybe *maybe = (Maybe *) ast;
727 if (maybe->child != NULL)
729 gchar *child_pattern;
732 child_pattern = ast_get_pattern (maybe->child, error);
734 if (child_pattern == NULL)
737 pattern = g_strdup_printf ("m%s", child_pattern);
738 g_free (child_pattern);
743 return g_strdup ("m*");
747 maybe_get_value (AST *ast,
748 const GVariantType *type,
751 Maybe *maybe = (Maybe *) ast;
754 if (!g_variant_type_is_maybe (type))
755 return ast_type_error (ast, type, error);
757 type = g_variant_type_element (type);
761 value = ast_get_value (maybe->child, type, error);
769 return g_variant_new_maybe (type, value);
773 maybe_free (AST *ast)
775 Maybe *maybe = (Maybe *) ast;
777 if (maybe->child != NULL)
778 ast_free (maybe->child);
780 g_slice_free (Maybe, maybe);
784 maybe_parse (TokenStream *stream,
788 static const ASTClass maybe_class = {
790 maybe_get_value, NULL,
796 if (token_stream_consume (stream, "just"))
798 child = parse (stream, app, error);
803 else if (!token_stream_consume (stream, "nothing"))
805 token_stream_set_error (stream, error, TRUE,
806 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
811 maybe = g_slice_new (Maybe);
812 maybe->ast.class = &maybe_class;
813 maybe->child = child;
815 return (AST *) maybe;
819 maybe_wrapper (AST *ast,
820 const GVariantType *type,
823 const GVariantType *t;
827 for (depth = 0, t = type;
828 g_variant_type_is_maybe (t);
829 depth++, t = g_variant_type_element (t));
831 value = ast->class->get_base_value (ast, t, error);
837 value = g_variant_new_maybe (NULL, value);
851 array_get_pattern (AST *ast,
854 Array *array = (Array *) ast;
858 if (array->n_children == 0)
859 return g_strdup ("Ma*");
861 pattern = ast_array_get_pattern (array->children, array->n_children, error);
866 result = g_strdup_printf ("Ma%s", pattern);
873 array_get_value (AST *ast,
874 const GVariantType *type,
877 Array *array = (Array *) ast;
878 const GVariantType *childtype;
879 GVariantBuilder builder;
882 if (!g_variant_type_is_array (type))
883 return ast_type_error (ast, type, error);
885 g_variant_builder_init (&builder, type);
886 childtype = g_variant_type_element (type);
888 for (i = 0; i < array->n_children; i++)
892 if (!(child = ast_get_value (array->children[i], childtype, error)))
894 g_variant_builder_clear (&builder);
898 g_variant_builder_add_value (&builder, child);
901 return g_variant_builder_end (&builder);
905 array_free (AST *ast)
907 Array *array = (Array *) ast;
909 ast_array_free (array->children, array->n_children);
910 g_slice_free (Array, array);
914 array_parse (TokenStream *stream,
918 static const ASTClass array_class = {
920 maybe_wrapper, array_get_value,
923 gboolean need_comma = FALSE;
926 array = g_slice_new (Array);
927 array->ast.class = &array_class;
928 array->children = NULL;
929 array->n_children = 0;
931 token_stream_assert (stream, "[");
932 while (!token_stream_consume (stream, "]"))
937 !token_stream_require (stream, ",",
938 " or `]' to follow array element",
942 child = parse (stream, app, error);
947 ast_array_append (&array->children, &array->n_children, child);
951 return (AST *) array;
954 ast_array_free (array->children, array->n_children);
955 g_slice_free (Array, array);
969 tuple_get_pattern (AST *ast,
972 Tuple *tuple = (Tuple *) ast;
973 gchar *result = NULL;
977 parts = g_new (gchar *, tuple->n_children + 4);
978 parts[tuple->n_children + 1] = (gchar *) ")";
979 parts[tuple->n_children + 2] = NULL;
980 parts[0] = (gchar *) "M(";
982 for (i = 0; i < tuple->n_children; i++)
983 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
986 if (i == tuple->n_children)
987 result = g_strjoinv ("", parts);
989 /* parts[0] should not be freed */
998 tuple_get_value (AST *ast,
999 const GVariantType *type,
1002 Tuple *tuple = (Tuple *) ast;
1003 const GVariantType *childtype;
1004 GVariantBuilder builder;
1007 if (!g_variant_type_is_tuple (type))
1008 return ast_type_error (ast, type, error);
1010 g_variant_builder_init (&builder, type);
1011 childtype = g_variant_type_first (type);
1013 for (i = 0; i < tuple->n_children; i++)
1017 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1019 g_variant_builder_clear (&builder);
1023 g_variant_builder_add_value (&builder, child);
1024 childtype = g_variant_type_next (childtype);
1027 return g_variant_builder_end (&builder);
1031 tuple_free (AST *ast)
1033 Tuple *tuple = (Tuple *) ast;
1035 ast_array_free (tuple->children, tuple->n_children);
1036 g_slice_free (Tuple, tuple);
1040 tuple_parse (TokenStream *stream,
1044 static const ASTClass tuple_class = {
1046 maybe_wrapper, tuple_get_value,
1049 gboolean need_comma = FALSE;
1050 gboolean first = TRUE;
1053 tuple = g_slice_new (Tuple);
1054 tuple->ast.class = &tuple_class;
1055 tuple->children = NULL;
1056 tuple->n_children = 0;
1058 token_stream_assert (stream, "(");
1059 while (!token_stream_consume (stream, ")"))
1064 !token_stream_require (stream, ",",
1065 " or `)' to follow tuple element",
1069 child = parse (stream, app, error);
1074 ast_array_append (&tuple->children, &tuple->n_children, child);
1076 /* the first time, we absolutely require a comma, so grab it here
1077 * and leave need_comma = FALSE so that the code above doesn't
1078 * require a second comma.
1080 * the second and remaining times, we set need_comma = TRUE.
1084 if (!token_stream_require (stream, ",",
1085 " after first tuple element", error))
1094 return (AST *) tuple;
1097 ast_array_free (tuple->children, tuple->n_children);
1098 g_slice_free (Tuple, tuple);
1111 variant_get_pattern (AST *ast,
1114 return g_strdup ("Mv");
1118 variant_get_value (AST *ast,
1119 const GVariantType *type,
1122 Variant *variant = (Variant *) ast;
1125 g_assert (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT));
1126 child = ast_resolve (variant->value, error);
1131 return g_variant_new_variant (child);
1135 variant_free (AST *ast)
1137 Variant *variant = (Variant *) ast;
1139 ast_free (variant->value);
1140 g_slice_free (Variant, variant);
1144 variant_parse (TokenStream *stream,
1148 static const ASTClass variant_class = {
1149 variant_get_pattern,
1150 maybe_wrapper, variant_get_value,
1156 token_stream_assert (stream, "<");
1157 value = parse (stream, app, error);
1162 if (!token_stream_require (stream, ">", " to follow variant value", error))
1168 variant = g_slice_new (Variant);
1169 variant->ast.class = &variant_class;
1170 variant->value = value;
1172 return (AST *) variant;
1185 dictionary_get_pattern (AST *ast,
1188 Dictionary *dict = (Dictionary *) ast;
1189 gchar *value_pattern;
1194 if (dict->n_children == 0)
1195 return g_strdup ("Ma{**}");
1197 key_pattern = ast_array_get_pattern (dict->keys,
1198 abs (dict->n_children),
1201 if (key_pattern == NULL)
1204 /* we can not have maybe keys */
1205 if (key_pattern[0] == 'M')
1206 key_char = key_pattern[1];
1208 key_char = key_pattern[0];
1210 g_free (key_pattern);
1213 * plus undetermined number type and undetermined string type.
1215 if (!strchr ("bynqiuxthdsogNS", key_char))
1217 ast_set_error (ast, error, NULL,
1218 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1219 "dictionary keys must have basic types");
1223 value_pattern = ast_get_pattern (dict->values[0], error);
1225 if (value_pattern == NULL)
1228 result = g_strdup_printf ("M%s{%c%s}",
1229 dict->n_children > 0 ? "a" : "",
1230 key_char, value_pattern);
1231 g_free (value_pattern);
1237 dictionary_get_value (AST *ast,
1238 const GVariantType *type,
1241 Dictionary *dict = (Dictionary *) ast;
1243 if (dict->n_children == -1)
1245 const GVariantType *subtype;
1246 GVariantBuilder builder;
1249 if (!g_variant_type_is_dict_entry (type))
1250 return ast_type_error (ast, type, error);
1252 g_variant_builder_init (&builder, type);
1254 subtype = g_variant_type_key (type);
1255 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1257 g_variant_builder_clear (&builder);
1260 g_variant_builder_add_value (&builder, subvalue);
1262 subtype = g_variant_type_value (type);
1263 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1265 g_variant_builder_clear (&builder);
1268 g_variant_builder_add_value (&builder, subvalue);
1270 return g_variant_builder_end (&builder);
1274 const GVariantType *entry, *key, *val;
1275 GVariantBuilder builder;
1278 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1279 return ast_type_error (ast, type, error);
1281 entry = g_variant_type_element (type);
1282 key = g_variant_type_key (entry);
1283 val = g_variant_type_value (entry);
1285 g_variant_builder_init (&builder, type);
1287 for (i = 0; i < dict->n_children; i++)
1291 g_variant_builder_open (&builder, entry);
1293 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1295 g_variant_builder_clear (&builder);
1298 g_variant_builder_add_value (&builder, subvalue);
1300 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1302 g_variant_builder_clear (&builder);
1305 g_variant_builder_add_value (&builder, subvalue);
1306 g_variant_builder_close (&builder);
1309 return g_variant_builder_end (&builder);
1314 dictionary_free (AST *ast)
1316 Dictionary *dict = (Dictionary *) ast;
1319 if (dict->n_children > -1)
1320 n_children = dict->n_children;
1324 ast_array_free (dict->keys, n_children);
1325 ast_array_free (dict->values, n_children);
1326 g_slice_free (Dictionary, dict);
1330 dictionary_parse (TokenStream *stream,
1334 static const ASTClass dictionary_class = {
1335 dictionary_get_pattern,
1336 maybe_wrapper, dictionary_get_value,
1339 gint n_keys, n_values;
1344 dict = g_slice_new (Dictionary);
1345 dict->ast.class = &dictionary_class;
1347 dict->values = NULL;
1348 n_keys = n_values = 0;
1350 token_stream_assert (stream, "{");
1352 if (token_stream_consume (stream, "}"))
1354 dict->n_children = 0;
1355 return (AST *) dict;
1358 if ((first = parse (stream, app, error)) == NULL)
1361 ast_array_append (&dict->keys, &n_keys, first);
1363 only_one = token_stream_consume (stream, ",");
1365 !token_stream_require (stream, ":",
1366 " or `,' to follow dictionary entry key",
1370 if ((first = parse (stream, app, error)) == NULL)
1373 ast_array_append (&dict->values, &n_values, first);
1377 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1381 g_assert (n_keys == 1 && n_values == 1);
1382 dict->n_children = -1;
1384 return (AST *) dict;
1387 while (!token_stream_consume (stream, "}"))
1391 if (!token_stream_require (stream, ",",
1392 " or `}' to follow dictionary entry", error))
1395 child = parse (stream, app, error);
1400 ast_array_append (&dict->keys, &n_keys, child);
1402 if (!token_stream_require (stream, ":",
1403 " to follow dictionary entry key", error))
1406 child = parse (stream, app, error);
1411 ast_array_append (&dict->values, &n_values, child);
1414 g_assert (n_keys == n_values);
1415 dict->n_children = n_keys;
1417 return (AST *) dict;
1420 ast_array_free (dict->keys, n_keys);
1421 ast_array_free (dict->values, n_values);
1422 g_slice_free (Dictionary, dict);
1434 string_get_pattern (AST *ast,
1437 return g_strdup ("MS");
1441 string_get_value (AST *ast,
1442 const GVariantType *type,
1445 String *string = (String *) ast;
1447 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1448 return g_variant_new_string (string->string);
1450 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1452 if (!g_variant_is_object_path (string->string))
1454 ast_set_error (ast, error, NULL,
1455 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1456 "not a valid object path");
1460 return g_variant_new_object_path (string->string);
1463 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1465 if (!g_variant_is_signature (string->string))
1467 ast_set_error (ast, error, NULL,
1468 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1469 "not a valid signature");
1473 return g_variant_new_signature (string->string);
1477 return ast_type_error (ast, type, error);
1481 string_free (AST *ast)
1483 String *string = (String *) ast;
1485 g_free (string->string);
1486 g_slice_free (String, string);
1490 unicode_unescape (const gchar *src,
1504 g_assert (length < sizeof (buffer));
1505 strncpy (buffer, src + *src_ofs, length);
1506 buffer[length] = '\0';
1508 value = g_ascii_strtoull (buffer, &end, 0x10);
1510 if (value == 0 || end != buffer + length)
1512 parser_set_error (error, ref, NULL,
1513 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1514 "invalid %d-character unicode escape", length);
1518 g_assert (value <= G_MAXUINT32);
1520 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1527 string_parse (TokenStream *stream,
1531 static const ASTClass string_class = {
1533 maybe_wrapper, string_get_value,
1544 token_stream_start_ref (stream, &ref);
1545 token = token_stream_get (stream);
1546 token_stream_end_ref (stream, &ref);
1547 length = strlen (token);
1550 str = g_malloc (length);
1551 g_assert (quote == '"' || quote == '\'');
1554 while (token[i] != quote)
1558 parser_set_error (error, &ref, NULL,
1559 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1560 "unterminated string constant");
1569 parser_set_error (error, &ref, NULL,
1570 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1571 "unterminated string constant");
1577 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1586 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1594 case 'a': str[j++] = '\a'; i++; continue;
1595 case 'b': str[j++] = '\b'; i++; continue;
1596 case 'f': str[j++] = '\f'; i++; continue;
1597 case 'n': str[j++] = '\n'; i++; continue;
1598 case 'r': str[j++] = '\r'; i++; continue;
1599 case 't': str[j++] = '\t'; i++; continue;
1600 case 'v': str[j++] = '\v'; i++; continue;
1601 case '\n': i++; continue;
1605 str[j++] = token[i++];
1610 string = g_slice_new (String);
1611 string->ast.class = &string_class;
1612 string->string = str;
1614 token_stream_next (stream);
1616 return (AST *) string;
1626 bytestring_get_pattern (AST *ast,
1629 return g_strdup ("May");
1633 bytestring_get_value (AST *ast,
1634 const GVariantType *type,
1637 ByteString *string = (ByteString *) ast;
1639 g_assert (g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING));
1641 return g_variant_new_bytestring (string->string);
1645 bytestring_free (AST *ast)
1647 ByteString *string = (ByteString *) ast;
1649 g_free (string->string);
1650 g_slice_free (ByteString, string);
1654 bytestring_parse (TokenStream *stream,
1658 static const ASTClass bytestring_class = {
1659 bytestring_get_pattern,
1660 maybe_wrapper, bytestring_get_value,
1671 token_stream_start_ref (stream, &ref);
1672 token = token_stream_get (stream);
1673 token_stream_end_ref (stream, &ref);
1674 g_assert (token[0] == 'b');
1675 length = strlen (token);
1678 str = g_malloc (length);
1679 g_assert (quote == '"' || quote == '\'');
1682 while (token[i] != quote)
1686 parser_set_error (error, &ref, NULL,
1687 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1688 "unterminated string constant");
1696 parser_set_error (error, &ref, NULL,
1697 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1698 "unterminated string constant");
1702 case '0': case '1': case '2': case '3':
1703 case '4': case '5': case '6': case '7':
1705 /* up to 3 characters */
1706 guchar val = token[i++] - '0';
1708 if ('0' <= token[i] && token[i] < '8')
1709 val = (val << 3) | (token[i++] - '0');
1711 if ('0' <= token[i] && token[i] < '8')
1712 val = (val << 3) | (token[i++] - '0');
1718 case 'a': str[j++] = '\a'; i++; continue;
1719 case 'b': str[j++] = '\b'; i++; continue;
1720 case 'f': str[j++] = '\f'; i++; continue;
1721 case 'n': str[j++] = '\n'; i++; continue;
1722 case 'r': str[j++] = '\r'; i++; continue;
1723 case 't': str[j++] = '\t'; i++; continue;
1724 case 'v': str[j++] = '\v'; i++; continue;
1725 case '\n': i++; continue;
1729 str[j++] = token[i++];
1734 string = g_slice_new (ByteString);
1735 string->ast.class = &bytestring_class;
1736 string->string = str;
1738 token_stream_next (stream);
1740 return (AST *) string;
1751 number_get_pattern (AST *ast,
1754 Number *number = (Number *) ast;
1756 if (strchr (number->token, '.') ||
1757 (!g_str_has_prefix (number->token, "0x") &&
1758 strchr (number->token, 'e')))
1759 return g_strdup ("Md");
1761 return g_strdup ("MN");
1765 number_overflow (AST *ast,
1766 const GVariantType *type,
1769 ast_set_error (ast, error, NULL,
1770 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1771 "number out of range for type `%c'",
1772 g_variant_type_peek_string (type)[0]);
1777 number_get_value (AST *ast,
1778 const GVariantType *type,
1781 Number *number = (Number *) ast;
1789 token = number->token;
1791 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1796 dbl_val = g_ascii_strtod (token, &end);
1797 if (dbl_val != 0.0 && errno == ERANGE)
1799 ast_set_error (ast, error, NULL,
1800 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1801 "number too big for any type");
1805 /* silence uninitialised warnings... */
1812 negative = token[0] == '-';
1813 if (token[0] == '-')
1817 abs_val = g_ascii_strtoull (token, &end, 0);
1818 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1820 ast_set_error (ast, error, NULL,
1821 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1822 "integer too big for any type");
1829 /* silence uninitialised warning... */
1837 ref = ast->source_ref;
1838 ref.start += end - number->token;
1839 ref.end = ref.start + 1;
1841 parser_set_error (error, &ref, NULL,
1842 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1843 "invalid character in number");
1848 return g_variant_new_double (dbl_val);
1850 switch (*g_variant_type_peek_string (type))
1853 if (negative || abs_val > G_MAXUINT8)
1854 return number_overflow (ast, type, error);
1855 return g_variant_new_byte (abs_val);
1858 if (abs_val - negative > G_MAXINT16)
1859 return number_overflow (ast, type, error);
1860 return g_variant_new_int16 (negative ? -abs_val : abs_val);
1863 if (negative || abs_val > G_MAXUINT16)
1864 return number_overflow (ast, type, error);
1865 return g_variant_new_uint16 (negative ? -abs_val : abs_val);
1868 if (abs_val - negative > G_MAXINT32)
1869 return number_overflow (ast, type, error);
1870 return g_variant_new_int32 (negative ? -abs_val : abs_val);
1873 if (negative || abs_val > G_MAXUINT32)
1874 return number_overflow (ast, type, error);
1875 return g_variant_new_uint32 (negative ? -abs_val : abs_val);
1878 if (abs_val - negative > G_MAXINT64)
1879 return number_overflow (ast, type, error);
1880 return g_variant_new_int64 (negative ? -abs_val : abs_val);
1884 return number_overflow (ast, type, error);
1885 return g_variant_new_uint64 (negative ? -abs_val : abs_val);
1888 if (abs_val - negative > G_MAXINT32)
1889 return number_overflow (ast, type, error);
1890 return g_variant_new_handle (negative ? -abs_val : abs_val);
1893 return ast_type_error (ast, type, error);
1898 number_free (AST *ast)
1900 Number *number = (Number *) ast;
1902 g_free (number->token);
1903 g_slice_free (Number, number);
1907 number_parse (TokenStream *stream,
1911 static const ASTClass number_class = {
1913 maybe_wrapper, number_get_value,
1918 number = g_slice_new (Number);
1919 number->ast.class = &number_class;
1920 number->token = token_stream_get (stream);
1921 token_stream_next (stream);
1923 return (AST *) number;
1933 boolean_get_pattern (AST *ast,
1936 return g_strdup ("Mb");
1940 boolean_get_value (AST *ast,
1941 const GVariantType *type,
1944 Boolean *boolean = (Boolean *) ast;
1946 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
1947 return ast_type_error (ast, type, error);
1949 return g_variant_new_boolean (boolean->value);
1953 boolean_free (AST *ast)
1955 Boolean *boolean = (Boolean *) ast;
1957 g_slice_free (Boolean, boolean);
1961 boolean_new (gboolean value)
1963 static const ASTClass boolean_class = {
1964 boolean_get_pattern,
1965 maybe_wrapper, boolean_get_value,
1970 boolean = g_slice_new (Boolean);
1971 boolean->ast.class = &boolean_class;
1972 boolean->value = value;
1974 return (AST *) boolean;
1985 positional_get_pattern (AST *ast,
1988 Positional *positional = (Positional *) ast;
1990 return g_strdup (g_variant_get_type_string (positional->value));
1994 positional_get_value (AST *ast,
1995 const GVariantType *type,
1998 Positional *positional = (Positional *) ast;
2001 g_assert (positional->value != NULL);
2003 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2004 return ast_type_error (ast, type, error);
2006 /* NOTE: if _get is called more than once then
2007 * things get messed up with respect to floating refs.
2009 * fortunately, this function should only ever get called once.
2011 g_assert (positional->value != NULL);
2012 value = positional->value;
2013 positional->value = NULL;
2019 positional_free (AST *ast)
2021 Positional *positional = (Positional *) ast;
2023 /* if positional->value is set, just leave it.
2024 * memory management doesn't matter in case of programmer error.
2026 g_slice_free (Positional, positional);
2030 positional_parse (TokenStream *stream,
2034 static const ASTClass positional_class = {
2035 positional_get_pattern,
2036 positional_get_value, NULL,
2039 Positional *positional;
2040 const gchar *endptr;
2043 token = token_stream_get (stream);
2044 g_assert (token[0] == '%');
2046 positional = g_slice_new (Positional);
2047 positional->ast.class = &positional_class;
2048 positional->value = g_variant_new_va (token + 1, &endptr, app);
2050 if (*endptr || positional->value == NULL)
2052 token_stream_set_error (stream, error, TRUE,
2053 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2054 "invalid GVariant format string");
2055 /* memory management doesn't matter in case of programmer error. */
2059 token_stream_next (stream);
2062 return (AST *) positional;
2074 typedecl_get_pattern (AST *ast,
2077 TypeDecl *decl = (TypeDecl *) ast;
2079 return g_variant_type_dup_string (decl->type);
2083 typedecl_get_value (AST *ast,
2084 const GVariantType *type,
2087 TypeDecl *decl = (TypeDecl *) ast;
2089 return ast_get_value (decl->child, type, error);
2093 typedecl_free (AST *ast)
2095 TypeDecl *decl = (TypeDecl *) ast;
2097 ast_free (decl->child);
2098 g_variant_type_free (decl->type);
2099 g_slice_free (TypeDecl, decl);
2103 typedecl_parse (TokenStream *stream,
2107 static const ASTClass typedecl_class = {
2108 typedecl_get_pattern,
2109 typedecl_get_value, NULL,
2116 if (token_stream_peek (stream, '@'))
2120 token = token_stream_get (stream);
2122 if (!g_variant_type_string_is_valid (token + 1))
2124 token_stream_set_error (stream, error, TRUE,
2125 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2126 "invalid type declaration");
2132 type = g_variant_type_new (token + 1);
2134 if (!g_variant_type_is_definite (type))
2136 token_stream_set_error (stream, error, TRUE,
2137 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2138 "type declarations must be definite");
2139 g_variant_type_free (type);
2145 token_stream_next (stream);
2150 if (token_stream_consume (stream, "boolean"))
2151 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2153 else if (token_stream_consume (stream, "byte"))
2154 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2156 else if (token_stream_consume (stream, "int16"))
2157 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2159 else if (token_stream_consume (stream, "uint16"))
2160 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2162 else if (token_stream_consume (stream, "int32"))
2163 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2165 else if (token_stream_consume (stream, "handle"))
2166 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2168 else if (token_stream_consume (stream, "uint32"))
2169 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2171 else if (token_stream_consume (stream, "int64"))
2172 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2174 else if (token_stream_consume (stream, "uint64"))
2175 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2177 else if (token_stream_consume (stream, "double"))
2178 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2180 else if (token_stream_consume (stream, "string"))
2181 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2183 else if (token_stream_consume (stream, "objectpath"))
2184 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2186 else if (token_stream_consume (stream, "signature"))
2187 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2191 token_stream_set_error (stream, error, TRUE,
2192 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2198 if ((child = parse (stream, app, error)) == NULL)
2200 g_variant_type_free (type);
2204 decl = g_slice_new (TypeDecl);
2205 decl->ast.class = &typedecl_class;
2207 decl->child = child;
2209 return (AST *) decl;
2213 parse (TokenStream *stream,
2217 SourceRef source_ref;
2220 token_stream_prepare (stream);
2221 token_stream_start_ref (stream, &source_ref);
2223 if (token_stream_peek (stream, '['))
2224 result = array_parse (stream, app, error);
2226 else if (token_stream_peek (stream, '('))
2227 result = tuple_parse (stream, app, error);
2229 else if (token_stream_peek (stream, '<'))
2230 result = variant_parse (stream, app, error);
2232 else if (token_stream_peek (stream, '{'))
2233 result = dictionary_parse (stream, app, error);
2235 else if (app && token_stream_peek (stream, '%'))
2236 result = positional_parse (stream, app, error);
2238 else if (token_stream_consume (stream, "true"))
2239 result = boolean_new (TRUE);
2241 else if (token_stream_consume (stream, "false"))
2242 result = boolean_new (FALSE);
2244 else if (token_stream_peek (stream, 'n') ||
2245 token_stream_peek (stream, 'j'))
2246 result = maybe_parse (stream, app, error);
2248 else if (token_stream_peek (stream, '@') ||
2249 token_stream_is_keyword (stream))
2250 result = typedecl_parse (stream, app, error);
2252 else if (token_stream_is_numeric (stream))
2253 result = number_parse (stream, app, error);
2255 else if (token_stream_peek (stream, '\'') ||
2256 token_stream_peek (stream, '"'))
2257 result = string_parse (stream, app, error);
2259 else if (token_stream_peek2 (stream, 'b', '\'') ||
2260 token_stream_peek2 (stream, 'b', '"'))
2261 result = bytestring_parse (stream, app, error);
2265 token_stream_set_error (stream, error, FALSE,
2266 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2273 token_stream_end_ref (stream, &source_ref);
2274 result->source_ref = source_ref;
2282 * @type: a #GVariantType, or %NULL
2283 * @text: a string containing a GVariant in text form
2284 * @limit: a pointer to the end of @text, or %NULL
2285 * @endptr: a location to store the end pointer, or %NULL
2286 * @error: a pointer to a %NULL #GError pointer, or %NULL
2287 * @Returns: a reference to a #GVariant, or %NULL
2289 * Parses a #GVariant from a text representation.
2291 * A single #GVariant is parsed from the content of @text.
2293 * The memory at @limit will never be accessed and the parser behaves as
2294 * if the character at @limit is the nul terminator. This has the
2295 * effect of bounding @text.
2297 * If @endptr is non-%NULL then @text is permitted to contain data
2298 * following the value that this function parses and @endptr will be
2299 * updated to point to the first character past the end of the text
2300 * parsed by this function. If @endptr is %NULL and there is extra data
2301 * then an error is returned.
2303 * If @type is non-%NULL then the value will be parsed to have that
2304 * type. This may result in additional parse errors (in the case that
2305 * the parsed value doesn't fit the type) but may also result in fewer
2306 * errors (in the case that the type would have been ambiguous, such as
2307 * with empty arrays).
2309 * In the event that the parsing is successful, the resulting #GVariant
2312 * In case of any error, %NULL will be returned. If @error is non-%NULL
2313 * then it will be set to reflect the error that occured.
2315 * Officially, the language understood by the parser is "any string
2316 * produced by g_variant_print()".
2319 g_variant_parse (const GVariantType *type,
2322 const gchar **endptr,
2325 TokenStream stream = { 0, };
2326 GVariant *result = NULL;
2329 g_return_val_if_fail (text != NULL, NULL);
2330 g_return_val_if_fail (text == limit || text != NULL, NULL);
2332 stream.start = text;
2333 stream.stream = text;
2336 if ((ast = parse (&stream, NULL, error)))
2339 result = ast_resolve (ast, error);
2341 result = ast_get_value (ast, type, error);
2345 g_variant_ref_sink (result);
2349 while (stream.stream != limit &&
2350 g_ascii_isspace (*stream.stream))
2353 if (stream.stream != limit && *stream.stream != '\0')
2355 SourceRef ref = { stream.stream - text,
2356 stream.stream - text };
2358 parser_set_error (error, &ref, NULL,
2359 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2360 "expected end of input");
2361 g_variant_unref (result);
2367 *endptr = stream.stream;
2377 * g_variant_new_parsed_va:
2378 * @format: a text format #GVariant
2379 * @app: a pointer to a #va_list
2380 * @returns: a new, usually floating, #GVariant
2382 * Parses @format and returns the result.
2384 * This is the version of g_variant_new_parsed() intended to be used
2387 * The return value will be floating if it was a newly created GVariant
2388 * instance. In the case that @format simply specified the collection
2389 * of a #GVariant pointer (eg: @format was "%*") then the collected
2390 * #GVariant pointer will be returned unmodified, without adding any
2391 * additional references.
2393 * In order to behave correctly in all cases it is necessary for the
2394 * calling function to g_variant_ref_sink() the return result before
2395 * returning control to the user that originally provided the pointer.
2396 * At this point, the caller will have their own full reference to the
2397 * result. This can also be done by adding the result to a container,
2398 * or by passing it to another g_variant_new() call.
2401 g_variant_new_parsed_va (const gchar *format,
2404 TokenStream stream = { 0, };
2405 GVariant *result = NULL;
2406 GError *error = NULL;
2409 g_return_val_if_fail (format != NULL, NULL);
2410 g_return_val_if_fail (app != NULL, NULL);
2412 stream.start = format;
2413 stream.stream = format;
2416 if ((ast = parse (&stream, app, &error)))
2418 result = ast_resolve (ast, &error);
2423 g_error ("g_variant_new_parsed: %s", error->message);
2426 g_error ("g_variant_new_parsed: trailing text after value");
2432 * g_variant_new_parsed:
2433 * @format: a text format #GVariant
2434 * @...: arguments as per @format
2435 * @returns: a new floating #GVariant instance
2437 * Parses @format and returns the result.
2439 * @format must be a text format #GVariant with one extension: at any
2440 * point that a value may appear in the text, a '%' character followed
2441 * by a GVariant format string (as per g_variant_new()) may appear. In
2442 * that case, the same arguments are collected from the argument list as
2443 * g_variant_new() would have collected.
2445 * Consider this simple example:
2447 * <informalexample><programlisting>
2448 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2449 * </programlisting></informalexample>
2451 * In the example, the variable argument parameters are collected and
2452 * filled in as if they were part of the original string to produce the
2453 * result of <code>[('one', 1), ('two', 2), ('three', 3)]</code>.
2455 * This function is intended only to be used with @format as a string
2456 * literal. Any parse error is fatal to the calling process. If you
2457 * want to parse data from untrusted sources, use g_variant_parse().
2459 * You may not use this function to return, unmodified, a single
2460 * #GVariant pointer from the argument list. ie: @format may not solely
2461 * be anything along the lines of "%*", "%?", "%r", or anything starting
2465 g_variant_new_parsed (const gchar *format,
2471 va_start (ap, format);
2472 result = g_variant_new_parsed_va (format, &ap);
2479 * g_variant_builder_add_parsed:
2480 * @builder: a #GVariantBuilder
2481 * @format: a text format #GVariant
2482 * @...: arguments as per @format
2484 * Adds to a #GVariantBuilder.
2486 * This call is a convenience wrapper that is exactly equivalent to
2487 * calling g_variant_new_parsed() followed by
2488 * g_variant_builder_add_value().
2490 * This function might be used as follows:
2494 * make_pointless_dictionary (void)
2496 * GVariantBuilder *builder;
2499 * builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
2500 * g_variant_builder_add_parsed (builder, "{'width', <%i>}", 600);
2501 * g_variant_builder_add_parsed (builder, "{'title', <%s>}", "foo");
2502 * g_variant_builder_add_parsed (builder, "{'transparency', <0.5>}");
2503 * return g_variant_builder_end (builder);
2510 g_variant_builder_add_parsed (GVariantBuilder *builder,
2511 const gchar *format,
2516 va_start (ap, format);
2517 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));