From 2d6f8a8ea4a0c86c40da60db2d948306f4c2f5c9 Mon Sep 17 00:00:00 2001 From: Ryan Lortie Date: Sun, 3 Oct 2010 02:40:48 -0400 Subject: [PATCH] gsettings-tool: Rewrite Rewrite the GSettings tool. Improvements/changes: - simplify the code by performing common actions (like creating a schema) in only one place instead of one per-command - new features (list schemas, list keys, monitor multiple, etc) - factor-out bash completion and implement in shellscript - input validation: should never abort due to invalid inputs Still to do: - proper error checking for ranges/choices - support for querying range/choice information - bash completion support for enums Closes bug #629289, possibly among others. --- gio/gsettings-bash-completion.sh | 58 ++- gio/gsettings-tool.c | 1047 ++++++++++++++------------------------ 2 files changed, 405 insertions(+), 700 deletions(-) diff --git a/gio/gsettings-bash-completion.sh b/gio/gsettings-bash-completion.sh index 47ffcbe..adbc556 100644 --- a/gio/gsettings-bash-completion.sh +++ b/gio/gsettings-bash-completion.sh @@ -4,28 +4,44 @@ #################################################################################################### - __gsettings() { - local IFS=$'\n' - local cur=`_get_cword :` - - local suggestions=$(gsettings complete "${COMP_LINE}" ${COMP_POINT}) - COMPREPLY=($(compgen -W "$suggestions" -- "$cur")) - - # Remove colon-word prefix from COMPREPLY items - case "$cur" in - *:*) - case "$COMP_WORDBREAKS" in - *:*) - local colon_word=${cur%${cur##*:}} - local i=${#COMPREPLY[*]} - while [ $((--i)) -ge 0 ]; do - COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} - done - ;; - esac - ;; - esac + local choices + + case "${COMP_CWORD}" in + 1) + choices=$'help \nlist-schemas\nlist-relocatable-schemas\nlist-keys \nlist-children \nget \nset \nreset \nwritable \nmonitor' + ;; + + 2) + case "${COMP_WORDS[1]}" in + help) + choices=$'list-schemas\nlist-relocatable-schemas\nlist-keys\nlist-children\nget\nset\nreset\nwritable\nmonitor' + ;; + list-keys|list-children) + choices="$(gsettings list-schemas)"$'\n'"$(gsettings list-relocatable-schemas | sed -e 's.$.:/.')" + ;; + + get|set|reset|writable|monitor) + choices="$(gsettings list-schemas | sed -e 's.$. .')"$'\n'"$(gsettings list-relocatable-schemas | sed -e 's.$.:/.')" + ;; + esac + ;; + + 3) + case "${COMP_WORDS[1]}" in + set) + choices="$(gsettings list-keys ${COMP_WORDS[2]} 2> /dev/null | sed -e 's.$. .')" + ;; + + get|reset|writable|monitor) + choices="$(gsettings list-keys ${COMP_WORDS[2]} 2> /dev/null)" + ;; + esac + ;; + esac + + local IFS=$'\n' + COMPREPLY=($(compgen -W "${choices}" "${COMP_WORDS[$COMP_CWORD]}")) } #################################################################################################### diff --git a/gio/gsettings-tool.c b/gio/gsettings-tool.c index cb3f344..e35dd37 100644 --- a/gio/gsettings-tool.c +++ b/gio/gsettings-tool.c @@ -1,10 +1,10 @@ -/* GLIB - Library of useful routines for C programming - * Copyright (C) 2010 Red Hat, Inc. +/* + * Copyright © 2010 Codethink Limited * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * version 2 of the licence, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,828 +16,517 @@ * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * - * Author: Matthias Clasen + * Author: Ryan Lortie */ -#include "config.h" - +#include +#include #include -#include -#include -#include -#include - -static gchar * -pick_word_at (const gchar *s, - gint cursor, - gint *out_word_begins_at) -{ - gint begin; - gint end; - if (s[0] == '\0') - { - if (out_word_begins_at != NULL) - *out_word_begins_at = -1; - return NULL; - } - - if (g_ascii_isspace (s[cursor]) && - ((cursor > 0 && g_ascii_isspace (s[cursor-1])) || cursor == 0)) - { - if (out_word_begins_at != NULL) - *out_word_begins_at = cursor; - return g_strdup (""); - } - while (!g_ascii_isspace (s[cursor - 1]) && cursor > 0) - cursor--; - begin = cursor; +static gboolean +contained (const gchar * const *items, + const gchar *item) +{ + while (*items) + if (strcmp (*items++, item) == 0) + return TRUE; - end = begin; - while (!g_ascii_isspace (s[end]) && s[end] != '\0') - end++; + return FALSE; +} - if (out_word_begins_at != NULL) - *out_word_begins_at = begin; +static gboolean +is_schema (const gchar *schema) +{ + return contained (g_settings_list_schemas (), schema); +} - return g_strndup (s + begin, end - begin); +static gboolean +is_relocatable_schema (const gchar *schema) +{ + return contained (g_settings_list_relocatable_schemas (), schema); } -static gint -usage (gint *argc, - gchar **argv[], - gboolean use_stdout) +static gboolean +check_relocatable_schema (const gchar *schema) { - GOptionContext *context; - gchar *s; - - g_set_prgname (g_path_get_basename ((*argv)[0])); - - context = g_option_context_new (_("COMMAND")); - g_option_context_set_help_enabled (context, FALSE); - s = g_strdup_printf ( - _("Commands:\n" - " help Show this information\n" - " get Get the value of a key\n" - " set Set the value of a key\n" - " reset Reset the value of a key\n" - " monitor Monitor a key for changes\n" - " writable Check if a key is writable\n" - "\n" - "Use '%s COMMAND --help' to get help for individual commands.\n"), - g_get_prgname ()); - g_option_context_set_description (context, s); - g_free (s); - s = g_option_context_get_help (context, FALSE, NULL); - if (use_stdout) - g_print ("%s", s); + if (is_relocatable_schema (schema)) + return TRUE; + + if (is_schema (schema)) + g_printerr ("Schema '%s' is not relocatable " + "(path must not be specified)\n", + schema); + else - g_printerr ("%s", s); - g_free (s); - g_option_context_free (context); + g_printerr ("No such schema '%s'\n", schema); - return use_stdout ? 0 : 1; + return FALSE; } -static void -remove_arg (gint num, gint *argc, gchar **argv[]) +static gboolean +check_schema (const gchar *schema) { - gint n; + if (is_schema (schema)) + return TRUE; - g_assert (num <= (*argc)); + if (is_relocatable_schema (schema)) + g_printerr ("Schema '%s' is relocatable " + "(path must be specified)\n", + schema); - for (n = num; (*argv)[n] != NULL; n++) - (*argv)[n] = (*argv)[n+1]; - (*argv)[n] = NULL; - (*argc) = (*argc) - 1; -} + else + g_printerr ("No such schema '%s'\n", schema); + return FALSE; +} -static void -modify_argv0_for_command (gint *argc, - gchar **argv[], - const gchar *command) +static gboolean +check_path (const gchar *path) { - gchar *s; + if (path[0] == '\0') + { + g_printerr ("Empty path given.\n"); + return FALSE; + } - g_assert (g_strcmp0 ((*argv)[1], command) == 0); - remove_arg (1, argc, argv); + if (path[0] != '/') + { + g_printerr ("Path must begin with a slash (/)\n"); + return FALSE; + } + + if (!g_str_has_suffix (path, "/")) + { + g_printerr ("Path must end with a slash (/)\n"); + return FALSE; + } - s = g_strdup_printf ("%s %s", (*argv)[0], command); - (*argv)[0] = s; + if (strstr (path, "//")) + { + g_printerr ("Path must not contain two adjacent slashes (//)\n"); + return FALSE; + } + + return TRUE; } static gboolean -schema_exists (const gchar *name) +check_key (GSettings *settings, + const gchar *key) { - const gchar * const *schemas; - gint i; + gboolean good; + gchar **keys; - schemas = g_settings_list_schemas (); - for (i = 0; schemas[i]; i++) - if (g_strcmp0 (name, schemas[i]) == 0) - return TRUE; + keys = g_settings_list_keys (settings); + good = contained ((const gchar **) keys, key); + g_strfreev (keys); + + if (good) + return TRUE; + + g_printerr ("No such key '%s'\n", key); return FALSE; } static void -list_schemas (const gchar *prefix) +output_list (const gchar * const *list) { - const gchar * const *schemas; gint i; - schemas = g_settings_list_schemas (); - for (i = 0; schemas[i]; i++) - if (prefix == NULL || g_str_has_prefix (schemas[i], prefix)) - g_print ("%s \n", schemas[i]); + for (i = 0; list[i]; i++) + g_print ("%s\n", list[i]); } -static gboolean -key_exists (GSettings *settings, - const gchar *name) +static void +gsettings_list_schemas (GSettings *settings, + const gchar *key, + const gchar *value) { - gchar **keys; - gint i; - gboolean ret; - - ret = FALSE; - - keys = g_settings_list_keys (settings); - for (i = 0; keys[i]; i++) - if (g_strcmp0 (keys[i], name) == 0) - { - ret = TRUE; - break; - } - g_strfreev (keys); + output_list (g_settings_list_schemas ()); +} - return ret; +static void +gsettings_list_relocatable_schemas (GSettings *settings, + const gchar *key, + const gchar *value) +{ + output_list (g_settings_list_relocatable_schemas ()); } static void -list_keys (GSettings *settings, - const gchar *prefix) +gsettings_list_keys (GSettings *settings, + const gchar *key, + const gchar *value) { gchar **keys; - gint i; keys = g_settings_list_keys (settings); - for (i = 0; keys[i]; i++) - { - if (prefix == NULL || g_str_has_prefix (keys[i], prefix)) - g_print ("%s \n", keys[i]); - } + output_list ((const gchar **) keys); g_strfreev (keys); } static void -list_options (GOptionContext *context, - const gchar *prefix) +gsettings_list_children (GSettings *settings, + const gchar *key, + const gchar *value) { - /* FIXME extract options from context */ - const gchar *options[] = { "--help", "--path", NULL }; + gchar **children; + gint max = 0; gint i; - for (i = 0; options[i]; i++) - if (g_str_has_prefix (options[i], prefix)) - g_print ("%s \n", options[i]); -} -static gint -handle_get (gint *argc, - gchar **argv[], - gboolean request_completion, - gchar *completion_cur, - gchar *completion_prev) -{ - gchar *schema; - gchar *path; - gchar *key; - GSettings *settings; - GVariant *v; - GOptionContext *context; - GOptionEntry entries[] = { - { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") }, - { NULL } - }; - GError *error; - gint ret = 1; - - modify_argv0_for_command (argc, argv, "get"); - - context = g_option_context_new (_("SCHEMA KEY")); - g_option_context_set_help_enabled (context, FALSE); - g_option_context_set_summary (context, _("Get the value of KEY")); - g_option_context_set_description (context, - _("Arguments:\n" - " SCHEMA The id of the schema\n" - " KEY The name of the key\n")); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - - settings = NULL; - path = NULL; - schema = NULL; - key = NULL; - - error = NULL; - if (!g_option_context_parse (context, argc, argv, NULL)) - { - if (!request_completion) - { - gchar *s; - s = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", s); - g_free (s); - - goto out; - } - } - - if (*argc > 1) - schema = (*argv)[1]; - if (*argc > 2) - key = (*argv)[2]; + children = g_settings_list_children (settings); + for (i = 0; children[i]; i++) + if (strlen (children[i]) > max) + max = strlen (children[i]); - if (request_completion && completion_cur[0] == '-') + for (i = 0; children[i]; i++) { - list_options (context, completion_cur); - ret = 0; - goto out; - } - - if (request_completion && !schema_exists (schema)) - { - list_schemas (schema); - ret = 0; - goto out; - } + GSettings *child; + gchar *schema; + gchar *path; - if (path) - settings = g_settings_new_with_path (schema, path); - else - settings = g_settings_new (schema); + child = g_settings_get_child (settings, children[i]); + g_object_get (child, + "schema", &schema, + "path", &path, + NULL); - if (request_completion && !key_exists (settings, key)) - { - list_keys (settings, key); - ret = 0; - goto out; - } + if (is_schema (schema)) + g_print ("%-*s %s\n", max, children[i], schema); + else + g_print ("%-*s %s:%s\n", max, children[i], schema, path); - if (!request_completion) - { - v = g_settings_get_value (settings, key); - g_print ("%s\n", g_variant_print (v, FALSE)); - g_variant_unref (v); - ret = 0; + g_object_unref (child); + g_free (schema); + g_free (path); } - out: - if (settings) - g_object_unref (settings); + g_strfreev (children); +} - g_option_context_free (context); +static void +gsettings_get (GSettings *settings, + const gchar *key, + const gchar *value_) +{ + GVariant *value; + gchar *printed; + + value = g_settings_get_value (settings, key); + printed = g_variant_print (value, TRUE); + g_print ("%s\n", printed); + g_variant_unref (value); + g_free (printed); +} - return ret; +static void +gsettings_reset (GSettings *settings, + const gchar *key, + const gchar *value) +{ + g_settings_reset (settings, key); + g_settings_sync (); } -static gint -handle_set (gint *argc, - gchar **argv[], - gboolean request_completion, - gchar *completion_cur, - gchar *completion_prev) +static void +gsettings_writable (GSettings *settings, + const gchar *key, + const gchar *value) { - gchar *schema; - gchar *path; - gchar *key; - gchar *value; - GSettings *settings; - GVariant *v, *default_v; - const GVariantType *type; - GOptionContext *context; - GOptionEntry entries[] = { - { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") }, - { NULL } - }; - GError *error; - gint ret = 1; - - modify_argv0_for_command (argc, argv, "set"); - - /* Translators: Please keep order of words (command parameters) */ - context = g_option_context_new (_("SCHEMA KEY VALUE")); - g_option_context_set_help_enabled (context, FALSE); - g_option_context_set_summary (context, _("Set the value of KEY")); - g_option_context_set_description (context, - _("Arguments:\n" - " SCHEMA The id of the schema\n" - " KEY The name of the key\n" - " VALUE The value to set key to, as a serialized GVariant\n")); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - - settings = NULL; - path = NULL; - schema = NULL; - key = NULL; - - error = NULL; - if (!g_option_context_parse (context, argc, argv, NULL)) - { - if (!request_completion) - { - gchar *s; - s = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", s); - g_free (s); - goto out; - } - } + g_print ("%s\n", + g_settings_is_writable (settings, key) ? + "true" : "false"); +} - if (*argc > 1) - schema = (*argv)[1]; - if (*argc > 2) - key = (*argv)[2]; - if (*argc > 3) - value = (*argv)[3]; +static void +value_changed (GSettings *settings, + const gchar *key, + gpointer user_data) +{ + GVariant *value; + gchar *printed; + + value = g_settings_get_value (settings, key); + printed = g_variant_print (value, TRUE); + g_print ("%s: %s\n", key, printed); + g_variant_unref (value); + g_free (printed); +} - if (request_completion && completion_cur[0] == '-') +static void +gsettings_monitor (GSettings *settings, + const gchar *key, + const gchar *value) +{ + if (key) { - list_options (context, completion_cur); - ret = 0; - goto out; - } + gchar *name; - if (request_completion && !schema_exists (schema)) - { - list_schemas (schema); - ret = 0; - goto out; + name = g_strdup_printf ("changed::%s", key); + g_signal_connect (settings, name, G_CALLBACK (value_changed), NULL); } - - if (path) - settings = g_settings_new_with_path (schema, path); else - settings = g_settings_new (schema); + g_signal_connect (settings, "changed", G_CALLBACK (value_changed), NULL); - if (request_completion && !key_exists (settings, key)) - { - list_keys (settings, key); - ret = 0; - goto out; - } + g_main_loop_run (g_main_loop_new (NULL, FALSE)); +} - if (!request_completion) - { - default_v = g_settings_get_value (settings, key); - type = g_variant_get_type (default_v); +static void +gsettings_set (GSettings *settings, + const gchar *key, + const gchar *value) +{ + const GVariantType *type; + GError *error = NULL; + GVariant *existing; + GVariant *new; - error = NULL; - v = g_variant_parse (type, value, NULL, NULL, &error); - g_variant_unref (default_v); - if (v == NULL) - { - g_printerr ("%s\n", error->message); - goto out; - } + existing = g_settings_get_value (settings, key); + type = g_variant_get_type (existing); - if (!g_settings_set_value (settings, key, v)) - { - g_printerr (_("Key %s is not writable\n"), key); - goto out; - } + new = g_variant_parse (type, value, NULL, NULL, &error); - g_settings_sync (); - ret = 0; + if (new == NULL) + { + g_printerr ("%s\n", error->message); + exit (1); } - out: - if (settings) - g_object_unref (settings); - - g_option_context_free (context); + g_settings_set_value (settings, key, new); + g_variant_unref (existing); + g_variant_unref (new); - return ret; + g_settings_sync (); } - -static gint -handle_reset (gint *argc, - gchar **argv[], - gboolean request_completion, - gchar *completion_cur, - gchar *completion_prev) +static int +gsettings_help (gboolean requested, + const gchar *command) { - gchar *schema; - gchar *path; - gchar *key; - GSettings *settings; - GOptionContext *context; - GOptionEntry entries[] = { - { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") }, - { NULL } - }; - GError *error; - gint ret = 1; - - modify_argv0_for_command (argc, argv, "reset"); - - context = g_option_context_new (_("SCHEMA KEY VALUE")); - g_option_context_set_help_enabled (context, FALSE); - g_option_context_set_summary (context, _("Sets KEY to its default value")); - g_option_context_set_description (context, - _("Arguments:\n" - " SCHEMA The id of the schema\n" - " KEY The name of the key\n")); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - - settings = NULL; - path = NULL; - schema = NULL; - key = NULL; - - error = NULL; - if (!g_option_context_parse (context, argc, argv, NULL)) - { - if (!request_completion) - { - gchar *s; - s = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", s); - g_free (s); - goto out; - } - } + const gchar *description; + const gchar *synopsis; + GString *string; - if (*argc > 1) - schema = (*argv)[1]; - if (*argc > 2) - key = (*argv)[2]; + string = g_string_new (NULL); - if (request_completion && completion_cur[0] == '-') + if (command == NULL) + ; + + else if (strcmp (command, "list-schemas") == 0) { - list_options (context, completion_cur); - ret = 0; - goto out; + description = "List the installed (non-relocatable) schemas"; + synopsis = ""; } - if (request_completion && !schema_exists (schema)) + else if (strcmp (command, "list-relocatable-schemas") == 0) { - list_schemas (schema); - ret = 0; - goto out; + description = "List the installed relocatable schemas"; + synopsis = ""; } - if (path) - settings = g_settings_new_with_path (schema, path); - else - settings = g_settings_new (schema); - - if (request_completion && !key_exists (settings, key)) + else if (strcmp (command, "list-keys") == 0) { - list_keys (settings, key); - ret = 0; - goto out; + description = "Lists the keys in SCHEMA"; + synopsis = "SCHEMA[:PATH]"; } - if (!request_completion) + else if (strcmp (command, "list-children") == 0) { - g_settings_reset (settings, key); - g_settings_sync (); - ret = 0; + description = "Lists the children of SCHEMA"; + synopsis = "SCHEMA[:PATH]"; } - out: - if (settings) - g_object_unref (settings); - - g_option_context_free (context); - - return ret; -} - -static gint -handle_writable (gint *argc, - gchar **argv[], - gboolean request_completion, - gchar *completion_cur, - gchar *completion_prev) -{ - gchar *schema; - gchar *path; - gchar *key; - GSettings *settings; - GOptionContext *context; - GOptionEntry entries[] = { - { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") }, - { NULL } - }; - GError *error; - gint ret = 1; - - modify_argv0_for_command (argc, argv, "writable"); - - /* Translators: Please keep order of words (command parameters) */ - context = g_option_context_new (_("SCHEMA KEY")); - g_option_context_set_help_enabled (context, FALSE); - g_option_context_set_summary (context, _("Find out whether KEY is writable")); - g_option_context_set_description (context, - _("Arguments:\n" - " SCHEMA The id of the schema\n" - " KEY The name of the key\n")); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - - settings = NULL; - path = NULL; - schema = NULL; - key = NULL; - - error = NULL; - if (!g_option_context_parse (context, argc, argv, NULL)) + else if (strcmp (command, "get") == 0) { - if (!request_completion) - { - gchar *s; - s = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", s); - g_free (s); - goto out; - } + description = "Gets the value of KEY"; + synopsis = "SCHEMA[:PATH] KEY"; } - if (*argc > 1) - schema = (*argv)[1]; - if (*argc > 2) - key = (*argv)[2]; + else if (strcmp (command, "set") == 0) + { + description = "Sets the value of KEY to VALUE"; + synopsis = "SCHEMA[:PATH] KEY VALUE"; + } - if (request_completion && completion_cur[0] == '-') + else if (strcmp (command, "reset") == 0) { - list_options (context, completion_cur); - ret = 0; - goto out; + description = "Resets KEY to its default value"; + synopsis = "SCHEMA[:PATH] KEY"; } - if (request_completion && !schema_exists (schema)) + else if (strcmp (command, "writable") == 0) { - list_schemas (schema); - ret = 0; - goto out; + description = "Checks if KEY is writable"; + synopsis = "SCHEMA[:PATH] KEY"; } - if (path) - settings = g_settings_new_with_path (schema, path); + else if (strcmp (command, "monitor") == 0) + { + description = "Monitors KEY for changes.\n" + "If no KEY is specified, monitor all keys in SCHEMA.\n" + "Use ^C to stop monitoring.\n"; + synopsis = "SCHEMA[:PATH] [KEY]"; + } else - settings = g_settings_new (schema); - - if (request_completion && !key_exists (settings, key)) { - list_keys (settings, key); - ret = 0; - goto out; + g_string_printf (string, "Unknown command %s\n\n", command); + requested = FALSE; + command = NULL; + } + + if (command == NULL) + { + g_string_append (string, + "Usage:\n" + " gsettings COMMAND [ARGS...]\n" + "\n" + "Commands:\n" + " help Show this information\n" + " list-schemas List installed schemas\n" + " list-relocatable-schemas List relocatable schemas\n" + " list-keys List keys in a schema\n" + " list-children List children of a schema\n" + " get Get the value of a key\n" + " set Set the value of a key\n" + " reset Reset the value of a key\n" + " writable Check if a key is writable\n" + " monitor Watch for changes\n" + "\n" + "Use 'gsettings help COMMAND' to get detailed help.\n\n"); } - - if (!request_completion) + else { - if (g_settings_is_writable (settings, key)) - g_print ("true\n"); - else - g_print ("false\n"); - ret = 0; + g_string_append_printf (string, "Usage:\n gsettings %s %s\n\n%s\n\n", + command, synopsis, description); + + if (synopsis[0]) + { + g_string_append (string, "Arguments:\n"); + + if (strstr (synopsis, "SCHEMA")) + g_string_append (string, + " SCHEMA The name of the schema\n" + " PATH The path, for relocatable schemas\n"); + + if (strstr (synopsis, "[KEY]")) + g_string_append (string, + " KEY The (optional) key within the schema\n"); + + else if (strstr (synopsis, "KEY")) + g_string_append (string, + " KEY The key within the schema\n"); + + if (strstr (synopsis, "VALUE")) + g_string_append (string, + " VALUE The value to set\n"); + + g_string_append (string, "\n"); + } } - out: - if (settings) - g_object_unref (settings); + if (requested) + g_print ("%s", string->str); + else + g_printerr ("%s", string->str); - g_option_context_free (context); + g_string_free (string, TRUE); - return ret; + return requested ? 0 : 1; } -static void -key_changed (GSettings *settings, - const gchar *key) -{ - GVariant *v; - gchar *value; - - v = g_settings_get_value (settings, key); - value = g_variant_print (v, FALSE); - g_print ("%s\n", value); - g_free (value); - g_variant_unref (v); -} -static gint -handle_monitor (gint *argc, - gchar **argv[], - gboolean request_completion, - gchar *completion_cur, - gchar *completion_prev) +int +main (int argc, char **argv) { - gchar *schema; - gchar *path; - gchar *key; + void (* function) (GSettings *, const gchar *, const gchar *); GSettings *settings; - gchar *detailed_signal; - GMainLoop *loop; - GOptionContext *context; - GOptionEntry entries[] = { - { "path", 'p', 0, G_OPTION_ARG_STRING, &path, N_("Specify the path for the schema"), N_("PATH") }, - { NULL } - }; - GError *error; - gint ret = 1; - - modify_argv0_for_command (argc, argv, "monitor"); - - context = g_option_context_new (_("SCHEMA KEY")); - g_option_context_set_help_enabled (context, FALSE); - g_option_context_set_summary (context, - _("Monitor KEY for changes and print the changed values.\n" - "Monitoring will continue until the process is terminated.")); - - g_option_context_set_description (context, - _("Arguments:\n" - " SCHEMA The id of the schema\n" - " KEY The name of the key\n")); - g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - - settings = NULL; - path = NULL; - schema = NULL; - key = NULL; - - error = NULL; - if (!g_option_context_parse (context, argc, argv, NULL)) - { - if (!request_completion) - { - gchar *s; - s = g_option_context_get_help (context, FALSE, NULL); - g_printerr ("%s", s); - g_free (s); - goto out; - } - } + const gchar *key; - if (*argc > 1) - schema = (*argv)[1]; - if (*argc > 2) - key = (*argv)[2]; + if (argc < 2) + return gsettings_help (FALSE, NULL); - if (request_completion && completion_cur[0] == '-') - { - list_options (context, completion_cur); - ret = 0; - goto out; - } + else if (strcmp (argv[1], "help") == 0) + return gsettings_help (TRUE, argv[2]); - if (request_completion && !schema_exists (schema)) - { - list_schemas (schema); - ret = 0; - goto out; - } + else if (argc == 2 && strcmp (argv[1], "list-schemas") == 0) + function = gsettings_list_schemas; - if (path) - settings = g_settings_new_with_path (schema, path); - else - settings = g_settings_new (schema); + else if (argc == 2 && strcmp (argv[1], "list-relocatable-schemas") == 0) + function = gsettings_list_relocatable_schemas; - if (request_completion && !key_exists (settings, key)) - { - list_keys (settings, key); - ret = 0; - goto out; - } + else if (argc == 3 && strcmp (argv[1], "list-keys") == 0) + function = gsettings_list_keys; - if (!request_completion) - { - detailed_signal = g_strdup_printf ("changed::%s", key); - g_signal_connect (settings, detailed_signal, - G_CALLBACK (key_changed), NULL); - - loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (loop); - g_main_loop_unref (loop); - ret = 0; - } + else if (argc == 3 && strcmp (argv[1], "list-children") == 0) + function = gsettings_list_children; - out: - if (settings) - g_object_unref (settings); + else if (argc == 4 && strcmp (argv[1], "get") == 0) + function = gsettings_get; - g_option_context_free (context); + else if (argc == 5 && strcmp (argv[1], "set") == 0) + function = gsettings_set; - return ret; -} + else if (argc == 4 && strcmp (argv[1], "reset") == 0) + function = gsettings_reset; -int -main (int argc, char *argv[]) -{ - gboolean ret; - gchar *command; - gboolean request_completion; - gchar *completion_cur; - gchar *completion_prev; + else if (argc == 4 && strcmp (argv[1], "writable") == 0) + function = gsettings_writable; - setlocale (LC_ALL, ""); + else if ((argc == 3 || argc == 4) && strcmp (argv[1], "monitor") == 0) + function = gsettings_monitor; - g_type_init (); + else + return gsettings_help (FALSE, argv[1]); - ret = 1; - completion_cur = NULL; - completion_prev = NULL; - request_completion = FALSE; + g_type_init (); - if (argc < 2) + if (argc > 2) { - ret = usage (&argc, &argv, FALSE); - goto out; - } - - again: - command = argv[1]; + gchar **parts; - if (g_strcmp0 (command, "help") == 0) - { - if (!request_completion) - ret = usage (&argc, &argv, TRUE); - } - else if (g_strcmp0 (command, "get") == 0) - ret = handle_get (&argc, &argv, request_completion, completion_cur, completion_prev); - else if (g_strcmp0 (command, "set") == 0) - ret = handle_set (&argc, &argv, request_completion, completion_cur, completion_prev); - else if (g_strcmp0 (command, "reset") == 0) - ret = handle_reset (&argc, &argv, request_completion, completion_cur, completion_prev); - else if (g_strcmp0 (command, "monitor") == 0) - ret = handle_monitor (&argc, &argv, request_completion, completion_cur, completion_prev); - else if (g_strcmp0 (command, "writable") == 0) - ret = handle_writable (&argc, &argv, request_completion, completion_cur, completion_prev); - else if (g_strcmp0 (command, "complete") == 0 && argc == 4 && !request_completion) - { - gchar *completion_line; - gint completion_point; - gchar *endp; - gchar **completion_argv; - gint completion_argc; - gint cur_begin; - - request_completion = TRUE; - - completion_line = argv[2]; - completion_point = strtol (argv[3], &endp, 10); - if (endp == argv[3] || *endp != '\0') - goto out; - - if (!g_shell_parse_argv (completion_line, - &completion_argc, - &completion_argv, - NULL)) + if (argv[2][0] == '\0') { - /* can't parse partical cmdline, don't attempt completion */ - goto out; + g_printerr ("Empty schema name given"); + return 1; } - completion_prev = NULL; - completion_cur = pick_word_at (completion_line, completion_point, &cur_begin); - if (cur_begin > 0) + parts = g_strsplit (argv[2], ":", 2); + + if (parts[1]) { - gint prev_end; - for (prev_end = cur_begin - 1; prev_end >= 0; prev_end--) - { - if (!g_ascii_isspace (completion_line[prev_end])) - { - completion_prev = pick_word_at (completion_line, prev_end, NULL); - break; - } - } + if (!check_relocatable_schema (parts[0]) || !check_path (parts[1])) + return 1; + + settings = g_settings_new_with_path (parts[0], parts[1]); } + else + { + if (!check_schema (parts[0])) + return 1; - argc = completion_argc; - argv = completion_argv; + settings = g_settings_new (parts[0]); + } - ret = 0; - goto again; + g_strfreev (parts); } else + settings = NULL; + + if (argc > 3) { - if (request_completion) - { - g_print ("help \nget \nmonitor \nwritable \nset \nreset \n"); - ret = 0; - } - else - { - g_printerr (_("Unknown command '%s'\n"), argv[1]); - ret = usage (&argc, &argv, FALSE); - } + if (!check_key (settings, argv[3])) + return 1; + + key = argv[3]; } + else + key = NULL; + + (* function) (settings, key, argc > 4 ? argv[4] : NULL); - out: - g_free (completion_cur); - g_free (completion_prev); + if (settings != NULL) + g_object_unref (settings); - return ret; + return 0; } -- 2.7.4