Add translator comments for command parameter translation
[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   /* Translators: Please keep order of words (command parameters) */
329   context = g_option_context_new (_("SCHEMA KEY VALUE"));
330   g_option_context_set_help_enabled (context, FALSE);
331   g_option_context_set_summary (context, _("Set the value of KEY"));
332   g_option_context_set_description (context,
333     _("Arguments:\n"
334       "  SCHEMA      The id of the schema\n"
335       "  KEY         The name of the key\n"
336       "  VALUE       The value to set key to, as a serialized GVariant\n"));
337   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
338
339   settings = NULL;
340   path = NULL;
341   schema = NULL;
342   key = NULL;
343
344   error = NULL;
345   if (!g_option_context_parse (context, argc, argv, NULL))
346     {
347       if (!request_completion)
348         {
349           gchar *s;
350           s = g_option_context_get_help (context, FALSE, NULL);
351           g_printerr ("%s", s);
352           g_free (s);
353           goto out;
354         }
355     }
356
357   if (*argc > 1)
358     schema = (*argv)[1];
359   if (*argc > 2)
360     key = (*argv)[2];
361   if (*argc > 3)
362     value = (*argv)[3];
363
364   if (request_completion && completion_cur[0] == '-')
365     {
366       list_options (context, completion_cur);
367       ret = 0;
368       goto out;
369     }
370
371   if (request_completion && !schema_exists (schema))
372     {
373       list_schemas (schema);
374       ret = 0;
375       goto out;
376     }
377
378   if (path)
379     settings = g_settings_new_with_path (schema, path);
380   else
381     settings = g_settings_new (schema);
382
383   if (request_completion && !key_exists (settings, key))
384     {
385       list_keys (settings, key);
386       ret = 0;
387       goto out;
388     }
389
390   if (!request_completion)
391     {
392       default_v = g_settings_get_value (settings, key);
393       type = g_variant_get_type (default_v);
394
395       error = NULL;
396       v = g_variant_parse (type, value, NULL, NULL, &error);
397       g_variant_unref (default_v);
398       if (v == NULL)
399         {
400           g_printerr ("%s\n", error->message);
401           goto out;
402         }
403
404       if (!g_settings_set_value (settings, key, v))
405         {
406           g_printerr (_("Key %s is not writable\n"), key);
407           goto out;
408         }
409
410       g_settings_sync ();
411       ret = 0;
412     }
413
414  out:
415   if (settings)
416     g_object_unref (settings);
417
418   g_option_context_free (context);
419
420   return ret;
421 }
422
423
424 static gint
425 handle_reset (gint      *argc,
426               gchar    **argv[],
427               gboolean   request_completion,
428               gchar     *completion_cur,
429               gchar     *completion_prev)
430 {
431   gchar *schema;
432   gchar *path;
433   gchar *key;
434   GSettings *settings;
435   GOptionContext *context;
436   GOptionEntry entries[] = {
437     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
438     { NULL }
439   };
440   GError *error;
441   gint ret = 1;
442
443   modify_argv0_for_command (argc, argv, "reset");
444
445   context = g_option_context_new (_("SCHEMA KEY VALUE"));
446   g_option_context_set_help_enabled (context, FALSE);
447   g_option_context_set_summary (context, _("Sets KEY to its default value"));
448   g_option_context_set_description (context,
449     _("Arguments:\n"
450       "  SCHEMA      The id of the schema\n"
451       "  KEY         The name of the key\n"));
452   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
453
454   settings = NULL;
455   path = NULL;
456   schema = NULL;
457   key = NULL;
458
459   error = NULL;
460   if (!g_option_context_parse (context, argc, argv, NULL))
461     {
462       if (!request_completion)
463         {
464           gchar *s;
465           s = g_option_context_get_help (context, FALSE, NULL);
466           g_printerr ("%s", s);
467           g_free (s);
468           goto out;
469         }
470     }
471
472   if (*argc > 1)
473     schema = (*argv)[1];
474   if (*argc > 2)
475     key = (*argv)[2];
476
477   if (request_completion && completion_cur[0] == '-')
478     {
479       list_options (context, completion_cur);
480       ret = 0;
481       goto out;
482     }
483
484   if (request_completion && !schema_exists (schema))
485     {
486       list_schemas (schema);
487       ret = 0;
488       goto out;
489     }
490
491   if (path)
492     settings = g_settings_new_with_path (schema, path);
493   else
494     settings = g_settings_new (schema);
495
496   if (request_completion && !key_exists (settings, key))
497     {
498       list_keys (settings, key);
499       ret = 0;
500       goto out;
501     }
502
503   if (!request_completion)
504     {
505       g_settings_reset (settings, key);
506       g_settings_sync ();
507       ret = 0;
508     }
509
510  out:
511   if (settings)
512     g_object_unref (settings);
513
514   g_option_context_free (context);
515
516   return ret;
517 }
518
519 static gint
520 handle_writable (gint   *argc,
521                  gchar **argv[],
522                  gboolean   request_completion,
523                  gchar     *completion_cur,
524                  gchar     *completion_prev)
525 {
526   gchar *schema;
527   gchar *path;
528   gchar *key;
529   GSettings *settings;
530   GOptionContext *context;
531   GOptionEntry entries[] = {
532     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
533     { NULL }
534   };
535   GError *error;
536   gint ret = 1;
537
538   modify_argv0_for_command (argc, argv, "writable");
539
540   /* Translators: Please keep order of words (command parameters) */
541   context = g_option_context_new (_("SCHEMA KEY"));
542   g_option_context_set_help_enabled (context, FALSE);
543   g_option_context_set_summary (context, _("Find out whether KEY is writable"));
544   g_option_context_set_description (context,
545     _("Arguments:\n"
546       "  SCHEMA      The id of the schema\n"
547       "  KEY         The name of the key\n"));
548   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
549
550   settings = NULL;
551   path = NULL;
552   schema = NULL;
553   key = NULL;
554
555   error = NULL;
556   if (!g_option_context_parse (context, argc, argv, NULL))
557     {
558       if (!request_completion)
559         {
560           gchar *s;
561           s = g_option_context_get_help (context, FALSE, NULL);
562           g_printerr ("%s", s);
563           g_free (s);
564           goto out;
565         }
566     }
567
568   if (*argc > 1)
569     schema = (*argv)[1];
570   if (*argc > 2)
571     key = (*argv)[2];
572
573   if (request_completion && completion_cur[0] == '-')
574     {
575       list_options (context, completion_cur);
576       ret = 0;
577       goto out;
578     }
579
580   if (request_completion && !schema_exists (schema))
581     {
582       list_schemas (schema);
583       ret = 0;
584       goto out;
585     }
586
587   if (path)
588     settings = g_settings_new_with_path (schema, path);
589   else
590     settings = g_settings_new (schema);
591
592   if (request_completion && !key_exists (settings, key))
593     {
594       list_keys (settings, key);
595       ret = 0;
596       goto out;
597     }
598
599   if (!request_completion)
600     {
601       if (g_settings_is_writable (settings, key))
602         g_print ("true\n");
603       else
604         g_print ("false\n");
605       ret = 0;
606     }
607
608  out:
609   if (settings)
610     g_object_unref (settings);
611
612   g_option_context_free (context);
613
614   return ret;
615 }
616
617 static void
618 key_changed (GSettings   *settings,
619              const gchar *key)
620 {
621   GVariant *v;
622   gchar *value;
623
624   v = g_settings_get_value (settings, key);
625   value = g_variant_print (v, FALSE);
626   g_print ("%s\n", value);
627   g_free (value);
628   g_variant_unref (v);
629 }
630
631 static gint
632 handle_monitor (gint      *argc,
633                 gchar    **argv[],
634                 gboolean   request_completion,
635                 gchar     *completion_cur,
636                 gchar     *completion_prev)
637 {
638   gchar *schema;
639   gchar *path;
640   gchar *key;
641   GSettings *settings;
642   gchar *detailed_signal;
643   GMainLoop *loop;
644   GOptionContext *context;
645   GOptionEntry entries[] = {
646     { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") },
647     { NULL }
648   };
649   GError *error;
650   gint ret = 1;
651
652   modify_argv0_for_command (argc, argv, "monitor");
653
654   context = g_option_context_new (_("SCHEMA KEY"));
655   g_option_context_set_help_enabled (context, FALSE);
656   g_option_context_set_summary (context,
657     _("Monitor KEY for changes and print the changed values.\n"
658       "Monitoring will continue until the process is terminated."));
659
660   g_option_context_set_description (context,
661     _("Arguments:\n"
662       "  SCHEMA      The id of the schema\n"
663       "  KEY         The name of the key\n"));
664   g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
665
666   settings = NULL;
667   path = NULL;
668   schema = NULL;
669   key = NULL;
670
671   error = NULL;
672   if (!g_option_context_parse (context, argc, argv, NULL))
673     {
674       if (!request_completion)
675         {
676           gchar *s;
677           s = g_option_context_get_help (context, FALSE, NULL);
678           g_printerr ("%s", s);
679           g_free (s);
680           goto out;
681         }
682     }
683
684   if (*argc > 1)
685     schema = (*argv)[1];
686   if (*argc > 2)
687     key = (*argv)[2];
688
689   if (request_completion && completion_cur[0] == '-')
690     {
691       list_options (context, completion_cur);
692       ret = 0;
693       goto out;
694     }
695
696   if (request_completion && !schema_exists (schema))
697     {
698       list_schemas (schema);
699       ret = 0;
700       goto out;
701     }
702
703   if (path)
704     settings = g_settings_new_with_path (schema, path);
705   else
706     settings = g_settings_new (schema);
707
708   if (request_completion && !key_exists (settings, key))
709     {
710       list_keys (settings, key);
711       ret = 0;
712       goto out;
713     }
714
715   if (!request_completion)
716     {
717       detailed_signal = g_strdup_printf ("changed::%s", key);
718       g_signal_connect (settings, detailed_signal,
719                         G_CALLBACK (key_changed), NULL);
720
721       loop = g_main_loop_new (NULL, FALSE);
722       g_main_loop_run (loop);
723       g_main_loop_unref (loop);
724       ret = 0;
725     }
726
727  out:
728   if (settings)
729     g_object_unref (settings);
730
731   g_option_context_free (context);
732
733   return ret;
734 }
735
736 int
737 main (int argc, char *argv[])
738 {
739   gboolean ret;
740   gchar *command;
741   gboolean request_completion;
742   gchar *completion_cur;
743   gchar *completion_prev;
744
745   setlocale (LC_ALL, "");
746
747   g_type_init ();
748
749   ret = 1;
750   completion_cur = NULL;
751   completion_prev = NULL;
752   request_completion = FALSE;
753
754   if (argc < 2)
755     {
756       ret = usage (&argc, &argv, FALSE);
757       goto out;
758     }
759
760  again:
761   command = argv[1];
762
763   if (g_strcmp0 (command, "help") == 0)
764     {
765       if (!request_completion)
766         ret = usage (&argc, &argv, TRUE);
767     }
768   else if (g_strcmp0 (command, "get") == 0)
769     ret = handle_get (&argc, &argv, request_completion, completion_cur, completion_prev);
770   else if (g_strcmp0 (command, "set") == 0)
771     ret = handle_set (&argc, &argv, request_completion, completion_cur, completion_prev);
772   else if (g_strcmp0 (command, "reset") == 0)
773     ret = handle_reset (&argc, &argv, request_completion, completion_cur, completion_prev);
774   else if (g_strcmp0 (command, "monitor") == 0)
775     ret = handle_monitor (&argc, &argv, request_completion, completion_cur, completion_prev);
776   else if (g_strcmp0 (command, "writable") == 0)
777     ret = handle_writable (&argc, &argv, request_completion, completion_cur, completion_prev);
778   else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion)
779     {
780       gchar *completion_line;
781       gint completion_point;
782       gchar *endp;
783       gchar **completion_argv;
784       gint completion_argc;
785       gint cur_begin;
786
787       request_completion = TRUE;
788
789       completion_line = argv[2];
790       completion_point = strtol (argv[3], &endp, 10);
791       if (endp == argv[3] || *endp != '\0')
792         goto out;
793
794       if (!g_shell_parse_argv (completion_line,
795                                &completion_argc,
796                                &completion_argv,
797                                NULL))
798         {
799           /* can't parse partical cmdline, don't attempt completion */
800           goto out;
801         }
802
803       completion_prev = NULL;
804       completion_cur = pick_word_at (completion_line, completion_point, &cur_begin);
805       if (cur_begin > 0)
806         {
807           gint prev_end;
808           for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--)
809             {
810               if (!g_ascii_isspace (completion_line[prev_end]))
811                 {
812                   completion_prev = pick_word_at (completion_line, prev_end, NULL);
813                   break;
814                 }
815             }
816         }
817
818       argc = completion_argc;
819       argv = completion_argv;
820
821       ret = 0;
822       goto again;
823     }
824   else
825     {
826       if (request_completion)
827         {
828           g_print ("help \nget \nmonitor \nwritable \nset \nreset \n");
829           ret = 0;
830         }
831       else
832         {
833           g_printerr (_("Unknown command '%s'\n"), argv[1]);
834           ret = usage (&argc, &argv, FALSE);
835         }
836     }
837
838  out:
839   g_free (completion_cur);
840   g_free (completion_prev);
841
842   return ret;
843 }