gtester: fix test result in gtester XML report
[glib.git] / glib / gvariant-parser.c
blob3261bc1af3e0ddfad089c30df33ec255e8bc7dff
1 /*
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>
20 #include "config.h"
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
26 #include "gerror.h"
27 #include "gquark.h"
28 #include "gstring.h"
29 #include "gstrfuncs.h"
30 #include "gtestutils.h"
31 #include "gvariant.h"
32 #include "gvarianttype.h"
33 #include "gslice.h"
34 #include "gthread.h"
37 * two-pass algorithm
38 * designed by ryan lortie and william hua
39 * designed in itb-229 and at ghazi's, 2009.
42 /**
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.
48 **/
49 /**
50 * GVariantParseError:
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.
71 **/
72 G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
74 /**
75 * g_variant_parser_get_error_quark:
77 * Same as g_variant_error_quark().
79 * Deprecated: Use g_variant_parse_error_quark() instead.
81 GQuark
82 g_variant_parser_get_error_quark (void)
84 return g_variant_parse_error_quark ();
87 typedef struct
89 gint start, end;
90 } SourceRef;
92 G_GNUC_PRINTF(5, 0)
93 static void
94 parser_set_error_va (GError **error,
95 SourceRef *location,
96 SourceRef *other,
97 gint code,
98 const gchar *format,
99 va_list ap)
101 GString *msg = g_string_new (NULL);
103 if (location->start == location->end)
104 g_string_append_printf (msg, "%d", location->start);
105 else
106 g_string_append_printf (msg, "%d-%d", location->start, location->end);
108 if (other != NULL)
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);
120 G_GNUC_PRINTF(5, 6)
121 static void
122 parser_set_error (GError **error,
123 SourceRef *location,
124 SourceRef *other,
125 gint code,
126 const gchar *format,
127 ...)
129 va_list ap;
131 va_start (ap, format);
132 parser_set_error_va (error, location, other, code, format, ap);
133 va_end (ap);
136 typedef struct
138 const gchar *start;
139 const gchar *stream;
140 const gchar *end;
142 const gchar *this;
143 } TokenStream;
146 G_GNUC_PRINTF(5, 6)
147 static void
148 token_stream_set_error (TokenStream *stream,
149 GError **error,
150 gboolean this_token,
151 gint code,
152 const gchar *format,
153 ...)
155 SourceRef ref;
156 va_list ap;
158 ref.start = stream->this - stream->start;
160 if (this_token)
161 ref.end = stream->stream - stream->start;
162 else
163 ref.end = ref.start;
165 va_start (ap, format);
166 parser_set_error_va (error, &ref, NULL, code, format, ap);
167 va_end (ap);
170 static gboolean
171 token_stream_prepare (TokenStream *stream)
173 gint brackets = 0;
174 const gchar *end;
176 if (stream->this != NULL)
177 return TRUE;
179 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
180 stream->stream++;
182 if (stream->stream == stream->end || *stream->stream == '\0')
184 stream->this = stream->stream;
185 return FALSE;
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':
192 case '9':
193 for (end = stream->stream; end != stream->end; end++)
194 if (!g_ascii_isalnum (*end) &&
195 *end != '-' && *end != '+' && *end != '.')
196 break;
197 break;
199 case 'b':
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')))
205 break;
207 if (end != stream->end && *end)
208 end++;
209 break;
212 else
214 /* ↓↓↓ */
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':
221 case 'y': case 'z':
222 for (end = stream->stream; end != stream->end; end++)
223 if (!g_ascii_isalnum (*end))
224 break;
225 break;
227 case '\'': case '"':
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')))
231 break;
233 if (end != stream->end && *end)
234 end++;
235 break;
237 case '@': case '%':
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);
245 end++)
247 if (*end == '(' || *end == '{')
248 brackets++;
250 else if ((*end == ')' || *end == '}') && !brackets--)
251 break;
253 break;
255 default:
256 end = stream->stream + 1;
257 break;
260 stream->this = stream->stream;
261 stream->stream = end;
263 return TRUE;
266 static void
267 token_stream_next (TokenStream *stream)
269 stream->this = NULL;
272 static gboolean
273 token_stream_peek (TokenStream *stream,
274 gchar first_char)
276 if (!token_stream_prepare (stream))
277 return FALSE;
279 return stream->this[0] == first_char;
282 static gboolean
283 token_stream_peek2 (TokenStream *stream,
284 gchar first_char,
285 gchar second_char)
287 if (!token_stream_prepare (stream))
288 return FALSE;
290 return stream->this[0] == first_char &&
291 stream->this[1] == second_char;
294 static gboolean
295 token_stream_is_keyword (TokenStream *stream)
297 if (!token_stream_prepare (stream))
298 return FALSE;
300 return g_ascii_isalpha (stream->this[0]) &&
301 g_ascii_isalpha (stream->this[1]);
304 static gboolean
305 token_stream_is_numeric (TokenStream *stream)
307 if (!token_stream_prepare (stream))
308 return FALSE;
310 return (g_ascii_isdigit (stream->this[0]) ||
311 stream->this[0] == '-' ||
312 stream->this[0] == '+' ||
313 stream->this[0] == '.');
316 static gboolean
317 token_stream_peek_string (TokenStream *stream,
318 const gchar *token)
320 gint length = strlen (token);
322 return token_stream_prepare (stream) &&
323 stream->stream - stream->this == length &&
324 memcmp (stream->this, token, length) == 0;
327 static gboolean
328 token_stream_consume (TokenStream *stream,
329 const gchar *token)
331 if (!token_stream_peek_string (stream, token))
332 return FALSE;
334 token_stream_next (stream);
335 return TRUE;
338 static gboolean
339 token_stream_require (TokenStream *stream,
340 const gchar *token,
341 const gchar *purpose,
342 GError **error)
345 if (!token_stream_consume (stream, token))
347 token_stream_set_error (stream, error, FALSE,
348 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
349 "expected '%s'%s", token, purpose);
350 return FALSE;
353 return TRUE;
356 static void
357 token_stream_assert (TokenStream *stream,
358 const gchar *token)
360 gboolean correct_token;
362 correct_token = token_stream_consume (stream, token);
363 g_assert (correct_token);
366 static gchar *
367 token_stream_get (TokenStream *stream)
369 gchar *result;
371 if (!token_stream_prepare (stream))
372 return NULL;
374 result = g_strndup (stream->this, stream->stream - stream->this);
376 return result;
379 static void
380 token_stream_start_ref (TokenStream *stream,
381 SourceRef *ref)
383 token_stream_prepare (stream);
384 ref->start = stream->this - stream->start;
387 static void
388 token_stream_end_ref (TokenStream *stream,
389 SourceRef *ref)
391 ref->end = stream->stream - stream->start;
394 static void
395 pattern_copy (gchar **out,
396 const gchar **in)
398 gint brackets = 0;
400 while (**in == 'a' || **in == 'm' || **in == 'M')
401 *(*out)++ = *(*in)++;
405 if (**in == '(' || **in == '{')
406 brackets++;
408 else if (**in == ')' || **in == '}')
409 brackets--;
411 *(*out)++ = *(*in)++;
413 while (brackets);
416 static gchar *
417 pattern_coalesce (const gchar *left,
418 const gchar *right)
420 gchar *result;
421 gchar *out;
423 /* the length of the output is loosely bound by the sum of the input
424 * lengths, not simply the greater of the two lengths.
426 * (*(iii)) + ((iii)*) ((iii)(iii))
428 * 8 + 8 = 12
430 out = result = g_malloc (strlen (left) + strlen (right));
432 while (*left && *right)
434 if (*left == *right)
436 *out++ = *left++;
437 right++;
440 else
442 const gchar **one = &left, **the_other = &right;
444 again:
445 if (**one == '*' && **the_other != ')')
447 pattern_copy (&out, the_other);
448 (*one)++;
451 else if (**one == 'M' && **the_other == 'm')
453 *out++ = *(*the_other)++;
456 else if (**one == 'M' && **the_other != 'm')
458 (*one)++;
461 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
463 *out++ = *(*the_other)++;
464 (*one)++;
467 else if (**one == 'S' && strchr ("sog", **the_other))
469 *out++ = *(*the_other)++;
470 (*one)++;
473 else if (one == &left)
475 one = &right, the_other = &left;
476 goto again;
479 else
480 break;
484 if (*left || *right)
486 g_free (result);
487 result = NULL;
489 else
490 *out++ = '\0';
492 return result;
495 typedef struct _AST AST;
496 typedef gchar * (*get_pattern_func) (AST *ast,
497 GError **error);
498 typedef GVariant * (*get_value_func) (AST *ast,
499 const GVariantType *type,
500 GError **error);
501 typedef GVariant * (*get_base_value_func) (AST *ast,
502 const GVariantType *type,
503 GError **error);
504 typedef void (*free_func) (AST *ast);
506 typedef struct
508 gchar * (* get_pattern) (AST *ast,
509 GError **error);
510 GVariant * (* get_value) (AST *ast,
511 const GVariantType *type,
512 GError **error);
513 GVariant * (* get_base_value) (AST *ast,
514 const GVariantType *type,
515 GError **error);
516 void (* free) (AST *ast);
517 } ASTClass;
519 struct _AST
521 const ASTClass *class;
522 SourceRef source_ref;
525 static gchar *
526 ast_get_pattern (AST *ast,
527 GError **error)
529 return ast->class->get_pattern (ast, error);
532 static GVariant *
533 ast_get_value (AST *ast,
534 const GVariantType *type,
535 GError **error)
537 return ast->class->get_value (ast, type, error);
540 static void
541 ast_free (AST *ast)
543 ast->class->free (ast);
546 G_GNUC_PRINTF(5, 6)
547 static void
548 ast_set_error (AST *ast,
549 GError **error,
550 AST *other_ast,
551 gint code,
552 const gchar *format,
553 ...)
555 va_list ap;
557 va_start (ap, format);
558 parser_set_error_va (error, &ast->source_ref,
559 other_ast ? & other_ast->source_ref : NULL,
560 code,
561 format, ap);
562 va_end (ap);
565 static GVariant *
566 ast_type_error (AST *ast,
567 const GVariantType *type,
568 GError **error)
570 gchar *typestr;
572 typestr = g_variant_type_dup_string (type);
573 ast_set_error (ast, error, NULL,
574 G_VARIANT_PARSE_ERROR_TYPE_ERROR,
575 "can not parse as value of type '%s'",
576 typestr);
577 g_free (typestr);
579 return NULL;
582 static GVariant *
583 ast_resolve (AST *ast,
584 GError **error)
586 GVariant *value;
587 gchar *pattern;
588 gint i, j = 0;
590 pattern = ast_get_pattern (ast, error);
592 if (pattern == NULL)
593 return NULL;
595 /* choose reasonable defaults
597 * 1) favour non-maybe values where possible
598 * 2) default type for strings is 's'
599 * 3) default type for integers is 'i'
601 for (i = 0; pattern[i]; i++)
602 switch (pattern[i])
604 case '*':
605 ast_set_error (ast, error, NULL,
606 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
607 "unable to infer type");
608 g_free (pattern);
609 return NULL;
611 case 'M':
612 break;
614 case 'S':
615 pattern[j++] = 's';
616 break;
618 case 'N':
619 pattern[j++] = 'i';
620 break;
622 default:
623 pattern[j++] = pattern[i];
624 break;
626 pattern[j++] = '\0';
628 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
629 g_free (pattern);
631 return value;
635 static AST *parse (TokenStream *stream,
636 va_list *app,
637 GError **error);
639 static void
640 ast_array_append (AST ***array,
641 gint *n_items,
642 AST *ast)
644 if ((*n_items & (*n_items - 1)) == 0)
645 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
647 (*array)[(*n_items)++] = ast;
650 static void
651 ast_array_free (AST **array,
652 gint n_items)
654 gint i;
656 for (i = 0; i < n_items; i++)
657 ast_free (array[i]);
658 g_free (array);
661 static gchar *
662 ast_array_get_pattern (AST **array,
663 gint n_items,
664 GError **error)
666 gchar *pattern;
667 gint i;
669 pattern = ast_get_pattern (array[0], error);
671 if (pattern == NULL)
672 return NULL;
674 for (i = 1; i < n_items; i++)
676 gchar *tmp, *merged;
678 tmp = ast_get_pattern (array[i], error);
680 if (tmp == NULL)
682 g_free (pattern);
683 return NULL;
686 merged = pattern_coalesce (pattern, tmp);
687 g_free (pattern);
688 pattern = merged;
690 if (merged == NULL)
691 /* set coalescence implies pairwise coalescence (i think).
692 * we should therefore be able to trace the failure to a single
693 * pair of values.
696 int j = 0;
698 while (TRUE)
700 gchar *tmp2;
701 gchar *m;
703 /* if 'j' reaches 'i' then we failed to find the pair */
704 g_assert (j < i);
706 tmp2 = ast_get_pattern (array[j], NULL);
707 g_assert (tmp2 != NULL);
709 m = pattern_coalesce (tmp, tmp2);
710 g_free (tmp2);
711 g_free (m);
713 if (m == NULL)
715 /* we found a conflict between 'i' and 'j'.
717 * report the error. note: 'j' is first.
719 ast_set_error (array[j], error, array[i],
720 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
721 "unable to find a common type");
722 g_free (tmp);
723 return NULL;
726 j++;
731 g_free (tmp);
734 return pattern;
737 typedef struct
739 AST ast;
741 AST *child;
742 } Maybe;
744 static gchar *
745 maybe_get_pattern (AST *ast,
746 GError **error)
748 Maybe *maybe = (Maybe *) ast;
750 if (maybe->child != NULL)
752 gchar *child_pattern;
753 gchar *pattern;
755 child_pattern = ast_get_pattern (maybe->child, error);
757 if (child_pattern == NULL)
758 return NULL;
760 pattern = g_strdup_printf ("m%s", child_pattern);
761 g_free (child_pattern);
763 return pattern;
766 return g_strdup ("m*");
769 static GVariant *
770 maybe_get_value (AST *ast,
771 const GVariantType *type,
772 GError **error)
774 Maybe *maybe = (Maybe *) ast;
775 GVariant *value;
777 if (!g_variant_type_is_maybe (type))
778 return ast_type_error (ast, type, error);
780 type = g_variant_type_element (type);
782 if (maybe->child)
784 value = ast_get_value (maybe->child, type, error);
786 if (value == NULL)
787 return NULL;
789 else
790 value = NULL;
792 return g_variant_new_maybe (type, value);
795 static void
796 maybe_free (AST *ast)
798 Maybe *maybe = (Maybe *) ast;
800 if (maybe->child != NULL)
801 ast_free (maybe->child);
803 g_slice_free (Maybe, maybe);
806 static AST *
807 maybe_parse (TokenStream *stream,
808 va_list *app,
809 GError **error)
811 static const ASTClass maybe_class = {
812 maybe_get_pattern,
813 maybe_get_value, NULL,
814 maybe_free
816 AST *child = NULL;
817 Maybe *maybe;
819 if (token_stream_consume (stream, "just"))
821 child = parse (stream, app, error);
822 if (child == NULL)
823 return NULL;
826 else if (!token_stream_consume (stream, "nothing"))
828 token_stream_set_error (stream, error, TRUE,
829 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
830 "unknown keyword");
831 return NULL;
834 maybe = g_slice_new (Maybe);
835 maybe->ast.class = &maybe_class;
836 maybe->child = child;
838 return (AST *) maybe;
841 static GVariant *
842 maybe_wrapper (AST *ast,
843 const GVariantType *type,
844 GError **error)
846 const GVariantType *t;
847 GVariant *value;
848 int depth;
850 for (depth = 0, t = type;
851 g_variant_type_is_maybe (t);
852 depth++, t = g_variant_type_element (t));
854 value = ast->class->get_base_value (ast, t, error);
856 if (value == NULL)
857 return NULL;
859 while (depth--)
860 value = g_variant_new_maybe (NULL, value);
862 return value;
865 typedef struct
867 AST ast;
869 AST **children;
870 gint n_children;
871 } Array;
873 static gchar *
874 array_get_pattern (AST *ast,
875 GError **error)
877 Array *array = (Array *) ast;
878 gchar *pattern;
879 gchar *result;
881 if (array->n_children == 0)
882 return g_strdup ("Ma*");
884 pattern = ast_array_get_pattern (array->children, array->n_children, error);
886 if (pattern == NULL)
887 return NULL;
889 result = g_strdup_printf ("Ma%s", pattern);
890 g_free (pattern);
892 return result;
895 static GVariant *
896 array_get_value (AST *ast,
897 const GVariantType *type,
898 GError **error)
900 Array *array = (Array *) ast;
901 const GVariantType *childtype;
902 GVariantBuilder builder;
903 gint i;
905 if (!g_variant_type_is_array (type))
906 return ast_type_error (ast, type, error);
908 g_variant_builder_init (&builder, type);
909 childtype = g_variant_type_element (type);
911 for (i = 0; i < array->n_children; i++)
913 GVariant *child;
915 if (!(child = ast_get_value (array->children[i], childtype, error)))
917 g_variant_builder_clear (&builder);
918 return NULL;
921 g_variant_builder_add_value (&builder, child);
924 return g_variant_builder_end (&builder);
927 static void
928 array_free (AST *ast)
930 Array *array = (Array *) ast;
932 ast_array_free (array->children, array->n_children);
933 g_slice_free (Array, array);
936 static AST *
937 array_parse (TokenStream *stream,
938 va_list *app,
939 GError **error)
941 static const ASTClass array_class = {
942 array_get_pattern,
943 maybe_wrapper, array_get_value,
944 array_free
946 gboolean need_comma = FALSE;
947 Array *array;
949 array = g_slice_new (Array);
950 array->ast.class = &array_class;
951 array->children = NULL;
952 array->n_children = 0;
954 token_stream_assert (stream, "[");
955 while (!token_stream_consume (stream, "]"))
957 AST *child;
959 if (need_comma &&
960 !token_stream_require (stream, ",",
961 " or ']' to follow array element",
962 error))
963 goto error;
965 child = parse (stream, app, error);
967 if (!child)
968 goto error;
970 ast_array_append (&array->children, &array->n_children, child);
971 need_comma = TRUE;
974 return (AST *) array;
976 error:
977 ast_array_free (array->children, array->n_children);
978 g_slice_free (Array, array);
980 return NULL;
983 typedef struct
985 AST ast;
987 AST **children;
988 gint n_children;
989 } Tuple;
991 static gchar *
992 tuple_get_pattern (AST *ast,
993 GError **error)
995 Tuple *tuple = (Tuple *) ast;
996 gchar *result = NULL;
997 gchar **parts;
998 gint i;
1000 parts = g_new (gchar *, tuple->n_children + 4);
1001 parts[tuple->n_children + 1] = (gchar *) ")";
1002 parts[tuple->n_children + 2] = NULL;
1003 parts[0] = (gchar *) "M(";
1005 for (i = 0; i < tuple->n_children; i++)
1006 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
1007 break;
1009 if (i == tuple->n_children)
1010 result = g_strjoinv ("", parts);
1012 /* parts[0] should not be freed */
1013 while (i)
1014 g_free (parts[i--]);
1015 g_free (parts);
1017 return result;
1020 static GVariant *
1021 tuple_get_value (AST *ast,
1022 const GVariantType *type,
1023 GError **error)
1025 Tuple *tuple = (Tuple *) ast;
1026 const GVariantType *childtype;
1027 GVariantBuilder builder;
1028 gint i;
1030 if (!g_variant_type_is_tuple (type))
1031 return ast_type_error (ast, type, error);
1033 g_variant_builder_init (&builder, type);
1034 childtype = g_variant_type_first (type);
1036 for (i = 0; i < tuple->n_children; i++)
1038 GVariant *child;
1040 if (childtype == NULL)
1042 g_variant_builder_clear (&builder);
1043 return ast_type_error (ast, type, error);
1046 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1048 g_variant_builder_clear (&builder);
1049 return FALSE;
1052 g_variant_builder_add_value (&builder, child);
1053 childtype = g_variant_type_next (childtype);
1056 if (childtype != NULL)
1058 g_variant_builder_clear (&builder);
1059 return ast_type_error (ast, type, error);
1062 return g_variant_builder_end (&builder);
1065 static void
1066 tuple_free (AST *ast)
1068 Tuple *tuple = (Tuple *) ast;
1070 ast_array_free (tuple->children, tuple->n_children);
1071 g_slice_free (Tuple, tuple);
1074 static AST *
1075 tuple_parse (TokenStream *stream,
1076 va_list *app,
1077 GError **error)
1079 static const ASTClass tuple_class = {
1080 tuple_get_pattern,
1081 maybe_wrapper, tuple_get_value,
1082 tuple_free
1084 gboolean need_comma = FALSE;
1085 gboolean first = TRUE;
1086 Tuple *tuple;
1088 tuple = g_slice_new (Tuple);
1089 tuple->ast.class = &tuple_class;
1090 tuple->children = NULL;
1091 tuple->n_children = 0;
1093 token_stream_assert (stream, "(");
1094 while (!token_stream_consume (stream, ")"))
1096 AST *child;
1098 if (need_comma &&
1099 !token_stream_require (stream, ",",
1100 " or ')' to follow tuple element",
1101 error))
1102 goto error;
1104 child = parse (stream, app, error);
1106 if (!child)
1107 goto error;
1109 ast_array_append (&tuple->children, &tuple->n_children, child);
1111 /* the first time, we absolutely require a comma, so grab it here
1112 * and leave need_comma = FALSE so that the code above doesn't
1113 * require a second comma.
1115 * the second and remaining times, we set need_comma = TRUE.
1117 if (first)
1119 if (!token_stream_require (stream, ",",
1120 " after first tuple element", error))
1121 goto error;
1123 first = FALSE;
1125 else
1126 need_comma = TRUE;
1129 return (AST *) tuple;
1131 error:
1132 ast_array_free (tuple->children, tuple->n_children);
1133 g_slice_free (Tuple, tuple);
1135 return NULL;
1138 typedef struct
1140 AST ast;
1142 AST *value;
1143 } Variant;
1145 static gchar *
1146 variant_get_pattern (AST *ast,
1147 GError **error)
1149 return g_strdup ("Mv");
1152 static GVariant *
1153 variant_get_value (AST *ast,
1154 const GVariantType *type,
1155 GError **error)
1157 Variant *variant = (Variant *) ast;
1158 GVariant *child;
1160 if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
1161 return ast_type_error (ast, type, error);
1163 child = ast_resolve (variant->value, error);
1165 if (child == NULL)
1166 return NULL;
1168 return g_variant_new_variant (child);
1171 static void
1172 variant_free (AST *ast)
1174 Variant *variant = (Variant *) ast;
1176 ast_free (variant->value);
1177 g_slice_free (Variant, variant);
1180 static AST *
1181 variant_parse (TokenStream *stream,
1182 va_list *app,
1183 GError **error)
1185 static const ASTClass variant_class = {
1186 variant_get_pattern,
1187 maybe_wrapper, variant_get_value,
1188 variant_free
1190 Variant *variant;
1191 AST *value;
1193 token_stream_assert (stream, "<");
1194 value = parse (stream, app, error);
1196 if (!value)
1197 return NULL;
1199 if (!token_stream_require (stream, ">", " to follow variant value", error))
1201 ast_free (value);
1202 return NULL;
1205 variant = g_slice_new (Variant);
1206 variant->ast.class = &variant_class;
1207 variant->value = value;
1209 return (AST *) variant;
1212 typedef struct
1214 AST ast;
1216 AST **keys;
1217 AST **values;
1218 gint n_children;
1219 } Dictionary;
1221 static gchar *
1222 dictionary_get_pattern (AST *ast,
1223 GError **error)
1225 Dictionary *dict = (Dictionary *) ast;
1226 gchar *value_pattern;
1227 gchar *key_pattern;
1228 gchar key_char;
1229 gchar *result;
1231 if (dict->n_children == 0)
1232 return g_strdup ("Ma{**}");
1234 key_pattern = ast_array_get_pattern (dict->keys,
1235 abs (dict->n_children),
1236 error);
1238 if (key_pattern == NULL)
1239 return NULL;
1241 /* we can not have maybe keys */
1242 if (key_pattern[0] == 'M')
1243 key_char = key_pattern[1];
1244 else
1245 key_char = key_pattern[0];
1247 g_free (key_pattern);
1249 /* the basic types,
1250 * plus undetermined number type and undetermined string type.
1252 if (!strchr ("bynqiuxthdsogNS", key_char))
1254 ast_set_error (ast, error, NULL,
1255 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1256 "dictionary keys must have basic types");
1257 return NULL;
1260 value_pattern = ast_get_pattern (dict->values[0], error);
1262 if (value_pattern == NULL)
1263 return NULL;
1265 result = g_strdup_printf ("M%s{%c%s}",
1266 dict->n_children > 0 ? "a" : "",
1267 key_char, value_pattern);
1268 g_free (value_pattern);
1270 return result;
1273 static GVariant *
1274 dictionary_get_value (AST *ast,
1275 const GVariantType *type,
1276 GError **error)
1278 Dictionary *dict = (Dictionary *) ast;
1280 if (dict->n_children == -1)
1282 const GVariantType *subtype;
1283 GVariantBuilder builder;
1284 GVariant *subvalue;
1286 if (!g_variant_type_is_dict_entry (type))
1287 return ast_type_error (ast, type, error);
1289 g_variant_builder_init (&builder, type);
1291 subtype = g_variant_type_key (type);
1292 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1294 g_variant_builder_clear (&builder);
1295 return NULL;
1297 g_variant_builder_add_value (&builder, subvalue);
1299 subtype = g_variant_type_value (type);
1300 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1302 g_variant_builder_clear (&builder);
1303 return NULL;
1305 g_variant_builder_add_value (&builder, subvalue);
1307 return g_variant_builder_end (&builder);
1309 else
1311 const GVariantType *entry, *key, *val;
1312 GVariantBuilder builder;
1313 gint i;
1315 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1316 return ast_type_error (ast, type, error);
1318 entry = g_variant_type_element (type);
1319 key = g_variant_type_key (entry);
1320 val = g_variant_type_value (entry);
1322 g_variant_builder_init (&builder, type);
1324 for (i = 0; i < dict->n_children; i++)
1326 GVariant *subvalue;
1328 g_variant_builder_open (&builder, entry);
1330 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1332 g_variant_builder_clear (&builder);
1333 return NULL;
1335 g_variant_builder_add_value (&builder, subvalue);
1337 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1339 g_variant_builder_clear (&builder);
1340 return NULL;
1342 g_variant_builder_add_value (&builder, subvalue);
1343 g_variant_builder_close (&builder);
1346 return g_variant_builder_end (&builder);
1350 static void
1351 dictionary_free (AST *ast)
1353 Dictionary *dict = (Dictionary *) ast;
1354 gint n_children;
1356 if (dict->n_children > -1)
1357 n_children = dict->n_children;
1358 else
1359 n_children = 1;
1361 ast_array_free (dict->keys, n_children);
1362 ast_array_free (dict->values, n_children);
1363 g_slice_free (Dictionary, dict);
1366 static AST *
1367 dictionary_parse (TokenStream *stream,
1368 va_list *app,
1369 GError **error)
1371 static const ASTClass dictionary_class = {
1372 dictionary_get_pattern,
1373 maybe_wrapper, dictionary_get_value,
1374 dictionary_free
1376 gint n_keys, n_values;
1377 gboolean only_one;
1378 Dictionary *dict;
1379 AST *first;
1381 dict = g_slice_new (Dictionary);
1382 dict->ast.class = &dictionary_class;
1383 dict->keys = NULL;
1384 dict->values = NULL;
1385 n_keys = n_values = 0;
1387 token_stream_assert (stream, "{");
1389 if (token_stream_consume (stream, "}"))
1391 dict->n_children = 0;
1392 return (AST *) dict;
1395 if ((first = parse (stream, app, error)) == NULL)
1396 goto error;
1398 ast_array_append (&dict->keys, &n_keys, first);
1400 only_one = token_stream_consume (stream, ",");
1401 if (!only_one &&
1402 !token_stream_require (stream, ":",
1403 " or ',' to follow dictionary entry key",
1404 error))
1405 goto error;
1407 if ((first = parse (stream, app, error)) == NULL)
1408 goto error;
1410 ast_array_append (&dict->values, &n_values, first);
1412 if (only_one)
1414 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1415 error))
1416 goto error;
1418 g_assert (n_keys == 1 && n_values == 1);
1419 dict->n_children = -1;
1421 return (AST *) dict;
1424 while (!token_stream_consume (stream, "}"))
1426 AST *child;
1428 if (!token_stream_require (stream, ",",
1429 " or '}' to follow dictionary entry", error))
1430 goto error;
1432 child = parse (stream, app, error);
1434 if (!child)
1435 goto error;
1437 ast_array_append (&dict->keys, &n_keys, child);
1439 if (!token_stream_require (stream, ":",
1440 " to follow dictionary entry key", error))
1441 goto error;
1443 child = parse (stream, app, error);
1445 if (!child)
1446 goto error;
1448 ast_array_append (&dict->values, &n_values, child);
1451 g_assert (n_keys == n_values);
1452 dict->n_children = n_keys;
1454 return (AST *) dict;
1456 error:
1457 ast_array_free (dict->keys, n_keys);
1458 ast_array_free (dict->values, n_values);
1459 g_slice_free (Dictionary, dict);
1461 return NULL;
1464 typedef struct
1466 AST ast;
1467 gchar *string;
1468 } String;
1470 static gchar *
1471 string_get_pattern (AST *ast,
1472 GError **error)
1474 return g_strdup ("MS");
1477 static GVariant *
1478 string_get_value (AST *ast,
1479 const GVariantType *type,
1480 GError **error)
1482 String *string = (String *) ast;
1484 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1485 return g_variant_new_string (string->string);
1487 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1489 if (!g_variant_is_object_path (string->string))
1491 ast_set_error (ast, error, NULL,
1492 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1493 "not a valid object path");
1494 return NULL;
1497 return g_variant_new_object_path (string->string);
1500 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1502 if (!g_variant_is_signature (string->string))
1504 ast_set_error (ast, error, NULL,
1505 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1506 "not a valid signature");
1507 return NULL;
1510 return g_variant_new_signature (string->string);
1513 else
1514 return ast_type_error (ast, type, error);
1517 static void
1518 string_free (AST *ast)
1520 String *string = (String *) ast;
1522 g_free (string->string);
1523 g_slice_free (String, string);
1526 static gboolean
1527 unicode_unescape (const gchar *src,
1528 gint *src_ofs,
1529 gchar *dest,
1530 gint *dest_ofs,
1531 gint length,
1532 SourceRef *ref,
1533 GError **error)
1535 gchar buffer[9];
1536 guint64 value;
1537 gchar *end;
1539 (*src_ofs)++;
1541 g_assert (length < sizeof (buffer));
1542 strncpy (buffer, src + *src_ofs, length);
1543 buffer[length] = '\0';
1545 value = g_ascii_strtoull (buffer, &end, 0x10);
1547 if (value == 0 || end != buffer + length)
1549 parser_set_error (error, ref, NULL,
1550 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1551 "invalid %d-character unicode escape", length);
1552 return FALSE;
1555 g_assert (value <= G_MAXUINT32);
1557 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1558 *src_ofs += length;
1560 return TRUE;
1563 static AST *
1564 string_parse (TokenStream *stream,
1565 va_list *app,
1566 GError **error)
1568 static const ASTClass string_class = {
1569 string_get_pattern,
1570 maybe_wrapper, string_get_value,
1571 string_free
1573 String *string;
1574 SourceRef ref;
1575 gchar *token;
1576 gsize length;
1577 gchar quote;
1578 gchar *str;
1579 gint i, j;
1581 token_stream_start_ref (stream, &ref);
1582 token = token_stream_get (stream);
1583 token_stream_end_ref (stream, &ref);
1584 length = strlen (token);
1585 quote = token[0];
1587 str = g_malloc (length);
1588 g_assert (quote == '"' || quote == '\'');
1589 j = 0;
1590 i = 1;
1591 while (token[i] != quote)
1592 switch (token[i])
1594 case '\0':
1595 parser_set_error (error, &ref, NULL,
1596 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1597 "unterminated string constant");
1598 g_free (token);
1599 g_free (str);
1600 return NULL;
1602 case '\\':
1603 switch (token[++i])
1605 case '\0':
1606 parser_set_error (error, &ref, NULL,
1607 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1608 "unterminated string constant");
1609 g_free (token);
1610 g_free (str);
1611 return NULL;
1613 case 'u':
1614 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1616 g_free (token);
1617 g_free (str);
1618 return NULL;
1620 continue;
1622 case 'U':
1623 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1625 g_free (token);
1626 g_free (str);
1627 return NULL;
1629 continue;
1631 case 'a': str[j++] = '\a'; i++; continue;
1632 case 'b': str[j++] = '\b'; i++; continue;
1633 case 'f': str[j++] = '\f'; i++; continue;
1634 case 'n': str[j++] = '\n'; i++; continue;
1635 case 'r': str[j++] = '\r'; i++; continue;
1636 case 't': str[j++] = '\t'; i++; continue;
1637 case 'v': str[j++] = '\v'; i++; continue;
1638 case '\n': i++; continue;
1641 default:
1642 str[j++] = token[i++];
1644 str[j++] = '\0';
1645 g_free (token);
1647 string = g_slice_new (String);
1648 string->ast.class = &string_class;
1649 string->string = str;
1651 token_stream_next (stream);
1653 return (AST *) string;
1656 typedef struct
1658 AST ast;
1659 gchar *string;
1660 } ByteString;
1662 static gchar *
1663 bytestring_get_pattern (AST *ast,
1664 GError **error)
1666 return g_strdup ("May");
1669 static GVariant *
1670 bytestring_get_value (AST *ast,
1671 const GVariantType *type,
1672 GError **error)
1674 ByteString *string = (ByteString *) ast;
1676 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
1677 return ast_type_error (ast, type, error);
1679 return g_variant_new_bytestring (string->string);
1682 static void
1683 bytestring_free (AST *ast)
1685 ByteString *string = (ByteString *) ast;
1687 g_free (string->string);
1688 g_slice_free (ByteString, string);
1691 static AST *
1692 bytestring_parse (TokenStream *stream,
1693 va_list *app,
1694 GError **error)
1696 static const ASTClass bytestring_class = {
1697 bytestring_get_pattern,
1698 maybe_wrapper, bytestring_get_value,
1699 bytestring_free
1701 ByteString *string;
1702 SourceRef ref;
1703 gchar *token;
1704 gsize length;
1705 gchar quote;
1706 gchar *str;
1707 gint i, j;
1709 token_stream_start_ref (stream, &ref);
1710 token = token_stream_get (stream);
1711 token_stream_end_ref (stream, &ref);
1712 g_assert (token[0] == 'b');
1713 length = strlen (token);
1714 quote = token[1];
1716 str = g_malloc (length);
1717 g_assert (quote == '"' || quote == '\'');
1718 j = 0;
1719 i = 2;
1720 while (token[i] != quote)
1721 switch (token[i])
1723 case '\0':
1724 parser_set_error (error, &ref, NULL,
1725 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1726 "unterminated string constant");
1727 g_free (str);
1728 g_free (token);
1729 return NULL;
1731 case '\\':
1732 switch (token[++i])
1734 case '\0':
1735 parser_set_error (error, &ref, NULL,
1736 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1737 "unterminated string constant");
1738 g_free (str);
1739 g_free (token);
1740 return NULL;
1742 case '0': case '1': case '2': case '3':
1743 case '4': case '5': case '6': case '7':
1745 /* up to 3 characters */
1746 guchar val = token[i++] - '0';
1748 if ('0' <= token[i] && token[i] < '8')
1749 val = (val << 3) | (token[i++] - '0');
1751 if ('0' <= token[i] && token[i] < '8')
1752 val = (val << 3) | (token[i++] - '0');
1754 str[j++] = val;
1756 continue;
1758 case 'a': str[j++] = '\a'; i++; continue;
1759 case 'b': str[j++] = '\b'; i++; continue;
1760 case 'f': str[j++] = '\f'; i++; continue;
1761 case 'n': str[j++] = '\n'; i++; continue;
1762 case 'r': str[j++] = '\r'; i++; continue;
1763 case 't': str[j++] = '\t'; i++; continue;
1764 case 'v': str[j++] = '\v'; i++; continue;
1765 case '\n': i++; continue;
1768 default:
1769 str[j++] = token[i++];
1771 str[j++] = '\0';
1772 g_free (token);
1774 string = g_slice_new (ByteString);
1775 string->ast.class = &bytestring_class;
1776 string->string = str;
1778 token_stream_next (stream);
1780 return (AST *) string;
1783 typedef struct
1785 AST ast;
1787 gchar *token;
1788 } Number;
1790 static gchar *
1791 number_get_pattern (AST *ast,
1792 GError **error)
1794 Number *number = (Number *) ast;
1796 if (strchr (number->token, '.') ||
1797 (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
1798 strstr (number->token, "inf") ||
1799 strstr (number->token, "nan"))
1800 return g_strdup ("Md");
1802 return g_strdup ("MN");
1805 static GVariant *
1806 number_overflow (AST *ast,
1807 const GVariantType *type,
1808 GError **error)
1810 ast_set_error (ast, error, NULL,
1811 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1812 "number out of range for type '%c'",
1813 g_variant_type_peek_string (type)[0]);
1814 return NULL;
1817 static GVariant *
1818 number_get_value (AST *ast,
1819 const GVariantType *type,
1820 GError **error)
1822 Number *number = (Number *) ast;
1823 const gchar *token;
1824 gboolean negative;
1825 gboolean floating;
1826 guint64 abs_val;
1827 gdouble dbl_val;
1828 gchar *end;
1830 token = number->token;
1832 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1834 floating = TRUE;
1836 errno = 0;
1837 dbl_val = g_ascii_strtod (token, &end);
1838 if (dbl_val != 0.0 && errno == ERANGE)
1840 ast_set_error (ast, error, NULL,
1841 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1842 "number too big for any type");
1843 return NULL;
1846 /* silence uninitialised warnings... */
1847 negative = FALSE;
1848 abs_val = 0;
1850 else
1852 floating = FALSE;
1853 negative = token[0] == '-';
1854 if (token[0] == '-')
1855 token++;
1857 errno = 0;
1858 abs_val = g_ascii_strtoull (token, &end, 0);
1859 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1861 ast_set_error (ast, error, NULL,
1862 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1863 "integer too big for any type");
1864 return NULL;
1867 if (abs_val == 0)
1868 negative = FALSE;
1870 /* silence uninitialised warning... */
1871 dbl_val = 0.0;
1874 if (*end != '\0')
1876 SourceRef ref;
1878 ref = ast->source_ref;
1879 ref.start += end - number->token;
1880 ref.end = ref.start + 1;
1882 parser_set_error (error, &ref, NULL,
1883 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1884 "invalid character in number");
1885 return NULL;
1888 if (floating)
1889 return g_variant_new_double (dbl_val);
1891 switch (*g_variant_type_peek_string (type))
1893 case 'y':
1894 if (negative || abs_val > G_MAXUINT8)
1895 return number_overflow (ast, type, error);
1896 return g_variant_new_byte (abs_val);
1898 case 'n':
1899 if (abs_val - negative > G_MAXINT16)
1900 return number_overflow (ast, type, error);
1901 return g_variant_new_int16 (negative ? -abs_val : abs_val);
1903 case 'q':
1904 if (negative || abs_val > G_MAXUINT16)
1905 return number_overflow (ast, type, error);
1906 return g_variant_new_uint16 (abs_val);
1908 case 'i':
1909 if (abs_val - negative > G_MAXINT32)
1910 return number_overflow (ast, type, error);
1911 return g_variant_new_int32 (negative ? -abs_val : abs_val);
1913 case 'u':
1914 if (negative || abs_val > G_MAXUINT32)
1915 return number_overflow (ast, type, error);
1916 return g_variant_new_uint32 (abs_val);
1918 case 'x':
1919 if (abs_val - negative > G_MAXINT64)
1920 return number_overflow (ast, type, error);
1921 return g_variant_new_int64 (negative ? -abs_val : abs_val);
1923 case 't':
1924 if (negative)
1925 return number_overflow (ast, type, error);
1926 return g_variant_new_uint64 (abs_val);
1928 case 'h':
1929 if (abs_val - negative > G_MAXINT32)
1930 return number_overflow (ast, type, error);
1931 return g_variant_new_handle (negative ? -abs_val : abs_val);
1933 default:
1934 return ast_type_error (ast, type, error);
1938 static void
1939 number_free (AST *ast)
1941 Number *number = (Number *) ast;
1943 g_free (number->token);
1944 g_slice_free (Number, number);
1947 static AST *
1948 number_parse (TokenStream *stream,
1949 va_list *app,
1950 GError **error)
1952 static const ASTClass number_class = {
1953 number_get_pattern,
1954 maybe_wrapper, number_get_value,
1955 number_free
1957 Number *number;
1959 number = g_slice_new (Number);
1960 number->ast.class = &number_class;
1961 number->token = token_stream_get (stream);
1962 token_stream_next (stream);
1964 return (AST *) number;
1967 typedef struct
1969 AST ast;
1970 gboolean value;
1971 } Boolean;
1973 static gchar *
1974 boolean_get_pattern (AST *ast,
1975 GError **error)
1977 return g_strdup ("Mb");
1980 static GVariant *
1981 boolean_get_value (AST *ast,
1982 const GVariantType *type,
1983 GError **error)
1985 Boolean *boolean = (Boolean *) ast;
1987 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
1988 return ast_type_error (ast, type, error);
1990 return g_variant_new_boolean (boolean->value);
1993 static void
1994 boolean_free (AST *ast)
1996 Boolean *boolean = (Boolean *) ast;
1998 g_slice_free (Boolean, boolean);
2001 static AST *
2002 boolean_new (gboolean value)
2004 static const ASTClass boolean_class = {
2005 boolean_get_pattern,
2006 maybe_wrapper, boolean_get_value,
2007 boolean_free
2009 Boolean *boolean;
2011 boolean = g_slice_new (Boolean);
2012 boolean->ast.class = &boolean_class;
2013 boolean->value = value;
2015 return (AST *) boolean;
2018 typedef struct
2020 AST ast;
2022 GVariant *value;
2023 } Positional;
2025 static gchar *
2026 positional_get_pattern (AST *ast,
2027 GError **error)
2029 Positional *positional = (Positional *) ast;
2031 return g_strdup (g_variant_get_type_string (positional->value));
2034 static GVariant *
2035 positional_get_value (AST *ast,
2036 const GVariantType *type,
2037 GError **error)
2039 Positional *positional = (Positional *) ast;
2040 GVariant *value;
2042 g_assert (positional->value != NULL);
2044 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2045 return ast_type_error (ast, type, error);
2047 /* NOTE: if _get is called more than once then
2048 * things get messed up with respect to floating refs.
2050 * fortunately, this function should only ever get called once.
2052 g_assert (positional->value != NULL);
2053 value = positional->value;
2054 positional->value = NULL;
2056 return value;
2059 static void
2060 positional_free (AST *ast)
2062 Positional *positional = (Positional *) ast;
2064 /* if positional->value is set, just leave it.
2065 * memory management doesn't matter in case of programmer error.
2067 g_slice_free (Positional, positional);
2070 static AST *
2071 positional_parse (TokenStream *stream,
2072 va_list *app,
2073 GError **error)
2075 static const ASTClass positional_class = {
2076 positional_get_pattern,
2077 positional_get_value, NULL,
2078 positional_free
2080 Positional *positional;
2081 const gchar *endptr;
2082 gchar *token;
2084 token = token_stream_get (stream);
2085 g_assert (token[0] == '%');
2087 positional = g_slice_new (Positional);
2088 positional->ast.class = &positional_class;
2089 positional->value = g_variant_new_va (token + 1, &endptr, app);
2091 if (*endptr || positional->value == NULL)
2093 token_stream_set_error (stream, error, TRUE,
2094 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2095 "invalid GVariant format string");
2096 /* memory management doesn't matter in case of programmer error. */
2097 return NULL;
2100 token_stream_next (stream);
2101 g_free (token);
2103 return (AST *) positional;
2106 typedef struct
2108 AST ast;
2110 GVariantType *type;
2111 AST *child;
2112 } TypeDecl;
2114 static gchar *
2115 typedecl_get_pattern (AST *ast,
2116 GError **error)
2118 TypeDecl *decl = (TypeDecl *) ast;
2120 return g_variant_type_dup_string (decl->type);
2123 static GVariant *
2124 typedecl_get_value (AST *ast,
2125 const GVariantType *type,
2126 GError **error)
2128 TypeDecl *decl = (TypeDecl *) ast;
2130 return ast_get_value (decl->child, type, error);
2133 static void
2134 typedecl_free (AST *ast)
2136 TypeDecl *decl = (TypeDecl *) ast;
2138 ast_free (decl->child);
2139 g_variant_type_free (decl->type);
2140 g_slice_free (TypeDecl, decl);
2143 static AST *
2144 typedecl_parse (TokenStream *stream,
2145 va_list *app,
2146 GError **error)
2148 static const ASTClass typedecl_class = {
2149 typedecl_get_pattern,
2150 typedecl_get_value, NULL,
2151 typedecl_free
2153 GVariantType *type;
2154 TypeDecl *decl;
2155 AST *child;
2157 if (token_stream_peek (stream, '@'))
2159 gchar *token;
2161 token = token_stream_get (stream);
2163 if (!g_variant_type_string_is_valid (token + 1))
2165 token_stream_set_error (stream, error, TRUE,
2166 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2167 "invalid type declaration");
2168 g_free (token);
2170 return NULL;
2173 type = g_variant_type_new (token + 1);
2175 if (!g_variant_type_is_definite (type))
2177 token_stream_set_error (stream, error, TRUE,
2178 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2179 "type declarations must be definite");
2180 g_variant_type_free (type);
2181 g_free (token);
2183 return NULL;
2186 token_stream_next (stream);
2187 g_free (token);
2189 else
2191 if (token_stream_consume (stream, "boolean"))
2192 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2194 else if (token_stream_consume (stream, "byte"))
2195 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2197 else if (token_stream_consume (stream, "int16"))
2198 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2200 else if (token_stream_consume (stream, "uint16"))
2201 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2203 else if (token_stream_consume (stream, "int32"))
2204 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2206 else if (token_stream_consume (stream, "handle"))
2207 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2209 else if (token_stream_consume (stream, "uint32"))
2210 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2212 else if (token_stream_consume (stream, "int64"))
2213 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2215 else if (token_stream_consume (stream, "uint64"))
2216 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2218 else if (token_stream_consume (stream, "double"))
2219 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2221 else if (token_stream_consume (stream, "string"))
2222 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2224 else if (token_stream_consume (stream, "objectpath"))
2225 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2227 else if (token_stream_consume (stream, "signature"))
2228 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2230 else
2232 token_stream_set_error (stream, error, TRUE,
2233 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2234 "unknown keyword");
2235 return NULL;
2239 if ((child = parse (stream, app, error)) == NULL)
2241 g_variant_type_free (type);
2242 return NULL;
2245 decl = g_slice_new (TypeDecl);
2246 decl->ast.class = &typedecl_class;
2247 decl->type = type;
2248 decl->child = child;
2250 return (AST *) decl;
2253 static AST *
2254 parse (TokenStream *stream,
2255 va_list *app,
2256 GError **error)
2258 SourceRef source_ref;
2259 AST *result;
2261 token_stream_prepare (stream);
2262 token_stream_start_ref (stream, &source_ref);
2264 if (token_stream_peek (stream, '['))
2265 result = array_parse (stream, app, error);
2267 else if (token_stream_peek (stream, '('))
2268 result = tuple_parse (stream, app, error);
2270 else if (token_stream_peek (stream, '<'))
2271 result = variant_parse (stream, app, error);
2273 else if (token_stream_peek (stream, '{'))
2274 result = dictionary_parse (stream, app, error);
2276 else if (app && token_stream_peek (stream, '%'))
2277 result = positional_parse (stream, app, error);
2279 else if (token_stream_consume (stream, "true"))
2280 result = boolean_new (TRUE);
2282 else if (token_stream_consume (stream, "false"))
2283 result = boolean_new (FALSE);
2285 else if (token_stream_is_numeric (stream) ||
2286 token_stream_peek_string (stream, "inf") ||
2287 token_stream_peek_string (stream, "nan"))
2288 result = number_parse (stream, app, error);
2290 else if (token_stream_peek (stream, 'n') ||
2291 token_stream_peek (stream, 'j'))
2292 result = maybe_parse (stream, app, error);
2294 else if (token_stream_peek (stream, '@') ||
2295 token_stream_is_keyword (stream))
2296 result = typedecl_parse (stream, app, error);
2298 else if (token_stream_peek (stream, '\'') ||
2299 token_stream_peek (stream, '"'))
2300 result = string_parse (stream, app, error);
2302 else if (token_stream_peek2 (stream, 'b', '\'') ||
2303 token_stream_peek2 (stream, 'b', '"'))
2304 result = bytestring_parse (stream, app, error);
2306 else
2308 token_stream_set_error (stream, error, FALSE,
2309 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2310 "expected value");
2311 return NULL;
2314 if (result != NULL)
2316 token_stream_end_ref (stream, &source_ref);
2317 result->source_ref = source_ref;
2320 return result;
2324 * g_variant_parse:
2325 * @type: (nullable): a #GVariantType, or %NULL
2326 * @text: a string containing a GVariant in text form
2327 * @limit: (nullable): a pointer to the end of @text, or %NULL
2328 * @endptr: (nullable): a location to store the end pointer, or %NULL
2329 * @error: (nullable): a pointer to a %NULL #GError pointer, or %NULL
2331 * Parses a #GVariant from a text representation.
2333 * A single #GVariant is parsed from the content of @text.
2335 * The format is described [here][gvariant-text].
2337 * The memory at @limit will never be accessed and the parser behaves as
2338 * if the character at @limit is the nul terminator. This has the
2339 * effect of bounding @text.
2341 * If @endptr is non-%NULL then @text is permitted to contain data
2342 * following the value that this function parses and @endptr will be
2343 * updated to point to the first character past the end of the text
2344 * parsed by this function. If @endptr is %NULL and there is extra data
2345 * then an error is returned.
2347 * If @type is non-%NULL then the value will be parsed to have that
2348 * type. This may result in additional parse errors (in the case that
2349 * the parsed value doesn't fit the type) but may also result in fewer
2350 * errors (in the case that the type would have been ambiguous, such as
2351 * with empty arrays).
2353 * In the event that the parsing is successful, the resulting #GVariant
2354 * is returned. It is never floating, and must be freed with
2355 * g_variant_unref().
2357 * In case of any error, %NULL will be returned. If @error is non-%NULL
2358 * then it will be set to reflect the error that occurred.
2360 * Officially, the language understood by the parser is "any string
2361 * produced by g_variant_print()".
2363 * Returns: a non-floating reference to a #GVariant, or %NULL
2365 GVariant *
2366 g_variant_parse (const GVariantType *type,
2367 const gchar *text,
2368 const gchar *limit,
2369 const gchar **endptr,
2370 GError **error)
2372 TokenStream stream = { 0, };
2373 GVariant *result = NULL;
2374 AST *ast;
2376 g_return_val_if_fail (text != NULL, NULL);
2377 g_return_val_if_fail (text == limit || text != NULL, NULL);
2379 stream.start = text;
2380 stream.stream = text;
2381 stream.end = limit;
2383 if ((ast = parse (&stream, NULL, error)))
2385 if (type == NULL)
2386 result = ast_resolve (ast, error);
2387 else
2388 result = ast_get_value (ast, type, error);
2390 if (result != NULL)
2392 g_variant_ref_sink (result);
2394 if (endptr == NULL)
2396 while (stream.stream != limit &&
2397 g_ascii_isspace (*stream.stream))
2398 stream.stream++;
2400 if (stream.stream != limit && *stream.stream != '\0')
2402 SourceRef ref = { stream.stream - text,
2403 stream.stream - text };
2405 parser_set_error (error, &ref, NULL,
2406 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2407 "expected end of input");
2408 g_variant_unref (result);
2410 result = NULL;
2413 else
2414 *endptr = stream.stream;
2417 ast_free (ast);
2420 return result;
2424 * g_variant_new_parsed_va:
2425 * @format: a text format #GVariant
2426 * @app: a pointer to a #va_list
2428 * Parses @format and returns the result.
2430 * This is the version of g_variant_new_parsed() intended to be used
2431 * from libraries.
2433 * The return value will be floating if it was a newly created GVariant
2434 * instance. In the case that @format simply specified the collection
2435 * of a #GVariant pointer (eg: @format was "%*") then the collected
2436 * #GVariant pointer will be returned unmodified, without adding any
2437 * additional references.
2439 * Note that the arguments in @app must be of the correct width for their types
2440 * specified in @format when collected into the #va_list. See
2441 * the [GVariant varargs documentation][gvariant-varargs].
2443 * In order to behave correctly in all cases it is necessary for the
2444 * calling function to g_variant_ref_sink() the return result before
2445 * returning control to the user that originally provided the pointer.
2446 * At this point, the caller will have their own full reference to the
2447 * result. This can also be done by adding the result to a container,
2448 * or by passing it to another g_variant_new() call.
2450 * Returns: a new, usually floating, #GVariant
2452 GVariant *
2453 g_variant_new_parsed_va (const gchar *format,
2454 va_list *app)
2456 TokenStream stream = { 0, };
2457 GVariant *result = NULL;
2458 GError *error = NULL;
2459 AST *ast;
2461 g_return_val_if_fail (format != NULL, NULL);
2462 g_return_val_if_fail (app != NULL, NULL);
2464 stream.start = format;
2465 stream.stream = format;
2466 stream.end = NULL;
2468 if ((ast = parse (&stream, app, &error)))
2470 result = ast_resolve (ast, &error);
2471 ast_free (ast);
2474 if (result == NULL)
2475 g_error ("g_variant_new_parsed: %s", error->message);
2477 if (*stream.stream)
2478 g_error ("g_variant_new_parsed: trailing text after value");
2480 return result;
2484 * g_variant_new_parsed:
2485 * @format: a text format #GVariant
2486 * @...: arguments as per @format
2488 * Parses @format and returns the result.
2490 * @format must be a text format #GVariant with one extension: at any
2491 * point that a value may appear in the text, a '%' character followed
2492 * by a GVariant format string (as per g_variant_new()) may appear. In
2493 * that case, the same arguments are collected from the argument list as
2494 * g_variant_new() would have collected.
2496 * Note that the arguments must be of the correct width for their types
2497 * specified in @format. This can be achieved by casting them. See
2498 * the [GVariant varargs documentation][gvariant-varargs].
2500 * Consider this simple example:
2501 * |[<!-- language="C" -->
2502 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2503 * ]|
2505 * In the example, the variable argument parameters are collected and
2506 * filled in as if they were part of the original string to produce the
2507 * result of
2508 * |[<!-- language="C" -->
2509 * [('one', 1), ('two', 2), ('three', 3)]
2510 * ]|
2512 * This function is intended only to be used with @format as a string
2513 * literal. Any parse error is fatal to the calling process. If you
2514 * want to parse data from untrusted sources, use g_variant_parse().
2516 * You may not use this function to return, unmodified, a single
2517 * #GVariant pointer from the argument list. ie: @format may not solely
2518 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2519 * with "%@".
2521 * Returns: a new floating #GVariant instance
2523 GVariant *
2524 g_variant_new_parsed (const gchar *format,
2525 ...)
2527 GVariant *result;
2528 va_list ap;
2530 va_start (ap, format);
2531 result = g_variant_new_parsed_va (format, &ap);
2532 va_end (ap);
2534 return result;
2538 * g_variant_builder_add_parsed:
2539 * @builder: a #GVariantBuilder
2540 * @format: a text format #GVariant
2541 * @...: arguments as per @format
2543 * Adds to a #GVariantBuilder.
2545 * This call is a convenience wrapper that is exactly equivalent to
2546 * calling g_variant_new_parsed() followed by
2547 * g_variant_builder_add_value().
2549 * Note that the arguments must be of the correct width for their types
2550 * specified in @format_string. This can be achieved by casting them. See
2551 * the [GVariant varargs documentation][gvariant-varargs].
2553 * This function might be used as follows:
2555 * |[<!-- language="C" -->
2556 * GVariant *
2557 * make_pointless_dictionary (void)
2559 * GVariantBuilder builder;
2560 * int i;
2562 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2563 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2564 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2565 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2566 * return g_variant_builder_end (&builder);
2568 * ]|
2570 * Since: 2.26
2572 void
2573 g_variant_builder_add_parsed (GVariantBuilder *builder,
2574 const gchar *format,
2575 ...)
2577 va_list ap;
2579 va_start (ap, format);
2580 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
2581 va_end (ap);
2584 static gboolean
2585 parse_num (const gchar *num,
2586 const gchar *limit,
2587 gint *result)
2589 gchar *endptr;
2590 gint64 bignum;
2592 bignum = g_ascii_strtoll (num, &endptr, 10);
2594 if (endptr != limit)
2595 return FALSE;
2597 if (bignum < 0 || bignum > G_MAXINT)
2598 return FALSE;
2600 *result = bignum;
2602 return TRUE;
2605 static void
2606 add_last_line (GString *err,
2607 const gchar *str)
2609 const gchar *last_nl;
2610 gchar *chomped;
2611 gint i;
2613 /* This is an error at the end of input. If we have a file
2614 * with newlines, that's probably the empty string after the
2615 * last newline, which is not the most useful thing to show.
2617 * Instead, show the last line of non-whitespace that we have
2618 * and put the pointer at the end of it.
2620 chomped = g_strchomp (g_strdup (str));
2621 last_nl = strrchr (chomped, '\n');
2622 if (last_nl == NULL)
2623 last_nl = chomped;
2624 else
2625 last_nl++;
2627 /* Print the last line like so:
2629 * [1, 2, 3,
2632 g_string_append (err, " ");
2633 if (last_nl[0])
2634 g_string_append (err, last_nl);
2635 else
2636 g_string_append (err, "(empty input)");
2637 g_string_append (err, "\n ");
2638 for (i = 0; last_nl[i]; i++)
2639 g_string_append_c (err, ' ');
2640 g_string_append (err, "^\n");
2641 g_free (chomped);
2644 static void
2645 add_lines_from_range (GString *err,
2646 const gchar *str,
2647 const gchar *start1,
2648 const gchar *end1,
2649 const gchar *start2,
2650 const gchar *end2)
2652 while (str < end1 || str < end2)
2654 const gchar *nl;
2656 nl = str + strcspn (str, "\n");
2658 if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
2660 const gchar *s;
2662 /* We're going to print this line */
2663 g_string_append (err, " ");
2664 g_string_append_len (err, str, nl - str);
2665 g_string_append (err, "\n ");
2667 /* And add underlines... */
2668 for (s = str; s < nl; s++)
2670 if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
2671 g_string_append_c (err, '^');
2672 else
2673 g_string_append_c (err, ' ');
2675 g_string_append_c (err, '\n');
2678 if (!*nl)
2679 break;
2681 str = nl + 1;
2686 * g_variant_parse_error_print_context:
2687 * @error: a #GError from the #GVariantParseError domain
2688 * @source_str: the string that was given to the parser
2690 * Pretty-prints a message showing the context of a #GVariant parse
2691 * error within the string for which parsing was attempted.
2693 * The resulting string is suitable for output to the console or other
2694 * monospace media where newlines are treated in the usual way.
2696 * The message will typically look something like one of the following:
2698 * |[
2699 * unterminated string constant:
2700 * (1, 2, 3, 'abc
2701 * ^^^^
2702 * ]|
2704 * or
2706 * |[
2707 * unable to find a common type:
2708 * [1, 2, 3, 'str']
2709 * ^ ^^^^^
2710 * ]|
2712 * The format of the message may change in a future version.
2714 * @error must have come from a failed attempt to g_variant_parse() and
2715 * @source_str must be exactly the same string that caused the error.
2716 * If @source_str was not nul-terminated when you passed it to
2717 * g_variant_parse() then you must add nul termination before using this
2718 * function.
2720 * Returns: (transfer full): the printed message
2722 * Since: 2.40
2724 gchar *
2725 g_variant_parse_error_print_context (GError *error,
2726 const gchar *source_str)
2728 const gchar *colon, *dash, *comma;
2729 gboolean success = FALSE;
2730 GString *err;
2732 g_return_val_if_fail (error->domain == G_VARIANT_PARSE_ERROR, FALSE);
2734 /* We can only have a limited number of possible types of ranges
2735 * emitted from the parser:
2737 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2738 * - a-b: -- usually errors from handling one single token
2739 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2741 * We never see, for example "a,c".
2744 colon = strchr (error->message, ':');
2745 dash = strchr (error->message, '-');
2746 comma = strchr (error->message, ',');
2748 if (!colon)
2749 return NULL;
2751 err = g_string_new (colon + 1);
2752 g_string_append (err, ":\n");
2754 if (dash == NULL || colon < dash)
2756 gint point;
2758 /* we have a single point */
2759 if (!parse_num (error->message, colon, &point))
2760 goto out;
2762 if (point >= strlen (source_str))
2763 /* the error is at the end of the input */
2764 add_last_line (err, source_str);
2765 else
2766 /* otherwise just treat it as a error at a thin range */
2767 add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
2769 else
2771 /* We have one or two ranges... */
2772 if (comma && comma < colon)
2774 gint start1, end1, start2, end2;
2775 const gchar *dash2;
2777 /* Two ranges */
2778 dash2 = strchr (comma, '-');
2780 if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
2781 !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
2782 goto out;
2784 add_lines_from_range (err, source_str,
2785 source_str + start1, source_str + end1,
2786 source_str + start2, source_str + end2);
2788 else
2790 gint start, end;
2792 /* One range */
2793 if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
2794 goto out;
2796 add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
2800 success = TRUE;
2802 out:
2803 return g_string_free (err, !success);