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