[PATCH 2/3] Convert to GOption for command line option parsing

Dan Nicholson dbn.lists at gmail.com
Thu Mar 22 10:36:51 PDT 2012


Use glib's GOption instead of popt for command line option
handling. The APIs and output are very similar. A couple minor
differences are:

* The callback for handling --define-variable is associated only with
  that option where popt was just leaving the argument and then it was
  handled in a generic callback.

* Remaining arguments after option parsing are in argc/argv while they
  are collected through poptGetArg with popt.

* GOption does not provide the short --usage summary.

This also works around bugs in the command line option handling with
the ancient internal popt.
---
 main.c |  216 ++++++++++++++++++++++++++++++----------------------------------
 1 files changed, 102 insertions(+), 114 deletions(-)

diff --git a/main.c b/main.c
index 95ce69d..8ee9c41 100644
--- a/main.c
+++ b/main.c
@@ -24,7 +24,6 @@
 #include "pkg.h"
 #include "parse.h"
 
-#include <popt.h>
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
@@ -95,49 +94,41 @@ verbose_error (const char *format, ...)
   g_free (str);
 }
 
-#define DEFINE_VARIABLE 1
-
-static void
-popt_callback (poptContext con,
-               enum poptCallbackReason reason,
-               const struct poptOption * opt,
-               const char * arg, void * data)
+static gboolean
+define_variable_cb (const char *opt, const char *arg, gpointer data,
+                    GError **error)
 {
-  debug_spew ("Option --%s seen\n", opt->longName);
+  char *varname;
+  char *varval;
+  char *tmp;
 
-  if (opt->val == DEFINE_VARIABLE)
-    {
-      char *varname;
-      char *varval;
-      char *tmp;
+  tmp = g_strdup (arg);
 
-      tmp = g_strdup (arg);
+  varname = tmp;
+  while (*varname && isspace ((guchar)*varname))
+    ++varname;
 
-      varname = tmp;
-      while (*varname && isspace ((guchar)*varname))
-        ++varname;
+  varval = varname;
+  while (*varval && *varval != '=' && *varval != ' ')
+    ++varval;
 
-      varval = varname;
-      while (*varval && *varval != '=' && *varval != ' ')
-        ++varval;
-
-      while (*varval && (*varval == '=' || *varval == ' '))
-        {
-          *varval = '\0';
-          ++varval;
-        }
-
-      if (*varval == '\0')
-        {
-          fprintf (stderr, "--define-variable argument does not have a value for the variable\n");
+  while (*varval && (*varval == '=' || *varval == ' '))
+    {
+      *varval = '\0';
+      ++varval;
+    }
 
-          exit (1);
-        }
+  if (*varval == '\0')
+    {
+      fprintf (stderr, "--define-variable argument does not have a value "
+               "for the variable\n");
+      exit (1);
+    }
 
-      define_global_variable (varname, varval);
+  define_global_variable (varname, varval);
 
-      g_free (tmp);
-    }
+  g_free (tmp);
+  return TRUE;
 }
 
 static gboolean
@@ -205,81 +196,81 @@ main (int argc, char **argv)
   char *pcbuilddir;
   gboolean need_newline;
   FILE *log = NULL;
