[libvirt] [PATCH 09/11] virsh: convert command line parsing to use GOptionContext

Daniel P. Berrangé posted 11 patches 6 years, 4 months ago
Only 10 patches received!
There is a newer version of this series
[libvirt] [PATCH 09/11] virsh: convert command line parsing to use GOptionContext
Posted by Daniel P. Berrangé 6 years, 4 months ago
The GOptionContext API has the benefit over getopt_long that it will
automatically handle --help output formatting.

Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 tools/virsh.c | 303 ++++++++++++++++++++++----------------------------
 1 file changed, 135 insertions(+), 168 deletions(-)

diff --git a/tools/virsh.c b/tools/virsh.c
index ec20f35a77..6c469ff576 100644
--- a/tools/virsh.c
+++ b/tools/virsh.c
@@ -23,7 +23,6 @@
 
 #include <stdarg.h>
 #include <unistd.h>
-#include <getopt.h>
 #include <sys/time.h>
 #include <fcntl.h>
 #include <time.h>
@@ -445,53 +444,36 @@ virshDeinit(vshControl *ctl)
 }
 
 /*
- * Print usage
+ * Build help description for commands
  */
-static void
-virshUsage(void)
+static char *
+virshBuildDescription(void)
 {
     const vshCmdGrp *grp;
     const vshCmdDef *cmd;
-
-    fprintf(stdout, _("\n%s [options]... [<command_string>]"
-                      "\n%s [options]... <command> [args...]\n\n"
-                      "  options:\n"
-                      "    -c | --connect=URI      hypervisor connection URI\n"
-                      "    -d | --debug=NUM        debug level [0-4]\n"
-                      "    -e | --escape <char>    set escape sequence for console\n"
-                      "    -h | --help             this help\n"
-                      "    -k | --keepalive-interval=NUM\n"
-                      "                            keepalive interval in seconds, 0 for disable\n"
-                      "    -K | --keepalive-count=NUM\n"
-                      "                            number of possible missed keepalive messages\n"
-                      "    -l | --log=FILE         output logging to file\n"
-                      "    -q | --quiet            quiet mode\n"
-                      "    -r | --readonly         connect readonly\n"
-                      "    -t | --timing           print timing information\n"
-                      "    -v                      short version\n"
-                      "    -V                      long version\n"
-                      "         --version[=TYPE]   version, TYPE is short or long (default short)\n"
-                      "  commands (non interactive mode):\n\n"), progname,
-            progname);
+    GString *str = g_string_new("Commands (non interactive mode):\n\n");
 
     for (grp = cmdGroups; grp->name; grp++) {
-        fprintf(stdout, _(" %s (help keyword '%s')\n"),
-                grp->name, grp->keyword);
+        g_string_append_printf(str,
+                               _("  %s (help keyword '%s')\n"),
+                               grp->name, grp->keyword);
         for (cmd = grp->commands; cmd->name; cmd++) {
             if (cmd->flags & VSH_CMD_FLAG_ALIAS)
                 continue;
-            fprintf(stdout,
-                    "    %-30s %s\n", cmd->name,
-                    _(vshCmddefGetInfo(cmd, "help")));
+            g_string_append_printf(str,
+                                   "    %-30s %s\n",
+                                   cmd->name,
+                                   _(vshCmddefGetInfo(cmd, "help")));
         }
-        fprintf(stdout, "\n");
+        g_string_append_printf(str, "\n");
     }
 
-    fprintf(stdout, "%s",
-            _("\n  (specify help <group> for details about the commands in the group)\n"));
-    fprintf(stdout, "%s",
-            _("\n  (specify help <command> for details about the command)\n\n"));
-    return;
+    g_string_append_printf(str,
+                           _("Specify help <group> for details about the commands in the group)\n"));
+    g_string_append_printf(str,
+                           _("Specify help <command> for details about the command)\n"));
+
+    return g_string_free(str, FALSE);
 }
 
 /*
@@ -647,6 +629,22 @@ virshAllowedEscapeChar(char c)
         ('@' <= c && c <= '_');
 }
 
+static gboolean
+virshVersion(const gchar *option_name G_GNUC_UNUSED,
+             const gchar *value,
+             gpointer data,
+             GError **error G_GNUC_UNUSED)
+{
+    vshControl *ctl = data;
+
+    if (value == NULL || STRNEQ(value, "long"))
+        puts(VERSION);
+    else
+        virshShowVersion(ctl);
+
+    exit(EXIT_SUCCESS);
+}
+
 /*
  * argv[]:  virsh [options] [command]
  *
@@ -654,152 +652,121 @@ virshAllowedEscapeChar(char c)
 static bool
 virshParseArgv(vshControl *ctl, int argc, char **argv)
 {
-    int arg, len, debug, keepalive;
-    size_t i;
-    int longindex = -1;
+    int debug = 0;
+    bool version = false;
+    size_t len;
     virshControlPtr priv = ctl->privData;
-    struct option opt[] = {
-        {"connect", required_argument, NULL, 'c'},
-        {"debug", required_argument, NULL, 'd'},
-        {"escape", required_argument, NULL, 'e'},
-        {"help", no_argument, NULL, 'h'},
-        {"keepalive-interval", required_argument, NULL, 'k'},
-        {"keepalive-count", required_argument, NULL, 'K'},
-        {"log", required_argument, NULL, 'l'},
-        {"quiet", no_argument, NULL, 'q'},
-        {"readonly", no_argument, NULL, 'r'},
-        {"timing", no_argument, NULL, 't'},
-        {"version", optional_argument, NULL, 'v'},
-        {NULL, 0, NULL, 0}
+    char *logfile = NULL;
+    int keepalive_interval = INT_MAX;
+    int keepalive_count = INT_MAX;
+    GOptionEntry opt[] = {
+        { "connect", 'c', 0,
+          G_OPTION_ARG_STRING, &ctl->connname,
+          _("hypervisor connection URI"), "URI" },
+        { "debug", 'd', 0,
+          G_OPTION_ARG_INT, &debug,
+          _("debug level [0-4]\n"), "LEVEL" },
+        { "escape", 'e', 0,
+          G_OPTION_ARG_STRING, &priv->escapeChar,
+          _("set escape sequence for console"), "ESCAPE" },
+        { "keepalive-interval", 'k', 0,
+          G_OPTION_ARG_INT, &keepalive_interval,
+          _("keepalive interval in seconds, 0 for disable"), "SECS" },
+        { "keepalive-count", 'K', 0,
+          G_OPTION_ARG_INT, &keepalive_count,
+          _("number of possible missed keepalive messages"), "NUM" },
+        { "log", 'l', 0,
+          G_OPTION_ARG_STRING, &logfile,
+          _("output logging to file"), "FILENAME" },
+        { "quiet", 'q', 0,
+          G_OPTION_ARG_NONE, &ctl->quiet,
+          _("quite mode"), NULL },
+        { "readonly", 'r', 0,
+          G_OPTION_ARG_NONE, &priv->readonly,
+          _("connect readonly"), NULL },
+        { "timing", 't', 0,
+          G_OPTION_ARG_NONE, &ctl->timing,
+          _("print timing information"), NULL },
+        { "version", 'v', G_OPTION_FLAG_OPTIONAL_ARG,
+          G_OPTION_ARG_CALLBACK, virshVersion,
+          _("print short version"), "[short]" },
+        { "version", 'V', 0,
+          G_OPTION_ARG_NONE, &version,
+          _("print long version"), "long" },
+        { NULL, 0, 0, 0, NULL, NULL, NULL },
     };
+    g_autoptr(GOptionContext) optctx = NULL;
+    GOptionGroup *optgrp;
+    g_autoptr(GError) error = NULL;
+
+    optctx = g_option_context_new(_("[COMMAND [OPTION…] - libvirt shell"));
+    optgrp = g_option_group_new(NULL, NULL, NULL, ctl, NULL);
+    g_option_group_set_translation_domain(optgrp, PACKAGE);
+    g_option_group_add_entries(optgrp, opt);
+    g_option_context_set_main_group(optctx, optgrp);
+    g_option_context_set_strict_posix(optctx, true);
+    g_option_context_set_description(optctx,
+                                     virshBuildDescription());
+
+    if (!g_option_context_parse(optctx, &argc, &argv, &error)) {
+        vshError(ctl, _("option parsing failed: %s\n"), error->message);
+        exit(EXIT_FAILURE);
+    }
 
-    /* Standard (non-command) options. The leading + ensures that no
-     * argument reordering takes place, so that command options are
-     * not confused with top-level virsh options. */
-    while ((arg = getopt_long(argc, argv, "+:c:d:e:hk:K:l:qrtvV", opt, &longindex)) != -1) {
-        switch (arg) {
-        case 'c':
-            VIR_FREE(ctl->connname);
-            ctl->connname = vshStrdup(ctl, optarg);
-            break;
-        case 'd':
-            if (virStrToLong_i(optarg, NULL, 10, &debug) < 0) {
-                vshError(ctl, _("option %s takes a numeric argument"),
-                         longindex == -1 ? "-d" : "--debug");
-                exit(EXIT_FAILURE);
-            }
-            if (debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR)
-                vshError(ctl, _("ignoring debug level %d out of range [%d-%d]"),
-                         debug, VSH_ERR_DEBUG, VSH_ERR_ERROR);
-            else
-                ctl->debug = debug;
-            break;
-        case 'e':
-            len = strlen(optarg);
-
-            if ((len == 2 && *optarg == '^' &&
-                 virshAllowedEscapeChar(optarg[1])) ||
-                (len == 1 && *optarg != '^')) {
-                priv->escapeChar = optarg;
-            } else {
-                vshError(ctl, _("Invalid string '%s' for escape sequence"),
-                         optarg);
-                exit(EXIT_FAILURE);
-            }
-            break;
-        case 'h':
-            virshUsage();
-            exit(EXIT_SUCCESS);
-            break;
-        case 'k':
-            if (virStrToLong_i(optarg, NULL, 0, &keepalive) < 0) {
-                vshError(ctl,
-                         _("Invalid value for option %s"),
-                         longindex == -1 ? "-k" : "--keepalive-interval");
-                exit(EXIT_FAILURE);
-            }
-
-            if (keepalive < 0) {
-                vshError(ctl,
-                         _("option %s requires a positive integer argument"),
-                         longindex == -1 ? "-k" : "--keepalive-interval");
-                exit(EXIT_FAILURE);
-            }
-            ctl->keepalive_interval = keepalive;
-            break;
-        case 'K':
-            if (virStrToLong_i(optarg, NULL, 0, &keepalive) < 0) {
-                vshError(ctl,
-                         _("Invalid value for option %s"),
-                         longindex == -1 ? "-K" : "--keepalive-count");
-                exit(EXIT_FAILURE);
-            }
+    if (debug < VSH_ERR_DEBUG || debug > VSH_ERR_ERROR) {
+        vshError(ctl, _("debug level %d out of range [%d-%d]"),
+                 debug, VSH_ERR_DEBUG, VSH_ERR_ERROR);
+        exit(EXIT_FAILURE);
+    }
 
-            if (keepalive < 0) {
-                vshError(ctl,
-                         _("option %s requires a positive integer argument"),
-                         longindex == -1 ? "-K" : "--keepalive-count");
-                exit(EXIT_FAILURE);
-            }
-            ctl->keepalive_count = keepalive;
-            break;
-        case 'l':
-            vshCloseLogFile(ctl);
-            ctl->logfile = vshStrdup(ctl, optarg);
-            vshOpenLogFile(ctl);
-            break;
-        case 'q':
-            ctl->quiet = true;
-            break;
-        case 't':
-            ctl->timing = true;
-            break;
-        case 'r':
-            priv->readonly = true;
-            break;
-        case 'v':
-            if (STRNEQ_NULLABLE(optarg, "long")) {
-                puts(VERSION);
-                exit(EXIT_SUCCESS);
-            }
-            ATTRIBUTE_FALLTHROUGH;
-        case 'V':
-            virshShowVersion(ctl);
-            exit(EXIT_SUCCESS);
-        case ':':
-            for (i = 0; opt[i].name != NULL; i++) {
-                if (opt[i].val == optopt)
-                    break;
-            }
-            if (opt[i].name)
-                vshError(ctl, _("option '-%c'/'--%s' requires an argument"),
-                         optopt, opt[i].name);
-            else
-                vshError(ctl, _("option '-%c' requires an argument"), optopt);
+    if (keepalive_interval != INT_MAX) {
+        if (keepalive_interval < 0) {
+            vshError(ctl,
+                     _("keepalive interval requires a positive integer"));
             exit(EXIT_FAILURE);
-        case '?':
-            if (optopt)
-                vshError(ctl, _("unsupported option '-%c'. See --help."), optopt);
-            else
-                vshError(ctl, _("unsupported option '%s'. See --help."), argv[optind - 1]);
-            exit(EXIT_FAILURE);
-        default:
-            vshError(ctl, _("unknown option"));
+        }
+        ctl->keepalive_interval = keepalive_interval;
+    }
+
+    if (keepalive_count != INT_MAX) {
+        if (keepalive_count < 0) {
+            vshError(ctl,
+                     _("keepalive count requires a positive integer"));
             exit(EXIT_FAILURE);
         }
-        longindex = -1;
+        ctl->keepalive_count = keepalive_count;
+    }
+
+    len = strlen(priv->escapeChar);
+    if (!((len == 2 && *priv->escapeChar == '^' &&
+           virshAllowedEscapeChar(priv->escapeChar[1])) ||
+          (len == 1 && *priv->escapeChar != '^'))) {
+        vshError(ctl, _("Invalid string '%s' for escape sequence"),
+                 priv->escapeChar);
+        exit(EXIT_FAILURE);
+    }
+
+    if (version) {
+        virshShowVersion(ctl);
+        exit(EXIT_SUCCESS);
+    }
+
+    if (logfile) {
+        vshCloseLogFile(ctl);
+        ctl->logfile = logfile;
+        vshOpenLogFile(ctl);
     }
 
-    if (argc == optind) {
+    if (argc == 1) {
         ctl->imode = true;
     } else {
         /* parse command */
         ctl->imode = false;
-        if (argc - optind == 1) {
-            vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[optind]);
-            return vshCommandStringParse(ctl, argv[optind], NULL);
+        if (argc == 2) {
+            vshDebug(ctl, VSH_ERR_INFO, "commands: \"%s\"\n", argv[1]);
+            return vshCommandStringParse(ctl, argv[1], NULL);
         } else {
-            return vshCommandArgvParse(ctl, argc - optind, argv + optind);
+            return vshCommandArgvParse(ctl, argc - 1, argv + 1);
         }
     }
     return true;
-- 
2.21.0

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 09/11] virsh: convert command line parsing to use GOptionContext
Posted by Pavel Hrdina 6 years, 4 months ago
On Fri, Sep 27, 2019 at 06:17:31PM +0100, Daniel P. Berrangé wrote:
> The GOptionContext API has the benefit over getopt_long that it will
> automatically handle --help output formatting.
> 
> Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> ---
>  tools/virsh.c | 303 ++++++++++++++++++++++----------------------------
>  1 file changed, 135 insertions(+), 168 deletions(-)
> 
> diff --git a/tools/virsh.c b/tools/virsh.c
> index ec20f35a77..6c469ff576 100644
> --- a/tools/virsh.c
> +++ b/tools/virsh.c
> @@ -23,7 +23,6 @@
>  
>  #include <stdarg.h>
>  #include <unistd.h>
> -#include <getopt.h>
>  #include <sys/time.h>
>  #include <fcntl.h>
>  #include <time.h>
> @@ -445,53 +444,36 @@ virshDeinit(vshControl *ctl)
>  }
>  
>  /*
> - * Print usage
> + * Build help description for commands
>   */
> -static void
> -virshUsage(void)
> +static char *
> +virshBuildDescription(void)
>  {
>      const vshCmdGrp *grp;
>      const vshCmdDef *cmd;
> -
> -    fprintf(stdout, _("\n%s [options]... [<command_string>]"
> -                      "\n%s [options]... <command> [args...]\n\n"
> -                      "  options:\n"
> -                      "    -c | --connect=URI      hypervisor connection URI\n"
> -                      "    -d | --debug=NUM        debug level [0-4]\n"
> -                      "    -e | --escape <char>    set escape sequence for console\n"
> -                      "    -h | --help             this help\n"
> -                      "    -k | --keepalive-interval=NUM\n"
> -                      "                            keepalive interval in seconds, 0 for disable\n"
> -                      "    -K | --keepalive-count=NUM\n"
> -                      "                            number of possible missed keepalive messages\n"
> -                      "    -l | --log=FILE         output logging to file\n"
> -                      "    -q | --quiet            quiet mode\n"
> -                      "    -r | --readonly         connect readonly\n"
> -                      "    -t | --timing           print timing information\n"
> -                      "    -v                      short version\n"
> -                      "    -V                      long version\n"
> -                      "         --version[=TYPE]   version, TYPE is short or long (default short)\n"
> -                      "  commands (non interactive mode):\n\n"), progname,
> -            progname);
> +    GString *str = g_string_new("Commands (non interactive mode):\n\n");
>  
>      for (grp = cmdGroups; grp->name; grp++) {
> -        fprintf(stdout, _(" %s (help keyword '%s')\n"),
> -                grp->name, grp->keyword);
> +        g_string_append_printf(str,
> +                               _("  %s (help keyword '%s')\n"),
> +                               grp->name, grp->keyword);
>          for (cmd = grp->commands; cmd->name; cmd++) {
>              if (cmd->flags & VSH_CMD_FLAG_ALIAS)
>                  continue;
> -            fprintf(stdout,
> -                    "    %-30s %s\n", cmd->name,
> -                    _(vshCmddefGetInfo(cmd, "help")));
> +            g_string_append_printf(str,
> +                                   "    %-30s %s\n",
> +                                   cmd->name,
> +                                   _(vshCmddefGetInfo(cmd, "help")));
>          }
> -        fprintf(stdout, "\n");
> +        g_string_append_printf(str, "\n");
>      }
>  
> -    fprintf(stdout, "%s",
> -            _("\n  (specify help <group> for details about the commands in the group)\n"));
> -    fprintf(stdout, "%s",
> -            _("\n  (specify help <command> for details about the command)\n\n"));
> -    return;
> +    g_string_append_printf(str,
> +                           _("Specify help <group> for details about the commands in the group)\n"));
> +    g_string_append_printf(str,
> +                           _("Specify help <command> for details about the command)\n"));
> +
> +    return g_string_free(str, FALSE);
>  }
>  
>  /*
> @@ -647,6 +629,22 @@ virshAllowedEscapeChar(char c)
>          ('@' <= c && c <= '_');
>  }
>  
> +static gboolean
> +virshVersion(const gchar *option_name G_GNUC_UNUSED,
> +             const gchar *value,
> +             gpointer data,
> +             GError **error G_GNUC_UNUSED)
> +{
> +    vshControl *ctl = data;
> +
> +    if (value == NULL || STRNEQ(value, "long"))
> +        puts(VERSION);
> +    else
> +        virshShowVersion(ctl);
> +
> +    exit(EXIT_SUCCESS);
> +}
> +
>  /*
>   * argv[]:  virsh [options] [command]
>   *
> @@ -654,152 +652,121 @@ virshAllowedEscapeChar(char c)
>  static bool
>  virshParseArgv(vshControl *ctl, int argc, char **argv)
>  {
> -    int arg, len, debug, keepalive;
> -    size_t i;
> -    int longindex = -1;
> +    int debug = 0;
> +    bool version = false;
> +    size_t len;
>      virshControlPtr priv = ctl->privData;
> -    struct option opt[] = {
> -        {"connect", required_argument, NULL, 'c'},
> -        {"debug", required_argument, NULL, 'd'},
> -        {"escape", required_argument, NULL, 'e'},
> -        {"help", no_argument, NULL, 'h'},
> -        {"keepalive-interval", required_argument, NULL, 'k'},
> -        {"keepalive-count", required_argument, NULL, 'K'},
> -        {"log", required_argument, NULL, 'l'},
> -        {"quiet", no_argument, NULL, 'q'},
> -        {"readonly", no_argument, NULL, 'r'},
> -        {"timing", no_argument, NULL, 't'},
> -        {"version", optional_argument, NULL, 'v'},
> -        {NULL, 0, NULL, 0}
> +    char *logfile = NULL;
> +    int keepalive_interval = INT_MAX;
> +    int keepalive_count = INT_MAX;
> +    GOptionEntry opt[] = {
> +        { "connect", 'c', 0,
> +          G_OPTION_ARG_STRING, &ctl->connname,
> +          _("hypervisor connection URI"), "URI" },
> +        { "debug", 'd', 0,
> +          G_OPTION_ARG_INT, &debug,
> +          _("debug level [0-4]\n"), "LEVEL" },
> +        { "escape", 'e', 0,
> +          G_OPTION_ARG_STRING, &priv->escapeChar,
> +          _("set escape sequence for console"), "ESCAPE" },
> +        { "keepalive-interval", 'k', 0,
> +          G_OPTION_ARG_INT, &keepalive_interval,
> +          _("keepalive interval in seconds, 0 for disable"), "SECS" },
> +        { "keepalive-count", 'K', 0,
> +          G_OPTION_ARG_INT, &keepalive_count,
> +          _("number of possible missed keepalive messages"), "NUM" },
> +        { "log", 'l', 0,
> +          G_OPTION_ARG_STRING, &logfile,
> +          _("output logging to file"), "FILENAME" },
> +        { "quiet", 'q', 0,
> +          G_OPTION_ARG_NONE, &ctl->quiet,
> +          _("quite mode"), NULL },
> +        { "readonly", 'r', 0,
> +          G_OPTION_ARG_NONE, &priv->readonly,
> +          _("connect readonly"), NULL },
> +        { "timing", 't', 0,
> +          G_OPTION_ARG_NONE, &ctl->timing,
> +          _("print timing information"), NULL },
> +        { "version", 'v', G_OPTION_FLAG_OPTIONAL_ARG,
> +          G_OPTION_ARG_CALLBACK, virshVersion,
> +          _("print short version"), "[short]" },
> +        { "version", 'V', 0,
> +          G_OPTION_ARG_NONE, &version,
> +          _("print long version"), "long" },

We should be able to have both -v and -V call virshVersion if the
functions will look like this:

static gboolean
virshVersion(const gchar *option_name,
             const gchar *value,
             gpointer data,
             GError **error G_GNUC_UNUSED)
{
    vshControl *ctl = data;

    if (STREQ(option_name, "-V") || STREQ_NULLABLE(value, "long"))
        virshShowVersion(ctl);
    else
        puts(VERSION);

    exit(EXIT_SUCCESS);
}

That way we will have only a single place where the version printing
code is.

Otherwise looks good to me.

Pavel
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 09/11] virsh: convert command line parsing to use GOptionContext
Posted by Daniel P. Berrangé 6 years, 4 months ago
On Tue, Oct 01, 2019 at 11:37:17AM +0200, Pavel Hrdina wrote:
> On Fri, Sep 27, 2019 at 06:17:31PM +0100, Daniel P. Berrangé wrote:
> > The GOptionContext API has the benefit over getopt_long that it will
> > automatically handle --help output formatting.
> > 
> > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> > ---
> >  tools/virsh.c | 303 ++++++++++++++++++++++----------------------------
> >  1 file changed, 135 insertions(+), 168 deletions(-)
> > 
> > diff --git a/tools/virsh.c b/tools/virsh.c
> > index ec20f35a77..6c469ff576 100644
> > --- a/tools/virsh.c
> > +++ b/tools/virsh.c
> > @@ -23,7 +23,6 @@
> >  
> >  #include <stdarg.h>
> >  #include <unistd.h>
> > -#include <getopt.h>
> >  #include <sys/time.h>
> >  #include <fcntl.h>
> >  #include <time.h>
> > @@ -445,53 +444,36 @@ virshDeinit(vshControl *ctl)
> >  }

> > +        { "version", 'v', G_OPTION_FLAG_OPTIONAL_ARG,
> > +          G_OPTION_ARG_CALLBACK, virshVersion,
> > +          _("print short version"), "[short]" },
> > +        { "version", 'V', 0,
> > +          G_OPTION_ARG_NONE, &version,
> > +          _("print long version"), "long" },
> 
> We should be able to have both -v and -V call virshVersion if the
> functions will look like this:
> 
> static gboolean
> virshVersion(const gchar *option_name,
>              const gchar *value,
>              gpointer data,
>              GError **error G_GNUC_UNUSED)
> {
>     vshControl *ctl = data;
> 
>     if (STREQ(option_name, "-V") || STREQ_NULLABLE(value, "long"))
>         virshShowVersion(ctl);
>     else
>         puts(VERSION);
> 
>     exit(EXIT_SUCCESS);
> }
> 
> That way we will have only a single place where the version printing
> code is.

Hmm, so "option_name" in the callback is the option that the user
actually passed ? I was thinking it was the option name from the
static array - ie it would always be "version". If you're right
though, this is definitely my preference.


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list
Re: [libvirt] [PATCH 09/11] virsh: convert command line parsing to use GOptionContext
Posted by Pavel Hrdina 6 years, 4 months ago
On Tue, Oct 01, 2019 at 10:48:50AM +0100, Daniel P. Berrangé wrote:
> On Tue, Oct 01, 2019 at 11:37:17AM +0200, Pavel Hrdina wrote:
> > On Fri, Sep 27, 2019 at 06:17:31PM +0100, Daniel P. Berrangé wrote:
> > > The GOptionContext API has the benefit over getopt_long that it will
> > > automatically handle --help output formatting.
> > > 
> > > Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
> > > ---
> > >  tools/virsh.c | 303 ++++++++++++++++++++++----------------------------
> > >  1 file changed, 135 insertions(+), 168 deletions(-)
> > > 
> > > diff --git a/tools/virsh.c b/tools/virsh.c
> > > index ec20f35a77..6c469ff576 100644
> > > --- a/tools/virsh.c
> > > +++ b/tools/virsh.c
> > > @@ -23,7 +23,6 @@
> > >  
> > >  #include <stdarg.h>
> > >  #include <unistd.h>
> > > -#include <getopt.h>
> > >  #include <sys/time.h>
> > >  #include <fcntl.h>
> > >  #include <time.h>
> > > @@ -445,53 +444,36 @@ virshDeinit(vshControl *ctl)
> > >  }
> 
> > > +        { "version", 'v', G_OPTION_FLAG_OPTIONAL_ARG,
> > > +          G_OPTION_ARG_CALLBACK, virshVersion,
> > > +          _("print short version"), "[short]" },
> > > +        { "version", 'V', 0,
> > > +          G_OPTION_ARG_NONE, &version,
> > > +          _("print long version"), "long" },
> > 
> > We should be able to have both -v and -V call virshVersion if the
> > functions will look like this:
> > 
> > static gboolean
> > virshVersion(const gchar *option_name,
> >              const gchar *value,
> >              gpointer data,
> >              GError **error G_GNUC_UNUSED)
> > {
> >     vshControl *ctl = data;
> > 
> >     if (STREQ(option_name, "-V") || STREQ_NULLABLE(value, "long"))
> >         virshShowVersion(ctl);
> >     else
> >         puts(VERSION);
> > 
> >     exit(EXIT_SUCCESS);
> > }
> > 
> > That way we will have only a single place where the version printing
> > code is.
> 
> Hmm, so "option_name" in the callback is the option that the user
> actually passed ? I was thinking it was the option name from the
> static array - ie it would always be "version". If you're right
> though, this is definitely my preference.

It is the option actually used by the user, from the glib docs:

option_name     The name of the option being parsed. This will be either
                a single dash followed by a single letter (for a short
                name) or two dashes followed by a long option name.

Pavel
--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list