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