nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * Copyright © 2009, 2010 Codethink Limited
3 *
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.
8 *
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.
13 *
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/>.
16 *
17 * Author: Ryan Lortie <desrt@desrt.ca>
18 */
19  
20 #include "config.h"
21  
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25  
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"
35  
36 /*
37 * two-pass algorithm
38 * designed by ryan lortie and william hua
39 * designed in itb-229 and at ghazi's, 2009.
40 */
41  
42 /**
43 * G_VARIANT_PARSE_ERROR:
44 *
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
69 *
70 * Error codes returned by parsing text-format GVariants.
71 **/
72 G_DEFINE_QUARK (g-variant-parse-error-quark, g_variant_parse_error)
73  
74 /**
75 * g_variant_parser_get_error_quark:
76 *
77 * Same as g_variant_error_quark().
78 *
79 * Deprecated: Use g_variant_parse_error_quark() instead.
80 */
81 GQuark
82 g_variant_parser_get_error_quark (void)
83 {
84 return g_variant_parse_error_quark ();
85 }
86  
87 typedef struct
88 {
89 gint start, end;
90 } SourceRef;
91  
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)
100 {
101 GString *msg = g_string_new (NULL);
102  
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);
107  
108 if (other != NULL)
109 {
110 g_assert (other->start != other->end);
111 g_string_append_printf (msg, ",%d-%d", other->start, other->end);
112 }
113 g_string_append_c (msg, ':');
114  
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);
118 }
119  
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 ...)
128 {
129 va_list ap;
130  
131 va_start (ap, format);
132 parser_set_error_va (error, location, other, code, format, ap);
133 va_end (ap);
134 }
135  
136 typedef struct
137 {
138 const gchar *start;
139 const gchar *stream;
140 const gchar *end;
141  
142 const gchar *this;
143 } TokenStream;
144  
145  
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 ...)
154 {
155 SourceRef ref;
156 va_list ap;
157  
158 ref.start = stream->this - stream->start;
159  
160 if (this_token)
161 ref.end = stream->stream - stream->start;
162 else
163 ref.end = ref.start;
164  
165 va_start (ap, format);
166 parser_set_error_va (error, &ref, NULL, code, format, ap);
167 va_end (ap);
168 }
169  
170 static gboolean
171 token_stream_prepare (TokenStream *stream)
172 {
173 gint brackets = 0;
174 const gchar *end;
175  
176 if (stream->this != NULL)
177 return TRUE;
178  
179 while (stream->stream != stream->end && g_ascii_isspace (*stream->stream))
180 stream->stream++;
181  
182 if (stream->stream == stream->end || *stream->stream == '\0')
183 {
184 stream->this = stream->stream;
185 return FALSE;
186 }
187  
188 switch (stream->stream[0])
189 {
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;
198  
199 case 'b':
200 if (stream->stream[1] == '\'' || stream->stream[1] == '"')
201 {
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;
206  
207 if (end != stream->end && *end)
208 end++;
209 break;
210 }
211  
212 else /* ↓↓↓ */;
213  
214 case 'a': /* 'b' */ case 'c': case 'd': case 'e': case 'f':
215 case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
216 case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
217 case 's': case 't': case 'u': case 'v': case 'w': case 'x':
218 case 'y': case 'z':
219 for (end = stream->stream; end != stream->end; end++)
220 if (!g_ascii_isalnum (*end))
221 break;
222 break;
223  
224 case '\'': case '"':
225 for (end = stream->stream + 1; end != stream->end; end++)
226 if (*end == stream->stream[0] || *end == '\0' ||
227 (*end == '\\' && (++end == stream->end || *end == '\0')))
228 break;
229  
230 if (end != stream->end && *end)
231 end++;
232 break;
233  
234 case '@': case '%':
235 /* stop at the first space, comma, colon or unmatched bracket.
236 * deals nicely with cases like (%i, %i) or {%i: %i}.
237 * Also: ] and > are never in format strings.
238 */
239 for (end = stream->stream + 1;
240 end != stream->end && *end != '\0' && *end != ',' &&
241 *end != ':' && *end != '>' && *end != ']' && !g_ascii_isspace (*end);
242 end++)
243  
244 if (*end == '(' || *end == '{')
245 brackets++;
246  
247 else if ((*end == ')' || *end == '}') && !brackets--)
248 break;
249  
250 break;
251  
252 default:
253 end = stream->stream + 1;
254 break;
255 }
256  
257 stream->this = stream->stream;
258 stream->stream = end;
259  
260 return TRUE;
261 }
262  
263 static void
264 token_stream_next (TokenStream *stream)
265 {
266 stream->this = NULL;
267 }
268  
269 static gboolean
270 token_stream_peek (TokenStream *stream,
271 gchar first_char)
272 {
273 if (!token_stream_prepare (stream))
274 return FALSE;
275  
276 return stream->this[0] == first_char;
277 }
278  
279 static gboolean
280 token_stream_peek2 (TokenStream *stream,
281 gchar first_char,
282 gchar second_char)
283 {
284 if (!token_stream_prepare (stream))
285 return FALSE;
286  
287 return stream->this[0] == first_char &&
288 stream->this[1] == second_char;
289 }
290  
291 static gboolean
292 token_stream_is_keyword (TokenStream *stream)
293 {
294 if (!token_stream_prepare (stream))
295 return FALSE;
296  
297 return g_ascii_isalpha (stream->this[0]) &&
298 g_ascii_isalpha (stream->this[1]);
299 }
300  
301 static gboolean
302 token_stream_is_numeric (TokenStream *stream)
303 {
304 if (!token_stream_prepare (stream))
305 return FALSE;
306  
307 return (g_ascii_isdigit (stream->this[0]) ||
308 stream->this[0] == '-' ||
309 stream->this[0] == '+' ||
310 stream->this[0] == '.');
311 }
312  
313 static gboolean
314 token_stream_peek_string (TokenStream *stream,
315 const gchar *token)
316 {
317 gint length = strlen (token);
318  
319 return token_stream_prepare (stream) &&
320 stream->stream - stream->this == length &&
321 memcmp (stream->this, token, length) == 0;
322 }
323  
324 static gboolean
325 token_stream_consume (TokenStream *stream,
326 const gchar *token)
327 {
328 if (!token_stream_peek_string (stream, token))
329 return FALSE;
330  
331 token_stream_next (stream);
332 return TRUE;
333 }
334  
335 static gboolean
336 token_stream_require (TokenStream *stream,
337 const gchar *token,
338 const gchar *purpose,
339 GError **error)
340 {
341  
342 if (!token_stream_consume (stream, token))
343 {
344 token_stream_set_error (stream, error, FALSE,
345 G_VARIANT_PARSE_ERROR_UNEXPECTED_TOKEN,
346 "expected '%s'%s", token, purpose);
347 return FALSE;
348 }
349  
350 return TRUE;
351 }
352  
353 static void
354 token_stream_assert (TokenStream *stream,
355 const gchar *token)
356 {
357 gboolean correct_token;
358  
359 correct_token = token_stream_consume (stream, token);
360 g_assert (correct_token);
361 }
362  
363 static gchar *
364 token_stream_get (TokenStream *stream)
365 {
366 gchar *result;
367  
368 if (!token_stream_prepare (stream))
369 return NULL;
370  
371 result = g_strndup (stream->this, stream->stream - stream->this);
372  
373 return result;
374 }
375  
376 static void
377 token_stream_start_ref (TokenStream *stream,
378 SourceRef *ref)
379 {
380 token_stream_prepare (stream);
381 ref->start = stream->this - stream->start;
382 }
383  
384 static void
385 token_stream_end_ref (TokenStream *stream,
386 SourceRef *ref)
387 {
388 ref->end = stream->stream - stream->start;
389 }
390  
391 static void
392 pattern_copy (gchar **out,
393 const gchar **in)
394 {
395 gint brackets = 0;
396  
397 while (**in == 'a' || **in == 'm' || **in == 'M')
398 *(*out)++ = *(*in)++;
399  
400 do
401 {
402 if (**in == '(' || **in == '{')
403 brackets++;
404  
405 else if (**in == ')' || **in == '}')
406 brackets--;
407  
408 *(*out)++ = *(*in)++;
409 }
410 while (brackets);
411 }
412  
413 static gchar *
414 pattern_coalesce (const gchar *left,
415 const gchar *right)
416 {
417 gchar *result;
418 gchar *out;
419  
420 /* the length of the output is loosely bound by the sum of the input
421 * lengths, not simply the greater of the two lengths.
422 *
423 * (*(iii)) + ((iii)*) ((iii)(iii))
424 *
425 * 8 + 8 = 12
426 */
427 out = result = g_malloc (strlen (left) + strlen (right));
428  
429 while (*left && *right)
430 {
431 if (*left == *right)
432 {
433 *out++ = *left++;
434 right++;
435 }
436  
437 else
438 {
439 const gchar **one = &left, **the_other = &right;
440  
441 again:
442 if (**one == '*' && **the_other != ')')
443 {
444 pattern_copy (&out, the_other);
445 (*one)++;
446 }
447  
448 else if (**one == 'M' && **the_other == 'm')
449 {
450 *out++ = *(*the_other)++;
451 }
452  
453 else if (**one == 'M' && **the_other != 'm')
454 {
455 (*one)++;
456 }
457  
458 else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
459 {
460 *out++ = *(*the_other)++;
461 (*one)++;
462 }
463  
464 else if (**one == 'S' && strchr ("sog", **the_other))
465 {
466 *out++ = *(*the_other)++;
467 (*one)++;
468 }
469  
470 else if (one == &left)
471 {
472 one = &right, the_other = &left;
473 goto again;
474 }
475  
476 else
477 break;
478 }
479 }
480  
481 if (*left || *right)
482 {
483 g_free (result);
484 result = NULL;
485 }
486 else
487 *out++ = '\0';
488  
489 return result;
490 }
491  
492 typedef struct _AST AST;
493 typedef gchar * (*get_pattern_func) (AST *ast,
494 GError **error);
495 typedef GVariant * (*get_value_func) (AST *ast,
496 const GVariantType *type,
497 GError **error);
498 typedef GVariant * (*get_base_value_func) (AST *ast,
499 const GVariantType *type,
500 GError **error);
501 typedef void (*free_func) (AST *ast);
502  
503 typedef struct
504 {
505 gchar * (* get_pattern) (AST *ast,
506 GError **error);
507 GVariant * (* get_value) (AST *ast,
508 const GVariantType *type,
509 GError **error);
510 GVariant * (* get_base_value) (AST *ast,
511 const GVariantType *type,
512 GError **error);
513 void (* free) (AST *ast);
514 } ASTClass;
515  
516 struct _AST
517 {
518 const ASTClass *class;
519 SourceRef source_ref;
520 };
521  
522 static gchar *
523 ast_get_pattern (AST *ast,
524 GError **error)
525 {
526 return ast->class->get_pattern (ast, error);
527 }
528  
529 static GVariant *
530 ast_get_value (AST *ast,
531 const GVariantType *type,
532 GError **error)
533 {
534 return ast->class->get_value (ast, type, error);
535 }
536  
537 static void
538 ast_free (AST *ast)
539 {
540 ast->class->free (ast);
541 }
542  
543 G_GNUC_PRINTF(5, 6)
544 static void
545 ast_set_error (AST *ast,
546 GError **error,
547 AST *other_ast,
548 gint code,
549 const gchar *format,
550 ...)
551 {
552 va_list ap;
553  
554 va_start (ap, format);
555 parser_set_error_va (error, &ast->source_ref,
556 other_ast ? & other_ast->source_ref : NULL,
557 code,
558 format, ap);
559 va_end (ap);
560 }
561  
562 static GVariant *
563 ast_type_error (AST *ast,
564 const GVariantType *type,
565 GError **error)
566 {
567 gchar *typestr;
568  
569 typestr = g_variant_type_dup_string (type);
570 ast_set_error (ast, error, NULL,
571 G_VARIANT_PARSE_ERROR_TYPE_ERROR,
572 "can not parse as value of type '%s'",
573 typestr);
574 g_free (typestr);
575  
576 return NULL;
577 }
578  
579 static GVariant *
580 ast_resolve (AST *ast,
581 GError **error)
582 {
583 GVariant *value;
584 gchar *pattern;
585 gint i, j = 0;
586  
587 pattern = ast_get_pattern (ast, error);
588  
589 if (pattern == NULL)
590 return NULL;
591  
592 /* choose reasonable defaults
593 *
594 * 1) favour non-maybe values where possible
595 * 2) default type for strings is 's'
596 * 3) default type for integers is 'i'
597 */
598 for (i = 0; pattern[i]; i++)
599 switch (pattern[i])
600 {
601 case '*':
602 ast_set_error (ast, error, NULL,
603 G_VARIANT_PARSE_ERROR_CANNOT_INFER_TYPE,
604 "unable to infer type");
605 g_free (pattern);
606 return NULL;
607  
608 case 'M':
609 break;
610  
611 case 'S':
612 pattern[j++] = 's';
613 break;
614  
615 case 'N':
616 pattern[j++] = 'i';
617 break;
618  
619 default:
620 pattern[j++] = pattern[i];
621 break;
622 }
623 pattern[j++] = '\0';
624  
625 value = ast_get_value (ast, G_VARIANT_TYPE (pattern), error);
626 g_free (pattern);
627  
628 return value;
629 }
630  
631  
632 static AST *parse (TokenStream *stream,
633 va_list *app,
634 GError **error);
635  
636 static void
637 ast_array_append (AST ***array,
638 gint *n_items,
639 AST *ast)
640 {
641 if ((*n_items & (*n_items - 1)) == 0)
642 *array = g_renew (AST *, *array, *n_items ? 2 ** n_items : 1);
643  
644 (*array)[(*n_items)++] = ast;
645 }
646  
647 static void
648 ast_array_free (AST **array,
649 gint n_items)
650 {
651 gint i;
652  
653 for (i = 0; i < n_items; i++)
654 ast_free (array[i]);
655 g_free (array);
656 }
657  
658 static gchar *
659 ast_array_get_pattern (AST **array,
660 gint n_items,
661 GError **error)
662 {
663 gchar *pattern;
664 gint i;
665  
666 pattern = ast_get_pattern (array[0], error);
667  
668 if (pattern == NULL)
669 return NULL;
670  
671 for (i = 1; i < n_items; i++)
672 {
673 gchar *tmp, *merged;
674  
675 tmp = ast_get_pattern (array[i], error);
676  
677 if (tmp == NULL)
678 {
679 g_free (pattern);
680 return NULL;
681 }
682  
683 merged = pattern_coalesce (pattern, tmp);
684 g_free (pattern);
685 pattern = merged;
686  
687 if (merged == NULL)
688 /* set coalescence implies pairwise coalescence (i think).
689 * we should therefore be able to trace the failure to a single
690 * pair of values.
691 */
692 {
693 int j = 0;
694  
695 while (TRUE)
696 {
697 gchar *tmp2;
698 gchar *m;
699  
700 /* if 'j' reaches 'i' then we failed to find the pair */
701 g_assert (j < i);
702  
703 tmp2 = ast_get_pattern (array[j], NULL);
704 g_assert (tmp2 != NULL);
705  
706 m = pattern_coalesce (tmp, tmp2);
707 g_free (tmp2);
708 g_free (m);
709  
710 if (m == NULL)
711 {
712 /* we found a conflict between 'i' and 'j'.
713 *
714 * report the error. note: 'j' is first.
715 */
716 ast_set_error (array[j], error, array[i],
717 G_VARIANT_PARSE_ERROR_NO_COMMON_TYPE,
718 "unable to find a common type");
719 g_free (tmp);
720 return NULL;
721 }
722  
723 j++;
724 }
725  
726 }
727  
728 g_free (tmp);
729 }
730  
731 return pattern;
732 }
733  
734 typedef struct
735 {
736 AST ast;
737  
738 AST *child;
739 } Maybe;
740  
741 static gchar *
742 maybe_get_pattern (AST *ast,
743 GError **error)
744 {
745 Maybe *maybe = (Maybe *) ast;
746  
747 if (maybe->child != NULL)
748 {
749 gchar *child_pattern;
750 gchar *pattern;
751  
752 child_pattern = ast_get_pattern (maybe->child, error);
753  
754 if (child_pattern == NULL)
755 return NULL;
756  
757 pattern = g_strdup_printf ("m%s", child_pattern);
758 g_free (child_pattern);
759  
760 return pattern;
761 }
762  
763 return g_strdup ("m*");
764 }
765  
766 static GVariant *
767 maybe_get_value (AST *ast,
768 const GVariantType *type,
769 GError **error)
770 {
771 Maybe *maybe = (Maybe *) ast;
772 GVariant *value;
773  
774 if (!g_variant_type_is_maybe (type))
775 return ast_type_error (ast, type, error);
776  
777 type = g_variant_type_element (type);
778  
779 if (maybe->child)
780 {
781 value = ast_get_value (maybe->child, type, error);
782  
783 if (value == NULL)
784 return NULL;
785 }
786 else
787 value = NULL;
788  
789 return g_variant_new_maybe (type, value);
790 }
791  
792 static void
793 maybe_free (AST *ast)
794 {
795 Maybe *maybe = (Maybe *) ast;
796  
797 if (maybe->child != NULL)
798 ast_free (maybe->child);
799  
800 g_slice_free (Maybe, maybe);
801 }
802  
803 static AST *
804 maybe_parse (TokenStream *stream,
805 va_list *app,
806 GError **error)
807 {
808 static const ASTClass maybe_class = {
809 maybe_get_pattern,
810 maybe_get_value, NULL,
811 maybe_free
812 };
813 AST *child = NULL;
814 Maybe *maybe;
815  
816 if (token_stream_consume (stream, "just"))
817 {
818 child = parse (stream, app, error);
819 if (child == NULL)
820 return NULL;
821 }
822  
823 else if (!token_stream_consume (stream, "nothing"))
824 {
825 token_stream_set_error (stream, error, TRUE,
826 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
827 "unknown keyword");
828 return NULL;
829 }
830  
831 maybe = g_slice_new (Maybe);
832 maybe->ast.class = &maybe_class;
833 maybe->child = child;
834  
835 return (AST *) maybe;
836 }
837  
838 static GVariant *
839 maybe_wrapper (AST *ast,
840 const GVariantType *type,
841 GError **error)
842 {
843 const GVariantType *t;
844 GVariant *value;
845 int depth;
846  
847 for (depth = 0, t = type;
848 g_variant_type_is_maybe (t);
849 depth++, t = g_variant_type_element (t));
850  
851 value = ast->class->get_base_value (ast, t, error);
852  
853 if (value == NULL)
854 return NULL;
855  
856 while (depth--)
857 value = g_variant_new_maybe (NULL, value);
858  
859 return value;
860 }
861  
862 typedef struct
863 {
864 AST ast;
865  
866 AST **children;
867 gint n_children;
868 } Array;
869  
870 static gchar *
871 array_get_pattern (AST *ast,
872 GError **error)
873 {
874 Array *array = (Array *) ast;
875 gchar *pattern;
876 gchar *result;
877  
878 if (array->n_children == 0)
879 return g_strdup ("Ma*");
880  
881 pattern = ast_array_get_pattern (array->children, array->n_children, error);
882  
883 if (pattern == NULL)
884 return NULL;
885  
886 result = g_strdup_printf ("Ma%s", pattern);
887 g_free (pattern);
888  
889 return result;
890 }
891  
892 static GVariant *
893 array_get_value (AST *ast,
894 const GVariantType *type,
895 GError **error)
896 {
897 Array *array = (Array *) ast;
898 const GVariantType *childtype;
899 GVariantBuilder builder;
900 gint i;
901  
902 if (!g_variant_type_is_array (type))
903 return ast_type_error (ast, type, error);
904  
905 g_variant_builder_init (&builder, type);
906 childtype = g_variant_type_element (type);
907  
908 for (i = 0; i < array->n_children; i++)
909 {
910 GVariant *child;
911  
912 if (!(child = ast_get_value (array->children[i], childtype, error)))
913 {
914 g_variant_builder_clear (&builder);
915 return NULL;
916 }
917  
918 g_variant_builder_add_value (&builder, child);
919 }
920  
921 return g_variant_builder_end (&builder);
922 }
923  
924 static void
925 array_free (AST *ast)
926 {
927 Array *array = (Array *) ast;
928  
929 ast_array_free (array->children, array->n_children);
930 g_slice_free (Array, array);
931 }
932  
933 static AST *
934 array_parse (TokenStream *stream,
935 va_list *app,
936 GError **error)
937 {
938 static const ASTClass array_class = {
939 array_get_pattern,
940 maybe_wrapper, array_get_value,
941 array_free
942 };
943 gboolean need_comma = FALSE;
944 Array *array;
945  
946 array = g_slice_new (Array);
947 array->ast.class = &array_class;
948 array->children = NULL;
949 array->n_children = 0;
950  
951 token_stream_assert (stream, "[");
952 while (!token_stream_consume (stream, "]"))
953 {
954 AST *child;
955  
956 if (need_comma &&
957 !token_stream_require (stream, ",",
958 " or ']' to follow array element",
959 error))
960 goto error;
961  
962 child = parse (stream, app, error);
963  
964 if (!child)
965 goto error;
966  
967 ast_array_append (&array->children, &array->n_children, child);
968 need_comma = TRUE;
969 }
970  
971 return (AST *) array;
972  
973 error:
974 ast_array_free (array->children, array->n_children);
975 g_slice_free (Array, array);
976  
977 return NULL;
978 }
979  
980 typedef struct
981 {
982 AST ast;
983  
984 AST **children;
985 gint n_children;
986 } Tuple;
987  
988 static gchar *
989 tuple_get_pattern (AST *ast,
990 GError **error)
991 {
992 Tuple *tuple = (Tuple *) ast;
993 gchar *result = NULL;
994 gchar **parts;
995 gint i;
996  
997 parts = g_new (gchar *, tuple->n_children + 4);
998 parts[tuple->n_children + 1] = (gchar *) ")";
999 parts[tuple->n_children + 2] = NULL;
1000 parts[0] = (gchar *) "M(";
1001  
1002 for (i = 0; i < tuple->n_children; i++)
1003 if (!(parts[i + 1] = ast_get_pattern (tuple->children[i], error)))
1004 break;
1005  
1006 if (i == tuple->n_children)
1007 result = g_strjoinv ("", parts);
1008  
1009 /* parts[0] should not be freed */
1010 while (i)
1011 g_free (parts[i--]);
1012 g_free (parts);
1013  
1014 return result;
1015 }
1016  
1017 static GVariant *
1018 tuple_get_value (AST *ast,
1019 const GVariantType *type,
1020 GError **error)
1021 {
1022 Tuple *tuple = (Tuple *) ast;
1023 const GVariantType *childtype;
1024 GVariantBuilder builder;
1025 gint i;
1026  
1027 if (!g_variant_type_is_tuple (type))
1028 return ast_type_error (ast, type, error);
1029  
1030 g_variant_builder_init (&builder, type);
1031 childtype = g_variant_type_first (type);
1032  
1033 for (i = 0; i < tuple->n_children; i++)
1034 {
1035 GVariant *child;
1036  
1037 if (childtype == NULL)
1038 {
1039 g_variant_builder_clear (&builder);
1040 return ast_type_error (ast, type, error);
1041 }
1042  
1043 if (!(child = ast_get_value (tuple->children[i], childtype, error)))
1044 {
1045 g_variant_builder_clear (&builder);
1046 return FALSE;
1047 }
1048  
1049 g_variant_builder_add_value (&builder, child);
1050 childtype = g_variant_type_next (childtype);
1051 }
1052  
1053 if (childtype != NULL)
1054 {
1055 g_variant_builder_clear (&builder);
1056 return ast_type_error (ast, type, error);
1057 }
1058  
1059 return g_variant_builder_end (&builder);
1060 }
1061  
1062 static void
1063 tuple_free (AST *ast)
1064 {
1065 Tuple *tuple = (Tuple *) ast;
1066  
1067 ast_array_free (tuple->children, tuple->n_children);
1068 g_slice_free (Tuple, tuple);
1069 }
1070  
1071 static AST *
1072 tuple_parse (TokenStream *stream,
1073 va_list *app,
1074 GError **error)
1075 {
1076 static const ASTClass tuple_class = {
1077 tuple_get_pattern,
1078 maybe_wrapper, tuple_get_value,
1079 tuple_free
1080 };
1081 gboolean need_comma = FALSE;
1082 gboolean first = TRUE;
1083 Tuple *tuple;
1084  
1085 tuple = g_slice_new (Tuple);
1086 tuple->ast.class = &tuple_class;
1087 tuple->children = NULL;
1088 tuple->n_children = 0;
1089  
1090 token_stream_assert (stream, "(");
1091 while (!token_stream_consume (stream, ")"))
1092 {
1093 AST *child;
1094  
1095 if (need_comma &&
1096 !token_stream_require (stream, ",",
1097 " or ')' to follow tuple element",
1098 error))
1099 goto error;
1100  
1101 child = parse (stream, app, error);
1102  
1103 if (!child)
1104 goto error;
1105  
1106 ast_array_append (&tuple->children, &tuple->n_children, child);
1107  
1108 /* the first time, we absolutely require a comma, so grab it here
1109 * and leave need_comma = FALSE so that the code above doesn't
1110 * require a second comma.
1111 *
1112 * the second and remaining times, we set need_comma = TRUE.
1113 */
1114 if (first)
1115 {
1116 if (!token_stream_require (stream, ",",
1117 " after first tuple element", error))
1118 goto error;
1119  
1120 first = FALSE;
1121 }
1122 else
1123 need_comma = TRUE;
1124 }
1125  
1126 return (AST *) tuple;
1127  
1128 error:
1129 ast_array_free (tuple->children, tuple->n_children);
1130 g_slice_free (Tuple, tuple);
1131  
1132 return NULL;
1133 }
1134  
1135 typedef struct
1136 {
1137 AST ast;
1138  
1139 AST *value;
1140 } Variant;
1141  
1142 static gchar *
1143 variant_get_pattern (AST *ast,
1144 GError **error)
1145 {
1146 return g_strdup ("Mv");
1147 }
1148  
1149 static GVariant *
1150 variant_get_value (AST *ast,
1151 const GVariantType *type,
1152 GError **error)
1153 {
1154 Variant *variant = (Variant *) ast;
1155 GVariant *child;
1156  
1157 if (!g_variant_type_equal (type, G_VARIANT_TYPE_VARIANT))
1158 return ast_type_error (ast, type, error);
1159  
1160 child = ast_resolve (variant->value, error);
1161  
1162 if (child == NULL)
1163 return NULL;
1164  
1165 return g_variant_new_variant (child);
1166 }
1167  
1168 static void
1169 variant_free (AST *ast)
1170 {
1171 Variant *variant = (Variant *) ast;
1172  
1173 ast_free (variant->value);
1174 g_slice_free (Variant, variant);
1175 }
1176  
1177 static AST *
1178 variant_parse (TokenStream *stream,
1179 va_list *app,
1180 GError **error)
1181 {
1182 static const ASTClass variant_class = {
1183 variant_get_pattern,
1184 maybe_wrapper, variant_get_value,
1185 variant_free
1186 };
1187 Variant *variant;
1188 AST *value;
1189  
1190 token_stream_assert (stream, "<");
1191 value = parse (stream, app, error);
1192  
1193 if (!value)
1194 return NULL;
1195  
1196 if (!token_stream_require (stream, ">", " to follow variant value", error))
1197 {
1198 ast_free (value);
1199 return NULL;
1200 }
1201  
1202 variant = g_slice_new (Variant);
1203 variant->ast.class = &variant_class;
1204 variant->value = value;
1205  
1206 return (AST *) variant;
1207 }
1208  
1209 typedef struct
1210 {
1211 AST ast;
1212  
1213 AST **keys;
1214 AST **values;
1215 gint n_children;
1216 } Dictionary;
1217  
1218 static gchar *
1219 dictionary_get_pattern (AST *ast,
1220 GError **error)
1221 {
1222 Dictionary *dict = (Dictionary *) ast;
1223 gchar *value_pattern;
1224 gchar *key_pattern;
1225 gchar key_char;
1226 gchar *result;
1227  
1228 if (dict->n_children == 0)
1229 return g_strdup ("Ma{**}");
1230  
1231 key_pattern = ast_array_get_pattern (dict->keys,
1232 abs (dict->n_children),
1233 error);
1234  
1235 if (key_pattern == NULL)
1236 return NULL;
1237  
1238 /* we can not have maybe keys */
1239 if (key_pattern[0] == 'M')
1240 key_char = key_pattern[1];
1241 else
1242 key_char = key_pattern[0];
1243  
1244 g_free (key_pattern);
1245  
1246 /* the basic types,
1247 * plus undetermined number type and undetermined string type.
1248 */
1249 if (!strchr ("bynqiuxthdsogNS", key_char))
1250 {
1251 ast_set_error (ast, error, NULL,
1252 G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
1253 "dictionary keys must have basic types");
1254 return NULL;
1255 }
1256  
1257 value_pattern = ast_get_pattern (dict->values[0], error);
1258  
1259 if (value_pattern == NULL)
1260 return NULL;
1261  
1262 result = g_strdup_printf ("M%s{%c%s}",
1263 dict->n_children > 0 ? "a" : "",
1264 key_char, value_pattern);
1265 g_free (value_pattern);
1266  
1267 return result;
1268 }
1269  
1270 static GVariant *
1271 dictionary_get_value (AST *ast,
1272 const GVariantType *type,
1273 GError **error)
1274 {
1275 Dictionary *dict = (Dictionary *) ast;
1276  
1277 if (dict->n_children == -1)
1278 {
1279 const GVariantType *subtype;
1280 GVariantBuilder builder;
1281 GVariant *subvalue;
1282  
1283 if (!g_variant_type_is_dict_entry (type))
1284 return ast_type_error (ast, type, error);
1285  
1286 g_variant_builder_init (&builder, type);
1287  
1288 subtype = g_variant_type_key (type);
1289 if (!(subvalue = ast_get_value (dict->keys[0], subtype, error)))
1290 {
1291 g_variant_builder_clear (&builder);
1292 return NULL;
1293 }
1294 g_variant_builder_add_value (&builder, subvalue);
1295  
1296 subtype = g_variant_type_value (type);
1297 if (!(subvalue = ast_get_value (dict->values[0], subtype, error)))
1298 {
1299 g_variant_builder_clear (&builder);
1300 return NULL;
1301 }
1302 g_variant_builder_add_value (&builder, subvalue);
1303  
1304 return g_variant_builder_end (&builder);
1305 }
1306 else
1307 {
1308 const GVariantType *entry, *key, *val;
1309 GVariantBuilder builder;
1310 gint i;
1311  
1312 if (!g_variant_type_is_subtype_of (type, G_VARIANT_TYPE_DICTIONARY))
1313 return ast_type_error (ast, type, error);
1314  
1315 entry = g_variant_type_element (type);
1316 key = g_variant_type_key (entry);
1317 val = g_variant_type_value (entry);
1318  
1319 g_variant_builder_init (&builder, type);
1320  
1321 for (i = 0; i < dict->n_children; i++)
1322 {
1323 GVariant *subvalue;
1324  
1325 g_variant_builder_open (&builder, entry);
1326  
1327 if (!(subvalue = ast_get_value (dict->keys[i], key, error)))
1328 {
1329 g_variant_builder_clear (&builder);
1330 return NULL;
1331 }
1332 g_variant_builder_add_value (&builder, subvalue);
1333  
1334 if (!(subvalue = ast_get_value (dict->values[i], val, error)))
1335 {
1336 g_variant_builder_clear (&builder);
1337 return NULL;
1338 }
1339 g_variant_builder_add_value (&builder, subvalue);
1340 g_variant_builder_close (&builder);
1341 }
1342  
1343 return g_variant_builder_end (&builder);
1344 }
1345 }
1346  
1347 static void
1348 dictionary_free (AST *ast)
1349 {
1350 Dictionary *dict = (Dictionary *) ast;
1351 gint n_children;
1352  
1353 if (dict->n_children > -1)
1354 n_children = dict->n_children;
1355 else
1356 n_children = 1;
1357  
1358 ast_array_free (dict->keys, n_children);
1359 ast_array_free (dict->values, n_children);
1360 g_slice_free (Dictionary, dict);
1361 }
1362  
1363 static AST *
1364 dictionary_parse (TokenStream *stream,
1365 va_list *app,
1366 GError **error)
1367 {
1368 static const ASTClass dictionary_class = {
1369 dictionary_get_pattern,
1370 maybe_wrapper, dictionary_get_value,
1371 dictionary_free
1372 };
1373 gint n_keys, n_values;
1374 gboolean only_one;
1375 Dictionary *dict;
1376 AST *first;
1377  
1378 dict = g_slice_new (Dictionary);
1379 dict->ast.class = &dictionary_class;
1380 dict->keys = NULL;
1381 dict->values = NULL;
1382 n_keys = n_values = 0;
1383  
1384 token_stream_assert (stream, "{");
1385  
1386 if (token_stream_consume (stream, "}"))
1387 {
1388 dict->n_children = 0;
1389 return (AST *) dict;
1390 }
1391  
1392 if ((first = parse (stream, app, error)) == NULL)
1393 goto error;
1394  
1395 ast_array_append (&dict->keys, &n_keys, first);
1396  
1397 only_one = token_stream_consume (stream, ",");
1398 if (!only_one &&
1399 !token_stream_require (stream, ":",
1400 " or ',' to follow dictionary entry key",
1401 error))
1402 goto error;
1403  
1404 if ((first = parse (stream, app, error)) == NULL)
1405 goto error;
1406  
1407 ast_array_append (&dict->values, &n_values, first);
1408  
1409 if (only_one)
1410 {
1411 if (!token_stream_require (stream, "}", " at end of dictionary entry",
1412 error))
1413 goto error;
1414  
1415 g_assert (n_keys == 1 && n_values == 1);
1416 dict->n_children = -1;
1417  
1418 return (AST *) dict;
1419 }
1420  
1421 while (!token_stream_consume (stream, "}"))
1422 {
1423 AST *child;
1424  
1425 if (!token_stream_require (stream, ",",
1426 " or '}' to follow dictionary entry", error))
1427 goto error;
1428  
1429 child = parse (stream, app, error);
1430  
1431 if (!child)
1432 goto error;
1433  
1434 ast_array_append (&dict->keys, &n_keys, child);
1435  
1436 if (!token_stream_require (stream, ":",
1437 " to follow dictionary entry key", error))
1438 goto error;
1439  
1440 child = parse (stream, app, error);
1441  
1442 if (!child)
1443 goto error;
1444  
1445 ast_array_append (&dict->values, &n_values, child);
1446 }
1447  
1448 g_assert (n_keys == n_values);
1449 dict->n_children = n_keys;
1450  
1451 return (AST *) dict;
1452  
1453 error:
1454 ast_array_free (dict->keys, n_keys);
1455 ast_array_free (dict->values, n_values);
1456 g_slice_free (Dictionary, dict);
1457  
1458 return NULL;
1459 }
1460  
1461 typedef struct
1462 {
1463 AST ast;
1464 gchar *string;
1465 } String;
1466  
1467 static gchar *
1468 string_get_pattern (AST *ast,
1469 GError **error)
1470 {
1471 return g_strdup ("MS");
1472 }
1473  
1474 static GVariant *
1475 string_get_value (AST *ast,
1476 const GVariantType *type,
1477 GError **error)
1478 {
1479 String *string = (String *) ast;
1480  
1481 if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
1482 return g_variant_new_string (string->string);
1483  
1484 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
1485 {
1486 if (!g_variant_is_object_path (string->string))
1487 {
1488 ast_set_error (ast, error, NULL,
1489 G_VARIANT_PARSE_ERROR_INVALID_OBJECT_PATH,
1490 "not a valid object path");
1491 return NULL;
1492 }
1493  
1494 return g_variant_new_object_path (string->string);
1495 }
1496  
1497 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
1498 {
1499 if (!g_variant_is_signature (string->string))
1500 {
1501 ast_set_error (ast, error, NULL,
1502 G_VARIANT_PARSE_ERROR_INVALID_SIGNATURE,
1503 "not a valid signature");
1504 return NULL;
1505 }
1506  
1507 return g_variant_new_signature (string->string);
1508 }
1509  
1510 else
1511 return ast_type_error (ast, type, error);
1512 }
1513  
1514 static void
1515 string_free (AST *ast)
1516 {
1517 String *string = (String *) ast;
1518  
1519 g_free (string->string);
1520 g_slice_free (String, string);
1521 }
1522  
1523 static gboolean
1524 unicode_unescape (const gchar *src,
1525 gint *src_ofs,
1526 gchar *dest,
1527 gint *dest_ofs,
1528 gint length,
1529 SourceRef *ref,
1530 GError **error)
1531 {
1532 gchar buffer[9];
1533 guint64 value;
1534 gchar *end;
1535  
1536 (*src_ofs)++;
1537  
1538 g_assert (length < sizeof (buffer));
1539 strncpy (buffer, src + *src_ofs, length);
1540 buffer[length] = '\0';
1541  
1542 value = g_ascii_strtoull (buffer, &end, 0x10);
1543  
1544 if (value == 0 || end != buffer + length)
1545 {
1546 parser_set_error (error, ref, NULL,
1547 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1548 "invalid %d-character unicode escape", length);
1549 return FALSE;
1550 }
1551  
1552 g_assert (value <= G_MAXUINT32);
1553  
1554 *dest_ofs += g_unichar_to_utf8 (value, dest + *dest_ofs);
1555 *src_ofs += length;
1556  
1557 return TRUE;
1558 }
1559  
1560 static AST *
1561 string_parse (TokenStream *stream,
1562 va_list *app,
1563 GError **error)
1564 {
1565 static const ASTClass string_class = {
1566 string_get_pattern,
1567 maybe_wrapper, string_get_value,
1568 string_free
1569 };
1570 String *string;
1571 SourceRef ref;
1572 gchar *token;
1573 gsize length;
1574 gchar quote;
1575 gchar *str;
1576 gint i, j;
1577  
1578 token_stream_start_ref (stream, &ref);
1579 token = token_stream_get (stream);
1580 token_stream_end_ref (stream, &ref);
1581 length = strlen (token);
1582 quote = token[0];
1583  
1584 str = g_malloc (length);
1585 g_assert (quote == '"' || quote == '\'');
1586 j = 0;
1587 i = 1;
1588 while (token[i] != quote)
1589 switch (token[i])
1590 {
1591 case '\0':
1592 parser_set_error (error, &ref, NULL,
1593 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1594 "unterminated string constant");
1595 g_free (token);
1596 g_free (str);
1597 return NULL;
1598  
1599 case '\\':
1600 switch (token[++i])
1601 {
1602 case '\0':
1603 parser_set_error (error, &ref, NULL,
1604 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1605 "unterminated string constant");
1606 g_free (token);
1607 g_free (str);
1608 return NULL;
1609  
1610 case 'u':
1611 if (!unicode_unescape (token, &i, str, &j, 4, &ref, error))
1612 {
1613 g_free (token);
1614 g_free (str);
1615 return NULL;
1616 }
1617 continue;
1618  
1619 case 'U':
1620 if (!unicode_unescape (token, &i, str, &j, 8, &ref, error))
1621 {
1622 g_free (token);
1623 g_free (str);
1624 return NULL;
1625 }
1626 continue;
1627  
1628 case 'a': str[j++] = '\a'; i++; continue;
1629 case 'b': str[j++] = '\b'; i++; continue;
1630 case 'f': str[j++] = '\f'; i++; continue;
1631 case 'n': str[j++] = '\n'; i++; continue;
1632 case 'r': str[j++] = '\r'; i++; continue;
1633 case 't': str[j++] = '\t'; i++; continue;
1634 case 'v': str[j++] = '\v'; i++; continue;
1635 case '\n': i++; continue;
1636 }
1637  
1638 default:
1639 str[j++] = token[i++];
1640 }
1641 str[j++] = '\0';
1642 g_free (token);
1643  
1644 string = g_slice_new (String);
1645 string->ast.class = &string_class;
1646 string->string = str;
1647  
1648 token_stream_next (stream);
1649  
1650 return (AST *) string;
1651 }
1652  
1653 typedef struct
1654 {
1655 AST ast;
1656 gchar *string;
1657 } ByteString;
1658  
1659 static gchar *
1660 bytestring_get_pattern (AST *ast,
1661 GError **error)
1662 {
1663 return g_strdup ("May");
1664 }
1665  
1666 static GVariant *
1667 bytestring_get_value (AST *ast,
1668 const GVariantType *type,
1669 GError **error)
1670 {
1671 ByteString *string = (ByteString *) ast;
1672  
1673 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BYTESTRING))
1674 return ast_type_error (ast, type, error);
1675  
1676 return g_variant_new_bytestring (string->string);
1677 }
1678  
1679 static void
1680 bytestring_free (AST *ast)
1681 {
1682 ByteString *string = (ByteString *) ast;
1683  
1684 g_free (string->string);
1685 g_slice_free (ByteString, string);
1686 }
1687  
1688 static AST *
1689 bytestring_parse (TokenStream *stream,
1690 va_list *app,
1691 GError **error)
1692 {
1693 static const ASTClass bytestring_class = {
1694 bytestring_get_pattern,
1695 maybe_wrapper, bytestring_get_value,
1696 bytestring_free
1697 };
1698 ByteString *string;
1699 SourceRef ref;
1700 gchar *token;
1701 gsize length;
1702 gchar quote;
1703 gchar *str;
1704 gint i, j;
1705  
1706 token_stream_start_ref (stream, &ref);
1707 token = token_stream_get (stream);
1708 token_stream_end_ref (stream, &ref);
1709 g_assert (token[0] == 'b');
1710 length = strlen (token);
1711 quote = token[1];
1712  
1713 str = g_malloc (length);
1714 g_assert (quote == '"' || quote == '\'');
1715 j = 0;
1716 i = 2;
1717 while (token[i] != quote)
1718 switch (token[i])
1719 {
1720 case '\0':
1721 parser_set_error (error, &ref, NULL,
1722 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1723 "unterminated string constant");
1724 g_free (token);
1725 return NULL;
1726  
1727 case '\\':
1728 switch (token[++i])
1729 {
1730 case '\0':
1731 parser_set_error (error, &ref, NULL,
1732 G_VARIANT_PARSE_ERROR_UNTERMINATED_STRING_CONSTANT,
1733 "unterminated string constant");
1734 g_free (token);
1735 return NULL;
1736  
1737 case '0': case '1': case '2': case '3':
1738 case '4': case '5': case '6': case '7':
1739 {
1740 /* up to 3 characters */
1741 guchar val = token[i++] - '0';
1742  
1743 if ('0' <= token[i] && token[i] < '8')
1744 val = (val << 3) | (token[i++] - '0');
1745  
1746 if ('0' <= token[i] && token[i] < '8')
1747 val = (val << 3) | (token[i++] - '0');
1748  
1749 str[j++] = val;
1750 }
1751 continue;
1752  
1753 case 'a': str[j++] = '\a'; i++; continue;
1754 case 'b': str[j++] = '\b'; i++; continue;
1755 case 'f': str[j++] = '\f'; i++; continue;
1756 case 'n': str[j++] = '\n'; i++; continue;
1757 case 'r': str[j++] = '\r'; i++; continue;
1758 case 't': str[j++] = '\t'; i++; continue;
1759 case 'v': str[j++] = '\v'; i++; continue;
1760 case '\n': i++; continue;
1761 }
1762  
1763 default:
1764 str[j++] = token[i++];
1765 }
1766 str[j++] = '\0';
1767 g_free (token);
1768  
1769 string = g_slice_new (ByteString);
1770 string->ast.class = &bytestring_class;
1771 string->string = str;
1772  
1773 token_stream_next (stream);
1774  
1775 return (AST *) string;
1776 }
1777  
1778 typedef struct
1779 {
1780 AST ast;
1781  
1782 gchar *token;
1783 } Number;
1784  
1785 static gchar *
1786 number_get_pattern (AST *ast,
1787 GError **error)
1788 {
1789 Number *number = (Number *) ast;
1790  
1791 if (strchr (number->token, '.') ||
1792 (!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
1793 strstr (number->token, "inf") ||
1794 strstr (number->token, "nan"))
1795 return g_strdup ("Md");
1796  
1797 return g_strdup ("MN");
1798 }
1799  
1800 static GVariant *
1801 number_overflow (AST *ast,
1802 const GVariantType *type,
1803 GError **error)
1804 {
1805 ast_set_error (ast, error, NULL,
1806 G_VARIANT_PARSE_ERROR_NUMBER_OUT_OF_RANGE,
1807 "number out of range for type '%c'",
1808 g_variant_type_peek_string (type)[0]);
1809 return NULL;
1810 }
1811  
1812 static GVariant *
1813 number_get_value (AST *ast,
1814 const GVariantType *type,
1815 GError **error)
1816 {
1817 Number *number = (Number *) ast;
1818 const gchar *token;
1819 gboolean negative;
1820 gboolean floating;
1821 guint64 abs_val;
1822 gdouble dbl_val;
1823 gchar *end;
1824  
1825 token = number->token;
1826  
1827 if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
1828 {
1829 floating = TRUE;
1830  
1831 errno = 0;
1832 dbl_val = g_ascii_strtod (token, &end);
1833 if (dbl_val != 0.0 && errno == ERANGE)
1834 {
1835 ast_set_error (ast, error, NULL,
1836 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1837 "number too big for any type");
1838 return NULL;
1839 }
1840  
1841 /* silence uninitialised warnings... */
1842 negative = FALSE;
1843 abs_val = 0;
1844 }
1845 else
1846 {
1847 floating = FALSE;
1848 negative = token[0] == '-';
1849 if (token[0] == '-')
1850 token++;
1851  
1852 errno = 0;
1853 abs_val = g_ascii_strtoull (token, &end, 0);
1854 if (abs_val == G_MAXUINT64 && errno == ERANGE)
1855 {
1856 ast_set_error (ast, error, NULL,
1857 G_VARIANT_PARSE_ERROR_NUMBER_TOO_BIG,
1858 "integer too big for any type");
1859 return NULL;
1860 }
1861  
1862 if (abs_val == 0)
1863 negative = FALSE;
1864  
1865 /* silence uninitialised warning... */
1866 dbl_val = 0.0;
1867 }
1868  
1869 if (*end != '\0')
1870 {
1871 SourceRef ref;
1872  
1873 ref = ast->source_ref;
1874 ref.start += end - number->token;
1875 ref.end = ref.start + 1;
1876  
1877 parser_set_error (error, &ref, NULL,
1878 G_VARIANT_PARSE_ERROR_INVALID_CHARACTER,
1879 "invalid character in number");
1880 return NULL;
1881 }
1882  
1883 if (floating)
1884 return g_variant_new_double (dbl_val);
1885  
1886 switch (*g_variant_type_peek_string (type))
1887 {
1888 case 'y':
1889 if (negative || abs_val > G_MAXUINT8)
1890 return number_overflow (ast, type, error);
1891 return g_variant_new_byte (abs_val);
1892  
1893 case 'n':
1894 if (abs_val - negative > G_MAXINT16)
1895 return number_overflow (ast, type, error);
1896 return g_variant_new_int16 (negative ? -abs_val : abs_val);
1897  
1898 case 'q':
1899 if (negative || abs_val > G_MAXUINT16)
1900 return number_overflow (ast, type, error);
1901 return g_variant_new_uint16 (abs_val);
1902  
1903 case 'i':
1904 if (abs_val - negative > G_MAXINT32)
1905 return number_overflow (ast, type, error);
1906 return g_variant_new_int32 (negative ? -abs_val : abs_val);
1907  
1908 case 'u':
1909 if (negative || abs_val > G_MAXUINT32)
1910 return number_overflow (ast, type, error);
1911 return g_variant_new_uint32 (abs_val);
1912  
1913 case 'x':
1914 if (abs_val - negative > G_MAXINT64)
1915 return number_overflow (ast, type, error);
1916 return g_variant_new_int64 (negative ? -abs_val : abs_val);
1917  
1918 case 't':
1919 if (negative)
1920 return number_overflow (ast, type, error);
1921 return g_variant_new_uint64 (abs_val);
1922  
1923 case 'h':
1924 if (abs_val - negative > G_MAXINT32)
1925 return number_overflow (ast, type, error);
1926 return g_variant_new_handle (negative ? -abs_val : abs_val);
1927  
1928 default:
1929 return ast_type_error (ast, type, error);
1930 }
1931 }
1932  
1933 static void
1934 number_free (AST *ast)
1935 {
1936 Number *number = (Number *) ast;
1937  
1938 g_free (number->token);
1939 g_slice_free (Number, number);
1940 }
1941  
1942 static AST *
1943 number_parse (TokenStream *stream,
1944 va_list *app,
1945 GError **error)
1946 {
1947 static const ASTClass number_class = {
1948 number_get_pattern,
1949 maybe_wrapper, number_get_value,
1950 number_free
1951 };
1952 Number *number;
1953  
1954 number = g_slice_new (Number);
1955 number->ast.class = &number_class;
1956 number->token = token_stream_get (stream);
1957 token_stream_next (stream);
1958  
1959 return (AST *) number;
1960 }
1961  
1962 typedef struct
1963 {
1964 AST ast;
1965 gboolean value;
1966 } Boolean;
1967  
1968 static gchar *
1969 boolean_get_pattern (AST *ast,
1970 GError **error)
1971 {
1972 return g_strdup ("Mb");
1973 }
1974  
1975 static GVariant *
1976 boolean_get_value (AST *ast,
1977 const GVariantType *type,
1978 GError **error)
1979 {
1980 Boolean *boolean = (Boolean *) ast;
1981  
1982 if (!g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
1983 return ast_type_error (ast, type, error);
1984  
1985 return g_variant_new_boolean (boolean->value);
1986 }
1987  
1988 static void
1989 boolean_free (AST *ast)
1990 {
1991 Boolean *boolean = (Boolean *) ast;
1992  
1993 g_slice_free (Boolean, boolean);
1994 }
1995  
1996 static AST *
1997 boolean_new (gboolean value)
1998 {
1999 static const ASTClass boolean_class = {
2000 boolean_get_pattern,
2001 maybe_wrapper, boolean_get_value,
2002 boolean_free
2003 };
2004 Boolean *boolean;
2005  
2006 boolean = g_slice_new (Boolean);
2007 boolean->ast.class = &boolean_class;
2008 boolean->value = value;
2009  
2010 return (AST *) boolean;
2011 }
2012  
2013 typedef struct
2014 {
2015 AST ast;
2016  
2017 GVariant *value;
2018 } Positional;
2019  
2020 static gchar *
2021 positional_get_pattern (AST *ast,
2022 GError **error)
2023 {
2024 Positional *positional = (Positional *) ast;
2025  
2026 return g_strdup (g_variant_get_type_string (positional->value));
2027 }
2028  
2029 static GVariant *
2030 positional_get_value (AST *ast,
2031 const GVariantType *type,
2032 GError **error)
2033 {
2034 Positional *positional = (Positional *) ast;
2035 GVariant *value;
2036  
2037 g_assert (positional->value != NULL);
2038  
2039 if G_UNLIKELY (!g_variant_is_of_type (positional->value, type))
2040 return ast_type_error (ast, type, error);
2041  
2042 /* NOTE: if _get is called more than once then
2043 * things get messed up with respect to floating refs.
2044 *
2045 * fortunately, this function should only ever get called once.
2046 */
2047 g_assert (positional->value != NULL);
2048 value = positional->value;
2049 positional->value = NULL;
2050  
2051 return value;
2052 }
2053  
2054 static void
2055 positional_free (AST *ast)
2056 {
2057 Positional *positional = (Positional *) ast;
2058  
2059 /* if positional->value is set, just leave it.
2060 * memory management doesn't matter in case of programmer error.
2061 */
2062 g_slice_free (Positional, positional);
2063 }
2064  
2065 static AST *
2066 positional_parse (TokenStream *stream,
2067 va_list *app,
2068 GError **error)
2069 {
2070 static const ASTClass positional_class = {
2071 positional_get_pattern,
2072 positional_get_value, NULL,
2073 positional_free
2074 };
2075 Positional *positional;
2076 const gchar *endptr;
2077 gchar *token;
2078  
2079 token = token_stream_get (stream);
2080 g_assert (token[0] == '%');
2081  
2082 positional = g_slice_new (Positional);
2083 positional->ast.class = &positional_class;
2084 positional->value = g_variant_new_va (token + 1, &endptr, app);
2085  
2086 if (*endptr || positional->value == NULL)
2087 {
2088 token_stream_set_error (stream, error, TRUE,
2089 G_VARIANT_PARSE_ERROR_INVALID_FORMAT_STRING,
2090 "invalid GVariant format string");
2091 /* memory management doesn't matter in case of programmer error. */
2092 return NULL;
2093 }
2094  
2095 token_stream_next (stream);
2096 g_free (token);
2097  
2098 return (AST *) positional;
2099 }
2100  
2101 typedef struct
2102 {
2103 AST ast;
2104  
2105 GVariantType *type;
2106 AST *child;
2107 } TypeDecl;
2108  
2109 static gchar *
2110 typedecl_get_pattern (AST *ast,
2111 GError **error)
2112 {
2113 TypeDecl *decl = (TypeDecl *) ast;
2114  
2115 return g_variant_type_dup_string (decl->type);
2116 }
2117  
2118 static GVariant *
2119 typedecl_get_value (AST *ast,
2120 const GVariantType *type,
2121 GError **error)
2122 {
2123 TypeDecl *decl = (TypeDecl *) ast;
2124  
2125 return ast_get_value (decl->child, type, error);
2126 }
2127  
2128 static void
2129 typedecl_free (AST *ast)
2130 {
2131 TypeDecl *decl = (TypeDecl *) ast;
2132  
2133 ast_free (decl->child);
2134 g_variant_type_free (decl->type);
2135 g_slice_free (TypeDecl, decl);
2136 }
2137  
2138 static AST *
2139 typedecl_parse (TokenStream *stream,
2140 va_list *app,
2141 GError **error)
2142 {
2143 static const ASTClass typedecl_class = {
2144 typedecl_get_pattern,
2145 typedecl_get_value, NULL,
2146 typedecl_free
2147 };
2148 GVariantType *type;
2149 TypeDecl *decl;
2150 AST *child;
2151  
2152 if (token_stream_peek (stream, '@'))
2153 {
2154 gchar *token;
2155  
2156 token = token_stream_get (stream);
2157  
2158 if (!g_variant_type_string_is_valid (token + 1))
2159 {
2160 token_stream_set_error (stream, error, TRUE,
2161 G_VARIANT_PARSE_ERROR_INVALID_TYPE_STRING,
2162 "invalid type declaration");
2163 g_free (token);
2164  
2165 return NULL;
2166 }
2167  
2168 type = g_variant_type_new (token + 1);
2169  
2170 if (!g_variant_type_is_definite (type))
2171 {
2172 token_stream_set_error (stream, error, TRUE,
2173 G_VARIANT_PARSE_ERROR_DEFINITE_TYPE_EXPECTED,
2174 "type declarations must be definite");
2175 g_variant_type_free (type);
2176 g_free (token);
2177  
2178 return NULL;
2179 }
2180  
2181 token_stream_next (stream);
2182 g_free (token);
2183 }
2184 else
2185 {
2186 if (token_stream_consume (stream, "boolean"))
2187 type = g_variant_type_copy (G_VARIANT_TYPE_BOOLEAN);
2188  
2189 else if (token_stream_consume (stream, "byte"))
2190 type = g_variant_type_copy (G_VARIANT_TYPE_BYTE);
2191  
2192 else if (token_stream_consume (stream, "int16"))
2193 type = g_variant_type_copy (G_VARIANT_TYPE_INT16);
2194  
2195 else if (token_stream_consume (stream, "uint16"))
2196 type = g_variant_type_copy (G_VARIANT_TYPE_UINT16);
2197  
2198 else if (token_stream_consume (stream, "int32"))
2199 type = g_variant_type_copy (G_VARIANT_TYPE_INT32);
2200  
2201 else if (token_stream_consume (stream, "handle"))
2202 type = g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
2203  
2204 else if (token_stream_consume (stream, "uint32"))
2205 type = g_variant_type_copy (G_VARIANT_TYPE_UINT32);
2206  
2207 else if (token_stream_consume (stream, "int64"))
2208 type = g_variant_type_copy (G_VARIANT_TYPE_INT64);
2209  
2210 else if (token_stream_consume (stream, "uint64"))
2211 type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
2212  
2213 else if (token_stream_consume (stream, "double"))
2214 type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
2215  
2216 else if (token_stream_consume (stream, "string"))
2217 type = g_variant_type_copy (G_VARIANT_TYPE_STRING);
2218  
2219 else if (token_stream_consume (stream, "objectpath"))
2220 type = g_variant_type_copy (G_VARIANT_TYPE_OBJECT_PATH);
2221  
2222 else if (token_stream_consume (stream, "signature"))
2223 type = g_variant_type_copy (G_VARIANT_TYPE_SIGNATURE);
2224  
2225 else
2226 {
2227 token_stream_set_error (stream, error, TRUE,
2228 G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD,
2229 "unknown keyword");
2230 return NULL;
2231 }
2232 }
2233  
2234 if ((child = parse (stream, app, error)) == NULL)
2235 {
2236 g_variant_type_free (type);
2237 return NULL;
2238 }
2239  
2240 decl = g_slice_new (TypeDecl);
2241 decl->ast.class = &typedecl_class;
2242 decl->type = type;
2243 decl->child = child;
2244  
2245 return (AST *) decl;
2246 }
2247  
2248 static AST *
2249 parse (TokenStream *stream,
2250 va_list *app,
2251 GError **error)
2252 {
2253 SourceRef source_ref;
2254 AST *result;
2255  
2256 token_stream_prepare (stream);
2257 token_stream_start_ref (stream, &source_ref);
2258  
2259 if (token_stream_peek (stream, '['))
2260 result = array_parse (stream, app, error);
2261  
2262 else if (token_stream_peek (stream, '('))
2263 result = tuple_parse (stream, app, error);
2264  
2265 else if (token_stream_peek (stream, '<'))
2266 result = variant_parse (stream, app, error);
2267  
2268 else if (token_stream_peek (stream, '{'))
2269 result = dictionary_parse (stream, app, error);
2270  
2271 else if (app && token_stream_peek (stream, '%'))
2272 result = positional_parse (stream, app, error);
2273  
2274 else if (token_stream_consume (stream, "true"))
2275 result = boolean_new (TRUE);
2276  
2277 else if (token_stream_consume (stream, "false"))
2278 result = boolean_new (FALSE);
2279  
2280 else if (token_stream_is_numeric (stream) ||
2281 token_stream_peek_string (stream, "inf") ||
2282 token_stream_peek_string (stream, "nan"))
2283 result = number_parse (stream, app, error);
2284  
2285 else if (token_stream_peek (stream, 'n') ||
2286 token_stream_peek (stream, 'j'))
2287 result = maybe_parse (stream, app, error);
2288  
2289 else if (token_stream_peek (stream, '@') ||
2290 token_stream_is_keyword (stream))
2291 result = typedecl_parse (stream, app, error);
2292  
2293 else if (token_stream_peek (stream, '\'') ||
2294 token_stream_peek (stream, '"'))
2295 result = string_parse (stream, app, error);
2296  
2297 else if (token_stream_peek2 (stream, 'b', '\'') ||
2298 token_stream_peek2 (stream, 'b', '"'))
2299 result = bytestring_parse (stream, app, error);
2300  
2301 else
2302 {
2303 token_stream_set_error (stream, error, FALSE,
2304 G_VARIANT_PARSE_ERROR_VALUE_EXPECTED,
2305 "expected value");
2306 return NULL;
2307 }
2308  
2309 if (result != NULL)
2310 {
2311 token_stream_end_ref (stream, &source_ref);
2312 result->source_ref = source_ref;
2313 }
2314  
2315 return result;
2316 }
2317  
2318 /**
2319 * g_variant_parse:
2320 * @type: (allow-none): a #GVariantType, or %NULL
2321 * @text: a string containing a GVariant in text form
2322 * @limit: (allow-none): a pointer to the end of @text, or %NULL
2323 * @endptr: (allow-none): a location to store the end pointer, or %NULL
2324 * @error: (allow-none): a pointer to a %NULL #GError pointer, or %NULL
2325 *
2326 * Parses a #GVariant from a text representation.
2327 *
2328 * A single #GVariant is parsed from the content of @text.
2329 *
2330 * The format is described [here][gvariant-text].
2331 *
2332 * The memory at @limit will never be accessed and the parser behaves as
2333 * if the character at @limit is the nul terminator. This has the
2334 * effect of bounding @text.
2335 *
2336 * If @endptr is non-%NULL then @text is permitted to contain data
2337 * following the value that this function parses and @endptr will be
2338 * updated to point to the first character past the end of the text
2339 * parsed by this function. If @endptr is %NULL and there is extra data
2340 * then an error is returned.
2341 *
2342 * If @type is non-%NULL then the value will be parsed to have that
2343 * type. This may result in additional parse errors (in the case that
2344 * the parsed value doesn't fit the type) but may also result in fewer
2345 * errors (in the case that the type would have been ambiguous, such as
2346 * with empty arrays).
2347 *
2348 * In the event that the parsing is successful, the resulting #GVariant
2349 * is returned. It is never floating, and must be freed with
2350 * g_variant_unref().
2351 *
2352 * In case of any error, %NULL will be returned. If @error is non-%NULL
2353 * then it will be set to reflect the error that occurred.
2354 *
2355 * Officially, the language understood by the parser is "any string
2356 * produced by g_variant_print()".
2357 *
2358 * Returns: a non-floating reference to a #GVariant, or %NULL
2359 **/
2360 GVariant *
2361 g_variant_parse (const GVariantType *type,
2362 const gchar *text,
2363 const gchar *limit,
2364 const gchar **endptr,
2365 GError **error)
2366 {
2367 TokenStream stream = { 0, };
2368 GVariant *result = NULL;
2369 AST *ast;
2370  
2371 g_return_val_if_fail (text != NULL, NULL);
2372 g_return_val_if_fail (text == limit || text != NULL, NULL);
2373  
2374 stream.start = text;
2375 stream.stream = text;
2376 stream.end = limit;
2377  
2378 if ((ast = parse (&stream, NULL, error)))
2379 {
2380 if (type == NULL)
2381 result = ast_resolve (ast, error);
2382 else
2383 result = ast_get_value (ast, type, error);
2384  
2385 if (result != NULL)
2386 {
2387 g_variant_ref_sink (result);
2388  
2389 if (endptr == NULL)
2390 {
2391 while (stream.stream != limit &&
2392 g_ascii_isspace (*stream.stream))
2393 stream.stream++;
2394  
2395 if (stream.stream != limit && *stream.stream != '\0')
2396 {
2397 SourceRef ref = { stream.stream - text,
2398 stream.stream - text };
2399  
2400 parser_set_error (error, &ref, NULL,
2401 G_VARIANT_PARSE_ERROR_INPUT_NOT_AT_END,
2402 "expected end of input");
2403 g_variant_unref (result);
2404  
2405 result = NULL;
2406 }
2407 }
2408 else
2409 *endptr = stream.stream;
2410 }
2411  
2412 ast_free (ast);
2413 }
2414  
2415 return result;
2416 }
2417  
2418 /**
2419 * g_variant_new_parsed_va:
2420 * @format: a text format #GVariant
2421 * @app: a pointer to a #va_list
2422 *
2423 * Parses @format and returns the result.
2424 *
2425 * This is the version of g_variant_new_parsed() intended to be used
2426 * from libraries.
2427 *
2428 * The return value will be floating if it was a newly created GVariant
2429 * instance. In the case that @format simply specified the collection
2430 * of a #GVariant pointer (eg: @format was "%*") then the collected
2431 * #GVariant pointer will be returned unmodified, without adding any
2432 * additional references.
2433 *
2434 * Note that the arguments in @app must be of the correct width for their types
2435 * specified in @format when collected into the #va_list. See
2436 * the [GVariant varargs documentation][gvariant-varargs].
2437 *
2438 * In order to behave correctly in all cases it is necessary for the
2439 * calling function to g_variant_ref_sink() the return result before
2440 * returning control to the user that originally provided the pointer.
2441 * At this point, the caller will have their own full reference to the
2442 * result. This can also be done by adding the result to a container,
2443 * or by passing it to another g_variant_new() call.
2444 *
2445 * Returns: a new, usually floating, #GVariant
2446 **/
2447 GVariant *
2448 g_variant_new_parsed_va (const gchar *format,
2449 va_list *app)
2450 {
2451 TokenStream stream = { 0, };
2452 GVariant *result = NULL;
2453 GError *error = NULL;
2454 AST *ast;
2455  
2456 g_return_val_if_fail (format != NULL, NULL);
2457 g_return_val_if_fail (app != NULL, NULL);
2458  
2459 stream.start = format;
2460 stream.stream = format;
2461 stream.end = NULL;
2462  
2463 if ((ast = parse (&stream, app, &error)))
2464 {
2465 result = ast_resolve (ast, &error);
2466 ast_free (ast);
2467 }
2468  
2469 if (result == NULL)
2470 g_error ("g_variant_new_parsed: %s", error->message);
2471  
2472 if (*stream.stream)
2473 g_error ("g_variant_new_parsed: trailing text after value");
2474  
2475 return result;
2476 }
2477  
2478 /**
2479 * g_variant_new_parsed:
2480 * @format: a text format #GVariant
2481 * @...: arguments as per @format
2482 *
2483 * Parses @format and returns the result.
2484 *
2485 * @format must be a text format #GVariant with one extension: at any
2486 * point that a value may appear in the text, a '%' character followed
2487 * by a GVariant format string (as per g_variant_new()) may appear. In
2488 * that case, the same arguments are collected from the argument list as
2489 * g_variant_new() would have collected.
2490 *
2491 * Note that the arguments must be of the correct width for their types
2492 * specified in @format. This can be achieved by casting them. See
2493 * the [GVariant varargs documentation][gvariant-varargs].
2494 *
2495 * Consider this simple example:
2496 * |[<!-- language="C" -->
2497 * g_variant_new_parsed ("[('one', 1), ('two', %i), (%s, 3)]", 2, "three");
2498 * ]|
2499 *
2500 * In the example, the variable argument parameters are collected and
2501 * filled in as if they were part of the original string to produce the
2502 * result of
2503 * |[<!-- language="C" -->
2504 * [('one', 1), ('two', 2), ('three', 3)]
2505 * ]|
2506 *
2507 * This function is intended only to be used with @format as a string
2508 * literal. Any parse error is fatal to the calling process. If you
2509 * want to parse data from untrusted sources, use g_variant_parse().
2510 *
2511 * You may not use this function to return, unmodified, a single
2512 * #GVariant pointer from the argument list. ie: @format may not solely
2513 * be anything along the lines of "%*", "%?", "\%r", or anything starting
2514 * with "%@".
2515 *
2516 * Returns: a new floating #GVariant instance
2517 **/
2518 GVariant *
2519 g_variant_new_parsed (const gchar *format,
2520 ...)
2521 {
2522 GVariant *result;
2523 va_list ap;
2524  
2525 va_start (ap, format);
2526 result = g_variant_new_parsed_va (format, &ap);
2527 va_end (ap);
2528  
2529 return result;
2530 }
2531  
2532 /**
2533 * g_variant_builder_add_parsed:
2534 * @builder: a #GVariantBuilder
2535 * @format: a text format #GVariant
2536 * @...: arguments as per @format
2537 *
2538 * Adds to a #GVariantBuilder.
2539 *
2540 * This call is a convenience wrapper that is exactly equivalent to
2541 * calling g_variant_new_parsed() followed by
2542 * g_variant_builder_add_value().
2543 *
2544 * Note that the arguments must be of the correct width for their types
2545 * specified in @format_string. This can be achieved by casting them. See
2546 * the [GVariant varargs documentation][gvariant-varargs].
2547 *
2548 * This function might be used as follows:
2549 *
2550 * |[<!-- language="C" -->
2551 * GVariant *
2552 * make_pointless_dictionary (void)
2553 * {
2554 * GVariantBuilder builder;
2555 * int i;
2556 *
2557 * g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
2558 * g_variant_builder_add_parsed (&builder, "{'width', <%i>}", 600);
2559 * g_variant_builder_add_parsed (&builder, "{'title', <%s>}", "foo");
2560 * g_variant_builder_add_parsed (&builder, "{'transparency', <0.5>}");
2561 * return g_variant_builder_end (&builder);
2562 * }
2563 * ]|
2564 *
2565 * Since: 2.26
2566 */
2567 void
2568 g_variant_builder_add_parsed (GVariantBuilder *builder,
2569 const gchar *format,
2570 ...)
2571 {
2572 va_list ap;
2573  
2574 va_start (ap, format);
2575 g_variant_builder_add_value (builder, g_variant_new_parsed_va (format, &ap));
2576 va_end (ap);
2577 }
2578  
2579 static gboolean
2580 parse_num (const gchar *num,
2581 const gchar *limit,
2582 gint *result)
2583 {
2584 gchar *endptr;
2585 gint64 bignum;
2586  
2587 bignum = g_ascii_strtoll (num, &endptr, 10);
2588  
2589 if (endptr != limit)
2590 return FALSE;
2591  
2592 if (bignum < 0 || bignum > G_MAXINT)
2593 return FALSE;
2594  
2595 *result = bignum;
2596  
2597 return TRUE;
2598 }
2599  
2600 static void
2601 add_last_line (GString *err,
2602 const gchar *str)
2603 {
2604 const gchar *last_nl;
2605 gchar *chomped;
2606 gint i;
2607  
2608 /* This is an error at the end of input. If we have a file
2609 * with newlines, that's probably the empty string after the
2610 * last newline, which is not the most useful thing to show.
2611 *
2612 * Instead, show the last line of non-whitespace that we have
2613 * and put the pointer at the end of it.
2614 */
2615 chomped = g_strchomp (g_strdup (str));
2616 last_nl = strrchr (chomped, '\n');
2617 if (last_nl == NULL)
2618 last_nl = chomped;
2619 else
2620 last_nl++;
2621  
2622 /* Print the last line like so:
2623 *
2624 * [1, 2, 3,
2625 * ^
2626 */
2627 g_string_append (err, " ");
2628 if (last_nl[0])
2629 g_string_append (err, last_nl);
2630 else
2631 g_string_append (err, "(empty input)");
2632 g_string_append (err, "\n ");
2633 for (i = 0; last_nl[i]; i++)
2634 g_string_append_c (err, ' ');
2635 g_string_append (err, "^\n");
2636 g_free (chomped);
2637 }
2638  
2639 static void
2640 add_lines_from_range (GString *err,
2641 const gchar *str,
2642 const gchar *start1,
2643 const gchar *end1,
2644 const gchar *start2,
2645 const gchar *end2)
2646 {
2647 while (str < end1 || str < end2)
2648 {
2649 const gchar *nl;
2650  
2651 nl = str + strcspn (str, "\n");
2652  
2653 if ((start1 < nl && str < end1) || (start2 < nl && str < end2))
2654 {
2655 const gchar *s;
2656  
2657 /* We're going to print this line */
2658 g_string_append (err, " ");
2659 g_string_append_len (err, str, nl - str);
2660 g_string_append (err, "\n ");
2661  
2662 /* And add underlines... */
2663 for (s = str; s < nl; s++)
2664 {
2665 if ((start1 <= s && s < end1) || (start2 <= s && s < end2))
2666 g_string_append_c (err, '^');
2667 else
2668 g_string_append_c (err, ' ');
2669 }
2670 g_string_append_c (err, '\n');
2671 }
2672  
2673 if (!*nl)
2674 break;
2675  
2676 str = nl + 1;
2677 }
2678 }
2679  
2680 /**
2681 * g_variant_parse_error_print_context:
2682 * @error: a #GError from the #GVariantParseError domain
2683 * @source_str: the string that was given to the parser
2684 *
2685 * Pretty-prints a message showing the context of a #GVariant parse
2686 * error within the string for which parsing was attempted.
2687 *
2688 * The resulting string is suitable for output to the console or other
2689 * monospace media where newlines are treated in the usual way.
2690 *
2691 * The message will typically look something like one of the following:
2692 *
2693 * |[
2694 * unterminated string constant:
2695 * (1, 2, 3, 'abc
2696 * ^^^^
2697 * ]|
2698 *
2699 * or
2700 *
2701 * |[
2702 * unable to find a common type:
2703 * [1, 2, 3, 'str']
2704 * ^ ^^^^^
2705 * ]|
2706 *
2707 * The format of the message may change in a future version.
2708 *
2709 * @error must have come from a failed attempt to g_variant_parse() and
2710 * @source_str must be exactly the same string that caused the error.
2711 * If @source_str was not nul-terminated when you passed it to
2712 * g_variant_parse() then you must add nul termination before using this
2713 * function.
2714 *
2715 * Returns: (transfer full): the printed message
2716 *
2717 * Since: 2.40
2718 **/
2719 gchar *
2720 g_variant_parse_error_print_context (GError *error,
2721 const gchar *source_str)
2722 {
2723 const gchar *colon, *dash, *comma;
2724 gboolean success = FALSE;
2725 GString *err;
2726  
2727 g_return_val_if_fail (error->domain == G_VARIANT_PARSE_ERROR, FALSE);
2728  
2729 /* We can only have a limited number of possible types of ranges
2730 * emitted from the parser:
2731 *
2732 * - a: -- usually errors from the tokeniser (eof, invalid char, etc.)
2733 * - a-b: -- usually errors from handling one single token
2734 * - a-b,c-d: -- errors involving two tokens (ie: type inferencing)
2735 *
2736 * We never see, for example "a,c".
2737 */
2738  
2739 colon = strchr (error->message, ':');
2740 dash = strchr (error->message, '-');
2741 comma = strchr (error->message, ',');
2742  
2743 if (!colon)
2744 return NULL;
2745  
2746 err = g_string_new (colon + 1);
2747 g_string_append (err, ":\n");
2748  
2749 if (dash == NULL || colon < dash)
2750 {
2751 gint point;
2752  
2753 /* we have a single point */
2754 if (!parse_num (error->message, colon, &point))
2755 goto out;
2756  
2757 if (point >= strlen (source_str))
2758 /* the error is at the end of the input */
2759 add_last_line (err, source_str);
2760 else
2761 /* otherwise just treat it as a error at a thin range */
2762 add_lines_from_range (err, source_str, source_str + point, source_str + point + 1, NULL, NULL);
2763 }
2764 else
2765 {
2766 /* We have one or two ranges... */
2767 if (comma && comma < colon)
2768 {
2769 gint start1, end1, start2, end2;
2770 const gchar *dash2;
2771  
2772 /* Two ranges */
2773 dash2 = strchr (comma, '-');
2774  
2775 if (!parse_num (error->message, dash, &start1) || !parse_num (dash + 1, comma, &end1) ||
2776 !parse_num (comma + 1, dash2, &start2) || !parse_num (dash2 + 1, colon, &end2))
2777 goto out;
2778  
2779 add_lines_from_range (err, source_str,
2780 source_str + start1, source_str + end1,
2781 source_str + start2, source_str + end2);
2782 }
2783 else
2784 {
2785 gint start, end;
2786  
2787 /* One range */
2788 if (!parse_num (error->message, dash, &start) || !parse_num (dash + 1, colon, &end))
2789 goto out;
2790  
2791 add_lines_from_range (err, source_str, source_str + start, source_str + end, NULL, NULL);
2792 }
2793 }
2794  
2795 success = TRUE;
2796  
2797 out:
2798 return g_string_free (err, !success);
2799 }