split GSettings.list_items => list_{children,keys}
[platform/upstream/glib.git] / gio / gsettings-tool.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 2010 Red Hat, Inc.
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 License, 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: Matthias Clasen
20  */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <locale.h>
27 #include <gi18n.h>
28 #include <gio.h>
29
30 static gchar *
31 pick_word_at (const gchar  *s,
32               gint          cursor,
33               gint         *out_word_begins_at)
34 {
35   gint begin;
36   gint end;
37
38   if (s[0] == '\0')
39     {
40       if (out_word_begins_at != NULL)
41         *out_word_begins_at = -1;
42       return NULL;
43     }
44
45   if (g_ascii_isspace (s[cursor]) &&
46       ((cursor > 0 && g_ascii_isspace (s[cursor-1])) || cursor == 0))
47     {
48       if (out_word_begins_at != NULL)
49         *out_word_begins_at = cursor;
50       return g_strdup ("");
51     }
52   while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0)
53     cursor--;
54   begin = cursor;
55
56   end = begin;
57   while (!g_ascii_isspace (s[end]) && s[end] != '\0')
58     end++;
59
60   if (out_word_begins_at != NULL)
61     *out_word_begins_at = begin;
62
63   return g_strndup (s + begin, end - begin);
64 }
65
66 static gint
67 usage (gint      *argc,
68        gchar    **argv[],
69        gboolean   use_stdout)
70 {
71   GOptionContext *context;
72   gchar *s;
73
74   g_set_prgname (g_path_get_basename ((*argv)[0]));
75
76   context = g_option_context_new (_("COMMAND"));
77   g_option_context_set_help_enabled (context, FALSE);
78   s = g_strdup_printf (
79     _("Commands:\n"
80       "  help        Show this information\n"
81       "  get         Get the value of a key\n"
82       "  set         Set the value of a key\n"
83       "  reset       Reset the value of a key\n"
84       "  monitor     Monitor a key for changes\n"
85       "  writable    Check if a key is writable\n"
86       "\n"
87       "Use '%s COMMAND --help' to get help for individual commands.\n"),
88       g_get_prgname ());
89   g_option_context_set_description (context, s);
90   g_free (s);
91   s = g_option_context_get_help (context, FALSE, NULL);
92   if (use_stdout)
93     g_print ("%s", s);
94   else
95     g_printerr ("%s", s);
96   g_free (s);
97   g_option_context_free (context);
98
99   return use_stdout ? 0 : 1;
100 }
101
102 static void
103 remove_arg (gint num, gint *argc, gchar **argv[])
104 {
105   gint n;
106
107   g_assert (num <= (*argc));
108
109   for (n = num; (*argv)[n] != NULL; n++)
110     (*argv)[n] = (*argv)[n+1];
111   (*argv)[n] = NULL;
112   (*argc) = (*argc) - 1;
113 }
114
115
116 static void
117 modify_argv0_for_command (gint         *argc,
118                           gchar       **argv[],
119                           const gchar  *command)
120 {
121   gchar *s;
122
123   g_assert (g_strcmp0 ((*argv)[1], command) == 0);
124   remove_arg (1, argc, argv);
125
126   s = g_strdup_printf ("%s %s", (*argv)[0], command);
127   (*argv)[0] = s;
128 }
129
130 static gboolean
131 schema_exists (const gchar *name)
132 {
133   const gchar * const *schemas;
134   gint i;
135
136   schemas = g_settings_list_schemas ();
137   for (i = 0; schemas[i]; i++)
138     if (g_strcmp0 (name, schemas[i]) == 0)
139       return TRUE;
140
141   return FALSE;
142 }
143
144 static void
145 list_schemas (const gchar *prefix)
146 {
147   const gchar * const *schemas;
148   gint i;
149
150   schemas = g_settings_list_schemas ();
151   for (i = 0; schemas[i]; i++)
152     if (prefix == NULL || g_str_has_prefix (schemas[i], prefix))
153       g_print ("%s \n", schemas[i]);
154 }
155
156 static gboolean
157 key_exists (GSettings   *settings,
158             const gchar *name)
159 {
160   gchar **keys;
161   gint i;
162   gboolean ret;
163
164   ret = FALSE;
165
166   keys = g_settings_list_keys (settings);
167   for (i = 0; keys[i]; i++)
168     if (g_strcmp0 (keys[i], name) == 0)
169       {
170         ret = TRUE;
171         break;
172       }
173   g_strfreev (keys);
174
175   return ret;
176 }
177
178 static void
179 list_keys (GSettings   *settings,
180            const gchar *prefix)
181 {
182   gchar **keys;
183   gint i;
184
185   keys = g_settings_list_keys (settings);
186   for (i = 0; keys[i]; i++)
187     {
188       if (prefix == NULL || g_str_has_prefix (keys[i], prefix))
189         g_print ("%s \n", keys[i]);
190     }
191   g_strfreev (keys);
192 }
193
194 static void
195 list_options (GOptionContext *context,
196               const gchar    *prefix)
197 {
198   /* FIXME extract options from context */
199   const gchar *options[] = { "--help", "--path", NULL };
200   gint i;
201   for (i = 0; options[i]; i++)
202     if (g_str_has_prefix (options[i], prefix))
203       g_print ("%s \n", options[i]);
204 }
205
206 static gint
207 handle_get (gint      *argc,
208             gchar    **argv[],
209             gboolean   request_completion,
210             gchar     *completion_cur,
211             gchar     *completion_prev)
212 {
213   gchar *schema;
214   gchar *path;
215   gchar *key;
216   GSettings *settings;
217   GVariant *v;
218   GOptionContext *context;
219   GOptionEntry entries[] = {
220     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
221     { NULL }
222   };
223   GError *error;
224   gint ret = 1;
225
226   modify_argv0_for_command (argc, argv, "get");
227
228   context = g_option_context_new (_("SCHEMA KEY"));
229   g_option_context_set_help_enabled (context, FALSE);
230   g_option_context_set_summary (context, _("Get the value of KEY"));
231   g_option_context_set_description (context,
232     _("Arguments:\n"
233       "  SCHEMA      The id of the schema\n"
234       "  KEY         The name of the key\n"));
235   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
236
237   settings = NULL;
238   path = NULL;
239   schema = NULL;
240   key = NULL;
241
242   error = NULL;
243   if (!g_option_context_parse (context, argc, argv, NULL))
244     {
245       if (!request_completion)
246         {
247           gchar *s;
248           s = g_option_context_get_help (context, FALSE, NULL);
249           g_printerr ("%s", s);
250           g_free (s);
251
252           goto out;
253         }
254     }
255
256   if (*argc > 1)
257     schema = (*argv)[1];
258   if (*argc > 2)
259     key = (*argv)[2];
260
261   if (request_completion && completion_cur[0] == '-')
262     {
263       list_options (context, completion_cur);
264       ret = 0;
265       goto out;
266     }
267
268   if (request_completion && !schema_exists (schema))
269     {
270       list_schemas (schema);
271       ret = 0;
272       goto out;
273     }
274
275   if (path)
276     settings = g_settings_new_with_path (schema, path);
277   else
278     settings = g_settings_new (schema);
279
280   if (request_completion && !key_exists (settings, key))
281     {
282       list_keys (settings, key);
283       ret = 0;
284       goto out;
285     }
286
287   if (!request_completion)
288     {
289       v = g_settings_get_value (settings, key);
290       g_print ("%s\n", g_variant_print (v, FALSE));
291       g_variant_unref (v);
292       ret = 0;
293     }
294
295  out:
296   if (settings)
297     g_object_unref (settings);
298
299   g_option_context_free (context);
300
301   return ret;
302 }
303
304 static gint
305 handle_set (gint      *argc,
306             gchar    **argv[],
307             gboolean   request_completion,
308             gchar     *completion_cur,
309             gchar     *completion_prev)
310 {
311   gchar *schema;
312   gchar *path;
313   gchar *key;
314   gchar *value;
315   GSettings *settings;
316   GVariant *v, *default_v;
317   const GVariantType *type;
318   GOptionContext *context;
319   GOptionEntry entries[] = {
320     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
321     { NULL }
322   };
323   GError *error;
324   gint ret = 1;
325
326   modify_argv0_for_command (argc, argv, "set");
327
328   context = g_option_context_new (_("SCHEMA KEY VALUE"));
329   g_option_context_set_help_enabled (context, FALSE);
330   g_option_context_set_summary (context, _("Set the value of KEY"));
331   g_option_context_set_description (context,
332     _("Arguments:\n"
333       "  SCHEMA      The id of the schema\n"
334       "  KEY         The name of the key\n"
335       "  VALUE       The value to set key to, as a serialized GVariant\n"));
336   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
337
338   settings = NULL;
339   path = NULL;
340   schema = NULL;
341   key = NULL;
342
343   error = NULL;
344   if (!g_option_context_parse (context, argc, argv, NULL))
345     {
346       if (!request_completion)
347         {
348           gchar *s;
349           s = g_option_context_get_help (context, FALSE, NULL);
350           g_printerr ("%s", s);
351           g_free (s);
352           goto out;
353         }
354     }
355
356   if (*argc > 1)
357     schema = (*argv)[1];
358   if (*argc > 2)
359     key = (*argv)[2];
360   if (*argc > 3)
361     value = (*argv)[3];
362
363   if (request_completion && completion_cur[0] == '-')
364     {
365       list_options (context, completion_cur);
366       ret = 0;
367       goto out;
368     }
369
370   if (request_completion && !schema_exists (schema))
371     {
372       list_schemas (schema);
373       ret = 0;
374       goto out;
375     }
376
377   if (path)
378     settings = g_settings_new_with_path (schema, path);
379   else
380     settings = g_settings_new (schema);
381
382   if (request_completion && !key_exists (settings, key))
383     {
384       list_keys (settings, key);
385       ret = 0;
386       goto out;
387     }
388
389   if (!request_completion)
390     {
391       default_v = g_settings_get_value (settings, key);
392       type = g_variant_get_type (default_v);
393
394       error = NULL;
395       v = g_variant_parse (type, value, NULL, NULL, &error);
396       g_variant_unref (default_v);
397       if (v == NULL)
398         {
399           g_printerr ("%s\n", error->message);
400           goto out;
401         }
402
403       if (!g_settings_set_value (settings, key, v))
404         {
405           g_printerr (_("Key %s is not writable\n"), key);
406           goto out;
407         }
408
409       g_settings_sync ();
410       ret = 0;
411     }
412
413  out:
414   if (settings)
415     g_object_unref (settings);
416
417   g_option_context_free (context);
418
419   return ret;
420 }
421
422
423 static gint
424 handle_reset (gint      *argc,
425               gchar    **argv[],
426               gboolean   request_completion,
427               gchar     *completion_cur,
428               gchar     *completion_prev)
429 {
430   gchar *schema;
431   gchar *path;
432   gchar *key;
433   GSettings *settings;
434   GOptionContext *context;
435   GOptionEntry entries[] = {
436     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
437     { NULL }
438   };
439   GError *error;
440   gint ret = 1;
441
442   modify_argv0_for_command (argc, argv, "reset");
443
444   context = g_option_context_new (_("SCHEMA KEY VALUE"));
445   g_option_context_set_help_enabled (context, FALSE);
446   g_option_context_set_summary (context, _("Sets KEY to its default value"));
447   g_option_context_set_description (context,
448     _("Arguments:\n"
449       "  SCHEMA      The id of the schema\n"
450       "  KEY         The name of the key\n"));
451   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
452
453   settings = NULL;
454   path = NULL;
455   schema = NULL;
456   key = NULL;
457
458   error = NULL;
459   if (!g_option_context_parse (context, argc, argv, NULL))
460     {
461       if (!request_completion)
462         {
463           gchar *s;
464           s = g_option_context_get_help (context, FALSE, NULL);
465           g_printerr ("%s", s);
466           g_free (s);
467           goto out;
468         }
469     }
470
471   if (*argc > 1)
472     schema = (*argv)[1];
473   if (*argc > 2)
474     key = (*argv)[2];
475
476   if (request_completion && completion_cur[0] == '-')
477     {
478       list_options (context, completion_cur);
479       ret = 0;
480       goto out;
481     }
482
483   if (request_completion && !schema_exists (schema))
484     {
485       list_schemas (schema);
486       ret = 0;
487       goto out;
488     }
489
490   if (path)
491     settings = g_settings_new_with_path (schema, path);
492   else
493     settings = g_settings_new (schema);
494
495   if (request_completion && !key_exists (settings, key))
496     {
497       list_keys (settings, key);
498       ret = 0;
499       goto out;
500     }
501
502   if (!request_completion)
503     {
504       g_settings_reset (settings, key);
505       g_settings_sync ();
506       ret = 0;
507     }
508
509  out:
510   if (settings)
511     g_object_unref (settings);
512
513   g_option_context_free (context);
514
515   return ret;
516 }
517
518 static gint
519 handle_writable (gint   *argc,
520                  gchar **argv[],
521                  gboolean   request_completion,
522                  gchar     *completion_cur,
523                  gchar     *completion_prev)
524 {
525   gchar *schema;
526   gchar *path;
527   gchar *key;
528   GSettings *settings;
529   GOptionContext *context;
530   GOptionEntry entries[] = {
531     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
532     { NULL }
533   };
534   GError *error;
535   gint ret = 1;
536
537   modify_argv0_for_command (argc, argv, "writable");
538
539   context = g_option_context_new (_("SCHEMA KEY"));
540   g_option_context_set_help_enabled (context, FALSE);
541   g_option_context_set_summary (context, _("Find out whether KEY is writable"));
542   g_option_context_set_description (context,
543     _("Arguments:\n"
544       "  SCHEMA      The id of the schema\n"
545       "  KEY         The name of the key\n"));
546   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
547
548   settings = NULL;
549   path = NULL;
550   schema = NULL;
551   key = NULL;
552
553   error = NULL;
554   if (!g_option_context_parse (context, argc, argv, NULL))
555     {
556       if (!request_completion)
557         {
558           gchar *s;
559           s = g_option_context_get_help (context, FALSE, NULL);
560           g_printerr ("%s", s);
561           g_free (s);
562           goto out;
563         }
564     }
565
566   if (*argc > 1)
567     schema = (*argv)[1];
568   if (*argc > 2)
569     key = (*argv)[2];
570
571   if (request_completion && completion_cur[0] == '-')
572     {
573       list_options (context, completion_cur);
574       ret = 0;
575       goto out;
576     }
577
578   if (request_completion && !schema_exists (schema))
579     {
580       list_schemas (schema);
581       ret = 0;
582       goto out;
583     }
584
585   if (path)
586     settings = g_settings_new_with_path (schema, path);
587   else
588     settings = g_settings_new (schema);
589
590   if (request_completion && !key_exists (settings, key))
591     {
592       list_keys (settings, key);
593       ret = 0;
594       goto out;
595     }
596
597   if (!request_completion)
598     {
599       if (g_settings_is_writable (settings, key))
600         g_print ("true\n");
601       else
602         g_print ("false\n");
603       ret = 0;
604     }
605
606  out:
607   if (settings)
608     g_object_unref (settings);
609
610   g_option_context_free (context);
611
612   return ret;
613 }
614
615 static void
616 key_changed (GSettings   *settings,
617              const gchar *key)
618 {
619   GVariant *v;
620   gchar *value;
621
622   v = g_settings_get_value (settings, key);
623   value = g_variant_print (v, FALSE);
624   g_print ("%s\n", value);
625   g_free (value);
626   g_variant_unref (v);
627 }
628
629 static gint
630 handle_monitor (gint      *argc,
631                 gchar    **argv[],
632                 gboolean   request_completion,
633                 gchar     *completion_cur,
634                 gchar     *completion_prev)
635 {
636   gchar *schema;
637   gchar *path;
638   gchar *key;
639   GSettings *settings;
640   gchar *detailed_signal;
641   GMainLoop *loop;
642   GOptionContext *context;
643   GOptionEntry entries[] = {
644     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
645     { NULL }
646   };
647   GError *error;
648   gint ret = 1;
649
650   modify_argv0_for_command (argc, argv, "monitor");
651
652   context = g_option_context_new (_("SCHEMA KEY"));
653   g_option_context_set_help_enabled (context, FALSE);
654   g_option_context_set_summary (context,
655     _("Monitor KEY for changes and print the changed values.\n"
656       "Monitoring will continue until the process is terminated."));
657
658   g_option_context_set_description (context,
659     _("Arguments:\n"
660       "  SCHEMA      The id of the schema\n"
661       "  KEY         The name of the key\n"));
662   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
663
664   settings = NULL;
665   path = NULL;
666   schema = NULL;
667   key = NULL;
668
669   error = NULL;
670   if (!g_option_context_parse (context, argc, argv, NULL))
671     {
672       if (!request_completion)
673         {
674           gchar *s;
675           s = g_option_context_get_help (context, FALSE, NULL);
676           g_printerr ("%s", s);
677           g_free (s);
678           goto out;
679         }
680     }
681
682   if (*argc > 1)
683     schema = (*argv)[1];
684   if (*argc > 2)
685     key = (*argv)[2];
686
687   if (request_completion && completion_cur[0] == '-')
688     {
689       list_options (context, completion_cur);
690       ret = 0;
691       goto out;
692     }
693
694   if (request_completion && !schema_exists (schema))
695     {
696       list_schemas (schema);
697       ret = 0;
698       goto out;
699     }
700
701   if (path)
702     settings = g_settings_new_with_path (schema, path);
703   else
704     settings = g_settings_new (schema);
705
706   if (request_completion && !key_exists (settings, key))
707     {
708       list_keys (settings, key);
709       ret = 0;
710       goto out;
711     }
712
713   if (!request_completion)
714     {
715       detailed_signal = g_strdup_printf ("changed::%s", key);
716       g_signal_connect (settings, detailed_signal,
717                         G_CALLBACK (key_changed), NULL);
718
719       loop = g_main_loop_new (NULL, FALSE);
720       g_main_loop_run (loop);
721       g_main_loop_unref (loop);
722       ret = 0;
723     }
724
725  out:
726   if (settings)
727     g_object_unref (settings);
728
729   g_option_context_free (context);
730
731   return ret;
732 }
733
734 int
735 main (int argc, char *argv[])
736 {
737   gboolean ret;
738   gchar *command;
739   gboolean request_completion;
740   gchar *completion_cur;
741   gchar *completion_prev;
742
743   setlocale (LC_ALL, "");
744
745   g_type_init ();
746
747   ret = 1;
748   completion_cur = NULL;
749   completion_prev = NULL;
750   request_completion = FALSE;
751
752   if (argc < 2)
753     {
754       ret = usage (&argc, &argv, FALSE);
755       goto out;
756     }
757
758  again:
759   command = argv[1];
760
761   if (g_strcmp0 (command, "help") == 0)
762     {
763       if (!request_completion)
764         ret = usage (&argc, &argv, TRUE);
765     }
766   else if (g_strcmp0 (command, "get") == 0)
767     ret = handle_get (&argc, &argv, request_completion, completion_cur, completion_prev);
768   else if (g_strcmp0 (command, "set") == 0)
769     ret = handle_set (&argc, &argv, request_completion, completion_cur, completion_prev);
770   else if (g_strcmp0 (command, "reset") == 0)
771     ret = handle_reset (&argc, &argv, request_completion, completion_cur, completion_prev);
772   else if (g_strcmp0 (command, "monitor") == 0)
773     ret = handle_monitor (&argc, &argv, request_completion, completion_cur, completion_prev);
774   else if (g_strcmp0 (command, "writable") == 0)
775     ret = handle_writable (&argc, &argv, request_completion, completion_cur, completion_prev);
776   else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
777     {
778       gchar *completion_line;
779       gint completion_point;
780       gchar *endp;
781       gchar **completion_argv;
782       gint completion_argc;
783       gint cur_begin;
784
785       request_completion = TRUE;
786
787       completion_line = argv[2];
788       completion_point = strtol (argv[3], &endp, 10);
789       if (endp == argv[3] || *endp != '\0')
790         goto out;
791
792       if (!g_shell_parse_argv (completion_line,
793                                &completion_argc,
794                                &completion_argv,
795                                NULL))
796         {
797           /* can't parse partical cmdline, don't attempt completion */
798           goto out;
799         }
800
801       completion_prev = NULL;
802       completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
803       if (cur_begin > 0)
804         {
805           gint prev_end;
806           for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
807             {
808               if (!g_ascii_isspace (completion_line[prev_end]))
809                 {
810                   completion_prev = pick_word_at (completion_line, prev_end, NULL);
811                   break;
812                 }
813             }
814         }
815
816       argc = completion_argc;
817       argv = completion_argv;
818
819       ret = 0;
820       goto again;
821     }
822   else
823     {
824       if (request_completion)
825         {
826           g_print ("help \nget \nmonitor \nwritable \nset \nreset \n");
827           ret = 0;
828         }
829       else
830         {
831           g_printerr (_("Unknown command '%s'\n"), argv[1]);
832           ret = usage (&argc, &argv, FALSE);
833         }
834     }
835
836  out:
837   g_free (completion_cur);
838   g_free (completion_prev);
839
840   return ret;
841 }