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, 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
->stream
[1] == '"')
202 for (end
= stream
->stream
+ 2; end
!= stream
->end
; end
++)
203 if (*end
== stream
->stream
[1] || *end
== '\0' ||
204 (*end
== '\\' && (++end
== stream
->end
|| *end
== '\0')))
207 if (end
!= stream
->end
&& *end
)
217 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
218 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
219 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
220 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
222 for (end
= stream
->stream
; end
!= stream
->end
; end
++)
223 if (!g_ascii_isalnum (*end
))
228 for (end
= stream
->stream
+ 1; end
!= stream
->end
; end
++)
229 if (*end
== stream
->stream
[0] || *end
== '\0' ||
230 (*end
== '\\' && (++end
== stream
->end
|| *end
== '\0')))
233 if (end
!= stream
->end
&& *end
)
238 /* stop at the first space, comma, colon or unmatched bracket.
239 * deals nicely with cases like (%i, %i) or {%i: %i}.
240 * Also: ] and > are never in format strings.
242 for (end
= stream
->stream
+ 1;
243 end
!= stream
->end
&& *end
!= '\0' && *end
!= ',' &&
244 *end
!= ':' && *end
!= '>' && *end
!= ']' && !g_ascii_isspace (*end
);
247 if (*end
== '(' || *end
== '{')
250 else if ((*end
== ')' || *end
== '}') && !brackets
--)
256 end
= stream
->stream
+ 1;
260 stream
->this = stream
->stream
;
261 stream
->stream
= end
;
267 token_stream_next (TokenStream
*stream
)
273 token_stream_peek (TokenStream
*stream
,
276 if (!token_stream_prepare (stream
))
279 return stream
->this[0] == first_char
;
283 token_stream_peek2 (TokenStream
*stream
,
287 if (!token_stream_prepare (stream
))
290 return stream
->this[0] == first_char
&&
291 stream
->this[1] == second_char
;
295 token_stream_is_keyword (TokenStream
*stream
)
297 if (!token_stream_prepare (stream
))
300 return g_ascii_isalpha (stream
->this[0]) &&
301 g_ascii_isalpha (stream
->this[1]);
305 token_stream_is_numeric (TokenStream
*stream
)
307 if (!token_stream_prepare (stream
))
310 return (g_ascii_isdigit (stream
->this[0]) ||
311 stream
->this[0] == '-' ||
312 stream
->this[0] == '+' ||
313 stream
->this[0] == '.');
317 token_stream_peek_string (TokenStream
*stream
,
320 gint length
= strlen (token
);
322 return token_stream_prepare (stream
) &&
323 stream
->stream
- stream
->this == length
&&
324 memcmp (stream
->this, token
, length
) == 0;
328 token_stream_consume (TokenStream
*stream
,
331 if (!token_stream_peek_string (stream
, token
))
334 token_stream_next (stream
);
339 token_stream_require (TokenStream
*stream
,
341 const gchar
*purpose
,
345 if (!token_stream_consume (stream
, token
))
347 token_stream_set_error (stream
, error
, FALSE
,
348 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN
,
349 "expected '%s'%s", token
, purpose
);
357 token_stream_assert (TokenStream
*stream
,
360 gboolean correct_token
;
362 correct_token
= token_stream_consume (stream
, token
);
363 g_assert (correct_token
);
367 token_stream_get (TokenStream
*stream
)
371 if (!token_stream_prepare (stream
))
374 result
= g_strndup (stream
->this, stream
->stream
- stream
->this);
380 token_stream_start_ref (TokenStream
*stream
,
383 token_stream_prepare (stream
);
384 ref
->start
= stream
->this - stream
->start
;
388 token_stream_end_ref (TokenStream
*stream
,
391 ref
->end
= stream
->stream
- stream
->start
;
395 pattern_copy (gchar
**out
,
400 while (**in
== 'a' || **in
== 'm' || **in
== 'M')
401 *(*out
)++ = *(*in
)++;
405 if (**in
== '(' || **in
== '{')
408 else if (**in
== ')' || **in
== '}')
411 *(*out
)++ = *(*in
)++;
417 pattern_coalesce (const gchar
*left
,
423 /* the length of the output is loosely bound by the sum of the input
424 * lengths, not simply the greater of the two lengths.
426 * (*(iii)) + ((iii)*) ((iii)(iii))
430 out
= result
= g_malloc (strlen (left
) + strlen (right
));
432 while (*left
&& *right
)
442 const gchar
**one
= &left
, **the_other
= &right
;
445 if (**one
== '*' && **the_other
!= ')')
447 pattern_copy (&out
, the_other
);
451 else if (**one
== 'M' && **the_other
== 'm')
453 *out
++ = *(*the_other
)++;
456 else if (**one
== 'M' && **the_other
!= 'm')
461 else if (**one
== 'N' && strchr ("ynqiuxthd", **the_other
))
463 *out
++ = *(*the_other
)++;
467 else if (**one
== 'S' && strchr ("sog", **the_other
))
469 *out
++ = *(*the_other
)++;
473 else if (one
== &left
)
475 one
= &right
, the_other
= &left
;
495 typedef struct _AST AST
;
496 typedef gchar
* (*get_pattern_func
) (AST
*ast
,
498 typedef GVariant
* (*get_value_func
) (AST
*ast
,
499 const GVariantType
*type
,
501 typedef GVariant
* (*get_base_value_func
) (AST
*ast
,
502 const GVariantType
*type
,
504 typedef void (*free_func
) (AST
*ast
);
508 gchar
* (* get_pattern
) (AST
*ast
,
510 GVariant
* (* get_value
) (AST
*ast
,
511 const GVariantType
*type
,
513 GVariant
* (* get_base_value
) (AST
*ast
,
514 const GVariantType
*type
,
516 void (* free
) (AST
*ast
);
521 const ASTClass
*class;
522 SourceRef source_ref
;
526 ast_get_pattern (AST
*ast
,
529 return ast
->class->get_pattern (ast
, error
);
533 ast_get_value (AST
*ast
,
534 const GVariantType
*type
,
537 return ast
->class->get_value (ast
, type
, error
);
543 ast
->class->free (ast
);
548 ast_set_error (AST
*ast
,
557 va_start (ap
, format
);
558 parser_set_error_va (error
, &ast
->source_ref
,
559 other_ast
? & other_ast
->source_ref
: NULL
,
566 ast_type_error (AST
*ast
,
567 const GVariantType
*type
,
572 typestr
= g_variant_type_dup_string (type
);
573 ast_set_error (ast
, error
, NULL
,
574 G_VARIANT_PARSE_ERROR_TYPE_ERROR
,
575 "can not parse as value of type '%s'",
583 ast_resolve (AST
*ast
,
590 pattern
= ast_get_pattern (ast
, error
);
595 /* choose reasonable defaults
597 * 1) favour non-maybe values where possible
598 * 2) default type for strings is 's'
599 * 3) default type for integers is 'i'
601 for (i
= 0; pattern
[i
]; i
++)
605 ast_set_error (ast
, error
, NULL
,
606 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE
,
607 "unable to infer type");
623 pattern
[j
++] = pattern
[i
];
628 value
= ast_get_value (ast
, G_VARIANT_TYPE (pattern
), error
);
635 static AST
*parse (TokenStream
*stream
,
640 ast_array_append (AST
***array
,
644 if ((*n_items
& (*n_items
- 1)) == 0)
645 *array
= g_renew (AST
*, *array
, *n_items
? 2 ** n_items
: 1);
647 (*array
)[(*n_items
)++] = ast
;
651 ast_array_free (AST
**array
,
656 for (i
= 0; i
< n_items
; i
++)
662 ast_array_get_pattern (AST
**array
,
669 pattern
= ast_get_pattern (array
[0], error
);
674 for (i
= 1; i
< n_items
; i
++)
678 tmp
= ast_get_pattern (array
[i
], error
);
686 merged
= pattern_coalesce (pattern
, tmp
);
691 /* set coalescence implies pairwise coalescence (i think).
692 * we should therefore be able to trace the failure to a single
703 /* if 'j' reaches 'i' then we failed to find the pair */
706 tmp2
= ast_get_pattern (array
[j
], NULL
);
707 g_assert (tmp2
!= NULL
);
709 m
= pattern_coalesce (tmp
, tmp2
);
715 /* we found a conflict between 'i' and 'j'.
717 * report the error. note: 'j' is first.
719 ast_set_error (array
[j
], error
, array
[i
],
720 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE
,
721 "unable to find a common type");
745 maybe_get_pattern (AST
*ast
,
748 Maybe
*maybe
= (Maybe
*) ast
;
750 if (maybe
->child
!= NULL
)
752 gchar
*child_pattern
;
755 child_pattern
= ast_get_pattern (maybe
->child
, error
);
757 if (child_pattern
== NULL
)
760 pattern
= g_strdup_printf ("m%s", child_pattern
);
761 g_free (child_pattern
);
766 return g_strdup ("m*");
770 maybe_get_value (AST
*ast
,
771 const GVariantType
*type
,
774 Maybe
*maybe
= (Maybe
*) ast
;
777 if (!g_variant_type_is_maybe (type
))
778 return ast_type_error (ast
, type
, error
);
780 type
= g_variant_type_element (type
);
784 value
= ast_get_value (maybe
->child
, type
, error
);
792 return g_variant_new_maybe (type
, value
);
796 maybe_free (AST
*ast
)
798 Maybe
*maybe
= (Maybe
*) ast
;
800 if (maybe
->child
!= NULL
)
801 ast_free (maybe
->child
);
803 g_slice_free (Maybe
, maybe
);
807 maybe_parse (TokenStream
*stream
,
811 static const ASTClass maybe_class
= {
813 maybe_get_value
, NULL
,
819 if (token_stream_consume (stream
, "just"))
821 child
= parse (stream
, app
, error
);
826 else if (!token_stream_consume (stream
, "nothing"))
828 token_stream_set_error (stream
, error
, TRUE
,
829 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
834 maybe
= g_slice_new (Maybe
);
835 maybe
->ast
.class = &maybe_class
;
836 maybe
->child
= child
;
838 return (AST
*) maybe
;
842 maybe_wrapper (AST
*ast
,
843 const GVariantType
*type
,
846 const GVariantType
*t
;
850 for (depth
= 0, t
= type
;
851 g_variant_type_is_maybe (t
);
852 depth
++, t
= g_variant_type_element (t
));
854 value
= ast
->class->get_base_value (ast
, t
, error
);
860 value
= g_variant_new_maybe (NULL
, value
);
874 array_get_pattern (AST
*ast
,
877 Array
*array
= (Array
*) ast
;
881 if (array
->n_children
== 0)
882 return g_strdup ("Ma*");
884 pattern
= ast_array_get_pattern (array
->children
, array
->n_children
, error
);
889 result
= g_strdup_printf ("Ma%s", pattern
);
896 array_get_value (AST
*ast
,
897 const GVariantType
*type
,
900 Array
*array
= (Array
*) ast
;
901 const GVariantType
*childtype
;
902 GVariantBuilder builder
;
905 if (!g_variant_type_is_array (type
))
906 return ast_type_error (ast
, type
, error
);
908 g_variant_builder_init (&builder
, type
);
909 childtype
= g_variant_type_element (type
);
911 for (i
= 0; i
< array
->n_children
; i
++)
915 if (!(child
= ast_get_value (array
->children
[i
], childtype
, error
)))
917 g_variant_builder_clear (&builder
);
921 g_variant_builder_add_value (&builder
, child
);
924 return g_variant_builder_end (&builder
);
928 array_free (AST
*ast
)
930 Array
*array
= (Array
*) ast
;
932 ast_array_free (array
->children
, array
->n_children
);
933 g_slice_free (Array
, array
);
937 array_parse (TokenStream
*stream
,
941 static const ASTClass array_class
= {
943 maybe_wrapper
, array_get_value
,
946 gboolean need_comma
= FALSE
;
949 array
= g_slice_new (Array
);
950 array
->ast
.class = &array_class
;
951 array
->children
= NULL
;
952 array
->n_children
= 0;
954 token_stream_assert (stream
, "[");
955 while (!token_stream_consume (stream
, "]"))
960 !token_stream_require (stream
, ",",
961 " or ']' to follow array element",
965 child
= parse (stream
, app
, error
);
970 ast_array_append (&array
->children
, &array
->n_children
, child
);
974 return (AST
*) array
;
977 ast_array_free (array
->children
, array
->n_children
);
978 g_slice_free (Array
, array
);
992 tuple_get_pattern (AST
*ast
,
995 Tuple
*tuple
= (Tuple
*) ast
;
996 gchar
*result
= NULL
;
1000 parts
= g_new (gchar
*, tuple
->n_children
+ 4);
1001 parts
[tuple
->n_children
+ 1] = (gchar
*) ")";
1002 parts
[tuple
->n_children
+ 2] = NULL
;
1003 parts
[0] = (gchar
*) "M(";
1005 for (i
= 0; i
< tuple
->n_children
; i
++)
1006 if (!(parts
[i
+ 1] = ast_get_pattern (tuple
->children
[i
], error
)))
1009 if (i
== tuple
->n_children
)
1010 result
= g_strjoinv ("", parts
);
1012 /* parts[0] should not be freed */
1014 g_free (parts
[i
--]);
1021 tuple_get_value (AST
*ast
,
1022 const GVariantType
*type
,
1025 Tuple
*tuple
= (Tuple
*) ast
;
1026 const GVariantType
*childtype
;
1027 GVariantBuilder builder
;
1030 if (!g_variant_type_is_tuple (type
))
1031 return ast_type_error (ast
, type
, error
);
1033 g_variant_builder_init (&builder
, type
);
1034 childtype
= g_variant_type_first (type
);
1036 for (i
= 0; i
< tuple
->n_children
; i
++)
1040 if (childtype
== NULL
)
1042 g_variant_builder_clear (&builder
);
1043 return ast_type_error (ast
, type
, error
);
1046 if (!(child
= ast_get_value (tuple
->children
[i
], childtype
, error
)))
1048 g_variant_builder_clear (&builder
);
1052 g_variant_builder_add_value (&builder
, child
);
1053 childtype
= g_variant_type_next (childtype
);
1056 if (childtype
!= NULL
)
1058 g_variant_builder_clear (&builder
);
1059 return ast_type_error (ast
, type
, error
);
1062 return g_variant_builder_end (&builder
);
1066 tuple_free (AST
*ast
)
1068 Tuple
*tuple
= (Tuple
*) ast
;
1070 ast_array_free (tuple
->children
, tuple
->n_children
);
1071 g_slice_free (Tuple
, tuple
);
1075 tuple_parse (TokenStream
*stream
,
1079 static const ASTClass tuple_class
= {
1081 maybe_wrapper
, tuple_get_value
,
1084 gboolean need_comma
= FALSE
;
1085 gboolean first
= TRUE
;
1088 tuple
= g_slice_new (Tuple
);
1089 tuple
->ast
.class = &tuple_class
;
1090 tuple
->children
= NULL
;
1091 tuple
->n_children
= 0;
1093 token_stream_assert (stream
, "(");
1094 while (!token_stream_consume (stream
, ")"))
1099 !token_stream_require (stream
, ",",
1100 " or ')' to follow tuple element",
1104 child
= parse (stream
, app
, error
);
1109 ast_array_append (&tuple
->children
, &tuple
->n_children
, child
);
1111 /* the first time, we absolutely require a comma, so grab it here
1112 * and leave need_comma = FALSE so that the code above doesn't
1113 * require a second comma.
1115 * the second and remaining times, we set need_comma = TRUE.
1119 if (!token_stream_require (stream
, ",",
1120 " after first tuple element", error
))
1129 return (AST
*) tuple
;
1132 ast_array_free (tuple
->children
, tuple
->n_children
);
1133 g_slice_free (Tuple
, tuple
);
1146 variant_get_pattern (AST
*ast
,
1149 return g_strdup ("Mv");
1153 variant_get_value (AST
*ast
,
1154 const GVariantType
*type
,
1157 Variant
*variant
= (Variant
*) ast
;
1160 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_VARIANT
))
1161 return ast_type_error (ast
, type
, error
);
1163 child
= ast_resolve (variant
->value
, error
);
1168 return g_variant_new_variant (child
);
1172 variant_free (AST
*ast
)
1174 Variant
*variant
= (Variant
*) ast
;
1176 ast_free (variant
->value
);
1177 g_slice_free (Variant
, variant
);
1181 variant_parse (TokenStream
*stream
,
1185 static const ASTClass variant_class
= {
1186 variant_get_pattern
,
1187 maybe_wrapper
, variant_get_value
,
1193 token_stream_assert (stream
, "<");
1194 value
= parse (stream
, app
, error
);
1199 if (!token_stream_require (stream
, ">", " to follow variant value", error
))
1205 variant
= g_slice_new (Variant
);
1206 variant
->ast
.class = &variant_class
;
1207 variant
->value
= value
;
1209 return (AST
*) variant
;
1222 dictionary_get_pattern (AST
*ast
,
1225 Dictionary
*dict
= (Dictionary
*) ast
;
1226 gchar
*value_pattern
;
1231 if (dict
->n_children
== 0)
1232 return g_strdup ("Ma{**}");
1234 key_pattern
= ast_array_get_pattern (dict
->keys
,
1235 abs (dict
->n_children
),
1238 if (key_pattern
== NULL
)
1241 /* we can not have maybe keys */
1242 if (key_pattern
[0] == 'M')
1243 key_char
= key_pattern
[1];
1245 key_char
= key_pattern
[0];
1247 g_free (key_pattern
);
1250 * plus undetermined number type and undetermined string type.
1252 if (!strchr ("bynqiuxthdsogNS", key_char
))
1254 ast_set_error (ast
, error
, NULL
,
1255 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED
,
1256 "dictionary keys must have basic types");
1260 value_pattern
= ast_get_pattern (dict
->values
[0], error
);
1262 if (value_pattern
== NULL
)
1265 result
= g_strdup_printf ("M%s{%c%s}",
1266 dict
->n_children
> 0 ? "a" : "",
1267 key_char
, value_pattern
);
1268 g_free (value_pattern
);
1274 dictionary_get_value (AST
*ast
,
1275 const GVariantType
*type
,
1278 Dictionary
*dict
= (Dictionary
*) ast
;
1280 if (dict
->n_children
== -1)
1282 const GVariantType
*subtype
;
1283 GVariantBuilder builder
;
1286 if (!g_variant_type_is_dict_entry (type
))
1287 return ast_type_error (ast
, type
, error
);
1289 g_variant_builder_init (&builder
, type
);
1291 subtype
= g_variant_type_key (type
);
1292 if (!(subvalue
= ast_get_value (dict
->keys
[0], subtype
, error
)))
1294 g_variant_builder_clear (&builder
);
1297 g_variant_builder_add_value (&builder
, subvalue
);
1299 subtype
= g_variant_type_value (type
);
1300 if (!(subvalue
= ast_get_value (dict
->values
[0], subtype
, error
)))
1302 g_variant_builder_clear (&builder
);
1305 g_variant_builder_add_value (&builder
, subvalue
);
1307 return g_variant_builder_end (&builder
);
1311 const GVariantType
*entry
, *key
, *val
;
1312 GVariantBuilder builder
;
1315 if (!g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE_DICTIONARY
))
1316 return ast_type_error (ast
, type
, error
);
1318 entry
= g_variant_type_element (type
);
1319 key
= g_variant_type_key (entry
);
1320 val
= g_variant_type_value (entry
);
1322 g_variant_builder_init (&builder
, type
);
1324 for (i
= 0; i
< dict
->n_children
; i
++)
1328 g_variant_builder_open (&builder
, entry
);
1330 if (!(subvalue
= ast_get_value (dict
->keys
[i
], key
, error
)))
1332 g_variant_builder_clear (&builder
);
1335 g_variant_builder_add_value (&builder
, subvalue
);
1337 if (!(subvalue
= ast_get_value (dict
->values
[i
], val
, error
)))
1339 g_variant_builder_clear (&builder
);
1342 g_variant_builder_add_value (&builder
, subvalue
);
1343 g_variant_builder_close (&builder
);
1346 return g_variant_builder_end (&builder
);
1351 dictionary_free (AST
*ast
)
1353 Dictionary
*dict
= (Dictionary
*) ast
;
1356 if (dict
->n_children
> -1)
1357 n_children
= dict
->n_children
;
1361 ast_array_free (dict
->keys
, n_children
);
1362 ast_array_free (dict
->values
, n_children
);
1363 g_slice_free (Dictionary
, dict
);
1367 dictionary_parse (TokenStream
*stream
,
1371 static const ASTClass dictionary_class
= {
1372 dictionary_get_pattern
,
1373 maybe_wrapper
, dictionary_get_value
,
1376 gint n_keys
, n_values
;
1381 dict
= g_slice_new (Dictionary
);
1382 dict
->ast
.class = &dictionary_class
;
1384 dict
->values
= NULL
;
1385 n_keys
= n_values
= 0;
1387 token_stream_assert (stream
, "{");
1389 if (token_stream_consume (stream
, "}"))
1391 dict
->n_children
= 0;
1392 return (AST
*) dict
;
1395 if ((first
= parse (stream
, app
, error
)) == NULL
)
1398 ast_array_append (&dict
->keys
, &n_keys
, first
);
1400 only_one
= token_stream_consume (stream
, ",");
1402 !token_stream_require (stream
, ":",
1403 " or ',' to follow dictionary entry key",
1407 if ((first
= parse (stream
, app
, error
)) == NULL
)
1410 ast_array_append (&dict
->values
, &n_values
, first
);
1414 if (!token_stream_require (stream
, "}", " at end of dictionary entry",
1418 g_assert (n_keys
== 1 && n_values
== 1);
1419 dict
->n_children
= -1;
1421 return (AST
*) dict
;
1424 while (!token_stream_consume (stream
, "}"))
1428 if (!token_stream_require (stream
, ",",
1429 " or '}' to follow dictionary entry", error
))
1432 child
= parse (stream
, app
, error
);
1437 ast_array_append (&dict
->keys
, &n_keys
, child
);
1439 if (!token_stream_require (stream
, ":",
1440 " to follow dictionary entry key", error
))
1443 child
= parse (stream
, app
, error
);
1448 ast_array_append (&dict
->values
, &n_values
, child
);
1451 g_assert (n_keys
== n_values
);
1452 dict
->n_children
= n_keys
;
1454 return (AST
*) dict
;
1457 ast_array_free (dict
->keys
, n_keys
);
1458 ast_array_free (dict
->values
, n_values
);
1459 g_slice_free (Dictionary
, dict
);
1471 string_get_pattern (AST
*ast
,
1474 return g_strdup ("MS");
1478 string_get_value (AST
*ast
,
1479 const GVariantType
*type
,
1482 String
*string
= (String
*) ast
;
1484 if (g_variant_type_equal (type
, G_VARIANT_TYPE_STRING
))
1485 return g_variant_new_string (string
->string
);
1487 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_OBJECT_PATH
))
1489 if (!g_variant_is_object_path (string
->string
))
1491 ast_set_error (ast
, error
, NULL
,
1492 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH
,
1493 "not a valid object path");
1497 return g_variant_new_object_path (string
->string
);
1500 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_SIGNATURE
))
1502 if (!g_variant_is_signature (string
->string
))
1504 ast_set_error (ast
, error
, NULL
,
1505 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE
,
1506 "not a valid signature");
1510 return g_variant_new_signature (string
->string
);
1514 return ast_type_error (ast
, type
, error
);
1518 string_free (AST
*ast
)
1520 String
*string
= (String
*) ast
;
1522 g_free (string
->string
);
1523 g_slice_free (String
, string
);
1527 unicode_unescape (const gchar
*src
,
1541 g_assert (length
< sizeof (buffer
));
1542 strncpy (buffer
, src
+ *src_ofs
, length
);
1543 buffer
[length
] = '\0';
1545 value
= g_ascii_strtoull (buffer
, &end
, 0x10);
1547 if (value
== 0 || end
!= buffer
+ length
)
1549 parser_set_error (error
, ref
, NULL
,
1550 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1551 "invalid %d-character unicode escape", length
);
1555 g_assert (value
<= G_MAXUINT32
);
1557 *dest_ofs
+= g_unichar_to_utf8 (value
, dest
+ *dest_ofs
);
1564 string_parse (TokenStream
*stream
,
1568 static const ASTClass string_class
= {
1570 maybe_wrapper
, string_get_value
,
1581 token_stream_start_ref (stream
, &ref
);
1582 token
= token_stream_get (stream
);
1583 token_stream_end_ref (stream
, &ref
);
1584 length
= strlen (token
);
1587 str
= g_malloc (length
);
1588 g_assert (quote
== '"' || quote
== '\'');
1591 while (token
[i
] != quote
)
1595 parser_set_error (error
, &ref
, NULL
,
1596 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1597 "unterminated string constant");
1606 parser_set_error (error
, &ref
, NULL
,
1607 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1608 "unterminated string constant");
1614 if (!unicode_unescape (token
, &i
, str
, &j
, 4, &ref
, error
))
1623 if (!unicode_unescape (token
, &i
, str
, &j
, 8, &ref
, error
))
1631 case 'a': str
[j
++] = '\a'; i
++; continue;
1632 case 'b': str
[j
++] = '\b'; i
++; continue;
1633 case 'f': str
[j
++] = '\f'; i
++; continue;
1634 case 'n': str
[j
++] = '\n'; i
++; continue;
1635 case 'r': str
[j
++] = '\r'; i
++; continue;
1636 case 't': str
[j
++] = '\t'; i
++; continue;
1637 case 'v': str
[j
++] = '\v'; i
++; continue;
1638 case '\n': i
++; continue;
1642 str
[j
++] = token
[i
++];
1647 string
= g_slice_new (String
);
1648 string
->ast
.class = &string_class
;
1649 string
->string
= str
;
1651 token_stream_next (stream
);
1653 return (AST
*) string
;
1663 bytestring_get_pattern (AST
*ast
,
1666 return g_strdup ("May");
1670 bytestring_get_value (AST
*ast
,
1671 const GVariantType
*type
,
1674 ByteString
*string
= (ByteString
*) ast
;
1676 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BYTESTRING
))
1677 return ast_type_error (ast
, type
, error
);
1679 return g_variant_new_bytestring (string
->string
);
1683 bytestring_free (AST
*ast
)
1685 ByteString
*string
= (ByteString
*) ast
;
1687 g_free (string
->string
);
1688 g_slice_free (ByteString
, string
);
1692 bytestring_parse (TokenStream
*stream
,
1696 static const ASTClass bytestring_class
= {
1697 bytestring_get_pattern
,
1698 maybe_wrapper
, bytestring_get_value
,
1709 token_stream_start_ref (stream
, &ref
);
1710 token
= token_stream_get (stream
);
1711 token_stream_end_ref (stream
, &ref
);
1712 g_assert (token
[0] == 'b');
1713 length
= strlen (token
);
1716 str
= g_malloc (length
);
1717 g_assert (quote
== '"' || quote
== '\'');
1720 while (token
[i
] != quote
)
1724 parser_set_error (error
, &ref
, NULL
,
1725 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1726 "unterminated string constant");
1734 parser_set_error (error
, &ref
, NULL
,
1735 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1736 "unterminated string constant");
1740 case '0': case '1': case '2': case '3':
1741 case '4': case '5': case '6': case '7':
1743 /* up to 3 characters */
1744 guchar val
= token
[i
++] - '0';
1746 if ('0' <= token
[i
] && token
[i
] < '8')
1747 val
= (val
<< 3) | (token
[i
++] - '0');
1749 if ('0' <= token
[i
] && token
[i
] < '8')
1750 val
= (val
<< 3) | (token
[i
++] - '0');
1756 case 'a': str
[j
++] = '\a'; i
++; continue;
1757 case 'b': str
[j
++] = '\b'; i
++; continue;
1758 case 'f': str
[j
++] = '\f'; i
++; continue;
1759 case 'n': str
[j
++] = '\n'; i
++; continue;
1760 case 'r': str
[j
++] = '\r'; i
++; continue;
1761 case 't': str
[j
++] = '\t'; i
++; continue;
1762 case 'v': str
[j
++] = '\v'; i
++; continue;
1763 case '\n': i
++; continue;
1767 str
[j
++] = token
[i
++];
1772 string
= g_slice_new (ByteString
);
1773 string
->ast
.class = &bytestring_class
;
1774 string
->string
= str
;
1776 token_stream_next (stream
);
1778 return (AST
*) string
;
1789 number_get_pattern (AST
*ast
,
1792 Number
*number
= (Number
*) ast
;
1794 if (strchr (number
->token
, '.') ||
1795 (!g_str_has_prefix (number
->token
, "0x") && strchr (number
->token
, 'e')) ||
1796 strstr (number
->token
, "inf") ||
1797 strstr (number
->token
, "nan"))
1798 return g_strdup ("Md");
1800 return g_strdup ("MN");
1804 number_overflow (AST
*ast
,
1805 const GVariantType
*type
,
1808 ast_set_error (ast
, error
, NULL
,
1809 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE
,
1810 "number out of range for type '%c'",
1811 g_variant_type_peek_string (type
)[0]);
1816 number_get_value (AST
*ast
,
1817 const GVariantType
*type
,
1820 Number
*number
= (Number
*) ast
;
1828 token
= number
->token
;
1830 if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
1835 dbl_val
= g_ascii_strtod (token
, &end
);
1836 if (dbl_val
!= 0.0 && errno
== ERANGE
)
1838 ast_set_error (ast
, error
, NULL
,
1839 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1840 "number too big for any type");
1844 /* silence uninitialised warnings... */
1851 negative
= token
[0] == '-';
1852 if (token
[0] == '-')
1856 abs_val
= g_ascii_strtoull (token
, &end
, 0);
1857 if (abs_val
== G_MAXUINT64
&& errno
== ERANGE
)
1859 ast_set_error (ast
, error
, NULL
,
1860 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1861 "integer too big for any type");
1868 /* silence uninitialised warning... */
1876 ref
= ast
->source_ref
;
1877 ref
.start
+= end
- number
->token
;
1878 ref
.end
= ref
.start
+ 1;
1880 parser_set_error (error
, &ref
, NULL
,
1881 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1882 "invalid character in number");
1887 return g_variant_new_double (dbl_val
);
1889 switch (*g_variant_type_peek_string (type
))
1892 if (negative
|| abs_val
> G_MAXUINT8
)
1893 return number_overflow (ast
, type
, error
);
1894 return g_variant_new_byte (abs_val
);
1897 if (abs_val
- negative
> G_MAXINT16
)
1898 return number_overflow (ast
, type
, error
);
1899 return g_variant_new_int16 (negative
? -abs_val
: abs_val
);
1902 if (negative
|| abs_val
> G_MAXUINT16
)
1903 return number_overflow (ast
, type
, error
);
1904 return g_variant_new_uint16 (abs_val
);
1907 if (abs_val
- negative
> G_MAXINT32
)
1908 return number_overflow (ast
, type
, error
);
1909 return g_variant_new_int32 (negative
? -abs_val
: abs_val
);
1912 if (negative
|| abs_val
> G_MAXUINT32
)
1913 return number_overflow (ast
, type
, error
);
1914 return g_variant_new_uint32 (abs_val
);
1917 if (abs_val
- negative
> G_MAXINT64
)
1918 return number_overflow (ast
, type
, error
);
1919 return g_variant_new_int64 (negative
? -abs_val
: abs_val
);
1923 return number_overflow (ast
, type
, error
);
1924 return g_variant_new_uint64 (abs_val
);
1927 if (abs_val
- negative
> G_MAXINT32
)
1928 return number_overflow (ast
, type
, error
);
1929 return g_variant_new_handle (negative
? -abs_val
: abs_val
);
1932 return ast_type_error (ast
, type
, error
);
1937 number_free (AST
*ast
)
1939 Number
*number
= (Number
*) ast
;
1941 g_free (number
->token
);
1942 g_slice_free (Number
, number
);
1946 number_parse (TokenStream
*stream
,
1950 static const ASTClass number_class
= {
1952 maybe_wrapper
, number_get_value
,
1957 number
= g_slice_new (Number
);
1958 number
->ast
.class = &number_class
;
1959 number
->token
= token_stream_get (stream
);
1960 token_stream_next (stream
);
1962 return (AST
*) number
;
1972 boolean_get_pattern (AST
*ast
,
1975 return g_strdup ("Mb");
1979 boolean_get_value (AST
*ast
,
1980 const GVariantType
*type
,
1983 Boolean
*boolean
= (Boolean
*) ast
;
1985 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
1986 return ast_type_error (ast
, type
, error
);
1988 return g_variant_new_boolean (boolean
->value
);
1992 boolean_free (AST
*ast
)
1994 Boolean
*boolean
= (Boolean
*) ast
;
1996 g_slice_free (Boolean
, boolean
);
2000 boolean_new (gboolean value
)
2002 static const ASTClass boolean_class
= {
2003 boolean_get_pattern
,
2004 maybe_wrapper
, boolean_get_value
,
2009 boolean
= g_slice_new (Boolean
);
2010 boolean
->ast
.class = &boolean_class
;
2011 boolean
->value
= value
;
2013 return (AST
*) boolean
;
2024 positional_get_pattern (AST
*ast
,
2027 Positional
*positional
= (Positional
*) ast
;
2029 return g_strdup (g_variant_get_type_string (positional
->value
));
2033 positional_get_value (AST
*ast
,
2034 const GVariantType
*type
,
2037 Positional
*positional
= (Positional
*) ast
;
2040 g_assert (positional
->value
!= NULL
);
2042 if G_UNLIKELY (!g_variant_is_of_type (positional
->value
, type
))
2043 return ast_type_error (ast
, type
, error
);
2045 /* NOTE: if _get is called more than once then
2046 * things get messed up with respect to floating refs.
2048 * fortunately, this function should only ever get called once.
2050 g_assert (positional
->value
!= NULL
);
2051 value
= positional
->value
;
2052 positional
->value
= NULL
;
2058 positional_free (AST
*ast
)
2060 Positional
*positional
= (Positional
*) ast
;
2062 /* if positional->value is set, just leave it.
2063 * memory management doesn't matter in case of programmer error.
2065 g_slice_free (Positional
, positional
);
2069 positional_parse (TokenStream
*stream
,
2073 static const ASTClass positional_class
= {
2074 positional_get_pattern
,
2075 positional_get_value
, NULL
,
2078 Positional
*positional
;
2079 const gchar
*endptr
;
2082 token
= token_stream_get (stream
);
2083 g_assert (token
[0] == '%');
2085 positional
= g_slice_new (Positional
);
2086 positional
->ast
.class = &positional_class
;
2087 positional
->value
= g_variant_new_va (token
+ 1, &endptr
, app
);
2089 if (*endptr
|| positional
->value
== NULL
)
2091 token_stream_set_error (stream
, error
, TRUE
,
2092 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING
,
2093 "invalid GVariant format string");
2094 /* memory management doesn't matter in case of programmer error. */
2098 token_stream_next (stream
);
2101 return (AST
*) positional
;
2113 typedecl_get_pattern (AST
*ast
,
2116 TypeDecl
*decl
= (TypeDecl
*) ast
;
2118 return g_variant_type_dup_string (decl
->type
);
2122 typedecl_get_value (AST
*ast
,
2123 const GVariantType
*type
,
2126 TypeDecl
*decl
= (TypeDecl
*) ast
;
2128 return ast_get_value (decl
->child
, type
, error
);
2132 typedecl_free (AST
*ast
)
2134 TypeDecl
*decl
= (TypeDecl
*) ast
;
2136 ast_free (decl
->child
);
2137 g_variant_type_free (decl
->type
);
2138 g_slice_free (TypeDecl
, decl
);
2142 typedecl_parse (TokenStream
*stream
,
2146 static const ASTClass typedecl_class
= {
2147 typedecl_get_pattern
,
2148 typedecl_get_value
, NULL
,
2155 if (token_stream_peek (stream
, '@'))
2159 token
= token_stream_get (stream
);
2161 if (!g_variant_type_string_is_valid (token
+ 1))
2163 token_stream_set_error (stream
, error
, TRUE
,
2164 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING
,
2165 "invalid type declaration");
2171 type
= g_variant_type_new (token
+ 1);
2173 if (!g_variant_type_is_definite (type
))
2175 token_stream_set_error (stream
, error
, TRUE
,
2176 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED
,
2177 "type declarations must be definite");
2178 g_variant_type_free (type
);
2184 token_stream_next (stream
);
2189 if (token_stream_consume (stream
, "boolean"))
2190 type
= g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN
);
2192 else if (token_stream_consume (stream
, "byte"))
2193 type
= g_variant_type_copy (G_VARIANT_TYPE_BYTE
);
2195 else if (token_stream_consume (stream
, "int16"))
2196 type
= g_variant_type_copy (G_VARIANT_TYPE_INT16
);
2198 else if (token_stream_consume (stream
, "uint16"))
2199 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT16
);
2201 else if (token_stream_consume (stream
, "int32"))
2202 type
= g_variant_type_copy (G_VARIANT_TYPE_INT32
);
2204 else if (token_stream_consume (stream
, "handle"))
2205 type
= g_variant_type_copy (G_VARIANT_TYPE_HANDLE
);
2207 else if (token_stream_consume (stream
, "uint32"))
2208 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT32
);
2210 else if (token_stream_consume (stream
, "int64"))
2211 type
= g_variant_type_copy (G_VARIANT_TYPE_INT64
);
2213 else if (token_stream_consume (stream
, "uint64"))
2214 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT64
);
2216 else if (token_stream_consume (stream
, "double"))
2217 type
= g_variant_type_copy (G_VARIANT_TYPE_DOUBLE
);
2219 else if (token_stream_consume (stream
, "string"))
2220 type
= g_variant_type_copy (G_VARIANT_TYPE_STRING
);
2222 else if (token_stream_consume (stream
, "objectpath"))
2223 type
= g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH
);
2225 else if (token_stream_consume (stream
, "signature"))
2226 type
= g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE
);
2230 token_stream_set_error (stream
, error
, TRUE
,
2231 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
2237 if ((child
= parse (stream
, app
, error
)) == NULL
)
2239 g_variant_type_free (type
);
2243 decl
= g_slice_new (TypeDecl
);
2244 decl
->ast
.class = &typedecl_class
;
2246 decl
->child
= child
;
2248 return (AST
*) decl
;
2252 parse (TokenStream
*stream
,
2256 SourceRef source_ref
;
2259 token_stream_prepare (stream
);
2260 token_stream_start_ref (stream
, &source_ref
);
2262 if (token_stream_peek (stream
, '['))
2263 result
= array_parse (stream
, app
, error
);
2265 else if (token_stream_peek (stream
, '('))
2266 result
= tuple_parse (stream
, app
, error
);
2268 else if (token_stream_peek (stream
, '<'))
2269 result
= variant_parse (stream
, app
, error
);
2271 else if (token_stream_peek (stream
, '{'))
2272 result
= dictionary_parse (stream
, app
, error
);
2274 else if (app
&& token_stream_peek (stream
, '%'))
2275 result
= positional_parse (stream
, app
, error
);
2277 else if (token_stream_consume (stream
, "true"))
2278 result
= boolean_new (TRUE
);
2280 else if (token_stream_consume (stream
, "false"))
2281 result
= boolean_new (FALSE
);
2283 else if (token_stream_is_numeric (stream
) ||
2284 token_stream_peek_string (stream
, "inf") ||
2285 token_stream_peek_string (stream
, "nan"))
2286 result
= number_parse (stream
, app
, error
);
2288 else if (token_stream_peek (stream
, 'n') ||
2289 token_stream_peek (stream
, 'j'))
2290 result
= maybe_parse (stream
, app
, error
);
2292 else if (token_stream_peek (stream
, '@') ||
2293 token_stream_is_keyword (stream
))
2294 result
= typedecl_parse (stream
, app
, error
);
2296 else if (token_stream_peek (stream
, '\'') ||
2297 token_stream_peek (stream
, '"'))
2298 result
= string_parse (stream
, app
, error
);
2300 else if (token_stream_peek2 (stream
, 'b', '\'') ||
2301 token_stream_peek2 (stream
, 'b', '"'))
2302 result
= bytestring_parse (stream
, app
, error
);
2306 token_stream_set_error (stream
, error
, FALSE
,
2307 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED
,
2314 token_stream_end_ref (stream
, &source_ref
);
2315 result
->source_ref
= source_ref
;
2323 * @type: (nullable): a #GVariantType, or %NULL
2324 * @text: a string containing a GVariant in text form
2325 * @limit: (nullable): a pointer to the end of @text, or %NULL
2326 * @endptr: (nullable): a location to store the end pointer, or %NULL
2327 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2329 * Parses a #GVariant from a text representation.
2331 * A single #GVariant is parsed from the content of @text.
2333 * The format is described [here][gvariant-text].
2335 * The memory at @limit will never be accessed and the parser behaves as
2336 * if the character at @limit is the nul terminator. This has the
2337 * effect of bounding @text.
2339 * If @endptr is non-%NULL then @text is permitted to contain data
2340 * following the value that this function parses and @endptr will be
2341 * updated to point to the first character past the end of the text
2342 * parsed by this function. If @endptr is %NULL and there is extra data
2343 * then an error is returned.
2345 * If @type is non-%NULL then the value will be parsed to have that
2346 * type. This may result in additional parse errors (in the case that
2347 * the parsed value doesn't fit the type) but may also result in fewer
2348 * errors (in the case that the type would have been ambiguous, such as
2349 * with empty arrays).
2351 * In the event that the parsing is successful, the resulting #GVariant
2352 * is returned. It is never floating, and must be freed with
2353 * g_variant_unref().
2355 * In case of any error, %NULL will be returned. If @error is non-%NULL
2356 * then it will be set to reflect the error that occurred.
2358 * Officially, the language understood by the parser is "any string
2359 * produced by g_variant_print()".
2361 * Returns: a non-floating reference to a #GVariant, or %NULL
2364 g_variant_parse (const GVariantType
*type
,
2367 const gchar
**endptr
,
2370 TokenStream stream
= { 0, };
2371 GVariant
*result
= NULL
;
2374 g_return_val_if_fail (text
!= NULL
, NULL
);
2375 g_return_val_if_fail (text
== limit
|| text
!= NULL
, NULL
);
2377 stream
.start
= text
;
2378 stream
.stream
= text
;
2381 if ((ast
= parse (&stream
, NULL
, error
)))
2384 result
= ast_resolve (ast
, error
);
2386 result
= ast_get_value (ast
, type
, error
);
2390 g_variant_ref_sink (result
);
2394 while (stream
.stream
!= limit
&&
2395 g_ascii_isspace (*stream
.stream
))
2398 if (stream
.stream
!= limit
&& *stream
.stream
!= '\0')
2400 SourceRef ref
= { stream
.stream
- text
,
2401 stream
.stream
- text
};
2403 parser_set_error (error
, &ref
, NULL
,
2404 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END
,
2405 "expected end of input");
2406 g_variant_unref (result
);
2412 *endptr
= stream
.stream
;
2422 * g_variant_new_parsed_va:
2423 * @format: a text format #GVariant
2424 * @app: a pointer to a #va_list
2426 * Parses @format and returns the result.
2428 * This is the version of g_variant_new_parsed() intended to be used
2431 * The return value will be floating if it was a newly created GVariant
2432 * instance. In the case that @format simply specified the collection
2433 * of a #GVariant pointer (eg: @format was "%*") then the collected
2434 * #GVariant pointer will be returned unmodified, without adding any
2435 * additional references.
2437 * Note that the arguments in @app must be of the correct width for their types
2438 * specified in @format when collected into the #va_list. See
2439 * the [GVariant varargs documentation][gvariant-varargs].
2441 * In order to behave correctly in all cases it is necessary for the
2442 * calling function to g_variant_ref_sink() the return result before
2443 * returning control to the user that originally provided the pointer.
2444 * At this point, the caller will have their own full reference to the
2445 * result. This can also be done by adding the result to a container,
2446 * or by passing it to another g_variant_new() call.
2448 * Returns: a new, usually floating, #GVariant
2451 g_variant_new_parsed_va (const gchar
*format
,
2454 TokenStream stream
= { 0, };
2455 GVariant
*result
= NULL
;
2456 GError
*error
= NULL
;
2459 g_return_val_if_fail (format
!= NULL
, NULL
);
2460 g_return_val_if_fail (app
!= NULL
, NULL
);
2462 stream
.start
= format
;
2463 stream
.stream
= format
;
2466 if ((ast
= parse (&stream
, app
, &error
)))
2468 result
= ast_resolve (ast
, &error
);
2473 g_error ("g_variant_new_parsed: %s", error
->message
);
2476 g_error ("g_variant_new_parsed: trailing text after value");
2482 * g_variant_new_parsed:
2483 * @format: a text format #GVariant
2484 * @...: arguments as per @format
2486 * Parses @format and returns the result.
2488 * @format must be a text format #GVariant with one extension: at any
2489 * point that a value may appear in the text, a '%' character followed
2490 * by a GVariant format string (as per g_variant_new()) may appear. In
2491 * that case, the same arguments are collected from the argument list as
2492 * g_variant_new() would have collected.
2494 * Note that the arguments must be of the correct width for their types
2495 * specified in @format. This can be achieved by casting them. See
2496 * the [GVariant varargs documentation][gvariant-varargs].
2498 * Consider this simple example:
2499 * |[<!-- language="C" -->
2500 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2503 * In the example, the variable argument parameters are collected and
2504 * filled in as if they were part of the original string to produce the
2506 * |[<!-- language="C" -->
2507 * [('one', 1), ('two', 2), ('three', 3)]
2510 * This function is intended only to be used with @format as a string
2511 * literal. Any parse error is fatal to the calling process. If you
2512 * want to parse data from untrusted sources, use g_variant_parse().
2514 * You may not use this function to return, unmodified, a single
2515 * #GVariant pointer from the argument list. ie: @format may not solely
2516 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2519 * Returns: a new floating #GVariant instance
2522 g_variant_new_parsed (const gchar
*format
,
2528 va_start (ap
, format
);
2529 result
= g_variant_new_parsed_va (format
, &ap
);
2536 * g_variant_builder_add_parsed:
2537 * @builder: a #GVariantBuilder
2538 * @format: a text format #GVariant
2539 * @...: arguments as per @format
2541 * Adds to a #GVariantBuilder.
2543 * This call is a convenience wrapper that is exactly equivalent to
2544 * calling g_variant_new_parsed() followed by
2545 * g_variant_builder_add_value().
2547 * Note that the arguments must be of the correct width for their types
2548 * specified in @format_string. This can be achieved by casting them. See
2549 * the [GVariant varargs documentation][gvariant-varargs].
2551 * This function might be used as follows:
2553 * |[<!-- language="C" -->
2555 * make_pointless_dictionary (void)
2557 * GVariantBuilder builder;
2560 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2561 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2562 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2563 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2564 * return g_variant_builder_end (&builder);
2571 g_variant_builder_add_parsed (GVariantBuilder
*builder
,
2572 const gchar
*format
,
2577 va_start (ap
, format
);
2578 g_variant_builder_add_value (builder
, g_variant_new_parsed_va (format
, &ap
));
2583 parse_num (const gchar
*num
,
2590 bignum
= g_ascii_strtoll (num
, &endptr
, 10);
2592 if (endptr
!= limit
)
2595 if (bignum
< 0 || bignum
> G_MAXINT
)
2604 add_last_line (GString
*err
,
2607 const gchar
*last_nl
;
2611 /* This is an error at the end of input. If we have a file
2612 * with newlines, that's probably the empty string after the
2613 * last newline, which is not the most useful thing to show.
2615 * Instead, show the last line of non-whitespace that we have
2616 * and put the pointer at the end of it.
2618 chomped
= g_strchomp (g_strdup (str
));
2619 last_nl
= strrchr (chomped
, '\n');
2620 if (last_nl
== NULL
)
2625 /* Print the last line like so:
2630 g_string_append (err
, " ");
2632 g_string_append (err
, last_nl
);
2634 g_string_append (err
, "(empty input)");
2635 g_string_append (err
, "\n ");
2636 for (i
= 0; last_nl
[i
]; i
++)
2637 g_string_append_c (err
, ' ');
2638 g_string_append (err
, "^\n");
2643 add_lines_from_range (GString
*err
,
2645 const gchar
*start1
,
2647 const gchar
*start2
,
2650 while (str
< end1
|| str
< end2
)
2654 nl
= str
+ strcspn (str
, "\n");
2656 if ((start1
< nl
&& str
< end1
) || (start2
< nl
&& str
< end2
))
2660 /* We're going to print this line */
2661 g_string_append (err
, " ");
2662 g_string_append_len (err
, str
, nl
- str
);
2663 g_string_append (err
, "\n ");
2665 /* And add underlines... */
2666 for (s
= str
; s
< nl
; s
++)
2668 if ((start1
<= s
&& s
< end1
) || (start2
<= s
&& s
< end2
))
2669 g_string_append_c (err
, '^');
2671 g_string_append_c (err
, ' ');
2673 g_string_append_c (err
, '\n');
2684 * g_variant_parse_error_print_context:
2685 * @error: a #GError from the #GVariantParseError domain
2686 * @source_str: the string that was given to the parser
2688 * Pretty-prints a message showing the context of a #GVariant parse
2689 * error within the string for which parsing was attempted.
2691 * The resulting string is suitable for output to the console or other
2692 * monospace media where newlines are treated in the usual way.
2694 * The message will typically look something like one of the following:
2697 * unterminated string constant:
2705 * unable to find a common type:
2710 * The format of the message may change in a future version.
2712 * @error must have come from a failed attempt to g_variant_parse() and
2713 * @source_str must be exactly the same string that caused the error.
2714 * If @source_str was not nul-terminated when you passed it to
2715 * g_variant_parse() then you must add nul termination before using this
2718 * Returns: (transfer full): the printed message
2723 g_variant_parse_error_print_context (GError
*error
,
2724 const gchar
*source_str
)
2726 const gchar
*colon
, *dash
, *comma
;
2727 gboolean success
= FALSE
;
2730 g_return_val_if_fail (error
->domain
== G_VARIANT_PARSE_ERROR
, FALSE
);
2732 /* We can only have a limited number of possible types of ranges
2733 * emitted from the parser:
2735 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2736 * - a-b: -- usually errors from handling one single token
2737 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2739 * We never see, for example "a,c".
2742 colon
= strchr (error
->message
, ':');
2743 dash
= strchr (error
->message
, '-');
2744 comma
= strchr (error
->message
, ',');
2749 err
= g_string_new (colon
+ 1);
2750 g_string_append (err
, ":\n");
2752 if (dash
== NULL
|| colon
< dash
)
2756 /* we have a single point */
2757 if (!parse_num (error
->message
, colon
, &point
))
2760 if (point
>= strlen (source_str
))
2761 /* the error is at the end of the input */
2762 add_last_line (err
, source_str
);
2764 /* otherwise just treat it as a error at a thin range */
2765 add_lines_from_range (err
, source_str
, source_str
+ point
, source_str
+ point
+ 1, NULL
, NULL
);
2769 /* We have one or two ranges... */
2770 if (comma
&& comma
< colon
)
2772 gint start1
, end1
, start2
, end2
;
2776 dash2
= strchr (comma
, '-');
2778 if (!parse_num (error
->message
, dash
, &start1
) || !parse_num (dash
+ 1, comma
, &end1
) ||
2779 !parse_num (comma
+ 1, dash2
, &start2
) || !parse_num (dash2
+ 1, colon
, &end2
))
2782 add_lines_from_range (err
, source_str
,
2783 source_str
+ start1
, source_str
+ end1
,
2784 source_str
+ start2
, source_str
+ end2
);
2791 if (!parse_num (error
->message
, dash
, &start
) || !parse_num (dash
+ 1, colon
, &end
))
2794 add_lines_from_range (err
, source_str
, source_str
+ start
, source_str
+ end
, NULL
, NULL
);
2801 return g_string_free (err
, !success
);