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