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
)
214 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
215 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
216 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
217 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
219 for (end
= stream
->stream
; end
!= stream
->end
; end
++)
220 if (!g_ascii_isalnum (*end
))
225 for (end
= stream
->stream
+ 1; end
!= stream
->end
; end
++)
226 if (*end
== stream
->stream
[0] || *end
== '\0' ||
227 (*end
== '\\' && (++end
== stream
->end
|| *end
== '\0')))
230 if (end
!= stream
->end
&& *end
)
235 /* stop at the first space, comma, colon or unmatched bracket.
236 * deals nicely with cases like (%i, %i) or {%i: %i}.
237 * Also: ] and > are never in format strings.
239 for (end
= stream
->stream
+ 1;
240 end
!= stream
->end
&& *end
!= ',' &&
241 *end
!= ':' && *end
!= '>' && *end
!= ']' && !g_ascii_isspace (*end
);
244 if (*end
== '(' || *end
== '{')
247 else if ((*end
== ')' || *end
== '}') && !brackets
--)
253 end
= stream
->stream
+ 1;
257 stream
->this = stream
->stream
;
258 stream
->stream
= end
;
264 token_stream_next (TokenStream
*stream
)
270 token_stream_peek (TokenStream
*stream
,
273 if (!token_stream_prepare (stream
))
276 return stream
->this[0] == first_char
;
280 token_stream_peek2 (TokenStream
*stream
,
284 if (!token_stream_prepare (stream
))
287 return stream
->this[0] == first_char
&&
288 stream
->this[1] == second_char
;
292 token_stream_is_keyword (TokenStream
*stream
)
294 if (!token_stream_prepare (stream
))
297 return g_ascii_isalpha (stream
->this[0]) &&
298 g_ascii_isalpha (stream
->this[1]);
302 token_stream_is_numeric (TokenStream
*stream
)
304 if (!token_stream_prepare (stream
))
307 return (g_ascii_isdigit (stream
->this[0]) ||
308 stream
->this[0] == '-' ||
309 stream
->this[0] == '+' ||
310 stream
->this[0] == '.');
314 token_stream_peek_string (TokenStream
*stream
,
317 gint length
= strlen (token
);
319 return token_stream_prepare (stream
) &&
320 stream
->stream
- stream
->this == length
&&
321 memcmp (stream
->this, token
, length
) == 0;
325 token_stream_consume (TokenStream
*stream
,
328 if (!token_stream_peek_string (stream
, token
))
331 token_stream_next (stream
);
336 token_stream_require (TokenStream
*stream
,
338 const gchar
*purpose
,
342 if (!token_stream_consume (stream
, token
))
344 token_stream_set_error (stream
, error
, FALSE
,
345 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN
,
346 "expected '%s'%s", token
, purpose
);
354 token_stream_assert (TokenStream
*stream
,
357 gboolean correct_token
;
359 correct_token
= token_stream_consume (stream
, token
);
360 g_assert (correct_token
);
364 token_stream_get (TokenStream
*stream
)
368 if (!token_stream_prepare (stream
))
371 result
= g_strndup (stream
->this, stream
->stream
- stream
->this);
377 token_stream_start_ref (TokenStream
*stream
,
380 token_stream_prepare (stream
);
381 ref
->start
= stream
->this - stream
->start
;
385 token_stream_end_ref (TokenStream
*stream
,
388 ref
->end
= stream
->stream
- stream
->start
;
392 pattern_copy (gchar
**out
,
397 while (**in
== 'a' || **in
== 'm' || **in
== 'M')
398 *(*out
)++ = *(*in
)++;
402 if (**in
== '(' || **in
== '{')
405 else if (**in
== ')' || **in
== '}')
408 *(*out
)++ = *(*in
)++;
414 pattern_coalesce (const gchar
*left
,
420 /* the length of the output is loosely bound by the sum of the input
421 * lengths, not simply the greater of the two lengths.
423 * (*(iii)) + ((iii)*) ((iii)(iii))
427 out
= result
= g_malloc (strlen (left
) + strlen (right
));
429 while (*left
&& *right
)
439 const gchar
**one
= &left
, **the_other
= &right
;
442 if (**one
== '*' && **the_other
!= ')')
444 pattern_copy (&out
, the_other
);
448 else if (**one
== 'M' && **the_other
== 'm')
450 *out
++ = *(*the_other
)++;
453 else if (**one
== 'M' && **the_other
!= 'm')
458 else if (**one
== 'N' && strchr ("ynqiuxthd", **the_other
))
460 *out
++ = *(*the_other
)++;
464 else if (**one
== 'S' && strchr ("sog", **the_other
))
466 *out
++ = *(*the_other
)++;
470 else if (one
== &left
)
472 one
= &right
, the_other
= &left
;
492 typedef struct _AST AST
;
493 typedef gchar
* (*get_pattern_func
) (AST
*ast
,
495 typedef GVariant
* (*get_value_func
) (AST
*ast
,
496 const GVariantType
*type
,
498 typedef GVariant
* (*get_base_value_func
) (AST
*ast
,
499 const GVariantType
*type
,
501 typedef void (*free_func
) (AST
*ast
);
505 gchar
* (* get_pattern
) (AST
*ast
,
507 GVariant
* (* get_value
) (AST
*ast
,
508 const GVariantType
*type
,
510 GVariant
* (* get_base_value
) (AST
*ast
,
511 const GVariantType
*type
,
513 void (* free
) (AST
*ast
);
518 const ASTClass
*class;
519 SourceRef source_ref
;
523 ast_get_pattern (AST
*ast
,
526 return ast
->class->get_pattern (ast
, error
);
530 ast_get_value (AST
*ast
,
531 const GVariantType
*type
,
534 return ast
->class->get_value (ast
, type
, error
);
540 ast
->class->free (ast
);
545 ast_set_error (AST
*ast
,
554 va_start (ap
, format
);
555 parser_set_error_va (error
, &ast
->source_ref
,
556 other_ast
? & other_ast
->source_ref
: NULL
,
563 ast_type_error (AST
*ast
,
564 const GVariantType
*type
,
569 typestr
= g_variant_type_dup_string (type
);
570 ast_set_error (ast
, error
, NULL
,
571 G_VARIANT_PARSE_ERROR_TYPE_ERROR
,
572 "can not parse as value of type '%s'",
580 ast_resolve (AST
*ast
,
587 pattern
= ast_get_pattern (ast
, error
);
592 /* choose reasonable defaults
594 * 1) favour non-maybe values where possible
595 * 2) default type for strings is 's'
596 * 3) default type for integers is 'i'
598 for (i
= 0; pattern
[i
]; i
++)
602 ast_set_error (ast
, error
, NULL
,
603 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE
,
604 "unable to infer type");
620 pattern
[j
++] = pattern
[i
];
625 value
= ast_get_value (ast
, G_VARIANT_TYPE (pattern
), error
);
632 static AST
*parse (TokenStream
*stream
,
637 ast_array_append (AST
***array
,
641 if ((*n_items
& (*n_items
- 1)) == 0)
642 *array
= g_renew (AST
*, *array
, *n_items
? 2 ** n_items
: 1);
644 (*array
)[(*n_items
)++] = ast
;
648 ast_array_free (AST
**array
,
653 for (i
= 0; i
< n_items
; i
++)
659 ast_array_get_pattern (AST
**array
,
666 pattern
= ast_get_pattern (array
[0], error
);
671 for (i
= 1; i
< n_items
; i
++)
675 tmp
= ast_get_pattern (array
[i
], error
);
683 merged
= pattern_coalesce (pattern
, tmp
);
688 /* set coalescence implies pairwise coalescence (i think).
689 * we should therefore be able to trace the failure to a single
700 /* if 'j' reaches 'i' then we failed to find the pair */
703 tmp2
= ast_get_pattern (array
[j
], NULL
);
704 g_assert (tmp2
!= NULL
);
706 m
= pattern_coalesce (tmp
, tmp2
);
712 /* we found a conflict between 'i' and 'j'.
714 * report the error. note: 'j' is first.
716 ast_set_error (array
[j
], error
, array
[i
],
717 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE
,
718 "unable to find a common type");
742 maybe_get_pattern (AST
*ast
,
745 Maybe
*maybe
= (Maybe
*) ast
;
747 if (maybe
->child
!= NULL
)
749 gchar
*child_pattern
;
752 child_pattern
= ast_get_pattern (maybe
->child
, error
);
754 if (child_pattern
== NULL
)
757 pattern
= g_strdup_printf ("m%s", child_pattern
);
758 g_free (child_pattern
);
763 return g_strdup ("m*");
767 maybe_get_value (AST
*ast
,
768 const GVariantType
*type
,
771 Maybe
*maybe
= (Maybe
*) ast
;
774 if (!g_variant_type_is_maybe (type
))
775 return ast_type_error (ast
, type
, error
);
777 type
= g_variant_type_element (type
);
781 value
= ast_get_value (maybe
->child
, type
, error
);
789 return g_variant_new_maybe (type
, value
);
793 maybe_free (AST
*ast
)
795 Maybe
*maybe
= (Maybe
*) ast
;
797 if (maybe
->child
!= NULL
)
798 ast_free (maybe
->child
);
800 g_slice_free (Maybe
, maybe
);
804 maybe_parse (TokenStream
*stream
,
808 static const ASTClass maybe_class
= {
810 maybe_get_value
, NULL
,
816 if (token_stream_consume (stream
, "just"))
818 child
= parse (stream
, app
, error
);
823 else if (!token_stream_consume (stream
, "nothing"))
825 token_stream_set_error (stream
, error
, TRUE
,
826 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
831 maybe
= g_slice_new (Maybe
);
832 maybe
->ast
.class = &maybe_class
;
833 maybe
->child
= child
;
835 return (AST
*) maybe
;
839 maybe_wrapper (AST
*ast
,
840 const GVariantType
*type
,
843 const GVariantType
*t
;
847 for (depth
= 0, t
= type
;
848 g_variant_type_is_maybe (t
);
849 depth
++, t
= g_variant_type_element (t
));
851 value
= ast
->class->get_base_value (ast
, t
, error
);
857 value
= g_variant_new_maybe (NULL
, value
);
871 array_get_pattern (AST
*ast
,
874 Array
*array
= (Array
*) ast
;
878 if (array
->n_children
== 0)
879 return g_strdup ("Ma*");
881 pattern
= ast_array_get_pattern (array
->children
, array
->n_children
, error
);
886 result
= g_strdup_printf ("Ma%s", pattern
);
893 array_get_value (AST
*ast
,
894 const GVariantType
*type
,
897 Array
*array
= (Array
*) ast
;
898 const GVariantType
*childtype
;
899 GVariantBuilder builder
;
902 if (!g_variant_type_is_array (type
))
903 return ast_type_error (ast
, type
, error
);
905 g_variant_builder_init (&builder
, type
);
906 childtype
= g_variant_type_element (type
);
908 for (i
= 0; i
< array
->n_children
; i
++)
912 if (!(child
= ast_get_value (array
->children
[i
], childtype
, error
)))
914 g_variant_builder_clear (&builder
);
918 g_variant_builder_add_value (&builder
, child
);
921 return g_variant_builder_end (&builder
);
925 array_free (AST
*ast
)
927 Array
*array
= (Array
*) ast
;
929 ast_array_free (array
->children
, array
->n_children
);
930 g_slice_free (Array
, array
);
934 array_parse (TokenStream
*stream
,
938 static const ASTClass array_class
= {
940 maybe_wrapper
, array_get_value
,
943 gboolean need_comma
= FALSE
;
946 array
= g_slice_new (Array
);
947 array
->ast
.class = &array_class
;
948 array
->children
= NULL
;
949 array
->n_children
= 0;
951 token_stream_assert (stream
, "[");
952 while (!token_stream_consume (stream
, "]"))
957 !token_stream_require (stream
, ",",
958 " or ']' to follow array element",
962 child
= parse (stream
, app
, error
);
967 ast_array_append (&array
->children
, &array
->n_children
, child
);
971 return (AST
*) array
;
974 ast_array_free (array
->children
, array
->n_children
);
975 g_slice_free (Array
, array
);
989 tuple_get_pattern (AST
*ast
,
992 Tuple
*tuple
= (Tuple
*) ast
;
993 gchar
*result
= NULL
;
997 parts
= g_new (gchar
*, tuple
->n_children
+ 4);
998 parts
[tuple
->n_children
+ 1] = (gchar
*) ")";
999 parts
[tuple
->n_children
+ 2] = NULL
;
1000 parts
[0] = (gchar
*) "M(";
1002 for (i
= 0; i
< tuple
->n_children
; i
++)
1003 if (!(parts
[i
+ 1] = ast_get_pattern (tuple
->children
[i
], error
)))
1006 if (i
== tuple
->n_children
)
1007 result
= g_strjoinv ("", parts
);
1009 /* parts[0] should not be freed */
1011 g_free (parts
[i
--]);
1018 tuple_get_value (AST
*ast
,
1019 const GVariantType
*type
,
1022 Tuple
*tuple
= (Tuple
*) ast
;
1023 const GVariantType
*childtype
;
1024 GVariantBuilder builder
;
1027 if (!g_variant_type_is_tuple (type
))
1028 return ast_type_error (ast
, type
, error
);
1030 g_variant_builder_init (&builder
, type
);
1031 childtype
= g_variant_type_first (type
);
1033 for (i
= 0; i
< tuple
->n_children
; i
++)
1037 if (childtype
== NULL
)
1039 g_variant_builder_clear (&builder
);
1040 return ast_type_error (ast
, type
, error
);
1043 if (!(child
= ast_get_value (tuple
->children
[i
], childtype
, error
)))
1045 g_variant_builder_clear (&builder
);
1049 g_variant_builder_add_value (&builder
, child
);
1050 childtype
= g_variant_type_next (childtype
);
1053 if (childtype
!= NULL
)
1055 g_variant_builder_clear (&builder
);
1056 return ast_type_error (ast
, type
, error
);
1059 return g_variant_builder_end (&builder
);
1063 tuple_free (AST
*ast
)
1065 Tuple
*tuple
= (Tuple
*) ast
;
1067 ast_array_free (tuple
->children
, tuple
->n_children
);
1068 g_slice_free (Tuple
, tuple
);
1072 tuple_parse (TokenStream
*stream
,
1076 static const ASTClass tuple_class
= {
1078 maybe_wrapper
, tuple_get_value
,
1081 gboolean need_comma
= FALSE
;
1082 gboolean first
= TRUE
;
1085 tuple
= g_slice_new (Tuple
);
1086 tuple
->ast
.class = &tuple_class
;
1087 tuple
->children
= NULL
;
1088 tuple
->n_children
= 0;
1090 token_stream_assert (stream
, "(");
1091 while (!token_stream_consume (stream
, ")"))
1096 !token_stream_require (stream
, ",",
1097 " or ')' to follow tuple element",
1101 child
= parse (stream
, app
, error
);
1106 ast_array_append (&tuple
->children
, &tuple
->n_children
, child
);
1108 /* the first time, we absolutely require a comma, so grab it here
1109 * and leave need_comma = FALSE so that the code above doesn't
1110 * require a second comma.
1112 * the second and remaining times, we set need_comma = TRUE.
1116 if (!token_stream_require (stream
, ",",
1117 " after first tuple element", error
))
1126 return (AST
*) tuple
;
1129 ast_array_free (tuple
->children
, tuple
->n_children
);
1130 g_slice_free (Tuple
, tuple
);
1143 variant_get_pattern (AST
*ast
,
1146 return g_strdup ("Mv");
1150 variant_get_value (AST
*ast
,
1151 const GVariantType
*type
,
1154 Variant
*variant
= (Variant
*) ast
;
1157 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_VARIANT
))
1158 return ast_type_error (ast
, type
, error
);
1160 child
= ast_resolve (variant
->value
, error
);
1165 return g_variant_new_variant (child
);
1169 variant_free (AST
*ast
)
1171 Variant
*variant
= (Variant
*) ast
;
1173 ast_free (variant
->value
);
1174 g_slice_free (Variant
, variant
);
1178 variant_parse (TokenStream
*stream
,
1182 static const ASTClass variant_class
= {
1183 variant_get_pattern
,
1184 maybe_wrapper
, variant_get_value
,
1190 token_stream_assert (stream
, "<");
1191 value
= parse (stream
, app
, error
);
1196 if (!token_stream_require (stream
, ">", " to follow variant value", error
))
1202 variant
= g_slice_new (Variant
);
1203 variant
->ast
.class = &variant_class
;
1204 variant
->value
= value
;
1206 return (AST
*) variant
;
1219 dictionary_get_pattern (AST
*ast
,
1222 Dictionary
*dict
= (Dictionary
*) ast
;
1223 gchar
*value_pattern
;
1228 if (dict
->n_children
== 0)
1229 return g_strdup ("Ma{**}");
1231 key_pattern
= ast_array_get_pattern (dict
->keys
,
1232 abs (dict
->n_children
),
1235 if (key_pattern
== NULL
)
1238 /* we can not have maybe keys */
1239 if (key_pattern
[0] == 'M')
1240 key_char
= key_pattern
[1];
1242 key_char
= key_pattern
[0];
1244 g_free (key_pattern
);
1247 * plus undetermined number type and undetermined string type.
1249 if (!strchr ("bynqiuxthdsogNS", key_char
))
1251 ast_set_error (ast
, error
, NULL
,
1252 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED
,
1253 "dictionary keys must have basic types");
1257 value_pattern
= ast_get_pattern (dict
->values
[0], error
);
1259 if (value_pattern
== NULL
)
1262 result
= g_strdup_printf ("M%s{%c%s}",
1263 dict
->n_children
> 0 ? "a" : "",
1264 key_char
, value_pattern
);
1265 g_free (value_pattern
);
1271 dictionary_get_value (AST
*ast
,
1272 const GVariantType
*type
,
1275 Dictionary
*dict
= (Dictionary
*) ast
;
1277 if (dict
->n_children
== -1)
1279 const GVariantType
*subtype
;
1280 GVariantBuilder builder
;
1283 if (!g_variant_type_is_dict_entry (type
))
1284 return ast_type_error (ast
, type
, error
);
1286 g_variant_builder_init (&builder
, type
);
1288 subtype
= g_variant_type_key (type
);
1289 if (!(subvalue
= ast_get_value (dict
->keys
[0], subtype
, error
)))
1291 g_variant_builder_clear (&builder
);
1294 g_variant_builder_add_value (&builder
, subvalue
);
1296 subtype
= g_variant_type_value (type
);
1297 if (!(subvalue
= ast_get_value (dict
->values
[0], subtype
, error
)))
1299 g_variant_builder_clear (&builder
);
1302 g_variant_builder_add_value (&builder
, subvalue
);
1304 return g_variant_builder_end (&builder
);
1308 const GVariantType
*entry
, *key
, *val
;
1309 GVariantBuilder builder
;
1312 if (!g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE_DICTIONARY
))
1313 return ast_type_error (ast
, type
, error
);
1315 entry
= g_variant_type_element (type
);
1316 key
= g_variant_type_key (entry
);
1317 val
= g_variant_type_value (entry
);
1319 g_variant_builder_init (&builder
, type
);
1321 for (i
= 0; i
< dict
->n_children
; i
++)
1325 g_variant_builder_open (&builder
, entry
);
1327 if (!(subvalue
= ast_get_value (dict
->keys
[i
], key
, error
)))
1329 g_variant_builder_clear (&builder
);
1332 g_variant_builder_add_value (&builder
, subvalue
);
1334 if (!(subvalue
= ast_get_value (dict
->values
[i
], val
, error
)))
1336 g_variant_builder_clear (&builder
);
1339 g_variant_builder_add_value (&builder
, subvalue
);
1340 g_variant_builder_close (&builder
);
1343 return g_variant_builder_end (&builder
);
1348 dictionary_free (AST
*ast
)
1350 Dictionary
*dict
= (Dictionary
*) ast
;
1353 if (dict
->n_children
> -1)
1354 n_children
= dict
->n_children
;
1358 ast_array_free (dict
->keys
, n_children
);
1359 ast_array_free (dict
->values
, n_children
);
1360 g_slice_free (Dictionary
, dict
);
1364 dictionary_parse (TokenStream
*stream
,
1368 static const ASTClass dictionary_class
= {
1369 dictionary_get_pattern
,
1370 maybe_wrapper
, dictionary_get_value
,
1373 gint n_keys
, n_values
;
1378 dict
= g_slice_new (Dictionary
);
1379 dict
->ast
.class = &dictionary_class
;
1381 dict
->values
= NULL
;
1382 n_keys
= n_values
= 0;
1384 token_stream_assert (stream
, "{");
1386 if (token_stream_consume (stream
, "}"))
1388 dict
->n_children
= 0;
1389 return (AST
*) dict
;
1392 if ((first
= parse (stream
, app
, error
)) == NULL
)
1395 ast_array_append (&dict
->keys
, &n_keys
, first
);
1397 only_one
= token_stream_consume (stream
, ",");
1399 !token_stream_require (stream
, ":",
1400 " or ',' to follow dictionary entry key",
1404 if ((first
= parse (stream
, app
, error
)) == NULL
)
1407 ast_array_append (&dict
->values
, &n_values
, first
);
1411 if (!token_stream_require (stream
, "}", " at end of dictionary entry",
1415 g_assert (n_keys
== 1 && n_values
== 1);
1416 dict
->n_children
= -1;
1418 return (AST
*) dict
;
1421 while (!token_stream_consume (stream
, "}"))
1425 if (!token_stream_require (stream
, ",",
1426 " or '}' to follow dictionary entry", error
))
1429 child
= parse (stream
, app
, error
);
1434 ast_array_append (&dict
->keys
, &n_keys
, child
);
1436 if (!token_stream_require (stream
, ":",
1437 " to follow dictionary entry key", error
))
1440 child
= parse (stream
, app
, error
);
1445 ast_array_append (&dict
->values
, &n_values
, child
);
1448 g_assert (n_keys
== n_values
);
1449 dict
->n_children
= n_keys
;
1451 return (AST
*) dict
;
1454 ast_array_free (dict
->keys
, n_keys
);
1455 ast_array_free (dict
->values
, n_values
);
1456 g_slice_free (Dictionary
, dict
);
1468 string_get_pattern (AST
*ast
,
1471 return g_strdup ("MS");
1475 string_get_value (AST
*ast
,
1476 const GVariantType
*type
,
1479 String
*string
= (String
*) ast
;
1481 if (g_variant_type_equal (type
, G_VARIANT_TYPE_STRING
))
1482 return g_variant_new_string (string
->string
);
1484 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_OBJECT_PATH
))
1486 if (!g_variant_is_object_path (string
->string
))
1488 ast_set_error (ast
, error
, NULL
,
1489 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH
,
1490 "not a valid object path");
1494 return g_variant_new_object_path (string
->string
);
1497 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_SIGNATURE
))
1499 if (!g_variant_is_signature (string
->string
))
1501 ast_set_error (ast
, error
, NULL
,
1502 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE
,
1503 "not a valid signature");
1507 return g_variant_new_signature (string
->string
);
1511 return ast_type_error (ast
, type
, error
);
1515 string_free (AST
*ast
)
1517 String
*string
= (String
*) ast
;
1519 g_free (string
->string
);
1520 g_slice_free (String
, string
);
1524 unicode_unescape (const gchar
*src
,
1538 g_assert (length
< sizeof (buffer
));
1539 strncpy (buffer
, src
+ *src_ofs
, length
);
1540 buffer
[length
] = '\0';
1542 value
= g_ascii_strtoull (buffer
, &end
, 0x10);
1544 if (value
== 0 || end
!= buffer
+ length
)
1546 parser_set_error (error
, ref
, NULL
,
1547 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1548 "invalid %d-character unicode escape", length
);
1552 g_assert (value
<= G_MAXUINT32
);
1554 *dest_ofs
+= g_unichar_to_utf8 (value
, dest
+ *dest_ofs
);
1561 string_parse (TokenStream
*stream
,
1565 static const ASTClass string_class
= {
1567 maybe_wrapper
, string_get_value
,
1578 token_stream_start_ref (stream
, &ref
);
1579 token
= token_stream_get (stream
);
1580 token_stream_end_ref (stream
, &ref
);
1581 length
= strlen (token
);
1584 str
= g_malloc (length
);
1585 g_assert (quote
== '"' || quote
== '\'');
1588 while (token
[i
] != quote
)
1592 parser_set_error (error
, &ref
, NULL
,
1593 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1594 "unterminated string constant");
1603 parser_set_error (error
, &ref
, NULL
,
1604 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1605 "unterminated string constant");
1611 if (!unicode_unescape (token
, &i
, str
, &j
, 4, &ref
, error
))
1620 if (!unicode_unescape (token
, &i
, str
, &j
, 8, &ref
, error
))
1628 case 'a': str
[j
++] = '\a'; i
++; continue;
1629 case 'b': str
[j
++] = '\b'; i
++; continue;
1630 case 'f': str
[j
++] = '\f'; i
++; continue;
1631 case 'n': str
[j
++] = '\n'; i
++; continue;
1632 case 'r': str
[j
++] = '\r'; i
++; continue;
1633 case 't': str
[j
++] = '\t'; i
++; continue;
1634 case 'v': str
[j
++] = '\v'; i
++; continue;
1635 case '\n': i
++; continue;
1639 str
[j
++] = token
[i
++];
1644 string
= g_slice_new (String
);
1645 string
->ast
.class = &string_class
;
1646 string
->string
= str
;
1648 token_stream_next (stream
);
1650 return (AST
*) string
;
1660 bytestring_get_pattern (AST
*ast
,
1663 return g_strdup ("May");
1667 bytestring_get_value (AST
*ast
,
1668 const GVariantType
*type
,
1671 ByteString
*string
= (ByteString
*) ast
;
1673 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BYTESTRING
))
1674 return ast_type_error (ast
, type
, error
);
1676 return g_variant_new_bytestring (string
->string
);
1680 bytestring_free (AST
*ast
)
1682 ByteString
*string
= (ByteString
*) ast
;
1684 g_free (string
->string
);
1685 g_slice_free (ByteString
, string
);
1689 bytestring_parse (TokenStream
*stream
,
1693 static const ASTClass bytestring_class
= {
1694 bytestring_get_pattern
,
1695 maybe_wrapper
, bytestring_get_value
,
1706 token_stream_start_ref (stream
, &ref
);
1707 token
= token_stream_get (stream
);
1708 token_stream_end_ref (stream
, &ref
);
1709 g_assert (token
[0] == 'b');
1710 length
= strlen (token
);
1713 str
= g_malloc (length
);
1714 g_assert (quote
== '"' || quote
== '\'');
1717 while (token
[i
] != quote
)
1721 parser_set_error (error
, &ref
, NULL
,
1722 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1723 "unterminated string constant");
1731 parser_set_error (error
, &ref
, NULL
,
1732 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1733 "unterminated string constant");
1737 case '0': case '1': case '2': case '3':
1738 case '4': case '5': case '6': case '7':
1740 /* up to 3 characters */
1741 guchar val
= token
[i
++] - '0';
1743 if ('0' <= token
[i
] && token
[i
] < '8')
1744 val
= (val
<< 3) | (token
[i
++] - '0');
1746 if ('0' <= token
[i
] && token
[i
] < '8')
1747 val
= (val
<< 3) | (token
[i
++] - '0');
1753 case 'a': str
[j
++] = '\a'; i
++; continue;
1754 case 'b': str
[j
++] = '\b'; i
++; continue;
1755 case 'f': str
[j
++] = '\f'; i
++; continue;
1756 case 'n': str
[j
++] = '\n'; i
++; continue;
1757 case 'r': str
[j
++] = '\r'; i
++; continue;
1758 case 't': str
[j
++] = '\t'; i
++; continue;
1759 case 'v': str
[j
++] = '\v'; i
++; continue;
1760 case '\n': i
++; continue;
1764 str
[j
++] = token
[i
++];
1769 string
= g_slice_new (ByteString
);
1770 string
->ast
.class = &bytestring_class
;
1771 string
->string
= str
;
1773 token_stream_next (stream
);
1775 return (AST
*) string
;
1786 number_get_pattern (AST
*ast
,
1789 Number
*number
= (Number
*) ast
;
1791 if (strchr (number
->token
, '.') ||
1792 (!g_str_has_prefix (number
->token
, "0x") && strchr (number
->token
, 'e')) ||
1793 strstr (number
->token
, "inf") ||
1794 strstr (number
->token
, "nan"))
1795 return g_strdup ("Md");
1797 return g_strdup ("MN");
1801 number_overflow (AST
*ast
,
1802 const GVariantType
*type
,
1805 ast_set_error (ast
, error
, NULL
,
1806 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE
,
1807 "number out of range for type '%c'",
1808 g_variant_type_peek_string (type
)[0]);
1813 number_get_value (AST
*ast
,
1814 const GVariantType
*type
,
1817 Number
*number
= (Number
*) ast
;
1825 token
= number
->token
;
1827 if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
1832 dbl_val
= g_ascii_strtod (token
, &end
);
1833 if (dbl_val
!= 0.0 && errno
== ERANGE
)
1835 ast_set_error (ast
, error
, NULL
,
1836 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1837 "number too big for any type");
1841 /* silence uninitialised warnings... */
1848 negative
= token
[0] == '-';
1849 if (token
[0] == '-')
1853 abs_val
= g_ascii_strtoull (token
, &end
, 0);
1854 if (abs_val
== G_MAXUINT64
&& errno
== ERANGE
)
1856 ast_set_error (ast
, error
, NULL
,
1857 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1858 "integer too big for any type");
1865 /* silence uninitialised warning... */
1873 ref
= ast
->source_ref
;
1874 ref
.start
+= end
- number
->token
;
1875 ref
.end
= ref
.start
+ 1;
1877 parser_set_error (error
, &ref
, NULL
,
1878 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1879 "invalid character in number");
1884 return g_variant_new_double (dbl_val
);
1886 switch (*g_variant_type_peek_string (type
))
1889 if (negative
|| abs_val
> G_MAXUINT8
)
1890 return number_overflow (ast
, type
, error
);
1891 return g_variant_new_byte (abs_val
);
1894 if (abs_val
- negative
> G_MAXINT16
)
1895 return number_overflow (ast
, type
, error
);
1896 return g_variant_new_int16 (negative
? -abs_val
: abs_val
);
1899 if (negative
|| abs_val
> G_MAXUINT16
)
1900 return number_overflow (ast
, type
, error
);
1901 return g_variant_new_uint16 (abs_val
);
1904 if (abs_val
- negative
> G_MAXINT32
)
1905 return number_overflow (ast
, type
, error
);
1906 return g_variant_new_int32 (negative
? -abs_val
: abs_val
);
1909 if (negative
|| abs_val
> G_MAXUINT32
)
1910 return number_overflow (ast
, type
, error
);
1911 return g_variant_new_uint32 (abs_val
);
1914 if (abs_val
- negative
> G_MAXINT64
)
1915 return number_overflow (ast
, type
, error
);
1916 return g_variant_new_int64 (negative
? -abs_val
: abs_val
);
1920 return number_overflow (ast
, type
, error
);
1921 return g_variant_new_uint64 (abs_val
);
1924 if (abs_val
- negative
> G_MAXINT32
)
1925 return number_overflow (ast
, type
, error
);
1926 return g_variant_new_handle (negative
? -abs_val
: abs_val
);
1929 return ast_type_error (ast
, type
, error
);
1934 number_free (AST
*ast
)
1936 Number
*number
= (Number
*) ast
;
1938 g_free (number
->token
);
1939 g_slice_free (Number
, number
);
1943 number_parse (TokenStream
*stream
,
1947 static const ASTClass number_class
= {
1949 maybe_wrapper
, number_get_value
,
1954 number
= g_slice_new (Number
);
1955 number
->ast
.class = &number_class
;
1956 number
->token
= token_stream_get (stream
);
1957 token_stream_next (stream
);
1959 return (AST
*) number
;
1969 boolean_get_pattern (AST
*ast
,
1972 return g_strdup ("Mb");
1976 boolean_get_value (AST
*ast
,
1977 const GVariantType
*type
,
1980 Boolean
*boolean
= (Boolean
*) ast
;
1982 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
1983 return ast_type_error (ast
, type
, error
);
1985 return g_variant_new_boolean (boolean
->value
);
1989 boolean_free (AST
*ast
)
1991 Boolean
*boolean
= (Boolean
*) ast
;
1993 g_slice_free (Boolean
, boolean
);
1997 boolean_new (gboolean value
)
1999 static const ASTClass boolean_class
= {
2000 boolean_get_pattern
,
2001 maybe_wrapper
, boolean_get_value
,
2006 boolean
= g_slice_new (Boolean
);
2007 boolean
->ast
.class = &boolean_class
;
2008 boolean
->value
= value
;
2010 return (AST
*) boolean
;
2021 positional_get_pattern (AST
*ast
,
2024 Positional
*positional
= (Positional
*) ast
;
2026 return g_strdup (g_variant_get_type_string (positional
->value
));
2030 positional_get_value (AST
*ast
,
2031 const GVariantType
*type
,
2034 Positional
*positional
= (Positional
*) ast
;
2037 g_assert (positional
->value
!= NULL
);
2039 if G_UNLIKELY (!g_variant_is_of_type (positional
->value
, type
))
2040 return ast_type_error (ast
, type
, error
);
2042 /* NOTE: if _get is called more than once then
2043 * things get messed up with respect to floating refs.
2045 * fortunately, this function should only ever get called once.
2047 g_assert (positional
->value
!= NULL
);
2048 value
= positional
->value
;
2049 positional
->value
= NULL
;
2055 positional_free (AST
*ast
)
2057 Positional
*positional
= (Positional
*) ast
;
2059 /* if positional->value is set, just leave it.
2060 * memory management doesn't matter in case of programmer error.
2062 g_slice_free (Positional
, positional
);
2066 positional_parse (TokenStream
*stream
,
2070 static const ASTClass positional_class
= {
2071 positional_get_pattern
,
2072 positional_get_value
, NULL
,
2075 Positional
*positional
;
2076 const gchar
*endptr
;
2079 token
= token_stream_get (stream
);
2080 g_assert (token
[0] == '%');
2082 positional
= g_slice_new (Positional
);
2083 positional
->ast
.class = &positional_class
;
2084 positional
->value
= g_variant_new_va (token
+ 1, &endptr
, app
);
2086 if (*endptr
|| positional
->value
== NULL
)
2088 token_stream_set_error (stream
, error
, TRUE
,
2089 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING
,
2090 "invalid GVariant format string");
2091 /* memory management doesn't matter in case of programmer error. */
2095 token_stream_next (stream
);
2098 return (AST
*) positional
;
2110 typedecl_get_pattern (AST
*ast
,
2113 TypeDecl
*decl
= (TypeDecl
*) ast
;
2115 return g_variant_type_dup_string (decl
->type
);
2119 typedecl_get_value (AST
*ast
,
2120 const GVariantType
*type
,
2123 TypeDecl
*decl
= (TypeDecl
*) ast
;
2125 return ast_get_value (decl
->child
, type
, error
);
2129 typedecl_free (AST
*ast
)
2131 TypeDecl
*decl
= (TypeDecl
*) ast
;
2133 ast_free (decl
->child
);
2134 g_variant_type_free (decl
->type
);
2135 g_slice_free (TypeDecl
, decl
);
2139 typedecl_parse (TokenStream
*stream
,
2143 static const ASTClass typedecl_class
= {
2144 typedecl_get_pattern
,
2145 typedecl_get_value
, NULL
,
2152 if (token_stream_peek (stream
, '@'))
2156 token
= token_stream_get (stream
);
2158 if (!g_variant_type_string_is_valid (token
+ 1))
2160 token_stream_set_error (stream
, error
, TRUE
,
2161 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING
,
2162 "invalid type declaration");
2168 type
= g_variant_type_new (token
+ 1);
2170 if (!g_variant_type_is_definite (type
))
2172 token_stream_set_error (stream
, error
, TRUE
,
2173 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED
,
2174 "type declarations must be definite");
2175 g_variant_type_free (type
);
2181 token_stream_next (stream
);
2186 if (token_stream_consume (stream
, "boolean"))
2187 type
= g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN
);
2189 else if (token_stream_consume (stream
, "byte"))
2190 type
= g_variant_type_copy (G_VARIANT_TYPE_BYTE
);
2192 else if (token_stream_consume (stream
, "int16"))
2193 type
= g_variant_type_copy (G_VARIANT_TYPE_INT16
);
2195 else if (token_stream_consume (stream
, "uint16"))
2196 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT16
);
2198 else if (token_stream_consume (stream
, "int32"))
2199 type
= g_variant_type_copy (G_VARIANT_TYPE_INT32
);
2201 else if (token_stream_consume (stream
, "handle"))
2202 type
= g_variant_type_copy (G_VARIANT_TYPE_HANDLE
);
2204 else if (token_stream_consume (stream
, "uint32"))
2205 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT32
);
2207 else if (token_stream_consume (stream
, "int64"))
2208 type
= g_variant_type_copy (G_VARIANT_TYPE_INT64
);
2210 else if (token_stream_consume (stream
, "uint64"))
2211 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT64
);
2213 else if (token_stream_consume (stream
, "double"))
2214 type
= g_variant_type_copy (G_VARIANT_TYPE_DOUBLE
);
2216 else if (token_stream_consume (stream
, "string"))
2217 type
= g_variant_type_copy (G_VARIANT_TYPE_STRING
);
2219 else if (token_stream_consume (stream
, "objectpath"))
2220 type
= g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH
);
2222 else if (token_stream_consume (stream
, "signature"))
2223 type
= g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE
);
2227 token_stream_set_error (stream
, error
, TRUE
,
2228 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
2234 if ((child
= parse (stream
, app
, error
)) == NULL
)
2236 g_variant_type_free (type
);
2240 decl
= g_slice_new (TypeDecl
);
2241 decl
->ast
.class = &typedecl_class
;
2243 decl
->child
= child
;
2245 return (AST
*) decl
;
2249 parse (TokenStream
*stream
,
2253 SourceRef source_ref
;
2256 token_stream_prepare (stream
);
2257 token_stream_start_ref (stream
, &source_ref
);
2259 if (token_stream_peek (stream
, '['))
2260 result
= array_parse (stream
, app
, error
);
2262 else if (token_stream_peek (stream
, '('))
2263 result
= tuple_parse (stream
, app
, error
);
2265 else if (token_stream_peek (stream
, '<'))
2266 result
= variant_parse (stream
, app
, error
);
2268 else if (token_stream_peek (stream
, '{'))
2269 result
= dictionary_parse (stream
, app
, error
);
2271 else if (app
&& token_stream_peek (stream
, '%'))
2272 result
= positional_parse (stream
, app
, error
);
2274 else if (token_stream_consume (stream
, "true"))
2275 result
= boolean_new (TRUE
);
2277 else if (token_stream_consume (stream
, "false"))
2278 result
= boolean_new (FALSE
);
2280 else if (token_stream_is_numeric (stream
) ||
2281 token_stream_peek_string (stream
, "inf") ||
2282 token_stream_peek_string (stream
, "nan"))
2283 result
= number_parse (stream
, app
, error
);
2285 else if (token_stream_peek (stream
, 'n') ||
2286 token_stream_peek (stream
, 'j'))
2287 result
= maybe_parse (stream
, app
, error
);
2289 else if (token_stream_peek (stream
, '@') ||
2290 token_stream_is_keyword (stream
))
2291 result
= typedecl_parse (stream
, app
, error
);
2293 else if (token_stream_peek (stream
, '\'') ||
2294 token_stream_peek (stream
, '"'))
2295 result
= string_parse (stream
, app
, error
);
2297 else if (token_stream_peek2 (stream
, 'b', '\'') ||
2298 token_stream_peek2 (stream
, 'b', '"'))
2299 result
= bytestring_parse (stream
, app
, error
);
2303 token_stream_set_error (stream
, error
, FALSE
,
2304 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED
,
2311 token_stream_end_ref (stream
, &source_ref
);
2312 result
->source_ref
= source_ref
;
2320 * @type: (allow-none): a #GVariantType, or %NULL
2321 * @text: a string containing a GVariant in text form
2322 * @limit: (allow-none): a pointer to the end of @text, or %NULL
2323 * @endptr: (allow-none): a location to store the end pointer, or %NULL
2324 * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
2326 * Parses a #GVariant from a text representation.
2328 * A single #GVariant is parsed from the content of @text.
2330 * The format is described [here][gvariant-text].
2332 * The memory at @limit will never be accessed and the parser behaves as
2333 * if the character at @limit is the nul terminator. This has the
2334 * effect of bounding @text.
2336 * If @endptr is non-%NULL then @text is permitted to contain data
2337 * following the value that this function parses and @endptr will be
2338 * updated to point to the first character past the end of the text
2339 * parsed by this function. If @endptr is %NULL and there is extra data
2340 * then an error is returned.
2342 * If @type is non-%NULL then the value will be parsed to have that
2343 * type. This may result in additional parse errors (in the case that
2344 * the parsed value doesn't fit the type) but may also result in fewer
2345 * errors (in the case that the type would have been ambiguous, such as
2346 * with empty arrays).
2348 * In the event that the parsing is successful, the resulting #GVariant
2351 * In case of any error, %NULL will be returned. If @error is non-%NULL
2352 * then it will be set to reflect the error that occurred.
2354 * Officially, the language understood by the parser is "any string
2355 * produced by g_variant_print()".
2357 * Returns: a reference to a #GVariant, or %NULL
2360 g_variant_parse (const GVariantType
*type
,
2363 const gchar
**endptr
,
2366 TokenStream stream
= { 0, };
2367 GVariant
*result
= NULL
;
2370 g_return_val_if_fail (text
!= NULL
, NULL
);
2371 g_return_val_if_fail (text
== limit
|| text
!= NULL
, NULL
);
2373 stream
.start
= text
;
2374 stream
.stream
= text
;
2377 if ((ast
= parse (&stream
, NULL
, error
)))
2380 result
= ast_resolve (ast
, error
);
2382 result
= ast_get_value (ast
, type
, error
);
2386 g_variant_ref_sink (result
);
2390 while (stream
.stream
!= limit
&&
2391 g_ascii_isspace (*stream
.stream
))
2394 if (stream
.stream
!= limit
&& *stream
.stream
!= '\0')
2396 SourceRef ref
= { stream
.stream
- text
,
2397 stream
.stream
- text
};
2399 parser_set_error (error
, &ref
, NULL
,
2400 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END
,
2401 "expected end of input");
2402 g_variant_unref (result
);
2408 *endptr
= stream
.stream
;
2418 * g_variant_new_parsed_va:
2419 * @format: a text format #GVariant
2420 * @app: a pointer to a #va_list
2422 * Parses @format and returns the result.
2424 * This is the version of g_variant_new_parsed() intended to be used
2427 * The return value will be floating if it was a newly created GVariant
2428 * instance. In the case that @format simply specified the collection
2429 * of a #GVariant pointer (eg: @format was "%*") then the collected
2430 * #GVariant pointer will be returned unmodified, without adding any
2431 * additional references.
2433 * Note that the arguments in @app must be of the correct width for their types
2434 * specified in @format when collected into the #va_list. See
2435 * the [GVariant varargs documentation][gvariant-varargs].
2437 * In order to behave correctly in all cases it is necessary for the
2438 * calling function to g_variant_ref_sink() the return result before
2439 * returning control to the user that originally provided the pointer.
2440 * At this point, the caller will have their own full reference to the
2441 * result. This can also be done by adding the result to a container,
2442 * or by passing it to another g_variant_new() call.
2444 * Returns: a new, usually floating, #GVariant
2447 g_variant_new_parsed_va (const gchar
*format
,
2450 TokenStream stream
= { 0, };
2451 GVariant
*result
= NULL
;
2452 GError
*error
= NULL
;
2455 g_return_val_if_fail (format
!= NULL
, NULL
);
2456 g_return_val_if_fail (app
!= NULL
, NULL
);
2458 stream
.start
= format
;
2459 stream
.stream
= format
;
2462 if ((ast
= parse (&stream
, app
, &error
)))
2464 result
= ast_resolve (ast
, &error
);
2469 g_error ("g_variant_new_parsed: %s", error
->message
);
2472 g_error ("g_variant_new_parsed: trailing text after value");
2478 * g_variant_new_parsed:
2479 * @format: a text format #GVariant
2480 * @...: arguments as per @format
2482 * Parses @format and returns the result.
2484 * @format must be a text format #GVariant with one extension: at any
2485 * point that a value may appear in the text, a '%' character followed
2486 * by a GVariant format string (as per g_variant_new()) may appear. In
2487 * that case, the same arguments are collected from the argument list as
2488 * g_variant_new() would have collected.
2490 * Note that the arguments must be of the correct width for their types
2491 * specified in @format. This can be achieved by casting them. See
2492 * the [GVariant varargs documentation][gvariant-varargs].
2494 * Consider this simple example:
2495 * |[<!-- language="C" -->
2496 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2499 * In the example, the variable argument parameters are collected and
2500 * filled in as if they were part of the original string to produce the
2502 * |[<!-- language="C" -->
2503 * [('one', 1), ('two', 2), ('three', 3)]
2506 * This function is intended only to be used with @format as a string
2507 * literal. Any parse error is fatal to the calling process. If you
2508 * want to parse data from untrusted sources, use g_variant_parse().
2510 * You may not use this function to return, unmodified, a single
2511 * #GVariant pointer from the argument list. ie: @format may not solely
2512 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2515 * Returns: a new floating #GVariant instance
2518 g_variant_new_parsed (const gchar
*format
,
2524 va_start (ap
, format
);
2525 result
= g_variant_new_parsed_va (format
, &ap
);
2532 * g_variant_builder_add_parsed:
2533 * @builder: a #GVariantBuilder
2534 * @format: a text format #GVariant
2535 * @...: arguments as per @format
2537 * Adds to a #GVariantBuilder.
2539 * This call is a convenience wrapper that is exactly equivalent to
2540 * calling g_variant_new_parsed() followed by
2541 * g_variant_builder_add_value().
2543 * Note that the arguments must be of the correct width for their types
2544 * specified in @format_string. This can be achieved by casting them. See
2545 * the [GVariant varargs documentation][gvariant-varargs].
2547 * This function might be used as follows:
2549 * |[<!-- language="C" -->
2551 * make_pointless_dictionary (void)
2553 * GVariantBuilder builder;
2556 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2557 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2558 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2559 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2560 * return g_variant_builder_end (&builder);
2567 g_variant_builder_add_parsed (GVariantBuilder
*builder
,
2568 const gchar
*format
,
2573 va_start (ap
, format
);
2574 g_variant_builder_add_value (builder
, g_variant_new_parsed_va (format
, &ap
));
2579 parse_num (const gchar
*num
,
2586 bignum
= g_ascii_strtoll (num
, &endptr
, 10);
2588 if (endptr
!= limit
)
2591 if (bignum
< 0 || bignum
> G_MAXINT
)
2600 add_last_line (GString
*err
,
2603 const gchar
*last_nl
;
2607 /* This is an error at the end of input. If we have a file
2608 * with newlines, that's probably the empty string after the
2609 * last newline, which is not the most useful thing to show.
2611 * Instead, show the last line of non-whitespace that we have
2612 * and put the pointer at the end of it.
2614 chomped
= g_strchomp (g_strdup (str
));
2615 last_nl
= strrchr (chomped
, '\n');
2616 if (last_nl
== NULL
)
2621 /* Print the last line like so:
2626 g_string_append (err
, " ");
2628 g_string_append (err
, last_nl
);
2630 g_string_append (err
, "(empty input)");
2631 g_string_append (err
, "\n ");
2632 for (i
= 0; last_nl
[i
]; i
++)
2633 g_string_append_c (err
, ' ');
2634 g_string_append (err
, "^\n");
2639 add_lines_from_range (GString
*err
,
2641 const gchar
*start1
,
2643 const gchar
*start2
,
2646 while (str
< end1
|| str
< end2
)
2650 nl
= str
+ strcspn (str
, "\n");
2652 if ((start1
< nl
&& str
< end1
) || (start2
< nl
&& str
< end2
))
2656 /* We're going to print this line */
2657 g_string_append (err
, " ");
2658 g_string_append_len (err
, str
, nl
- str
);
2659 g_string_append (err
, "\n ");
2661 /* And add underlines... */
2662 for (s
= str
; s
< nl
; s
++)
2664 if ((start1
<= s
&& s
< end1
) || (start2
<= s
&& s
< end2
))
2665 g_string_append_c (err
, '^');
2667 g_string_append_c (err
, ' ');
2669 g_string_append_c (err
, '\n');
2680 * g_variant_parse_error_print_context:
2681 * @error: a #GError from the #GVariantParseError domain
2682 * @source_str: the string that was given to the parser
2684 * Pretty-prints a message showing the context of a #GVariant parse
2685 * error within the string for which parsing was attempted.
2687 * The resulting string is suitable for output to the console or other
2688 * monospace media where newlines are treated in the usual way.
2690 * The message will typically look something like one of the following:
2693 * unterminated string constant:
2701 * unable to find a common type:
2706 * The format of the message may change in a future version.
2708 * @error must have come from a failed attempt to g_variant_parse() and
2709 * @source_str must be exactly the same string that caused the error.
2710 * If @source_str was not nul-terminated when you passed it to
2711 * g_variant_parse() then you must add nul termination before using this
2714 * Returns: (transfer full): the printed message
2719 g_variant_parse_error_print_context (GError
*error
,
2720 const gchar
*source_str
)
2722 const gchar
*colon
, *dash
, *comma
;
2723 gboolean success
= FALSE
;
2726 g_return_val_if_fail (error
->domain
== G_VARIANT_PARSE_ERROR
, FALSE
);
2728 /* We can only have a limited number of possible types of ranges
2729 * emitted from the parser:
2731 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2732 * - a-b: -- usually errors from handling one single token
2733 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2735 * We never see, for example "a,c".
2738 colon
= strchr (error
->message
, ':');
2739 dash
= strchr (error
->message
, '-');
2740 comma
= strchr (error
->message
, ',');
2745 err
= g_string_new (colon
+ 1);
2746 g_string_append (err
, ":\n");
2748 if (dash
== NULL
|| colon
< dash
)
2752 /* we have a single point */
2753 if (!parse_num (error
->message
, colon
, &point
))
2756 if (point
>= strlen (source_str
))
2757 /* the error is at the end of the input */
2758 add_last_line (err
, source_str
);
2760 /* otherwise just treat it as a error at a thin range */
2761 add_lines_from_range (err
, source_str
, source_str
+ point
, source_str
+ point
+ 1, NULL
, NULL
);
2765 /* We have one or two ranges... */
2766 if (comma
&& comma
< colon
)
2768 gint start1
, end1
, start2
, end2
;
2772 dash2
= strchr (comma
, '-');
2774 if (!parse_num (error
->message
, dash
, &start1
) || !parse_num (dash
+ 1, comma
, &end1
) ||
2775 !parse_num (comma
+ 1, dash2
, &start2
) || !parse_num (dash2
+ 1, colon
, &end2
))
2778 add_lines_from_range (err
, source_str
,
2779 source_str
+ start1
, source_str
+ end1
,
2780 source_str
+ start2
, source_str
+ end2
);
2787 if (!parse_num (error
->message
, dash
, &start
) || !parse_num (dash
+ 1, colon
, &end
))
2790 add_lines_from_range (err
, source_str
, source_str
+ start
, source_str
+ end
, NULL
, NULL
);
2797 return g_string_free (err
, !success
);