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