fix test case, implement base32 argument parser logic
authorChristian Grothoff <christian@grothoff.org>
Wed, 15 Mar 2017 09:16:42 +0000 (10:16 +0100)
committerChristian Grothoff <christian@grothoff.org>
Wed, 15 Mar 2017 09:16:42 +0000 (10:16 +0100)
src/include/gnunet_getopt_lib.h
src/util/getopt.c
src/util/getopt_helpers.c
src/util/test_getopt.c

index cd546905efa62fc51830f164c6f0d7856c6b6761..0acf156797a91545f74043ee58b6318f08b103bb 100644 (file)
@@ -135,6 +135,12 @@ struct GNUNET_GETOPT_CommandLineOption
    */
   GNUNET_GETOPT_CommandLineOptionProcessor processor;
 
+  /**
+   * Function to call on @e scls to clean up after processing all
+   * the arguments. Can be NULL.
+   */
+  void (*cleaner)(void *cls);
+
   /**
    * Specific closure to pass to the processor.
    */
@@ -206,6 +212,42 @@ GNUNET_GETOPT_OPTION_FILENAME (char shortName,
                                char **str);
 
 
+/**
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument
+ * @param val_size size of @a val in bytes
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
+                                            const char *name,
+                                            const char *argumentHelp,
+                                            const char *description,
+                                            void *val,
+                                            size_t val_size);
+
+
+/**
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding where the size of the binary value is
+ * automatically determined from its type.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument;
+ *             size is determined by type (sizeof (*val)).
+ */
+#define GNUNET_GETOPT_OPTION_SET_BASE32_AUTO(shortName,name,argumentHelp,description,val) \
+  GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE(shortName,name,argumentHelp,description,val,sizeof(*val))
+
+
 /**
  * Allow user to specify a flag (which internally means setting
  * an integer to 1/#GNUNET_YES/#GNUNET_OK.
@@ -307,7 +349,7 @@ GNUNET_GETOPT_OPTION_LOGLEVEL (char **level);
  * @param[out] level set to the verbosity level
  */
 struct GNUNET_GETOPT_CommandLineOption
-GNUNET_GETOPT_OPTION_VERBOSE (int *level);
+GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level);
 
 
 /**
@@ -332,7 +374,7 @@ GNUNET_GETOPT_OPTION_CFG_FILE (char **fn);
  * Marker for the end of the list of options.
  */
 #define GNUNET_GETOPT_OPTION_END \
-  { '\0', NULL, NULL, NULL, 0, NULL, NULL }
+  { '\0', NULL, NULL, NULL, 0, NULL, NULL, NULL }
 
 
 /**
index ff62dba9be0fae2d9fee7fb95917253da5f8264e..85f67500c85bd0317778287f3ea33934cd873edc 100644 (file)
@@ -26,7 +26,7 @@ USA.
 
 
 This code was heavily modified for GNUnet.
-Copyright Copyright (C) 2006 Christian Grothoff
+Copyright Copyright (C) 2006, 2017 Christian Grothoff
 */
 
 /**
@@ -845,9 +845,13 @@ GN_getopt_internal (int argc, char *const *argv, const char *optstring,
   }
 }
 
+
 static int
-GNgetopt_long (int argc, char *const *argv, const char *options,
-               const struct GNoption *long_options, int *opt_index)
+GNgetopt_long (int argc,
+               char *const *argv,
+               const char *options,
+               const struct GNoption *long_options,
+               int *opt_index)
 {
   return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
 }
@@ -867,12 +871,12 @@ GNgetopt_long (int argc, char *const *argv, const char *options,
 int
 GNUNET_GETOPT_run (const char *binaryOptions,
                    const struct GNUNET_GETOPT_CommandLineOption *allOptions,
-                   unsigned int argc, char *const *argv)
+                   unsigned int argc,
+                   char *const *argv)
 {
   struct GNoption *long_options;
   struct GNUNET_GETOPT_CommandLineProcessorContext clpc;
   int count;
-  int i;
   char *shorts;
   int spos;
   int cont;
@@ -885,13 +889,13 @@ GNUNET_GETOPT_run (const char *binaryOptions,
   clpc.allOptions = allOptions;
   clpc.argv = argv;
   clpc.argc = argc;
-  count = 0;
-  while (allOptions[count].name != NULL)
-    count++;
-  long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1));
+  for (count = 0; NULL != allOptions[count].name; count++) ;
+
+  long_options = GNUNET_new_array (count + 1,
+                                   struct GNoption);
   shorts = GNUNET_malloc (count * 2 + 1);
   spos = 0;
-  for (i = 0; i < count; i++)
+  for (unsigned i = 0; i < count; i++)
   {
     long_options[i].name = allOptions[i].name;
     long_options[i].has_arg = allOptions[i].require_argument;
@@ -907,13 +911,17 @@ GNUNET_GETOPT_run (const char *binaryOptions,
   long_options[count].val = '\0';
   shorts[spos] = '\0';
   cont = GNUNET_OK;
+
   /* main getopt loop */
-  while (cont == GNUNET_OK)
+  while (GNUNET_OK == cont)
   {
     int option_index = 0;
+    unsigned int i;
 
-    c = GNgetopt_long (argc, argv, shorts, long_options, &option_index);
-
+    c = GNgetopt_long (argc, argv,
+                       shorts,
+                       long_options,
+                       &option_index);
     if (c == GNUNET_SYSERR)
       break;                    /* No more flags to process */
 
@@ -922,25 +930,31 @@ GNUNET_GETOPT_run (const char *binaryOptions,
       clpc.currentArgument = GNoptind - 1;
       if ((char) c == allOptions[i].shortName)
       {
-        cont =
-            allOptions[i].processor (&clpc, allOptions[i].scls,
-                                     allOptions[i].name, GNoptarg);
+        cont = allOptions[i].processor (&clpc,
+                                        allOptions[i].scls,
+                                        allOptions[i].name,
+                                        GNoptarg);
         break;
       }
     }
     if (i == count)
     {
-      FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help");
+      FPRINTF (stderr,
+               _("Use %s to get a list of options.\n"),
+               "--help");
       cont = GNUNET_SYSERR;
     }
   }
