changeset 1742:ddec147d1f90

Bring in changes from the th-libs version of commandline argument handling.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 09 Jun 2018 17:56:07 +0300
parents 6f1313c761aa
children bcdea45a14cb
files Makefile.gen src/dmargs.c src/dmargs.h src/dmargs_int.c tools/packed.c
diffstat 5 files changed, 303 insertions(+), 295 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.gen	Sat Jun 09 17:04:33 2018 +0300
+++ b/Makefile.gen	Sat Jun 09 17:56:07 2018 +0300
@@ -395,10 +395,6 @@
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
 
-$(OBJPATH)dmargs.o: $(DMLIBSRC)dmargs.c $(DMLIBSRC)dmargs.h $(DMLIBSRC)dmargs_int.c $(DMLIBSRC)dmlib.h
-	@echo " CC $+"
-	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS)
-
 $(OBJPATH)libgfx.o: $(DMLIB)tools/libgfx.c $(DMLIB)tools/libgfx.h
 	@echo " CC $+"
 	@$(CC) $(CFLAGS) -c -o $@ $< $(DM_CFLAGS) $(LIBPNG_CFLAGS)
--- a/src/dmargs.c	Sat Jun 09 17:04:33 2018 +0300
+++ b/src/dmargs.c	Sat Jun 09 17:56:07 2018 +0300
@@ -1,12 +1,279 @@
+/*
+ * Simple commandline argument processing
+ * Programmed and designed by Matti 'ccr' Hamalainen
+ * (C) Copyright 2002-2018 Tecnic Software productions (TNSP)
+ *
+ * Please read file 'COPYING' for information on license and distribution.
+ */
+/// @file
+/// @brief Simple commandline argument processing functions
 #include "dmargs.h"
