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
->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");
1735 parser_set_error (error
, &ref
, NULL
,
1736 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1737 "unterminated string constant");
1742 case '0': case '1': case '2': case '3':
1743 case '4': case '5': case '6': case '7':
1745 /* up to 3 characters */
1746 guchar val
= token
[i
++] - '0';
1748 if ('0' <= token
[i
] && token
[i
] < '8')
1749 val
= (val
<< 3) | (token
[i
++] - '0');
1751 if ('0' <= token
[i
] && token
[i
] < '8')
1752 val
= (val
<< 3) | (token
[i
++] - '0');
1758 case 'a': str
[j
++] = '\a'; i
++; continue;
1759 case 'b': str
[j
++] = '\b'; i
++; continue;
1760 case 'f': str
[j
++] = '\f'; i
++; continue;
1761 case 'n': str
[j
++] = '\n'; i
++; continue;
1762 case 'r': str
[j
++] = '\r'; i
++; continue;
1763 case 't': str
[j
++] = '\t'; i
++; continue;
1764 case 'v': str
[j
++] = '\v'; i
++; continue;
1765 case '\n': i
++; continue;
1769 str
[j
++] = token
[i
++];
1774 string
= g_slice_new (ByteString
);
1775 string
->ast
.class = &bytestring_class
;
1776 string
->string
= str
;
1778 token_stream_next (stream
);
1780 return (AST
*) string
;
1791 number_get_pattern (AST
*ast
,
1794 Number
*number
= (Number
*) ast
;
1796 if (strchr (number
->token
, '.') ||
1797 (!g_str_has_prefix (number
->token
, "0x") && strchr (number
->token
, 'e')) ||
1798 strstr (number
->token
, "inf") ||
1799 strstr (number
->token
, "nan"))
1800 return g_strdup ("Md");
1802 return g_strdup ("MN");
1806 number_overflow (AST
*ast
,
1807 const GVariantType
*type
,
1810 ast_set_error (ast
, error
, NULL
,
1811 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE
,
1812 "number out of range for type '%c'",
1813 g_variant_type_peek_string (type
)[0]);
1818 number_get_value (AST
*ast
,
1819 const GVariantType
*type
,
1822 Number
*number
= (Number
*) ast
;
1830 token
= number
->token
;
1832 if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
1837 dbl_val
= g_ascii_strtod (token
, &end
);
1838 if (dbl_val
!= 0.0 && errno
== ERANGE
)
1840 ast_set_error (ast
, error
, NULL
,
1841 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1842 "number too big for any type");
1846 /* silence uninitialised warnings... */
1853 negative
= token
[0] == '-';
1854 if (token
[0] == '-')
1858 abs_val
= g_ascii_strtoull (token
, &end
, 0);
1859 if (abs_val
== G_MAXUINT64
&& errno
== ERANGE
)
1861 ast_set_error (ast
, error
, NULL
,
1862 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1863 "integer too big for any type");
1870 /* silence uninitialised warning... */
1878 ref
= ast
->source_ref
;
1879 ref
.start
+= end
- number
->token
;
1880 ref
.end
= ref
.start
+ 1;
1882 parser_set_error (error
, &ref
, NULL
,
1883 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1884 "invalid character in number");
1889 return g_variant_new_double (dbl_val
);
1891 switch (*g_variant_type_peek_string (type
))
1894 if (negative
|| abs_val
> G_MAXUINT8
)
1895 return number_overflow (ast
, type
, error
);
1896 return g_variant_new_byte (abs_val
);
1899 if (abs_val
- negative
> G_MAXINT16
)
1900 return number_overflow (ast
, type
, error
);
1901 return g_variant_new_int16 (negative
? -abs_val
: abs_val
);
1904 if (negative
|| abs_val
> G_MAXUINT16
)
1905 return number_overflow (ast
, type
, error
);
1906 return g_variant_new_uint16 (abs_val
);
1909 if (abs_val
- negative
> G_MAXINT32
)
1910 return number_overflow (ast
, type
, error
);
1911 return g_variant_new_int32 (negative
? -abs_val
: abs_val
);
1914 if (negative
|| abs_val
> G_MAXUINT32
)
1915 return number_overflow (ast
, type
, error
);
1916 return g_variant_new_uint32 (abs_val
);
1919 if (abs_val
- negative
> G_MAXINT64
)
1920 return number_overflow (ast
, type
, error
);
1921 return g_variant_new_int64 (negative
? -abs_val
: abs_val
);
1925 return number_overflow (ast
, type
, error
);
1926 return g_variant_new_uint64 (abs_val
);
1929 if (abs_val
- negative
> G_MAXINT32
)
1930 return number_overflow (ast
, type
, error
);
1931 return g_variant_new_handle (negative
? -abs_val
: abs_val
);
1934 return ast_type_error (ast
, type
, error
);
1939 number_free (AST
*ast
)
1941 Number
*number
= (Number
*) ast
;
1943 g_free (number
->token
);
1944 g_slice_free (Number
, number
);
1948 number_parse (TokenStream
*stream
,
1952 static const ASTClass number_class
= {
1954 maybe_wrapper
, number_get_value
,
1959 number
= g_slice_new (Number
);
1960 number
->ast
.class = &number_class
;
1961 number
->token
= token_stream_get (stream
);
1962 token_stream_next (stream
);
1964 return (AST
*) number
;
1974 boolean_get_pattern (AST
*ast
,
1977 return g_strdup ("Mb");
1981 boolean_get_value (AST
*ast
,
1982 const GVariantType
*type
,
1985 Boolean
*boolean
= (Boolean
*) ast
;
1987 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
1988 return ast_type_error (ast
, type
, error
);
1990 return g_variant_new_boolean (boolean
->value
);
1994 boolean_free (AST
*ast
)
1996 Boolean
*boolean
= (Boolean
*) ast
;
1998 g_slice_free (Boolean
, boolean
);
2002 boolean_new (gboolean value
)
2004 static const ASTClass boolean_class
= {
2005 boolean_get_pattern
,
2006 maybe_wrapper
, boolean_get_value
,
2011 boolean
= g_slice_new (Boolean
);
2012 boolean
->ast
.class = &boolean_class
;
2013 boolean
->value
= value
;
2015 return (AST
*) boolean
;
2026 positional_get_pattern (AST
*ast
,
2029 Positional
*positional
= (Positional
*) ast
;
2031 return g_strdup (g_variant_get_type_string (positional
->value
));
2035 positional_get_value (AST
*ast
,
2036 const GVariantType
*type
,
2039 Positional
*positional
= (Positional
*) ast
;
2042 g_assert (positional
->value
!= NULL
);
2044 if G_UNLIKELY (!g_variant_is_of_type (positional
->value
, type
))
2045 return ast_type_error (ast
, type
, error
);
2047 /* NOTE: if _get is called more than once then
2048 * things get messed up with respect to floating refs.
2050 * fortunately, this function should only ever get called once.
2052 g_assert (positional
->value
!= NULL
);
2053 value
= positional
->value
;
2054 positional
->value
= NULL
;
2060 positional_free (AST
*ast
)
2062 Positional
*positional
= (Positional
*) ast
;
2064 /* if positional->value is set, just leave it.
2065 * memory management doesn't matter in case of programmer error.
2067 g_slice_free (Positional
, positional
);
2071 positional_parse (TokenStream
*stream
,
2075 static const ASTClass positional_class
= {
2076 positional_get_pattern
,
2077 positional_get_value
, NULL
,
2080 Positional
*positional
;
2081 const gchar
*endptr
;
2084 token
= token_stream_get (stream
);
2085 g_assert (token
[0] == '%');
2087 positional
= g_slice_new (Positional
);
2088 positional
->ast
.class = &positional_class
;
2089 positional
->value
= g_variant_new_va (token
+ 1, &endptr
, app
);
2091 if (*endptr
|| positional
->value
== NULL
)
2093 token_stream_set_error (stream
, error
, TRUE
,
2094 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING
,
2095 "invalid GVariant format string");
2096 /* memory management doesn't matter in case of programmer error. */
2100 token_stream_next (stream
);
2103 return (AST
*) positional
;
2115 typedecl_get_pattern (AST
*ast
,
2118 TypeDecl
*decl
= (TypeDecl
*) ast
;
2120 return g_variant_type_dup_string (decl
->type
);
2124 typedecl_get_value (AST
*ast
,
2125 const GVariantType
*type
,
2128 TypeDecl
*decl
= (TypeDecl
*) ast
;
2130 return ast_get_value (decl
->child
, type
, error
);
2134 typedecl_free (AST
*ast
)
2136 TypeDecl
*decl
= (TypeDecl
*) ast
;
2138 ast_free (decl
->child
);
2139 g_variant_type_free (decl
->type
);
2140 g_slice_free (TypeDecl
, decl
);
2144 typedecl_parse (TokenStream
*stream
,
2148 static const ASTClass typedecl_class
= {
2149 typedecl_get_pattern
,
2150 typedecl_get_value
, NULL
,
2157 if (token_stream_peek (stream
, '@'))
2161 token
= token_stream_get (stream
);
2163 if (!g_variant_type_string_is_valid (token
+ 1))
2165 token_stream_set_error (stream
, error
, TRUE
,
2166 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING
,
2167 "invalid type declaration");
2173 type
= g_variant_type_new (token
+ 1);
2175 if (!g_variant_type_is_definite (type
))
2177 token_stream_set_error (stream
, error
, TRUE
,
2178 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED
,
2179 "type declarations must be definite");
2180 g_variant_type_free (type
);
2186 token_stream_next (stream
);
2191 if (token_stream_consume (stream
, "boolean"))
2192 type
= g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN
);
2194 else if (token_stream_consume (stream
, "byte"))
2195 type
= g_variant_type_copy (G_VARIANT_TYPE_BYTE
);
2197 else if (token_stream_consume (stream
, "int16"))
2198 type
= g_variant_type_copy (G_VARIANT_TYPE_INT16
);
2200 else if (token_stream_consume (stream
, "uint16"))
2201 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT16
);
2203 else if (token_stream_consume (stream
, "int32"))
2204 type
= g_variant_type_copy (G_VARIANT_TYPE_INT32
);
2206 else if (token_stream_consume (stream
, "handle"))
2207 type
= g_variant_type_copy (G_VARIANT_TYPE_HANDLE
);
2209 else if (token_stream_consume (stream
, "uint32"))
2210 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT32
);
2212 else if (token_stream_consume (stream
, "int64"))
2213 type
= g_variant_type_copy (G_VARIANT_TYPE_INT64
);
2215 else if (token_stream_consume (stream
, "uint64"))
2216 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT64
);
2218 else if (token_stream_consume (stream
, "double"))
2219 type
= g_variant_type_copy (G_VARIANT_TYPE_DOUBLE
);
2221 else if (token_stream_consume (stream
, "string"))
2222 type
= g_variant_type_copy (G_VARIANT_TYPE_STRING
);
2224 else if (token_stream_consume (stream
, "objectpath"))
2225 type
= g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH
);
2227 else if (token_stream_consume (stream
, "signature"))
2228 type
= g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE
);
2232 token_stream_set_error (stream
, error
, TRUE
,
2233 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
2239 if ((child
= parse (stream
, app
, error
)) == NULL
)
2241 g_variant_type_free (type
);
2245 decl
= g_slice_new (TypeDecl
);
2246 decl
->ast
.class = &typedecl_class
;
2248 decl
->child
= child
;
2250 return (AST
*) decl
;
2254 parse (TokenStream
*stream
,
2258 SourceRef source_ref
;
2261 token_stream_prepare (stream
);
2262 token_stream_start_ref (stream
, &source_ref
);
2264 if (token_stream_peek (stream
, '['))
2265 result
= array_parse (stream
, app
, error
);
2267 else if (token_stream_peek (stream
, '('))
2268 result
= tuple_parse (stream
, app
, error
);
2270 else if (token_stream_peek (stream
, '<'))
2271 result
= variant_parse (stream
, app
, error
);
2273 else if (token_stream_peek (stream
, '{'))
2274 result
= dictionary_parse (stream
, app
, error
);
2276 else if (app
&& token_stream_peek (stream
, '%'))
2277 result
= positional_parse (stream
, app
, error
);
2279 else if (token_stream_consume (stream
, "true"))
2280 result
= boolean_new (TRUE
);
2282 else if (token_stream_consume (stream
, "false"))
2283 result
= boolean_new (FALSE
);
2285 else if (token_stream_is_numeric (stream
) ||
2286 token_stream_peek_string (stream
, "inf") ||
2287 token_stream_peek_string (stream
, "nan"))
2288 result
= number_parse (stream
, app
, error
);
2290 else if (token_stream_peek (stream
, 'n') ||
2291 token_stream_peek (stream
, 'j'))
2292 result
= maybe_parse (stream
, app
, error
);
2294 else if (token_stream_peek (stream
, '@') ||
2295 token_stream_is_keyword (stream
))
2296 result
= typedecl_parse (stream
, app
, error
);
2298 else if (token_stream_peek (stream
, '\'') ||
2299 token_stream_peek (stream
, '"'))
2300 result
= string_parse (stream
, app
, error
);
2302 else if (token_stream_peek2 (stream
, 'b', '\'') ||
2303 token_stream_peek2 (stream
, 'b', '"'))
2304 result
= bytestring_parse (stream
, app
, error
);
2308 token_stream_set_error (stream
, error
, FALSE
,
2309 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED
,
2316 token_stream_end_ref (stream
, &source_ref
);
2317 result
->source_ref
= source_ref
;
2325 * @type: (nullable): a #GVariantType, or %NULL
2326 * @text: a string containing a GVariant in text form
2327 * @limit: (nullable): a pointer to the end of @text, or %NULL
2328 * @endptr: (nullable): a location to store the end pointer, or %NULL
2329 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2331 * Parses a #GVariant from a text representation.
2333 * A single #GVariant is parsed from the content of @text.
2335 * The format is described [here][gvariant-text].
2337 * The memory at @limit will never be accessed and the parser behaves as
2338 * if the character at @limit is the nul terminator. This has the
2339 * effect of bounding @text.
2341 * If @endptr is non-%NULL then @text is permitted to contain data
2342 * following the value that this function parses and @endptr will be
2343 * updated to point to the first character past the end of the text
2344 * parsed by this function. If @endptr is %NULL and there is extra data
2345 * then an error is returned.
2347 * If @type is non-%NULL then the value will be parsed to have that
2348 * type. This may result in additional parse errors (in the case that
2349 * the parsed value doesn't fit the type) but may also result in fewer
2350 * errors (in the case that the type would have been ambiguous, such as
2351 * with empty arrays).
2353 * In the event that the parsing is successful, the resulting #GVariant
2354 * is returned. It is never floating, and must be freed with
2355 * g_variant_unref().
2357 * In case of any error, %NULL will be returned. If @error is non-%NULL
2358 * then it will be set to reflect the error that occurred.
2360 * Officially, the language understood by the parser is "any string
2361 * produced by g_variant_print()".
2363 * Returns: a non-floating reference to a #GVariant, or %NULL
2366 g_variant_parse (const GVariantType
*type
,
2369 const gchar
**endptr
,
2372 TokenStream stream
= { 0, };
2373 GVariant
*result
= NULL
;
2376 g_return_val_if_fail (text
!= NULL
, NULL
);
2377 g_return_val_if_fail (text
== limit
|| text
!= NULL
, NULL
);
2379 stream
.start
= text
;
2380 stream
.stream
= text
;
2383 if ((ast
= parse (&stream
, NULL
, error
)))
2386 result
= ast_resolve (ast
, error
);
2388 result
= ast_get_value (ast
, type
, error
);
2392 g_variant_ref_sink (result
);
2396 while (stream
.stream
!= limit
&&
2397 g_ascii_isspace (*stream
.stream
))
2400 if (stream
.stream
!= limit
&& *stream
.stream
!= '\0')
2402 SourceRef ref
= { stream
.stream
- text
,
2403 stream
.stream
- text
};
2405 parser_set_error (error
, &ref
, NULL
,
2406 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END
,
2407 "expected end of input");
2408 g_variant_unref (result
);
2414 *endptr
= stream
.stream
;
2424 * g_variant_new_parsed_va:
2425 * @format: a text format #GVariant
2426 * @app: a pointer to a #va_list
2428 * Parses @format and returns the result.
2430 * This is the version of g_variant_new_parsed() intended to be used
2433 * The return value will be floating if it was a newly created GVariant
2434 * instance. In the case that @format simply specified the collection
2435 * of a #GVariant pointer (eg: @format was "%*") then the collected
2436 * #GVariant pointer will be returned unmodified, without adding any
2437 * additional references.
2439 * Note that the arguments in @app must be of the correct width for their types
2440 * specified in @format when collected into the #va_list. See
2441 * the [GVariant varargs documentation][gvariant-varargs].
2443 * In order to behave correctly in all cases it is necessary for the
2444 * calling function to g_variant_ref_sink() the return result before
2445 * returning control to the user that originally provided the pointer.
2446 * At this point, the caller will have their own full reference to the
2447 * result. This can also be done by adding the result to a container,
2448 * or by passing it to another g_variant_new() call.
2450 * Returns: a new, usually floating, #GVariant
2453 g_variant_new_parsed_va (const gchar
*format
,
2456 TokenStream stream
= { 0, };
2457 GVariant
*result
= NULL
;
2458 GError
*error
= NULL
;
2461 g_return_val_if_fail (format
!= NULL
, NULL
);
2462 g_return_val_if_fail (app
!= NULL
, NULL
);
2464 stream
.start
= format
;
2465 stream
.stream
= format
;
2468 if ((ast
= parse (&stream
, app
, &error
)))
2470 result
= ast_resolve (ast
, &error
);
2475 g_error ("g_variant_new_parsed: %s", error
->message
);
2478 g_error ("g_variant_new_parsed: trailing text after value");
2484 * g_variant_new_parsed:
2485 * @format: a text format #GVariant
2486 * @...: arguments as per @format
2488 * Parses @format and returns the result.
2490 * @format must be a text format #GVariant with one extension: at any
2491 * point that a value may appear in the text, a '%' character followed
2492 * by a GVariant format string (as per g_variant_new()) may appear. In
2493 * that case, the same arguments are collected from the argument list as
2494 * g_variant_new() would have collected.
2496 * Note that the arguments must be of the correct width for their types
2497 * specified in @format. This can be achieved by casting them. See
2498 * the [GVariant varargs documentation][gvariant-varargs].
2500 * Consider this simple example:
2501 * |[<!-- language="C" -->
2502 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2505 * In the example, the variable argument parameters are collected and
2506 * filled in as if they were part of the original string to produce the
2508 * |[<!-- language="C" -->
2509 * [('one', 1), ('two', 2), ('three', 3)]
2512 * This function is intended only to be used with @format as a string
2513 * literal. Any parse error is fatal to the calling process. If you
2514 * want to parse data from untrusted sources, use g_variant_parse().
2516 * You may not use this function to return, unmodified, a single
2517 * #GVariant pointer from the argument list. ie: @format may not solely
2518 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2521 * Returns: a new floating #GVariant instance
2524 g_variant_new_parsed (const gchar
*format
,
2530 va_start (ap
, format
);
2531 result
= g_variant_new_parsed_va (format
, &ap
);
2538 * g_variant_builder_add_parsed:
2539 * @builder: a #GVariantBuilder
2540 * @format: a text format #GVariant
2541 * @...: arguments as per @format
2543 * Adds to a #GVariantBuilder.
2545 * This call is a convenience wrapper that is exactly equivalent to
2546 * calling g_variant_new_parsed() followed by
2547 * g_variant_builder_add_value().
2549 * Note that the arguments must be of the correct width for their types
2550 * specified in @format_string. This can be achieved by casting them. See
2551 * the [GVariant varargs documentation][gvariant-varargs].
2553 * This function might be used as follows:
2555 * |[<!-- language="C" -->
2557 * make_pointless_dictionary (void)
2559 * GVariantBuilder builder;
2562 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2563 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2564 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2565 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2566 * return g_variant_builder_end (&builder);
2573 g_variant_builder_add_parsed (GVariantBuilder
*builder
,
2574 const gchar
*format
,
2579 va_start (ap
, format
);
2580 g_variant_builder_add_value (builder
, g_variant_new_parsed_va (format
, &ap
));
2585 parse_num (const gchar
*num
,
2592 bignum
= g_ascii_strtoll (num
, &endptr
, 10);
2594 if (endptr
!= limit
)
2597 if (bignum
< 0 || bignum
> G_MAXINT
)
2606 add_last_line (GString
*err
,
2609 const gchar
*last_nl
;
2613 /* This is an error at the end of input. If we have a file
2614 * with newlines, that's probably the empty string after the
2615 * last newline, which is not the most useful thing to show.
2617 * Instead, show the last line of non-whitespace that we have
2618 * and put the pointer at the end of it.
2620 chomped
= g_strchomp (g_strdup (str
));
2621 last_nl
= strrchr (chomped
, '\n');
2622 if (last_nl
== NULL
)
2627 /* Print the last line like so:
2632 g_string_append (err
, " ");
2634 g_string_append (err
, last_nl
);
2636 g_string_append (err
, "(empty input)");
2637 g_string_append (err
, "\n ");
2638 for (i
= 0; last_nl
[i
]; i
++)
2639 g_string_append_c (err
, ' ');
2640 g_string_append (err
, "^\n");
2645 add_lines_from_range (GString
*err
,
2647 const gchar
*start1
,
2649 const gchar
*start2
,
2652 while (str
< end1
|| str
< end2
)
2656 nl
= str
+ strcspn (str
, "\n");
2658 if ((start1
< nl
&& str
< end1
) || (start2
< nl
&& str
< end2
))
2662 /* We're going to print this line */
2663 g_string_append (err
, " ");
2664 g_string_append_len (err
, str
, nl
- str
);
2665 g_string_append (err
, "\n ");
2667 /* And add underlines... */
2668 for (s
= str
; s
< nl
; s
++)
2670 if ((start1
<= s
&& s
< end1
) || (start2
<= s
&& s
< end2
))
2671 g_string_append_c (err
, '^');
2673 g_string_append_c (err
, ' ');
2675 g_string_append_c (err
, '\n');
2686 * g_variant_parse_error_print_context:
2687 * @error: a #GError from the #GVariantParseError domain
2688 * @source_str: the string that was given to the parser
2690 * Pretty-prints a message showing the context of a #GVariant parse
2691 * error within the string for which parsing was attempted.
2693 * The resulting string is suitable for output to the console or other
2694 * monospace media where newlines are treated in the usual way.
2696 * The message will typically look something like one of the following:
2699 * unterminated string constant:
2707 * unable to find a common type:
2712 * The format of the message may change in a future version.
2714 * @error must have come from a failed attempt to g_variant_parse() and
2715 * @source_str must be exactly the same string that caused the error.
2716 * If @source_str was not nul-terminated when you passed it to
2717 * g_variant_parse() then you must add nul termination before using this
2720 * Returns: (transfer full): the printed message
2725 g_variant_parse_error_print_context (GError
*error
,
2726 const gchar
*source_str
)
2728 const gchar
*colon
, *dash
, *comma
;
2729 gboolean success
= FALSE
;
2732 g_return_val_if_fail (error
->domain
== G_VARIANT_PARSE_ERROR
, FALSE
);
2734 /* We can only have a limited number of possible types of ranges
2735 * emitted from the parser:
2737 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2738 * - a-b: -- usually errors from handling one single token
2739 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2741 * We never see, for example "a,c".
2744 colon
= strchr (error
->message
, ':');
2745 dash
= strchr (error
->message
, '-');
2746 comma
= strchr (error
->message
, ',');
2751 err
= g_string_new (colon
+ 1);
2752 g_string_append (err
, ":\n");
2754 if (dash
== NULL
|| colon
< dash
)
2758 /* we have a single point */
2759 if (!parse_num (error
->message
, colon
, &point
))
2762 if (point
>= strlen (source_str
))
2763 /* the error is at the end of the input */
2764 add_last_line (err
, source_str
);
2766 /* otherwise just treat it as a error at a thin range */
2767 add_lines_from_range (err
, source_str
, source_str
+ point
, source_str
+ point
+ 1, NULL
, NULL
);
2771 /* We have one or two ranges... */
2772 if (comma
&& comma
< colon
)
2774 gint start1
, end1
, start2
, end2
;
2778 dash2
= strchr (comma
, '-');
2780 if (!parse_num (error
->message
, dash
, &start1
) || !parse_num (dash
+ 1, comma
, &end1
) ||
2781 !parse_num (comma
+ 1, dash2
, &start2
) || !parse_num (dash2
+ 1, colon
, &end2
))
2784 add_lines_from_range (err
, source_str
,
2785 source_str
+ start1
, source_str
+ end1
,
2786 source_str
+ start2
, source_str
+ end2
);
2793 if (!parse_num (error
->message
, dash
, &start
) || !parse_num (dash
+ 1, colon
, &end
))
2796 add_lines_from_range (err
, source_str
, source_str
+ start
, source_str
+ end
, NULL
, NULL
);
2803 return g_string_free (err
, !success
);