-  const char *pkgname;
-
-  poptContext opt_context;
-
-  struct poptOption options_table[] = {
-    { NULL, 0, POPT_ARG_CALLBACK, popt_callback, 0, NULL, NULL },
-    { "version", 0, POPT_ARG_NONE, &want_my_version, 0,
-      "output version of pkg-config" },
-    { "modversion", 0, POPT_ARG_NONE, &want_version, 0,
-      "output version for package" },
-    { "atleast-pkgconfig-version", 0, POPT_ARG_STRING, &required_pkgconfig_version, 0,
+  GError *error = NULL;
+  GOptionContext *opt_context;
+
+  GOptionEntry options_table[] = {
+    { "version", 0, 0, G_OPTION_ARG_NONE, &want_my_version,
+      "output version of pkg-config", NULL },
+    { "modversion", 0, 0, G_OPTION_ARG_NONE, &want_version,
+      "output version for package", NULL },
+    { "atleast-pkgconfig-version", 0, 0, G_OPTION_ARG_STRING,
+      &required_pkgconfig_version,
       "require given version of pkg-config", "VERSION" },
-    { "libs", 0, POPT_ARG_NONE, &want_libs, 0,
-      "output all linker flags" },
-    { "static", 0, POPT_ARG_NONE, &want_static_lib_list, 0,
-      "output linker flags for static linking" },
-    { "short-errors", 0, POPT_ARG_NONE, &want_short_errors, 0,
-      "print short errors" },
-    { "libs-only-l", 0, POPT_ARG_NONE, &want_l_libs, 0,
-      "output -l flags" },
-    { "libs-only-other", 0, POPT_ARG_NONE, &want_other_libs, 0,
-      "output other libs (e.g. -pthread)" },
-    { "libs-only-L", 0, POPT_ARG_NONE, &want_L_libs, 0,
-      "output -L flags" },
-    { "cflags", 0, POPT_ARG_NONE, &want_cflags, 0,
-      "output all pre-processor and compiler flags" },
-    { "cflags-only-I", 0, POPT_ARG_NONE, &want_I_cflags, 0,
-      "output -I flags" },
-    { "cflags-only-other", 0, POPT_ARG_NONE, &want_other_cflags, 0,
-      "output cflags not covered by the cflags-only-I option"},
-    { "variable", 0, POPT_ARG_STRING, &variable_name, 0,
+    { "libs", 0, 0, G_OPTION_ARG_NONE, &want_libs,
+      "output all linker flags", NULL },
+    { "static", 0, 0, G_OPTION_ARG_NONE, &want_static_lib_list,
+      "output linker flags for static linking", NULL },
+    { "short-errors", 0, 0, G_OPTION_ARG_NONE, &want_short_errors,
+      "print short errors", NULL },
+    { "libs-only-l", 0, 0, G_OPTION_ARG_NONE, &want_l_libs,
+      "output -l flags", NULL },
+    { "libs-only-other", 0, 0, G_OPTION_ARG_NONE, &want_other_libs,
+      "output other libs (e.g. -pthread)", NULL },
+    { "libs-only-L", 0, 0, G_OPTION_ARG_NONE, &want_L_libs,
+      "output -L flags", NULL },
+    { "cflags", 0, 0, G_OPTION_ARG_NONE, &want_cflags,
+      "output all pre-processor and compiler flags", NULL },
+    { "cflags-only-I", 0, 0, G_OPTION_ARG_NONE, &want_I_cflags,
+      "output -I flags", NULL },
+    { "cflags-only-other", 0, 0, G_OPTION_ARG_NONE, &want_other_cflags,
+      "output cflags not covered by the cflags-only-I option", NULL },
+    { "variable", 0, 0, G_OPTION_ARG_STRING, &variable_name,
       "get the value of variable named NAME", "NAME" },
-    { "define-variable", 0, POPT_ARG_STRING, NULL, DEFINE_VARIABLE,
+    { "define-variable", 0, 0, G_OPTION_ARG_CALLBACK, &define_variable_cb,
       "set variable NAME to VALUE", "NAME=VALUE" },
-    { "exists", 0, POPT_ARG_NONE, &want_exists, 0,
-      "return 0 if the module(s) exist" },
-    { "print-variables", 0, POPT_ARG_NONE, &want_variable_list, 0,
-      "output list of variables defined by the module" },
-    { "uninstalled", 0, POPT_ARG_NONE, &want_uninstalled, 0,
-      "return 0 if the uninstalled version of one or more module(s) or their dependencies will be used" },
-    { "atleast-version", 0, POPT_ARG_STRING, &required_atleast_version, 0,
+    { "exists", 0, 0, G_OPTION_ARG_NONE, &want_exists,
+      "return 0 if the module(s) exist", NULL },
+    { "print-variables", 0, 0, G_OPTION_ARG_NONE, &want_variable_list,
+      "output list of variables defined by the module", NULL },
+    { "uninstalled", 0, 0, G_OPTION_ARG_NONE, &want_uninstalled,
+      "return 0 if the uninstalled version of one or more module(s) "
+      "or their dependencies will be used", NULL },
+    { "atleast-version", 0, 0, G_OPTION_ARG_STRING, &required_atleast_version,
       "return 0 if the module is at least version VERSION", "VERSION" },
-    { "exact-version", 0, POPT_ARG_STRING, &required_exact_version, 0,
+    { "exact-version", 0, 0, G_OPTION_ARG_STRING, &required_exact_version,
       "return 0 if the module is at exactly version VERSION", "VERSION" },
-    { "max-version", 0, POPT_ARG_STRING, &required_max_version, 0,
+    { "max-version", 0, 0, G_OPTION_ARG_STRING, &required_max_version,
       "return 0 if the module is at no newer than version VERSION", "VERSION" },
-    { "list-all", 0, POPT_ARG_NONE, &want_list, 0,
-      "list all known packages" },
-    { "debug", 0, POPT_ARG_NONE, &want_debug_spew, 0,
-      "show verbose debug information" },
-    { "print-errors", 0, POPT_ARG_NONE, &want_verbose_errors, 0,
+    { "list-all", 0, 0, G_OPTION_ARG_NONE, &want_list,
+      "list all known packages", NULL },
+    { "debug", 0, 0, G_OPTION_ARG_NONE, &want_debug_spew,
+      "show verbose debug information", NULL },
+    { "print-errors", 0, 0, G_OPTION_ARG_NONE, &want_verbose_errors,
       "show verbose information about missing or conflicting packages,"
-      "default if --cflags or --libs given on the command line" },
-    { "silence-errors", 0, POPT_ARG_NONE, &want_silence_errors, 0,
+      "default if --cflags or --libs given on the command line", NULL },
+    { "silence-errors", 0, 0, G_OPTION_ARG_NONE, &want_silence_errors,
       "be silent about errors (default unless --cflags or --libs"
-      "given on the command line)" },
-    { "errors-to-stdout", 0, POPT_ARG_NONE, &want_stdout_errors, 0,
-      "print errors from --print-errors to stdout not stderr" },
-    { "print-provides", 0, POPT_ARG_NONE, &want_provides, 0,
-      "print which packages the package provides" },
-    { "print-requires", 0, POPT_ARG_NONE, &want_requires, 0,
-      "print which packages the package requires" },
-    { "print-requires-private", 0, POPT_ARG_NONE, &want_requires_private, 0,
-      "print which packages the package requires for static linking" },
+      "given on the command line)", NULL },
+    { "errors-to-stdout", 0, 0, G_OPTION_ARG_NONE, &want_stdout_errors,
+      "print errors from --print-errors to stdout not stderr", NULL },
+    { "print-provides", 0, 0, G_OPTION_ARG_NONE, &want_provides,
+      "print which packages the package provides", NULL },
+    { "print-requires", 0, 0, G_OPTION_ARG_NONE, &want_requires,
+      "print which packages the package requires", NULL },
+    { "print-requires-private", 0, 0, G_OPTION_ARG_NONE, &want_requires_private,
+      "print which packages the package requires for static linking", NULL },
 #ifdef G_OS_WIN32
-    { "dont-define-prefix", 0, POPT_ARG_NONE, &dont_define_prefix, 0,
+    { "dont-define-prefix", 0, 0, G_OPTION_ARG_NONE, &dont_define_prefix,
       "don't try to override the value of prefix for each .pc file found with "
-      "a guesstimated value based on the location of the .pc file" },
-    { "prefix-variable", 0, POPT_ARG_STRING, &prefix_variable, 0,
-      "set the name of the variable that pkg-config automatically sets", "PREFIX" },
-    { "msvc-syntax", 0, POPT_ARG_NONE, &msvc_syntax, 0,
-      "output -l and -L flags for the Microsoft compiler (cl)" },
+      "a guesstimated value based on the location of the .pc file", NULL },
+    { "prefix-variable", 0, 0, G_OPTION_ARG_STRING, &prefix_variable,
+      "set the name of the variable that pkg-config automatically sets",
+      "PREFIX" },
+    { "msvc-syntax", 0, 0, G_OPTION_ARG_NONE, &msvc_syntax,
+      "output -l and -L flags for the Microsoft compiler (cl)", NULL },
 #endif
-    POPT_AUTOHELP
-    { NULL, 0, 0, NULL, 0 }
+    { NULL, 0, 0, 0, NULL, NULL, NULL }
   };
 
   /* This is here so that we get debug spew from the start,
@@ -334,15 +325,12 @@ main (int argc, char **argv)
       disable_uninstalled = TRUE;
     }
 
-  opt_context = poptGetContext (NULL, argc, argv,
-                                options_table, 0);
-
-  result = poptGetNextOpt (opt_context);
-  if (result != -1)
+  /* Parse options */
+  opt_context = g_option_context_new (NULL);
+  g_option_context_add_main_entries (opt_context, options_table, NULL);
+  if (!g_option_context_parse(opt_context, &argc, &argv, &error))
     {
-      fprintf(stderr, "%s: %s\n",
-	      poptBadOption(opt_context, POPT_BADOPTION_NOALIAS),
-	      poptStrerror(result));
+      fprintf (stderr, "%s\n", error->message);
       return 1;
     }
 
@@ -428,18 +416,18 @@ main (int argc, char **argv)
       return 0;
     }
 
+  /* Collect packages from remaining args */
   str = g_string_new ("");
-  while (1)
+  while (argc > 1)
     {
-      pkgname = poptGetArg (opt_context);
-      if (pkgname == NULL)
-	break;
+      argc--;
+      argv++;
 
-      g_string_append (str, pkgname);
+      g_string_append (str, *argv);
       g_string_append (str, " ");
     }
 
-  poptFreeContext (opt_context);
+  g_option_context_free (opt_context);
 
   g_strstrip (str->str);
 
-- 
1.7.7.6



More information about the pkg-config mailing list