Welcome to little lamb

Code » limb » commit 4b68021

parseopt: Actually emit warnings unless PARSEOPT_SILENT..

author Olivier Brunel
2023-04-14 12:54:22 UTC
committer Olivier Brunel
2023-05-20 18:06:36 UTC
parent 09dd44238a5219ba2118e6d31703603dbe23dfbc

parseopt: Actually emit warnings unless PARSEOPT_SILENT..

..is set in flags.

src/doc/loadopt.h/loadopt.3.md +4 -5
src/doc/parseopt.h.0.md +1 -1
src/doc/parseopt.h/parseopt.3.md +6 -3
src/include/parseopt.h +13 -0
src/liblimb/include/limb/parseopt.h +1 -0
src/liblimb/loadopt.h/loadopt.c +5 -42
src/liblimb/parseopt.h/parseopt.c +14 -4
src/liblimb/parseopt.h/parseopt_warn.c +41 -0

diff --git a/src/doc/loadopt.h/loadopt.3.md b/src/doc/loadopt.h/loadopt.3.md
index 1324e38..3fd2e92 100644
--- a/src/doc/loadopt.h/loadopt.3.md
+++ b/src/doc/loadopt.h/loadopt.3.md
@@ -131,13 +131,12 @@ If an option was successfully found, `loadopt`() returns the option's `id` if
 non-zero, else its `shortopt`. When all options, and, optionally, arguments,
 have been successfully parsed it returns 0.
 
-If an error occurs, a warning is emitted to *stderr* and it returns -1, setting
-`errno` to indicate the error.
+If an error occurs, `loadopt`() returns -1 and sets `errno` to indicate the
+error.
 
 ! INFO:
-! The warnings are actually written out using one of the [warn](3) family of
-! functions. Refer to it for more on how and where data is being written to, or
-! how to silence them.
+! Warnings may be emitted on error unless *PARSEOPT_SILENT* was set in `flags`.
+! Refer to [parseopt](3) for more.
 
 # ERRORS
 
diff --git a/src/doc/parseopt.h.0.md b/src/doc/parseopt.h.0.md
index 32914c6..4aafe68 100644
--- a/src/doc/parseopt.h.0.md
+++ b/src/doc/parseopt.h.0.md
@@ -34,7 +34,7 @@ The following constants are defined :
 : *OPTID_SHORTOPT*
 :: Special ID for an option, meaning to return its `shortopt` instead.
 
-: *PARSEOPT_IS_LONG*, *PARSEOPT_STRICT*
+: *PARSEOPT_IS_LONG*, *PARSEOPT_STRICT*, *PARSEOPT_SILENT*
 :: Flags that can be passed to [parseopt](3).
 
 ## Structures
diff --git a/src/doc/parseopt.h/parseopt.3.md b/src/doc/parseopt.h/parseopt.3.md
index 76dc32a..d74c579 100644
--- a/src/doc/parseopt.h/parseopt.3.md
+++ b/src/doc/parseopt.h/parseopt.3.md
@@ -139,6 +139,9 @@ constructed as a bitwise-inclusive OR of flags from the following list :
 : *PARSEOPT_STRICT*
 :: Long options can not be abbreviated, and must be exact match.
 
+: *PARSEOPT_SILENT*
+:: Do not emit any warnings in case of errors.
+
 : *PARSEOPT_IS_LONG*
 :: /Intended for internal use./ Assumes all elements of `argv` are option
 :: elements, composed of long option names directly (i.e. without "--" prefix).
@@ -153,9 +156,9 @@ When all command-line options have been parsed it returns 0.
 If an error occurs, it returns -1 and sets `errno` to indicate the error.
 
 ! NOTE:
-! Unlike [getopt](3), `parseopt`() will not print any warning/error messages.
-! The indication of the error is sent through `errno` and it is up to the
-! caller to inform the user of what failed.
+! In case of error, `parseopt`() will also write a warning explaining the error
+! on *stderr* (done through the [warn](3) family of functions), /unless/
+! *PARSEOPT_SILENT* was specified in its `flags` argument.
 
 # ERRORS
 
diff --git a/src/include/parseopt.h b/src/include/parseopt.h
new file mode 100644
index 0000000..5e0a058
--- /dev/null
+++ b/src/include/parseopt.h
@@ -0,0 +1,13 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LIMB_LIMB_PARSEOPT_H
+#define LIMB_LIMB_PARSEOPT_H
+
+#include <limb/gccattributes.h>
+#include <limb/parseopt.h>
+
+void parseopt_warn(const char **argv, const struct option *options,
+                   const struct parseopt *ctx) gccattr_hidden;
+
+#endif /* LIMB_LIMB_PARSEOPT_H */
diff --git a/src/liblimb/include/limb/parseopt.h b/src/liblimb/include/limb/parseopt.h
index b3f31bf..9dedd93 100644
--- a/src/liblimb/include/limb/parseopt.h
+++ b/src/liblimb/include/limb/parseopt.h
@@ -39,6 +39,7 @@ enum {
     PARSEOPT_IS_LONG    = 1 << 0,
     /* public */
     PARSEOPT_STRICT     = 1 << 1,
+    PARSEOPT_SILENT     = 1 << 2,
 };
 
 struct parseopt {
diff --git a/src/liblimb/loadopt.h/loadopt.c b/src/liblimb/loadopt.h/loadopt.c
index 7de2984..a2c1818 100644
--- a/src/liblimb/loadopt.h/loadopt.c
+++ b/src/liblimb/loadopt.h/loadopt.c
@@ -7,6 +7,7 @@
 #include <limb/djbunix.h>
 #include <limb/loadopt.h>
 #include <limb/output.h>
+#include "parseopt.h"
 #include "loadopt.h"
 
 void
@@ -27,43 +28,6 @@ get_optflags(const u8 *optflags, int idx)
     return b & 0xf;
 }
 
