Implement bash completion for gsettings
[platform/upstream/glib.git] / gio / gschema-compile.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 GString EnumState;
39
40 static void
41 enum_state_free (gpointer data)
42 {
43   EnumState *state = data;
44
45   g_string_free (state, TRUE);
46 }
47
48 static void
49 enum_state_add_value (EnumState    *state,
50                       const gchar  *nick,
51                       const gchar  *valuestr,
52                       GError      **error)
53 {
54   gint64 value;
55   gchar *end;
56
57   if (nick[0] == '\0' || nick[1] == '\0')
58     {
59       g_set_error (error, G_MARKUP_ERROR,
60                    G_MARKUP_ERROR_INVALID_CONTENT,
61                    "enum nick must be a minimum of 2 characters");
62       return;
63     }
64
65   value = g_ascii_strtoll (valuestr, &end, 0);
66   if (*end || value > G_MAXINT32 || value < G_MININT32)
67     {
68       g_set_error (error, G_MARKUP_ERROR,
69                    G_MARKUP_ERROR_INVALID_CONTENT,
70                    "invalid numeric value");
71       return;
72     }
73
74   if (strinfo_builder_contains (state, nick))
75     {
76       g_set_error (error, G_MARKUP_ERROR,
77                    G_MARKUP_ERROR_INVALID_CONTENT,
78                    "<value nick='%s'> already specified", nick);
79       return;
80     }
81
82   strinfo_builder_append_item (state, nick, value);
83 }
84
85 static void
86 enum_state_end (EnumState **state_ptr,
87                 GError    **error)
88 {
89   EnumState *state;
90
91   state = *state_ptr;
92   *state_ptr = NULL;
93
94   if (state->len == 0)
95     g_set_error_literal (error,
96                          G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
97                          "<enum> must contain at least one <value>");
98 }
99
100 /* Handling of <key> {{{1 */
101 typedef struct
102 {
103   /* for <child>, @child_schema will be set.
104    * for <key>, everything else will be set.
105    */
106   gchar        *child_schema;
107
108
109   GVariantType *type;
110   gboolean      have_gettext_domain;
111
112   gchar         l10n;
113   gchar        *l10n_context;
114   GString      *unparsed_default_value;
115   GVariant     *default_value;
116
117   GString      *strinfo;
118   gboolean      is_enum;
119
120   GVariant     *minimum;
121   GVariant     *maximum;
122
123   gboolean      has_choices;
124   gboolean      has_aliases;
125
126   gboolean      checked;
127   GVariant     *serialised;
128 } KeyState;
129
130 static KeyState *
131 key_state_new (const gchar *type_string,
132                const gchar *gettext_domain,
133                EnumState   *enum_data)
134 {
135   KeyState *state;
136
137   state = g_slice_new0 (KeyState);
138   state->type = g_variant_type_new (type_string);
139   state->have_gettext_domain = gettext_domain != NULL;
140
141   if ((state->is_enum = (enum_data != NULL)))
142     state->strinfo = g_string_new_len (enum_data->str, enum_data->len);
143   else
144     state->strinfo = g_string_new (NULL);
145
146   return state;
147 }
148
149 static KeyState *
150 key_state_new_child (const gchar *child_schema)
151 {
152   KeyState *state;
153
154   state = g_slice_new0 (KeyState);
155   state->child_schema = g_strdup (child_schema);
156
157   return state;
158 }
159
160 static gboolean
161 is_valid_choices (GVariant *variant,
162                   GString  *strinfo)
163 {
164   switch (g_variant_classify (variant))
165     {
166       case G_VARIANT_CLASS_MAYBE:
167       case G_VARIANT_CLASS_ARRAY:
168         {
169           gboolean valid = TRUE;
170           GVariantIter iter;
171
172           g_variant_iter_init (&iter, variant);
173
174           while (valid && (variant = g_variant_iter_next_value (&iter)))
175             {
176               valid = is_valid_choices (variant, strinfo);
177               g_variant_unref (variant);
178             }
179
180           return valid;
181         }
182
183       case G_VARIANT_CLASS_STRING:
184         return strinfo_is_string_valid ((const guint32 *) strinfo->str,
185                                         strinfo->len / 4,
186                                         g_variant_get_string (variant, NULL));
187
188       default:
189         g_assert_not_reached ();
190     }
191 }
192
193
194 /* Gets called at </default> </choices> or <range/> to check for
195  * validity of the default value so that any inconsistency is
196  * reported as soon as it is encountered.
197  */
198 static void
199 key_state_check_range (KeyState  *state,
200                        GError   **error)
201 {
202   if (state->default_value)
203     {
204       if (state->minimum)
205         {
206           if (g_variant_compare (state->default_value, state->minimum) < 0 ||
207               g_variant_compare (state->default_value, state->maximum) > 0)
208             {
209               g_set_error (error, G_MARKUP_ERROR,
210                            G_MARKUP_ERROR_INVALID_CONTENT,
211                            "<default> is not contained in "
212                            "the specified range");
213             }
214         }
215
216       else if (state->strinfo->len)
217         {
218           if (!is_valid_choices (state->default_value, state->strinfo))
219             {
220               if (state->is_enum)
221                 g_set_error_literal (error, G_MARKUP_ERROR,
222                                      G_MARKUP_ERROR_INVALID_CONTENT,
223                                      "<default> is not a valid member of "
224                                      "the specified enumerated type");
225
226               else
227                 g_set_error_literal (error, G_MARKUP_ERROR,
228                                      G_MARKUP_ERROR_INVALID_CONTENT,
229                                      "<default> contains string not in "
230                                      "<choices>");
231             }
232         }
233     }
234 }
235
236 static void
237 key_state_set_range (KeyState     *state,
238                      const gchar  *min_str,
239                      const gchar  *max_str,
240                      GError      **error)
241 {
242   if (state->minimum)
243     {
244       g_set_error_literal (error, G_MARKUP_ERROR,
245                            G_MARKUP_ERROR_INVALID_CONTENT,
246                            "<range/> already specified for this key");
247       return;
248     }
249
250   if (strchr ("ynqiuxtd", *(char *) state->type) == NULL)
251     {
252       gchar *type = g_variant_type_dup_string (state->type);
253       g_set_error (error, G_MARKUP_ERROR,
254                   G_MARKUP_ERROR_INVALID_CONTENT,
255                   "<range> not allowed for keys of type '%s'", type);
256       g_free (type);
257       return;
258     }
259
260   state->minimum = g_variant_parse (state->type, min_str, NULL, NULL, error);
261   if (state->minimum == NULL)
262     return;
263
264   state->maximum = g_variant_parse (state->type, max_str, NULL, NULL, error);
265   if (state->maximum == NULL)
266     return;
267
268   if (g_variant_compare (state->minimum, state->maximum) > 0)
269     {
270       g_set_error (error, G_MARKUP_ERROR,
271                    G_MARKUP_ERROR_INVALID_CONTENT,
272                    "<range> specified minimum is greater than maxmimum");
273       return;
274     }
275
276   key_state_check_range (state, error);
277 }
278
279 static GString *
280 key_state_start_default (KeyState     *state,
281                          const gchar  *l10n,
282                          const gchar  *context,
283                          GError      **error)
284 {
285   if (l10n != NULL)
286     {
287       if (strcmp (l10n, "messages") == 0)
288         state->l10n = 'm';
289
290       else if (strcmp (l10n, "time") == 0)
291         state->l10n = 't';
292
293       else
294         {
295           g_set_error (error, G_MARKUP_ERROR,
296                        G_MARKUP_ERROR_INVALID_CONTENT,
297                        "unsupported l10n category: %s", l10n);
298           return NULL;
299         }
300
301       if (!state->have_gettext_domain)
302         {
303           g_set_error_literal (error, G_MARKUP_ERROR,
304                                G_MARKUP_ERROR_INVALID_CONTENT,
305                                "l10n requested, but no "
306                                "gettext domain given");
307           return NULL;
308         }
309
310       state->l10n_context = g_strdup (context);
311     }
312
313   else if (context != NULL)
314     {
315       g_set_error_literal (error, G_MARKUP_ERROR,
316                            G_MARKUP_ERROR_INVALID_CONTENT,
317                            "translation context given for "
318                            " value without l10n enabled");
319       return NULL;
320     }
321
322   return g_string_new (NULL);
323 }
324
325 static void
326 key_state_end_default (KeyState  *state,
327                        GString  **string,
328                        GError   **error)
329 {
330   state->unparsed_default_value = *string;
331   *string = NULL;
332
333   state->default_value = g_variant_parse (state->type,
334                                           state->unparsed_default_value->str,
335                                           NULL, NULL, error);
336   key_state_check_range (state, error);
337 }
338
339 static void
340 key_state_start_choices (KeyState  *state,
341                          GError   **error)
342 {
343   const GVariantType *type = state->type;
344
345   if (state->is_enum)
346     {
347       g_set_error_literal (error, G_MARKUP_ERROR,
348                            G_MARKUP_ERROR_INVALID_CONTENT,
349                            "<choices> can not be specified for keys "
350                            "tagged as having an enumerated type");
351       return;
352     }
353
354   if (state->has_choices)
355     {
356       g_set_error_literal (error, G_MARKUP_ERROR,
357                            G_MARKUP_ERROR_INVALID_CONTENT,
358                            "<choices> already specified for this key");
359       return;
360     }
361
362   while (g_variant_type_is_maybe (type) || g_variant_type_is_array (type))
363     type = g_variant_type_element (type);
364
365   if (!g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
366     {
367       gchar *type_string = g_variant_type_dup_string (state->type);
368       g_set_error (error, G_MARKUP_ERROR,
369                    G_MARKUP_ERROR_INVALID_CONTENT,
370                    "<choices> not allowed for keys of type '%s'",
371                    type_string);
372       g_free (type_string);
373       return;
374     }
375 }
376
377 static void
378 key_state_add_choice (KeyState     *state,
379                       const gchar  *choice,
380                       GError      **error)
381 {
382   if (strinfo_builder_contains (state->strinfo, choice))
383     {
384       g_set_error (error, G_MARKUP_ERROR,
385                    G_MARKUP_ERROR_INVALID_CONTENT,
386                    "<choice value='%s'/> already given", choice);
387       return;
388     }
389
390   strinfo_builder_append_item (state->strinfo, choice, 0);
391   state->has_choices = TRUE;
392 }
393
394 static void
395 key_state_end_choices (KeyState  *state,
396                        GError   **error)
397 {
398   if (!state->has_choices)
399     {
400       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
401                    "<choices> must contain at least one <choice>");
402       return;
403     }
404
405   key_state_check_range (state, error);
406 }
407
408 static void
409 key_state_start_aliases (KeyState  *state,
410                          GError   **error)
411 {
412   if (state->has_aliases)
413     g_set_error_literal (error, G_MARKUP_ERROR,
414                          G_MARKUP_ERROR_INVALID_CONTENT,
415                          "<aliases> already specified for this key");
416
417   if (!state->is_enum && !state->has_choices)
418     g_set_error_literal (error, G_MARKUP_ERROR,
419                          G_MARKUP_ERROR_INVALID_CONTENT,
420                          "<aliases> can only be specified for keys with "
421                          "enumerated types or after <choices>");
422 }
423
424 static void
425 key_state_add_alias (KeyState     *state,
426                      const gchar  *alias,
427                      const gchar  *target,
428                      GError      **error)
429 {
430   if (strinfo_builder_contains (state->strinfo, alias))
431     {
432       if (strinfo_is_string_valid ((guint32 *) state->strinfo->str,
433                                    state->strinfo->len / 4,
434                                    alias))
435         {
436           if (state->is_enum)
437             g_set_error (error, G_MARKUP_ERROR,
438                          G_MARKUP_ERROR_INVALID_CONTENT,
439                          "<alias value='%s'/> given when '%s' is already "
440                          "a member of the enumerated type", alias, alias);
441
442           else
443             g_set_error (error, G_MARKUP_ERROR,
444                          G_MARKUP_ERROR_INVALID_CONTENT,
445                          "<alias value='%s'/> given when "
446                          "<choice value='%s'/> was already given",
447                          alias, alias);
448         }
449
450       else
451         g_set_error (error, G_MARKUP_ERROR,
452                      G_MARKUP_ERROR_INVALID_CONTENT,
453                      "<alias value='%s'/> already specified", alias);
454
455       return;
456     }
457
458   if (!strinfo_builder_append_alias (state->strinfo, alias, target))
459     {
460       g_set_error (error, G_MARKUP_ERROR,
461                    G_MARKUP_ERROR_INVALID_CONTENT,
462                    "alias target '%s' is not in %s", target,
463                    state->is_enum ? "enumerated type" : "<choices>");
464       return;
465     }
466
467   state->has_aliases = TRUE;
468 }
469
470 static void
471 key_state_end_aliases (KeyState  *state,
472                        GError   **error)
473 {
474   if (!state->has_aliases)
475     {
476       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
477                    "<aliases> must contain at least one <alias>");
478       return;
479     }
480 }
481
482 static gboolean
483 key_state_check (KeyState  *state,
484                  GError   **error)
485 {
486   if (state->checked)
487     return TRUE;
488
489   return state->checked = TRUE;
490 }
491
492 static GVariant *
493 key_state_serialise (KeyState *state)
494 {
495   if (state->serialised == NULL)
496     {
497       if (state->child_schema)
498         {
499           state->serialised = g_variant_new_string (state->child_schema);
500         }
501
502       else
503         {
504           GVariantBuilder builder;
505
506           g_assert (key_state_check (state, NULL));
507
508           g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
509
510           /* default value */
511           g_variant_builder_add_value (&builder, state->default_value);
512
513           /* translation */
514           if (state->l10n)
515             {
516               if (state->l10n_context)
517                 {
518                   gint len;
519
520                   /* Contextified messages are supported by prepending
521                    * the context, followed by '\004' to the start of the
522                    * message string.  We do that here to save GSettings
523                    * the work later on.
524                    */
525                   len = strlen (state->l10n_context);
526                   state->l10n_context[len] = '\004';
527                   g_string_prepend_len (state->unparsed_default_value,
528                                         state->l10n_context, len + 1);
529                   g_free (state->l10n_context);
530                   state->l10n_context = NULL;
531                 }
532
533               g_variant_builder_add (&builder, "(y(y&s))", 'l', state->l10n,
534                                      state->unparsed_default_value);
535               g_string_free (state->unparsed_default_value, TRUE);
536               state->unparsed_default_value = NULL;
537             }
538
539           /* choice, aliases, enums */
540           if (state->strinfo->len)
541             {
542               GVariant *array;
543               gpointer data;
544               gsize size;
545
546               data = state->strinfo->str;
547               size = state->strinfo->len;
548
549               array = g_variant_new_from_data (G_VARIANT_TYPE ("au"),
550                                                data, size, TRUE,
551                                                g_free, data);
552
553               g_string_free (state->strinfo, FALSE);
554               state->strinfo = NULL;
555
556               g_variant_builder_add (&builder, "(y@au)",
557                                      state->is_enum ? 'e' : 'c',
558                                      array);
559             }
560
561           /* range */
562           if (state->minimum || state->maximum)
563             g_variant_builder_add (&builder, "(y(**))", 'r',
564                                    state->minimum, state->maximum);
565
566           state->serialised = g_variant_builder_end (&builder);
567         }
568
569       g_variant_ref_sink (state->serialised);
570     }
571
572   return g_variant_ref (state->serialised);
573 }
574
575 static void
576 key_state_free (gpointer data)
577 {
578   KeyState *state = data;
579
580   if (state->type)
581     g_variant_type_free (state->type);
582
583   g_free (state->l10n_context);
584
585   if (state->unparsed_default_value)
586     g_string_free (state->unparsed_default_value, TRUE);
587
588   if (state->default_value)
589     g_variant_unref (state->default_value);
590
591   if (state->strinfo)
592     g_string_free (state->strinfo, TRUE);
593
594   if (state->minimum)
595     g_variant_unref (state->minimum);
596
597   if (state->maximum)
598     g_variant_unref (state->maximum);
599
600   if (state->serialised)
601     g_variant_unref (state->serialised);
602
603   g_slice_free (KeyState, state);
604 }
605
606 /* Key name validity {{{1 */
607 static gboolean allow_any_name = FALSE;
608
609 static gboolean
610 is_valid_keyname (const gchar  *key,
611                   GError      **error)
612 {
613   gint i;
614
615   if (key[0] == '\0')
616     {
617       g_set_error_literal (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
618                            "empty names are not permitted");
619       return FALSE;
620     }
621
622   if (allow_any_name)
623     return TRUE;
624
625   if (!g_ascii_islower (key[0]))
626     {
627       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
628                    "invalid name '%s': names must begin "
629                    "with a lowercase letter", key);
630       return FALSE;
631     }
632
633   for (i = 1; key[i]; i++)
634     {
635       if (key[i] != '-' &&
636           !g_ascii_islower (key[i]) &&
637           !g_ascii_isdigit (key[i]))
638         {
639           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
640                        "invalid name '%s': invalid character '%c'; "
641                        "only lowercase letters, numbers and dash ('-') "
642                        "are permitted.", key, key[i]);
643           return FALSE;
644         }
645
646       if (key[i] == '-' && key[i + 1] == '-')
647         {
648           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
649                        "invalid name '%s': two successive dashes ('--') are "
650                        "not permitted.", key);
651           return FALSE;
652         }
653     }
654
655   if (key[i - 1] == '-')
656     {
657       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
658                    "invalid name '%s': the last character may not be a "
659                    "dash ('-').", key);
660       return FALSE;
661     }
662
663   if (i > 32)
664     {
665       g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
666                    "invalid name '%s': maximum length is 32", key);
667       return FALSE;
668     }
669
670   return TRUE;
671 }
672
673 /* Handling of <schema> {{{1 */
674 typedef struct
675 {
676   gchar      *path;
677   gchar      *gettext_domain;
678
679   GHashTable *keys;
680 } SchemaState;
681
682 static SchemaState *
683 schema_state_new (const gchar  *path,
684                   const gchar  *gettext_domain)
685 {
686   SchemaState *state;
687
688   state = g_slice_new (SchemaState);
689   state->path = g_strdup (path);
690   state->gettext_domain = g_strdup (gettext_domain);
691   state->keys = g_hash_table_new_full (g_str_hash, g_str_equal,
692                                        g_free, key_state_free);
693
694   return state;
695 }
696
697 static void
698 schema_state_free (gpointer data)
699 {
700   SchemaState *state = data;
701
702   g_free (state->path);
703   g_free (state->gettext_domain);
704   g_hash_table_unref (state->keys);
705 }
706
707 static void
708 schema_state_add_child (SchemaState  *state,
709                         const gchar  *name,
710                         const gchar  *schema,
711                         GError      **error)
712 {
713   gchar *childname;
714
715   if (!is_valid_keyname (name, error))
716     return;
717
718   childname = g_strconcat (name, "/", NULL);
719
720   if (g_hash_table_lookup (state->keys, childname))
721     {
722       g_set_error (error, G_MARKUP_ERROR,
723                    G_MARKUP_ERROR_INVALID_CONTENT,
724                    "<child name='%s'> already specified", name);
725       return;
726     }
727
728   g_hash_table_insert (state->keys, childname,
729                        key_state_new_child (schema));
730 }
731
732 static KeyState *
733 schema_state_add_key (SchemaState  *state,
734                       GHashTable   *enum_table,
735                       const gchar  *name,
736                       const gchar  *type_string,
737                       const gchar  *enum_type,
738                       GError      **error)
739 {
740   GString *enum_data;
741   KeyState *key;
742
743   if (!is_valid_keyname (name, error))
744     return NULL;
745
746   if (g_hash_table_lookup (state->keys, name))
747     {
748       g_set_error (error, G_MARKUP_ERROR,
749                    G_MARKUP_ERROR_INVALID_CONTENT,
750                    "<key name='%s'> already specified", name);
751       return NULL;
752     }
753
754   if ((type_string == NULL) == (enum_type == NULL))
755     {
756       g_set_error (error, G_MARKUP_ERROR,
757                    G_MARKUP_ERROR_MISSING_ATTRIBUTE,
758                    "exactly one of 'type' or 'enum' must "
759                    "be specified as an attribute to <key>");
760       return NULL;
761     }
762
763   if (enum_type != NULL)
764     {
765       enum_data = g_hash_table_lookup (enum_table, enum_type);
766
767       if (enum_data == NULL)
768         {
769           g_set_error (error, G_MARKUP_ERROR,
770                        G_MARKUP_ERROR_INVALID_CONTENT,
771                        "<enum id='%s'> not (yet) defined.", enum_type);
772           return NULL;
773         }
774
775       g_assert (type_string == NULL);
776       type_string = "s";
777     }
778   else
779     {
780       if (!g_variant_type_string_is_valid (type_string))
781         {
782           g_set_error (error, G_MARKUP_ERROR,
783                        G_MARKUP_ERROR_INVALID_CONTENT,
784                        "invalid GVariant type string '%s'", type_string);
785           return NULL;
786         }
787
788       enum_data = NULL;
789     }
790
791   key = key_state_new (type_string, state->gettext_domain, enum_data);
792   g_hash_table_insert (state->keys, g_strdup (name), key);
793
794   return key;
795 }
796
797 /* Handling of toplevel state {{{1 */
798 typedef struct
799 {
800   GHashTable  *schema_table;            /* string -> SchemaState */
801   GHashTable  *enum_table;              /* string -> GString */
802
803   gchar       *schemalist_domain;       /* the <schemalist> gettext domain */
804
805   SchemaState *schema_state;            /* non-NULL when inside <schema> */
806   KeyState    *key_state;               /* non-NULL when inside <key> */
807   GString     *enum_state;              /* non-NULL when inside <enum> */
808
809   GString     *string;                  /* non-NULL when accepting text */
810 } ParseState;
811
812 static void
813 parse_state_start_schema (ParseState  *state,
814                           const gchar  *id,
815                           const gchar  *path,
816                           const gchar  *gettext_domain,
817                           GError      **error)
818 {
819   if (g_hash_table_lookup (state->schema_table, id))
820     {
821       g_set_error (error, G_MARKUP_ERROR,
822                    G_MARKUP_ERROR_INVALID_CONTENT,
823                    "<schema id='%s'> already specified", id);
824       return;
825     }
826
827   if (path && !(g_str_has_prefix (path, "/") && g_str_has_suffix (path, "/")))
828     {
829       g_set_error (error, G_MARKUP_ERROR,
830                    G_MARKUP_ERROR_INVALID_CONTENT,
831                    "a path, if given, must begin and "
832                    "end with a slash");
833       return;
834     }
835
836   state->schema_state = schema_state_new (path, gettext_domain);
837   g_hash_table_insert (state->schema_table, g_strdup (id),
838                        state->schema_state);
839 }
840
841 static void
842 parse_state_start_enum (ParseState   *state,
843                         const gchar  *id,
844                         GError      **error)
845 {
846   if (g_hash_table_lookup (state->enum_table, id))
847     {
848       g_set_error (error, G_MARKUP_ERROR,
849                    G_MARKUP_ERROR_INVALID_CONTENT,
850                    "<enum id='%s'> already specified", id);
851       return;
852     }
853
854   state->enum_state = g_string_new (NULL);
855   g_hash_table_insert (state->enum_table, g_strdup (id), state->enum_state);
856 }
857
858 /* GMarkup Parser Functions {{{1 */
859
860 /* Start element {{{2 */
861 static void
862 start_element (GMarkupParseContext  *context,
863                const gchar          *element_name,
864                const gchar         **attribute_names,
865                const gchar         **attribute_values,
866                gpointer              user_data,
867                GError              **error)
868 {
869   ParseState *state = user_data;
870   const GSList *element_stack;
871   const gchar *container;
872
873   element_stack = g_markup_parse_context_get_element_stack (context);
874   container = element_stack->next ? element_stack->next->data : NULL;
875
876 #define COLLECT(first, ...) \
877   g_markup_collect_attributes (element_name,                                 \
878                                attribute_names, attribute_values, error,     \
879                                first, __VA_ARGS__, G_MARKUP_COLLECT_INVALID)
880 #define OPTIONAL   G_MARKUP_COLLECT_OPTIONAL
881 #define STRDUP     G_MARKUP_COLLECT_STRDUP
882 #define STRING     G_MARKUP_COLLECT_STRING
883 #define NO_ATTRS()  COLLECT (G_MARKUP_COLLECT_INVALID, NULL)
884
885   /* Toplevel items {{{3 */
886   if (container == NULL)
887     {
888       if (strcmp (element_name, "schemalist") == 0)
889         {
890           COLLECT (OPTIONAL | STRDUP,
891                    "gettext-domain",
892                    &state->schemalist_domain);
893           return;
894         }
895     }
896
897
898   /* children of <schemalist> {{{3 */
899   else if (strcmp (container, "schemalist") == 0)
900     {
901       if (strcmp (element_name, "schema") == 0)
902         {
903           const gchar *id, *path, *gettext_domain;
904           if (COLLECT (STRING, "id", &id,
905                        OPTIONAL | STRING, "path", &path,
906                        OPTIONAL | STRDUP, "gettext-domain", &gettext_domain))
907             parse_state_start_schema (state, id, path, gettext_domain, error);
908           return;
909         }
910
911       else if (strcmp (element_name, "enum") == 0)
912         {
913           const gchar *id;
914           if (COLLECT (STRING, "id", &id))
915             parse_state_start_enum (state, id, error);
916           return;
917         }
918     }
919
920
921   /* children of <schema> {{{3 */
922   else if (strcmp (container, "schema") == 0)
923     {
924       if (strcmp (element_name, "key") == 0)
925         {
926           const gchar *name, *type_string, *enum_type;
927
928           if (COLLECT (STRING,            "name", &name,
929                        OPTIONAL | STRING, "type", &type_string,
930                        OPTIONAL | STRING, "enum", &enum_type))
931
932             state->key_state = schema_state_add_key (state->schema_state,
933                                                      state->enum_table,
934                                                      name, type_string,
935                                                      enum_type, error);
936           return;
937         }
938       else if (strcmp (element_name, "child") == 0)
939         {
940           const gchar *name, *schema;
941
942           if (COLLECT (STRING, "name", &name, STRING, "schema", &schema))
943             schema_state_add_child (state->schema_state,
944                                     name, schema, error);
945           return;
946         }
947     }
948
949
950   /* children of <key> {{{3 */
951   else if (strcmp (container, "key") == 0)
952     {
953       if (strcmp (element_name, "default") == 0)
954         {
955           const gchar *l10n, *context;
956           if (COLLECT (STRING | OPTIONAL, "l10n",    &l10n,
957                        STRING | OPTIONAL, "context", &context))
958             state->string = key_state_start_default (state->key_state,
959                                                      l10n, context, error);
960           return;
961         }
962
963       else if (strcmp (element_name, "summary") == 0 ||
964                strcmp (element_name, "description") == 0)
965         {
966           if (NO_ATTRS ())
967             state->string = g_string_new (NULL);
968           return;
969         }
970
971       else if (strcmp (element_name, "range") == 0)
972         {
973           const gchar *min, *max;
974           if (COLLECT (STRING, "min", &min, STRING, "max", &max))
975             key_state_set_range (state->key_state, min, max, error);
976           return;
977         }
978
979       else if (strcmp (element_name, "choices") == 0)
980         {
981           if (NO_ATTRS ())
982             key_state_start_choices (state->key_state, error);
983           return;
984         }
985
986       else if (strcmp (element_name, "aliases") == 0)
987         {
988           if (NO_ATTRS ())
989             key_state_start_aliases (state->key_state, error);
990           return;
991         }
992     }
993
994
995   /* children of <choices> {{{3 */
996   else if (strcmp (container, "choices") == 0)
997     {
998       if (strcmp (element_name, "choice") == 0)
999         {
1000           const gchar *value;
1001           if (COLLECT (STRING, "value", &value))
1002             key_state_add_choice (state->key_state, value, error);
1003           return;
1004         }
1005     }
1006
1007
1008   /* children of <aliases> {{{3 */
1009   else if (strcmp (container, "aliases") == 0)
1010     {
1011       if (strcmp (element_name, "alias") == 0)
1012         {
1013           const gchar *value, *target;
1014           if (COLLECT (STRING, "value", &value, STRING, "target", &target))
1015             key_state_add_alias (state->key_state, value, target, error);
1016           return;
1017         }
1018     }
1019
1020
1021   /* children of <enum> {{{3 */
1022   else if (strcmp (container, "enum") == 0)
1023     {
1024       if (strcmp (element_name, "value") == 0)
1025         {
1026           const gchar *nick, *valuestr;
1027           if (COLLECT (STRING, "nick", &nick,
1028                        STRING, "value", &valuestr))
1029             enum_state_add_value (state->enum_state, nick, valuestr, error);
1030           return;
1031         }
1032     }
1033   /* 3}}} */
1034
1035   if (container)
1036     g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1037                  "Element <%s> not allowed inside <%s>",
1038                  element_name, container);
1039   else
1040     g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT,
1041                  "Element <%s> not allowed at toplevel", element_name);
1042 }
1043 /* 2}}} */
1044 /* End element {{{2 */
1045
1046 static void
1047 key_state_end (KeyState **state_ptr,
1048                GError   **error)
1049 {
1050   KeyState *state;
1051
1052   state = *state_ptr;
1053   *state_ptr = NULL;
1054
1055   if (state->default_value == NULL)
1056     {
1057       g_set_error_literal (error,
1058                            G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1059                            "element <default> is required in <key>");
1060       return;
1061     }
1062 }
1063
1064 static void
1065 schema_state_end (SchemaState **state_ptr,
1066                   GError      **error)
1067 {
1068   SchemaState *state;
1069
1070   state = *state_ptr;
1071   *state_ptr = NULL;
1072 }
1073
1074 static void
1075 end_element (GMarkupParseContext  *context,
1076              const gchar          *element_name,
1077              gpointer              user_data,
1078              GError              **error)
1079 {
1080   ParseState *state = user_data;
1081
1082   if (strcmp (element_name, "schemalist") == 0)
1083     {
1084       g_free (state->schemalist_domain);
1085       state->schemalist_domain = NULL;
1086     }
1087
1088   else if (strcmp (element_name, "enum") == 0)
1089     enum_state_end (&state->enum_state, error);
1090
1091   else if (strcmp (element_name, "schema") == 0)
1092     schema_state_end (&state->schema_state, error);
1093
1094   else if (strcmp (element_name, "key") == 0)
1095     key_state_end (&state->key_state, error);
1096
1097   else if (strcmp (element_name, "default") == 0)
1098     key_state_end_default (state->key_state, &state->string, error);
1099
1100   else if (strcmp (element_name, "choices") == 0)
1101     key_state_end_choices (state->key_state, error);
1102
1103   else if (strcmp (element_name, "aliases") == 0)
1104     key_state_end_aliases (state->key_state, error);
1105
1106   if (state->string)
1107     {
1108       g_string_free (state->string, TRUE);
1109       state->string = NULL;
1110     }
1111 }
1112 /* Text {{{2 */
1113 static void
1114 text (GMarkupParseContext  *context,
1115       const gchar          *text,
1116       gsize                 text_len,
1117       gpointer              user_data,
1118       GError              **error)
1119 {
1120   ParseState *state = user_data;
1121   gsize i;
1122
1123   for (i = 0; i < text_len; i++)
1124     if (!g_ascii_isspace (text[i]))
1125       {
1126         if (state->string)
1127           g_string_append_len (state->string, text, text_len);
1128
1129         else
1130           g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT,
1131                        "text may not appear inside <%s>",
1132                        g_markup_parse_context_get_element (context));
1133
1134         break;
1135       }
1136 }
1137
1138 /* Write to GVDB {{{1 */
1139 typedef struct
1140 {
1141   GHashTable *table;
1142   GvdbItem *root;
1143 } GvdbPair;
1144
1145 static void
1146 gvdb_pair_init (GvdbPair *pair)
1147 {
1148   pair->table = gvdb_hash_table_new (NULL, NULL);
1149   pair->root = gvdb_hash_table_insert (pair->table, "");
1150 }
1151
1152 typedef struct
1153 {
1154   GvdbPair pair;
1155   gboolean l10n;
1156 } OutputSchemaData;
1157
1158 static void
1159 output_key (gpointer key,
1160             gpointer value,
1161             gpointer user_data)
1162 {
1163   OutputSchemaData *data;
1164   const gchar *name;
1165   KeyState *state;
1166   GvdbItem *item;
1167
1168   name = key;
1169   state = value;
1170   data = user_data;
1171
1172   item = gvdb_hash_table_insert (data->pair.table, name);
1173   gvdb_item_set_parent (item, data->pair.root);
1174   gvdb_item_set_value (item, key_state_serialise (state));
1175
1176   if (state->l10n)
1177     data->l10n = TRUE;
1178 }
1179
1180 static void
1181 output_schema (gpointer key,
1182                gpointer value,
1183                gpointer user_data)
1184 {
1185   OutputSchemaData data;
1186   GvdbPair *root_pair;
1187   SchemaState *state;
1188   const gchar *id;
1189   GvdbItem *item;
1190
1191   id = key;
1192   state = value;
1193   root_pair = user_data;
1194
1195   gvdb_pair_init (&data.pair);
1196   data.l10n = FALSE;
1197
1198   item = gvdb_hash_table_insert (root_pair->table, id);
1199   gvdb_item_set_parent (item, root_pair->root);
1200   gvdb_item_set_hash_table (item, data.pair.table);
1201
1202   g_hash_table_foreach (state->keys, output_key, &data);
1203
1204   if (state->path)
1205     gvdb_hash_table_insert_string (data.pair.table, ".path", state->path);
1206
1207   if (data.l10n)
1208     gvdb_hash_table_insert_string (data.pair.table,
1209                                    ".gettext-domain",
1210                                    state->gettext_domain);
1211 }
1212
1213 static gboolean
1214 write_to_file (GHashTable   *schema_table,
1215                const gchar  *filename,
1216                GError      **error)
1217 {
1218   gboolean success;
1219   GvdbPair pair;
1220
1221   gvdb_pair_init (&pair);
1222
1223   g_hash_table_foreach (schema_table, output_schema, &pair);
1224
1225   success = gvdb_table_write_contents (pair.table, filename,
1226                                        G_BYTE_ORDER != G_LITTLE_ENDIAN,
1227                                        error);
1228   g_hash_table_unref (pair.table);
1229
1230   return success;
1231 }
1232
1233 /* Parser driver {{{1 */
1234 static GHashTable *
1235 parse_gschema_files (gchar  **files,
1236                      GError **error)
1237 {
1238   GMarkupParser parser = { start_element, end_element, text };
1239   GMarkupParseContext *context;
1240   ParseState state = { 0, };
1241   const gchar *filename;
1242
1243   context = g_markup_parse_context_new (&parser,
1244                                         G_MARKUP_PREFIX_ERROR_POSITION,
1245                                         &state, NULL);
1246
1247   state.enum_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1248                                             g_free, enum_state_free);
1249
1250   state.schema_table = g_hash_table_new_full (g_str_hash, g_str_equal,
1251                                               g_free, schema_state_free);
1252
1253   while ((filename = *files++) != NULL)
1254     {
1255       gchar *contents;
1256       gsize size;
1257
1258       if (!g_file_get_contents (filename, &contents, &size, error))
1259         return FALSE;
1260
1261       if (!g_markup_parse_context_parse (context, contents, size, error))
1262         {
1263           g_prefix_error (error, "%s: ", filename);
1264           return FALSE;
1265         }
1266
1267       if (!g_markup_parse_context_end_parse (context, error))
1268         {
1269           g_prefix_error (error, "%s: ", filename);
1270           return FALSE;
1271         }
1272     }
1273
1274   g_hash_table_unref (state.enum_table);
1275
1276   return state.schema_table;
1277 }
1278
1279 static gint
1280 compare_strings (gconstpointer a,
1281                  gconstpointer b)
1282 {
1283   gchar *one = *(gchar **) a;
1284   gchar *two = *(gchar **) b;
1285
1286   return strcmp (one, two);
1287 }
1288
1289 int
1290 main (int argc, char **argv)
1291 {
1292   GError *error;
1293   GHashTable *table;
1294   GDir *dir;
1295   const gchar *file;
1296   gchar *srcdir;
1297   gchar *targetdir = NULL;
1298   gchar *target;
1299   gboolean uninstall = FALSE;
1300   gboolean dry_run = FALSE;
1301   gchar **schema_files = NULL;
1302   GOptionContext *context;
1303   GOptionEntry entries[] = {
1304     { "targetdir", 0, 0, G_OPTION_ARG_FILENAME, &targetdir, N_("where to store the gschemas.compiled file"), N_("DIRECTORY") },
1305     { "dry-run", 0, 0, G_OPTION_ARG_NONE, &dry_run, N_("Do not write the gschema.compiled file"), NULL },
1306     { "uninstall", 0, 0, G_OPTION_ARG_NONE, &uninstall, N_("Do not give error for empty directory"), NULL },
1307     { "allow-any-name", 0, 0, G_OPTION_ARG_NONE, &allow_any_name, N_("Do not enforce key name restrictions") },
1308
1309     /* These options are only for use in the gschema-compile tests */
1310     { "schema-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &schema_files, NULL, NULL },
1311     { NULL }
1312   };
1313
1314   setlocale (LC_ALL, "");
1315
1316   context = g_option_context_new (N_("DIRECTORY"));
1317   g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
1318   g_option_context_set_summary (context,
1319     N_("Compile all GSettings schema files into a schema cache.\n"
1320        "Schema files are required to have the extension .gschema.xml,\n"
1321        "and the cache file is called gschemas.compiled."));
1322   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
1323
1324   error = NULL;
1325   if (!g_option_context_parse (context, &argc, &argv, &error))
1326     {
1327       fprintf (stderr, "%s", error->message);
1328       return 1;
1329     }
1330
1331   g_option_context_free (context);
1332
1333   if (!schema_files && argc != 2)
1334     {
1335       fprintf (stderr, _("You should give exactly one directory name\n"));
1336       return 1;
1337     }
1338
1339   srcdir = argv[1];
1340
1341   if (targetdir == NULL)
1342     targetdir = srcdir;
1343
1344   target = g_build_filename (targetdir, "gschemas.compiled", NULL);
1345
1346   if (!schema_files)
1347     {
1348       GPtrArray *files;
1349
1350       files = g_ptr_array_new ();
1351
1352       dir = g_dir_open (srcdir, 0, &error);
1353       if (dir == NULL)
1354         {
1355           fprintf (stderr, "%s\n", error->message);
1356           return 1;
1357         }
1358
1359       while ((file = g_dir_read_name (dir)) != NULL)
1360         {
1361           if (g_str_has_suffix (file, ".gschema.xml") ||
1362               g_str_has_suffix (file, ".enums.xml"))
1363             g_ptr_array_add (files, g_build_filename (srcdir, file, NULL));
1364         }
1365
1366       if (files->len == 0)
1367         {
1368           if (uninstall)
1369             {
1370               g_unlink (target);
1371               return 0;
1372             }
1373           else
1374             {
1375               fprintf (stderr, _("No schema files found\n"));
1376               return 1;
1377             }
1378         }
1379       g_ptr_array_sort (files, compare_strings);
1380       g_ptr_array_add (files, NULL);
1381
1382       schema_files = (char **) g_ptr_array_free (files, FALSE);
1383     }
1384
1385
1386   if (!(table = parse_gschema_files (schema_files, &error)) ||
1387       (!dry_run && !write_to_file (table, target, &error)))
1388     {
1389       fprintf (stderr, "%s\n", error->message);
1390       return 1;
1391     }
1392
1393   g_free (target);
1394
1395   return 0;
1396 }
1397
1398 /* Epilogue {{{1 */
1399
1400 /* vim:set foldmethod=marker: */