Add non-aborting g_settings_schema_source_lookup()
[platform/upstream/glib.git] / gio / gsettingsschema.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
20 #include "config.h"
21
22 #include "gsettingsschema-internal.h"
23 #include "gsettings.h"
24
25 #include "gvdb/gvdb-reader.h"
26 #include "strinfo.c"
27
28 #include <glibintl.h>
29 #include <string.h>
30
31 struct _GSettingsSchema
32 {
33   const gchar *gettext_domain;
34   const gchar *path;
35   GQuark *items;
36   gint n_items;
37   GvdbTable *table;
38   gchar *name;
39
40   gint ref_count;
41 };
42
43 typedef struct _GSettingsSchemaSource GSettingsSchemaSource;
44
45 struct _GSettingsSchemaSource
46 {
47   GSettingsSchemaSource *parent;
48   GvdbTable *table;
49
50   gint ref_count;
51 };
52
53 static GSettingsSchemaSource *schema_sources;
54
55 static void
56 prepend_schema_table (GvdbTable *table)
57 {
58   GSettingsSchemaSource *source;
59
60   /* we steal the reference from 'schema_sources' for our ->parent */
61   source = g_slice_new (GSettingsSchemaSource);
62   source->parent = schema_sources;
63   source->table = table;
64   source->ref_count = 1;
65
66   schema_sources = source;
67 }
68
69 GSettingsSchemaSource *
70 g_settings_schema_source_ref (GSettingsSchemaSource *source)
71 {
72   g_atomic_int_inc (&source->ref_count);
73
74   return source;
75 }
76
77 void
78 g_settings_schema_source_unref (GSettingsSchemaSource *source)
79 {
80   if (g_atomic_int_dec_and_test (&source->ref_count))
81     {
82       if (source == schema_sources)
83         g_error ("g_settings_schema_source_unref() called too many times on the default schema source");
84
85       g_settings_schema_source_unref (source->parent);
86       gvdb_table_unref (source->table);
87
88       g_slice_free (GSettingsSchemaSource, source);
89     }
90 }
91
92 static void
93 initialise_schema_sources (void)
94 {
95   static gsize initialised;
96
97   /* need a separate variable because 'schema_sources' may legitimately
98    * be null if we have zero valid schema sources
99    */
100   if G_UNLIKELY (g_once_init_enter (&initialised))
101     {
102       const gchar * const *dirs;
103       const gchar *path;
104       gint i;
105
106       /* iterate in reverse: count up, then count down */
107       dirs = g_get_system_data_dirs ();
108       for (i = 0; dirs[i]; i++);
109
110       while (i--)
111         {
112           gchar *filename;
113           GvdbTable *table;
114
115           filename = g_build_filename (dirs[i], "glib-2.0", "schemas", "gschemas.compiled", NULL);
116           table = gvdb_table_new (filename, TRUE, NULL);
117
118           if (table != NULL)
119             prepend_schema_table (table);
120
121           g_free (filename);
122         }
123
124       if ((path = g_getenv ("GSETTINGS_SCHEMA_DIR")) != NULL)
125         {
126           gchar *filename;
127           GvdbTable *table;
128
129           filename = g_build_filename (path, "gschemas.compiled", NULL);
130           table = gvdb_table_new (filename, TRUE, NULL);
131
132           if (table != NULL)
133             prepend_schema_table (table);
134
135           g_free (filename);
136         }
137
138       g_once_init_leave (&initialised, TRUE);
139     }
140 }
141
142 GSettingsSchemaSource *
143 g_settings_schema_source_get_default (void)
144 {
145   initialise_schema_sources ();
146
147   return schema_sources;
148 }
149
150 GSettingsSchema *
151 g_settings_schema_source_lookup (GSettingsSchemaSource *source,
152                                  const gchar           *schema_name,
153                                  gboolean               recursive)
154 {
155   GSettingsSchema *schema;
156   GvdbTable *table;
157
158   g_return_val_if_fail (source != NULL, NULL);
159   g_return_val_if_fail (schema_name != NULL, NULL);
160
161   table = gvdb_table_get_table (source->table, schema_name);
162
163   if (table == NULL && recursive)
164     for (source = source->parent; source; source = source->parent)
165       if ((table = gvdb_table_get_table (source->table, schema_name)))
166         break;
167
168   if (table == NULL)
169     return NULL;
170
171   schema = g_slice_new0 (GSettingsSchema);
172   schema->ref_count = 1;
173   schema->name = g_strdup (schema_name);
174   schema->table = table;
175   schema->path = g_settings_schema_get_string (schema, ".path");
176   schema->gettext_domain = g_settings_schema_get_string (schema, ".gettext-domain");
177
178   if (schema->gettext_domain)
179     bind_textdomain_codeset (schema->gettext_domain, "UTF-8");
180
181   return schema;
182 }
183
184 static gboolean
185 steal_item (gpointer key,
186             gpointer value,
187             gpointer user_data)
188 {
189   gchar ***ptr = user_data;
190
191   *(*ptr)++ = (gchar *) key;
192
193   return TRUE;
194 }
195
196 static const gchar * const *non_relocatable_schema_list;
197 static const gchar * const *relocatable_schema_list;
198 static gsize schema_lists_initialised;
199
200 static void
201 ensure_schema_lists (void)
202 {
203   if (g_once_init_enter (&schema_lists_initialised))
204     {
205       GSettingsSchemaSource *source;
206       GHashTable *single, *reloc;
207       const gchar **ptr;
208       gchar **list;
209       gint i;
210
211       initialise_schema_sources ();
212
213       /* We use hash tables to avoid duplicate listings for schemas that
214        * appear in more than one file.
215        */
216       single = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
217       reloc = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
218
219       for (source = schema_sources; source; source = source->parent)
220         {
221           list = gvdb_table_list (source->table, "");
222
223           g_assert (list != NULL);
224
225           for (i = 0; list[i]; i++)
226             {
227               if (!g_hash_table_lookup (single, list[i]) &&
228                   !g_hash_table_lookup (reloc, list[i]))
229                 {
230                   GvdbTable *table;
231
232                   table = gvdb_table_get_table (source->table, list[i]);
233                   g_assert (table != NULL);
234
235                   if (gvdb_table_has_value (table, ".path"))
236                     g_hash_table_insert (single, g_strdup (list[i]), NULL);
237                   else
238                     g_hash_table_insert (reloc, g_strdup (list[i]), NULL);
239
240                   gvdb_table_unref (table);
241                 }
242             }
243
244           g_strfreev (list);
245         }
246
247       ptr = g_new (const gchar *, g_hash_table_size (single) + 1);
248       non_relocatable_schema_list = ptr;
249       g_hash_table_foreach_steal (single, steal_item, &ptr);
250       g_hash_table_unref (single);
251       *ptr = NULL;
252
253       ptr = g_new (const gchar *, g_hash_table_size (reloc) + 1);
254       relocatable_schema_list = ptr;
255       g_hash_table_foreach_steal (reloc, steal_item, &ptr);
256       g_hash_table_unref (reloc);
257       *ptr = NULL;
258
259       g_once_init_leave (&schema_lists_initialised, TRUE);
260     }
261 }
262
263 /**
264  * g_settings_list_schemas:
265  *
266  * Gets a list of the #GSettings schemas installed on the system.  The
267  * returned list is exactly the list of schemas for which you may call
268  * g_settings_new() without adverse effects.
269  *
270  * This function does not list the schemas that do not provide their own
271  * paths (ie: schemas for which you must use
272  * g_settings_new_with_path()).  See
273  * g_settings_list_relocatable_schemas() for that.
274  *
275  * Returns: (element-type utf8) (transfer none):  a list of #GSettings
276  *   schemas that are available.  The list must not be modified or
277  *   freed.
278  *
279  * Since: 2.26
280  **/
281 const gchar * const *
282 g_settings_list_schemas (void)
283 {
284   ensure_schema_lists ();
285
286   return non_relocatable_schema_list;
287 }
288
289 /**
290  * g_settings_list_relocatable_schemas:
291  *
292  * Gets a list of the relocatable #GSettings schemas installed on the
293  * system.  These are schemas that do not provide their own path.  It is
294  * usual to instantiate these schemas directly, but if you want to you
295  * can use g_settings_new_with_path() to specify the path.
296  *
297  * The output of this function, tTaken together with the output of
298  * g_settings_list_schemas() represents the complete list of all
299  * installed schemas.
300  *
301  * Returns: (element-type utf8) (transfer none): a list of relocatable
302  *   #GSettings schemas that are available.  The list must not be
303  *   modified or freed.
304  *
305  * Since: 2.28
306  **/
307 const gchar * const *
308 g_settings_list_relocatable_schemas (void)
309 {
310   ensure_schema_lists ();
311
312   return relocatable_schema_list;
313 }
314
315 GSettingsSchema *
316 g_settings_schema_ref (GSettingsSchema *schema)
317 {
318   g_atomic_int_inc (&schema->ref_count);
319
320   return schema;
321 }
322
323 void
324 g_settings_schema_unref (GSettingsSchema *schema)
325 {
326   if (g_atomic_int_dec_and_test (&schema->ref_count))
327     {
328       gvdb_table_unref (schema->table);
329       g_free (schema->items);
330       g_free (schema->name);
331
332       g_slice_free (GSettingsSchema, schema);
333     }
334 }
335
336 const gchar *
337 g_settings_schema_get_string (GSettingsSchema *schema,
338                               const gchar     *key)
339 {
340   const gchar *result = NULL;
341   GVariant *value;
342
343   if ((value = gvdb_table_get_raw_value (schema->table, key)))
344     {
345       result = g_variant_get_string (value, NULL);
346       g_variant_unref (value);
347     }
348
349   return result;
350 }
351
352 GSettingsSchema *
353 g_settings_schema_new (const gchar *name)
354 {
355   GSettingsSchemaSource *source;
356   GSettingsSchema *schema;
357
358   source = g_settings_schema_source_get_default ();
359
360   if (source == NULL)
361     g_error ("No GSettings schemas are installed on the system");
362
363   schema = g_settings_schema_source_lookup (source, name, TRUE);
364
365   if (schema == NULL)
366     g_error ("Settings schema '%s' is not installed\n", name);
367
368   return schema;
369 }
370
371 GVariantIter *
372 g_settings_schema_get_value (GSettingsSchema *schema,
373                              const gchar     *key)
374 {
375   GVariantIter *iter;
376   GVariant *value;
377
378   value = gvdb_table_get_raw_value (schema->table, key);
379
380   if G_UNLIKELY (value == NULL)
381     g_error ("Settings schema '%s' does not contain a key named '%s'",
382              schema->name, key);
383
384   iter = g_variant_iter_new (value);
385   g_variant_unref (value);
386
387   return iter;
388 }
389
390 const gchar *
391 g_settings_schema_get_path (GSettingsSchema *schema)
392 {
393   return schema->path;
394 }
395
396 const gchar *
397 g_settings_schema_get_gettext_domain (GSettingsSchema *schema)
398 {
399   return schema->gettext_domain;
400 }
401
402 gboolean
403 g_settings_schema_has_key (GSettingsSchema *schema,
404                            const gchar     *key)
405 {
406   return gvdb_table_has_value (schema->table, key);
407 }
408
409 const GQuark *
410 g_settings_schema_list (GSettingsSchema *schema,
411                         gint            *n_items)
412 {
413   gint i, j;
414
415   if (schema->items == NULL)
416     {
417       gchar **list;
418       gint len;
419
420       list = gvdb_table_list (schema->table, "");
421       len = list ? g_strv_length (list) : 0;
422
423       schema->items = g_new (GQuark, len);
424       j = 0;
425
426       for (i = 0; i < len; i++)
427         if (list[i][0] != '.')
428           schema->items[j++] = g_quark_from_string (list[i]);
429       schema->n_items = j;
430
431       g_strfreev (list);
432     }
433
434   *n_items = schema->n_items;
435   return schema->items;
436 }
437
438 const gchar *
439 g_settings_schema_get_name (GSettingsSchema *schema)
440 {
441   return schema->name;
442 }
443
444 static inline void
445 endian_fixup (GVariant **value)
446 {
447 #if G_BYTE_ORDER == G_BIG_ENDIAN
448   GVariant *tmp;
449
450   tmp = g_variant_byteswap (*value);
451   g_variant_unref (*value);
452   *value = tmp;
453 #endif
454 }
455
456 void
457 g_settings_schema_key_init (GSettingsSchemaKey *key,
458                             GSettingsSchema    *schema,
459                             const gchar        *name)
460 {
461   GVariantIter *iter;
462   GVariant *data;
463   guchar code;
464
465   memset (key, 0, sizeof *key);
466
467   iter = g_settings_schema_get_value (schema, name);
468
469   key->schema = g_settings_schema_ref (schema);
470   key->default_value = g_variant_iter_next_value (iter);
471   endian_fixup (&key->default_value);
472   key->type = g_variant_get_type (key->default_value);
473   key->name = g_intern_string (name);
474
475   while (g_variant_iter_next (iter, "(y*)", &code, &data))
476     {
477       switch (code)
478         {
479         case 'l':
480           /* translation requested */
481           g_variant_get (data, "(y&s)", &key->lc_char, &key->unparsed);
482           break;
483
484         case 'e':
485           /* enumerated types... */
486           key->is_enum = TRUE;
487           goto choice;
488
489         case 'f':
490           /* flags... */
491           key->is_flags = TRUE;
492           goto choice;
493
494         choice: case 'c':
495           /* ..., choices, aliases */
496           key->strinfo = g_variant_get_fixed_array (data, &key->strinfo_length, sizeof (guint32));
497           break;
498
499         case 'r':
500           g_variant_get (data, "(**)", &key->minimum, &key->maximum);
501           endian_fixup (&key->minimum);
502           endian_fixup (&key->maximum);
503           break;
504
505         default:
506           g_warning ("unknown schema extension '%c'", code);
507           break;
508         }
509
510       g_variant_unref (data);
511     }
512
513   g_variant_iter_free (iter);
514 }
515
516 void
517 g_settings_schema_key_clear (GSettingsSchemaKey *key)
518 {
519   if (key->minimum)
520     g_variant_unref (key->minimum);
521
522   if (key->maximum)
523     g_variant_unref (key->maximum);
524
525   g_variant_unref (key->default_value);
526
527   g_settings_schema_unref (key->schema);
528 }
529
530 gboolean
531 g_settings_schema_key_type_check (GSettingsSchemaKey *key,
532                                   GVariant           *value)
533 {
534   g_return_val_if_fail (value != NULL, FALSE);
535
536   return g_variant_is_of_type (value, key->type);
537 }
538
539 gboolean
540 g_settings_schema_key_range_check (GSettingsSchemaKey *key,
541                                    GVariant           *value)
542 {
543   if (key->minimum == NULL && key->strinfo == NULL)
544     return TRUE;
545
546   if (g_variant_is_container (value))
547     {
548       gboolean ok = TRUE;
549       GVariantIter iter;
550       GVariant *child;
551
552       g_variant_iter_init (&iter, value);
553       while (ok && (child = g_variant_iter_next_value (&iter)))
554         {
555           ok = g_settings_schema_key_range_check (key, child);
556           g_variant_unref (child);
557         }
558
559       return ok;
560     }
561
562   if (key->minimum)
563     {
564       return g_variant_compare (key->minimum, value) <= 0 &&
565              g_variant_compare (value, key->maximum) <= 0;
566     }
567
568   return strinfo_is_string_valid (key->strinfo, key->strinfo_length,
569                                   g_variant_get_string (value, NULL));
570 }
571
572 GVariant *
573 g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
574                                    GVariant           *value)
575 {
576   const gchar *target;
577
578   if (g_settings_schema_key_range_check (key, value))
579     return g_variant_ref (value);
580
581   if (key->strinfo == NULL)
582     return NULL;
583
584   if (g_variant_is_container (value))
585     {
586       GVariantBuilder builder;
587       GVariantIter iter;
588       GVariant *child;
589
590       g_variant_iter_init (&iter, value);
591       g_variant_builder_init (&builder, g_variant_get_type (value));
592
593       while ((child = g_variant_iter_next_value (&iter)))
594         {
595           GVariant *fixed;
596
597           fixed = g_settings_schema_key_range_fixup (key, child);
598           g_variant_unref (child);
599
600           if (fixed == NULL)
601             {
602               g_variant_builder_clear (&builder);
603               return NULL;
604             }
605
606           g_variant_builder_add_value (&builder, fixed);
607           g_variant_unref (fixed);
608         }
609
610       return g_variant_ref_sink (g_variant_builder_end (&builder));
611     }
612
613   target = strinfo_string_from_alias (key->strinfo, key->strinfo_length,
614                                       g_variant_get_string (value, NULL));
615   return target ? g_variant_ref_sink (g_variant_new_string (target)) : NULL;
616 }
617
618
619 GVariant *
620 g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
621 {
622   const gchar *translated;
623   GError *error = NULL;
624   const gchar *domain;
625   GVariant *value;
626
627   domain = g_settings_schema_get_gettext_domain (key->schema);
628
629   if (key->lc_char == '\0')
630     /* translation not requested for this key */
631     return NULL;
632
633   if (key->lc_char == 't')
634     translated = g_dcgettext (domain, key->unparsed, LC_TIME);
635   else
636     translated = g_dgettext (domain, key->unparsed);
637
638   if (translated == key->unparsed)
639     /* the default value was not translated */
640     return NULL;
641
642   /* try to parse the translation of the unparsed default */
643   value = g_variant_parse (key->type, translated, NULL, NULL, &error);
644
645   if (value == NULL)
646     {
647       g_warning ("Failed to parse translated string `%s' for "
648                  "key `%s' in schema `%s': %s", key->unparsed, key->name,
649                  g_settings_schema_get_name (key->schema), error->message);
650       g_warning ("Using untranslated default instead.");
651       g_error_free (error);
652     }
653
654   else if (!g_settings_schema_key_range_check (key, value))
655     {
656       g_warning ("Translated default `%s' for key `%s' in schema `%s' "
657                  "is outside of valid range", key->unparsed, key->name,
658                  g_settings_schema_get_name (key->schema));
659       g_variant_unref (value);
660       value = NULL;
661     }
662
663   return value;
664 }
665
666 gint
667 g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
668                                GVariant           *value)
669 {
670   gboolean it_worked;
671   guint result;
672
673   it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length,
674                                         g_variant_get_string (value, NULL),
675                                         &result);
676
677   /* 'value' can only come from the backend after being filtered for validity,
678    * from the translation after being filtered for validity, or from the schema
679    * itself (which the schema compiler checks for validity).  If this assertion
680    * fails then it's really a bug in GSettings or the schema compiler...
681    */
682   g_assert (it_worked);
683
684   return result;
685 }
686
687 GVariant *
688 g_settings_schema_key_from_enum (GSettingsSchemaKey *key,
689                                  gint                value)
690 {
691   const gchar *string;
692
693   string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, value);
694
695   if (string == NULL)
696     return NULL;
697
698   return g_variant_new_string (string);
699 }
700
701 guint
702 g_settings_schema_key_to_flags (GSettingsSchemaKey *key,
703                                 GVariant           *value)
704 {
705   GVariantIter iter;
706   const gchar *flag;
707   guint result;
708
709   result = 0;
710   g_variant_iter_init (&iter, value);
711   while (g_variant_iter_next (&iter, "&s", &flag))
712     {
713       gboolean it_worked;
714       guint flag_value;
715
716       it_worked = strinfo_enum_from_string (key->strinfo, key->strinfo_length, flag, &flag_value);
717       /* as in g_settings_to_enum() */
718       g_assert (it_worked);
719
720       result |= flag_value;
721     }
722
723   return result;
724 }
725
726 GVariant *
727 g_settings_schema_key_from_flags (GSettingsSchemaKey *key,
728                                   guint               value)
729 {
730   GVariantBuilder builder;
731   gint i;
732
733   g_variant_builder_init (&builder, G_VARIANT_TYPE ("as"));
734
735   for (i = 0; i < 32; i++)
736     if (value & (1u << i))
737       {
738         const gchar *string;
739
740         string = strinfo_string_from_enum (key->strinfo, key->strinfo_length, 1u << i);
741
742         if (string == NULL)
743           {
744             g_variant_builder_clear (&builder);
745             return NULL;
746           }
747
748         g_variant_builder_add (&builder, "s", string);
749       }
750
751   return g_variant_builder_end (&builder);
752 }