changeset 2400:01c6a5261962

Sync commandline argument help printing/handling changes from th-libs.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 12 Jan 2020 19:25:52 +0200
parents 5d391c31ebc9
children 263093248f26
files src/dmargs.c src/dmargs.h
diffstat 2 files changed, 149 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/src/dmargs.c	Sun Jan 12 03:41:02 2020 +0200
+++ b/src/dmargs.c	Sun Jan 12 19:25:52 2020 +0200
@@ -175,14 +175,24 @@
 }
 
 
-static void dmPad(FILE *outFile, int count)
+void dmPrintPad(FILE *fh, int count, const char och)
 {
     while (count--)
-        fputc(' ', outFile);
+        fputc(och, fh);
 }
 
 
-static void dmPrintWrap(FILE *fh, const char *str, int spad, int rpad, int width)
+/**
+ * Print given string indented in such a way that it is automatically
+ * line-wrapped as necessary, taking hard linefeeds into account as well.
+ * @param fh stdio file handle to output to
+ * @param str string to output
+ * @param spad starting pad/indent of the first line
+ * @param rpad how much to pad the other lines
+ * @param width total line width to wrap at
+ */
+void dmPrintWrap(FILE *fh, const char *str,
+    const int spad, int const rpad, const int width)
 {
     size_t pos = 0;
     BOOL first = TRUE;
@@ -191,42 +201,125 @@
     {
         // Pre-pad line
         int linelen = first ? spad : rpad;
-        dmPad(fh, first ? 0 : rpad);
+        dmPrintPad(fh, first ? 0 : rpad, ' ');
         first = FALSE;
 
         // Skip whitespace at line start
-        while (isspace(str[pos]) || str[pos] == '\n') pos++;
+        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);
+
+            // Find word length and next break
+            for (wlen = 0, next = pos;
+                str[next] && !isspace(str[next]) &&
+                str[next] != '\n';
+                next++, wlen++);
 
-                if (str[next] == '\n' || str[next] == 0)
-                {
-                    fprintf(fh, "\n");
-                    break;
-                }
-                else
-                {
-                    fputc(str[pos], fh);
-                    pos++;
-                    linelen++;
-                }
-            }
+            // Check if we have too much of text?
+            if (linelen + wlen >= width)
+                break;
+
+            // Print what we have
+            for (;pos < next; pos++, linelen++)
+                fputc(str[pos], fh);
+
+            // Check if we are at end of input or hard linefeed
+            if (str[next] == '\n' || str[next] == 0)
+                break;
             else
             {
-                fprintf(fh, "\n");
-                break;
+                fputc(str[pos], fh);
+                pos++;
+                linelen++;
             }
         }
+        fprintf(fh, "\n");
+    }
+}
+
+
+static inline const char *dmArgsGetOptArg(const DMOptArg *opt)
+{
+#ifdef DM_USE_OPT_ARG
+    return opt->o_arg != NULL ? opt->o_arg : "ARG";
+#else
+    (void) opt;
+    return "ARG";
+#endif
+}
+
+
+static void dmArgsPrintHelpPrintItem(FILE *fh, const DMOptArg *opt, int *lineWidth, const int maxLineWidth, const BOOL doPrint)
+{
+    const char *arg = dmArgsGetOptArg(opt);
+    char fmtBuf[32];
+    int padWidth;
+    BOOL hasLongOpt = opt->o_long != NULL;
+
+    if (opt->o_short != 0)
+    {
+        if (!hasLongOpt && (opt->flags & OPT_ARGREQ))
+        {
+            snprintf(fmtBuf, sizeof(fmtBuf), " -%c <%s>",
+                opt->o_short, arg);
+        }
+        else
+        {
+            snprintf(fmtBuf, sizeof(fmtBuf), " -%c,",
+                opt->o_short);
+        }
+
+        *lineWidth = strlen(fmtBuf);
+        if (doPrint)
+            padWidth = hasLongOpt ? 2 : maxLineWidth - *lineWidth;
+        else
+            padWidth = 2;
+    }
+    else
+    {
+        fmtBuf[0] = 0;
+        *lineWidth = 0;
+        padWidth = 4 + 2;
+    }
+
+    if (doPrint)
+    {
+        fputs(fmtBuf, fh);
+        dmPrintPad(fh, padWidth, ' ');
+    }
+    *lineWidth += padWidth;
+
+    if (hasLongOpt)
+    {
+        if (opt->flags & OPT_ARGREQ)
+        {
+            snprintf(fmtBuf, sizeof(fmtBuf), "--%s=<%s>",
+                opt->o_long, arg);
+        }
+        else
+        {
+            snprintf(fmtBuf, sizeof(fmtBuf), "--%s",
+                opt->o_long);
+        }
+
+        *lineWidth += strlen(fmtBuf);
+    }
+    else
+        fmtBuf[0] = 0;
+
+    if (doPrint)
+    {
+        padWidth = hasLongOpt ? maxLineWidth - *lineWidth : 0;
+        *lineWidth += padWidth;
+
+        fputs(fmtBuf, fh);
+        dmPrintPad(fh, padWidth, ' ');
+        dmPrintWrap(fh, opt->desc, *lineWidth, *lineWidth, 79);
     }
 }
 
@@ -238,42 +331,29 @@
  * @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)
+void dmArgsPrintHelp(FILE *fh, const DMOptArg *opts,
+    const int nopts, const int flags)
 {
-    int index;
+    int index, maxLineWidth;
+
     (void) flags;
 
-    // Print out option list
+    // Determine width of the options and arguments
+    maxLineWidth = 0;
     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);
+        int lineWidth = 0;
+        dmArgsPrintHelpPrintItem(NULL, &opts[index], &lineWidth, 0, FALSE);
+        if (lineWidth > maxLineWidth)
+            maxLineWidth = lineWidth;
+    }
 
-        // 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;
+    maxLineWidth += 2;
 
-        fprintf(fh, "%-18s", tmpStr);
-
-        dmPrintWrap(fh, opt->desc, 24, 24, 79);
+    // Print out the formatted option list
+    for (index = 0; index < nopts; index++)
+    {
+        int lineWidth;
+        dmArgsPrintHelpPrintItem(fh, &opts[index], &lineWidth, maxLineWidth, TRUE);
     }
 }
--- a/src/dmargs.h	Sun Jan 12 03:41:02 2020 +0200
+++ b/src/dmargs.h	Sun Jan 12 19:25:52 2020 +0200
@@ -35,20 +35,26 @@
 typedef struct
 {
     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 o_short;     ///< Short option name (one character, can be 0 for none)
+    char *o_long;     ///< Long option name (can be NULL for none)
+#ifdef DM_USE_OPT_ARG
+    char *o_arg;      ///< Option argument name (can be NULL for none/default)
+#endif
     char *desc;       ///< Option description
     int flags;        ///< Flags (see OPT_*)
 } DMOptArg;
 
 
-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);
+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);
 
-void dmArgsPrintHelp(FILE *, const DMOptArg *opts,
-     const int nopts, const int flags);
+void     dmArgsPrintHelp(FILE *fh, const DMOptArg *opts,
+         const int nopts, const int flags);
+
+void     dmPrintWrap(FILE *fh, const char *str,
+         const int spad, const int rpad, const int width);
 
 #ifdef __cplusplus
 }