-
   GNUNET_free (shorts);
   GNUNET_free (long_options);
-  if (cont != GNUNET_OK)
-  {
+
+  /* call cleaners, if available */
+  for (count = 0; NULL != allOptions[count].name; count++)
+    if (NULL != allOptions[count].cleaner)
+      allOptions[count].cleaner (allOptions[count].scls);
+
+  if (GNUNET_OK != cont)
     return cont;
-  }
   return GNoptind;
 }
 
index 234f5371f38b29000aa09b56b3a83943c20977dd..9f6f4c764e9b6c9b25784a7c7522e4a41f74f3f0 100644 (file)
@@ -266,7 +266,7 @@ GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName,
  * @param[out] level set to the verbosity level
  */
 struct GNUNET_GETOPT_CommandLineOption
-GNUNET_GETOPT_OPTION_VERBOSE (int *level)
+GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level)
 {
   struct GNUNET_GETOPT_CommandLineOption clo = {
     .shortName = 'V',
@@ -710,4 +710,107 @@ GNUNET_GETOPT_OPTION_SET_UINT (char shortName,
 }
 
 
+/**
+ * Closure for #set_base32().
+ */
+struct Base32Context
+{
+  /**
+   * Value to initialize (already allocated)
+   */
+  void *val;
+
+  /**
+   * Number of bytes expected for @e val.
+   */
+  size_t val_size;
+};
+
+
+/**
+ * Set an option of type 'unsigned int' from the command line.
+ * A pointer to this function should be passed as part of the
+ * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options
+ * of this type.  It should be followed by a pointer to a value of
+ * type 'unsigned int'.
+ *
+ * @param ctx command line processing context
+ * @param scls additional closure (will point to the 'unsigned int')
+ * @param option name of the option
+ * @param value actual value of the option as a string.
+ * @return #GNUNET_OK if parsing the value worked
+ */
+static int
+set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
+            void *scls,
+            const char *option,
+            const char *value)
+{
+  struct Base32Context *bc = scls;
+
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_string_to_data (value,
+                                     strlen (value),
+                                     bc->val,
+                                     bc->val_size))
+  {
+    fprintf (stderr,
+             _("Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"),
+             option);
+    return GNUNET_SYSERR;
+  }
+  return GNUNET_OK;
+}
+
+
+/**
+ * Helper function to clean up after
+ * #GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE.
+ *
+ * @param cls value to GNUNET_free()
+ */
+static void
+free_bc (void *cls)
+{
+  GNUNET_free (cls);
+}
+
+
+/**
+ * Allow user to specify a binary value using Crockford
+ * Base32 encoding.
+ *
+ * @param shortName short name of the option
+ * @param name long name of the option
+ * @param argumentHelp help text for the option argument
+ * @param description long help text for the option
+ * @param[out] val binary value decoded from Crockford Base32-encoded argument
+ * @param val_size size of @a val in bytes
+ */
+struct GNUNET_GETOPT_CommandLineOption
+GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName,
+                                            const char *name,
+                                            const char *argumentHelp,
+                                            const char *description,
+                                            void *val,
+                                            size_t val_size)
+{
+  struct Base32Context *bc = GNUNET_new (struct Base32Context);
+  struct GNUNET_GETOPT_CommandLineOption clo = {
+    .shortName =  shortName,
+    .name = name,
+    .argumentHelp = argumentHelp,
+    .description = description,
+    .require_argument = 1,
+    .processor = &set_base32,
+    .cleaner = &free_bc,
+    .scls = (void *) bc
+  };
+
+  bc->val = val;
+  bc->val_size = val_size;
+  return clo;
+}
+
+
 /* end of getopt_helpers.c */
index 8e578640dd9b3b226b917f266a0e82ba17416999..faa6a07a19c75abbc7146ce2fd402314baa068ae 100644 (file)
@@ -170,21 +170,35 @@ testFlagNum ()
   unsigned long long lnum = 0;
 
   const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = {
-    {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one,
-     (void *) &flag},
-    {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint,
-     (void *) &num},
-    {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong,
-     (void *) &lnum},
+    GNUNET_GETOPT_OPTION_SET_ONE ('f',
+                                  "--flag",
+                                  "helptext",
+                                  &flag),
+    GNUNET_GETOPT_OPTION_SET_UINT ('n',
+                                   "--num",
+                                   "ARG",
+                                   "helptext",
+                                   &num),
+    GNUNET_GETOPT_OPTION_SET_ULONG ('N',
+                                    "--lnum",
+                                    "ARG",
+                                    "helptext",
+                                    &lnum),
     GNUNET_GETOPT_OPTION_END
   };
 
-  if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv))
+  if (6 !=
+      GNUNET_GETOPT_run ("test_getopt",
+                         logoptionlist,
+                         6,
+                         myargv))
   {
     GNUNET_break (0);
     return 1;
   }
-  if ((1 != flag) || (42 != num) || (42 != lnum))
+  if ( (1 != flag) ||
+       (42 != num) ||
+       (42 != lnum))
   {
     GNUNET_break (0);
     return 1;