-static void
-parseopt_warn(int c, const char **argv, const struct option *options,
-             const struct parseopt *ctx)
-{
-    if (c >= 0)
-        return;
-
-    switch (errno) {
-        case EINVAL:
-            warn("option name missing");
-            break;
-        case ENOENT:
-            if (!strncmp(argv[ctx->cur], "--", 2)) {
-                warn("unknown option: ", argv[ctx->cur]);
-                /* was there a partial match? */
-                if (ctx->idx >= 0) {
-                    const char *s = argv[ctx->cur] + ctx->off;
-                    size_t l = byte_chr(s, strlen(s), '=');
-                    list_matches_full(err_putmsg, OLVL_NORMAL, "did you mean ",
-                                      "--", " or ", " ?", s, l, ctx->idx, options,
-                                      offsetof(struct option, longopt), sizeof(*options));
-                }
-            } else {
-                char buf[3] = { '-', argv[ctx->cur][ctx->off], 0 };
-                warn("unknown option: ", buf);
-            }
-            break;
-        case ENOMSG:
-            {
-                char buf[2] = { options[ctx->idx].shortopt, 0 };
-                warn("option --", options[ctx->idx].longopt,
-                     (*buf) ? "/-" : "", buf, " requires an argument");
-            }
-            break;
-    }
-}
-
 int
 loadopt(int argc, const char **argv, const struct option *options,
         const char *file, const char *section, unsigned int poflags,
@@ -84,8 +48,6 @@ loadopt(int argc, const char **argv, const struct option *options,
 
         if (c > 0)
             add_optflags(ctx->optflags, ctx->idx, OPT_SET);
-        else
-            parseopt_warn(c, argv, options, (struct parseopt *) ctx);
 
         if (c)
             return c;
@@ -186,7 +148,8 @@ nextfileopt:
             const char *argv[] = { "", ctx->sa.s + ctx->saoff };
 
             errno = 0;
-            int c = parseopt(2, argv, options, PARSEOPT_IS_LONG | PARSEOPT_STRICT, &po);
+            int c = parseopt(2, argv, options, PARSEOPT_IS_LONG
+                             | PARSEOPT_STRICT | PARSEOPT_SILENT, &po);
 
             /* seek past the line */
             ctx->saoff = o + 1;
@@ -200,8 +163,8 @@ nextfileopt:
 
             if (c > 0)
                 add_optflags(ctx->optflags, po.idx, OPT_SET);
-            else
-                parseopt_warn(c, argv, options, &po);
+            else if (c < 0 && !(poflags & PARSEOPT_SILENT))
+                parseopt_warn(argv, options, &po);
 
             if (c) {
                 /* adjust returned value */
diff --git a/src/liblimb/parseopt.h/parseopt.c b/src/liblimb/parseopt.h/parseopt.c
index 958eb63..668a68f 100644
--- a/src/liblimb/parseopt.h/parseopt.c
+++ b/src/liblimb/parseopt.h/parseopt.c
@@ -4,11 +4,11 @@
 #include <errno.h>
 #include <stddef.h> /* offsetof() */
 #include <limb/bytestr.h>
-#include <limb/parseopt.h>
+#include "parseopt.h"
 
-int
-parseopt(int argc, const char **argv, const struct option *options,
-         unsigned int flags, struct parseopt *ctx)
+static int
+do_parseopt(int argc, const char **argv, const struct option *options,
+            unsigned int flags, struct parseopt *ctx)
 {
     const char *arg;
     int is_long, arg_long;
@@ -116,3 +116,13 @@ again:
 
     return (options[ctx->idx].id) ? options[ctx->idx].id : options[ctx->idx].shortopt;
 }
+
+int
+parseopt(int argc, const char **argv, const struct option *options,
+         unsigned int flags, struct parseopt *ctx)
+{
+    int r = do_parseopt(argc, argv, options, flags, ctx);
+    if (r < 0 && !(flags & PARSEOPT_SILENT))
+        parseopt_warn(argv, options, ctx);
+    return r;
+}
diff --git a/src/liblimb/parseopt.h/parseopt_warn.c b/src/liblimb/parseopt.h/parseopt_warn.c
new file mode 100644
index 0000000..891ff38
--- /dev/null
+++ b/src/liblimb/parseopt.h/parseopt_warn.c
@@ -0,0 +1,41 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <errno.h>
+#include <limb/bytestr.h>
+#include <limb/output.h>
+#include "parseopt.h"
+
+void
+parseopt_warn(const char **argv, const struct option *options,
+              const struct parseopt *ctx)
+{
+    switch (errno) {
+        case EINVAL:
+            warn("option name missing");
+            break;
+        case ENOENT:
+            if (!strncmp(argv[ctx->cur], "--", 2)) {
+                warn("unknown option: ", argv[ctx->cur]);
+                /* was there a partial match? */
+                if (ctx->idx >= 0) {
+                    const char *s = argv[ctx->cur] + ctx->off;
+                    size_t l = byte_chr(s, strlen(s), '=');
+                    list_matches_full(err_putmsg, OLVL_NORMAL, "did you mean ",
+                                      "--", " or ", " ?", s, l, ctx->idx, options,
+                                      offsetof(struct option, longopt), sizeof(*options));
+                }
+            } else {
+                char buf[3] = { '-', argv[ctx->cur][ctx->off], 0 };
+                warn("unknown option: ", buf);
+            }
+            break;
+        case ENOMSG:
+            {
+                char buf[2] = { options[ctx->idx].shortopt, 0 };
+                warn("option --", options[ctx->idx].longopt,
+                     (*buf) ? "/-" : "", buf, " requires an argument");
+            }
+            break;
+    }
+}