Fix some problems with message handling
[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   gchar **children;
244   gint i;
245
246   enumerate (settings);
247
248   children = g_settings_list_children (settings);
249
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
268 static void
269 gsettings_range (GSettings   *settings,
270                  const gchar *key,
271                  const gchar *value)
272 {
273   GVariant *range, *detail;
274   const gchar *type;
275
276   range = g_settings_get_range (settings, key);
277   g_variant_get (range, "(&sv)", &type, &detail);
278
279   if (strcmp (type, "type") == 0)
280     g_print ("type %s\n", g_variant_get_type_string (detail) + 1);
281
282   else if (strcmp (type, "range") == 0)
283     {
284       GVariant *min, *max;
285       gchar *smin, *smax;
286
287       g_variant_get (detail, "(**)", &min, &max);
288       smin = g_variant_print (min, FALSE);
289       smax = g_variant_print (max, FALSE);
290
291       g_print ("range %s %s %s\n",
292                g_variant_get_type_string (min), smin, smax);
293       g_variant_unref (min);
294       g_variant_unref (max);
295       g_free (smin);
296       g_free (smax);
297     }
298
299   else if (strcmp (type, "enum") == 0 || strcmp (type, "flags") == 0)
300     {
301       GVariantIter iter;
302       GVariant *item;
303
304       g_print ("%s\n", type);
305
306       g_variant_iter_init (&iter, detail);
307       while (g_variant_iter_loop (&iter, "*", &item))
308         {
309           gchar *printed;
310
311           printed = g_variant_print (item, FALSE);
312           g_print ("%s\n", printed);
313           g_free (printed);
314         }
315     }
316
317   g_variant_unref (detail);
318   g_variant_unref (range);
319 }
320
321 static void
322 gsettings_get (GSettings   *settings,
323                const gchar *key,
324                const gchar *value_)
325 {
326   GVariant *value;
327   gchar *printed;
328
329   value = g_settings_get_value (settings, key);
330   printed = g_variant_print (value, TRUE);
331   g_print ("%s\n", printed);
332   g_variant_unref (value);
333   g_free (printed);
334 }
335
336 static void
337 gsettings_reset (GSettings   *settings,
338                  const gchar *key,
339                  const gchar *value)
340 {
341   g_settings_reset (settings, key);
342   g_settings_sync ();
343 }
344
345 static void
346 gsettings_writable (GSettings   *settings,
347                     const gchar *key,
348                     const gchar *value)
349 {
350   g_print ("%s\n",
351            g_settings_is_writable (settings, key) ?
352            "true" : "false");
353 }
354
355 static void
356 value_changed (GSettings   *settings,
357                const gchar *key,
358                gpointer     user_data)
359 {
360   GVariant *value;
361   gchar *printed;
362
363   value = g_settings_get_value (settings, key);
364   printed = g_variant_print (value, TRUE);
365   g_print ("%s: %s\n", key, printed);
366   g_variant_unref (value);
367   g_free (printed);
368 }
369
370 static void
371 gsettings_monitor (GSettings   *settings,
372                    const gchar *key,
373                    const gchar *value)
374 {
375   if (key)
376     {
377       gchar *name;
378
379       name = g_strdup_printf ("changed::%s", key);
380       g_signal_connect (settings, name, G_CALLBACK (value_changed), NULL);
381     }
382   else
383     g_signal_connect (settings, "changed", G_CALLBACK (value_changed), NULL);
384
385   g_main_loop_run (g_main_loop_new (NULL, FALSE));
386 }
387
388 static void
389 gsettings_set (GSettings   *settings,
390                const gchar *key,
391                const gchar *value)
392 {
393   const GVariantType *type;
394   GError *error = NULL;
395   GVariant *existing;
396   GVariant *new;
397   gchar *freeme = NULL;
398
399   existing = g_settings_get_value (settings, key);
400   type = g_variant_get_type (existing);
401
402   new = g_variant_parse (type, value, NULL, NULL, &error);
403
404   /* A common error is to specify a string with single quotes
405    * (or use completion for that), and forget that the shell
406    * will eat one level of quoting, resulting in 'unknown keyword'
407    * error from the gvariant parser.
408    * To handle this case, try to parse again with an extra level
409    * of quotes.
410    */
411   if (new == NULL &&
412       g_error_matches (error, G_VARIANT_PARSE_ERROR,
413                        G_VARIANT_PARSE_ERROR_UNKNOWN_KEYWORD))
414     {
415       value = freeme = g_strdup_printf ("\"%s\"", value);
416       new = g_variant_parse (type, value, NULL, NULL, NULL);
417       if (new != NULL)
418         g_clear_error (&error);
419     }
420
421   if (new == NULL)
422     {
423       g_printerr ("%s\n", error->message);
424       exit (1);
425     }
426
427   if (!g_settings_range_check (settings, key, new))
428     {
429       g_printerr (_("The provided value is outside of the valid range\n"));
430       g_variant_unref (new);
431       exit (1);
432     }
433
434   g_settings_set_value (settings, key, new);
435   g_variant_unref (existing);
436   g_variant_unref (new);
437
438   g_settings_sync ();
439
440   g_free (freeme);
441 }
442
443 static int
444 gsettings_help (gboolean     requested,
445                 const gchar *command)
446 {
447   const gchar *description;
448   const gchar *synopsis;
449   GString *string;
450
451   string = g_string_new (NULL);
452
453   if (command == NULL)
454     ;
455
456   else if (strcmp (command, "help") == 0)
457     {
458       description = _("Print help");
459       synopsis = "[COMMAND]";
460     }
461
462   else if (strcmp (command, "list-schemas") == 0)
463     {
464       description = _("List the installed (non-relocatable) schemas");
465       synopsis = "";
466     }
467
468   else if (strcmp (command, "list-relocatable-schemas") == 0)
469     {
470       description = _("List the installed relocatable schemas");
471       synopsis = "";
472     }
473
474   else if (strcmp (command, "list-keys") == 0)
475     {
476       description = _("List the keys in SCHEMA");
477       synopsis = N_("SCHEMA[:PATH]");
478     }
479
480   else if (strcmp (command, "list-children") == 0)
481     {
482       description = _("List the children of SCHEMA");
483       synopsis = N_("SCHEMA[:PATH]");
484     }
485
486   else if (strcmp (command, "list-recursively") == 0)
487     {
488       description = _("List keys and values, recursively");
489       synopsis = N_("SCHEMA[:PATH]");
490     }
491
492   else if (strcmp (command, "get") == 0)
493     {
494       description = _("Get the value of KEY");
495       synopsis = N_("SCHEMA[:PATH] KEY");
496     }
497
498   else if (strcmp (command, "range") == 0)
499     {
500       description = _("Query the range of valid values for KEY");
501       synopsis = N_("SCHEMA[:PATH] KEY");
502     }
503
504   else if (strcmp (command, "set") == 0)
505     {
506       description = _("Set the value of KEY to VALUE");
507       synopsis = N_("SCHEMA[:PATH] KEY VALUE");
508     }
509
510   else if (strcmp (command, "reset") == 0)
511     {
512       description = _("Reset KEY to its default value");
513       synopsis = N_("SCHEMA[:PATH] KEY");
514     }
515
516   else if (strcmp (command, "writable") == 0)
517     {
518       description = _("Check if KEY is writable");
519       synopsis = N_("SCHEMA[:PATH] KEY");
520     }
521
522   else if (strcmp (command, "monitor") == 0)
523     {
524       description = _("Monitor KEY for changes.\n"
525                     "If no KEY is specified, monitor all keys in SCHEMA.\n"
526                     "Use ^C to stop monitoring.\n");
527       synopsis = N_("SCHEMA[:PATH] [KEY]");
528     }
529   else
530     {
531       g_string_printf (string, _("Unknown command %s\n\n"), command);
532       requested = FALSE;
533       command = NULL;
534     }
535
536   if (command == NULL)
537     {
538       g_string_append (string,
539       _("Usage:\n"
540         "  gsettings COMMAND [ARGS...]\n"
541         "\n"
542         "Commands:\n"
543         "  help                      Show this information\n"
544         "  list-schemas              List installed schemas\n"
545         "  list-relocatable-schemas  List relocatable schemas\n"
546         "  list-keys                 List keys in a schema\n"
547         "  list-children             List children of a schema\n"
548         "  list-recursively          List keys and values, recursively\n"
549         "  range                     Queries the range of a key\n"
550         "  get                       Get the value of a key\n"
551         "  set                       Set the value of a key\n"
552         "  reset                     Reset the value of a key\n"
553         "  writable                  Check if a key is writable\n"
554         "  monitor                   Watch for changes\n"
555         "\n"
556         "Use 'gsettings help COMMAND' to get detailed help.\n\n"));
557     }
558   else
559     {
560       g_string_append_printf (string, _("Usage:\n  gsettings %s %s\n\n%s\n\n"),
561                               command, synopsis[0] ? _(synopsis) : "", description);
562
563       if (synopsis[0])
564         {
565           g_string_append (string, _("Arguments:\n"));
566
567           if (strstr (synopsis, "[COMMAND]"))
568             g_string_append (string,
569                            _("  COMMAND   The (optional) command to explain\n"));
570
571           else if (strstr (synopsis, "SCHEMA"))
572             g_string_append (string,
573                            _("  SCHEMA    The name of the schema\n"
574                              "  PATH      The path, for relocatable schemas\n"));
575
576           if (strstr (synopsis, "[KEY]"))
577             g_string_append (string,
578                            _("  KEY       The (optional) key within the schema\n"));
579
580           else if (strstr (synopsis, "KEY"))
581             g_string_append (string,
582                            _("  KEY       The key within the schema\n"));
583
584           if (strstr (synopsis, "VALUE"))
585             g_string_append (string,
586                            _("  VALUE     The value to set\n"));
587
588           g_string_append (string, "\n");
589         }
590     }
591
592   if (requested)
593     g_print ("%s", string->str);
594   else
595     g_printerr ("%s\n", string->str);
596
597   g_string_free (string, TRUE);
598
599   return requested ? 0 : 1;
600 }
601
602
603 int
604 main (int argc, char **argv)
605 {
606   void (* function) (GSettings *, const gchar *, const gchar *);
607   GSettings *settings;
608   const gchar *key;
609
610   setlocale (LC_ALL, "");
611   textdomain (GETTEXT_PACKAGE);
612
613 #ifdef G_OS_WIN32
614   gchar *tmp = _glib_get_locale_dir ();
615   bindtextdomain (GETTEXT_PACKAGE, tmp);
616   g_free (tmp);
617 #else
618   bindtextdomain (GETTEXT_PACKAGE, GLIB_LOCALE_DIR);
619 #endif
620
621 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
622   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
623 #endif
624
625   if (argc < 2)
626     return gsettings_help (FALSE, NULL);
627
628   else if (strcmp (argv[1], "help") == 0)
629     return gsettings_help (TRUE, argv[2]);
630
631   else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0)
632     function = gsettings_list_schemas;
633
634   else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0)
635     function = gsettings_list_relocatable_schemas;
636
637   else if (argc == 3 && strcmp (argv[1], "list-keys") == 0)
638     function = gsettings_list_keys;
639
640   else if (argc == 3 && strcmp (argv[1], "list-children") == 0)
641     function = gsettings_list_children;
642
643   else if (argc == 3 && strcmp (argv[1], "list-recursively") == 0)
644     function = gsettings_list_recursively;
645
646   else if (argc == 4 && strcmp (argv[1], "range") == 0)
647     function = gsettings_range;
648
649   else if (argc == 4 && strcmp (argv[1], "get") == 0)
650     function = gsettings_get;
651
652   else if (argc == 5 && strcmp (argv[1], "set") == 0)
653     function = gsettings_set;
654
655   else if (argc == 4 && strcmp (argv[1], "reset") == 0)
656     function = gsettings_reset;
657
658   else if (argc == 4 && strcmp (argv[1], "writable") == 0)
659     function = gsettings_writable;
660
661   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0)
662     function = gsettings_monitor;
663
664   else
665     return gsettings_help (FALSE, argv[1]);
666
667   g_type_init ();
668
669   if (argc > 2)
670     {
671       gchar **parts;
672
673       if (argv[2][0] == '\0')
674         {
675           g_printerr (_("Empty schema name given\n"));
676           return 1;
677         }
678
679       parts = g_strsplit (argv[2], ":", 2);
680
681       if (parts[1])
682         {
683           if (!check_relocatable_schema (parts[0]) || !check_path (parts[1]))
684             return 1;
685
686           settings = g_settings_new_with_path (parts[0], parts[1]);
687         }
688       else
689         {
690           if (!check_schema (parts[0]))
691             return 1;
692
693           settings = g_settings_new (parts[0]);
694         }
695
696       g_strfreev (parts);
697     }
698   else
699     settings = NULL;
700
701   if (argc > 3)
702     {
703       if (!check_key (settings, argv[3]))
704         return 1;
705
706       key = argv[3];
707     }
708   else
709     key = NULL;
710
711   (* function) (settings, key, argc > 4 ? argv[4] : NULL);
712
713   if (settings != NULL)
714     g_object_unref (settings);
715
716   return 0;
717 }