[glib] gsettings-tool: Rewrite



commit 2d6f8a8ea4a0c86c40da60db2d948306f4c2f5c9
Author: Ryan Lortie <desrt desrt ca>
Date:   Sun Oct 3 02:40:48 2010 -0400

    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 <desrt desrt ca>
  */
 
-#include "config.h"
-
+#include <gio/gio.h>
+#include <string.h>
 #include <stdlib.h>
-#include <stdio.h>
-#include <locale.h>
-#include <gi18n.h>
-#include <gio.h>
-
-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;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]