-#define TH_EXTERNAL 1
-#define th_optarg_t DMOptArg
-#define th_args_process dmArgsProcess
-#define th_args_help dmArgsPrintHelp
+
+
+/**
+ * Parse and optionally handle the given long or short option argument.
+ * @param currArg current argument string
+ * @param argIndex pointer to index of current argument in argv[]
+ * @param argc number of arguments
+ * @param argv argument string array
+ * @param opts options list array
+ * @param nopts number of elements in options list array
+ * @param handle_option function pointer to callback that handles option arguments
+ * @param doProcess if TRUE, actually handle the argument, aka call the handle_option() function. if FALSE, only validity of options are checked.
+ * @param isLong TRUE if the option is a --long-format one
+ */
+static BOOL dmArgsProcessOpt(
+    char *currArg, int *argIndex,
+    int argc, char *argv[],
+    const DMOptArg opts[], int nopts,
+    BOOL (*handle_option)(int id, char *, char *),
+    BOOL doProcess, BOOL isLong)
+{
+    const DMOptArg *opt = NULL;
+    char *optArg = NULL;
+    int optIndex;
+
+    for (optIndex = 0; optIndex < nopts; optIndex++)
+    {
+        const DMOptArg *node = &opts[optIndex];
+        if (isLong && node->o_long != NULL)
+        {
+            if (strcmp(currArg, node->o_long) == 0)
+            {
+                opt = node;
+                optArg = NULL;
+                break;
+            }
+
+            size_t len = strlen(node->o_long);
+            if (strncmp(currArg, node->o_long, len) == 0 &&
+                currArg[len] == '=')
+            {
+                opt = node;
+                optArg = (&currArg[len+1] != 0) ? &currArg[len+1] : NULL;
+                break;
+            }
+        }
+        else
+        if (!isLong && node->o_short != 0)
+        {
+            if (*currArg == node->o_short)
+            {
+                opt = node;
+                optArg = (currArg[1] != 0) ? &currArg[1] : NULL;
+            }
+        }
+    }
+
+    if (opt != NULL)
+    {
+        // Check for the possible option argument
+        if ((opt->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL)
+        {
+            if (*argIndex < argc)
+            {
+                (*argIndex)++;
+                optArg = argv[*argIndex];
+            }
+
+            if (optArg == NULL)
+            {
+                dmErrorMsg("Option '%s%s' requires an argument.\n",
+                    isLong ? "--" : "-",
+                    currArg);
+                return FALSE;
+            }
+        }
+
+        // Option was given succesfully, try to process it
+        if (doProcess && !handle_option(opt->id, optArg, currArg))
+            return FALSE;
+    }
+    else
+    {
+        dmErrorMsg("Unknown %s option '%s%s'\n",
+            isLong ? "long" : "short",
+            isLong ? "--" : "-",
+            currArg);
+
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+/**
+ * Process given array of commandline arguments, handling short
+ * and long options by calling the respective callback functions.
+ *
+ * @param argc number of arguments
+ * @param argv argument list
+ * @param opts supported option list array
+ * @param nopts number of elements in the option list array
+ * @param handle_option callback function
+ * @param handle_other callback function
+ * @param flags processing flags
+ * @return return TRUE if all is well
+ */
+BOOL dmArgsProcess(int argc, char *argv[],
+     const DMOptArg *opts, const int nopts,
+     BOOL(*handle_option)(int id, char *, char *),
+     BOOL(*handle_other)(char *), const int flags)
+{
+    int argIndex, handleFlags = flags & OPTH_ONLY_MASK;
+    BOOL optionsOK = TRUE, endOfOptions = FALSE;
+
+    for (argIndex = 1; argIndex < argc; argIndex++)
+    {
+        char *str = argv[argIndex];
+        if (*str == '-' && !endOfOptions)
+        {
+            // Should we process options?
+            BOOL doProcess = (handleFlags & OPTH_ONLY_OPTS) || handleFlags == 0;
+            BOOL isLong;
 
-#define THERR dmErrorMsg
-#define th_calloc dmCalloc
-#define th_malloc dmMalloc
-#define th_free dmFree
+            str++;
+            if (*str == '-')
+            {
+                // Check for "--", which ends the options-list
+                str++;
+                if (*str == 0)
+                {
+                    endOfOptions = TRUE;
+                    continue;
+                }
+
+                // We have a long option
+                isLong = TRUE;
+            }
+            else
+                isLong = FALSE;
+
+            if (!dmArgsProcessOpt(str, &argIndex, argc, argv,
+                opts, nopts, handle_option, doProcess, isLong))
+                optionsOK = FALSE;
+        }
+        else
+        if (handleFlags == OPTH_ONLY_OTHER || handleFlags == 0)
+        {
+            // Was not option argument
+            if (handle_other == NULL ||
+                (handle_other != NULL && !handle_other(str)))
+            {
+                dmErrorMsg("Invalid argument '%s'\n", str);
+                optionsOK = FALSE;
+            }
+        }
+
+        // Check if we bail out on invalid argument
+        if (!optionsOK && (flags & OPTH_BAILOUT))
+            return FALSE;
+    }
+
+    return optionsOK;
+}
+
+
+static void dmPad(FILE *outFile, int count)
+{
+    while (count--)
+        fputc(' ', outFile);
+}
+
+
+static void dmPrintWrap(FILE *fh, const char *str, int spad, int rpad, int width)
+{
+    size_t pos = 0;
+    BOOL first = TRUE;
+
+    while (str[pos])
+    {
+        // Pre-pad line
+        int linelen = first ? spad : rpad;
+        dmPad(fh, first ? 0 : rpad);
+        first = FALSE;
+
+        // Skip whitespace at line start
+        while (isspace(str[pos]) || str[pos] == '\n') pos++;
 
-#include "dmargs_int.c"
+        // Handle each word
+        while (str[pos] && str[pos] != '\n')
+        {
+            size_t next;
+            int wlen;
+            for (wlen = 0, next = pos; str[next] && !isspace(str[next]) && str[next] != '\n'; next++, wlen++);
+//            fprintf(stdout, "X '%c', %d .. linelen=%d/%d, wlen=%d\n", str[pos], pos, linelen, width, wlen);
+            if (linelen + wlen < width)
+            {
+                for (;pos < next; pos++, linelen++)
+                    fputc(str[pos], fh);
+
+                if (str[next] == '\n' || str[next] == 0)
+                {
+                    fprintf(fh, "\n");
+                    break;
+                }
+                else
+                {
+                    fputc(str[pos], fh);
+                    pos++;
+                    linelen++;
+                }
+            }
+            else
+            {
+                fprintf(fh, "\n");
+                break;
+            }
+        }
+    }
+}
+
+
+/**
+ * Print help for commandline arguments/options
+ * @param fh stdio file handle to output to
+ * @param opts options list array
+ * @param nopts number of elements in options list array
+ * @param flags flags (currently unused)
+ */
+void dmArgsPrintHelp(FILE *fh,
+    const DMOptArg *opts, const int nopts,
+    const int flags)
+{
+    int index;
+    (void) flags;
+
+    // Print out option list
+    for (index = 0; index < nopts; index++)
+    {
+        const DMOptArg *opt = &opts[index];
+        char tmpStr[128];
+
+        // Print short option
+        if (opt->o_short != 0)
+        {
+            snprintf(tmpStr, sizeof(tmpStr),
+                "-%c,", opt->o_short);
+        }
+        else
+            tmpStr[0] = 0;
+
+        fprintf(fh, " %-5s", tmpStr);
+
+        // Print long option
+        if (opt->o_long != NULL)
+        {
+            snprintf(tmpStr, sizeof(tmpStr), "--%s%s",
+                opt->o_long,
+                (opt->flags & OPT_ARGREQ) ? "=ARG" : "");
+        }
+        else
+            tmpStr[0] = 0;
+
+        fprintf(fh, "%-20s", tmpStr);
+
+        dmPrintWrap(fh, opt->desc, 26, 26, 79);
+    }
+}
--- a/src/dmargs.h	Sat Jun 09 17:04:33 2018 +0300
+++ b/src/dmargs.h	Sat Jun 09 17:56:07 2018 +0300
@@ -1,10 +1,12 @@
 /*
  * Simple commandline argument processing functions
  * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2002-2015 Tecnic Software productions (TNSP)
+ * (C) Copyright 2002-2018 Tecnic Software productions (TNSP)
  *
  * Please read file 'COPYING' for information on license and distribution.
  */
+/// @file
+/// @brief Simple commandline argument processing functions
 #ifndef DMARGS_H
 #define DMARGS_H
 
@@ -14,40 +16,39 @@
 extern "C" {
 #endif
 
-/* Option flags
+/** @def Option argument flags
  */
-#define OPT_NONE             (0)    // Simple option with no arguments
-#define OPT_ARGREQ           (1)    // Option requires an argument
-#define OPT_ARGMASK          (1)    // Mask for option argument flags
+#define OPT_NONE             (0)    ///< Simple option with no arguments
+#define OPT_ARGREQ           (1)    ///< Option requires an argument
+#define OPT_ARGMASK          (1)    ///< Mask for option argument flags
 
-#define OPTH_BAILOUT         0x0001 // Bail out on errors
-#define OPTH_ONLY_OPTS       0x0010 // Handle only options
-#define OPTH_ONLY_OTHER      0x0020 // Handle only "non-options"
-#define OPTH_ONLY_MASK       0x00f0 // Mask
+/** @def Option processing flags
+ */
+#define OPTH_BAILOUT         0x0001 ///< Bail out on errors
+#define OPTH_ONLY_OPTS       0x0010 ///< Handle only options
+#define OPTH_ONLY_OTHER      0x0020 ///< Handle only "non-options"
+#define OPTH_ONLY_MASK       0x00f0 ///< Mask
 
 
-/* Option argument structure
+/** Option argument structure
  */
 typedef struct
 {
-    int id;
-    char optShort;
-    char *optLong;
-    char *desc;
-    int flags;
+    int id;           ///< Option ID (should be unique for each option)
+    char o_short;     ///< Short option name (one character)
+    char *o_long;     ///< Long option name
+    char *desc;       ///< Option description
+    int flags;        ///< Flags (see OPT_*)
 } DMOptArg;
 
 
 BOOL dmArgsProcess(int argc, char *argv[],
-     const DMOptArg optList[], int noptList,
-     BOOL (*handleOptionCB)(int, char *, char *),
-     BOOL (*handleFileCB)(char *), BOOL);
+     const DMOptArg *opts, const int nopts,
+     BOOL (*handle_option)(int id, char *, char *),
+     BOOL (*handle_other)(char *), const int flags);
 
-void dmArgsPrintHelp(FILE *,
-     const DMOptArg optList[],
-     const int noptList,
-     const int flags);
-
+void dmArgsPrintHelp(FILE *, const DMOptArg *opts,
+     const int nopts, const int flags);
 
 #ifdef __cplusplus
 }
--- a/src/dmargs_int.c	Sat Jun 09 17:04:33 2018 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,256 +0,0 @@
-/*
- * Simple commandline argument processing
- * Programmed and designed by Matti 'ccr' Hamalainen
- * (C) Copyright 2002-2015 Tecnic Software productions (TNSP)
- *
- * Please read file 'COPYING' for information on license and distribution.
- */
-#ifndef TH_EXTERNAL
-#include "th_util.h"
-#include "th_args.h"
-#include "th_string.h"
-#endif
-
-
-/* Parse long and short options
- */
-static BOOL th_args_process_opt(
-    char *currArg, int *argIndex,
-    int argc, char *argv[],
-    const th_optarg_t opts[], int numOpts,
-    BOOL (*handleOptionCB)(int, char *, char *),
-    BOOL doProcess, BOOL isLong)
-{
-    const th_optarg_t *opt = NULL;
-    char *optArg = NULL;
-    int optIndex;
-
-    for (optIndex = 0; optIndex < numOpts; optIndex++)
-    {
-        const th_optarg_t *node = &opts[optIndex];
-        if (isLong && node->optLong != NULL)
-        {
-            if (strcmp(currArg, node->optLong) == 0)
-            {
-                opt = node;
-                optArg = NULL;
-                break;
-            }
-
-            size_t len = strlen(node->optLong);
-            if (strncmp(currArg, node->optLong, len) == 0 &&
-                currArg[len] == '=')
-            {
-                opt = node;
-                optArg = (&currArg[len+1] != 0) ? &currArg[len+1] : NULL;
-                break;
-            }
-        }
-        else
-        if (!isLong && node->optShort != 0)
-        {
-            if (*currArg == node->optShort)
-            {
-                opt = node;
-                optArg = (currArg[1] != 0) ? &currArg[1] : NULL;
-            }
-        }
-    }
-
-    if (opt != NULL)
-    {
-        // Check for the possible option argument
-        if ((opt->flags & OPT_ARGMASK) == OPT_ARGREQ && optArg == NULL)
-        {
-            if (*argIndex < argc)
-            {
-                (*argIndex)++;
-                optArg = argv[*argIndex];
-            }
-
-            if (optArg == NULL)
-            {
-                THERR("Option '%s%s' requires an argument.\n",
-                    isLong ? "--" : "-",
-                    currArg);
-                return FALSE;
-            }
-        }
-
-        // Option was given succesfully, try to process it
-        if (doProcess && !handleOptionCB(opt->id, optArg, currArg))
-            return FALSE;
-    }
-    else
-    {
-        THERR("Unknown %s option '%s%s'\n",
-            isLong ? "long" : "short",
-            isLong ? "--" : "-",
-            currArg);
-
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-
-/* Process arguments, handling short and long options by
- * calling the given callback functions.
- */
-BOOL th_args_process(int argc, char *argv[],
-     const th_optarg_t *opts, const int numOpts,
-     BOOL(*handleOptionCB) (int, char *, char *),
-     BOOL(*handleOther) (char *), int flags)
-{
-    int argIndex, handleFlags = flags & OPTH_ONLY_MASK;
-    BOOL optionsOK = TRUE, endOfOptions = FALSE;
-
-    for (argIndex = 1; argIndex < argc; argIndex++)
-    {
-        char *str = argv[argIndex];
-        if (*str == '-' && !endOfOptions)
-        {
-            // Should we process options?
-            BOOL doProcess = (handleFlags & OPTH_ONLY_OPTS) || handleFlags == 0;
-            BOOL isLong;
-
-            str++;
-            if (*str == '-')
-            {
-                // Check for "--", which ends the options-list
-                str++;
-                if (*str == 0)
-                {
-                    endOfOptions = TRUE;
-                    continue;
-                }
-
-                // We have a long option
-                isLong = TRUE;
-            }
-            else
-                isLong = FALSE;
-
-            if (!th_args_process_opt(str, &argIndex, argc, argv,
-                opts, numOpts, handleOptionCB, doProcess, isLong))
-                optionsOK = FALSE;
-        }
-        else
-        if (handleFlags == OPTH_ONLY_OTHER || handleFlags == 0)
-        {
-            // Was not option argument
-            if (handleOther == NULL ||
-                (handleOther != NULL && !handleOther(str)))
-            {
-                THERR("Invalid argument '%s'\n", str);
-                optionsOK = FALSE;
-            }
-        }
-
-        // Check if we bail out on invalid argument
-        if (!optionsOK && (flags & OPTH_BAILOUT))
-            return FALSE;
-    }
-
-    return optionsOK;
-}
-
-
-/* Print help for commandline arguments/options
- */
-static void th_pad(FILE *outFile, int count)
-{
-    while (count--)
-        fputc(' ', outFile);
-}
-
-
-static void th_print_wrap(FILE *fh, const char *str, int spad, int rpad, int width)
-{
-    size_t pos = 0;
-    BOOL first = TRUE;
-
-    while (str[pos])
-    {
-        // Pre-pad line
-        int linelen = first ? spad : rpad;
-        th_pad(fh, first ? 0 : rpad);
-        first = FALSE;
-
-        // Skip whitespace at line start
-        while (isspace(str[pos]) || str[pos] == '\n') pos++;
-
-        // Handle each word
-        while (str[pos] && str[pos] != '\n')
-        {
-            size_t next;
-            int wlen;
-            for (wlen = 0, next = pos; str[next] && !isspace(str[next]) && str[next] != '\n'; next++, wlen++);
-//            fprintf(stdout, "X '%c', %d .. linelen=%d/%d, wlen=%d\n", str[pos], pos, linelen, width, wlen);
-            if (linelen + wlen < width)
-            {
-                for (;pos < next; pos++, linelen++)
-                    fputc(str[pos], fh);
-
-                if (str[next] == '\n' || str[next] == 0)
-                {
-                    fprintf(fh, "\n");
-                    break;
-                }
-                else
-                {
-                    fputc(str[pos], fh);
-                    pos++;
-                    linelen++;
-                }
-            }
-            else
-            {
-                fprintf(fh, "\n");
-                break;
-            }
-        }
-    }
-}
-
-
-void th_args_help(FILE *fh,
-    const th_optarg_t *opts, const int numOpts,
-    const int flags)
-{
-    int index;
-    (void) flags;
-
-    // Print out option list
-    for (index = 0; index < numOpts; index++)
-    {
-        const th_optarg_t *opt = &opts[index];
-        char tmpStr[128];
-
-        // Print short option
-        if (opt->optShort != 0)
-        {
-            snprintf(tmpStr, sizeof(tmpStr),
-                "-%c,", opt->optShort);
-        }
-        else
-            tmpStr[0] = 0;
-
-        fprintf(fh, " %-5s", tmpStr);
-
-        // Print long option
-        if (opt->optLong != NULL)
-        {
-            snprintf(tmpStr, sizeof(tmpStr), "--%s%s",
-                opt->optLong,
-                (opt->flags & OPT_ARGREQ) ? "=ARG" : "");
-        }
-        else
-            tmpStr[0] = 0;
-
-        fprintf(fh, "%-20s", tmpStr);
-
-        th_print_wrap(fh, opt->desc, 26, 26, 73);
-    }
-}
--- a/tools/packed.c	Sat Jun 09 17:04:33 2018 +0300
+++ b/tools/packed.c	Sat Jun 09 17:56:07 2018 +0300
@@ -73,7 +73,7 @@
         const DMOptArg *cmd = &cmdList[i];
         char tmpStr[128];
         snprintf(tmpStr, sizeof(tmpStr), "%c / %s",
-            cmd->optShort, cmd->optLong);
+            cmd->o_short, cmd->o_long);
 
         fprintf(stdout, "  %-15s   %s\n", tmpStr, cmd->desc);
     }
@@ -159,8 +159,8 @@
         for (int n = 0; n < cmdListN; n++)
         {
             const DMOptArg *cmd = &cmdList[n];
-            if ((currArg[0] == cmd->optShort && currArg[1] == 0) ||
-                strcmp(currArg, cmd->optLong) == 0)
+            if ((currArg[0] == cmd->o_short && currArg[1] == 0) ||
+                strcmp(currArg, cmd->o_long) == 0)
             {
                 optCommand = cmd->id;
                 break;