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
;
263 /* We must have at least one byte in a token. */
264 g_assert (stream
->stream
- stream
->this >= 1);
270 token_stream_next (TokenStream
*stream
)
276 token_stream_peek (TokenStream
*stream
,
279 if (!token_stream_prepare (stream
))
282 return stream
->stream
- stream
->this >= 1 &&
283 stream
->this[0] == first_char
;
287 token_stream_peek2 (TokenStream
*stream
,
291 if (!token_stream_prepare (stream
))
294 return stream
->stream
- stream
->this >= 2 &&
295 stream
->this[0] == first_char
&&
296 stream
->this[1] == second_char
;
300 token_stream_is_keyword (TokenStream
*stream
)
302 if (!token_stream_prepare (stream
))
305 return stream
->stream
- stream
->this >= 2 &&
306 g_ascii_isalpha (stream
->this[0]) &&
307 g_ascii_isalpha (stream
->this[1]);
311 token_stream_is_numeric (TokenStream
*stream
)
313 if (!token_stream_prepare (stream
))
316 return (stream
->stream
- stream
->this >= 1 &&
317 (g_ascii_isdigit (stream
->this[0]) ||
318 stream
->this[0] == '-' ||
319 stream
->this[0] == '+' ||
320 stream
->this[0] == '.'));
324 token_stream_peek_string (TokenStream
*stream
,
327 gint length
= strlen (token
);
329 return token_stream_prepare (stream
) &&
330 stream
->stream
- stream
->this == length
&&
331 memcmp (stream
->this, token
, length
) == 0;
335 token_stream_consume (TokenStream
*stream
,
338 if (!token_stream_peek_string (stream
, token
))
341 token_stream_next (stream
);
346 token_stream_require (TokenStream
*stream
,
348 const gchar
*purpose
,
352 if (!token_stream_consume (stream
, token
))
354 token_stream_set_error (stream
, error
, FALSE
,
355 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN
,
356 "expected '%s'%s", token
, purpose
);
364 token_stream_assert (TokenStream
*stream
,
367 gboolean correct_token
;
369 correct_token
= token_stream_consume (stream
, token
);
370 g_assert (correct_token
);
374 token_stream_get (TokenStream
*stream
)
378 if (!token_stream_prepare (stream
))
381 result
= g_strndup (stream
->this, stream
->stream
- stream
->this);
387 token_stream_start_ref (TokenStream
*stream
,
390 token_stream_prepare (stream
);
391 ref
->start
= stream
->this - stream
->start
;
395 token_stream_end_ref (TokenStream
*stream
,
398 ref
->end
= stream
->stream
- stream
->start
;
402 pattern_copy (gchar
**out
,
407 while (**in
== 'a' || **in
== 'm' || **in
== 'M')
408 *(*out
)++ = *(*in
)++;
412 if (**in
== '(' || **in
== '{')
415 else if (**in
== ')' || **in
== '}')
418 *(*out
)++ = *(*in
)++;
424 pattern_coalesce (const gchar
*left
,
430 /* the length of the output is loosely bound by the sum of the input
431 * lengths, not simply the greater of the two lengths.
433 * (*(iii)) + ((iii)*) ((iii)(iii))
437 out
= result
= g_malloc (strlen (left
) + strlen (right
));
439 while (*left
&& *right
)
449 const gchar
**one
= &left
, **the_other
= &right
;
452 if (**one
== '*' && **the_other
!= ')')
454 pattern_copy (&out
, the_other
);
458 else if (**one
== 'M' && **the_other
== 'm')
460 *out
++ = *(*the_other
)++;
463 else if (**one
== 'M' && **the_other
!= 'm')
468 else if (**one
== 'N' && strchr ("ynqiuxthd", **the_other
))
470 *out
++ = *(*the_other
)++;
474 else if (**one
== 'S' && strchr ("sog", **the_other
))
476 *out
++ = *(*the_other
)++;
480 else if (one
== &left
)
482 one
= &right
, the_other
= &left
;
502 typedef struct _AST AST
;
503 typedef gchar
* (*get_pattern_func
) (AST
*ast
,
505 typedef GVariant
* (*get_value_func
) (AST
*ast
,
506 const GVariantType
*type
,
508 typedef GVariant
* (*get_base_value_func
) (AST
*ast
,
509 const GVariantType
*type
,
511 typedef void (*free_func
) (AST
*ast
);
515 gchar
* (* get_pattern
) (AST
*ast
,
517 GVariant
* (* get_value
) (AST
*ast
,
518 const GVariantType
*type
,
520 GVariant
* (* get_base_value
) (AST
*ast
,
521 const GVariantType
*type
,
523 void (* free
) (AST
*ast
);
528 const ASTClass
*class;
529 SourceRef source_ref
;
533 ast_get_pattern (AST
*ast
,
536 return ast
->class->get_pattern (ast
, error
);
540 ast_get_value (AST
*ast
,
541 const GVariantType
*type
,
544 return ast
->class->get_value (ast
, type
, error
);
550 ast
->class->free (ast
);
555 ast_set_error (AST
*ast
,
564 va_start (ap
, format
);
565 parser_set_error_va (error
, &ast
->source_ref
,
566 other_ast
? & other_ast
->source_ref
: NULL
,
573 ast_type_error (AST
*ast
,
574 const GVariantType
*type
,
579 typestr
= g_variant_type_dup_string (type
);
580 ast_set_error (ast
, error
, NULL
,
581 G_VARIANT_PARSE_ERROR_TYPE_ERROR
,
582 "can not parse as value of type '%s'",
590 ast_resolve (AST
*ast
,
597 pattern
= ast_get_pattern (ast
, error
);
602 /* choose reasonable defaults
604 * 1) favour non-maybe values where possible
605 * 2) default type for strings is 's'
606 * 3) default type for integers is 'i'
608 for (i
= 0; pattern
[i
]; i
++)
612 ast_set_error (ast
, error
, NULL
,
613 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE
,
614 "unable to infer type");
630 pattern
[j
++] = pattern
[i
];
635 value
= ast_get_value (ast
, G_VARIANT_TYPE (pattern
), error
);
642 static AST
*parse (TokenStream
*stream
,
647 ast_array_append (AST
***array
,
651 if ((*n_items
& (*n_items
- 1)) == 0)
652 *array
= g_renew (AST
*, *array
, *n_items
? 2 ** n_items
: 1);
654 (*array
)[(*n_items
)++] = ast
;
658 ast_array_free (AST
**array
,
663 for (i
= 0; i
< n_items
; i
++)
669 ast_array_get_pattern (AST
**array
,
676 pattern
= ast_get_pattern (array
[0], error
);
681 for (i
= 1; i
< n_items
; i
++)
685 tmp
= ast_get_pattern (array
[i
], error
);
693 merged
= pattern_coalesce (pattern
, tmp
);
698 /* set coalescence implies pairwise coalescence (i think).
699 * we should therefore be able to trace the failure to a single
710 /* if 'j' reaches 'i' then we failed to find the pair */
713 tmp2
= ast_get_pattern (array
[j
], NULL
);
714 g_assert (tmp2
!= NULL
);
716 m
= pattern_coalesce (tmp
, tmp2
);
722 /* we found a conflict between 'i' and 'j'.
724 * report the error. note: 'j' is first.
726 ast_set_error (array
[j
], error
, array
[i
],
727 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE
,
728 "unable to find a common type");
752 maybe_get_pattern (AST
*ast
,
755 Maybe
*maybe
= (Maybe
*) ast
;
757 if (maybe
->child
!= NULL
)
759 gchar
*child_pattern
;
762 child_pattern
= ast_get_pattern (maybe
->child
, error
);
764 if (child_pattern
== NULL
)
767 pattern
= g_strdup_printf ("m%s", child_pattern
);
768 g_free (child_pattern
);
773 return g_strdup ("m*");
777 maybe_get_value (AST
*ast
,
778 const GVariantType
*type
,
781 Maybe
*maybe
= (Maybe
*) ast
;
784 if (!g_variant_type_is_maybe (type
))
785 return ast_type_error (ast
, type
, error
);
787 type
= g_variant_type_element (type
);
791 value
= ast_get_value (maybe
->child
, type
, error
);
799 return g_variant_new_maybe (type
, value
);
803 maybe_free (AST
*ast
)
805 Maybe
*maybe
= (Maybe
*) ast
;
807 if (maybe
->child
!= NULL
)
808 ast_free (maybe
->child
);
810 g_slice_free (Maybe
, maybe
);
814 maybe_parse (TokenStream
*stream
,
818 static const ASTClass maybe_class
= {
820 maybe_get_value
, NULL
,
826 if (token_stream_consume (stream
, "just"))
828 child
= parse (stream
, app
, error
);
833 else if (!token_stream_consume (stream
, "nothing"))
835 token_stream_set_error (stream
, error
, TRUE
,
836 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
841 maybe
= g_slice_new (Maybe
);
842 maybe
->ast
.class = &maybe_class
;
843 maybe
->child
= child
;
845 return (AST
*) maybe
;
849 maybe_wrapper (AST
*ast
,
850 const GVariantType
*type
,
853 const GVariantType
*t
;
857 for (depth
= 0, t
= type
;
858 g_variant_type_is_maybe (t
);
859 depth
++, t
= g_variant_type_element (t
));
861 value
= ast
->class->get_base_value (ast
, t
, error
);
867 value
= g_variant_new_maybe (NULL
, value
);
881 array_get_pattern (AST
*ast
,
884 Array
*array
= (Array
*) ast
;
888 if (array
->n_children
== 0)
889 return g_strdup ("Ma*");
891 pattern
= ast_array_get_pattern (array
->children
, array
->n_children
, error
);
896 result
= g_strdup_printf ("Ma%s", pattern
);
903 array_get_value (AST
*ast
,
904 const GVariantType
*type
,
907 Array
*array
= (Array
*) ast
;
908 const GVariantType
*childtype
;
909 GVariantBuilder builder
;
912 if (!g_variant_type_is_array (type
))
913 return ast_type_error (ast
, type
, error
);
915 g_variant_builder_init (&builder
, type
);
916 childtype
= g_variant_type_element (type
);
918 for (i
= 0; i
< array
->n_children
; i
++)
922 if (!(child
= ast_get_value (array
->children
[i
], childtype
, error
)))
924 g_variant_builder_clear (&builder
);
928 g_variant_builder_add_value (&builder
, child
);
931 return g_variant_builder_end (&builder
);
935 array_free (AST
*ast
)
937 Array
*array
= (Array
*) ast
;
939 ast_array_free (array
->children
, array
->n_children
);
940 g_slice_free (Array
, array
);
944 array_parse (TokenStream
*stream
,
948 static const ASTClass array_class
= {
950 maybe_wrapper
, array_get_value
,
953 gboolean need_comma
= FALSE
;
956 array
= g_slice_new (Array
);
957 array
->ast
.class = &array_class
;
958 array
->children
= NULL
;
959 array
->n_children
= 0;
961 token_stream_assert (stream
, "[");
962 while (!token_stream_consume (stream
, "]"))
967 !token_stream_require (stream
, ",",
968 " or ']' to follow array element",
972 child
= parse (stream
, app
, error
);
977 ast_array_append (&array
->children
, &array
->n_children
, child
);
981 return (AST
*) array
;
984 ast_array_free (array
->children
, array
->n_children
);
985 g_slice_free (Array
, array
);
999 tuple_get_pattern (AST
*ast
,
1002 Tuple
*tuple
= (Tuple
*) ast
;
1003 gchar
*result
= NULL
;
1007 parts
= g_new (gchar
*, tuple
->n_children
+ 4);
1008 parts
[tuple
->n_children
+ 1] = (gchar
*) ")";
1009 parts
[tuple
->n_children
+ 2] = NULL
;
1010 parts
[0] = (gchar
*) "M(";
1012 for (i
= 0; i
< tuple
->n_children
; i
++)
1013 if (!(parts
[i
+ 1] = ast_get_pattern (tuple
->children
[i
], error
)))
1016 if (i
== tuple
->n_children
)
1017 result
= g_strjoinv ("", parts
);
1019 /* parts[0] should not be freed */
1021 g_free (parts
[i
--]);
1028 tuple_get_value (AST
*ast
,
1029 const GVariantType
*type
,
1032 Tuple
*tuple
= (Tuple
*) ast
;
1033 const GVariantType
*childtype
;
1034 GVariantBuilder builder
;
1037 if (!g_variant_type_is_tuple (type
))
1038 return ast_type_error (ast
, type
, error
);
1040 g_variant_builder_init (&builder
, type
);
1041 childtype
= g_variant_type_first (type
);
1043 for (i
= 0; i
< tuple
->n_children
; i
++)
1047 if (childtype
== NULL
)
1049 g_variant_builder_clear (&builder
);
1050 return ast_type_error (ast
, type
, error
);
1053 if (!(child
= ast_get_value (tuple
->children
[i
], childtype
, error
)))
1055 g_variant_builder_clear (&builder
);
1059 g_variant_builder_add_value (&builder
, child
);
1060 childtype
= g_variant_type_next (childtype
);
1063 if (childtype
!= NULL
)
1065 g_variant_builder_clear (&builder
);
1066 return ast_type_error (ast
, type
, error
);
1069 return g_variant_builder_end (&builder
);
1073 tuple_free (AST
*ast
)
1075 Tuple
*tuple
= (Tuple
*) ast
;
1077 ast_array_free (tuple
->children
, tuple
->n_children
);
1078 g_slice_free (Tuple
, tuple
);
1082 tuple_parse (TokenStream
*stream
,
1086 static const ASTClass tuple_class
= {
1088 maybe_wrapper
, tuple_get_value
,
1091 gboolean need_comma
= FALSE
;
1092 gboolean first
= TRUE
;
1095 tuple
= g_slice_new (Tuple
);
1096 tuple
->ast
.class = &tuple_class
;
1097 tuple
->children
= NULL
;
1098 tuple
->n_children
= 0;
1100 token_stream_assert (stream
, "(");
1101 while (!token_stream_consume (stream
, ")"))
1106 !token_stream_require (stream
, ",",
1107 " or ')' to follow tuple element",
1111 child
= parse (stream
, app
, error
);
1116 ast_array_append (&tuple
->children
, &tuple
->n_children
, child
);
1118 /* the first time, we absolutely require a comma, so grab it here
1119 * and leave need_comma = FALSE so that the code above doesn't
1120 * require a second comma.
1122 * the second and remaining times, we set need_comma = TRUE.
1126 if (!token_stream_require (stream
, ",",
1127 " after first tuple element", error
))
1136 return (AST
*) tuple
;
1139 ast_array_free (tuple
->children
, tuple
->n_children
);
1140 g_slice_free (Tuple
, tuple
);
1153 variant_get_pattern (AST
*ast
,
1156 return g_strdup ("Mv");
1160 variant_get_value (AST
*ast
,
1161 const GVariantType
*type
,
1164 Variant
*variant
= (Variant
*) ast
;
1167 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_VARIANT
))
1168 return ast_type_error (ast
, type
, error
);
1170 child
= ast_resolve (variant
->value
, error
);
1175 return g_variant_new_variant (child
);
1179 variant_free (AST
*ast
)
1181 Variant
*variant
= (Variant
*) ast
;
1183 ast_free (variant
->value
);
1184 g_slice_free (Variant
, variant
);
1188 variant_parse (TokenStream
*stream
,
1192 static const ASTClass variant_class
= {
1193 variant_get_pattern
,
1194 maybe_wrapper
, variant_get_value
,
1200 token_stream_assert (stream
, "<");
1201 value
= parse (stream
, app
, error
);
1206 if (!token_stream_require (stream
, ">", " to follow variant value", error
))
1212 variant
= g_slice_new (Variant
);
1213 variant
->ast
.class = &variant_class
;
1214 variant
->value
= value
;
1216 return (AST
*) variant
;
1229 dictionary_get_pattern (AST
*ast
,
1232 Dictionary
*dict
= (Dictionary
*) ast
;
1233 gchar
*value_pattern
;
1238 if (dict
->n_children
== 0)
1239 return g_strdup ("Ma{**}");
1241 key_pattern
= ast_array_get_pattern (dict
->keys
,
1242 abs (dict
->n_children
),
1245 if (key_pattern
== NULL
)
1248 /* we can not have maybe keys */
1249 if (key_pattern
[0] == 'M')
1250 key_char
= key_pattern
[1];
1252 key_char
= key_pattern
[0];
1254 g_free (key_pattern
);
1257 * plus undetermined number type and undetermined string type.
1259 if (!strchr ("bynqiuxthdsogNS", key_char
))
1261 ast_set_error (ast
, error
, NULL
,
1262 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED
,
1263 "dictionary keys must have basic types");
1267 value_pattern
= ast_get_pattern (dict
->values
[0], error
);
1269 if (value_pattern
== NULL
)
1272 result
= g_strdup_printf ("M%s{%c%s}",
1273 dict
->n_children
> 0 ? "a" : "",
1274 key_char
, value_pattern
);
1275 g_free (value_pattern
);
1281 dictionary_get_value (AST
*ast
,
1282 const GVariantType
*type
,
1285 Dictionary
*dict
= (Dictionary
*) ast
;
1287 if (dict
->n_children
== -1)
1289 const GVariantType
*subtype
;
1290 GVariantBuilder builder
;
1293 if (!g_variant_type_is_dict_entry (type
))
1294 return ast_type_error (ast
, type
, error
);
1296 g_variant_builder_init (&builder
, type
);
1298 subtype
= g_variant_type_key (type
);
1299 if (!(subvalue
= ast_get_value (dict
->keys
[0], subtype
, error
)))
1301 g_variant_builder_clear (&builder
);
1304 g_variant_builder_add_value (&builder
, subvalue
);
1306 subtype
= g_variant_type_value (type
);
1307 if (!(subvalue
= ast_get_value (dict
->values
[0], subtype
, error
)))
1309 g_variant_builder_clear (&builder
);
1312 g_variant_builder_add_value (&builder
, subvalue
);
1314 return g_variant_builder_end (&builder
);
1318 const GVariantType
*entry
, *key
, *val
;
1319 GVariantBuilder builder
;
1322 if (!g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE_DICTIONARY
))
1323 return ast_type_error (ast
, type
, error
);
1325 entry
= g_variant_type_element (type
);
1326 key
= g_variant_type_key (entry
);
1327 val
= g_variant_type_value (entry
);
1329 g_variant_builder_init (&builder
, type
);
1331 for (i
= 0; i
< dict
->n_children
; i
++)
1335 g_variant_builder_open (&builder
, entry
);
1337 if (!(subvalue
= ast_get_value (dict
->keys
[i
], key
, error
)))
1339 g_variant_builder_clear (&builder
);
1342 g_variant_builder_add_value (&builder
, subvalue
);
1344 if (!(subvalue
= ast_get_value (dict
->values
[i
], val
, error
)))
1346 g_variant_builder_clear (&builder
);
1349 g_variant_builder_add_value (&builder
, subvalue
);
1350 g_variant_builder_close (&builder
);
1353 return g_variant_builder_end (&builder
);
1358 dictionary_free (AST
*ast
)
1360 Dictionary
*dict
= (Dictionary
*) ast
;
1363 if (dict
->n_children
> -1)
1364 n_children
= dict
->n_children
;
1368 ast_array_free (dict
->keys
, n_children
);
1369 ast_array_free (dict
->values
, n_children
);
1370 g_slice_free (Dictionary
, dict
);
1374 dictionary_parse (TokenStream
*stream
,
1378 static const ASTClass dictionary_class
= {
1379 dictionary_get_pattern
,
1380 maybe_wrapper
, dictionary_get_value
,
1383 gint n_keys
, n_values
;
1388 dict
= g_slice_new (Dictionary
);
1389 dict
->ast
.class = &dictionary_class
;
1391 dict
->values
= NULL
;
1392 n_keys
= n_values
= 0;
1394 token_stream_assert (stream
, "{");
1396 if (token_stream_consume (stream
, "}"))
1398 dict
->n_children
= 0;
1399 return (AST
*) dict
;
1402 if ((first
= parse (stream
, app
, error
)) == NULL
)
1405 ast_array_append (&dict
->keys
, &n_keys
, first
);
1407 only_one
= token_stream_consume (stream
, ",");
1409 !token_stream_require (stream
, ":",
1410 " or ',' to follow dictionary entry key",
1414 if ((first
= parse (stream
, app
, error
)) == NULL
)
1417 ast_array_append (&dict
->values
, &n_values
, first
);
1421 if (!token_stream_require (stream
, "}", " at end of dictionary entry",
1425 g_assert (n_keys
== 1 && n_values
== 1);
1426 dict
->n_children
= -1;
1428 return (AST
*) dict
;
1431 while (!token_stream_consume (stream
, "}"))
1435 if (!token_stream_require (stream
, ",",
1436 " or '}' to follow dictionary entry", error
))
1439 child
= parse (stream
, app
, error
);
1444 ast_array_append (&dict
->keys
, &n_keys
, child
);
1446 if (!token_stream_require (stream
, ":",
1447 " to follow dictionary entry key", error
))
1450 child
= parse (stream
, app
, error
);
1455 ast_array_append (&dict
->values
, &n_values
, child
);
1458 g_assert (n_keys
== n_values
);
1459 dict
->n_children
= n_keys
;
1461 return (AST
*) dict
;
1464 ast_array_free (dict
->keys
, n_keys
);
1465 ast_array_free (dict
->values
, n_values
);
1466 g_slice_free (Dictionary
, dict
);
1478 string_get_pattern (AST
*ast
,
1481 return g_strdup ("MS");
1485 string_get_value (AST
*ast
,
1486 const GVariantType
*type
,
1489 String
*string
= (String
*) ast
;
1491 if (g_variant_type_equal (type
, G_VARIANT_TYPE_STRING
))
1492 return g_variant_new_string (string
->string
);
1494 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_OBJECT_PATH
))
1496 if (!g_variant_is_object_path (string
->string
))
1498 ast_set_error (ast
, error
, NULL
,
1499 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH
,
1500 "not a valid object path");
1504 return g_variant_new_object_path (string
->string
);
1507 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_SIGNATURE
))
1509 if (!g_variant_is_signature (string
->string
))
1511 ast_set_error (ast
, error
, NULL
,
1512 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE
,
1513 "not a valid signature");
1517 return g_variant_new_signature (string
->string
);
1521 return ast_type_error (ast
, type
, error
);
1525 string_free (AST
*ast
)
1527 String
*string
= (String
*) ast
;
1529 g_free (string
->string
);
1530 g_slice_free (String
, string
);
1534 unicode_unescape (const gchar
*src
,
1548 g_assert (length
< sizeof (buffer
));
1549 strncpy (buffer
, src
+ *src_ofs
, length
);
1550 buffer
[length
] = '\0';
1552 value
= g_ascii_strtoull (buffer
, &end
, 0x10);
1554 if (value
== 0 || end
!= buffer
+ length
)
1556 parser_set_error (error
, ref
, NULL
,
1557 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1558 "invalid %d-character unicode escape", length
);
1562 g_assert (value
<= G_MAXUINT32
);
1564 *dest_ofs
+= g_unichar_to_utf8 (value
, dest
+ *dest_ofs
);
1571 string_parse (TokenStream
*stream
,
1575 static const ASTClass string_class
= {
1577 maybe_wrapper
, string_get_value
,
1588 token_stream_start_ref (stream
, &ref
);
1589 token
= token_stream_get (stream
);
1590 token_stream_end_ref (stream
, &ref
);
1591 length
= strlen (token
);
1594 str
= g_malloc (length
);
1595 g_assert (quote
== '"' || quote
== '\'');
1598 while (token
[i
] != quote
)
1602 parser_set_error (error
, &ref
, NULL
,
1603 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1604 "unterminated string constant");
1613 parser_set_error (error
, &ref
, NULL
,
1614 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1615 "unterminated string constant");
1621 if (!unicode_unescape (token
, &i
, str
, &j
, 4, &ref
, error
))
1630 if (!unicode_unescape (token
, &i
, str
, &j
, 8, &ref
, error
))
1638 case 'a': str
[j
++] = '\a'; i
++; continue;
1639 case 'b': str
[j
++] = '\b'; i
++; continue;
1640 case 'f': str
[j
++] = '\f'; i
++; continue;
1641 case 'n': str
[j
++] = '\n'; i
++; continue;
1642 case 'r': str
[j
++] = '\r'; i
++; continue;
1643 case 't': str
[j
++] = '\t'; i
++; continue;
1644 case 'v': str
[j
++] = '\v'; i
++; continue;
1645 case '\n': i
++; continue;
1649 str
[j
++] = token
[i
++];
1654 string
= g_slice_new (String
);
1655 string
->ast
.class = &string_class
;
1656 string
->string
= str
;
1658 token_stream_next (stream
);
1660 return (AST
*) string
;
1670 bytestring_get_pattern (AST
*ast
,
1673 return g_strdup ("May");
1677 bytestring_get_value (AST
*ast
,
1678 const GVariantType
*type
,
1681 ByteString
*string
= (ByteString
*) ast
;
1683 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BYTESTRING
))
1684 return ast_type_error (ast
, type
, error
);
1686 return g_variant_new_bytestring (string
->string
);
1690 bytestring_free (AST
*ast
)
1692 ByteString
*string
= (ByteString
*) ast
;
1694 g_free (string
->string
);
1695 g_slice_free (ByteString
, string
);
1699 bytestring_parse (TokenStream
*stream
,
1703 static const ASTClass bytestring_class
= {
1704 bytestring_get_pattern
,
1705 maybe_wrapper
, bytestring_get_value
,
1716 token_stream_start_ref (stream
, &ref
);
1717 token
= token_stream_get (stream
);
1718 token_stream_end_ref (stream
, &ref
);
1719 g_assert (token
[0] == 'b');
1720 length
= strlen (token
);
1723 str
= g_malloc (length
);
1724 g_assert (quote
== '"' || quote
== '\'');
1727 while (token
[i
] != quote
)
1731 parser_set_error (error
, &ref
, NULL
,
1732 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1733 "unterminated string constant");
1742 parser_set_error (error
, &ref
, NULL
,
1743 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1744 "unterminated string constant");
1749 case '0': case '1': case '2': case '3':
1750 case '4': case '5': case '6': case '7':
1752 /* up to 3 characters */
1753 guchar val
= token
[i
++] - '0';
1755 if ('0' <= token
[i
] && token
[i
] < '8')
1756 val
= (val
<< 3) | (token
[i
++] - '0');
1758 if ('0' <= token
[i
] && token
[i
] < '8')
1759 val
= (val
<< 3) | (token
[i
++] - '0');
1765 case 'a': str
[j
++] = '\a'; i
++; continue;
1766 case 'b': str
[j
++] = '\b'; i
++; continue;
1767 case 'f': str
[j
++] = '\f'; i
++; continue;
1768 case 'n': str
[j
++] = '\n'; i
++; continue;
1769 case 'r': str
[j
++] = '\r'; i
++; continue;
1770 case 't': str
[j
++] = '\t'; i
++; continue;
1771 case 'v': str
[j
++] = '\v'; i
++; continue;
1772 case '\n': i
++; continue;
1776 str
[j
++] = token
[i
++];
1781 string
= g_slice_new (ByteString
);
1782 string
->ast
.class = &bytestring_class
;
1783 string
->string
= str
;
1785 token_stream_next (stream
);
1787 return (AST
*) string
;
1798 number_get_pattern (AST
*ast
,
1801 Number
*number
= (Number
*) ast
;
1803 if (strchr (number
->token
, '.') ||
1804 (!g_str_has_prefix (number
->token
, "0x") && strchr (number
->token
, 'e')) ||
1805 strstr (number
->token
, "inf") ||
1806 strstr (number
->token
, "nan"))
1807 return g_strdup ("Md");
1809 return g_strdup ("MN");
1813 number_overflow (AST
*ast
,
1814 const GVariantType
*type
,
1817 ast_set_error (ast
, error
, NULL
,
1818 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE
,
1819 "number out of range for type '%c'",
1820 g_variant_type_peek_string (type
)[0]);
1825 number_get_value (AST
*ast
,
1826 const GVariantType
*type
,
1829 Number
*number
= (Number
*) ast
;
1837 token
= number
->token
;
1839 if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
1844 dbl_val
= g_ascii_strtod (token
, &end
);
1845 if (dbl_val
!= 0.0 && errno
== ERANGE
)
1847 ast_set_error (ast
, error
, NULL
,
1848 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1849 "number too big for any type");
1853 /* silence uninitialised warnings... */
1860 negative
= token
[0] == '-';
1861 if (token
[0] == '-')
1865 abs_val
= g_ascii_strtoull (token
, &end
, 0);
1866 if (abs_val
== G_MAXUINT64
&& errno
== ERANGE
)
1868 ast_set_error (ast
, error
, NULL
,
1869 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1870 "integer too big for any type");
1877 /* silence uninitialised warning... */
1885 ref
= ast
->source_ref
;
1886 ref
.start
+= end
- number
->token
;
1887 ref
.end
= ref
.start
+ 1;
1889 parser_set_error (error
, &ref
, NULL
,
1890 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1891 "invalid character in number");
1896 return g_variant_new_double (dbl_val
);
1898 switch (*g_variant_type_peek_string (type
))
1901 if (negative
|| abs_val
> G_MAXUINT8
)
1902 return number_overflow (ast
, type
, error
);
1903 return g_variant_new_byte (abs_val
);
1906 if (abs_val
- negative
> G_MAXINT16
)
1907 return number_overflow (ast
, type
, error
);
1908 return g_variant_new_int16 (negative
? -abs_val
: abs_val
);
1911 if (negative
|| abs_val
> G_MAXUINT16
)
1912 return number_overflow (ast
, type
, error
);
1913 return g_variant_new_uint16 (abs_val
);
1916 if (abs_val
- negative
> G_MAXINT32
)
1917 return number_overflow (ast
, type
, error
);
1918 return g_variant_new_int32 (negative
? -abs_val
: abs_val
);
1921 if (negative
|| abs_val
> G_MAXUINT32
)
1922 return number_overflow (ast
, type
, error
);
1923 return g_variant_new_uint32 (abs_val
);
1926 if (abs_val
- negative
> G_MAXINT64
)
1927 return number_overflow (ast
, type
, error
);
1928 return g_variant_new_int64 (negative
? -abs_val
: abs_val
);
1932 return number_overflow (ast
, type
, error
);
1933 return g_variant_new_uint64 (abs_val
);
1936 if (abs_val
- negative
> G_MAXINT32
)
1937 return number_overflow (ast
, type
, error
);
1938 return g_variant_new_handle (negative
? -abs_val
: abs_val
);
1941 return ast_type_error (ast
, type
, error
);
1946 number_free (AST
*ast
)
1948 Number
*number
= (Number
*) ast
;
1950 g_free (number
->token
);
1951 g_slice_free (Number
, number
);
1955 number_parse (TokenStream
*stream
,
1959 static const ASTClass number_class
= {
1961 maybe_wrapper
, number_get_value
,
1966 number
= g_slice_new (Number
);
1967 number
->ast
.class = &number_class
;
1968 number
->token
= token_stream_get (stream
);
1969 token_stream_next (stream
);
1971 return (AST
*) number
;
1981 boolean_get_pattern (AST
*ast
,
1984 return g_strdup ("Mb");
1988 boolean_get_value (AST
*ast
,
1989 const GVariantType
*type
,
1992 Boolean
*boolean
= (Boolean
*) ast
;
1994 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
1995 return ast_type_error (ast
, type
, error
);
1997 return g_variant_new_boolean (boolean
->value
);
2001 boolean_free (AST
*ast
)
2003 Boolean
*boolean
= (Boolean
*) ast
;
2005 g_slice_free (Boolean
, boolean
);
2009 boolean_new (gboolean value
)
2011 static const ASTClass boolean_class
= {
2012 boolean_get_pattern
,
2013 maybe_wrapper
, boolean_get_value
,
2018 boolean
= g_slice_new (Boolean
);
2019 boolean
->ast
.class = &boolean_class
;
2020 boolean
->value
= value
;
2022 return (AST
*) boolean
;
2033 positional_get_pattern (AST
*ast
,
2036 Positional
*positional
= (Positional
*) ast
;
2038 return g_strdup (g_variant_get_type_string (positional
->value
));
2042 positional_get_value (AST
*ast
,
2043 const GVariantType
*type
,
2046 Positional
*positional
= (Positional
*) ast
;
2049 g_assert (positional
->value
!= NULL
);
2051 if G_UNLIKELY (!g_variant_is_of_type (positional
->value
, type
))
2052 return ast_type_error (ast
, type
, error
);
2054 /* NOTE: if _get is called more than once then
2055 * things get messed up with respect to floating refs.
2057 * fortunately, this function should only ever get called once.
2059 g_assert (positional
->value
!= NULL
);
2060 value
= positional
->value
;
2061 positional
->value
= NULL
;
2067 positional_free (AST
*ast
)
2069 Positional
*positional
= (Positional
*) ast
;
2071 /* if positional->value is set, just leave it.
2072 * memory management doesn't matter in case of programmer error.
2074 g_slice_free (Positional
, positional
);
2078 positional_parse (TokenStream
*stream
,
2082 static const ASTClass positional_class
= {
2083 positional_get_pattern
,
2084 positional_get_value
, NULL
,
2087 Positional
*positional
;
2088 const gchar
*endptr
;
2091 token
= token_stream_get (stream
);
2092 g_assert (token
[0] == '%');
2094 positional
= g_slice_new (Positional
);
2095 positional
->ast
.class = &positional_class
;
2096 positional
->value
= g_variant_new_va (token
+ 1, &endptr
, app
);
2098 if (*endptr
|| positional
->value
== NULL
)
2100 token_stream_set_error (stream
, error
, TRUE
,
2101 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING
,
2102 "invalid GVariant format string");
2103 /* memory management doesn't matter in case of programmer error. */
2107 token_stream_next (stream
);
2110 return (AST
*) positional
;
2122 typedecl_get_pattern (AST
*ast
,
2125 TypeDecl
*decl
= (TypeDecl
*) ast
;
2127 return g_variant_type_dup_string (decl
->type
);
2131 typedecl_get_value (AST
*ast
,
2132 const GVariantType
*type
,
2135 TypeDecl
*decl
= (TypeDecl
*) ast
;
2137 return ast_get_value (decl
->child
, type
, error
);
2141 typedecl_free (AST
*ast
)
2143 TypeDecl
*decl
= (TypeDecl
*) ast
;
2145 ast_free (decl
->child
);
2146 g_variant_type_free (decl
->type
);
2147 g_slice_free (TypeDecl
, decl
);
2151 typedecl_parse (TokenStream
*stream
,
2155 static const ASTClass typedecl_class
= {
2156 typedecl_get_pattern
,
2157 typedecl_get_value
, NULL
,
2164 if (token_stream_peek (stream
, '@'))
2168 token
= token_stream_get (stream
);
2170 if (!g_variant_type_string_is_valid (token
+ 1))
2172 token_stream_set_error (stream
, error
, TRUE
,
2173 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING
,
2174 "invalid type declaration");
2180 type
= g_variant_type_new (token
+ 1);
2182 if (!g_variant_type_is_definite (type
))
2184 token_stream_set_error (stream
, error
, TRUE
,
2185 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED
,
2186 "type declarations must be definite");
2187 g_variant_type_free (type
);
2193 token_stream_next (stream
);
2198 if (token_stream_consume (stream
, "boolean"))
2199 type
= g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN
);
2201 else if (token_stream_consume (stream
, "byte"))
2202 type
= g_variant_type_copy (G_VARIANT_TYPE_BYTE
);
2204 else if (token_stream_consume (stream
, "int16"))
2205 type
= g_variant_type_copy (G_VARIANT_TYPE_INT16
);
2207 else if (token_stream_consume (stream
, "uint16"))
2208 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT16
);
2210 else if (token_stream_consume (stream
, "int32"))
2211 type
= g_variant_type_copy (G_VARIANT_TYPE_INT32
);
2213 else if (token_stream_consume (stream
, "handle"))
2214 type
= g_variant_type_copy (G_VARIANT_TYPE_HANDLE
);
2216 else if (token_stream_consume (stream
, "uint32"))
2217 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT32
);
2219 else if (token_stream_consume (stream
, "int64"))
2220 type
= g_variant_type_copy (G_VARIANT_TYPE_INT64
);
2222 else if (token_stream_consume (stream
, "uint64"))
2223 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT64
);
2225 else if (token_stream_consume (stream
, "double"))
2226 type
= g_variant_type_copy (G_VARIANT_TYPE_DOUBLE
);
2228 else if (token_stream_consume (stream
, "string"))
2229 type
= g_variant_type_copy (G_VARIANT_TYPE_STRING
);
2231 else if (token_stream_consume (stream
, "objectpath"))
2232 type
= g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH
);
2234 else if (token_stream_consume (stream
, "signature"))
2235 type
= g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE
);
2239 token_stream_set_error (stream
, error
, TRUE
,
2240 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
2246 if ((child
= parse (stream
, app
, error
)) == NULL
)
2248 g_variant_type_free (type
);
2252 decl
= g_slice_new (TypeDecl
);
2253 decl
->ast
.class = &typedecl_class
;
2255 decl
->child
= child
;
2257 return (AST
*) decl
;
2261 parse (TokenStream
*stream
,
2265 SourceRef source_ref
;
2268 token_stream_prepare (stream
);
2269 token_stream_start_ref (stream
, &source_ref
);
2271 if (token_stream_peek (stream
, '['))
2272 result
= array_parse (stream
, app
, error
);
2274 else if (token_stream_peek (stream
, '('))
2275 result
= tuple_parse (stream
, app
, error
);
2277 else if (token_stream_peek (stream
, '<'))
2278 result
= variant_parse (stream
, app
, error
);
2280 else if (token_stream_peek (stream
, '{'))
2281 result
= dictionary_parse (stream
, app
, error
);
2283 else if (app
&& token_stream_peek (stream
, '%'))
2284 result
= positional_parse (stream
, app
, error
);
2286 else if (token_stream_consume (stream
, "true"))
2287 result
= boolean_new (TRUE
);
2289 else if (token_stream_consume (stream
, "false"))
2290 result
= boolean_new (FALSE
);
2292 else if (token_stream_is_numeric (stream
) ||
2293 token_stream_peek_string (stream
, "inf") ||
2294 token_stream_peek_string (stream
, "nan"))
2295 result
= number_parse (stream
, app
, error
);
2297 else if (token_stream_peek (stream
, 'n') ||
2298 token_stream_peek (stream
, 'j'))
2299 result
= maybe_parse (stream
, app
, error
);
2301 else if (token_stream_peek (stream
, '@') ||
2302 token_stream_is_keyword (stream
))
2303 result
= typedecl_parse (stream
, app
, error
);
2305 else if (token_stream_peek (stream
, '\'') ||
2306 token_stream_peek (stream
, '"'))
2307 result
= string_parse (stream
, app
, error
);
2309 else if (token_stream_peek2 (stream
, 'b', '\'') ||
2310 token_stream_peek2 (stream
, 'b', '"'))
2311 result
= bytestring_parse (stream
, app
, error
);
2315 token_stream_set_error (stream
, error
, FALSE
,
2316 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED
,
2323 token_stream_end_ref (stream
, &source_ref
);
2324 result
->source_ref
= source_ref
;
2332 * @type: (nullable): a #GVariantType, or %NULL
2333 * @text: a string containing a GVariant in text form
2334 * @limit: (nullable): a pointer to the end of @text, or %NULL
2335 * @endptr: (nullable): a location to store the end pointer, or %NULL
2336 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2338 * Parses a #GVariant from a text representation.
2340 * A single #GVariant is parsed from the content of @text.
2342 * The format is described [here][gvariant-text].
2344 * The memory at @limit will never be accessed and the parser behaves as
2345 * if the character at @limit is the nul terminator. This has the
2346 * effect of bounding @text.
2348 * If @endptr is non-%NULL then @text is permitted to contain data
2349 * following the value that this function parses and @endptr will be
2350 * updated to point to the first character past the end of the text
2351 * parsed by this function. If @endptr is %NULL and there is extra data
2352 * then an error is returned.
2354 * If @type is non-%NULL then the value will be parsed to have that
2355 * type. This may result in additional parse errors (in the case that
2356 * the parsed value doesn't fit the type) but may also result in fewer
2357 * errors (in the case that the type would have been ambiguous, such as
2358 * with empty arrays).
2360 * In the event that the parsing is successful, the resulting #GVariant
2361 * is returned. It is never floating, and must be freed with
2362 * g_variant_unref().
2364 * In case of any error, %NULL will be returned. If @error is non-%NULL
2365 * then it will be set to reflect the error that occurred.
2367 * Officially, the language understood by the parser is "any string
2368 * produced by g_variant_print()".
2370 * Returns: a non-floating reference to a #GVariant, or %NULL
2373 g_variant_parse (const GVariantType
*type
,
2376 const gchar
**endptr
,
2379 TokenStream stream
= { 0, };
2380 GVariant
*result
= NULL
;
2383 g_return_val_if_fail (text
!= NULL
, NULL
);
2384 g_return_val_if_fail (text
== limit
|| text
!= NULL
, NULL
);
2386 stream
.start
= text
;
2387 stream
.stream
= text
;
2390 if ((ast
= parse (&stream
, NULL
, error
)))
2393 result
= ast_resolve (ast
, error
);
2395 result
= ast_get_value (ast
, type
, error
);
2399 g_variant_ref_sink (result
);
2403 while (stream
.stream
!= limit
&&
2404 g_ascii_isspace (*stream
.stream
))
2407 if (stream
.stream
!= limit
&& *stream
.stream
!= '\0')
2409 SourceRef ref
= { stream
.stream
- text
,
2410 stream
.stream
- text
};
2412 parser_set_error (error
, &ref
, NULL
,
2413 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END
,
2414 "expected end of input");
2415 g_variant_unref (result
);
2421 *endptr
= stream
.stream
;
2431 * g_variant_new_parsed_va:
2432 * @format: a text format #GVariant
2433 * @app: a pointer to a #va_list
2435 * Parses @format and returns the result.
2437 * This is the version of g_variant_new_parsed() intended to be used
2440 * The return value will be floating if it was a newly created GVariant
2441 * instance. In the case that @format simply specified the collection
2442 * of a #GVariant pointer (eg: @format was "%*") then the collected
2443 * #GVariant pointer will be returned unmodified, without adding any
2444 * additional references.
2446 * Note that the arguments in @app must be of the correct width for their types
2447 * specified in @format when collected into the #va_list. See
2448 * the [GVariant varargs documentation][gvariant-varargs].
2450 * In order to behave correctly in all cases it is necessary for the
2451 * calling function to g_variant_ref_sink() the return result before
2452 * returning control to the user that originally provided the pointer.
2453 * At this point, the caller will have their own full reference to the
2454 * result. This can also be done by adding the result to a container,
2455 * or by passing it to another g_variant_new() call.
2457 * Returns: a new, usually floating, #GVariant
2460 g_variant_new_parsed_va (const gchar
*format
,
2463 TokenStream stream
= { 0, };
2464 GVariant
*result
= NULL
;
2465 GError
*error
= NULL
;
2468 g_return_val_if_fail (format
!= NULL
, NULL
);
2469 g_return_val_if_fail (app
!= NULL
, NULL
);
2471 stream
.start
= format
;
2472 stream
.stream
= format
;
2475 if ((ast
= parse (&stream
, app
, &error
)))
2477 result
= ast_resolve (ast
, &error
);
2482 g_error ("g_variant_new_parsed: %s", error
->message
);
2485 g_error ("g_variant_new_parsed: trailing text after value");
2491 * g_variant_new_parsed:
2492 * @format: a text format #GVariant
2493 * @...: arguments as per @format
2495 * Parses @format and returns the result.
2497 * @format must be a text format #GVariant with one extension: at any
2498 * point that a value may appear in the text, a '%' character followed
2499 * by a GVariant format string (as per g_variant_new()) may appear. In
2500 * that case, the same arguments are collected from the argument list as
2501 * g_variant_new() would have collected.
2503 * Note that the arguments must be of the correct width for their types
2504 * specified in @format. This can be achieved by casting them. See
2505 * the [GVariant varargs documentation][gvariant-varargs].
2507 * Consider this simple example:
2508 * |[<!-- language="C" -->
2509 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2512 * In the example, the variable argument parameters are collected and
2513 * filled in as if they were part of the original string to produce the
2515 * |[<!-- language="C" -->
2516 * [('one', 1), ('two', 2), ('three', 3)]
2519 * This function is intended only to be used with @format as a string
2520 * literal. Any parse error is fatal to the calling process. If you
2521 * want to parse data from untrusted sources, use g_variant_parse().
2523 * You may not use this function to return, unmodified, a single
2524 * #GVariant pointer from the argument list. ie: @format may not solely
2525 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2528 * Returns: a new floating #GVariant instance
2531 g_variant_new_parsed (const gchar
*format
,
2537 va_start (ap
, format
);
2538 result
= g_variant_new_parsed_va (format
, &ap
);
2545 * g_variant_builder_add_parsed:
2546 * @builder: a #GVariantBuilder
2547 * @format: a text format #GVariant
2548 * @...: arguments as per @format
2550 * Adds to a #GVariantBuilder.
2552 * This call is a convenience wrapper that is exactly equivalent to
2553 * calling g_variant_new_parsed() followed by
2554 * g_variant_builder_add_value().
2556 * Note that the arguments must be of the correct width for their types
2557 * specified in @format_string. This can be achieved by casting them. See
2558 * the [GVariant varargs documentation][gvariant-varargs].
2560 * This function might be used as follows:
2562 * |[<!-- language="C" -->
2564 * make_pointless_dictionary (void)
2566 * GVariantBuilder builder;
2569 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2570 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2571 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2572 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2573 * return g_variant_builder_end (&builder);
2580 g_variant_builder_add_parsed (GVariantBuilder
*builder
,
2581 const gchar
*format
,
2586 va_start (ap
, format
);
2587 g_variant_builder_add_value (builder
, g_variant_new_parsed_va (format
, &ap
));
2592 parse_num (const gchar
*num
,
2599 bignum
= g_ascii_strtoll (num
, &endptr
, 10);
2601 if (endptr
!= limit
)
2604 if (bignum
< 0 || bignum
> G_MAXINT
)
2613 add_last_line (GString
*err
,
2616 const gchar
*last_nl
;
2620 /* This is an error at the end of input. If we have a file
2621 * with newlines, that's probably the empty string after the
2622 * last newline, which is not the most useful thing to show.
2624 * Instead, show the last line of non-whitespace that we have
2625 * and put the pointer at the end of it.
2627 chomped
= g_strchomp (g_strdup (str
));
2628 last_nl
= strrchr (chomped
, '\n');
2629 if (last_nl
== NULL
)
2634 /* Print the last line like so:
2639 g_string_append (err
, " ");
2641 g_string_append (err
, last_nl
);
2643 g_string_append (err
, "(empty input)");
2644 g_string_append (err
, "\n ");
2645 for (i
= 0; last_nl
[i
]; i
++)
2646 g_string_append_c (err
, ' ');
2647 g_string_append (err
, "^\n");
2652 add_lines_from_range (GString
*err
,
2654 const gchar
*start1
,
2656 const gchar
*start2
,
2659 while (str
< end1
|| str
< end2
)
2663 nl
= str
+ strcspn (str
, "\n");
2665 if ((start1
< nl
&& str
< end1
) || (start2
< nl
&& str
< end2
))
2669 /* We're going to print this line */
2670 g_string_append (err
, " ");
2671 g_string_append_len (err
, str
, nl
- str
);
2672 g_string_append (err
, "\n ");
2674 /* And add underlines... */
2675 for (s
= str
; s
< nl
; s
++)
2677 if ((start1
<= s
&& s
< end1
) || (start2
<= s
&& s
< end2
))
2678 g_string_append_c (err
, '^');
2680 g_string_append_c (err
, ' ');
2682 g_string_append_c (err
, '\n');
2693 * g_variant_parse_error_print_context:
2694 * @error: a #GError from the #GVariantParseError domain
2695 * @source_str: the string that was given to the parser
2697 * Pretty-prints a message showing the context of a #GVariant parse
2698 * error within the string for which parsing was attempted.
2700 * The resulting string is suitable for output to the console or other
2701 * monospace media where newlines are treated in the usual way.
2703 * The message will typically look something like one of the following:
2706 * unterminated string constant:
2714 * unable to find a common type:
2719 * The format of the message may change in a future version.
2721 * @error must have come from a failed attempt to g_variant_parse() and
2722 * @source_str must be exactly the same string that caused the error.
2723 * If @source_str was not nul-terminated when you passed it to
2724 * g_variant_parse() then you must add nul termination before using this
2727 * Returns: (transfer full): the printed message
2732 g_variant_parse_error_print_context (GError
*error
,
2733 const gchar
*source_str
)
2735 const gchar
*colon
, *dash
, *comma
;
2736 gboolean success
= FALSE
;
2739 g_return_val_if_fail (error
->domain
== G_VARIANT_PARSE_ERROR
, FALSE
);
2741 /* We can only have a limited number of possible types of ranges
2742 * emitted from the parser:
2744 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2745 * - a-b: -- usually errors from handling one single token
2746 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2748 * We never see, for example "a,c".
2751 colon
= strchr (error
->message
, ':');
2752 dash
= strchr (error
->message
, '-');
2753 comma
= strchr (error
->message
, ',');
2758 err
= g_string_new (colon
+ 1);
2759 g_string_append (err
, ":\n");
2761 if (dash
== NULL
|| colon
< dash
)
2765 /* we have a single point */
2766 if (!parse_num (error
->message
, colon
, &point
))
2769 if (point
>= strlen (source_str
))
2770 /* the error is at the end of the input */
2771 add_last_line (err
, source_str
);
2773 /* otherwise just treat it as a error at a thin range */
2774 add_lines_from_range (err
, source_str
, source_str
+ point
, source_str
+ point
+ 1, NULL
, NULL
);
2778 /* We have one or two ranges... */
2779 if (comma
&& comma
< colon
)
2781 gint start1
, end1
, start2
, end2
;
2785 dash2
= strchr (comma
, '-');
2787 if (!parse_num (error
->message
, dash
, &start1
) || !parse_num (dash
+ 1, comma
, &end1
) ||
2788 !parse_num (comma
+ 1, dash2
, &start2
) || !parse_num (dash2
+ 1, colon
, &end2
))
2791 add_lines_from_range (err
, source_str
,
2792 source_str
+ start1
, source_str
+ end1
,
2793 source_str
+ start2
, source_str
+ end2
);
2800 if (!parse_num (error
->message
, dash
, &start
) || !parse_num (dash
+ 1, colon
, &end
))
2803 add_lines_from_range (err
, source_str
, source_str
+ start
, source_str
+ end
, NULL
, NULL
);
2810 return g_string_free (err
, !success
);