Add 3 new restrictions to the schema compiler
[platform/upstream/glib.git] / gio / glib-compile-schemas.c
1 /*
2  * Copyright © 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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 /* Prologue {{{1 */
23 #define _GNU_SOURCE
24 #include "config.h"
25
26 #include <gstdio.h>
27 #include <locale.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdio.h>
31
32 #include <gi18n.h>
33
34 #include "gvdb/gvdb-builder.h"
35 #include "strinfo.c"
36
37 /* Handling of <enum> {{{1 */
38 typedef struct
39 {
40   GString *strinfo;
41
42   gboolean is_flags;
43 } EnumState;
44
45 static void
46 enum_state_free (gpointer data)
47 {
48   EnumState *state = data;
49
50   g_string_free (state->strinfo, TRUE);
51   g_slice_free (EnumState, state);
52 }
53
54 EnumState *
55 enum_state_new (gboolean is_flags)
56 {
57   EnumState *state;
58
59   state = g_slice_new (EnumState);
60   state->strinfo = g_string_new (NULL);
61   state->is_flags = is_flags;
62
63   return state;
64 }
65
66 static void
67 enum_state_add_value (EnumState    *state,
68                       const gchar  *nick,
69                       const gchar  *valuestr,
70                       GError      **error)
71 {
72   gint64 value;
73   gchar *end;
74
75   if (nick[0] == '\0' || nick[1] == '\0')
76     {
77       g_set_error (error, G_MARKUP_ERROR,
78                    G_MARKUP_ERROR_INVALID_CONTENT,
79                    "nick must be a minimum of 2 characters");
80       return;
81     }
82
83   value = g_ascii_strtoll (valuestr, &end, 0);
84   if (*end || state->is_flags ?
85                 (value > G_MAXUINT32 || value < 0) :
86                 (value > G_MAXINT32 || value < G_MININT32))
87     {
88       g_set_error (error, G_MARKUP_ERROR,
89                    G_MARKUP_ERROR_INVALID_CONTENT,
90                    "invalid numeric value");
91       return;
92     }
93
94   if (strinfo_builder_contains (state->strinfo, nick))
95     {
96       g_set_error (error, G_MARKUP_ERROR,
97                    G_MARKUP_ERROR_INVALID_CONTENT,
98                    "<value nick='%s'/> already specified", nick);
99       return;
100     }
101
102   if (strinfo_builder_contains_value (state->strinfo, value))
103     {
104       g_set_error (error, G_MARKUP_ERROR,
105                    G_MARKUP_ERROR_INVALID_CONTENT,
106                    "value='%s' already specified", valuestr);
107       return;
108     }
109
110   if (state->is_flags && (value & (value - 1)))
111     {
112       g_set_error (error, G_MARKUP_ERROR,
113                    G_MARKUP_ERROR_INVALID_CONTENT,
114                    "flags values must have at most 1 bit set");
115       return;
116     }
117
118   /* Since we reject exact duplicates of value='' and we only allow one
119    * bit to be set, it's not possible to have overlaps.
120    *
121    * If we loosen the one-bit-set restriction we need an overlap check.
122    */
123
124
125   strinfo_builder_append_item (state->strinfo, nick, value);
126 }
127
128 static void
129 enum_state_end (EnumState **state_ptr,
130                 GError    **error)
131 {
132   EnumState *state;
133
134   state = *state_ptr;
135   *state_ptr = NULL;
136
137   if (state->strinfo->len == 0)
138     g_set_error_literal (error,
139                          G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
140                          "<enum> must contain at least one <value>");
141 }
142
143 /* Handling of <key> {{{1 */
144 typedef struct
145 {
146   /* for <child>, @child_schema will be set.
147    * for <key>, everything else will be set.
148    */
149   gchar        *child_schema;
150
151
152   GVariantType *type;
153   gboolean      have_gettext_domain;
154
155   gchar         l10n;
156   gchar        *l10n_context;
157   GString      *unparsed_default_value;
158   GVariant     *default_value;
159
160   GString      *strinfo;
161   gboolean      is_enum;
162   gboolean      is_flags;
163
164   GVariant     *minimum;
165   GVariant     *maximum;
166
167   gboolean      has_choices;
168   gboolean      has_aliases;
169   gboolean      is_override;
170
171   gboolean      checked;
172   GVariant     *serialised;
173 } KeyState;
174
175 static KeyState *
176 key_state_new (const gchar *type_string,
177                const gchar *gettext_domain,
178                gboolean     is_enum,
179                gboolean     is_flags,
180                GString     *strinfo)
181 {
182   KeyState *state;
183
184   state = g_slice_new0 (KeyState);
185   state->type = g_variant_type_new (type_string);
186   state->have_gettext_domain = gettext_domain != NULL;
187   state->is_enum = is_enum;
188   state->is_flags = is_flags;
189
190   if (strinfo)
191     state->strinfo = g_string_new_len (strinfo->str, strinfo->len);
192   else
193     state->strinfo = g_string_new (NULL);
194
195   return state;
196 }
197
198 static KeyState *
199 key_state_override (KeyState    *state,
200                     const gchar *gettext_domain)
201 {
202   KeyState *copy;
203
204   copy = g_slice_new0 (KeyState);
205   copy->type = g_variant_type_copy (state->type);
206   copy->have_gettext_domain = gettext_domain != NULL;
207   copy->strinfo = g_string_new_len (state->strinfo->str,
208                                     state->strinfo->len);
209   copy->is_enum = state->is_enum;
210   copy->is_flags = state->is_flags;
211   copy->is_override = TRUE;
212
213   if (state->minimum)
214     {
215       copy->minimum = g_variant_ref (state->minimum);
216       copy->maximum = g_variant_ref (state->maximum);
217     }
218
219   return copy;
220 }
221
222 static KeyState *
223 key_state_new_child (const gchar *child_schema)
224 {
225   KeyState *state;
226
227   state = g_slice_new0 (KeyState);
228   state->child_schema = g_strdup (child_schema);
229
230   return state;
231 }
232
233 static gboolean
234 is_valid_choices (GVariant *variant,
235                   GString  *strinfo)
236 {
237   switch (g_variant_classify (variant))
238     {
239       case G_VARIANT_CLASS_MAYBE:
240       case G_VARIANT_CLASS_ARRAY:
241         {
242           gboolean valid = TRUE;
243           GVariantIter iter;
244
245           g_variant_iter_init (&iter, variant);
246
247           while (valid && (variant = g_variant_iter_next_value (&iter)))
248             {
249               valid = is_valid_choices (variant, strinfo);
250               g_variant_unref (variant);
251             }
252
253           return valid;
254         }
255
256       case G_VARIANT_CLASS_STRING:
257         return strinfo_is_string_valid ((const guint32 *) strinfo->str,
258                                         strinfo->len / 4,
259                                         g_variant_get_string (variant, NULL));
260
261       default:
262         g_assert_not_reached ();
263     }
264 }
265
266
267 /* Gets called at </default> </choices> or <range/> to check for
268  * validity of the default value so that any inconsistency is
269  * reported as soon as it is encountered.
270  */
271 static void
272 key_state_check_range (KeyState  *state,
273                        GError   **error)
274 {
275   if (state->default_value)
276     {
277       const gchar *tag;
278
279       tag = state->is_override ? "override" : "default";
280
281       if (state->minimum)
282         {
283           if (g_variant_compare (state->default_value, state->minimum) < 0 ||
284               g_variant_compare (state->default_value, state->maximum) > 0)
285             {
286               g_set_error (error, G_MARKUP_ERROR,
287                            G_MARKUP_ERROR_INVALID_CONTENT,
288                            "<%s> is not contained in "
289                            "the specified range", tag);
290             }
291         }
292
293       else if (state->strinfo->len)
294         {
295           if (!is_valid_choices (state->default_value, state->strinfo))
296             {
297               if (state->is_enum)
298                 g_set_error (error, G_MARKUP_ERROR,
299                              G_MARKUP_ERROR_INVALID_CONTENT,
300                              "<%s> is not a valid member of "
301                              "the specified enumerated type", tag);
302
303               else if (state->is_flags)
304                 g_set_error (error, G_MARKUP_ERROR,
305                              G_MARKUP_ERROR_INVALID_CONTENT,
306                              "<%s> contains string not in the "
307                              "specified flags type", tag);
308
309               else
310                 g_set_error (error, G_MARKUP_ERROR,
311                              G_MARKUP_ERROR_INVALID_CONTENT,
312                              "<%s> contains string not in "
313                              "<choices>", tag);
314             }
315         }
316     }
317 }
318
319 static void
320 key_state_set_range (KeyState     *state,
321                      const gchar  *min_str,
322                      const gchar  *max_str,
323                      GError      **error)
324 {
325   if (state->minimum)
326     {
327       g_set_error_literal (error, G_MARKUP_ERROR,
328                            G_MARKUP_ERROR_INVALID_CONTENT,
329                            "<range/> already specified for this key");
330       return;
331     }
332
333   if (strchr ("ynqiuxtd", *(char *) state->type) == NULL)
334     {
335       gchar *type = g_variant_type_dup_string (state->type);
336       g_set_error (error, G_MARKUP_ERROR,
337                   G_MARKUP_ERROR_INVALID_CONTENT,
338                   "<range> not allowed for keys of type '%s'", type);
339       g_free (type);
340       return;
341     }
342
343   state->minimum = g_variant_parse (state->type, min_str, NULL, NULL, error);
344   if (state->minimum == NULL)
345     return;
346
347   state->maximum = g_variant_parse (state->type, max_str, NULL, NULL, error);
348   if (state->maximum == NULL)
349     return;
350
351   if (g_variant_compare (state->minimum, state->maximum) > 0)
352     {
353       g_set_error (error, G_MARKUP_ERROR,
354                    G_MARKUP_ERROR_INVALID_CONTENT,
355                    "<range> specified minimum is greater than maxmimum");
356       return;
357     }
358
359   key_state_check_range (state, error);
360 }
361
362 static GString *
363 key_state_start_default (KeyState     *state,
364                          const gchar  *l10n,
365                          const gchar  *context,
366                          GError      **error)
367 {
368   if (l10n != NULL)
369     {
370       if (strcmp (l10n, "messages") == 0)
371         state->l10n = 'm';
372
373       else if (strcmp (l10n, "time") == 0)
374         state->l10n = 't';
375
376       else
377         {
378           g_set_error (error, G_MARKUP_ERROR,
379                        G_MARKUP_ERROR_INVALID_CONTENT,
380                        "unsupported l10n category: %s", l10n);
381           return NULL;
382         }
383
384       if (!state->have_gettext_domain)
385         {
386           g_set_error_literal (error, G_MARKUP_ERROR,
387                                G_MARKUP_ERROR_INVALID_CONTENT,
388                                "l10n requested, but no "
389                                "gettext domain given");
390           return NULL;
391         }
392
393       state->l10n_context = g_strdup (context);
394     }
395
396   else if (context != NULL)
397     {
398       g_set_error_literal (error, G_MARKUP_ERROR,
399                            G_MARKUP_ERROR_INVALID_CONTENT,
400                            "translation context given for "
401                            " value without l10n enabled");
402       return NULL;
403     }
404
405   return g_string_new (NULL);
406 }
407
408 static void
409 key_state_end_default (KeyState  *state,
410                        GString  **string,
411                        GError   **error)
412 {
413   state->unparsed_default_value = *string;
414   *string = NULL;
415
416   state->default_value = g_variant_parse (state->type,
417                                           state->unparsed_default_value->str,
418                                           NULL, NULL, error);
419   key_state_check_range (state, error);
420 }
421
422 static void
423 key_state_start_choices (KeyState  *state,
424                          GError   **error)
425 {
426   const GVariantType *type = state->type;
427
428   if (state->is_enum)
429     {
430       g_set_error_literal (error, G_MARKUP_ERROR,
431                            G_MARKUP_ERROR_INVALID_CONTENT,
432                            "<choices> can not be specified for keys "
433                            "tagged as having an enumerated type");
434       return;
435     }
436
437   if (state->has_choices)
438     {
439       g_set_error_literal (error, G_MARKUP_ERROR,
440                            G_MARKUP_ERROR_INVALID_CONTENT,
441                            "<choices> already specified for this key");
442       return;
443     }
444
445   while (g_variant_type_is_maybe (type) || g_variant_type_is_array (type))
446     type = g_variant_type_element (type);
447
448   if (!g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
449     {
450       gchar *type_string = g_variant_type_dup_string (state->type);
451       g_set_error (error, G_MARKUP_ERROR,
452                    G_MARKUP_ERROR_INVALID_CONTENT,
453                    "<choices> not allowed for keys of type '%s'",
454                    type_string);
455       g_free (type_string);
456       return;
457     }
458 }
459
460 static void
461 key_state_add_choice (KeyState     *state,
462                       const gchar  *choice,
463                       GError      **error)
464 {
465   if (strinfo_builder_contains (state->strinfo, choice))
466     {
467       g_set_error (error, G_MARKUP_ERROR,
468                    G_MARKUP_ERROR_INVALID_CONTENT,
469                    "<choice value='%s'/> already given", choice);
470       return;
471     }
472
473   strinfo_builder_append_item (state->strinfo, choice, 0);
474   state->has_choices = TRUE;
475 }
476
477 static void
478 key_state_end_choices (KeyState  *state,
479                        GError   **error)
480 {
481   if (!state->has_choices)
482     {
483       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
484                    "<choices> must contain at least one <choice>");
485       return;
486     }
487
488   key_state_check_range (state, error);
489 }
490
491 static void
492 key_state_start_aliases (KeyState  *state,
493                          GError   **error)
494 {
495   if (state->has_aliases)
496     g_set_error_literal (error, G_MARKUP_ERROR,
497                          G_MARKUP_ERROR_INVALID_CONTENT,
498                          "<aliases> already specified for this key");
499
500   if (!state->is_flags && !state->is_enum && !state->has_choices)
501     g_set_error_literal (error, G_MARKUP_ERROR,
502                          G_MARKUP_ERROR_INVALID_CONTENT,
503                          "<aliases> can only be specified for keys with "
504                          "enumerated or flags types or after <choices>");
505 }
506
507 static void
508 key_state_add_alias (KeyState     *state,
509                      const gchar  *alias,
510                      const gchar  *target,
511                      GError      **error)
512 {
513   if (strinfo_builder_contains (state->strinfo, alias))
514     {
515       if (strinfo_is_string_valid ((guint32 *) state->strinfo->str,
516                                    state->strinfo->len / 4,
517                                    alias))
518         {
519           if (state->is_enum)
520             g_set_error (error, G_MARKUP_ERROR,
521                          G_MARKUP_ERROR_INVALID_CONTENT,
522                          "<alias value='%s'/> given when '%s' is already "
523                          "a member of the enumerated type", alias, alias);
524
525           else
526             g_set_error (error, G_MARKUP_ERROR,
527                          G_MARKUP_ERROR_INVALID_CONTENT,
528                          "<alias value='%s'/> given when "
529                          "<choice value='%s'/> was already given",
530                          alias, alias);
531         }
532
533       else
534         g_set_error (error, G_MARKUP_ERROR,
535                      G_MARKUP_ERROR_INVALID_CONTENT,
536                      "<alias value='%s'/> already specified", alias);
537
538       return;
539     }
540
541   if (!strinfo_builder_append_alias (state->strinfo, alias, target))
542     {
543       g_set_error (error, G_MARKUP_ERROR,
544                    G_MARKUP_ERROR_INVALID_CONTENT,
545                    "alias target '%s' is not in %s", target,
546                    state->is_enum ? "enumerated type" : "<choices>");
547       return;
548     }
549
550   state->has_aliases = TRUE;
551 }
552
553 static void
554 key_state_end_aliases (KeyState  *state,
555                        GError   **error)
556 {
557   if (!state->has_aliases)
558     {
559       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
560                    "<aliases> must contain at least one <alias>");
561       return;
562     }
563 }
564
565 static gboolean
566 key_state_check (KeyState  *state,
567                  GError   **error)
568 {
569   if (state->checked)
570     return TRUE;
571
572   return state->checked = TRUE;
573 }
574
575 static GVariant *
576 key_state_serialise (KeyState *state)
577 {
578   if (state->serialised == NULL)
579     {
580       if (state->child_schema)
581         {
582           state->serialised = g_variant_new_string (state->child_schema);
583         }
584
585       else
586         {
587           GVariantBuilder builder;
588
589           g_assert (key_state_check (state, NULL));
590
591           g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
592
593           /* default value */
594           g_variant_builder_add_value (&builder, state->default_value);
595
596           /* translation */
597           if (state->l10n)
598             {
599               if (state->l10n_context)
600                 {
601                   gint len;
602
603                   /* Contextified messages are supported by prepending
604                    * the context, followed by '\004' to the start of the
605                    * message string.  We do that here to save GSettings
606                    * the work later on.
607                    */
608                   len = strlen (state->l10n_context);
609                   state->l10n_context[len] = '\004';
610                   g_string_prepend_len (state->unparsed_default_value,
611                                         state->l10n_context, len + 1);
612                   g_free (state->l10n_context);
613                   state->l10n_context = NULL;
614                 }
615
616               g_variant_builder_add (&builder, "(y(y&s))", 'l', state->l10n,
617                                      state->unparsed_default_value->str);
618               g_string_free (state->unparsed_default_value, TRUE);
619               state->unparsed_default_value = NULL;
620             }
621
622           /* choice, aliases, enums */
623           if (state->strinfo->len)
624             {
625               GVariant *array;
626               gpointer data;
627               gsize size;
628
629               data = state->strinfo->str;
630               size = state->strinfo->len;
631
632               array = g_variant_new_from_data (G_VARIANT_TYPE ("au"),
633                                                data, size, TRUE,
634                                                g_free, data);
635
636               g_string_free (state->strinfo, FALSE);
637               state->strinfo = NULL;
638
639               g_variant_builder_add (&builder, "(y@au)",
640                                      state->is_flags ? 'f' :
641                                      state->is_enum ? 'e' : 'c',
642                                      array);
643             }
644
645           /* range */
646           if (state->minimum || state->maximum)
647             g_variant_builder_add (&builder, "(y(**))", 'r',
648                                    state->minimum, state->maximum);
649
650           state->serialised = g_variant_builder_end (&builder);
651         }
652
653       g_variant_ref_sink (state->serialised);
654     }
655
656   return g_variant_ref (state->serialised);
657 }
658
659 static void
660 key_state_free (gpointer data)
661 {
662   KeyState *state = data;
663
664   if (state->type)
665     g_variant_type_free (state->type);
666
667   g_free (state->l10n_context);
668
669   if (state->unparsed_default_value)
670     g_string_free (state->unparsed_default_value, TRUE);
671
672   if (state->default_value)
673     g_variant_unref (state->default_value);
674
675   if (state->strinfo)
676     g_string_free (state->strinfo, TRUE);
677
678   if (state->minimum)
679     g_variant_unref (state->minimum);
680
681   if (state->maximum)
682     g_variant_unref (state->maximum);
683
684   if (state->serialised)
685     g_variant_unref (state->serialised);
686
687   g_slice_free (KeyState, state);
688 }
689
690 /* Key name validity {{{1 */
691 static gboolean allow_any_name = FALSE;
692
693 static gboolean
694 is_valid_keyname (const gchar  *key,
695                   GError      **error)
696 {
697   gint i;
698
699   if (key[0] == '\0')
700     {
701       g_set_error_literal (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
702                            _("empty names are not permitted"));
703       return FALSE;
704     }
705
706   if (allow_any_name)
707     return TRUE;
708
709   if (!g_ascii_islower (key[0]))
710     {
711       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
712                    _("invalid name '%s': names must begin "
713                      "with a lowercase letter"), key);
714       return FALSE;
715     }
716
717   for (i = 1; key[i]; i++)
718     {
719       if (key[i] != '-' &&
720           !g_ascii_islower (key[i]) &&
721           !g_ascii_isdigit (key[i]))
722         {
723           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
724                        _("invalid name '%s': invalid character '%c'; "
725                          "only lowercase letters, numbers and dash ('-') "
726                          "are permitted."), key, key[i]);
727           return FALSE;
728         }
729
730       if (key[i] == '-' && key[i + 1] == '-')
731         {
732           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
733                        _("invalid name '%s': two successive dashes ('--') "
734                          "are not permitted."), key);
735           return FALSE;
736         }
737     }
738
739   if (key[i - 1] == '-')
740     {
741       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
742                    _("invalid name '%s': the last character may not be a "
743                      "dash ('-')."), key);
744       return FALSE;
745     }
746
747   if (i > 32)
748     {
749       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
750                    _("invalid name '%s': maximum length is 32"), key);
751       return FALSE;
752     }
753
754   return TRUE;
755 }
756
757 /* Handling of <schema> {{{1 */
758 typedef struct _SchemaState SchemaState;
759 struct _SchemaState
760 {
761   SchemaState *extends;
762
763   gchar       *path;
764   gchar       *gettext_domain;
765   gchar       *extends_name;
766   gchar       *list_of;
767
768   GHashTable  *keys;
769 };
770
771 static SchemaState *
772 schema_state_new (const gchar  *path,
773                   const gchar  *gettext_domain,
774                   SchemaState  *extends,
775                   const gchar  *extends_name,
776                   const gchar  *list_of)
777 {
778   SchemaState *state;
779
780   state = g_slice_new (SchemaState);
781   state->path = g_strdup (path);
782   state->gettext_domain = g_strdup (gettext_domain);
783   state->extends = extends;
784   state->extends_name = g_strdup (extends_name);
785   state->list_of = g_strdup (list_of);
786   state->keys = g_hash_table_new_full (g_str_hash, g_str_equal,
787                                        g_free, key_state_free);
788
789   return state;
790 }
791
792 static void
793 schema_state_free (gpointer data)
794 {
795   SchemaState *state = data;
796
797   g_free (state->path);
798   g_free (state->gettext_domain);
799   g_hash_table_unref (state->keys);
800 }
801
802 static void
803 schema_state_add_child (SchemaState  *state,
804                         const gchar  *name,
805                         const gchar  *schema,
806                         GError      **error)
807 {
808   gchar *childname;
809
810   if (!is_valid_keyname (name, error))
811     return;
812
813   childname = g_strconcat (name, "/", NULL);
814
815   if (g_hash_table_lookup (state->keys, childname))
816     {
817       g_set_error (error, G_MARKUP_ERROR,
818                    G_MARKUP_ERROR_INVALID_CONTENT,
819                    _("<child name='%s'> already specified"), name);
820       return;
821     }
822
823   g_hash_table_insert (state->keys, childname,
824                        key_state_new_child (schema));
825 }
826
827 static KeyState *
828 schema_state_add_key (SchemaState  *state,
829                       GHashTable   *enum_table,
830                       GHashTable   *flags_table,
831                       const gchar  *name,
832                       const gchar  *type_string,
833                       const gchar  *enum_type,
834                       const gchar  *flags_type,
835                       GError      **error)
836 {
837   SchemaState *node;
838   GString *strinfo;
839   KeyState *key;
840
841   if (state->list_of)
842     {
843       g_set_error_literal (error, G_MARKUP_ERROR,
844                            G_MARKUP_ERROR_INVALID_CONTENT,
845                            _("can not add keys to a 'list-of' schema"));
846       return NULL;
847     }
848
849   if (!is_valid_keyname (name, error))
850     return NULL;
851
852   if (g_hash_table_lookup (state->keys, name))
853     {
854       g_set_error (error, G_MARKUP_ERROR,
855                    G_MARKUP_ERROR_INVALID_CONTENT,
856                    _("<key name='%s'> already specified"), name);
857       return NULL;
858     }
859
860   for (node = state; node; node = node->extends)
861     if (node->extends)
862       {
863         KeyState *shadow;
864
865         shadow = g_hash_table_lookup (node->extends->keys, name);
866
867         /* in case of <key> <override> <key> make sure we report the
868          * location of the original <key>, not the <override>.
869          */
870         if (shadow && !shadow->is_override)
871           {
872             g_set_error (error, G_MARKUP_ERROR,
873                          G_MARKUP_ERROR_INVALID_CONTENT,
874                          _("<key name='%s'> shadows <key name='%s'> in "
875                            "<schema id='%s'>; use <override> to modify value"),
876                          name, name, node->extends_name);
877             return NULL;
878           }
879       }
880
881   if ((type_string != NULL) + (enum_type != NULL) + (flags_type != NULL) != 1)
882     {
883       g_set_error (error, G_MARKUP_ERROR,
884                    G_MARKUP_ERROR_MISSING_ATTRIBUTE,
885                    _("exactly one of 'type', 'enum' or 'flags' must "
886                      "be specified as an attribute to <key>"));
887       return NULL;
888     }
889
890   if (type_string == NULL) /* flags or enums was specified */
891     {
892       EnumState *enum_state;
893
894       if (enum_type)
895         enum_state = g_hash_table_lookup (enum_table, enum_type);
896       else
897         enum_state = g_hash_table_lookup (flags_table, flags_type);
898
899
900       if (enum_state == NULL)
901         {
902           g_set_error (error, G_MARKUP_ERROR,
903                        G_MARKUP_ERROR_INVALID_CONTENT,
904                        _("<%s id='%s'> not (yet) defined."),
905                        flags_type ? "flags"    : "enum",
906                        flags_type ? flags_type : enum_type);
907           return NULL;
908         }
909
910       type_string = flags_type ? "as" : "s";
911       strinfo = enum_state->strinfo;
912     }
913   else
914     {
915       if (!g_variant_type_string_is_valid (type_string))
916         {
917           g_set_error (error, G_MARKUP_ERROR,
918                        G_MARKUP_ERROR_INVALID_CONTENT,
919                        _("invalid GVariant type string '%s'"), type_string);
920           return NULL;
921         }
922
923       strinfo = NULL;
924     }
925
926   key = key_state_new (type_string, state->gettext_domain,
927                        enum_type != NULL, flags_type != NULL, strinfo);
928   g_hash_table_insert (state->keys, g_strdup (name), key);
929
930   return key;
931 }
932
933 static void
934 schema_state_add_override (SchemaState  *state,
935                            KeyState    **key_state,
936                            GString     **string,
937                            const gchar  *key,
938                            const gchar  *l10n,
939                            const gchar  *context,
940                            GError      **error)
941 {
942   SchemaState *parent;
943   KeyState *original;
944
945   if (state->extends == NULL)
946     {
947       g_set_error_literal (error, G_MARKUP_ERROR,
948                            G_MARKUP_ERROR_INVALID_CONTENT,
949                            _("<override> given but schema isn't "
950                              "extending anything"));
951       return;
952     }
953
954   for (parent = state->extends; parent; parent = parent->extends)
955     if ((original = g_hash_table_lookup (parent->keys, key)))
956       break;
957
958   if (original == NULL)
959     {
960       g_set_error (error, G_MARKUP_ERROR,
961                    G_MARKUP_ERROR_INVALID_CONTENT,
962                    _("no <key name='%s'> to override"), key);
963       return;
964     }
965
966   if (g_hash_table_lookup (state->keys, key))
967     {
968       g_set_error (error, G_MARKUP_ERROR,
969                    G_MARKUP_ERROR_INVALID_CONTENT,
970                    _("<override name='%s'> already specified"), key);
971       return;
972     }
973
974   *key_state = key_state_override (original, state->gettext_domain);
975   *string = key_state_start_default (*key_state, l10n, context, error);
976   g_hash_table_insert (state->keys, g_strdup (key), *key_state);
977 }
978
979 static void
980 override_state_end (KeyState **key_state,
981                     GString  **string,
982                     GError   **error)
983 {
984   key_state_end_default (*key_state, string, error);
985   *key_state = NULL;
986 }
987
988 /* Handling of toplevel state {{{1 */
989 typedef struct
990 {
991   GHashTable  *schema_table;            /* string -> SchemaState */
992   GHashTable  *flags_table;             /* string -> EnumState */
993   GHashTable  *enum_table;              /* string -> EnumState */
994
995   gchar       *schemalist_domain;       /* the <schemalist> gettext domain */
996
997   SchemaState *schema_state;            /* non-NULL when inside <schema> */
998   KeyState    *key_state;               /* non-NULL when inside <key> */
999   EnumState   *enum_state;              /* non-NULL when inside <enum> */
1000
1001   GString     *string;                  /* non-NULL when accepting text */
1002 } ParseState;
1003
1004 static gboolean
1005 is_subclass (const gchar *class_name,
1006              const gchar *possible_parent,
1007              GHashTable  *schema_table)
1008 {
1009   SchemaState *class;
1010
1011   if (strcmp (class_name, possible_parent) == 0)
1012     return TRUE;
1013
1014   class = g_hash_table_lookup (schema_table, class_name);
1015   g_assert (class != NULL);
1016
1017   return class->extends_name &&
1018          is_subclass (class->extends_name, possible_parent, schema_table);
1019 }
1020
1021 static void
1022 parse_state_start_schema (ParseState  *state,
1023                           const gchar  *id,
1024                           const gchar  *path,
1025                           const gchar  *gettext_domain,
1026                           const gchar  *extends_name,
1027                           const gchar  *list_of,
1028                           GError      **error)
1029 {
1030   SchemaState *extends;
1031
1032   if (g_hash_table_lookup (state->schema_table, id))
1033     {
1034       g_set_error (error, G_MARKUP_ERROR,
1035                    G_MARKUP_ERROR_INVALID_CONTENT,
1036                    _("<schema id='%s'> already specified"), id);
1037       return;
1038     }
1039
1040   if (extends_name)
1041     {
1042       extends = g_hash_table_lookup (state->schema_table, extends_name);
1043
1044       if (extends == NULL)
1045         {
1046           g_set_error (error, G_MARKUP_ERROR,
1047                        G_MARKUP_ERROR_INVALID_CONTENT,
1048                        _("<schema id='%s'> extends not yet "
1049                          "existing schema '%s'"), id, extends_name);
1050           return;
1051         }
1052     }
1053   else
1054     extends = NULL;
1055
1056   if (list_of)
1057     {
1058       SchemaState *tmp;
1059
1060       if (!(tmp = g_hash_table_lookup (state->schema_table, list_of)))
1061         {
1062           g_set_error (error, G_MARKUP_ERROR,
1063                        G_MARKUP_ERROR_INVALID_CONTENT,
1064                        _("<schema id='%s'> is list of not yet "
1065                          "existing schema '%s'"), id, list_of);
1066           return;
1067         }
1068
1069       if (tmp->path)
1070         {
1071           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1072                        _("Can not be a list of a schema with a path"));
1073           return;
1074         }
1075     }
1076
1077   if (extends)
1078     {
1079       if (extends->path)
1080         {
1081           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1082                        _("Can not extend a schema with a path"));
1083           return;
1084         }
1085
1086       if (list_of)
1087         {
1088           if (extends->list_of == NULL)
1089             {
1090               g_set_error (error, G_MARKUP_ERROR,
1091                            G_MARKUP_ERROR_INVALID_CONTENT,
1092                            _("<schema id='%s'> is a list, extending "
1093                              "<schema id='%s'> which is not a list"),
1094                            id, extends_name);
1095               return;
1096             }
1097
1098           if (!is_subclass (list_of, extends->list_of, state->schema_table))
1099             {
1100               g_set_error (error, G_MARKUP_ERROR,
1101                            G_MARKUP_ERROR_INVALID_CONTENT,
1102                            _("<schema id='%s' list-of='%s'> extends <schema "
1103                              "id='%s' list-of='%s'> but '%s' does not "
1104                              "extend '%s'"), id, list_of, extends_name,
1105                            extends->list_of, list_of, extends->list_of);
1106               return;
1107             }
1108         }
1109       else
1110         /* by default we are a list of the same thing that the schema
1111          * we are extending is a list of (which might be nothing)
1112          */
1113         list_of = extends->list_of;
1114     }
1115
1116   if (path && !(g_str_has_prefix (path, "/") && g_str_has_suffix (path, "/")))
1117     {
1118       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1119                    _("a path, if given, must begin and end with a slash"));
1120       return;
1121     }
1122
1123   if (path && list_of && !g_str_has_suffix (path, ":/"))
1124     {
1125       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1126                    _("the path of a list must end with ':/'"));
1127       return;
1128     }
1129
1130   state->schema_state = schema_state_new (path, gettext_domain,
1131                                           extends, extends_name, list_of);
1132   g_hash_table_insert (state->schema_table, g_strdup (id),
1133                        state->schema_state);
1134 }
1135
1136 static void
1137 parse_state_start_enum (ParseState   *state,
1138                         const gchar  *id,
1139                         gboolean      is_flags,
1140                         GError      **error)
1141 {
1142   GHashTable *table = is_flags ? state->flags_table : state->enum_table;
1143
1144   if (g_hash_table_lookup (table, id))
1145     {
1146       g_set_error (error, G_MARKUP_ERROR,
1147                    G_MARKUP_ERROR_INVALID_CONTENT,
1148                    _("<%s id='%s'> already specified"),
1149                    is_flags ? "flags" : "enum", id);
1150       return;
1151     }
1152
1153   state->enum_state = enum_state_new (is_flags);
1154   g_hash_table_insert (table, g_strdup (id), state->enum_state);
1155 }
1156
1157 /* GMarkup Parser Functions {{{1 */
1158
1159 /* Start element {{{2 */
1160 static void
1161 start_element (GMarkupParseContext  *context,
1162                const gchar          *element_name,
1163                const gchar         **attribute_names,
1164                const gchar         **attribute_values,
1165                gpointer              user_data,
1166                GError              **error)
1167 {
1168   ParseState *state = user_data;
1169   const GSList *element_stack;
1170   const gchar *container;
1171
1172   element_stack = g_markup_parse_context_get_element_stack (context);
1173   container = element_stack->next ? element_stack->next->data : NULL;
1174
1175 #define COLLECT(first, ...) \
1176   g_markup_collect_attributes (element_name,                                 \
1177                                attribute_names, attribute_values, error,     \
1178                                first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
1179 #define OPTIONAL   G_MARKUP_COLLECT_OPTIONAL
1180 #define STRDUP     G_MARKUP_COLLECT_STRDUP
1181 #define STRING     G_MARKUP_COLLECT_STRING
1182 #define NO_ATTRS()  COLLECT (G_MARKUP_COLLECT_INVALID, NULL)
1183
1184   /* Toplevel items {{{3 */
1185   if (container == NULL)
1186     {
1187       if (strcmp (element_name, "schemalist") == 0)
1188         {
1189           COLLECT (OPTIONAL | STRDUP,
1190                    "gettext-domain",
1191                    &state->schemalist_domain);
1192           return;
1193         }
1194     }
1195
1196
1197   /* children of <schemalist> {{{3 */
1198   else if (strcmp (container, "schemalist") == 0)
1199     {
1200       if (strcmp (element_name, "schema") == 0)
1201         {
1202           const gchar *id, *path, *gettext_domain, *extends, *list_of;
1203           if (COLLECT (STRING, "id", &id,
1204                        OPTIONAL | STRING, "path", &path,
1205                        OPTIONAL | STRING, "gettext-domain", &gettext_domain,
1206                        OPTIONAL | STRING, "extends", &extends,
1207                        OPTIONAL | STRING, "list-of", &list_of))
1208             parse_state_start_schema (state, id, path, gettext_domain,
1209                                       extends, list_of, error);
1210           return;
1211         }
1212
1213       else if (strcmp (element_name, "enum") == 0)
1214         {
1215           const gchar *id;
1216           if (COLLECT (STRING, "id", &id))
1217             parse_state_start_enum (state, id, FALSE, error);
1218           return;
1219         }
1220
1221       else if (strcmp (element_name, "flags") == 0)
1222         {
1223           const gchar *id;
1224           if (COLLECT (STRING, "id", &id))
1225             parse_state_start_enum (state, id, TRUE, error);
1226           return;
1227         }
1228     }
1229
1230
1231   /* children of <schema> {{{3 */
1232   else if (strcmp (container, "schema") == 0)
1233     {
1234       if (strcmp (element_name, "key") == 0)
1235         {
1236           const gchar *name, *type_string, *enum_type, *flags_type;
1237
1238           if (COLLECT (STRING,            "name",  &name,
1239                        OPTIONAL | STRING, "type",  &type_string,
1240                        OPTIONAL | STRING, "enum",  &enum_type,
1241                        OPTIONAL | STRING, "flags", &flags_type))
1242
1243             state->key_state = schema_state_add_key (state->schema_state,
1244                                                      state->enum_table,
1245                                                      state->flags_table,
1246                                                      name, type_string,
1247                                                      enum_type, flags_type,
1248                                                      error);
1249           return;
1250         }
1251       else if (strcmp (element_name, "child") == 0)
1252         {
1253           const gchar *name, *schema;
1254
1255           if (COLLECT (STRING, "name", &name, STRING, "schema", &schema))
1256             schema_state_add_child (state->schema_state,
1257                                     name, schema, error);
1258           return;
1259         }
1260       else if (strcmp (element_name, "override") == 0)
1261         {
1262           const gchar *name, *l10n, *context;
1263
1264           if (COLLECT (STRING,            "name",    &name,
1265                        OPTIONAL | STRING, "l10n",    &l10n,
1266                        OPTIONAL | STRING, "context", &context))
1267             schema_state_add_override (state->schema_state,
1268                                        &state->key_state, &state->string,
1269                                        name, l10n, context, error);
1270           return;
1271         }
1272     }
1273
1274   /* children of <key> {{{3 */
1275   else if (strcmp (container, "key") == 0)
1276     {
1277       if (strcmp (element_name, "default") == 0)
1278         {
1279           const gchar *l10n, *context;
1280           if (COLLECT (STRING | OPTIONAL, "l10n",    &l10n,
1281                        STRING | OPTIONAL, "context", &context))
1282             state->string = key_state_start_default (state->key_state,
1283                                                      l10n, context, error);
1284           return;
1285         }
1286
1287       else if (strcmp (element_name, "summary") == 0 ||
1288                strcmp (element_name, "description") == 0)
1289         {
1290           if (NO_ATTRS ())
1291             state->string = g_string_new (NULL);
1292           return;
1293         }
1294
1295       else if (strcmp (element_name, "range") == 0)
1296         {
1297           const gchar *min, *max;
1298           if (COLLECT (STRING, "min", &min, STRING, "max", &max))
1299             key_state_set_range (state->key_state, min, max, error);
1300           return;
1301         }
1302
1303       else if (strcmp (element_name, "choices") == 0)
1304         {
1305           if (NO_ATTRS ())
1306             key_state_start_choices (state->key_state, error);
1307           return;
1308         }
1309
1310       else if (strcmp (element_name, "aliases") == 0)
1311         {
1312           if (NO_ATTRS ())
1313             key_state_start_aliases (state->key_state, error);
1314           return;
1315         }
1316     }
1317
1318
1319   /* children of <choices> {{{3 */
1320   else if (strcmp (container, "choices") == 0)
1321     {
1322       if (strcmp (element_name, "choice") == 0)
1323         {
1324           const gchar *value;
1325           if (COLLECT (STRING, "value", &value))
1326             key_state_add_choice (state->key_state, value, error);
1327           return;
1328         }
1329     }
1330
1331
1332   /* children of <aliases> {{{3 */
1333   else if (strcmp (container, "aliases") == 0)
1334     {
1335       if (strcmp (element_name, "alias") == 0)
1336         {
1337           const gchar *value, *target;
1338           if (COLLECT (STRING, "value", &value, STRING, "target", &target))
1339             key_state_add_alias (state->key_state, value, target, error);
1340           return;
1341         }
1342     }
1343
1344
1345   /* children of <enum> {{{3 */
1346   else if (strcmp (container, "enum") == 0 ||
1347            strcmp (container, "flags") == 0)
1348     {
1349       if (strcmp (element_name, "value") == 0)
1350         {
1351           const gchar *nick, *valuestr;
1352           if (COLLECT (STRING, "nick", &nick,
1353                        STRING, "value", &valuestr))
1354             enum_state_add_value (state->enum_state, nick, valuestr, error);
1355           return;
1356         }
1357     }
1358   /* 3}}} */
1359
1360   if (container)
1361     g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1362                  _("Element <%s> not allowed inside <%s>"),
1363                  element_name, container);
1364   else
1365     g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1366                  _("Element <%s> not allowed at toplevel"), element_name);
1367 }
1368 /* 2}}} */
1369 /* End element {{{2 */
1370
1371 static void
1372 key_state_end (KeyState **state_ptr,
1373                GError   **error)
1374 {
1375   KeyState *state;
1376
1377   state = *state_ptr;
1378   *state_ptr = NULL;
1379
1380   if (state->default_value == NULL)
1381     {
1382       g_set_error_literal (error,
1383                            G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1384                            "element <default> is required in <key>");
1385       return;
1386     }
1387 }
1388
1389 static void
1390 schema_state_end (SchemaState **state_ptr,
1391                   GError      **error)
1392 {
1393   SchemaState *state;
1394
1395   state = *state_ptr;
1396   *state_ptr = NULL;
1397 }
1398
1399 static void
1400 end_element (GMarkupParseContext  *context,
1401              const gchar          *element_name,
1402              gpointer              user_data,
1403              GError              **error)
1404 {
1405   ParseState *state = user_data;
1406
1407   if (strcmp (element_name, "schemalist") == 0)
1408     {
1409       g_free (state->schemalist_domain);
1410       state->schemalist_domain = NULL;
1411     }
1412
1413   else if (strcmp (element_name, "enum") == 0 ||
1414            strcmp (element_name, "flags") == 0)
1415     enum_state_end (&state->enum_state, error);
1416
1417   else if (strcmp (element_name, "schema") == 0)
1418     schema_state_end (&state->schema_state, error);
1419
1420   else if (strcmp (element_name, "override") == 0)
1421     override_state_end (&state->key_state, &state->string, error);
1422
1423   else if (strcmp (element_name, "key") == 0)
1424     key_state_end (&state->key_state, error);
1425
1426   else if (strcmp (element_name, "default") == 0)
1427     key_state_end_default (state->key_state, &state->string, error);
1428
1429   else if (strcmp (element_name, "choices") == 0)
1430     key_state_end_choices (state->key_state, error);
1431
1432   else if (strcmp (element_name, "aliases") == 0)
1433     key_state_end_aliases (state->key_state, error);
1434
1435   if (state->string)
1436     {
1437       g_string_free (state->string, TRUE);
1438       state->string = NULL;
1439     }
1440 }
1441 /* Text {{{2 */
1442 static void
1443 text (GMarkupParseContext  *context,
1444       const gchar          *text,
1445       gsize                 text_len,
1446       gpointer              user_data,
1447       GError              **error)
1448 {
1449   ParseState *state = user_data;
1450   gsize i;
1451
1452   for (i = 0; i < text_len; i++)
1453     if (!g_ascii_isspace (text[i]))
1454       {
1455         if (state->string)
1456           g_string_append_len (state->string, text, text_len);
1457
1458         else
1459           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1460                        _("text may not appear inside <%s>"),
1461                        g_markup_parse_context_get_element (context));
1462
1463         break;
1464       }
1465 }
1466
1467 /* Write to GVDB {{{1 */
1468 typedef struct
1469 {
1470   GHashTable *table;
1471   GvdbItem *root;
1472 } GvdbPair;
1473
1474 static void
1475 gvdb_pair_init (GvdbPair *pair)
1476 {
1477   pair->table = gvdb_hash_table_new (NULL, NULL);
1478   pair->root = gvdb_hash_table_insert (pair->table, "");
1479 }
1480
1481 typedef struct
1482 {
1483   GvdbPair pair;
1484   gboolean l10n;
1485 } OutputSchemaData;
1486
1487 static void
1488 output_key (gpointer key,
1489             gpointer value,
1490             gpointer user_data)
1491 {
1492   OutputSchemaData *data;
1493   const gchar *name;
1494   KeyState *state;
1495   GvdbItem *item;
1496
1497   name = key;
1498   state = value;
1499   data = user_data;
1500
1501   item = gvdb_hash_table_insert (data->pair.table, name);
1502   gvdb_item_set_parent (item, data->pair.root);
1503   gvdb_item_set_value (item, key_state_serialise (state));
1504
1505   if (state->l10n)
1506     data->l10n = TRUE;
1507 }
1508
1509 static void
1510 output_schema (gpointer key,
1511                gpointer value,
1512                gpointer user_data)
1513 {
1514   OutputSchemaData data;
1515   GvdbPair *root_pair;
1516   SchemaState *state;
1517   const gchar *id;
1518   GvdbItem *item;
1519
1520   id = key;
1521   state = value;
1522   root_pair = user_data;
1523
1524   gvdb_pair_init (&data.pair);
1525   data.l10n = FALSE;
1526
1527   item = gvdb_hash_table_insert (root_pair->table, id);
1528   gvdb_item_set_parent (item, root_pair->root);
1529   gvdb_item_set_hash_table (item, data.pair.table);
1530
1531   g_hash_table_foreach (state->keys, output_key, &data);
1532
1533   if (state->path)
1534     gvdb_hash_table_insert_string (data.pair.table, ".path", state->path);
1535
1536   if (state->extends_name)
1537     gvdb_hash_table_insert_string (data.pair.table, ".extends",
1538                                    state->extends_name);
1539
1540   if (state->list_of)
1541     gvdb_hash_table_insert_string (data.pair.table, ".list-of",
1542                                    state->extends_name);
1543
1544   if (data.l10n)
1545     gvdb_hash_table_insert_string (data.pair.table,
1546                                    ".gettext-domain",
1547                                    state->gettext_domain);
1548 }
1549
1550 static gboolean
1551 write_to_file (GHashTable   *schema_table,
1552                const gchar  *filename,
1553                GError      **error)
1554 {
1555   gboolean success;
1556   GvdbPair pair;
1557
1558   gvdb_pair_init (&pair);
1559
1560   g_hash_table_foreach (schema_table, output_schema, &pair);
1561
1562   success = gvdb_table_write_contents (pair.table, filename,
1563                                        G_BYTE_ORDER != G_LITTLE_ENDIAN,
1564                                        error);
1565   g_hash_table_unref (pair.table);
1566
1567   return success;
1568 }
1569
1570 /* Parser driver {{{1 */
1571 static GHashTable *
1572 parse_gschema_files (gchar  **files,
1573                      GError **error)
1574 {
1575   GMarkupParser parser = { start_element, end_element, text };
1576   ParseState state = { 0, };
1577   const gchar *filename;
1578
1579   state.enum_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1580                                             g_free, enum_state_free);
1581
1582   state.flags_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1583                                              g_free, enum_state_free);
1584
1585   state.schema_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1586                                               g_free, schema_state_free);
1587
1588   while ((filename = *files++) != NULL)
1589     {
1590       GMarkupParseContext *context;
1591       gchar *contents;
1592       gsize size;
1593
1594       context = g_markup_parse_context_new (&parser,
1595                                             G_MARKUP_PREFIX_ERROR_POSITION,
1596                                             &state, NULL);
1597
1598       if (!g_file_get_contents (filename, &contents, &size, error))
1599         return NULL;
1600
1601       if (!g_markup_parse_context_parse (context, contents, size, error))
1602         {
1603           g_prefix_error (error, "%s: ", filename);
1604           return NULL;
1605         }
1606
1607       if (!g_markup_parse_context_end_parse (context, error))
1608         {
1609           g_prefix_error (error, "%s: ", filename);
1610           return NULL;
1611         }
1612
1613       g_markup_parse_context_free (context);
1614     }
1615
1616   g_hash_table_unref (state.enum_table);
1617
1618   return state.schema_table;
1619 }
1620
1621 static gint
1622 compare_strings (gconstpointer a,
1623                  gconstpointer b)
1624 {
1625   gchar *one = *(gchar **) a;
1626   gchar *two = *(gchar **) b;
1627   gint cmp;
1628
1629   cmp = g_str_has_suffix (two, ".enums.xml") -
1630         g_str_has_suffix (one, ".enums.xml");
1631
1632   if (!cmp)
1633     cmp = strcmp (one, two);
1634
1635   return cmp;
1636 }
1637
1638 static gboolean
1639 set_overrides (GHashTable  *schema_table,
1640                gchar      **files,
1641                GError     **error)
1642 {
1643   const gchar *filename;
1644
1645   while ((filename = *files++))
1646     {
1647       GKeyFile *key_file;
1648       gchar **groups;
1649       gint i;
1650
1651       key_file = g_key_file_new ();
1652       if (!g_key_file_load_from_file (key_file, filename, 0, error))
1653         {
1654           g_key_file_free (key_file);
1655
1656           return FALSE;
1657         }
1658
1659       groups = g_key_file_get_groups (key_file, NULL);
1660
1661       for (i = 0; groups[i]; i++)
1662         {
1663           const gchar *group = groups[i];
1664           SchemaState *schema;
1665           gchar **keys;
1666           gint j;
1667
1668           schema = g_hash_table_lookup (schema_table, group);
1669
1670           if (schema == NULL)
1671             {
1672               g_set_error (error, G_KEY_FILE_ERROR,
1673                            G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1674                            _("No such schema `%s' specified in "
1675                              "override file `%s'"), group, filename);
1676               g_key_file_free (key_file);
1677               g_strfreev (groups);
1678
1679               return FALSE;
1680             }
1681
1682           keys = g_key_file_get_keys (key_file, group, NULL, NULL);
1683           g_assert (keys != NULL);
1684
1685           for (j = 0; keys[j]; j++)
1686             {
1687               const gchar *key = keys[j];
1688               KeyState *state;
1689               GVariant *value;
1690               gchar *string;
1691
1692               state = g_hash_table_lookup (schema->keys, key);
1693
1694               if (state == NULL)
1695                 {
1696                   g_set_error (error, G_KEY_FILE_ERROR,
1697                                G_KEY_FILE_ERROR_KEY_NOT_FOUND,
1698                                _("No such key `%s' in schema `%s' as "
1699                                  "specified in override file `%s'"),
1700                                key, group, filename);
1701                   g_key_file_free (key_file);
1702                   g_strfreev (groups);
1703                   g_strfreev (keys);
1704
1705                   return FALSE;
1706                 }
1707
1708               string = g_key_file_get_value (key_file, group, key, NULL);
1709               g_assert (string != NULL);
1710
1711               value = g_variant_parse (state->type, string,
1712                                        NULL, NULL, error);
1713
1714               if (value == NULL)
1715                 {
1716                   g_key_file_free (key_file);
1717                   g_strfreev (groups);
1718                   g_strfreev (keys);
1719                   g_free (string);
1720
1721                   return FALSE;
1722                 }
1723
1724               if (state->minimum)
1725                 {
1726                   if (g_variant_compare (value, state->minimum) < 0 ||
1727                       g_variant_compare (value, state->maximum) > 0)
1728                     {
1729                       g_set_error (error, G_MARKUP_ERROR,
1730                                    G_MARKUP_ERROR_INVALID_CONTENT,
1731                                    _("override for key `%s' in schema `%s' in "
1732                                      "override file `%s' is out of the range "
1733                                      "given in the schema"),
1734                                    key, group, filename);
1735
1736                       g_key_file_free (key_file);
1737                       g_variant_unref (value);
1738                       g_strfreev (groups);
1739                       g_strfreev (keys);
1740                       g_free (string);
1741
1742                       return FALSE;
1743                     }
1744                 }
1745
1746               else if (state->strinfo->len)
1747                 {
1748                   if (!is_valid_choices (value, state->strinfo))
1749                     {
1750                       g_set_error (error, G_MARKUP_ERROR,
1751                                    G_MARKUP_ERROR_INVALID_CONTENT,
1752                                    _("override for key `%s' in schema `%s' in "
1753                                      "override file `%s' is not in the list "
1754                                      "of valid choices"),
1755                                    key, group, filename);
1756
1757                       g_key_file_free (key_file);
1758                       g_variant_unref (value);
1759                       g_strfreev (groups);
1760                       g_strfreev (keys);
1761                       g_free (string);
1762
1763                       return FALSE;
1764                     }
1765                 }
1766
1767               g_variant_unref (state->default_value);
1768               state->default_value = value;
1769             }
1770
1771
1772           g_strfreev (keys);
1773         }
1774
1775       g_strfreev (groups);
1776     }
1777
1778   return TRUE;
1779 }
1780
1781 int
1782 main (int argc, char **argv)
1783 {
1784   GError *error;
1785   GHashTable *table;
1786   GDir *dir;
1787   const gchar *file;
1788   gchar *srcdir;
1789   gchar *targetdir = NULL;
1790   gchar *target;
1791   gboolean uninstall = FALSE;
1792   gboolean dry_run = FALSE;
1793   gchar **schema_files = NULL;
1794   gchar **override_files = NULL;
1795   GOptionContext *context;
1796   GOptionEntry entries[] = {
1797     { "targetdir", 0, 0, G_OPTION_ARG_FILENAME, &targetdir, N_("where to store the gschemas.compiled file"), N_("DIRECTORY") },
1798     { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, N_("Do not write the gschema.compiled file"), NULL },
1799     { "uninstall", 0, 0, G_OPTION_ARG_NONE, &uninstall, N_("This option will be removed soon.") },
1800     { "allow-any-name", 0, 0, G_OPTION_ARG_NONE, &allow_any_name, N_("Do not enforce key name restrictions") },
1801
1802     /* These options are only for use in the gschema-compile tests */
1803     { "schema-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &schema_files, NULL, NULL },
1804     { NULL }
1805   };
1806
1807   setlocale (LC_ALL, "");
1808
1809   context = g_option_context_new (N_("DIRECTORY"));
1810   g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
1811   g_option_context_set_summary (context,
1812     N_("Compile all GSettings schema files into a schema cache.\n"
1813        "Schema files are required to have the extension .gschema.xml,\n"
1814        "and the cache file is called gschemas.compiled."));
1815   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
1816
1817   error = NULL;
1818   if (!g_option_context_parse (context, &argc, &argv, &error))
1819     {
1820       fprintf (stderr, "%s", error->message);
1821       return 1;
1822     }
1823
1824   g_option_context_free (context);
1825
1826   if (!schema_files && argc != 2)
1827     {
1828       fprintf (stderr, _("You should give exactly one directory name\n"));
1829       return 1;
1830     }
1831
1832   srcdir = argv[1];
1833
1834   if (targetdir == NULL)
1835     targetdir = srcdir;
1836
1837   target = g_build_filename (targetdir, "gschemas.compiled", NULL);
1838
1839   if (!schema_files)
1840     {
1841       GPtrArray *overrides;
1842       GPtrArray *files;
1843
1844       files = g_ptr_array_new ();
1845       overrides = g_ptr_array_new ();
1846
1847       dir = g_dir_open (srcdir, 0, &error);
1848       if (dir == NULL)
1849         {
1850           fprintf (stderr, "%s\n", error->message);
1851           return 1;
1852         }
1853
1854       while ((file = g_dir_read_name (dir)) != NULL)
1855         {
1856           if (g_str_has_suffix (file, ".gschema.xml") ||
1857               g_str_has_suffix (file, ".enums.xml"))
1858             g_ptr_array_add (files, g_build_filename (srcdir, file, NULL));
1859
1860           else if (g_str_has_suffix (file, ".gschema.override"))
1861             g_ptr_array_add (overrides,
1862                              g_build_filename (srcdir, file, NULL));
1863         }
1864
1865       if (files->len == 0)
1866         {
1867           fprintf (stderr, _("No schema files found: "));
1868
1869           if (g_unlink (target))
1870             fprintf (stderr, _("doing nothing.\n"));
1871
1872           else
1873             fprintf (stderr, _("removed existing output file.\n"));
1874
1875           return 0;
1876         }
1877       g_ptr_array_sort (files, compare_strings);
1878       g_ptr_array_add (files, NULL);
1879
1880       g_ptr_array_sort (overrides, compare_strings);
1881       g_ptr_array_add (overrides, NULL);
1882
1883       schema_files = (char **) g_ptr_array_free (files, FALSE);
1884       override_files = (gchar **) g_ptr_array_free (overrides, FALSE);
1885     }
1886
1887
1888   if (!(table = parse_gschema_files (schema_files, &error)) ||
1889       (override_files != NULL && !set_overrides (table, override_files, &error)) ||
1890       (!dry_run && !write_to_file (table, target, &error)))
1891     {
1892       fprintf (stderr, "%s\n", error->message);
1893       return 1;
1894     }
1895
1896   g_free (target);
1897
1898   return 0;
1899 }
1900
1901 /* Epilogue {{{1 */
1902
1903 /* vim:set foldmethod=marker: */