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>
30 * designed by ryan lortie and william hua
31 * designed in itb-229 and at ghazi's, 2009.
35 * G_VARIANT_PARSE_ERROR:
37 * Error domain for GVariant text format parsing. Specific error codes
38 * are not currently defined for this domain. See #GError for
39 * information on error domains.
43 * @G_VARIANT_PARSE_ERROR_FAILED: generic error
45 * Error codes returned by parsing text-format GVariants. Currently the
46 * parser makes no distinction between different types of error.
49 g_variant_parser_get_error_quark (void)
51 static GQuark the_quark;
54 the_quark = g_quark_from_static_string ("g-variant-parse-error-quark");
65 parser_set_error_va (GError **error,
71 GString *msg = g_string_new (NULL);
73 if (location->start == location->end)
74 g_string_append_printf (msg, "%d", location->start);
76 g_string_append_printf (msg, "%d-%d", location->start, location->end);
80 g_assert (other->start != other->end);
81 g_string_append_printf (msg, ",%d-%d", other->start, other->end);
83 g_string_append_c (msg, ':');
85 g_string_append_vprintf (msg, format, ap);
86 g_set_error_literal (error, G_VARIANT_PARSE_ERROR, 0, msg->str);
87 g_string_free (msg, TRUE);
91 parser_set_error (GError **error,
99 va_start (ap, format);
100 parser_set_error_va (error, location, other, format, ap);
115 token_stream_set_error (TokenStream *stream,
124 ref.start = stream->this - stream->start;
127 ref.end = stream->stream - stream->start;
131 va_start (ap, format);
132 parser_set_error_va (error, &ref, NULL, format, ap);
137 token_stream_prepare (TokenStream *stream)
142 if (stream->this != NULL)
145 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
148 if (stream->stream == stream->end || *stream->stream == '\0')
150 stream->this = stream->stream;
154 switch (stream->stream[0])
156 case '-': case '+': case '.': case '0': case '1': case '2':
157 case '3': case '4': case '5': case '6': case '7': case '8':
159 for (end = stream->stream; end != stream->end; end++)
160 if (!g_ascii_isalnum (*end) &&
161 *end != '-' && *end != '+' && *end != '.')
166 if (stream->stream[1] == '\'' || stream->stream[1] == '"')
168 for (end = stream->stream + 2; end != stream->end; end++)
169 if (*end == stream->stream[1] || *end == '\0' ||
170 (*end == '\\' && (++end == stream->end || *end == '\0')))
173 if (end != stream->end && *end)
180 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
181 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
182 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
183 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
185 for (end = stream->stream; end != stream->end; end++)
186 if (!g_ascii_isalnum (*end))
191 for (end = stream->stream + 1; end != stream->end; end++)
192 if (*end == stream->stream[0] || *end == '\0' ||
193 (*end == '\\' && (++end == stream->end || *end == '\0')))
196 if (end != stream->end && *end)
201 /* stop at the first space, comma, colon or unmatched bracket.
202 * deals nicely with cases like (%i, %i) or {%i: %i}.
204 for (end = stream->stream + 1;
205 end != stream->end && *end != ',' &&
206 *end != ':' && *end != '>' && !g_ascii_isspace (*end);
209 if (*end == '(' || *end == '{')
212 else if ((*end == ')' || *end == '}') && !brackets--)
218 end = stream->stream + 1;
222 stream->this = stream->stream;
223 stream->stream = end;
227 token_stream_next (TokenStream *stream)
233 token_stream_peek (TokenStream *stream,
236 token_stream_prepare (stream);
238 return stream->this[0] == first_char;
242 token_stream_peek2 (TokenStream *stream,
246 token_stream_prepare (stream);
248 return stream->this[0] == first_char &&
249 stream->this[1] == second_char;
253 token_stream_is_keyword (TokenStream *stream)
255 token_stream_prepare (stream);
257 return g_ascii_isalpha (stream->this[0]) &&
258 g_ascii_isalpha (stream->this[1]);
262 token_stream_is_numeric (TokenStream *stream)
264 token_stream_prepare (stream);
266 return (g_ascii_isdigit (stream->this[0]) ||
267 stream->this[0] == '-' ||
268 stream->this[0] == '+' ||
269 stream->this[0] == '.');
273 token_stream_consume (TokenStream *stream,
276 gint length = strlen (token);
278 token_stream_prepare (stream);
280 if (stream->stream - stream->this == length &&
281 memcmp (stream->this, token, length) == 0)
283 token_stream_next (stream);
291 token_stream_require (TokenStream *stream,
293 const gchar *purpose,
297 if (!token_stream_consume (stream, token))
299 token_stream_set_error (stream, error, FALSE,
300 "expected `%s'%s", token, purpose);
308 token_stream_assert (TokenStream *stream,
311 gboolean correct_token;
313 correct_token = token_stream_consume (stream, token);
314 g_assert (correct_token);
318 token_stream_get (TokenStream *stream)
322 token_stream_prepare (stream);
324 result = g_strndup (stream->this, stream->stream - stream->this);
330 token_stream_start_ref (TokenStream *stream,
333 token_stream_prepare (stream);
334 ref->start = stream->this - stream->start;
338 token_stream_end_ref (TokenStream *stream,
341 ref->end = stream->stream - stream->start;
345 pattern_copy (gchar **out,
350 while (**in == 'a' || **in == 'm' || **in == 'M')
351 *(*out)++ = *(*in)++;
355 if (**in == '(' || **in == '{')
358 else if (**in == ')' || **in == '}')
361 *(*out)++ = *(*in)++;
367 pattern_coalesce (const gchar *left,
373 /* the length of the output is loosely bound by the sum of the input
374 * lengths, not simply the greater of the two lengths.
376 * (*(iii)) + ((iii)*) ((iii)(iii))
380 out = result = g_malloc (strlen (left) + strlen (right));
382 while (*left && *right)
392 const gchar **one = &left, **the_other = &right;
395 if (**one == '*' && **the_other != ')')
397 pattern_copy (&out, the_other);
401 else if (**one == 'M' && **the_other == 'm')
403 *out++ = *(*the_other)++;
406 else if (**one == 'M' && **the_other != 'm')
411 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
413 *out++ = *(*the_other)++;
417 else if (**one == 'S' && strchr ("sog", **the_other))
419 *out++ = *(*the_other)++;
423 else if (one == &left)
425 one = &right, the_other = &left;
445 typedef struct _AST AST;
446 typedef gchar * (*get_pattern_func) (AST *ast,
448 typedef GVariant * (*get_value_func) (AST *ast,
449 const GVariantType *type,
451 typedef GVariant * (*get_base_value_func) (AST *ast,
452 const GVariantType *type,
454 typedef void (*free_func) (AST *ast);
458 gchar * (* get_pattern) (AST *ast,
460 GVariant * (* get_value) (AST *ast,
461 const GVariantType *type,
463 GVariant * (* get_base_value) (AST *ast,
464 const GVariantType *type,
466 void (* free) (AST *ast);
471 const ASTClass *class;
472 SourceRef source_ref;
476 ast_get_pattern (AST *ast,
479 return ast->class->get_pattern (ast, error);
483 ast_get_value (AST *ast,
484 const GVariantType *type,
487 return ast->class->get_value (ast, type, error);
493 ast->class->free (ast);
497 ast_set_error (AST *ast,
505 va_start (ap, format);
506 parser_set_error_va (error, &ast->source_ref,
507 other_ast ? & other_ast->source_ref : NULL,
513 ast_type_error (AST *ast,
514 const GVariantType *type,
519 typestr = g_variant_type_dup_string (type);
520 ast_set_error (ast, error, NULL,
521 "can not parse as value of type `%s'",
529 ast_resolve (AST *ast,
536 pattern = ast_get_pattern (ast, error);
541 /* choose reasonable defaults
543 * 1) favour non-maybe values where possible
544 * 2) default type for strings is 's'
545 * 3) default type for integers is 'i'
547 for (i = 0; pattern[i]; i++)
551 ast_set_error (ast, error, NULL, "unable to infer type");
567 pattern[j++] = pattern[i];
572 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
579 static AST *parse (TokenStream *stream,
584 ast_array_append (AST ***array,
588 if ((*n_items & (*n_items - 1)) == 0)
589 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
591 (*array)[(*n_items)++] = ast;
595 ast_array_free (AST **array,
600 for (i = 0; i < n_items; i++)
606 ast_array_get_pattern (AST **array,
613 pattern = ast_get_pattern (array[0], error);
618 for (i = 1; i < n_items; i++)
622 tmp = ast_get_pattern (array[i], error);
630 merged = pattern_coalesce (pattern, tmp);
635 /* set coalescence implies pairwise coalescence (i think).
636 * we should therefore be able to trace the failure to a single
647 /* if 'j' reaches 'i' then we failed to find the pair */
650 tmp2 = ast_get_pattern (array[j], NULL);
651 g_assert (tmp2 != NULL);
653 m = pattern_coalesce (tmp, tmp2);
659 /* we found a conflict between 'i' and 'j'.
661 * report the error. note: 'j' is first.
663 ast_set_error (array[j], error, array[i],
664 "unable to find a common type");
688 maybe_get_pattern (AST *ast,
691 Maybe *maybe = (Maybe *) ast;
693 if (maybe->child != NULL)
695 gchar *child_pattern;
698 child_pattern = ast_get_pattern (maybe->child, error);
700 if (child_pattern == NULL)
703 pattern = g_strdup_printf ("m%s", child_pattern);
704 g_free (child_pattern);
709 return g_strdup ("m*");
713 maybe_get_value (AST *ast,
714 const GVariantType *type,
717 Maybe *maybe = (Maybe *) ast;
720 if (!g_variant_type_is_maybe (type))
721 return ast_type_error (ast, type, error);
723 type = g_variant_type_element (type);
727 value = ast_get_value (maybe->child, type, error);
735 return g_variant_new_maybe (type, value);
739 maybe_free (AST *ast)
741 Maybe *maybe = (Maybe *) ast;
743 if (maybe->child != NULL)
744 ast_free (maybe->child);
746 g_slice_free (Maybe, maybe);
750 maybe_parse (TokenStream *stream,
754 static const ASTClass maybe_class = {
756 maybe_get_value, NULL,
762 if (token_stream_consume (stream, "just"))
764 child = parse (stream, app, error);
769 else if (!token_stream_consume (stream, "nothing"))
771 token_stream_set_error (stream, error, TRUE, "unknown keyword");
775 maybe = g_slice_new (Maybe);
776 maybe->ast.class = &maybe_class;
777 maybe->child = child;
779 return (AST *) maybe;
783 maybe_wrapper (AST *ast,
784 const GVariantType *type,
787 const GVariantType *t;
791 for (depth = 0, t = type;
792 g_variant_type_is_maybe (t);
793 depth++, t = g_variant_type_element (t));
795 value = ast->class->get_base_value (ast, t, error);
801 value = g_variant_new_maybe (NULL, value);
815 array_get_pattern (AST *ast,
818 Array *array = (Array *) ast;
822 if (array->n_children == 0)
823 return g_strdup ("Ma*");
825 pattern = ast_array_get_pattern (array->children, array->n_children, error);
830 result = g_strdup_printf ("Ma%s", pattern);
837 array_get_value (AST *ast,
838 const GVariantType *type,
841 Array *array = (Array *) ast;
842 const GVariantType *childtype;
843 GVariantBuilder builder;
846 if (!g_variant_type_is_array (type))
847 return ast_type_error (ast, type, error);
849 g_variant_builder_init (&builder, type);
850 childtype = g_variant_type_element (type);
852 for (i = 0; i < array->n_children; i++)
856 if (!(child = ast_get_value (array->children[i], childtype, error)))
858 g_variant_builder_clear (&builder);
862 g_variant_builder_add_value (&builder, child);
865 return g_variant_builder_end (&builder);
869 array_free (AST *ast)
871 Array *array = (Array *) ast;
873 ast_array_free (array->children, array->n_children);
874 g_slice_free (Array, array);
878 array_parse (TokenStream *stream,
882 static const ASTClass array_class = {
884 maybe_wrapper, array_get_value,
887 gboolean need_comma = FALSE;
890 array = g_slice_new (Array);
891 array->ast.class = &array_class;
892 array->children = NULL;
893 array->n_children = 0;
895 token_stream_assert (stream, "[");
896 while (!token_stream_consume (stream, "]"))
901 !token_stream_require (stream, ",",
902 " or `]' to follow array element",
906 child = parse (stream, app, error);
911 ast_array_append (&array->children, &array->n_children, child);
915 return (AST *) array;
918 ast_array_free (array->children, array->n_children);
919 g_slice_free (Array, array);
933 tuple_get_pattern (AST *ast,
936 Tuple *tuple = (Tuple *) ast;
937 gchar *result = NULL;
941 parts = g_new (gchar *, tuple->n_children + 4);
942 parts[tuple->n_children + 1] = (gchar *) ")";
943 parts[tuple->n_children + 2] = NULL;
944 parts[0] = (gchar *) "M(";
946 for (i = 0; i < tuple->n_children; i++)
947 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
950 if (i == tuple->n_children)
951 result = g_strjoinv ("", parts);
953 /* parts[0] should not be freed */
962 tuple_get_value (AST *ast,
963 const GVariantType *type,
966 Tuple *tuple = (Tuple *) ast;
967 const GVariantType *childtype;
968 GVariantBuilder builder;
971 if (!g_variant_type_is_tuple (type))
972 return ast_type_error (ast, type, error);
974 g_variant_builder_init (&builder, type);
975 childtype = g_variant_type_first (type);
977 for (i = 0; i < tuple->n_children; i++)
981 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
983 g_variant_builder_clear (&builder);
987 g_variant_builder_add_value (&builder, child);
988 childtype = g_variant_type_next (childtype);
991 return g_variant_builder_end (&builder);
995 tuple_free (AST *ast)
997 Tuple *tuple = (Tuple *) ast;
999 ast_array_free (tuple->children, tuple->n_children);
1000 g_slice_free (Tuple, tuple);
1004 tuple_parse (TokenStream *stream,
1008 static const ASTClass tuple_class = {
1010 maybe_wrapper, tuple_get_value,
1013 gboolean need_comma = FALSE;
1014 gboolean first = TRUE;
1017 tuple = g_slice_new (Tuple);
1018 tuple->ast.class = &tuple_class;
1019 tuple->children = NULL;
1020 tuple->n_children = 0;
1022 token_stream_assert (stream, "(");
1023 while (!token_stream_consume (stream, ")"))
1028 !token_stream_require (stream, ",",
1029 " or `)' to follow tuple element",
1033 child = parse (stream, app, error);
1038 ast_array_append (&tuple->children, &tuple->n_children, child);
1040 /* the first time, we absolutely require a comma, so grab it here
1041 * and leave need_comma = FALSE so that the code above doesn't
1042 * require a second comma.
1044 * the second and remaining times, we set need_comma = TRUE.
1048 if (!token_stream_require (stream, ",",
1049 " after first tuple element", error))
1058 return (AST *) tuple;
1061 ast_array_free (tuple->children, tuple->n_children);
1062 g_slice_free (Tuple, tuple);
1075 variant_get_pattern (AST *ast,
1078 return g_strdup ("Mv");
1082 variant_get_value (AST *ast,
1083 const GVariantType *type,
1086 Variant *variant = (Variant *) ast;
1089 g_assert (g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT));
1090 child = ast_resolve (variant->value, error);
1095 return g_variant_new_variant (child);
1099 variant_free (AST *ast)
1101 Variant *variant = (Variant *) ast;
1103 ast_free (variant->value);
1104 g_slice_free (Variant, variant);
1108 variant_parse (TokenStream *stream,
1112 static const ASTClass variant_class = {
1113 variant_get_pattern,
1114 maybe_wrapper, variant_get_value,
1120 token_stream_assert (stream, "<");
1121 value = parse (stream, app, error);
1126 if (!token_stream_require (stream, ">", " to follow variant value", error))
1132 variant = g_slice_new (Variant);
1133 variant->ast.class = &variant_class;
1134 variant->value = value;
1136 return (AST *) variant;
1149 dictionary_get_pattern (AST *ast,
1152 Dictionary *dict = (Dictionary *) ast;
1153 gchar *value_pattern;
1158 if (dict->n_children == 0)
1159 return g_strdup ("Ma{**}");
1161 key_pattern = ast_array_get_pattern (dict->keys,
1162 abs (dict->n_children),
1165 if (key_pattern == NULL)
1168 /* we can not have maybe keys */
1169 if (key_pattern[0] == 'M')
1170 key_char = key_pattern[1];
1172 key_char = key_pattern[0];
1174 g_free (key_pattern);
1177 * plus undetermined number type and undetermined string type.
1179 if (!strchr ("bynqiuxthdsogNS", key_char))
1181 ast_set_error (ast, error, NULL,
1182 "dictionary keys must have basic types");
1186 value_pattern = ast_get_pattern (dict->values[0], error);
1188 if (value_pattern == NULL)
1191 result = g_strdup_printf ("M%s{%c%s}",
1192 dict->n_children > 0 ? "a" : "",
1193 key_char, value_pattern);
1194 g_free (value_pattern);
1200 dictionary_get_value (AST *ast,
1201 const GVariantType *type,
1204 Dictionary *dict = (Dictionary *) ast;
1206 if (dict->n_children == -1)
1208 const GVariantType *subtype;
1209 GVariantBuilder builder;
1212 if (!g_variant_type_is_dict_entry (type))
1213 return ast_type_error (ast, type, error);
1215 g_variant_builder_init (&builder, type);
1217 subtype = g_variant_type_key (type);
1218 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1220 g_variant_builder_clear (&builder);
1223 g_variant_builder_add_value (&builder, subvalue);
1225 subtype = g_variant_type_value (type);
1226 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1228 g_variant_builder_clear (&builder);
1231 g_variant_builder_add_value (&builder, subvalue);
1233 return g_variant_builder_end (&builder);
1237 const GVariantType *entry, *key, *val;
1238 GVariantBuilder builder;
1241 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1242 return ast_type_error (ast, type, error);
1244 entry = g_variant_type_element (type);
1245 key = g_variant_type_key (entry);
1246 val = g_variant_type_value (entry);
1248 g_variant_builder_init (&builder, type);
1250 for (i = 0; i < dict->n_children; i++)
1254 g_variant_builder_open (&builder, entry);
1256 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1258 g_variant_builder_clear (&builder);
1261 g_variant_builder_add_value (&builder, subvalue);
1263 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1265 g_variant_builder_clear (&builder);
1268 g_variant_builder_add_value (&builder, subvalue);
1269 g_variant_builder_close (&builder);
1272 return g_variant_builder_end (&builder);
1277 dictionary_free (AST *ast)
1279 Dictionary *dict = (Dictionary *) ast;
1282 if (dict->n_children > -1)
1283 n_children = dict->n_children;
1287 ast_array_free (dict->keys, n_children);
1288 ast_array_free (dict->values, n_children);
1289 g_slice_free (Dictionary, dict);
1293 dictionary_parse (TokenStream *stream,
1297 static const ASTClass dictionary_class = {
1298 dictionary_get_pattern,
1299 maybe_wrapper, dictionary_get_value,
1302 gint n_keys, n_values;
1307 dict = g_slice_new (Dictionary);
1308 dict->ast.class = &dictionary_class;
1310 dict->values = NULL;
1311 n_keys = n_values = 0;
1313 token_stream_assert (stream, "{");
1315 if (token_stream_consume (stream, "}"))
1317 dict->n_children = 0;
1318 return (AST *) dict;
1321 if ((first = parse (stream, app, error)) == NULL)
1324 ast_array_append (&dict->keys, &n_keys, first);
1326 only_one = token_stream_consume (stream, ",");
1328 !token_stream_require (stream, ":",
1329 " or `,' to follow dictionary entry key",
1333 if ((first = parse (stream, app, error)) == NULL)
1336 ast_array_append (&dict->values, &n_values, first);
1340 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1344 g_assert (n_keys == 1 && n_values == 1);
1345 dict->n_children = -1;
1347 return (AST *) dict;
1350 while (!token_stream_consume (stream, "}"))
1354 if (!token_stream_require (stream, ",",
1355 " or `}' to follow dictionary entry", error))
1358 child = parse (stream, app, error);
1363 ast_array_append (&dict->keys, &n_keys, child);
1365 if (!token_stream_require (stream, ":",
1366 " to follow dictionary entry key", error))
1369 child = parse (stream, app, error);
1374 ast_array_append (&dict->values, &n_values, child);
1377 g_assert (n_keys == n_values);
1378 dict->n_children = n_keys;
1380 return (AST *) dict;
1383 ast_array_free (dict->keys, n_keys);
1384 ast_array_free (dict->values, n_values);
1385 g_slice_free (Dictionary, dict);
1397 string_get_pattern (AST *ast,
1400 return g_strdup ("MS");
1404 string_get_value (AST *ast,
1405 const GVariantType *type,
1408 String *string = (String *) ast;
1410 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1411 return g_variant_new_string (string->string);
1413 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1415 if (!g_variant_is_object_path (string->string))
1417 ast_set_error (ast, error, NULL, "not a valid object path");
1421 return g_variant_new_object_path (string->string);
1424 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1426 if (!g_variant_is_signature (string->string))
1428 ast_set_error (ast, error, NULL, "not a valid signature");
1432 return g_variant_new_signature (string->string);
1436 return ast_type_error (ast, type, error);
1440 string_free (AST *ast)
1442 String *string = (String *) ast;
1444 g_free (string->string);
1445 g_slice_free (String, string);
1449 unicode_unescape (const gchar *src,
1463 g_assert (length < sizeof (buffer));
1464 strncpy (buffer, src + *src_ofs, length);
1465 buffer[length] = '\0';
1467 value = g_ascii_strtoull (buffer, &end, 0x10);
1469 if (value == 0 || end != buffer + length)
1471 parser_set_error (error, ref, NULL,
1472 "invalid %d-character unicode escape", length);
1476 g_assert (value <= G_MAXUINT32);
1478 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1485 string_parse (TokenStream *stream,
1489 static const ASTClass string_class = {
1491 maybe_wrapper, string_get_value,
1502 token_stream_start_ref (stream, &ref);
1503 token = token_stream_get (stream);
1504 token_stream_end_ref (stream, &ref);
1505 length = strlen (token);
1508 str = g_malloc (length);
1509 g_assert (quote == '"' || quote == '\'');
1512 while (token[i] != quote)
1516 parser_set_error (error, &ref, NULL,
1517 "unterminated string constant");
1526 parser_set_error (error, &ref, NULL,
1527 "unterminated string constant");
1533 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1542 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1550 case 'a': str[j++] = '\a'; i++; continue;
1551 case 'b': str[j++] = '\b'; i++; continue;
1552 case 'f': str[j++] = '\f'; i++; continue;
1553 case 'n': str[j++] = '\n'; i++; continue;
1554 case 'r': str[j++] = '\r'; i++; continue;
1555 case 't': str[j++] = '\t'; i++; continue;
1556 case 'v': str[j++] = '\v'; i++; continue;
1557 case '\n': i++; continue;
1561 str[j++] = token[i++];
1566 string = g_slice_new (String);
1567 string->ast.class = &string_class;
1568 string->string = str;
1570 token_stream_next (stream);
1572 return (AST *) string;
1582 bytestring_get_pattern (AST *ast,
1585 return g_strdup ("May");
1589 bytestring_get_value (AST *ast,
1590 const GVariantType *type,
1593 ByteString *string = (ByteString *) ast;
1595 g_assert (g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING));
1597 return g_variant_new_bytestring (string->string);
1601 bytestring_free (AST *ast)
1603 ByteString *string = (ByteString *) ast;
1605 g_free (string->string);
1606 g_slice_free (ByteString, string);
1610 bytestring_parse (TokenStream *stream,
1614 static const ASTClass bytestring_class = {
1615 bytestring_get_pattern,
1616 maybe_wrapper, bytestring_get_value,
1627 token_stream_start_ref (stream, &ref);
1628 token = token_stream_get (stream);
1629 token_stream_end_ref (stream, &ref);
1630 g_assert (token[0] == 'b');
1631 length = strlen (token);
1634 str = g_malloc (length);
1635 g_assert (quote == '"' || quote == '\'');
1638 while (token[i] != quote)
1642 parser_set_error (error, &ref, NULL,
1643 "unterminated string constant");
1651 parser_set_error (error, &ref, NULL,
1652 "unterminated string constant");
1656 case '0': case '1': case '2': case '3':
1657 case '4': case '5': case '6': case '7':
1659 /* up to 3 characters */
1660 guchar val = token[i++] - '0';
1662 if ('0' <= token[i] && token[i] < '8')
1663 val = (val << 3) | (token[i++] - '0');
1665 if ('0' <= token[i] && token[i] < '8')
1666 val = (val << 3) | (token[i++] - '0');
1672 case 'a': str[j++] = '\a'; i++; continue;
1673 case 'b': str[j++] = '\b'; i++; continue;
1674 case 'f': str[j++] = '\f'; i++; continue;
1675 case 'n': str[j++] = '\n'; i++; continue;
1676 case 'r': str[j++] = '\r'; i++; continue;
1677 case 't': str[j++] = '\t'; i++; continue;
1678 case 'v': str[j++] = '\v'; i++; continue;
1679 case '\n': i++; continue;
1683 str[j++] = token[i++];
1688 string = g_slice_new (ByteString);
1689 string->ast.class = &bytestring_class;
1690 string->string = str;
1692 token_stream_next (stream);
1694 return (AST *) string;
1705 number_get_pattern (AST *ast,
1708 Number *number = (Number *) ast;
1710 if (strchr (number->token, '.') ||
1711 (!g_str_has_prefix (number->token, "0x") &&
1712 strchr (number->token, 'e')))
1713 return g_strdup ("Md");
1715 return g_strdup ("MN");
1719 number_overflow (AST *ast,
1720 const GVariantType *type,
1723 ast_set_error (ast, error, NULL, "number out of range for type `%c'",
1724 g_variant_type_peek_string (type)[0]);
1729 number_get_value (AST *ast,
1730 const GVariantType *type,
1733 Number *number = (Number *) ast;
1741 token = number->token;
1743 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1748 dbl_val = g_ascii_strtod (token, &end);
1749 if (dbl_val != 0.0 && errno == ERANGE)
1751 ast_set_error (ast, error, NULL, "number too big for any type");
1755 /* silence uninitialised warnings... */
1762 negative = token[0] == '-';
1763 if (token[0] == '-')
1767 abs_val = g_ascii_strtoull (token, &end, 0);
1768 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1770 ast_set_error (ast, error, NULL, "integer too big for any type");
1777 /* silence uninitialised warning... */
1785 ref = ast->source_ref;
1786 ref.start += end - number->token;
1787 ref.end = ref.start + 1;
1789 parser_set_error (error, &ref, NULL,
1790 "invalid character in number");
1795 return g_variant_new_double (dbl_val);
1797 switch (*g_variant_type_peek_string (type))
1800 if (negative || abs_val > G_MAXUINT8)
1801 return number_overflow (ast, type, error);
1802 return g_variant_new_byte (abs_val);
1805 if (abs_val - negative > G_MAXINT16)
1806 return number_overflow (ast, type, error);
1807 return g_variant_new_int16 (negative ? -abs_val : abs_val);
1810 if (negative || abs_val > G_MAXUINT16)
1811 return number_overflow (ast, type, error);
1812 return g_variant_new_uint16 (negative ? -abs_val : abs_val);
1815 if (abs_val - negative > G_MAXINT32)
1816 return number_overflow (ast, type, error);
1817 return g_variant_new_int32 (negative ? -abs_val : abs_val);
1820 if (negative || abs_val > G_MAXUINT32)
1821 return number_overflow (ast, type, error);
1822 return g_variant_new_uint32 (negative ? -abs_val : abs_val);
1825 if (abs_val - negative > G_MAXINT64)
1826 return number_overflow (ast, type, error);
1827 return g_variant_new_int64 (negative ? -abs_val : abs_val);
1831 return number_overflow (ast, type, error);
1832 return g_variant_new_uint64 (negative ? -abs_val : abs_val);
1835 if (abs_val - negative > G_MAXINT32)
1836 return number_overflow (ast, type, error);
1837 return g_variant_new_handle (negative ? -abs_val : abs_val);
1840 return ast_type_error (ast, type, error);
1845 number_free (AST *ast)
1847 Number *number = (Number *) ast;
1849 g_free (number->token);
1850 g_slice_free (Number, number);
1854 number_parse (TokenStream *stream,
1858 static const ASTClass number_class = {
1860 maybe_wrapper, number_get_value,
1865 number = g_slice_new (Number);
1866 number->ast.class = &number_class;
1867 number->token = token_stream_get (stream);
1868 token_stream_next (stream);
1870 return (AST *) number;
1880 boolean_get_pattern (AST *ast,
1883 return g_strdup ("Mb");
1887 boolean_get_value (AST *ast,
1888 const GVariantType *type,
1891 Boolean *boolean = (Boolean *) ast;
1893 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
1894 return ast_type_error (ast, type, error);
1896 return g_variant_new_boolean (boolean->value);
1900 boolean_free (AST *ast)
1902 Boolean *boolean = (Boolean *) ast;
1904 g_slice_free (Boolean, boolean);
1908 boolean_new (gboolean value)
1910 static const ASTClass boolean_class = {
1911 boolean_get_pattern,
1912 maybe_wrapper, boolean_get_value,
1917 boolean = g_slice_new (Boolean);
1918 boolean->ast.class = &boolean_class;
1919 boolean->value = value;
1921 return (AST *) boolean;
1932 positional_get_pattern (AST *ast,
1935 Positional *positional = (Positional *) ast;
1937 return g_strdup (g_variant_get_type_string (positional->value));
1941 positional_get_value (AST *ast,
1942 const GVariantType *type,
1945 Positional *positional = (Positional *) ast;
1948 g_assert (positional->value != NULL);
1950 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
1951 return ast_type_error (ast, type, error);
1953 /* NOTE: if _get is called more than once then
1954 * things get messed up with respect to floating refs.
1956 * fortunately, this function should only ever get called once.
1958 g_assert (positional->value != NULL);
1959 value = positional->value;
1960 positional->value = NULL;
1966 positional_free (AST *ast)
1968 Positional *positional = (Positional *) ast;
1970 /* if positional->value is set, just leave it.
1971 * memory management doesn't matter in case of programmer error.
1973 g_slice_free (Positional, positional);
1977 positional_parse (TokenStream *stream,
1981 static const ASTClass positional_class = {
1982 positional_get_pattern,
1983 positional_get_value, NULL,
1986 Positional *positional;
1987 const gchar *endptr;
1990 token = token_stream_get (stream);
1991 g_assert (token[0] == '%');
1993 positional = g_slice_new (Positional);
1994 positional->ast.class = &positional_class;
1995 positional->value = g_variant_new_va (token + 1, &endptr, app);
1997 if (*endptr || positional->value == NULL)
1999 token_stream_set_error (stream, error, TRUE,
2000 "invalid GVariant format string");
2001 /* memory management doesn't matter in case of programmer error. */
2005 token_stream_next (stream);
2008 return (AST *) positional;
2020 typedecl_get_pattern (AST *ast,
2023 TypeDecl *decl = (TypeDecl *) ast;
2025 return g_variant_type_dup_string (decl->type);
2029 typedecl_get_value (AST *ast,
2030 const GVariantType *type,
2033 TypeDecl *decl = (TypeDecl *) ast;
2035 return ast_get_value (decl->child, type, error);
2039 typedecl_free (AST *ast)
2041 TypeDecl *decl = (TypeDecl *) ast;
2043 ast_free (decl->child);
2044 g_variant_type_free (decl->type);
2045 g_slice_free (TypeDecl, decl);
2049 typedecl_parse (TokenStream *stream,
2053 static const ASTClass typedecl_class = {
2054 typedecl_get_pattern,
2055 typedecl_get_value, NULL,
2062 if (token_stream_peek (stream, '@'))
2066 token = token_stream_get (stream);
2068 if (!g_variant_type_string_is_valid (token + 1))
2070 token_stream_set_error (stream, error, TRUE,
2071 "invalid type declaration");
2077 type = g_variant_type_new (token + 1);
2079 if (!g_variant_type_is_definite (type))
2081 token_stream_set_error (stream, error, TRUE,
2082 "type declarations must be definite");
2083 g_variant_type_free (type);
2089 token_stream_next (stream);
2094 if (token_stream_consume (stream, "boolean"))
2095 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2097 else if (token_stream_consume (stream, "byte"))
2098 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2100 else if (token_stream_consume (stream, "int16"))
2101 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2103 else if (token_stream_consume (stream, "uint16"))
2104 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2106 else if (token_stream_consume (stream, "int32"))
2107 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2109 else if (token_stream_consume (stream, "handle"))
2110 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2112 else if (token_stream_consume (stream, "uint32"))
2113 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2115 else if (token_stream_consume (stream, "int64"))
2116 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2118 else if (token_stream_consume (stream, "uint64"))
2119 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2121 else if (token_stream_consume (stream, "double"))
2122 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2124 else if (token_stream_consume (stream, "string"))
2125 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2127 else if (token_stream_consume (stream, "objectpath"))
2128 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2130 else if (token_stream_consume (stream, "signature"))
2131 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2135 token_stream_set_error (stream, error, TRUE, "unknown keyword");
2140 if ((child = parse (stream, app, error)) == NULL)
2142 g_variant_type_free (type);
2146 decl = g_slice_new (TypeDecl);
2147 decl->ast.class = &typedecl_class;
2149 decl->child = child;
2151 return (AST *) decl;
2155 parse (TokenStream *stream,
2159 SourceRef source_ref;
2162 token_stream_prepare (stream);
2163 token_stream_start_ref (stream, &source_ref);
2165 if (token_stream_peek (stream, '['))
2166 result = array_parse (stream, app, error);
2168 else if (token_stream_peek (stream, '('))
2169 result = tuple_parse (stream, app, error);
2171 else if (token_stream_peek (stream, '<'))
2172 result = variant_parse (stream, app, error);
2174 else if (token_stream_peek (stream, '{'))
2175 result = dictionary_parse (stream, app, error);
2177 else if (app && token_stream_peek (stream, '%'))
2178 result = positional_parse (stream, app, error);
2180 else if (token_stream_consume (stream, "true"))
2181 result = boolean_new (TRUE);
2183 else if (token_stream_consume (stream, "false"))
2184 result = boolean_new (FALSE);
2186 else if (token_stream_peek (stream, 'n') ||
2187 token_stream_peek (stream, 'j'))
2188 result = maybe_parse (stream, app, error);
2190 else if (token_stream_peek (stream, '@') ||
2191 token_stream_is_keyword (stream))
2192 result = typedecl_parse (stream, app, error);
2194 else if (token_stream_is_numeric (stream))
2195 result = number_parse (stream, app, error);
2197 else if (token_stream_peek (stream, '\'') ||
2198 token_stream_peek (stream, '"'))
2199 result = string_parse (stream, app, error);
2201 else if (token_stream_peek2 (stream, 'b', '\'') ||
2202 token_stream_peek2 (stream, 'b', '"'))
2203 result = bytestring_parse (stream, app, error);
2207 token_stream_set_error (stream, error, FALSE, "expected value");
2213 token_stream_end_ref (stream, &source_ref);
2214 result->source_ref = source_ref;
2222 * @type: a #GVariantType, or %NULL
2223 * @text: a string containing a GVariant in text form
2224 * @limit: a pointer to the end of @text, or %NULL
2225 * @endptr: a location to store the end pointer, or %NULL
2226 * @error: a pointer to a %NULL #GError pointer, or %NULL
2227 * @Returns: a reference to a #GVariant, or %NULL
2229 * Parses a #GVariant from a text representation.
2231 * A single #GVariant is parsed from the content of @text.
2233 * The memory at @limit will never be accessed and the parser behaves as
2234 * if the character at @limit is the nul terminator. This has the
2235 * effect of bounding @text.
2237 * If @endptr is non-%NULL then @text is permitted to contain data
2238 * following the value that this function parses and @endptr will be
2239 * updated to point to the first character past the end of the text
2240 * parsed by this function. If @endptr is %NULL and there is extra data
2241 * then an error is returned.
2243 * If @type is non-%NULL then the value will be parsed to have that
2244 * type. This may result in additional parse errors (in the case that
2245 * the parsed value doesn't fit the type) but may also result in fewer
2246 * errors (in the case that the type would have been ambiguous, such as
2247 * with empty arrays).
2249 * In the event that the parsing is successful, the resulting #GVariant
2252 * In case of any error, %NULL will be returned. If @error is non-%NULL
2253 * then it will be set to reflect the error that occured.
2255 * Officially, the language understood by the parser is "any string
2256 * produced by g_variant_print()".
2259 g_variant_parse (const GVariantType *type,
2262 const gchar **endptr,
2265 TokenStream stream = { 0, };
2266 GVariant *result = NULL;
2269 g_return_val_if_fail (text != NULL, NULL);
2270 g_return_val_if_fail (text == limit || text != NULL, NULL);
2272 stream.start = text;
2273 stream.stream = text;
2276 if ((ast = parse (&stream, NULL, error)))
2279 result = ast_resolve (ast, error);
2281 result = ast_get_value (ast, type, error);
2285 g_variant_ref_sink (result);
2289 while (stream.stream != limit &&
2290 g_ascii_isspace (*stream.stream))
2293 if (stream.stream != limit && *stream.stream != '\0')
2295 SourceRef ref = { stream.stream - text,
2296 stream.stream - text };
2298 parser_set_error (error, &ref, NULL,
2299 "expected end of input");
2300 g_variant_unref (result);
2306 *endptr = stream.stream;
2316 * g_variant_new_parsed_va:
2317 * @format: a text format #GVariant
2318 * @app: a pointer to a #va_list
2319 * @returns: a new, usually floating, #GVariant
2321 * Parses @format and returns the result.
2323 * This is the version of g_variant_new_parsed() intended to be used
2326 * The return value will be floating if it was a newly created GVariant
2327 * instance. In the case that @format simply specified the collection
2328 * of a #GVariant pointer (eg: @format was "%*") then the collected
2329 * #GVariant pointer will be returned unmodified, without adding any
2330 * additional references.
2332 * In order to behave correctly in all cases it is necessary for the
2333 * calling function to g_variant_ref_sink() the return result before
2334 * returning control to the user that originally provided the pointer.
2335 * At this point, the caller will have their own full reference to the
2336 * result. This can also be done by adding the result to a container,
2337 * or by passing it to another g_variant_new() call.
2340 g_variant_new_parsed_va (const gchar *format,
2343 TokenStream stream = { 0, };
2344 GVariant *result = NULL;
2345 GError *error = NULL;
2348 g_return_val_if_fail (format != NULL, NULL);
2349 g_return_val_if_fail (app != NULL, NULL);
2351 stream.start = format;
2352 stream.stream = format;
2355 if ((ast = parse (&stream, app, &error)))
2357 result = ast_resolve (ast, &error);
2362 g_error ("g_variant_new_parsed: %s", error->message);
2365 g_error ("g_variant_new_parsed: trailing text after value");
2371 * g_variant_new_parsed:
2372 * @format: a text format #GVariant
2373 * @...: arguments as per @format
2374 * @returns: a new floating #GVariant instance
2376 * Parses @format and returns the result.
2378 * @format must be a text format #GVariant with one extention: at any
2379 * point that a value may appear in the text, a '%' character followed
2380 * by a GVariant format string (as per g_variant_new()) may appear. In
2381 * that case, the same arguments are collected from the argument list as
2382 * g_variant_new() would have collected.
2384 * Consider this simple example:
2386 * <informalexample><programlisting>
2387 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2388 * </programlisting></informalexample>
2390 * In the example, the variable argument parameters are collected and
2391 * filled in as if they were part of the original string to produce the
2392 * result of <code>[('one', 1), ('two', 2), ('three', 3)]</code>.
2394 * This function is intended only to be used with @format as a string
2395 * literal. Any parse error is fatal to the calling process. If you
2396 * want to parse data from untrusted sources, use g_variant_parse().
2398 * You may not use this function to return, unmodified, a single
2399 * #GVariant pointer from the argument list. ie: @format may not solely
2400 * be anything along the lines of "%*", "%?", "%r", or anything starting
2404 g_variant_new_parsed (const gchar *format,
2410 va_start (ap, format);
2411 result = g_variant_new_parsed_va (format, &ap);
2418 * g_variant_builder_add_parsed:
2419 * @builder: a #GVariantBuilder
2420 * @format: a text format #GVariant
2421 * @...: arguments as per @format
2423 * Adds to a #GVariantBuilder.
2425 * This call is a convenience wrapper that is exactly equivalent to
2426 * calling g_variant_new_parsed() followed by
2427 * g_variant_builder_add_value().
2429 * This function might be used as follows:
2433 * make_pointless_dictionary (void)
2435 * GVariantBuilder *builder;
2438 * builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
2439 * g_variant_builder_add_parsed (builder, "{'width', <%i>}", 600);
2440 * g_variant_builder_add_parsed (builder, "{'title', <%s>}", "foo");
2441 * g_variant_builder_add_parsed (builder, "{'transparency', <0.5>}");
2442 * return g_variant_builder_end (builder);
2449 g_variant_builder_add_parsed (GVariantBuilder *builder,
2450 const gchar *format,
2455 va_start (ap, format);
2456 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));