gsettings-tool: Support completion for enum values
[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 parse:
403   new = g_variant_parse (type, value, NULL, NULL, &error);
404
405   /* A common error is to specify a string with single quotes
406    * (or use completion for that), and forget that the shell
407    * will eat one level of quoting, resulting in 'unknown keyword'
408    * error from the gvariant parser.
409    * To handle this case, try to parse again with an extra level
410    * of quotes.
411    */
412   if (new == NULL && !freeme && strstr (error->message, "unknown keyword"))
413     {
414       value = freeme = g_strdup_printf ("\"%s\"", value);
415       goto parse;
416     }
417
418   if (new == NULL)
419     {
420       g_printerr ("%s\n", error->message);
421       exit (1);
422     }
423
424   if (!g_settings_range_check (settings, key, new))
425     {
426       g_printerr (_("The provided value is outside of the valid range\n"));
427       g_variant_unref (new);
428       exit (1);
429     }
430
431   g_settings_set_value (settings, key, new);
432   g_variant_unref (existing);
433   g_variant_unref (new);
434
435   g_settings_sync ();
436
437   g_free (freeme);
438 }
439
440 static int
441 gsettings_help (gboolean     requested,
442                 const gchar *command)
443 {
444   const gchar *description;
445   const gchar *synopsis;
446   GString *string;
447
448   string = g_string_new (NULL);
449
450   if (command == NULL)
451     ;
452
453   else if (strcmp (command, "list-schemas") == 0)
454     {
455       description = _("List the installed (non-relocatable) schemas");
456       synopsis = "";
457     }
458
459   else if (strcmp (command, "list-relocatable-schemas") == 0)
460     {
461       description = _("List the installed relocatable schemas");
462       synopsis = "";
463     }
464
465   else if (strcmp (command, "list-keys") == 0)
466     {
467       description = _("Lists the keys in SCHEMA");
468       synopsis = N_("SCHEMA[:PATH]");
469     }
470
471   else if (strcmp (command, "list-children") == 0)
472     {
473       description = _("Lists the children of SCHEMA");
474       synopsis = N_("SCHEMA[:PATH]");
475     }
476
477   else if (strcmp (command, "list-recursively") == 0)
478     {
479       description = _("List keys and values, recursively");
480       synopsis = N_("SCHEMA[:PATH]");
481     }
482
483   else if (strcmp (command, "get") == 0)
484     {
485       description = _("Gets the value of KEY");
486       synopsis = N_("SCHEMA[:PATH] KEY");
487     }
488
489   else if (strcmp (command, "range") == 0)
490     {
491       description = _("Queries the range of valid values for KEY");
492       synopsis = N_("SCHEMA[:PATH] KEY");
493     }
494
495   else if (strcmp (command, "set") == 0)
496     {
497       description = _("Sets the value of KEY to VALUE");
498       synopsis = N_("SCHEMA[:PATH] KEY VALUE");
499     }
500
501   else if (strcmp (command, "reset") == 0)
502     {
503       description = _("Resets KEY to its default value");
504       synopsis = N_("SCHEMA[:PATH] KEY");
505     }
506
507   else if (strcmp (command, "writable") == 0)
508     {
509       description = _("Checks if KEY is writable");
510       synopsis = N_("SCHEMA[:PATH] KEY");
511     }
512
513   else if (strcmp (command, "monitor") == 0)
514     {
515       description = _("Monitors KEY for changes.\n"
516                     "If no KEY is specified, monitor all keys in SCHEMA.\n"
517                     "Use ^C to stop monitoring.\n");
518       synopsis = N_("SCHEMA[:PATH] [KEY]");
519     }
520   else
521     {
522       g_string_printf (string, _("Unknown command %s\n\n"), command);
523       requested = FALSE;
524       command = NULL;
525     }
526
527   if (command == NULL)
528     {
529       g_string_append (string,
530       _("Usage:\n"
531         "  gsettings COMMAND [ARGS...]\n"
532         "\n"
533         "Commands:\n"
534         "  help                      Show this information\n"
535         "  list-schemas              List installed schemas\n"
536         "  list-relocatable-schemas  List relocatable schemas\n"
537         "  list-keys                 List keys in a schema\n"
538         "  list-children             List children of a schema\n"
539         "  list-recursively          List keys and values, recursively\n"
540         "  range                     Queries the range of a key\n"
541         "  get                       Get the value of a key\n"
542         "  set                       Set the value of a key\n"
543         "  reset                     Reset the value of a key\n"
544         "  writable                  Check if a key is writable\n"
545         "  monitor                   Watch for changes\n"
546         "\n"
547         "Use 'gsettings help COMMAND' to get detailed help.\n\n"));
548     }
549   else
550     {
551       g_string_append_printf (string, _("Usage:\n  gsettings %s %s\n\n%s\n\n"),
552                               command, _(synopsis), description);
553
554       if (synopsis[0])
555         {
556           g_string_append (string, _("Arguments:\n"));
557
558           if (strstr (synopsis, "SCHEMA"))
559             g_string_append (string,
560                            _("  SCHEMA    The name of the schema\n"
561                              "  PATH      The path, for relocatable schemas\n"));
562
563           if (strstr (synopsis, "[KEY]"))
564             g_string_append (string,
565                            _("  KEY       The (optional) key within the schema\n"));
566
567           else if (strstr (synopsis, "KEY"))
568             g_string_append (string,
569                            _("  KEY       The key within the schema\n"));
570
571           if (strstr (synopsis, "VALUE"))
572             g_string_append (string,
573                            _("  VALUE     The value to set\n"));
574
575           g_string_append (string, "\n");
576         }
577     }
578
579   if (requested)
580     g_print ("%s", string->str);
581   else
582     g_printerr ("%s", string->str);
583
584   g_string_free (string, TRUE);
585
586   return requested ? 0 : 1;
587 }
588
589
590 int
591 main (int argc, char **argv)
592 {
593   void (* function) (GSettings *, const gchar *, const gchar *);
594   GSettings *settings;
595   const gchar *key;
596
597   setlocale (LC_ALL, "");
598
599   if (argc < 2)
600     return gsettings_help (FALSE, NULL);
601
602   else if (strcmp (argv[1], "help") == 0)
603     return gsettings_help (TRUE, argv[2]);
604
605   else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0)
606     function = gsettings_list_schemas;
607
608   else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0)
609     function = gsettings_list_relocatable_schemas;
610
611   else if (argc == 3 && strcmp (argv[1], "list-keys") == 0)
612     function = gsettings_list_keys;
613
614   else if (argc == 3 && strcmp (argv[1], "list-children") == 0)
615     function = gsettings_list_children;
616
617   else if (argc == 3 && strcmp (argv[1], "list-recursively") == 0)
618     function = gsettings_list_recursively;
619
620   else if (argc == 4 && strcmp (argv[1], "range") == 0)
621     function = gsettings_range;
622
623   else if (argc == 4 && strcmp (argv[1], "get") == 0)
624     function = gsettings_get;
625
626   else if (argc == 5 && strcmp (argv[1], "set") == 0)
627     function = gsettings_set;
628
629   else if (argc == 4 && strcmp (argv[1], "reset") == 0)
630     function = gsettings_reset;
631
632   else if (argc == 4 && strcmp (argv[1], "writable") == 0)
633     function = gsettings_writable;
634
635   else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0)
636     function = gsettings_monitor;
637
638   else
639     return gsettings_help (FALSE, argv[1]);
640
641   g_type_init ();
642
643   if (argc > 2)
644     {
645       gchar **parts;
646
647       if (argv[2][0] == '\0')
648         {
649           g_printerr (_("Empty schema name given"));
650           return 1;
651         }
652
653       parts = g_strsplit (argv[2], ":", 2);
654
655       if (parts[1])
656         {
657           if (!check_relocatable_schema (parts[0]) || !check_path (parts[1]))
658             return 1;
659
660           settings = g_settings_new_with_path (parts[0], parts[1]);
661         }
662       else
663         {
664           if (!check_schema (parts[0]))
665             return 1;
666
667           settings = g_settings_new (parts[0]);
668         }
669
670       g_strfreev (parts);
671     }
672   else
673     settings = NULL;
674
675   if (argc > 3)
676     {
677       if (!check_key (settings, argv[3]))
678         return 1;
679
680       key = argv[3];
681     }
682   else
683     key = NULL;
684
685   (* function) (settings, key, argc > 4 ? argv[4] : NULL);
686
687   if (settings != NULL)
688     g_object_unref (settings);
689
690   return 0;
691 }