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.1 of the License, 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, see <http://www.gnu.org/licenses/>.
17 * Author: Ryan Lortie <desrt@desrt.ca>
29 #include "gstrfuncs.h"
30 #include "gtestutils.h"
32 #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.
72 G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
75 * g_variant_parser_get_error_quark:
77 * Same as g_variant_error_quark().
79 * Deprecated: Use g_variant_parse_error_quark() instead.
82 g_variant_parser_get_error_quark (void)
84 return g_variant_parse_error_quark ();
94 parser_set_error_va (GError **error,
101 GString *msg = g_string_new (NULL);
103 if (location->start == location->end)
104 g_string_append_printf (msg, "%d", location->start);
106 g_string_append_printf (msg, "%d-%d", location->start, location->end);
110 g_assert (other->start != other->end);
111 g_string_append_printf (msg, ",%d-%d", other->start, other->end);
113 g_string_append_c (msg, ':');
115 g_string_append_vprintf (msg, format, ap);
116 g_set_error_literal (error, G_VARIANT_PARSE_ERROR, code, msg->str);
117 g_string_free (msg, TRUE);
122 parser_set_error (GError **error,
131 va_start (ap, format);
132 parser_set_error_va (error, location, other, code, format, ap);
148 token_stream_set_error (TokenStream *stream,
158 ref.start = stream->this - stream->start;
161 ref.end = stream->stream - stream->start;
165 va_start (ap, format);
166 parser_set_error_va (error, &ref, NULL, code, format, ap);
171 token_stream_prepare (TokenStream *stream)
176 if (stream->this != NULL)
179 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
182 if (stream->stream == stream->end || *stream->stream == '\0')
184 stream->this = stream->stream;
188 switch (stream->stream[0])
190 case '-': case '+': case '.': case '0': case '1': case '2':
191 case '3': case '4': case '5': case '6': case '7': case '8':
193 for (end = stream->stream; end != stream->end; end++)
194 if (!g_ascii_isalnum (*end) &&
195 *end != '-' && *end != '+' && *end != '.')
200 if (stream->stream + 1 != stream->end &&
201 (stream->stream[1] == '\'' || stream->stream[1] == '"'))
203 for (end = stream->stream + 2; end != stream->end; end++)
204 if (*end == stream->stream[1] || *end == '\0' ||
205 (*end == '\\' && (++end == stream->end || *end == '\0')))
208 if (end != stream->end && *end)
218 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
219 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
220 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
221 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
223 for (end = stream->stream; end != stream->end; end++)
224 if (!g_ascii_isalnum (*end))
229 for (end = stream->stream + 1; end != stream->end; end++)
230 if (*end == stream->stream[0] || *end == '\0' ||
231 (*end == '\\' && (++end == stream->end || *end == '\0')))
234 if (end != stream->end && *end)
239 /* stop at the first space, comma, colon or unmatched bracket.
240 * deals nicely with cases like (%i, %i) or {%i: %i}.
241 * Also: ] and > are never in format strings.
243 for (end = stream->stream + 1;
244 end != stream->end && *end != '\0' && *end != ',' &&
245 *end != ':' && *end != '>' && *end != ']' && !g_ascii_isspace (*end);
248 if (*end == '(' || *end == '{')
251 else if ((*end == ')' || *end == '}') && !brackets--)
257 end = stream->stream + 1;
261 stream->this = stream->stream;
262 stream->stream = end;
264 /* We must have at least one byte in a token. */
265 g_assert (stream->stream - stream->this >= 1);
271 token_stream_next (TokenStream *stream)
277 token_stream_peek (TokenStream *stream,
280 if (!token_stream_prepare (stream))
283 return stream->stream - stream->this >= 1 &&
284 stream->this[0] == first_char;
288 token_stream_peek2 (TokenStream *stream,
292 if (!token_stream_prepare (stream))
295 return stream->stream - stream->this >= 2 &&
296 stream->this[0] == first_char &&
297 stream->this[1] == second_char;
301 token_stream_is_keyword (TokenStream *stream)
303 if (!token_stream_prepare (stream))
306 return stream->stream - stream->this >= 2 &&
307 g_ascii_isalpha (stream->this[0]) &&
308 g_ascii_isalpha (stream->this[1]);
312 token_stream_is_numeric (TokenStream *stream)
314 if (!token_stream_prepare (stream))
317 return (stream->stream - stream->this >= 1 &&
318 (g_ascii_isdigit (stream->this[0]) ||
319 stream->this[0] == '-' ||
320 stream->this[0] == '+' ||
321 stream->this[0] == '.'));
325 token_stream_peek_string (TokenStream *stream,
328 gint length = strlen (token);
330 return token_stream_prepare (stream) &&
331 stream->stream - stream->this == length &&
332 memcmp (stream->this, token, length) == 0;
336 token_stream_consume (TokenStream *stream,
339 if (!token_stream_peek_string (stream, token))
342 token_stream_next (stream);
347 token_stream_require (TokenStream *stream,
349 const gchar *purpose,
353 if (!token_stream_consume (stream, token))
355 token_stream_set_error (stream, error, FALSE,
356 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
357 "expected '%s'%s", token, purpose);
365 token_stream_assert (TokenStream *stream,
368 gboolean correct_token;
370 correct_token = token_stream_consume (stream, token);
371 g_assert (correct_token);
375 token_stream_get (TokenStream *stream)
379 if (!token_stream_prepare (stream))
382 result = g_strndup (stream->this, stream->stream - stream->this);
388 token_stream_start_ref (TokenStream *stream,
391 token_stream_prepare (stream);
392 ref->start = stream->this - stream->start;
396 token_stream_end_ref (TokenStream *stream,
399 ref->end = stream->stream - stream->start;
403 pattern_copy (gchar **out,
408 while (**in == 'a' || **in == 'm' || **in == 'M')
409 *(*out)++ = *(*in)++;
413 if (**in == '(' || **in == '{')
416 else if (**in == ')' || **in == '}')
419 *(*out)++ = *(*in)++;
425 pattern_coalesce (const gchar *left,
431 /* the length of the output is loosely bound by the sum of the input
432 * lengths, not simply the greater of the two lengths.
434 * (*(iii)) + ((iii)*) ((iii)(iii))
438 out = result = g_malloc (strlen (left) + strlen (right));
440 while (*left && *right)
450 const gchar **one = &left, **the_other = &right;
453 if (**one == '*' && **the_other != ')')
455 pattern_copy (&out, the_other);
459 else if (**one == 'M' && **the_other == 'm')
461 *out++ = *(*the_other)++;
464 else if (**one == 'M' && **the_other != 'm')
469 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
471 *out++ = *(*the_other)++;
475 else if (**one == 'S' && strchr ("sog", **the_other))
477 *out++ = *(*the_other)++;
481 else if (one == &left)
483 one = &right, the_other = &left;
503 typedef struct _AST AST;
504 typedef gchar * (*get_pattern_func) (AST *ast,
506 typedef GVariant * (*get_value_func) (AST *ast,
507 const GVariantType *type,
509 typedef GVariant * (*get_base_value_func) (AST *ast,
510 const GVariantType *type,
512 typedef void (*free_func) (AST *ast);
516 gchar * (* get_pattern) (AST *ast,
518 GVariant * (* get_value) (AST *ast,
519 const GVariantType *type,
521 GVariant * (* get_base_value) (AST *ast,
522 const GVariantType *type,
524 void (* free) (AST *ast);
529 const ASTClass *class;
530 SourceRef source_ref;
534 ast_get_pattern (AST *ast,
537 return ast->class->get_pattern (ast, error);
541 ast_get_value (AST *ast,
542 const GVariantType *type,
545 return ast->class->get_value (ast, type, error);
551 ast->class->free (ast);
556 ast_set_error (AST *ast,
565 va_start (ap, format);
566 parser_set_error_va (error, &ast->source_ref,
567 other_ast ? & other_ast->source_ref : NULL,
574 ast_type_error (AST *ast,
575 const GVariantType *type,
580 typestr = g_variant_type_dup_string (type);
581 ast_set_error (ast, error, NULL,
582 G_VARIANT_PARSE_ERROR_TYPE_ERROR,
583 "can not parse as value of type '%s'",
591 ast_resolve (AST *ast,
598 pattern = ast_get_pattern (ast, error);
603 /* choose reasonable defaults
605 * 1) favour non-maybe values where possible
606 * 2) default type for strings is 's'
607 * 3) default type for integers is 'i'
609 for (i = 0; pattern[i]; i++)
613 ast_set_error (ast, error, NULL,
614 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
615 "unable to infer type");
631 pattern[j++] = pattern[i];
636 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
643 static AST *parse (TokenStream *stream,
648 ast_array_append (AST ***array,
652 if ((*n_items & (*n_items - 1)) == 0)
653 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
655 (*array)[(*n_items)++] = ast;
659 ast_array_free (AST **array,
664 for (i = 0; i < n_items; i++)
670 ast_array_get_pattern (AST **array,
677 pattern = ast_get_pattern (array[0], error);
682 for (i = 1; i < n_items; i++)
686 tmp = ast_get_pattern (array[i], error);
694 merged = pattern_coalesce (pattern, tmp);
699 /* set coalescence implies pairwise coalescence (i think).
700 * we should therefore be able to trace the failure to a single
711 /* if 'j' reaches 'i' then we failed to find the pair */
714 tmp2 = ast_get_pattern (array[j], NULL);
715 g_assert (tmp2 != NULL);
717 m = pattern_coalesce (tmp, tmp2);
723 /* we found a conflict between 'i' and 'j'.
725 * report the error. note: 'j' is first.
727 ast_set_error (array[j], error, array[i],
728 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
729 "unable to find a common type");
753 maybe_get_pattern (AST *ast,
756 Maybe *maybe = (Maybe *) ast;
758 if (maybe->child != NULL)
760 gchar *child_pattern;
763 child_pattern = ast_get_pattern (maybe->child, error);
765 if (child_pattern == NULL)
768 pattern = g_strdup_printf ("m%s", child_pattern);
769 g_free (child_pattern);
774 return g_strdup ("m*");
778 maybe_get_value (AST *ast,
779 const GVariantType *type,
782 Maybe *maybe = (Maybe *) ast;
785 if (!g_variant_type_is_maybe (type))
786 return ast_type_error (ast, type, error);
788 type = g_variant_type_element (type);
792 value = ast_get_value (maybe->child, type, error);
800 return g_variant_new_maybe (type, value);
804 maybe_free (AST *ast)
806 Maybe *maybe = (Maybe *) ast;
808 if (maybe->child != NULL)
809 ast_free (maybe->child);
811 g_slice_free (Maybe, maybe);
815 maybe_parse (TokenStream *stream,
819 static const ASTClass maybe_class = {
821 maybe_get_value, NULL,
827 if (token_stream_consume (stream, "just"))
829 child = parse (stream, app, error);
834 else if (!token_stream_consume (stream, "nothing"))
836 token_stream_set_error (stream, error, TRUE,
837 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
842 maybe = g_slice_new (Maybe);
843 maybe->ast.class = &maybe_class;
844 maybe->child = child;
846 return (AST *) maybe;
850 maybe_wrapper (AST *ast,
851 const GVariantType *type,
854 const GVariantType *t;
858 for (depth = 0, t = type;
859 g_variant_type_is_maybe (t);
860 depth++, t = g_variant_type_element (t));
862 value = ast->class->get_base_value (ast, t, error);
868 value = g_variant_new_maybe (NULL, value);
882 array_get_pattern (AST *ast,
885 Array *array = (Array *) ast;
889 if (array->n_children == 0)
890 return g_strdup ("Ma*");
892 pattern = ast_array_get_pattern (array->children, array->n_children, error);
897 result = g_strdup_printf ("Ma%s", pattern);
904 array_get_value (AST *ast,
905 const GVariantType *type,
908 Array *array = (Array *) ast;
909 const GVariantType *childtype;
910 GVariantBuilder builder;
913 if (!g_variant_type_is_array (type))
914 return ast_type_error (ast, type, error);
916 g_variant_builder_init (&builder, type);
917 childtype = g_variant_type_element (type);
919 for (i = 0; i < array->n_children; i++)
923 if (!(child = ast_get_value (array->children[i], childtype, error)))
925 g_variant_builder_clear (&builder);
929 g_variant_builder_add_value (&builder, child);
932 return g_variant_builder_end (&builder);
936 array_free (AST *ast)
938 Array *array = (Array *) ast;
940 ast_array_free (array->children, array->n_children);
941 g_slice_free (Array, array);
945 array_parse (TokenStream *stream,
949 static const ASTClass array_class = {
951 maybe_wrapper, array_get_value,
954 gboolean need_comma = FALSE;
957 array = g_slice_new (Array);
958 array->ast.class = &array_class;
959 array->children = NULL;
960 array->n_children = 0;
962 token_stream_assert (stream, "[");
963 while (!token_stream_consume (stream, "]"))
968 !token_stream_require (stream, ",",
969 " or ']' to follow array element",
973 child = parse (stream, app, error);
978 ast_array_append (&array->children, &array->n_children, child);
982 return (AST *) array;
985 ast_array_free (array->children, array->n_children);
986 g_slice_free (Array, array);
1000 tuple_get_pattern (AST *ast,
1003 Tuple *tuple = (Tuple *) ast;
1004 gchar *result = NULL;
1008 parts = g_new (gchar *, tuple->n_children + 4);
1009 parts[tuple->n_children + 1] = (gchar *) ")";
1010 parts[tuple->n_children + 2] = NULL;
1011 parts[0] = (gchar *) "M(";
1013 for (i = 0; i < tuple->n_children; i++)
1014 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
1017 if (i == tuple->n_children)
1018 result = g_strjoinv ("", parts);
1020 /* parts[0] should not be freed */
1022 g_free (parts[i--]);
1029 tuple_get_value (AST *ast,
1030 const GVariantType *type,
1033 Tuple *tuple = (Tuple *) ast;
1034 const GVariantType *childtype;
1035 GVariantBuilder builder;
1038 if (!g_variant_type_is_tuple (type))
1039 return ast_type_error (ast, type, error);
1041 g_variant_builder_init (&builder, type);
1042 childtype = g_variant_type_first (type);
1044 for (i = 0; i < tuple->n_children; i++)
1048 if (childtype == NULL)
1050 g_variant_builder_clear (&builder);
1051 return ast_type_error (ast, type, error);
1054 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1056 g_variant_builder_clear (&builder);
1060 g_variant_builder_add_value (&builder, child);
1061 childtype = g_variant_type_next (childtype);
1064 if (childtype != NULL)
1066 g_variant_builder_clear (&builder);
1067 return ast_type_error (ast, type, error);
1070 return g_variant_builder_end (&builder);
1074 tuple_free (AST *ast)
1076 Tuple *tuple = (Tuple *) ast;
1078 ast_array_free (tuple->children, tuple->n_children);
1079 g_slice_free (Tuple, tuple);
1083 tuple_parse (TokenStream *stream,
1087 static const ASTClass tuple_class = {
1089 maybe_wrapper, tuple_get_value,
1092 gboolean need_comma = FALSE;
1093 gboolean first = TRUE;
1096 tuple = g_slice_new (Tuple);
1097 tuple->ast.class = &tuple_class;
1098 tuple->children = NULL;
1099 tuple->n_children = 0;
1101 token_stream_assert (stream, "(");
1102 while (!token_stream_consume (stream, ")"))
1107 !token_stream_require (stream, ",",
1108 " or ')' to follow tuple element",
1112 child = parse (stream, app, error);
1117 ast_array_append (&tuple->children, &tuple->n_children, child);
1119 /* the first time, we absolutely require a comma, so grab it here
1120 * and leave need_comma = FALSE so that the code above doesn't
1121 * require a second comma.
1123 * the second and remaining times, we set need_comma = TRUE.
1127 if (!token_stream_require (stream, ",",
1128 " after first tuple element", error))
1137 return (AST *) tuple;
1140 ast_array_free (tuple->children, tuple->n_children);
1141 g_slice_free (Tuple, tuple);
1154 variant_get_pattern (AST *ast,
1157 return g_strdup ("Mv");
1161 variant_get_value (AST *ast,
1162 const GVariantType *type,
1165 Variant *variant = (Variant *) ast;
1168 if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
1169 return ast_type_error (ast, type, error);
1171 child = ast_resolve (variant->value, error);
1176 return g_variant_new_variant (child);
1180 variant_free (AST *ast)
1182 Variant *variant = (Variant *) ast;
1184 ast_free (variant->value);
1185 g_slice_free (Variant, variant);
1189 variant_parse (TokenStream *stream,
1193 static const ASTClass variant_class = {
1194 variant_get_pattern,
1195 maybe_wrapper, variant_get_value,
1201 token_stream_assert (stream, "<");
1202 value = parse (stream, app, error);
1207 if (!token_stream_require (stream, ">", " to follow variant value", error))
1213 variant = g_slice_new (Variant);
1214 variant->ast.class = &variant_class;
1215 variant->value = value;
1217 return (AST *) variant;
1230 dictionary_get_pattern (AST *ast,
1233 Dictionary *dict = (Dictionary *) ast;
1234 gchar *value_pattern;
1239 if (dict->n_children == 0)
1240 return g_strdup ("Ma{**}");
1242 key_pattern = ast_array_get_pattern (dict->keys,
1243 abs (dict->n_children),
1246 if (key_pattern == NULL)
1249 /* we can not have maybe keys */
1250 if (key_pattern[0] == 'M')
1251 key_char = key_pattern[1];
1253 key_char = key_pattern[0];
1255 g_free (key_pattern);
1258 * plus undetermined number type and undetermined string type.
1260 if (!strchr ("bynqiuxthdsogNS", key_char))
1262 ast_set_error (ast, error, NULL,
1263 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1264 "dictionary keys must have basic types");
1268 value_pattern = ast_get_pattern (dict->values[0], error);
1270 if (value_pattern == NULL)
1273 result = g_strdup_printf ("M%s{%c%s}",
1274 dict->n_children > 0 ? "a" : "",
1275 key_char, value_pattern);
1276 g_free (value_pattern);
1282 dictionary_get_value (AST *ast,
1283 const GVariantType *type,
1286 Dictionary *dict = (Dictionary *) ast;
1288 if (dict->n_children == -1)
1290 const GVariantType *subtype;
1291 GVariantBuilder builder;
1294 if (!g_variant_type_is_dict_entry (type))
1295 return ast_type_error (ast, type, error);
1297 g_variant_builder_init (&builder, type);
1299 subtype = g_variant_type_key (type);
1300 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1302 g_variant_builder_clear (&builder);
1305 g_variant_builder_add_value (&builder, subvalue);
1307 subtype = g_variant_type_value (type);
1308 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1310 g_variant_builder_clear (&builder);
1313 g_variant_builder_add_value (&builder, subvalue);
1315 return g_variant_builder_end (&builder);
1319 const GVariantType *entry, *key, *val;
1320 GVariantBuilder builder;
1323 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1324 return ast_type_error (ast, type, error);
1326 entry = g_variant_type_element (type);
1327 key = g_variant_type_key (entry);
1328 val = g_variant_type_value (entry);
1330 g_variant_builder_init (&builder, type);
1332 for (i = 0; i < dict->n_children; i++)
1336 g_variant_builder_open (&builder, entry);
1338 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1340 g_variant_builder_clear (&builder);
1343 g_variant_builder_add_value (&builder, subvalue);
1345 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1347 g_variant_builder_clear (&builder);
1350 g_variant_builder_add_value (&builder, subvalue);
1351 g_variant_builder_close (&builder);
1354 return g_variant_builder_end (&builder);
1359 dictionary_free (AST *ast)
1361 Dictionary *dict = (Dictionary *) ast;
1364 if (dict->n_children > -1)
1365 n_children = dict->n_children;
1369 ast_array_free (dict->keys, n_children);
1370 ast_array_free (dict->values, n_children);
1371 g_slice_free (Dictionary, dict);
1375 dictionary_parse (TokenStream *stream,
1379 static const ASTClass dictionary_class = {
1380 dictionary_get_pattern,
1381 maybe_wrapper, dictionary_get_value,
1384 gint n_keys, n_values;
1389 dict = g_slice_new (Dictionary);
1390 dict->ast.class = &dictionary_class;
1392 dict->values = NULL;
1393 n_keys = n_values = 0;
1395 token_stream_assert (stream, "{");
1397 if (token_stream_consume (stream, "}"))
1399 dict->n_children = 0;
1400 return (AST *) dict;
1403 if ((first = parse (stream, app, error)) == NULL)
1406 ast_array_append (&dict->keys, &n_keys, first);
1408 only_one = token_stream_consume (stream, ",");
1410 !token_stream_require (stream, ":",
1411 " or ',' to follow dictionary entry key",
1415 if ((first = parse (stream, app, error)) == NULL)
1418 ast_array_append (&dict->values, &n_values, first);
1422 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1426 g_assert (n_keys == 1 && n_values == 1);
1427 dict->n_children = -1;
1429 return (AST *) dict;
1432 while (!token_stream_consume (stream, "}"))
1436 if (!token_stream_require (stream, ",",
1437 " or '}' to follow dictionary entry", error))
1440 child = parse (stream, app, error);
1445 ast_array_append (&dict->keys, &n_keys, child);
1447 if (!token_stream_require (stream, ":",
1448 " to follow dictionary entry key", error))
1451 child = parse (stream, app, error);
1456 ast_array_append (&dict->values, &n_values, child);
1459 g_assert (n_keys == n_values);
1460 dict->n_children = n_keys;
1462 return (AST *) dict;
1465 ast_array_free (dict->keys, n_keys);
1466 ast_array_free (dict->values, n_values);
1467 g_slice_free (Dictionary, dict);
1479 string_get_pattern (AST *ast,
1482 return g_strdup ("MS");
1486 string_get_value (AST *ast,
1487 const GVariantType *type,
1490 String *string = (String *) ast;
1492 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1493 return g_variant_new_string (string->string);
1495 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1497 if (!g_variant_is_object_path (string->string))
1499 ast_set_error (ast, error, NULL,
1500 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1501 "not a valid object path");
1505 return g_variant_new_object_path (string->string);
1508 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1510 if (!g_variant_is_signature (string->string))
1512 ast_set_error (ast, error, NULL,
1513 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1514 "not a valid signature");
1518 return g_variant_new_signature (string->string);
1522 return ast_type_error (ast, type, error);
1526 string_free (AST *ast)
1528 String *string = (String *) ast;
1530 g_free (string->string);
1531 g_slice_free (String, string);
1535 unicode_unescape (const gchar *src,
1549 g_assert (length < sizeof (buffer));
1550 strncpy (buffer, src + *src_ofs, length);
1551 buffer[length] = '\0';
1553 value = g_ascii_strtoull (buffer, &end, 0x10);
1555 if (value == 0 || end != buffer + length)
1557 parser_set_error (error, ref, NULL,
1558 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1559 "invalid %d-character unicode escape", length);
1563 g_assert (value <= G_MAXUINT32);
1565 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1572 string_parse (TokenStream *stream,
1576 static const ASTClass string_class = {
1578 maybe_wrapper, string_get_value,
1589 token_stream_start_ref (stream, &ref);
1590 token = token_stream_get (stream);
1591 token_stream_end_ref (stream, &ref);
1592 length = strlen (token);
1595 str = g_malloc (length);
1596 g_assert (quote == '"' || quote == '\'');
1599 while (token[i] != quote)
1603 parser_set_error (error, &ref, NULL,
1604 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1605 "unterminated string constant");
1614 parser_set_error (error, &ref, NULL,
1615 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1616 "unterminated string constant");
1622 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1631 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1639 case 'a': str[j++] = '\a'; i++; continue;
1640 case 'b': str[j++] = '\b'; i++; continue;
1641 case 'f': str[j++] = '\f'; i++; continue;
1642 case 'n': str[j++] = '\n'; i++; continue;
1643 case 'r': str[j++] = '\r'; i++; continue;
1644 case 't': str[j++] = '\t'; i++; continue;
1645 case 'v': str[j++] = '\v'; i++; continue;
1646 case '\n': i++; continue;
1650 str[j++] = token[i++];
1655 string = g_slice_new (String);
1656 string->ast.class = &string_class;
1657 string->string = str;
1659 token_stream_next (stream);
1661 return (AST *) string;
1671 bytestring_get_pattern (AST *ast,
1674 return g_strdup ("May");
1678 bytestring_get_value (AST *ast,
1679 const GVariantType *type,
1682 ByteString *string = (ByteString *) ast;
1684 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
1685 return ast_type_error (ast, type, error);
1687 return g_variant_new_bytestring (string->string);
1691 bytestring_free (AST *ast)
1693 ByteString *string = (ByteString *) ast;
1695 g_free (string->string);
1696 g_slice_free (ByteString, string);
1700 bytestring_parse (TokenStream *stream,
1704 static const ASTClass bytestring_class = {
1705 bytestring_get_pattern,
1706 maybe_wrapper, bytestring_get_value,
1717 token_stream_start_ref (stream, &ref);
1718 token = token_stream_get (stream);
1719 token_stream_end_ref (stream, &ref);
1720 g_assert (token[0] == 'b');
1721 length = strlen (token);
1724 str = g_malloc (length);
1725 g_assert (quote == '"' || quote == '\'');
1728 while (token[i] != quote)
1732 parser_set_error (error, &ref, NULL,
1733 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1734 "unterminated string constant");
1743 parser_set_error (error, &ref, NULL,
1744 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1745 "unterminated string constant");
1750 case '0': case '1': case '2': case '3':
1751 case '4': case '5': case '6': case '7':
1753 /* up to 3 characters */
1754 guchar val = token[i++] - '0';
1756 if ('0' <= token[i] && token[i] < '8')
1757 val = (val << 3) | (token[i++] - '0');
1759 if ('0' <= token[i] && token[i] < '8')
1760 val = (val << 3) | (token[i++] - '0');
1766 case 'a': str[j++] = '\a'; i++; continue;
1767 case 'b': str[j++] = '\b'; i++; continue;
1768 case 'f': str[j++] = '\f'; i++; continue;
1769 case 'n': str[j++] = '\n'; i++; continue;
1770 case 'r': str[j++] = '\r'; i++; continue;
1771 case 't': str[j++] = '\t'; i++; continue;
1772 case 'v': str[j++] = '\v'; i++; continue;
1773 case '\n': i++; continue;
1777 str[j++] = token[i++];
1782 string = g_slice_new (ByteString);
1783 string->ast.class = &bytestring_class;
1784 string->string = str;
1786 token_stream_next (stream);
1788 return (AST *) string;
1799 number_get_pattern (AST *ast,
1802 Number *number = (Number *) ast;
1804 if (strchr (number->token, '.') ||
1805 (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
1806 strstr (number->token, "inf") ||
1807 strstr (number->token, "nan"))
1808 return g_strdup ("Md");
1810 return g_strdup ("MN");
1814 number_overflow (AST *ast,
1815 const GVariantType *type,
1818 ast_set_error (ast, error, NULL,
1819 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1820 "number out of range for type '%c'",
1821 g_variant_type_peek_string (type)[0]);
1826 number_get_value (AST *ast,
1827 const GVariantType *type,
1830 Number *number = (Number *) ast;
1838 token = number->token;
1840 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1845 dbl_val = g_ascii_strtod (token, &end);
1846 if (dbl_val != 0.0 && errno == ERANGE)
1848 ast_set_error (ast, error, NULL,
1849 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1850 "number too big for any type");
1854 /* silence uninitialised warnings... */
1861 negative = token[0] == '-';
1862 if (token[0] == '-')
1866 abs_val = g_ascii_strtoull (token, &end, 0);
1867 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1869 ast_set_error (ast, error, NULL,
1870 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1871 "integer too big for any type");
1878 /* silence uninitialised warning... */
1886 ref = ast->source_ref;
1887 ref.start += end - number->token;
1888 ref.end = ref.start + 1;
1890 parser_set_error (error, &ref, NULL,
1891 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1892 "invalid character in number");
1897 return g_variant_new_double (dbl_val);
1899 switch (*g_variant_type_peek_string (type))
1902 if (negative || abs_val > G_MAXUINT8)
1903 return number_overflow (ast, type, error);
1904 return g_variant_new_byte (abs_val);
1907 if (abs_val - negative > G_MAXINT16)
1908 return number_overflow (ast, type, error);
1909 return g_variant_new_int16 (negative ? -abs_val : abs_val);
1912 if (negative || abs_val > G_MAXUINT16)
1913 return number_overflow (ast, type, error);
1914 return g_variant_new_uint16 (abs_val);
1917 if (abs_val - negative > G_MAXINT32)
1918 return number_overflow (ast, type, error);
1919 return g_variant_new_int32 (negative ? -abs_val : abs_val);
1922 if (negative || abs_val > G_MAXUINT32)
1923 return number_overflow (ast, type, error);
1924 return g_variant_new_uint32 (abs_val);
1927 if (abs_val - negative > G_MAXINT64)
1928 return number_overflow (ast, type, error);
1929 return g_variant_new_int64 (negative ? -abs_val : abs_val);
1933 return number_overflow (ast, type, error);
1934 return g_variant_new_uint64 (abs_val);
1937 if (abs_val - negative > G_MAXINT32)
1938 return number_overflow (ast, type, error);
1939 return g_variant_new_handle (negative ? -abs_val : abs_val);
1942 return ast_type_error (ast, type, error);
1947 number_free (AST *ast)
1949 Number *number = (Number *) ast;
1951 g_free (number->token);
1952 g_slice_free (Number, number);
1956 number_parse (TokenStream *stream,
1960 static const ASTClass number_class = {
1962 maybe_wrapper, number_get_value,
1967 number = g_slice_new (Number);
1968 number->ast.class = &number_class;
1969 number->token = token_stream_get (stream);
1970 token_stream_next (stream);
1972 return (AST *) number;
1982 boolean_get_pattern (AST *ast,
1985 return g_strdup ("Mb");
1989 boolean_get_value (AST *ast,
1990 const GVariantType *type,
1993 Boolean *boolean = (Boolean *) ast;
1995 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
1996 return ast_type_error (ast, type, error);
1998 return g_variant_new_boolean (boolean->value);
2002 boolean_free (AST *ast)
2004 Boolean *boolean = (Boolean *) ast;
2006 g_slice_free (Boolean, boolean);
2010 boolean_new (gboolean value)
2012 static const ASTClass boolean_class = {
2013 boolean_get_pattern,
2014 maybe_wrapper, boolean_get_value,
2019 boolean = g_slice_new (Boolean);
2020 boolean->ast.class = &boolean_class;
2021 boolean->value = value;
2023 return (AST *) boolean;
2034 positional_get_pattern (AST *ast,
2037 Positional *positional = (Positional *) ast;
2039 return g_strdup (g_variant_get_type_string (positional->value));
2043 positional_get_value (AST *ast,
2044 const GVariantType *type,
2047 Positional *positional = (Positional *) ast;
2050 g_assert (positional->value != NULL);
2052 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2053 return ast_type_error (ast, type, error);
2055 /* NOTE: if _get is called more than once then
2056 * things get messed up with respect to floating refs.
2058 * fortunately, this function should only ever get called once.
2060 g_assert (positional->value != NULL);
2061 value = positional->value;
2062 positional->value = NULL;
2068 positional_free (AST *ast)
2070 Positional *positional = (Positional *) ast;
2072 /* if positional->value is set, just leave it.
2073 * memory management doesn't matter in case of programmer error.
2075 g_slice_free (Positional, positional);
2079 positional_parse (TokenStream *stream,
2083 static const ASTClass positional_class = {
2084 positional_get_pattern,
2085 positional_get_value, NULL,
2088 Positional *positional;
2089 const gchar *endptr;
2092 token = token_stream_get (stream);
2093 g_assert (token[0] == '%');
2095 positional = g_slice_new (Positional);
2096 positional->ast.class = &positional_class;
2097 positional->value = g_variant_new_va (token + 1, &endptr, app);
2099 if (*endptr || positional->value == NULL)
2101 token_stream_set_error (stream, error, TRUE,
2102 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2103 "invalid GVariant format string");
2104 /* memory management doesn't matter in case of programmer error. */
2108 token_stream_next (stream);
2111 return (AST *) positional;
2123 typedecl_get_pattern (AST *ast,
2126 TypeDecl *decl = (TypeDecl *) ast;
2128 return g_variant_type_dup_string (decl->type);
2132 typedecl_get_value (AST *ast,
2133 const GVariantType *type,
2136 TypeDecl *decl = (TypeDecl *) ast;
2138 return ast_get_value (decl->child, type, error);
2142 typedecl_free (AST *ast)
2144 TypeDecl *decl = (TypeDecl *) ast;
2146 ast_free (decl->child);
2147 g_variant_type_free (decl->type);
2148 g_slice_free (TypeDecl, decl);
2152 typedecl_parse (TokenStream *stream,
2156 static const ASTClass typedecl_class = {
2157 typedecl_get_pattern,
2158 typedecl_get_value, NULL,
2165 if (token_stream_peek (stream, '@'))
2169 token = token_stream_get (stream);
2171 if (!g_variant_type_string_is_valid (token + 1))
2173 token_stream_set_error (stream, error, TRUE,
2174 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2175 "invalid type declaration");
2181 type = g_variant_type_new (token + 1);
2183 if (!g_variant_type_is_definite (type))
2185 token_stream_set_error (stream, error, TRUE,
2186 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2187 "type declarations must be definite");
2188 g_variant_type_free (type);
2194 token_stream_next (stream);
2199 if (token_stream_consume (stream, "boolean"))
2200 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2202 else if (token_stream_consume (stream, "byte"))
2203 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2205 else if (token_stream_consume (stream, "int16"))
2206 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2208 else if (token_stream_consume (stream, "uint16"))
2209 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2211 else if (token_stream_consume (stream, "int32"))
2212 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2214 else if (token_stream_consume (stream, "handle"))
2215 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2217 else if (token_stream_consume (stream, "uint32"))
2218 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2220 else if (token_stream_consume (stream, "int64"))
2221 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2223 else if (token_stream_consume (stream, "uint64"))
2224 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2226 else if (token_stream_consume (stream, "double"))
2227 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2229 else if (token_stream_consume (stream, "string"))
2230 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2232 else if (token_stream_consume (stream, "objectpath"))
2233 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2235 else if (token_stream_consume (stream, "signature"))
2236 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2240 token_stream_set_error (stream, error, TRUE,
2241 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2247 if ((child = parse (stream, app, error)) == NULL)
2249 g_variant_type_free (type);
2253 decl = g_slice_new (TypeDecl);
2254 decl->ast.class = &typedecl_class;
2256 decl->child = child;
2258 return (AST *) decl;
2262 parse (TokenStream *stream,
2266 SourceRef source_ref;
2269 token_stream_prepare (stream);
2270 token_stream_start_ref (stream, &source_ref);
2272 if (token_stream_peek (stream, '['))
2273 result = array_parse (stream, app, error);
2275 else if (token_stream_peek (stream, '('))
2276 result = tuple_parse (stream, app, error);
2278 else if (token_stream_peek (stream, '<'))
2279 result = variant_parse (stream, app, error);
2281 else if (token_stream_peek (stream, '{'))
2282 result = dictionary_parse (stream, app, error);
2284 else if (app && token_stream_peek (stream, '%'))
2285 result = positional_parse (stream, app, error);
2287 else if (token_stream_consume (stream, "true"))
2288 result = boolean_new (TRUE);
2290 else if (token_stream_consume (stream, "false"))
2291 result = boolean_new (FALSE);
2293 else if (token_stream_is_numeric (stream) ||
2294 token_stream_peek_string (stream, "inf") ||
2295 token_stream_peek_string (stream, "nan"))
2296 result = number_parse (stream, app, error);
2298 else if (token_stream_peek (stream, 'n') ||
2299 token_stream_peek (stream, 'j'))
2300 result = maybe_parse (stream, app, error);
2302 else if (token_stream_peek (stream, '@') ||
2303 token_stream_is_keyword (stream))
2304 result = typedecl_parse (stream, app, error);
2306 else if (token_stream_peek (stream, '\'') ||
2307 token_stream_peek (stream, '"'))
2308 result = string_parse (stream, app, error);
2310 else if (token_stream_peek2 (stream, 'b', '\'') ||
2311 token_stream_peek2 (stream, 'b', '"'))
2312 result = bytestring_parse (stream, app, error);
2316 token_stream_set_error (stream, error, FALSE,
2317 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2324 token_stream_end_ref (stream, &source_ref);
2325 result->source_ref = source_ref;
2333 * @type: (nullable): a #GVariantType, or %NULL
2334 * @text: a string containing a GVariant in text form
2335 * @limit: (nullable): a pointer to the end of @text, or %NULL
2336 * @endptr: (nullable): a location to store the end pointer, or %NULL
2337 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2339 * Parses a #GVariant from a text representation.
2341 * A single #GVariant is parsed from the content of @text.
2343 * The format is described [here][gvariant-text].
2345 * The memory at @limit will never be accessed and the parser behaves as
2346 * if the character at @limit is the nul terminator. This has the
2347 * effect of bounding @text.
2349 * If @endptr is non-%NULL then @text is permitted to contain data
2350 * following the value that this function parses and @endptr will be
2351 * updated to point to the first character past the end of the text
2352 * parsed by this function. If @endptr is %NULL and there is extra data
2353 * then an error is returned.
2355 * If @type is non-%NULL then the value will be parsed to have that
2356 * type. This may result in additional parse errors (in the case that
2357 * the parsed value doesn't fit the type) but may also result in fewer
2358 * errors (in the case that the type would have been ambiguous, such as
2359 * with empty arrays).
2361 * In the event that the parsing is successful, the resulting #GVariant
2362 * is returned. It is never floating, and must be freed with
2363 * g_variant_unref().
2365 * In case of any error, %NULL will be returned. If @error is non-%NULL
2366 * then it will be set to reflect the error that occurred.
2368 * Officially, the language understood by the parser is "any string
2369 * produced by g_variant_print()".
2371 * Returns: a non-floating reference to a #GVariant, or %NULL
2374 g_variant_parse (const GVariantType *type,
2377 const gchar **endptr,
2380 TokenStream stream = { 0, };
2381 GVariant *result = NULL;
2384 g_return_val_if_fail (text != NULL, NULL);
2385 g_return_val_if_fail (text == limit || text != NULL, NULL);
2387 stream.start = text;
2388 stream.stream = text;
2391 if ((ast = parse (&stream, NULL, error)))
2394 result = ast_resolve (ast, error);
2396 result = ast_get_value (ast, type, error);
2400 g_variant_ref_sink (result);
2404 while (stream.stream != limit &&
2405 g_ascii_isspace (*stream.stream))
2408 if (stream.stream != limit && *stream.stream != '\0')
2410 SourceRef ref = { stream.stream - text,
2411 stream.stream - text };
2413 parser_set_error (error, &ref, NULL,
2414 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2415 "expected end of input");
2416 g_variant_unref (result);
2422 *endptr = stream.stream;
2432 * g_variant_new_parsed_va:
2433 * @format: a text format #GVariant
2434 * @app: a pointer to a #va_list
2436 * Parses @format and returns the result.
2438 * This is the version of g_variant_new_parsed() intended to be used
2441 * The return value will be floating if it was a newly created GVariant
2442 * instance. In the case that @format simply specified the collection
2443 * of a #GVariant pointer (eg: @format was "%*") then the collected
2444 * #GVariant pointer will be returned unmodified, without adding any
2445 * additional references.
2447 * Note that the arguments in @app must be of the correct width for their types
2448 * specified in @format when collected into the #va_list. See
2449 * the [GVariant varargs documentation][gvariant-varargs].
2451 * In order to behave correctly in all cases it is necessary for the
2452 * calling function to g_variant_ref_sink() the return result before
2453 * returning control to the user that originally provided the pointer.
2454 * At this point, the caller will have their own full reference to the
2455 * result. This can also be done by adding the result to a container,
2456 * or by passing it to another g_variant_new() call.
2458 * Returns: a new, usually floating, #GVariant
2461 g_variant_new_parsed_va (const gchar *format,
2464 TokenStream stream = { 0, };
2465 GVariant *result = NULL;
2466 GError *error = NULL;
2469 g_return_val_if_fail (format != NULL, NULL);
2470 g_return_val_if_fail (app != NULL, NULL);
2472 stream.start = format;
2473 stream.stream = format;
2476 if ((ast = parse (&stream, app, &error)))
2478 result = ast_resolve (ast, &error);
2483 g_error ("g_variant_new_parsed: %s", error->message);
2486 g_error ("g_variant_new_parsed: trailing text after value");
2492 * g_variant_new_parsed:
2493 * @format: a text format #GVariant
2494 * @...: arguments as per @format
2496 * Parses @format and returns the result.
2498 * @format must be a text format #GVariant with one extension: at any
2499 * point that a value may appear in the text, a '%' character followed
2500 * by a GVariant format string (as per g_variant_new()) may appear. In
2501 * that case, the same arguments are collected from the argument list as
2502 * g_variant_new() would have collected.
2504 * Note that the arguments must be of the correct width for their types
2505 * specified in @format. This can be achieved by casting them. See
2506 * the [GVariant varargs documentation][gvariant-varargs].
2508 * Consider this simple example:
2509 * |[<!-- language="C" -->
2510 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2513 * In the example, the variable argument parameters are collected and
2514 * filled in as if they were part of the original string to produce the
2516 * |[<!-- language="C" -->
2517 * [('one', 1), ('two', 2), ('three', 3)]
2520 * This function is intended only to be used with @format as a string
2521 * literal. Any parse error is fatal to the calling process. If you
2522 * want to parse data from untrusted sources, use g_variant_parse().
2524 * You may not use this function to return, unmodified, a single
2525 * #GVariant pointer from the argument list. ie: @format may not solely
2526 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2529 * Returns: a new floating #GVariant instance
2532 g_variant_new_parsed (const gchar *format,
2538 va_start (ap, format);
2539 result = g_variant_new_parsed_va (format, &ap);
2546 * g_variant_builder_add_parsed:
2547 * @builder: a #GVariantBuilder
2548 * @format: a text format #GVariant
2549 * @...: arguments as per @format
2551 * Adds to a #GVariantBuilder.
2553 * This call is a convenience wrapper that is exactly equivalent to
2554 * calling g_variant_new_parsed() followed by
2555 * g_variant_builder_add_value().
2557 * Note that the arguments must be of the correct width for their types
2558 * specified in @format_string. This can be achieved by casting them. See
2559 * the [GVariant varargs documentation][gvariant-varargs].
2561 * This function might be used as follows:
2563 * |[<!-- language="C" -->
2565 * make_pointless_dictionary (void)
2567 * GVariantBuilder builder;
2570 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2571 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2572 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2573 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2574 * return g_variant_builder_end (&builder);
2581 g_variant_builder_add_parsed (GVariantBuilder *builder,
2582 const gchar *format,
2587 va_start (ap, format);
2588 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
2593 parse_num (const gchar *num,
2600 bignum = g_ascii_strtoll (num, &endptr, 10);
2602 if (endptr != limit)
2605 if (bignum < 0 || bignum > G_MAXINT)
2614 add_last_line (GString *err,
2617 const gchar *last_nl;
2621 /* This is an error at the end of input. If we have a file
2622 * with newlines, that's probably the empty string after the
2623 * last newline, which is not the most useful thing to show.
2625 * Instead, show the last line of non-whitespace that we have
2626 * and put the pointer at the end of it.
2628 chomped = g_strchomp (g_strdup (str));
2629 last_nl = strrchr (chomped, '\n');
2630 if (last_nl == NULL)
2635 /* Print the last line like so:
2640 g_string_append (err, " ");
2642 g_string_append (err, last_nl);
2644 g_string_append (err, "(empty input)");
2645 g_string_append (err, "\n ");
2646 for (i = 0; last_nl[i]; i++)
2647 g_string_append_c (err, ' ');
2648 g_string_append (err, "^\n");
2653 add_lines_from_range (GString *err,
2655 const gchar *start1,
2657 const gchar *start2,
2660 while (str < end1 || str < end2)
2664 nl = str + strcspn (str, "\n");
2666 if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
2670 /* We're going to print this line */
2671 g_string_append (err, " ");
2672 g_string_append_len (err, str, nl - str);
2673 g_string_append (err, "\n ");
2675 /* And add underlines... */
2676 for (s = str; s < nl; s++)
2678 if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
2679 g_string_append_c (err, '^');
2681 g_string_append_c (err, ' ');
2683 g_string_append_c (err, '\n');
2694 * g_variant_parse_error_print_context:
2695 * @error: a #GError from the #GVariantParseError domain
2696 * @source_str: the string that was given to the parser
2698 * Pretty-prints a message showing the context of a #GVariant parse
2699 * error within the string for which parsing was attempted.
2701 * The resulting string is suitable for output to the console or other
2702 * monospace media where newlines are treated in the usual way.
2704 * The message will typically look something like one of the following:
2707 * unterminated string constant:
2715 * unable to find a common type:
2720 * The format of the message may change in a future version.
2722 * @error must have come from a failed attempt to g_variant_parse() and
2723 * @source_str must be exactly the same string that caused the error.
2724 * If @source_str was not nul-terminated when you passed it to
2725 * g_variant_parse() then you must add nul termination before using this
2728 * Returns: (transfer full): the printed message
2733 g_variant_parse_error_print_context (GError *error,
2734 const gchar *source_str)
2736 const gchar *colon, *dash, *comma;
2737 gboolean success = FALSE;
2740 g_return_val_if_fail (error->domain == G_VARIANT_PARSE_ERROR, FALSE);
2742 /* We can only have a limited number of possible types of ranges
2743 * emitted from the parser:
2745 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2746 * - a-b: -- usually errors from handling one single token
2747 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2749 * We never see, for example "a,c".
2752 colon = strchr (error->message, ':');
2753 dash = strchr (error->message, '-');
2754 comma = strchr (error->message, ',');
2759 err = g_string_new (colon + 1);
2760 g_string_append (err, ":\n");
2762 if (dash == NULL || colon < dash)
2766 /* we have a single point */
2767 if (!parse_num (error->message, colon, &point))
2770 if (point >= strlen (source_str))
2771 /* the error is at the end of the input */
2772 add_last_line (err, source_str);
2774 /* otherwise just treat it as a error at a thin range */
2775 add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
2779 /* We have one or two ranges... */
2780 if (comma && comma < colon)
2782 gint start1, end1, start2, end2;
2786 dash2 = strchr (comma, '-');
2788 if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
2789 !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
2792 add_lines_from_range (err, source_str,
2793 source_str + start1, source_str + end1,
2794 source_str + start2, source_str + end2);
2801 if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
2804 add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
2811 return g_string_free (err, !success);