Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / gsettings-tool.c
1 /*
2  * Copyright © 2010 Codethink Limited
3  *
4  * SPDX-License-Identifier: LGPL-2.1-or-later
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Author: Ryan Lortie <desrt@desrt.ca>
20  */
21
22 #include "config.h"
23
24 #include <gio/gio.h>
25 #include <gi18n.h>
26 #include <locale.h>
27 #include <string.h>
28 #include <stdlib.h>
29
30 #include "glib/glib-private.h"
31
32 static GSettingsSchemaSource   *global_schema_source;
33 static GSettings               *global_settings;
34 static GSettingsSchema         *global_schema;
35 static GSettingsSchemaKey      *global_schema_key;
36 const gchar                    *global_key;
37 const gchar                    *global_value;
38
39 static gboolean
40 is_relocatable_schema (GSettingsSchema *schema)
41 {
42   return g_settings_schema_get_path (schema) == NULL;
43 }
44
45 static gboolean
46 check_relocatable_schema (GSettingsSchema *schema,
47                           const gchar     *schema_id)
48 {
49   if (schema == NULL)
50     {
51       g_printerr (_("No such schema “%s”\n"), schema_id);
52       return FALSE;
53     }
54
55   if (!is_relocatable_schema (schema))
56     {
57       g_printerr (_("Schema “%s” is not relocatable "
58                     "(path must not be specified)\n"),
59                   schema_id);
60       return FALSE;
61     }
62
63   return TRUE;
64 }
65
66 static gboolean
67 check_schema (GSettingsSchema *schema,
68               const gchar *schema_id)
69 {
70   if (schema == NULL)
71     {
72       g_printerr (_("No such schema “%s”\n"), schema_id);
73       return FALSE;
74     }
75
76   if (is_relocatable_schema (schema))
77     {
78       g_printerr (_("Schema “%s” is relocatable "
79                     "(path must be specified)\n"),
80                   schema_id);
81       return FALSE;
82     }
83
84   return TRUE;
85 }
86
87 static gboolean
88 check_path (const gchar *path)
89 {
90   if (path[0] == '\0')
91     {
92       g_printerr (_("Empty path given.\n"));
93       return FALSE;
94     }
95
96   if (path[0] != '/')
97     {
98       g_printerr (_("Path must begin with a slash (/)\n"));
99       return FALSE;
100     }
101
102   if (!g_str_has_suffix (path, "/"))
103     {
104       g_printerr (_("Path must end with a slash (/)\n"));
105       return FALSE;
106     }
107
108   if (strstr (path, "//"))
109     {
110       g_printerr (_("Path must not contain two adjacent slashes (//)\n"));
111       return FALSE;
112     }
113
114   return TRUE;
115 }
116
117 static int
118 qsort_cmp (const void *a,
119            const void *b)
120 {
121   return g_strcmp0 (*(gchar* const*)a, *(gchar* const*)b);
122 }
123
124 static void
125 output_list (gchar **list)
126 {
127   gint i;
128
129   qsort (list, g_strv_length (list), sizeof (gchar*), qsort_cmp);
130   for (i = 0; list[i]; i++)
131     g_print ("%s\n", list[i]);
132 }
133
134 static void
135 gsettings_print_version (void)
136 {
137   g_print ("%d.%d.%d\n", glib_major_version, glib_minor_version,
138            glib_micro_version);
139 }
140
141 static void
142 gsettings_list_schemas (void)
143 {
144   gchar **schemas;
145
146   g_settings_schema_source_list_schemas (global_schema_source, TRUE, &schemas, NULL);
147   output_list (schemas);
148   g_strfreev (schemas);
149 }
150
151 static void
152 gsettings_list_schemas_with_paths (void)
153 {
154   gchar **schemas;
155   gsize i;
156
157   g_settings_schema_source_list_schemas (global_schema_source, TRUE, &schemas, NULL);
158
159   for (i = 0; schemas[i] != NULL; i++)
160     {
161       GSettingsSchema *schema;
162       gchar *schema_name;
163       const gchar *schema_path;
164
165       schema_name = g_steal_pointer (&schemas[i]);
166
167       schema = g_settings_schema_source_lookup (global_schema_source, schema_name, TRUE);
168       schema_path = g_settings_schema_get_path (schema);
169
170       schemas[i] = g_strconcat (schema_name, " ", schema_path, NULL);
171
172       g_settings_schema_unref (schema);
173       g_free (schema_name);
174     }
175
176   output_list (schemas);
177   g_strfreev (schemas);
178 }
179
180 static void
181 gsettings_list_relocatable_schemas (void)
182 {
183   gchar **schemas;
184
185   g_settings_schema_source_list_schemas (global_schema_source, TRUE, NULL, &schemas);
186   output_list (schemas);
187   g_strfreev (schemas);
188 }
189
190 static void
191 gsettings_list_keys (void)
192 {
193   gchar **keys;
194
195   keys = g_settings_schema_list_keys (global_schema);
196   output_list (keys);
197   g_strfreev (keys);
198 }
199
200 static void
201 gsettings_list_children (void)
202 {
203   gchar **children;
204   gsize max = 0;
205   gint i;
206
207   children = g_settings_list_children (global_settings);
208   qsort (children, g_strv_length (children), sizeof (gchar*), qsort_cmp);
209   for (i = 0; children[i]; i++)
210     {
211       gsize len = strlen (children[i]);
212       if (len > max)
213         max = len;
214     }
215
216   for (i = 0; children[i]; i++)
217     {
218       GSettings *child;
219       GSettingsSchema *schema;
220       gchar *path;
221
222       child = g_settings_get_child (global_settings, children[i]);
223       g_object_get (child,
224                     "settings-schema", &schema,
225                     "path", &path,
226                     NULL);
227
228       if (g_settings_schema_get_path (schema) != NULL)
229         g_print ("%-*s   %s\n", (int) MIN (max, G_MAXINT), children[i],
230                  g_settings_schema_get_id (schema));
231       else
232         g_print ("%-*s   %s:%s\n", (int) MIN (max, G_MAXINT), children[i],
233                  g_settings_schema_get_id (schema), path);
234
235       g_object_unref (child);
236       g_settings_schema_unref (schema);
237       g_free (path);
238     }
239
240   g_strfreev (children);
241 }
242
243 static void
244 enumerate (GSettings *settings)
245 {
246   gchar **keys;
247   GSettingsSchema *schema;
248   gint i;
249
250   g_object_get (settings, "settings-schema", &schema, NULL);
251
252   keys = g_settings_schema_list_keys (schema);
253   qsort (keys, g_strv_length (keys), sizeof (gchar*), qsort_cmp);
254   for (i = 0; keys[i]; i++)
255     {
256       GVariant *value;
257       gchar *printed;
258
259       value = g_settings_get_value (settings, keys[i]);
260       printed = g_variant_print (value, TRUE);
261       g_print ("%s %s %s\n", g_settings_schema_get_id (schema), keys[i], printed);
262       g_variant_unref (value);
263       g_free (printed);
264     }
265
266   g_settings_schema_unref (schema);
267   g_strfreev (keys);
268 }
269
270 static void
271 list_recursively (GSettings *settings)
272 {
273   gchar **children;
274   gint i;
275
276   enumerate (settings);
277   children = g_settings_list_children (settings);
278   qsort (children, g_strv_length (children), sizeof (gchar*), qsort_cmp);
279   for (i = 0; children[i]; i++)
280     {
281       gboolean will_see_elsewhere = FALSE;
282       GSettings *child;
283
284       child = g_settings_get_child (settings, children[i]);
285
286       if (global_settings == NULL)
287         {
288           /* we're listing all non-relocatable settings objects from the
289            * top-level, so if this one is non-relocatable, don't recurse,
290            * because we will pick it up later on.
291            */
292
293           GSettingsSchema *child_schema;
294
295           g_object_get (child, "settings-schema", &child_schema, NULL);
296           will_see_elsewhere = !is_relocatable_schema (child_schema);
297           g_settings_schema_unref (child_schema);
298         }
299
300       if (!will_see_elsewhere)
301         list_recursively (child);
302
303       g_object_unref (child);
304     }
305
306   g_strfreev (children);
307 }
308
309 static void
310 gsettings_list_recursively (void)
311 {
312   if (global_settings)
313     {
314       list_recursively (global_settings);
315     }
316   else
317     {
318       gchar **schemas;
319       gint i;
320
321       g_settings_schema_source_list_schemas (global_schema_source, TRUE, &schemas, NULL);
322       qsort (schemas, g_strv_length (schemas), sizeof (gchar*), qsort_cmp);
323
324       for (i = 0; schemas[i]; i++)
325         {
326           GSettings *settings;
327
328           settings = g_settings_new (schemas[i]);
329           list_recursively (settings);
330           g_object_unref (settings);
331         }
332
333       g_strfreev (schemas);
334     }
335 }
336
337 static void
338 gsettings_description (void)
339 {
340   const gchar *description;
341   description = g_settings_schema_key_get_description (global_schema_key);
342   if (description == NULL)
343     description = g_settings_schema_key_get_summary (global_schema_key);
344   g_print ("%s\n", description);
345 }
346
347 static void
348 gsettings_range (void)
349 {
350   GVariant *range, *detail;
351   const gchar *type;
352
353   range = g_settings_schema_key_get_range (global_schema_key);
354   g_variant_get (range, "(&sv)", &type, &detail);
355
356   if (strcmp (type, "type") == 0)
357     g_print ("type %s\n", g_variant_get_type_string (detail) + 1);
358
359   else if (strcmp (type, "range") == 0)
360     {
361       GVariant *min, *max;
362       gchar *smin, *smax;
363
364       g_variant_get (detail, "(**)", &min, &max);
365       smin = g_variant_print (min, FALSE);
366       smax = g_variant_print (max, FALSE);
367
368       g_print ("range %s %s %s\n",
369                g_variant_get_type_string (min), smin, smax);
370       g_variant_unref (min);
371       g_variant_unref (max);
372       g_free (smin);
373       g_free (smax);
374     }
375
376   else if (strcmp (type, "enum") == 0 || strcmp (type, "flags") == 0)
377     {
378       GVariantIter iter;
379       GVariant *item;
380
381       g_print ("%s\n", type);
382
383       g_variant_iter_init (&iter, detail);
384       while (g_variant_iter_loop (&iter, "*", &item))
385         {
386           gchar *printed;
387
388           printed = g_variant_print (item, FALSE);
389           g_print ("%s\n", printed);
390           g_free (printed);
391         }
392     }
393
394   g_variant_unref (detail);
395   g_variant_unref (range);
396 }
397
398 static void
399 gsettings_get (void)
400 {
401   GVariant *value;
402   gchar *printed;
403
404   value = g_settings_get_value (global_settings, global_key);
405   printed = g_variant_print (value, TRUE);
406   g_print ("%s\n", printed);
407   g_variant_unref (value);
408   g_free (printed);
409 }
410
411 static void
412 gsettings_reset (void)
413 {
414   g_settings_reset (global_settings, global_key);
415   g_settings_sync ();
416 }
417
418 static void
419 reset_all_keys (GSettings *settings)
420 {
421   GSettingsSchema *schema;
422   gchar **keys;
423   gint i;
424
425   g_object_get (settings, "settings-schema", &schema, NULL);
426
427   keys = g_settings_schema_list_keys (schema);
428   for (i = 0; keys[i]; i++)
429     {
430       g_settings_reset (settings, keys[i]);
431     }
432
433   g_settings_schema_unref (schema);
434   g_strfreev (keys);
435 }
436
437 static void
438 gsettings_reset_recursively (void)
439 {
440   gchar **children;
441   gint i;
442
443   g_settings_delay (global_settings);
444
445   reset_all_keys (global_settings);
446   children = g_settings_list_children (global_settings);
447   for (i = 0; children[i]; i++)
448     {
449       GSettings *child;
450       child = g_settings_get_child (global_settings, children[i]);
451
452       reset_all_keys (child);
453
454       g_object_unref (child);
455     }
456
457   g_strfreev (children);
458
459   g_settings_apply (global_settings);
460   g_settings_sync ();
461 }
462
463 static void
464 gsettings_writable (void)
465 {
466   g_print ("%s\n",
467            g_settings_is_writable (global_settings, global_key) ?
468            "true" : "false");
469 }
470
471 static void
472 value_changed (GSettings   *settings,
473                const gchar *key,
474                gpointer     user_data)
475 {
476   GVariant *value;
477   gchar *printed;
478
479   value = g_settings_get_value (settings, key);
480   printed = g_variant_print (value, TRUE);
481   g_print ("%s: %s\n", key, printed);
482   g_variant_unref (value);
483   g_free (printed);
484 }
485
486 static void
487 gsettings_monitor (void)
488 {
489   if (global_key)
490     {
491       gchar *name;
492
493       name = g_strdup_printf ("changed::%s", global_key);
494       g_signal_connect (global_settings, name, G_CALLBACK (value_changed), NULL);
495     }
496   else
497     g_signal_connect (global_settings, "changed", G_CALLBACK (value_changed), NULL);
498
499   for (;;)
500     g_main_context_iteration (NULL, TRUE);
501 }
502
503 static void
504 gsettings_set (void)
505 {
506   const GVariantType *type;
507   GError *error = NULL;
508   GVariant *new;
509   gchar *freeme = NULL;
510
511   type = g_settings_schema_key_get_value_type (global_schema_key);
512
513   new = g_variant_parse (type, global_value, NULL, NULL, &error);
514
515   /* If that didn't work and the type is string then we should assume
516    * that the user is just trying to set a string directly and forgot
517    * the quotes (or had them consumed by the shell).
518    *
519    * If the user started with a quote then we assume that some deeper
520    * problem is at play and we want the failure in that case.
521    *
522    * Consider:
523    *
524    *   gsettings set x.y.z key "'i don't expect this to work'"
525    *
526    * Note that we should not just add quotes and try parsing again, but
527    * rather assume that the user is providing us with a bare string.
528    * Assume we added single quotes, then consider this case:
529    *
530    *   gsettings set x.y.z key "i'd expect this to work"
531    *
532    * A similar example could be given for double quotes.
533    *
534    * Avoid that whole mess by just using g_variant_new_string().
535    */
536   if (new == NULL &&
537       g_variant_type_equal (type, G_VARIANT_TYPE_STRING) &&
538       global_value[0] != '\'' && global_value[0] != '"')
539     {
540       g_clear_error (&error);
541       new = g_variant_new_string (global_value);
542     }
543
544   if (new == NULL)
545     {
546       gchar *context;
547
548       context = g_variant_parse_error_print_context (error, global_value);
549       g_printerr ("%s", context);
550       exit (1);
551     }
552
553   if (!g_settings_schema_key_range_check (global_schema_key, new))
554     {
555       g_printerr (_("The provided value is outside of the valid range\n"));
556       g_variant_unref (new);
557       exit (1);
558     }
559
560   if (!g_settings_set_value (global_settings, global_key, new))
561     {
562       g_printerr (_("The key is not writable\n"));
563       exit (1);
564     }
565
566   g_settings_sync ();
567
568   g_free (freeme);
569 }
570
571 static int
572 gsettings_help (gboolean     requested,
573                 const gchar *command)
574 {
575   const gchar *description = NULL;
576   const gchar *synopsis = NULL;
577   GString *string;
578
579   string = g_string_new (NULL);
580
581   if (command == NULL)
582     ;
583
584   else if (strcmp (command, "help") == 0)
585     {
586       description = _("Print help");
587       synopsis = "[COMMAND]";
588     }
589
590   else if (strcmp (command, "--version") == 0)
591     {
592       description = _("Print version information and exit");
593       synopsis = "";
594     }
595
596   else if (strcmp (command, "list-schemas") == 0)
597     {
598       description = _("List the installed (non-relocatable) schemas");
599       synopsis = "[--print-paths]";
600     }
601
602   else if (strcmp (command, "list-relocatable-schemas") == 0)
603     {
604       description = _("List the installed relocatable schemas");
605       synopsis = "";
606     }
607
608   else if (strcmp (command, "list-keys") == 0)
609     {
610       description = _("List the keys in SCHEMA");
611       synopsis = N_("SCHEMA[:PATH]");
612     }
613
614   else if (strcmp (command, "list-children") == 0)
615     {
616       description = _("List the children of SCHEMA");
617       synopsis = N_("SCHEMA[:PATH]");
618     }
619
620   else if (strcmp (command, "list-recursively") == 0)
621     {
622       description = _("List keys and values, recursively\n"
623                       "If no SCHEMA is given, list all keys\n");
624       synopsis = N_("[SCHEMA[:PATH]]");
625     }
626
627   else if (strcmp (command, "get") == 0)
628     {
629       description = _("Get the value of KEY");
630       synopsis = N_("SCHEMA[:PATH] KEY");
631     }
632
633   else if (strcmp (command, "range") == 0)
634     {
635       description = _("Query the range of valid values for KEY");
636       synopsis = N_("SCHEMA[:PATH] KEY");
637     }
638
639   else if (strcmp (command, "describe") == 0)
640     {
641       description = _("Query the description for KEY");
642       synopsis = N_("SCHEMA[:PATH] KEY");
643     }
644
645   else if (strcmp (command, "set") == 0)
646     {
647       description = _("Set the value of KEY to VALUE");
648       synopsis = N_("SCHEMA[:PATH] KEY VALUE");
649     }
650
651   else if (strcmp (command, "reset") == 0)
652     {
653       description = _("Reset KEY to its default value");
654       synopsis = N_("SCHEMA[:PATH] KEY");
655     }
656
657   else if (strcmp (command, "reset-recursively") == 0)
658     {
659       description = _("Reset all keys in SCHEMA to their defaults");
660       synopsis = N_("SCHEMA[:PATH]");
661     }
662
663   else if (strcmp (command, "writable") == 0)
664     {
665       description = _("Check if KEY is writable");
666       synopsis = N_("SCHEMA[:PATH] KEY");
667     }
668
669   else if (strcmp (command, "monitor") == 0)
670     {
671       description = _("Monitor KEY for changes.\n"
672                     "If no KEY is specified, monitor all keys in SCHEMA.\n"
673                     "Use ^C to stop monitoring.\n");
674       synopsis = N_("SCHEMA[:PATH] [KEY]");
675     }
676   else
677     {
678       g_string_printf (string, _("Unknown command %s\n\n"), command);
679       requested = FALSE;
680       command = NULL;
681     }
682
683   if (command == NULL)
684     {
685       g_string_append (string,
686       _("Usage:\n"
687         "  gsettings --version\n"
688         "  gsettings [--schemadir SCHEMADIR] COMMAND [ARGS…]\n"
689         "\n"
690         "Commands:\n"
691         "  help                      Show this information\n"
692         "  list-schemas              List installed schemas\n"
693         "  list-relocatable-schemas  List relocatable schemas\n"
694         "  list-keys                 List keys in a schema\n"
695         "  list-children             List children of a schema\n"
696         "  list-recursively          List keys and values, recursively\n"
697         "  range                     Queries the range of a key\n"
698         "  describe                  Queries the description of a key\n"
699         "  get                       Get the value of a key\n"
700         "  set                       Set the value of a key\n"
701         "  reset                     Reset the value of a key\n"
702         "  reset-recursively         Reset all values in a given schema\n"
703         "  writable                  Check if a key is writable\n"
704         "  monitor                   Watch for changes\n"
705         "\n"
706         "Use “gsettings help COMMAND” to get detailed help.\n\n"));
707     }
708   else
709     {
710       g_string_append_printf (string, _("Usage:\n  gsettings [--schemadir SCHEMADIR] %s %s\n\n%s\n\n"),
711                               command, synopsis[0] ? _(synopsis) : "", description);
712
713       g_string_append (string, _("Arguments:\n"));
714
715       g_string_append (string,
716                        _("  SCHEMADIR A directory to search for additional schemas\n"));
717
718       if (strstr (synopsis, "[COMMAND]"))
719         g_string_append (string,
720                        _("  COMMAND   The (optional) command to explain\n"));
721
722       else if (strstr (synopsis, "SCHEMA"))
723         g_string_append (string,
724                        _("  SCHEMA    The name of the schema\n"
725                          "  PATH      The path, for relocatable schemas\n"));
726
727       if (strstr (synopsis, "[KEY]"))
728         g_string_append (string,
729                        _("  KEY       The (optional) key within the schema\n"));
730
731       else if (strstr (synopsis, "KEY"))
732         g_string_append (string,
733                        _("  KEY       The key within the schema\n"));
734
735       if (strstr (synopsis, "VALUE"))
736         g_string_append (string,
737                        _("  VALUE     The value to set\n"));
738
739       g_string_append (string, "\n");
740     }
741
742   if (requested)
743     g_print ("%s", string->str);
744   else
745     g_printerr ("%s\n", string->str);
746
747   g_string_free (string, TRUE);
748
749   return requested ? 0 : 1;
750 }
751
752
753 int
754 main (int argc, char **argv)
755 {
756   void (* function) (void);
757   gboolean need_settings, skip_third_arg_test;
758
759 #ifdef G_OS_WIN32
760   gchar *tmp;
761 #endif
762
763   setlocale (LC_ALL, GLIB_DEFAULT_LOCALE);
764   textdomain (GETTEXT_PACKAGE);
765
766 #ifdef G_OS_WIN32
767   tmp = _glib_get_locale_dir ();
768   bindtextdomain (GETTEXT_PACKAGE, tmp);
769   g_free (tmp);
770 #else
771   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
772 #endif
773
774 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
775   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
776 #endif
777
778   if (argc < 2)
779     return gsettings_help (FALSE, NULL);
780
781   global_schema_source = g_settings_schema_source_get_default ();
782
783   if (argc > 3 && g_str_equal (argv[1], "--schemadir"))
784     {
785       GSettingsSchemaSource *parent = global_schema_source;
786       GError *error = NULL;
787
788       global_schema_source = g_settings_schema_source_new_from_directory (argv[2], parent, FALSE, &error);
789
790       if (global_schema_source == NULL)
791         {
792           g_printerr (_("Could not load schemas from %s: %s\n"), argv[2], error->message);
793           g_clear_error (&error);
794
795           return 1;
796         }
797
798       /* shift remaining arguments (not correct wrt argv[0], but doesn't matter) */
799       argv = argv + 2;
800       argc -= 2;
801     }
802   else if (global_schema_source == NULL)
803     {
804       g_printerr (_("No schemas installed\n"));
805       return 1;
806     }
807   else
808     g_settings_schema_source_ref (global_schema_source);
809
810   need_settings = TRUE;
811   skip_third_arg_test = FALSE;
812
813   if (strcmp (argv[1], "help") == 0)
814     return gsettings_help (TRUE, argv[2]);
815
816   else if (argc == 2 && strcmp (argv[1], "--version") == 0)
817     function = gsettings_print_version;
818
819   else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0)
820     function = gsettings_list_schemas;
821
822   else if (argc == 3 && strcmp (argv[1], "list-schemas") == 0
823                      && strcmp (argv[2], "--print-paths") == 0)
824     {
825       skip_third_arg_test = TRUE;
826       function = gsettings_list_schemas_with_paths;
827     }
828
829   else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0)
830     function = gsettings_list_relocatable_schemas;
831
832   else if (argc == 3 && strcmp (argv[1], "list-keys") == 0)
833     {
834       need_settings = FALSE;
835       function = gsettings_list_keys;
836     }
837
838   else if (argc == 3 && strcmp (argv[1], "list-children") == 0)
839     function = gsettings_list_children;
840
841   else if ((argc == 2 || argc == 3) && strcmp (argv[1], "list-recursively") == 0)
842     function = gsettings_list_recursively;
843
844   else if (argc == 4 && strcmp (argv[1], "describe") == 0)
845     {
846       need_settings = FALSE;
847       function = gsettings_description;
848     }
849
850   else if (argc == 4 && strcmp (argv[1], "range") == 0)
851     {
852       need_settings = FALSE;
853       function = gsettings_range;
854     }
855
856   else if (argc == 4 && strcmp (argv[1], "get") == 0)
857     function = gsettings_get;
858
859   else if (argc == 5 && strcmp (argv[1], "set") == 0)
860     function = gsettings_set;
861
862   else if (argc == 4 && strcmp (argv[1], "reset") == 0)
863     function = gsettings_reset;
864
865   else if (argc == 3 && strcmp (argv[1], "reset-recursively") == 0)
866     function = gsettings_reset_recursively;
867
868   else if (argc == 4 && strcmp (argv[1], "writable") == 0)
869     function = gsettings_writable;
870
871   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0)
872     function = gsettings_monitor;
873
874   else
875     return gsettings_help (FALSE, argv[1]);
876
877   if (argc > 2 && !skip_third_arg_test)
878     {
879       gchar **parts;
880
881       if (argv[2][0] == '\0')
882         {
883           g_printerr (_("Empty schema name given\n"));
884           return 1;
885         }
886
887       parts = g_strsplit (argv[2], ":", 2);
888
889       global_schema = g_settings_schema_source_lookup (global_schema_source, parts[0], TRUE);
890
891       if (need_settings)
892         {
893           if (parts[1])
894             {
895               if (!check_relocatable_schema (global_schema, parts[0]) || !check_path (parts[1]))
896                 return 1;
897
898               global_settings = g_settings_new_full (global_schema, NULL, parts[1]);
899             }
900           else
901             {
902               if (!check_schema (global_schema, parts[0]))
903                 return 1;
904
905               global_settings = g_settings_new_full (global_schema, NULL, NULL);
906             }
907         }
908       else
909         {
910           /* If the user has given a path then we enforce that we have a
911            * relocatable schema, but if they didn't give a path then it
912            * doesn't matter what type of schema we have (since it's
913            * reasonable to ask for introspection information on a
914            * relocatable schema without having to give the path).
915            */
916           if (parts[1])
917             {
918               if (!check_relocatable_schema (global_schema, parts[0]) || !check_path (parts[1]))
919                 return 1;
920             }
921           else
922             {
923               if (global_schema == NULL)
924                 {
925                   g_printerr (_("No such schema “%s”\n"), parts[0]);
926                   return 1;
927                 }
928             }
929         }
930
931       g_strfreev (parts);
932     }
933
934   if (argc > 3)
935     {
936       if (!g_settings_schema_has_key (global_schema, argv[3]))
937         {
938           g_printerr (_("No such key “%s”\n"), argv[3]);
939           return 1;
940         }
941
942       global_key = argv[3];
943       global_schema_key = g_settings_schema_get_key (global_schema, global_key);
944     }
945
946   if (argc > 4)
947     global_value = argv[4];
948
949   (* function) ();
950
951
952   g_clear_pointer (&global_schema_source, g_settings_schema_source_unref);
953   g_clear_pointer (&global_schema_key, g_settings_schema_key_unref);
954   g_clear_pointer (&global_schema, g_settings_schema_unref);
955   g_clear_object (&global_settings);
956
957   return 0;
958 }