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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Ryan Lortie <desrt@desrt.ca>
31 #include "gstrfuncs.h"
32 #include "gtestutils.h"
34 #include "gvarianttype.h"
40 * designed by ryan lortie and william hua
41 * designed in itb-229 and at ghazi's, 2009.
45 * G_VARIANT_PARSE_ERROR:
47 * Error domain for GVariant text format parsing. Specific error codes
48 * are not currently defined for this domain. See #GError for
49 * information on error domains.
53 * @G_VARIANT_PARSE_ERROR_FAILED: generic error (unused)
54 * @G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED: a non-basic #GVariantType was given where a basic type was expected
55 * @G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE: cannot infer the #GVariantType
56 * @G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED: an indefinite #GVariantType was given where a definite type was expected
57 * @G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END: extra data after parsing finished
58 * @G_VARIANT_PARSE_ERROR_INVALID_CHARACTER: invalid character in number or unicode escape
59 * @G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING: not a valid #GVariant format string
60 * @G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH: not a valid object path
61 * @G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE: not a valid type signature
62 * @G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING: not a valid #GVariant type string
63 * @G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE: could not find a common type for array entries
64 * @G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE: the numerical value is out of range of the given type
65 * @G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG: the numerical value is out of range for any type
66 * @G_VARIANT_PARSE_ERROR_TYPE_ERROR: cannot parse as variant of the specified type
67 * @G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN: an unexpected token was encountered
68 * @G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD: an unknown keyword was encountered
69 * @G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT: unterminated string constant
70 * @G_VARIANT_PARSE_ERROR_VALUE_EXPECTED: no value given
72 * Error codes returned by parsing text-format GVariants.
74 G_DEFINE_QUARK (g
-variant
-parse
-error
-quark
, g_variant_parser_get_error
)
83 parser_set_error_va (GError
**error
,
90 GString
*msg
= g_string_new (NULL
);
92 if (location
->start
== location
->end
)
93 g_string_append_printf (msg
, "%d", location
->start
);
95 g_string_append_printf (msg
, "%d-%d", location
->start
, location
->end
);
99 g_assert (other
->start
!= other
->end
);
100 g_string_append_printf (msg
, ",%d-%d", other
->start
, other
->end
);
102 g_string_append_c (msg
, ':');
104 g_string_append_vprintf (msg
, format
, ap
);
105 g_set_error_literal (error
, G_VARIANT_PARSE_ERROR
, code
, msg
->str
);
106 g_string_free (msg
, TRUE
);
111 parser_set_error (GError
**error
,
120 va_start (ap
, format
);
121 parser_set_error_va (error
, location
, other
, code
, format
, ap
);
137 token_stream_set_error (TokenStream
*stream
,
147 ref
.start
= stream
->this - stream
->start
;
150 ref
.end
= stream
->stream
- stream
->start
;
154 va_start (ap
, format
);
155 parser_set_error_va (error
, &ref
, NULL
, code
, format
, ap
);
160 token_stream_prepare (TokenStream
*stream
)
165 if (stream
->this != NULL
)
168 while (stream
->stream
!= stream
->end
&& g_ascii_isspace (*stream
->stream
))
171 if (stream
->stream
== stream
->end
|| *stream
->stream
== '\0')
173 stream
->this = stream
->stream
;
177 switch (stream
->stream
[0])
179 case '-': case '+': case '.': case '0': case '1': case '2':
180 case '3': case '4': case '5': case '6': case '7': case '8':
182 for (end
= stream
->stream
; end
!= stream
->end
; end
++)
183 if (!g_ascii_isalnum (*end
) &&
184 *end
!= '-' && *end
!= '+' && *end
!= '.')
189 if (stream
->stream
[1] == '\'' || stream
->stream
[1] == '"')
191 for (end
= stream
->stream
+ 2; end
!= stream
->end
; end
++)
192 if (*end
== stream
->stream
[1] || *end
== '\0' ||
193 (*end
== '\\' && (++end
== stream
->end
|| *end
== '\0')))
196 if (end
!= stream
->end
&& *end
)
203 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
204 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
205 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
206 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
208 for (end
= stream
->stream
; end
!= stream
->end
; end
++)
209 if (!g_ascii_isalnum (*end
))
214 for (end
= stream
->stream
+ 1; end
!= stream
->end
; end
++)
215 if (*end
== stream
->stream
[0] || *end
== '\0' ||
216 (*end
== '\\' && (++end
== stream
->end
|| *end
== '\0')))
219 if (end
!= stream
->end
&& *end
)
224 /* stop at the first space, comma, colon or unmatched bracket.
225 * deals nicely with cases like (%i, %i) or {%i: %i}.
226 * Also: ] and > are never in format strings.
228 for (end
= stream
->stream
+ 1;
229 end
!= stream
->end
&& *end
!= ',' &&
230 *end
!= ':' && *end
!= '>' && *end
!= ']' && !g_ascii_isspace (*end
);
233 if (*end
== '(' || *end
== '{')
236 else if ((*end
== ')' || *end
== '}') && !brackets
--)
242 end
= stream
->stream
+ 1;
246 stream
->this = stream
->stream
;
247 stream
->stream
= end
;
253 token_stream_next (TokenStream
*stream
)
259 token_stream_peek (TokenStream
*stream
,
262 if (!token_stream_prepare (stream
))
265 return stream
->this[0] == first_char
;
269 token_stream_peek2 (TokenStream
*stream
,
273 if (!token_stream_prepare (stream
))
276 return stream
->this[0] == first_char
&&
277 stream
->this[1] == second_char
;
281 token_stream_is_keyword (TokenStream
*stream
)
283 if (!token_stream_prepare (stream
))
286 return g_ascii_isalpha (stream
->this[0]) &&
287 g_ascii_isalpha (stream
->this[1]);
291 token_stream_is_numeric (TokenStream
*stream
)
293 if (!token_stream_prepare (stream
))
296 return (g_ascii_isdigit (stream
->this[0]) ||
297 stream
->this[0] == '-' ||
298 stream
->this[0] == '+' ||
299 stream
->this[0] == '.');
303 token_stream_peek_string (TokenStream
*stream
,
306 gint length
= strlen (token
);
308 return token_stream_prepare (stream
) &&
309 stream
->stream
- stream
->this == length
&&
310 memcmp (stream
->this, token
, length
) == 0;
314 token_stream_consume (TokenStream
*stream
,
317 if (!token_stream_peek_string (stream
, token
))
320 token_stream_next (stream
);
325 token_stream_require (TokenStream
*stream
,
327 const gchar
*purpose
,
331 if (!token_stream_consume (stream
, token
))
333 token_stream_set_error (stream
, error
, FALSE
,
334 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN
,
335 "expected `%s'%s", token
, purpose
);
343 token_stream_assert (TokenStream
*stream
,
346 gboolean correct_token
;
348 correct_token
= token_stream_consume (stream
, token
);
349 g_assert (correct_token
);
353 token_stream_get (TokenStream
*stream
)
357 if (!token_stream_prepare (stream
))
360 result
= g_strndup (stream
->this, stream
->stream
- stream
->this);
366 token_stream_start_ref (TokenStream
*stream
,
369 token_stream_prepare (stream
);
370 ref
->start
= stream
->this - stream
->start
;
374 token_stream_end_ref (TokenStream
*stream
,
377 ref
->end
= stream
->stream
- stream
->start
;
381 pattern_copy (gchar
**out
,
386 while (**in
== 'a' || **in
== 'm' || **in
== 'M')
387 *(*out
)++ = *(*in
)++;
391 if (**in
== '(' || **in
== '{')
394 else if (**in
== ')' || **in
== '}')
397 *(*out
)++ = *(*in
)++;
403 pattern_coalesce (const gchar
*left
,
409 /* the length of the output is loosely bound by the sum of the input
410 * lengths, not simply the greater of the two lengths.
412 * (*(iii)) + ((iii)*) ((iii)(iii))
416 out
= result
= g_malloc (strlen (left
) + strlen (right
));
418 while (*left
&& *right
)
428 const gchar
**one
= &left
, **the_other
= &right
;
431 if (**one
== '*' && **the_other
!= ')')
433 pattern_copy (&out
, the_other
);
437 else if (**one
== 'M' && **the_other
== 'm')
439 *out
++ = *(*the_other
)++;
442 else if (**one
== 'M' && **the_other
!= 'm')
447 else if (**one
== 'N' && strchr ("ynqiuxthd", **the_other
))
449 *out
++ = *(*the_other
)++;
453 else if (**one
== 'S' && strchr ("sog", **the_other
))
455 *out
++ = *(*the_other
)++;
459 else if (one
== &left
)
461 one
= &right
, the_other
= &left
;
481 typedef struct _AST AST
;
482 typedef gchar
* (*get_pattern_func
) (AST
*ast
,
484 typedef GVariant
* (*get_value_func
) (AST
*ast
,
485 const GVariantType
*type
,
487 typedef GVariant
* (*get_base_value_func
) (AST
*ast
,
488 const GVariantType
*type
,
490 typedef void (*free_func
) (AST
*ast
);
494 gchar
* (* get_pattern
) (AST
*ast
,
496 GVariant
* (* get_value
) (AST
*ast
,
497 const GVariantType
*type
,
499 GVariant
* (* get_base_value
) (AST
*ast
,
500 const GVariantType
*type
,
502 void (* free
) (AST
*ast
);
507 const ASTClass
*class;
508 SourceRef source_ref
;
512 ast_get_pattern (AST
*ast
,
515 return ast
->class->get_pattern (ast
, error
);
519 ast_get_value (AST
*ast
,
520 const GVariantType
*type
,
523 return ast
->class->get_value (ast
, type
, error
);
529 ast
->class->free (ast
);
534 ast_set_error (AST
*ast
,
543 va_start (ap
, format
);
544 parser_set_error_va (error
, &ast
->source_ref
,
545 other_ast
? & other_ast
->source_ref
: NULL
,
552 ast_type_error (AST
*ast
,
553 const GVariantType
*type
,
558 typestr
= g_variant_type_dup_string (type
);
559 ast_set_error (ast
, error
, NULL
,
560 G_VARIANT_PARSE_ERROR_TYPE_ERROR
,
561 "can not parse as value of type `%s'",
569 ast_resolve (AST
*ast
,
576 pattern
= ast_get_pattern (ast
, error
);
581 /* choose reasonable defaults
583 * 1) favour non-maybe values where possible
584 * 2) default type for strings is 's'
585 * 3) default type for integers is 'i'
587 for (i
= 0; pattern
[i
]; i
++)
591 ast_set_error (ast
, error
, NULL
,
592 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE
,
593 "unable to infer type");
609 pattern
[j
++] = pattern
[i
];
614 value
= ast_get_value (ast
, G_VARIANT_TYPE (pattern
), error
);
621 static AST
*parse (TokenStream
*stream
,
626 ast_array_append (AST
***array
,
630 if ((*n_items
& (*n_items
- 1)) == 0)
631 *array
= g_renew (AST
*, *array
, *n_items
? 2 ** n_items
: 1);
633 (*array
)[(*n_items
)++] = ast
;
637 ast_array_free (AST
**array
,
642 for (i
= 0; i
< n_items
; i
++)
648 ast_array_get_pattern (AST
**array
,
655 pattern
= ast_get_pattern (array
[0], error
);
660 for (i
= 1; i
< n_items
; i
++)
664 tmp
= ast_get_pattern (array
[i
], error
);
672 merged
= pattern_coalesce (pattern
, tmp
);
677 /* set coalescence implies pairwise coalescence (i think).
678 * we should therefore be able to trace the failure to a single
689 /* if 'j' reaches 'i' then we failed to find the pair */
692 tmp2
= ast_get_pattern (array
[j
], NULL
);
693 g_assert (tmp2
!= NULL
);
695 m
= pattern_coalesce (tmp
, tmp2
);
701 /* we found a conflict between 'i' and 'j'.
703 * report the error. note: 'j' is first.
705 ast_set_error (array
[j
], error
, array
[i
],
706 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE
,
707 "unable to find a common type");
731 maybe_get_pattern (AST
*ast
,
734 Maybe
*maybe
= (Maybe
*) ast
;
736 if (maybe
->child
!= NULL
)
738 gchar
*child_pattern
;
741 child_pattern
= ast_get_pattern (maybe
->child
, error
);
743 if (child_pattern
== NULL
)
746 pattern
= g_strdup_printf ("m%s", child_pattern
);
747 g_free (child_pattern
);
752 return g_strdup ("m*");
756 maybe_get_value (AST
*ast
,
757 const GVariantType
*type
,
760 Maybe
*maybe
= (Maybe
*) ast
;
763 if (!g_variant_type_is_maybe (type
))
764 return ast_type_error (ast
, type
, error
);
766 type
= g_variant_type_element (type
);
770 value
= ast_get_value (maybe
->child
, type
, error
);
778 return g_variant_new_maybe (type
, value
);
782 maybe_free (AST
*ast
)
784 Maybe
*maybe
= (Maybe
*) ast
;
786 if (maybe
->child
!= NULL
)
787 ast_free (maybe
->child
);
789 g_slice_free (Maybe
, maybe
);
793 maybe_parse (TokenStream
*stream
,
797 static const ASTClass maybe_class
= {
799 maybe_get_value
, NULL
,
805 if (token_stream_consume (stream
, "just"))
807 child
= parse (stream
, app
, error
);
812 else if (!token_stream_consume (stream
, "nothing"))
814 token_stream_set_error (stream
, error
, TRUE
,
815 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
820 maybe
= g_slice_new (Maybe
);
821 maybe
->ast
.class = &maybe_class
;
822 maybe
->child
= child
;
824 return (AST
*) maybe
;
828 maybe_wrapper (AST
*ast
,
829 const GVariantType
*type
,
832 const GVariantType
*t
;
836 for (depth
= 0, t
= type
;
837 g_variant_type_is_maybe (t
);
838 depth
++, t
= g_variant_type_element (t
));
840 value
= ast
->class->get_base_value (ast
, t
, error
);
846 value
= g_variant_new_maybe (NULL
, value
);
860 array_get_pattern (AST
*ast
,
863 Array
*array
= (Array
*) ast
;
867 if (array
->n_children
== 0)
868 return g_strdup ("Ma*");
870 pattern
= ast_array_get_pattern (array
->children
, array
->n_children
, error
);
875 result
= g_strdup_printf ("Ma%s", pattern
);
882 array_get_value (AST
*ast
,
883 const GVariantType
*type
,
886 Array
*array
= (Array
*) ast
;
887 const GVariantType
*childtype
;
888 GVariantBuilder builder
;
891 if (!g_variant_type_is_array (type
))
892 return ast_type_error (ast
, type
, error
);
894 g_variant_builder_init (&builder
, type
);
895 childtype
= g_variant_type_element (type
);
897 for (i
= 0; i
< array
->n_children
; i
++)
901 if (!(child
= ast_get_value (array
->children
[i
], childtype
, error
)))
903 g_variant_builder_clear (&builder
);
907 g_variant_builder_add_value (&builder
, child
);
910 return g_variant_builder_end (&builder
);
914 array_free (AST
*ast
)
916 Array
*array
= (Array
*) ast
;
918 ast_array_free (array
->children
, array
->n_children
);
919 g_slice_free (Array
, array
);
923 array_parse (TokenStream
*stream
,
927 static const ASTClass array_class
= {
929 maybe_wrapper
, array_get_value
,
932 gboolean need_comma
= FALSE
;
935 array
= g_slice_new (Array
);
936 array
->ast
.class = &array_class
;
937 array
->children
= NULL
;
938 array
->n_children
= 0;
940 token_stream_assert (stream
, "[");
941 while (!token_stream_consume (stream
, "]"))
946 !token_stream_require (stream
, ",",
947 " or `]' to follow array element",
951 child
= parse (stream
, app
, error
);
956 ast_array_append (&array
->children
, &array
->n_children
, child
);
960 return (AST
*) array
;
963 ast_array_free (array
->children
, array
->n_children
);
964 g_slice_free (Array
, array
);
978 tuple_get_pattern (AST
*ast
,
981 Tuple
*tuple
= (Tuple
*) ast
;
982 gchar
*result
= NULL
;
986 parts
= g_new (gchar
*, tuple
->n_children
+ 4);
987 parts
[tuple
->n_children
+ 1] = (gchar
*) ")";
988 parts
[tuple
->n_children
+ 2] = NULL
;
989 parts
[0] = (gchar
*) "M(";
991 for (i
= 0; i
< tuple
->n_children
; i
++)
992 if (!(parts
[i
+ 1] = ast_get_pattern (tuple
->children
[i
], error
)))
995 if (i
== tuple
->n_children
)
996 result
= g_strjoinv ("", parts
);
998 /* parts[0] should not be freed */
1000 g_free (parts
[i
--]);
1007 tuple_get_value (AST
*ast
,
1008 const GVariantType
*type
,
1011 Tuple
*tuple
= (Tuple
*) ast
;
1012 const GVariantType
*childtype
;
1013 GVariantBuilder builder
;
1016 if (!g_variant_type_is_tuple (type
))
1017 return ast_type_error (ast
, type
, error
);
1019 g_variant_builder_init (&builder
, type
);
1020 childtype
= g_variant_type_first (type
);
1022 for (i
= 0; i
< tuple
->n_children
; i
++)
1026 if (childtype
== NULL
)
1028 g_variant_builder_clear (&builder
);
1029 return ast_type_error (ast
, type
, error
);
1032 if (!(child
= ast_get_value (tuple
->children
[i
], childtype
, error
)))
1034 g_variant_builder_clear (&builder
);
1038 g_variant_builder_add_value (&builder
, child
);
1039 childtype
= g_variant_type_next (childtype
);
1042 if (childtype
!= NULL
)
1044 g_variant_builder_clear (&builder
);
1045 return ast_type_error (ast
, type
, error
);
1048 return g_variant_builder_end (&builder
);
1052 tuple_free (AST
*ast
)
1054 Tuple
*tuple
= (Tuple
*) ast
;
1056 ast_array_free (tuple
->children
, tuple
->n_children
);
1057 g_slice_free (Tuple
, tuple
);
1061 tuple_parse (TokenStream
*stream
,
1065 static const ASTClass tuple_class
= {
1067 maybe_wrapper
, tuple_get_value
,
1070 gboolean need_comma
= FALSE
;
1071 gboolean first
= TRUE
;
1074 tuple
= g_slice_new (Tuple
);
1075 tuple
->ast
.class = &tuple_class
;
1076 tuple
->children
= NULL
;
1077 tuple
->n_children
= 0;
1079 token_stream_assert (stream
, "(");
1080 while (!token_stream_consume (stream
, ")"))
1085 !token_stream_require (stream
, ",",
1086 " or `)' to follow tuple element",
1090 child
= parse (stream
, app
, error
);
1095 ast_array_append (&tuple
->children
, &tuple
->n_children
, child
);
1097 /* the first time, we absolutely require a comma, so grab it here
1098 * and leave need_comma = FALSE so that the code above doesn't
1099 * require a second comma.
1101 * the second and remaining times, we set need_comma = TRUE.
1105 if (!token_stream_require (stream
, ",",
1106 " after first tuple element", error
))
1115 return (AST
*) tuple
;
1118 ast_array_free (tuple
->children
, tuple
->n_children
);
1119 g_slice_free (Tuple
, tuple
);
1132 variant_get_pattern (AST
*ast
,
1135 return g_strdup ("Mv");
1139 variant_get_value (AST
*ast
,
1140 const GVariantType
*type
,
1143 Variant
*variant
= (Variant
*) ast
;
1146 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_VARIANT
))
1147 return ast_type_error (ast
, type
, error
);
1149 child
= ast_resolve (variant
->value
, error
);
1154 return g_variant_new_variant (child
);
1158 variant_free (AST
*ast
)
1160 Variant
*variant
= (Variant
*) ast
;
1162 ast_free (variant
->value
);
1163 g_slice_free (Variant
, variant
);
1167 variant_parse (TokenStream
*stream
,
1171 static const ASTClass variant_class
= {
1172 variant_get_pattern
,
1173 maybe_wrapper
, variant_get_value
,
1179 token_stream_assert (stream
, "<");
1180 value
= parse (stream
, app
, error
);
1185 if (!token_stream_require (stream
, ">", " to follow variant value", error
))
1191 variant
= g_slice_new (Variant
);
1192 variant
->ast
.class = &variant_class
;
1193 variant
->value
= value
;
1195 return (AST
*) variant
;
1208 dictionary_get_pattern (AST
*ast
,
1211 Dictionary
*dict
= (Dictionary
*) ast
;
1212 gchar
*value_pattern
;
1217 if (dict
->n_children
== 0)
1218 return g_strdup ("Ma{**}");
1220 key_pattern
= ast_array_get_pattern (dict
->keys
,
1221 abs (dict
->n_children
),
1224 if (key_pattern
== NULL
)
1227 /* we can not have maybe keys */
1228 if (key_pattern
[0] == 'M')
1229 key_char
= key_pattern
[1];
1231 key_char
= key_pattern
[0];
1233 g_free (key_pattern
);
1236 * plus undetermined number type and undetermined string type.
1238 if (!strchr ("bynqiuxthdsogNS", key_char
))
1240 ast_set_error (ast
, error
, NULL
,
1241 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED
,
1242 "dictionary keys must have basic types");
1246 value_pattern
= ast_get_pattern (dict
->values
[0], error
);
1248 if (value_pattern
== NULL
)
1251 result
= g_strdup_printf ("M%s{%c%s}",
1252 dict
->n_children
> 0 ? "a" : "",
1253 key_char
, value_pattern
);
1254 g_free (value_pattern
);
1260 dictionary_get_value (AST
*ast
,
1261 const GVariantType
*type
,
1264 Dictionary
*dict
= (Dictionary
*) ast
;
1266 if (dict
->n_children
== -1)
1268 const GVariantType
*subtype
;
1269 GVariantBuilder builder
;
1272 if (!g_variant_type_is_dict_entry (type
))
1273 return ast_type_error (ast
, type
, error
);
1275 g_variant_builder_init (&builder
, type
);
1277 subtype
= g_variant_type_key (type
);
1278 if (!(subvalue
= ast_get_value (dict
->keys
[0], subtype
, error
)))
1280 g_variant_builder_clear (&builder
);
1283 g_variant_builder_add_value (&builder
, subvalue
);
1285 subtype
= g_variant_type_value (type
);
1286 if (!(subvalue
= ast_get_value (dict
->values
[0], subtype
, error
)))
1288 g_variant_builder_clear (&builder
);
1291 g_variant_builder_add_value (&builder
, subvalue
);
1293 return g_variant_builder_end (&builder
);
1297 const GVariantType
*entry
, *key
, *val
;
1298 GVariantBuilder builder
;
1301 if (!g_variant_type_is_subtype_of (type
, G_VARIANT_TYPE_DICTIONARY
))
1302 return ast_type_error (ast
, type
, error
);
1304 entry
= g_variant_type_element (type
);
1305 key
= g_variant_type_key (entry
);
1306 val
= g_variant_type_value (entry
);
1308 g_variant_builder_init (&builder
, type
);
1310 for (i
= 0; i
< dict
->n_children
; i
++)
1314 g_variant_builder_open (&builder
, entry
);
1316 if (!(subvalue
= ast_get_value (dict
->keys
[i
], key
, error
)))
1318 g_variant_builder_clear (&builder
);
1321 g_variant_builder_add_value (&builder
, subvalue
);
1323 if (!(subvalue
= ast_get_value (dict
->values
[i
], val
, error
)))
1325 g_variant_builder_clear (&builder
);
1328 g_variant_builder_add_value (&builder
, subvalue
);
1329 g_variant_builder_close (&builder
);
1332 return g_variant_builder_end (&builder
);
1337 dictionary_free (AST
*ast
)
1339 Dictionary
*dict
= (Dictionary
*) ast
;
1342 if (dict
->n_children
> -1)
1343 n_children
= dict
->n_children
;
1347 ast_array_free (dict
->keys
, n_children
);
1348 ast_array_free (dict
->values
, n_children
);
1349 g_slice_free (Dictionary
, dict
);
1353 dictionary_parse (TokenStream
*stream
,
1357 static const ASTClass dictionary_class
= {
1358 dictionary_get_pattern
,
1359 maybe_wrapper
, dictionary_get_value
,
1362 gint n_keys
, n_values
;
1367 dict
= g_slice_new (Dictionary
);
1368 dict
->ast
.class = &dictionary_class
;
1370 dict
->values
= NULL
;
1371 n_keys
= n_values
= 0;
1373 token_stream_assert (stream
, "{");
1375 if (token_stream_consume (stream
, "}"))
1377 dict
->n_children
= 0;
1378 return (AST
*) dict
;
1381 if ((first
= parse (stream
, app
, error
)) == NULL
)
1384 ast_array_append (&dict
->keys
, &n_keys
, first
);
1386 only_one
= token_stream_consume (stream
, ",");
1388 !token_stream_require (stream
, ":",
1389 " or `,' to follow dictionary entry key",
1393 if ((first
= parse (stream
, app
, error
)) == NULL
)
1396 ast_array_append (&dict
->values
, &n_values
, first
);
1400 if (!token_stream_require (stream
, "}", " at end of dictionary entry",
1404 g_assert (n_keys
== 1 && n_values
== 1);
1405 dict
->n_children
= -1;
1407 return (AST
*) dict
;
1410 while (!token_stream_consume (stream
, "}"))
1414 if (!token_stream_require (stream
, ",",
1415 " or `}' to follow dictionary entry", error
))
1418 child
= parse (stream
, app
, error
);
1423 ast_array_append (&dict
->keys
, &n_keys
, child
);
1425 if (!token_stream_require (stream
, ":",
1426 " to follow dictionary entry key", error
))
1429 child
= parse (stream
, app
, error
);
1434 ast_array_append (&dict
->values
, &n_values
, child
);
1437 g_assert (n_keys
== n_values
);
1438 dict
->n_children
= n_keys
;
1440 return (AST
*) dict
;
1443 ast_array_free (dict
->keys
, n_keys
);
1444 ast_array_free (dict
->values
, n_values
);
1445 g_slice_free (Dictionary
, dict
);
1457 string_get_pattern (AST
*ast
,
1460 return g_strdup ("MS");
1464 string_get_value (AST
*ast
,
1465 const GVariantType
*type
,
1468 String
*string
= (String
*) ast
;
1470 if (g_variant_type_equal (type
, G_VARIANT_TYPE_STRING
))
1471 return g_variant_new_string (string
->string
);
1473 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_OBJECT_PATH
))
1475 if (!g_variant_is_object_path (string
->string
))
1477 ast_set_error (ast
, error
, NULL
,
1478 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH
,
1479 "not a valid object path");
1483 return g_variant_new_object_path (string
->string
);
1486 else if (g_variant_type_equal (type
, G_VARIANT_TYPE_SIGNATURE
))
1488 if (!g_variant_is_signature (string
->string
))
1490 ast_set_error (ast
, error
, NULL
,
1491 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE
,
1492 "not a valid signature");
1496 return g_variant_new_signature (string
->string
);
1500 return ast_type_error (ast
, type
, error
);
1504 string_free (AST
*ast
)
1506 String
*string
= (String
*) ast
;
1508 g_free (string
->string
);
1509 g_slice_free (String
, string
);
1513 unicode_unescape (const gchar
*src
,
1527 g_assert (length
< sizeof (buffer
));
1528 strncpy (buffer
, src
+ *src_ofs
, length
);
1529 buffer
[length
] = '\0';
1531 value
= g_ascii_strtoull (buffer
, &end
, 0x10);
1533 if (value
== 0 || end
!= buffer
+ length
)
1535 parser_set_error (error
, ref
, NULL
,
1536 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1537 "invalid %d-character unicode escape", length
);
1541 g_assert (value
<= G_MAXUINT32
);
1543 *dest_ofs
+= g_unichar_to_utf8 (value
, dest
+ *dest_ofs
);
1550 string_parse (TokenStream
*stream
,
1554 static const ASTClass string_class
= {
1556 maybe_wrapper
, string_get_value
,
1567 token_stream_start_ref (stream
, &ref
);
1568 token
= token_stream_get (stream
);
1569 token_stream_end_ref (stream
, &ref
);
1570 length
= strlen (token
);
1573 str
= g_malloc (length
);
1574 g_assert (quote
== '"' || quote
== '\'');
1577 while (token
[i
] != quote
)
1581 parser_set_error (error
, &ref
, NULL
,
1582 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1583 "unterminated string constant");
1592 parser_set_error (error
, &ref
, NULL
,
1593 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1594 "unterminated string constant");
1600 if (!unicode_unescape (token
, &i
, str
, &j
, 4, &ref
, error
))
1609 if (!unicode_unescape (token
, &i
, str
, &j
, 8, &ref
, error
))
1617 case 'a': str
[j
++] = '\a'; i
++; continue;
1618 case 'b': str
[j
++] = '\b'; i
++; continue;
1619 case 'f': str
[j
++] = '\f'; i
++; continue;
1620 case 'n': str
[j
++] = '\n'; i
++; continue;
1621 case 'r': str
[j
++] = '\r'; i
++; continue;
1622 case 't': str
[j
++] = '\t'; i
++; continue;
1623 case 'v': str
[j
++] = '\v'; i
++; continue;
1624 case '\n': i
++; continue;
1628 str
[j
++] = token
[i
++];
1633 string
= g_slice_new (String
);
1634 string
->ast
.class = &string_class
;
1635 string
->string
= str
;
1637 token_stream_next (stream
);
1639 return (AST
*) string
;
1649 bytestring_get_pattern (AST
*ast
,
1652 return g_strdup ("May");
1656 bytestring_get_value (AST
*ast
,
1657 const GVariantType
*type
,
1660 ByteString
*string
= (ByteString
*) ast
;
1662 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BYTESTRING
))
1663 return ast_type_error (ast
, type
, error
);
1665 return g_variant_new_bytestring (string
->string
);
1669 bytestring_free (AST
*ast
)
1671 ByteString
*string
= (ByteString
*) ast
;
1673 g_free (string
->string
);
1674 g_slice_free (ByteString
, string
);
1678 bytestring_parse (TokenStream
*stream
,
1682 static const ASTClass bytestring_class
= {
1683 bytestring_get_pattern
,
1684 maybe_wrapper
, bytestring_get_value
,
1695 token_stream_start_ref (stream
, &ref
);
1696 token
= token_stream_get (stream
);
1697 token_stream_end_ref (stream
, &ref
);
1698 g_assert (token
[0] == 'b');
1699 length
= strlen (token
);
1702 str
= g_malloc (length
);
1703 g_assert (quote
== '"' || quote
== '\'');
1706 while (token
[i
] != quote
)
1710 parser_set_error (error
, &ref
, NULL
,
1711 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1712 "unterminated string constant");
1720 parser_set_error (error
, &ref
, NULL
,
1721 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT
,
1722 "unterminated string constant");
1726 case '0': case '1': case '2': case '3':
1727 case '4': case '5': case '6': case '7':
1729 /* up to 3 characters */
1730 guchar val
= token
[i
++] - '0';
1732 if ('0' <= token
[i
] && token
[i
] < '8')
1733 val
= (val
<< 3) | (token
[i
++] - '0');
1735 if ('0' <= token
[i
] && token
[i
] < '8')
1736 val
= (val
<< 3) | (token
[i
++] - '0');
1742 case 'a': str
[j
++] = '\a'; i
++; continue;
1743 case 'b': str
[j
++] = '\b'; i
++; continue;
1744 case 'f': str
[j
++] = '\f'; i
++; continue;
1745 case 'n': str
[j
++] = '\n'; i
++; continue;
1746 case 'r': str
[j
++] = '\r'; i
++; continue;
1747 case 't': str
[j
++] = '\t'; i
++; continue;
1748 case 'v': str
[j
++] = '\v'; i
++; continue;
1749 case '\n': i
++; continue;
1753 str
[j
++] = token
[i
++];
1758 string
= g_slice_new (ByteString
);
1759 string
->ast
.class = &bytestring_class
;
1760 string
->string
= str
;
1762 token_stream_next (stream
);
1764 return (AST
*) string
;
1775 number_get_pattern (AST
*ast
,
1778 Number
*number
= (Number
*) ast
;
1780 if (strchr (number
->token
, '.') ||
1781 (!g_str_has_prefix (number
->token
, "0x") && strchr (number
->token
, 'e')) ||
1782 strstr (number
->token
, "inf") ||
1783 strstr (number
->token
, "nan"))
1784 return g_strdup ("Md");
1786 return g_strdup ("MN");
1790 number_overflow (AST
*ast
,
1791 const GVariantType
*type
,
1794 ast_set_error (ast
, error
, NULL
,
1795 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE
,
1796 "number out of range for type `%c'",
1797 g_variant_type_peek_string (type
)[0]);
1802 number_get_value (AST
*ast
,
1803 const GVariantType
*type
,
1806 Number
*number
= (Number
*) ast
;
1814 token
= number
->token
;
1816 if (g_variant_type_equal (type
, G_VARIANT_TYPE_DOUBLE
))
1821 dbl_val
= g_ascii_strtod (token
, &end
);
1822 if (dbl_val
!= 0.0 && errno
== ERANGE
)
1824 ast_set_error (ast
, error
, NULL
,
1825 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1826 "number too big for any type");
1830 /* silence uninitialised warnings... */
1837 negative
= token
[0] == '-';
1838 if (token
[0] == '-')
1842 abs_val
= g_ascii_strtoull (token
, &end
, 0);
1843 if (abs_val
== G_MAXUINT64
&& errno
== ERANGE
)
1845 ast_set_error (ast
, error
, NULL
,
1846 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG
,
1847 "integer too big for any type");
1854 /* silence uninitialised warning... */
1862 ref
= ast
->source_ref
;
1863 ref
.start
+= end
- number
->token
;
1864 ref
.end
= ref
.start
+ 1;
1866 parser_set_error (error
, &ref
, NULL
,
1867 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER
,
1868 "invalid character in number");
1873 return g_variant_new_double (dbl_val
);
1875 switch (*g_variant_type_peek_string (type
))
1878 if (negative
|| abs_val
> G_MAXUINT8
)
1879 return number_overflow (ast
, type
, error
);
1880 return g_variant_new_byte (abs_val
);
1883 if (abs_val
- negative
> G_MAXINT16
)
1884 return number_overflow (ast
, type
, error
);
1885 return g_variant_new_int16 (negative
? -abs_val
: abs_val
);
1888 if (negative
|| abs_val
> G_MAXUINT16
)
1889 return number_overflow (ast
, type
, error
);
1890 return g_variant_new_uint16 (abs_val
);
1893 if (abs_val
- negative
> G_MAXINT32
)
1894 return number_overflow (ast
, type
, error
);
1895 return g_variant_new_int32 (negative
? -abs_val
: abs_val
);
1898 if (negative
|| abs_val
> G_MAXUINT32
)
1899 return number_overflow (ast
, type
, error
);
1900 return g_variant_new_uint32 (abs_val
);
1903 if (abs_val
- negative
> G_MAXINT64
)
1904 return number_overflow (ast
, type
, error
);
1905 return g_variant_new_int64 (negative
? -abs_val
: abs_val
);
1909 return number_overflow (ast
, type
, error
);
1910 return g_variant_new_uint64 (abs_val
);
1913 if (abs_val
- negative
> G_MAXINT32
)
1914 return number_overflow (ast
, type
, error
);
1915 return g_variant_new_handle (negative
? -abs_val
: abs_val
);
1918 return ast_type_error (ast
, type
, error
);
1923 number_free (AST
*ast
)
1925 Number
*number
= (Number
*) ast
;
1927 g_free (number
->token
);
1928 g_slice_free (Number
, number
);
1932 number_parse (TokenStream
*stream
,
1936 static const ASTClass number_class
= {
1938 maybe_wrapper
, number_get_value
,
1943 number
= g_slice_new (Number
);
1944 number
->ast
.class = &number_class
;
1945 number
->token
= token_stream_get (stream
);
1946 token_stream_next (stream
);
1948 return (AST
*) number
;
1958 boolean_get_pattern (AST
*ast
,
1961 return g_strdup ("Mb");
1965 boolean_get_value (AST
*ast
,
1966 const GVariantType
*type
,
1969 Boolean
*boolean
= (Boolean
*) ast
;
1971 if (!g_variant_type_equal (type
, G_VARIANT_TYPE_BOOLEAN
))
1972 return ast_type_error (ast
, type
, error
);
1974 return g_variant_new_boolean (boolean
->value
);
1978 boolean_free (AST
*ast
)
1980 Boolean
*boolean
= (Boolean
*) ast
;
1982 g_slice_free (Boolean
, boolean
);
1986 boolean_new (gboolean value
)
1988 static const ASTClass boolean_class
= {
1989 boolean_get_pattern
,
1990 maybe_wrapper
, boolean_get_value
,
1995 boolean
= g_slice_new (Boolean
);
1996 boolean
->ast
.class = &boolean_class
;
1997 boolean
->value
= value
;
1999 return (AST
*) boolean
;
2010 positional_get_pattern (AST
*ast
,
2013 Positional
*positional
= (Positional
*) ast
;
2015 return g_strdup (g_variant_get_type_string (positional
->value
));
2019 positional_get_value (AST
*ast
,
2020 const GVariantType
*type
,
2023 Positional
*positional
= (Positional
*) ast
;
2026 g_assert (positional
->value
!= NULL
);
2028 if G_UNLIKELY (!g_variant_is_of_type (positional
->value
, type
))
2029 return ast_type_error (ast
, type
, error
);
2031 /* NOTE: if _get is called more than once then
2032 * things get messed up with respect to floating refs.
2034 * fortunately, this function should only ever get called once.
2036 g_assert (positional
->value
!= NULL
);
2037 value
= positional
->value
;
2038 positional
->value
= NULL
;
2044 positional_free (AST
*ast
)
2046 Positional
*positional
= (Positional
*) ast
;
2048 /* if positional->value is set, just leave it.
2049 * memory management doesn't matter in case of programmer error.
2051 g_slice_free (Positional
, positional
);
2055 positional_parse (TokenStream
*stream
,
2059 static const ASTClass positional_class
= {
2060 positional_get_pattern
,
2061 positional_get_value
, NULL
,
2064 Positional
*positional
;
2065 const gchar
*endptr
;
2068 token
= token_stream_get (stream
);
2069 g_assert (token
[0] == '%');
2071 positional
= g_slice_new (Positional
);
2072 positional
->ast
.class = &positional_class
;
2073 positional
->value
= g_variant_new_va (token
+ 1, &endptr
, app
);
2075 if (*endptr
|| positional
->value
== NULL
)
2077 token_stream_set_error (stream
, error
, TRUE
,
2078 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING
,
2079 "invalid GVariant format string");
2080 /* memory management doesn't matter in case of programmer error. */
2084 token_stream_next (stream
);
2087 return (AST
*) positional
;
2099 typedecl_get_pattern (AST
*ast
,
2102 TypeDecl
*decl
= (TypeDecl
*) ast
;
2104 return g_variant_type_dup_string (decl
->type
);
2108 typedecl_get_value (AST
*ast
,
2109 const GVariantType
*type
,
2112 TypeDecl
*decl
= (TypeDecl
*) ast
;
2114 return ast_get_value (decl
->child
, type
, error
);
2118 typedecl_free (AST
*ast
)
2120 TypeDecl
*decl
= (TypeDecl
*) ast
;
2122 ast_free (decl
->child
);
2123 g_variant_type_free (decl
->type
);
2124 g_slice_free (TypeDecl
, decl
);
2128 typedecl_parse (TokenStream
*stream
,
2132 static const ASTClass typedecl_class
= {
2133 typedecl_get_pattern
,
2134 typedecl_get_value
, NULL
,
2141 if (token_stream_peek (stream
, '@'))
2145 token
= token_stream_get (stream
);
2147 if (!g_variant_type_string_is_valid (token
+ 1))
2149 token_stream_set_error (stream
, error
, TRUE
,
2150 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING
,
2151 "invalid type declaration");
2157 type
= g_variant_type_new (token
+ 1);
2159 if (!g_variant_type_is_definite (type
))
2161 token_stream_set_error (stream
, error
, TRUE
,
2162 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED
,
2163 "type declarations must be definite");
2164 g_variant_type_free (type
);
2170 token_stream_next (stream
);
2175 if (token_stream_consume (stream
, "boolean"))
2176 type
= g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN
);
2178 else if (token_stream_consume (stream
, "byte"))
2179 type
= g_variant_type_copy (G_VARIANT_TYPE_BYTE
);
2181 else if (token_stream_consume (stream
, "int16"))
2182 type
= g_variant_type_copy (G_VARIANT_TYPE_INT16
);
2184 else if (token_stream_consume (stream
, "uint16"))
2185 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT16
);
2187 else if (token_stream_consume (stream
, "int32"))
2188 type
= g_variant_type_copy (G_VARIANT_TYPE_INT32
);
2190 else if (token_stream_consume (stream
, "handle"))
2191 type
= g_variant_type_copy (G_VARIANT_TYPE_HANDLE
);
2193 else if (token_stream_consume (stream
, "uint32"))
2194 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT32
);
2196 else if (token_stream_consume (stream
, "int64"))
2197 type
= g_variant_type_copy (G_VARIANT_TYPE_INT64
);
2199 else if (token_stream_consume (stream
, "uint64"))
2200 type
= g_variant_type_copy (G_VARIANT_TYPE_UINT64
);
2202 else if (token_stream_consume (stream
, "double"))
2203 type
= g_variant_type_copy (G_VARIANT_TYPE_DOUBLE
);
2205 else if (token_stream_consume (stream
, "string"))
2206 type
= g_variant_type_copy (G_VARIANT_TYPE_STRING
);
2208 else if (token_stream_consume (stream
, "objectpath"))
2209 type
= g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH
);
2211 else if (token_stream_consume (stream
, "signature"))
2212 type
= g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE
);
2216 token_stream_set_error (stream
, error
, TRUE
,
2217 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD
,
2223 if ((child
= parse (stream
, app
, error
)) == NULL
)
2225 g_variant_type_free (type
);
2229 decl
= g_slice_new (TypeDecl
);
2230 decl
->ast
.class = &typedecl_class
;
2232 decl
->child
= child
;
2234 return (AST
*) decl
;
2238 parse (TokenStream
*stream
,
2242 SourceRef source_ref
;
2245 token_stream_prepare (stream
);
2246 token_stream_start_ref (stream
, &source_ref
);
2248 if (token_stream_peek (stream
, '['))
2249 result
= array_parse (stream
, app
, error
);
2251 else if (token_stream_peek (stream
, '('))
2252 result
= tuple_parse (stream
, app
, error
);
2254 else if (token_stream_peek (stream
, '<'))
2255 result
= variant_parse (stream
, app
, error
);
2257 else if (token_stream_peek (stream
, '{'))
2258 result
= dictionary_parse (stream
, app
, error
);
2260 else if (app
&& token_stream_peek (stream
, '%'))
2261 result
= positional_parse (stream
, app
, error
);
2263 else if (token_stream_consume (stream
, "true"))
2264 result
= boolean_new (TRUE
);
2266 else if (token_stream_consume (stream
, "false"))
2267 result
= boolean_new (FALSE
);
2269 else if (token_stream_is_numeric (stream
) ||
2270 token_stream_peek_string (stream
, "inf") ||
2271 token_stream_peek_string (stream
, "nan"))
2272 result
= number_parse (stream
, app
, error
);
2274 else if (token_stream_peek (stream
, 'n') ||
2275 token_stream_peek (stream
, 'j'))
2276 result
= maybe_parse (stream
, app
, error
);
2278 else if (token_stream_peek (stream
, '@') ||
2279 token_stream_is_keyword (stream
))
2280 result
= typedecl_parse (stream
, app
, error
);
2282 else if (token_stream_peek (stream
, '\'') ||
2283 token_stream_peek (stream
, '"'))
2284 result
= string_parse (stream
, app
, error
);
2286 else if (token_stream_peek2 (stream
, 'b', '\'') ||
2287 token_stream_peek2 (stream
, 'b', '"'))
2288 result
= bytestring_parse (stream
, app
, error
);
2292 token_stream_set_error (stream
, error
, FALSE
,
2293 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED
,
2300 token_stream_end_ref (stream
, &source_ref
);
2301 result
->source_ref
= source_ref
;
2309 * @type: (allow-none): a #GVariantType, or %NULL
2310 * @text: a string containing a GVariant in text form
2311 * @limit: (allow-none): a pointer to the end of @text, or %NULL
2312 * @endptr: (allow-none): a location to store the end pointer, or %NULL
2313 * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
2315 * Parses a #GVariant from a text representation.
2317 * A single #GVariant is parsed from the content of @text.
2319 * The format is described <link linkend='gvariant-text'>here</link>.
2321 * The memory at @limit will never be accessed and the parser behaves as
2322 * if the character at @limit is the nul terminator. This has the
2323 * effect of bounding @text.
2325 * If @endptr is non-%NULL then @text is permitted to contain data
2326 * following the value that this function parses and @endptr will be
2327 * updated to point to the first character past the end of the text
2328 * parsed by this function. If @endptr is %NULL and there is extra data
2329 * then an error is returned.
2331 * If @type is non-%NULL then the value will be parsed to have that
2332 * type. This may result in additional parse errors (in the case that
2333 * the parsed value doesn't fit the type) but may also result in fewer
2334 * errors (in the case that the type would have been ambiguous, such as
2335 * with empty arrays).
2337 * In the event that the parsing is successful, the resulting #GVariant
2340 * In case of any error, %NULL will be returned. If @error is non-%NULL
2341 * then it will be set to reflect the error that occurred.
2343 * Officially, the language understood by the parser is "any string
2344 * produced by g_variant_print()".
2346 * Returns: a reference to a #GVariant, or %NULL
2349 g_variant_parse (const GVariantType
*type
,
2352 const gchar
**endptr
,
2355 TokenStream stream
= { 0, };
2356 GVariant
*result
= NULL
;
2359 g_return_val_if_fail (text
!= NULL
, NULL
);
2360 g_return_val_if_fail (text
== limit
|| text
!= NULL
, NULL
);
2362 stream
.start
= text
;
2363 stream
.stream
= text
;
2366 if ((ast
= parse (&stream
, NULL
, error
)))
2369 result
= ast_resolve (ast
, error
);
2371 result
= ast_get_value (ast
, type
, error
);
2375 g_variant_ref_sink (result
);
2379 while (stream
.stream
!= limit
&&
2380 g_ascii_isspace (*stream
.stream
))
2383 if (stream
.stream
!= limit
&& *stream
.stream
!= '\0')
2385 SourceRef ref
= { stream
.stream
- text
,
2386 stream
.stream
- text
};
2388 parser_set_error (error
, &ref
, NULL
,
2389 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END
,
2390 "expected end of input");
2391 g_variant_unref (result
);
2397 *endptr
= stream
.stream
;
2407 * g_variant_new_parsed_va:
2408 * @format: a text format #GVariant
2409 * @app: a pointer to a #va_list
2411 * Parses @format and returns the result.
2413 * This is the version of g_variant_new_parsed() intended to be used
2416 * The return value will be floating if it was a newly created GVariant
2417 * instance. In the case that @format simply specified the collection
2418 * of a #GVariant pointer (eg: @format was "%*") then the collected
2419 * #GVariant pointer will be returned unmodified, without adding any
2420 * additional references.
2422 * In order to behave correctly in all cases it is necessary for the
2423 * calling function to g_variant_ref_sink() the return result before
2424 * returning control to the user that originally provided the pointer.
2425 * At this point, the caller will have their own full reference to the
2426 * result. This can also be done by adding the result to a container,
2427 * or by passing it to another g_variant_new() call.
2429 * Returns: a new, usually floating, #GVariant
2432 g_variant_new_parsed_va (const gchar
*format
,
2435 TokenStream stream
= { 0, };
2436 GVariant
*result
= NULL
;
2437 GError
*error
= NULL
;
2440 g_return_val_if_fail (format
!= NULL
, NULL
);
2441 g_return_val_if_fail (app
!= NULL
, NULL
);
2443 stream
.start
= format
;
2444 stream
.stream
= format
;
2447 if ((ast
= parse (&stream
, app
, &error
)))
2449 result
= ast_resolve (ast
, &error
);
2454 g_error ("g_variant_new_parsed: %s", error
->message
);
2457 g_error ("g_variant_new_parsed: trailing text after value");
2463 * g_variant_new_parsed:
2464 * @format: a text format #GVariant
2465 * @...: arguments as per @format
2467 * Parses @format and returns the result.
2469 * @format must be a text format #GVariant with one extension: at any
2470 * point that a value may appear in the text, a '%' character followed
2471 * by a GVariant format string (as per g_variant_new()) may appear. In
2472 * that case, the same arguments are collected from the argument list as
2473 * g_variant_new() would have collected.
2475 * Consider this simple example:
2477 * <informalexample><programlisting>
2478 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2479 * </programlisting></informalexample>
2481 * In the example, the variable argument parameters are collected and
2482 * filled in as if they were part of the original string to produce the
2483 * result of <code>[('one', 1), ('two', 2), ('three', 3)]</code>.
2485 * This function is intended only to be used with @format as a string
2486 * literal. Any parse error is fatal to the calling process. If you
2487 * want to parse data from untrusted sources, use g_variant_parse().
2489 * You may not use this function to return, unmodified, a single
2490 * #GVariant pointer from the argument list. ie: @format may not solely
2491 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2494 * Returns: a new floating #GVariant instance
2497 g_variant_new_parsed (const gchar
*format
,
2503 va_start (ap
, format
);
2504 result
= g_variant_new_parsed_va (format
, &ap
);
2511 * g_variant_builder_add_parsed:
2512 * @builder: a #GVariantBuilder
2513 * @format: a text format #GVariant
2514 * @...: arguments as per @format
2516 * Adds to a #GVariantBuilder.
2518 * This call is a convenience wrapper that is exactly equivalent to
2519 * calling g_variant_new_parsed() followed by
2520 * g_variant_builder_add_value().
2522 * This function might be used as follows:
2526 * make_pointless_dictionary (void)
2528 * GVariantBuilder *builder;
2531 * builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
2532 * g_variant_builder_add_parsed (builder, "{'width', <%i>}", 600);
2533 * g_variant_builder_add_parsed (builder, "{'title', <%s>}", "foo");
2534 * g_variant_builder_add_parsed (builder, "{'transparency', <0.5>}");
2535 * return g_variant_builder_end (builder);
2542 g_variant_builder_add_parsed (GVariantBuilder
*builder
,
2543 const gchar
*format
,
2548 va_start (ap
, format
);
2549 g_variant_builder_add_value (builder
, g_variant_new_parsed_va (format
, &ap
));