]> git.ozlabs.org Git - ccan/commitdiff
opt: allow show callbacks to return false.
authorRusty Russell <rusty@rustcorp.com.au>
Mon, 8 May 2023 01:30:31 +0000 (11:00 +0930)
committerRusty Russell <rusty@rustcorp.com.au>
Tue, 20 Jun 2023 03:08:36 +0000 (12:38 +0930)
Sometimes, arguments are optional, so it's useful to decide at runtime
whether to print a default in --help.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ccan/opt/helpers.c
ccan/opt/opt.c
ccan/opt/opt.h
ccan/opt/test/run-add_desc.c
ccan/opt/test/utils.c
ccan/opt/test/utils.h
ccan/opt/usage.c

index 0a6cb345f807a4a27dea1c4bfb2f907016a4c7f4..df7ee6bb1f20cf791fe82525393e7c809b6f7afb 100644 (file)
@@ -138,10 +138,11 @@ char *opt_set_floatval(const char *arg, float *f)
        return NULL;
 }
 
-void opt_show_floatval(char *buf, size_t len, const float *f)
+bool opt_show_floatval(char *buf, size_t len, const float *f)
 {
        double d = *f;
        opt_show_doubleval(buf, len, &d);
+       return true;
 }
 
 char *opt_set_doubleval(const char *arg, double *d)
@@ -160,9 +161,10 @@ char *opt_set_doubleval(const char *arg, double *d)
        return NULL;
 }
 
-void opt_show_doubleval(char *buf, size_t len, const double *d)
+bool opt_show_doubleval(char *buf, size_t len, const double *d)
 {
        snprintf(buf, len, "%f", *d);
+       return true;
 }
 
 char *opt_inc_intval(int *i)
@@ -196,22 +198,24 @@ char *opt_usage_and_exit(const char *extra)
        exit(0);
 }
 
-void opt_show_bool(char *buf, size_t len, const bool *b)
+bool opt_show_bool(char *buf, size_t len, const bool *b)
 {
        strncpy(buf, *b ? "true" : "false", len);
+       return true;
 }
 
-void opt_show_invbool(char *buf, size_t len, const bool *b)
+bool opt_show_invbool(char *buf, size_t len, const bool *b)
 {
        strncpy(buf, *b ? "false" : "true", len);
+       return true;
 }
 
-void opt_show_charp(char *buf, size_t len, char *const *p)
+bool opt_show_charp(char *buf, size_t len, char *const *p)
 {
        if (*p) {
                size_t plen = strlen(*p);
                if (len < 2)
-                       return;
+                       return false;
                buf[0] = '"';
                if (plen > len - 2)
                        plen = len - 2;
@@ -219,31 +223,35 @@ void opt_show_charp(char *buf, size_t len, char *const *p)
                buf[1+plen] = '"';
                if (plen < len - 2)
                        buf[2+plen] = '\0';
-       }
-       else {
-               strncpy(buf, "(nil)", len);
+               return true;
+       else {
+               return false;
        }
 }
 
 /* Show an integer value, various forms. */
-void opt_show_intval(char *buf, size_t len, const int *i)
+bool opt_show_intval(char *buf, size_t len, const int *i)
 {
        snprintf(buf, len, "%i", *i);
+       return true;
 }
 
-void opt_show_uintval(char *buf, size_t len, const unsigned int *ui)
+bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui)
 {
        snprintf(buf, len, "%u", *ui);
+       return true;
 }
 
-void opt_show_longval(char *buf, size_t len, const long *l)
+bool opt_show_longval(char *buf, size_t len, const long *l)
 {
        snprintf(buf, len, "%li", *l);
+       return true;
 }
 
-void opt_show_ulongval(char *buf, size_t len, const unsigned long *ul)
+bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul)
 {
        snprintf(buf, len, "%lu", *ul);
+       return true;
 }
 
 /* a helper function that multiplies out an argument's kMGTPE suffix in the
@@ -495,66 +503,78 @@ static void show_ullong_with_suffix(char *buf, size_t len,
 }
 
 /* _bi, signed */
-void opt_show_intval_bi(char *buf, size_t len, const int *x)
+bool opt_show_intval_bi(char *buf, size_t len, const int *x)
 {
        show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
-void opt_show_longval_bi(char *buf, size_t len, const long *x)
+bool opt_show_longval_bi(char *buf, size_t len, const long *x)
 {
        show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
-void opt_show_longlongval_bi(char *buf, size_t len, const long long *x)
+bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x)
 {
        show_llong_with_suffix(buf, len, *x, 1024);
+       return true;
 }
 
 /* _bi, unsigned */
-void opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x)
+bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
-void opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x)
+bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
-void opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x)
+bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1024);
+       return true;
 }
 
 /* _si, signed */
-void opt_show_intval_si(char *buf, size_t len, const int *x)
+bool opt_show_intval_si(char *buf, size_t len, const int *x)
 {
        show_llong_with_suffix(buf, len, (long long) *x, 1000);
+       return true;
 }
 
-void opt_show_longval_si(char *buf, size_t len, const long *x)
+bool opt_show_longval_si(char *buf, size_t len, const long *x)
 {
        show_llong_with_suffix(buf, len, (long long) *x, 1000);
+       return true;
 }
 
-void opt_show_longlongval_si(char *buf, size_t len, const long long *x)
+bool opt_show_longlongval_si(char *buf, size_t len, const long long *x)
 {
        show_llong_with_suffix(buf, len, *x, 1000);
+       return true;
 }
 
 /* _si, unsigned */
-void opt_show_uintval_si(char *buf, size_t len, const unsigned int *x)
+bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
-void opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x)
+bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
-void opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x)
+bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x)
 {
        show_ullong_with_suffix(buf, len, (unsigned long long) *x, 1000);
+       return true;
 }
 
index 09c8508142341730002a03f6ab4cf9589b1ade61..9149374cb001e6152eb46e03de6cc092ef6e4297 100644 (file)
@@ -162,7 +162,7 @@ static void add_opt(const struct opt_table *entry)
 void _opt_register(const char *names, enum opt_type type,
                   char *(*cb)(void *arg),
                   char *(*cb_arg)(const char *optarg, void *arg),
-                  void (*show)(char *buf, size_t len, const void *arg),
+                  bool (*show)(char *buf, size_t len, const void *arg),
                   const void *arg, const char *desc)
 {
        struct opt_table opt;
index 9c9f337d0a61685bf301883b9a5d1d01bb93a82b..e0331be264230cb57a100f30e26a6f119bf6ca6c 100644 (file)
@@ -47,9 +47,10 @@ struct opt_table;
  * where "type" is the type of the @arg argument.  The first argument to the
  * @cb is the argument found on the commandline.
  *
- * Similarly, if @show is not NULL, it should be of type "void show(char *,
- * size_t len, const type *)".  It should write up to len bytes into the first
- * argument; unless it uses the entire len bytes it should nul-terminate that
+ * Similarly, if @show is not NULL, it should be of type "bool show(char *,
+ * size_t len, const type *)".  If there is no default, it should return false,
+ * otherwise it should write up to len bytes into the first argument and
+ * return true; unless it uses the entire len bytes it should nul-terminate that
  * buffer.
  *
  * Any number of equivalent short or long options can be listed in @names,
@@ -434,32 +435,33 @@ extern const char opt_hidden[];
 char *opt_set_bool(bool *b);
 /* Sets @b based on arg: (yes/no/true/false). */
 char *opt_set_bool_arg(const char *arg, bool *b);
-void opt_show_bool(char *buf, size_t len, const bool *b);
+bool opt_show_bool(char *buf, size_t len, const bool *b);
 /* The inverse */
 char *opt_set_invbool(bool *b);
-void opt_show_invbool(char *buf, size_t len, const bool *b);
+bool opt_show_invbool(char *buf, size_t len, const bool *b);
 /* Sets @b based on !arg: (yes/no/true/false). */
 char *opt_set_invbool_arg(const char *arg, bool *b);
 
 /* Set a char *. */
 char *opt_set_charp(const char *arg, char **p);
-void opt_show_charp(char *buf, size_t len, char *const *p);
+/* If *p is NULL, this returns false (i.e. doesn't show a default) */
+bool opt_show_charp(char *buf, size_t len, char *const *p);
 
 /* Set an integer value, various forms.  Sets to 1 on arg == NULL. */
 char *opt_set_intval(const char *arg, int *i);
-void opt_show_intval(char *buf, size_t len, const int *i);
+bool opt_show_intval(char *buf, size_t len, const int *i);
 char *opt_set_uintval(const char *arg, unsigned int *ui);
-void opt_show_uintval(char *buf, size_t len, const unsigned int *ui);
+bool opt_show_uintval(char *buf, size_t len, const unsigned int *ui);
 char *opt_set_longval(const char *arg, long *l);
-void opt_show_longval(char *buf, size_t len, const long *l);
+bool opt_show_longval(char *buf, size_t len, const long *l);
 char *opt_set_ulongval(const char *arg, unsigned long *ul);
-void opt_show_ulongval(char *buf, size_t len, const unsigned long *ul);
+bool opt_show_ulongval(char *buf, size_t len, const unsigned long *ul);
 
 /* Set an floating point value, various forms. */
 char *opt_set_floatval(const char *arg, float *f);
-void opt_show_floatval(char *buf, size_t len, const float *f);
+bool opt_show_floatval(char *buf, size_t len, const float *f);
 char *opt_set_doubleval(const char *arg, double *d);
-void opt_show_doubleval(char *buf, size_t len, const double *d);
+bool opt_show_doubleval(char *buf, size_t len, const double *d);
 
 /* the following setting functions accept k, M, G, T, P, or E suffixes, which
    multiplies the numeric value by the corresponding power of 1000 or 1024
@@ -479,19 +481,19 @@ char *opt_set_ulonglongval_bi(const char *arg, unsigned long long *ll);
 char *opt_set_ulonglongval_si(const char *arg, unsigned long long *ll);
 
 
-void opt_show_intval_bi(char *buf, size_t len, const int *x);
-void opt_show_longval_bi(char *buf, size_t len, const long *x);
-void opt_show_longlongval_bi(char *buf, size_t len, const long long *x);
-void opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x);
-void opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x);
-void opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x);
+bool opt_show_intval_bi(char *buf, size_t len, const int *x);
+bool opt_show_longval_bi(char *buf, size_t len, const long *x);
+bool opt_show_longlongval_bi(char *buf, size_t len, const long long *x);
+bool opt_show_uintval_bi(char *buf, size_t len, const unsigned int *x);
+bool opt_show_ulongval_bi(char *buf, size_t len, const unsigned long *x);
+bool opt_show_ulonglongval_bi(char *buf, size_t len, const unsigned long long *x);
 
-void opt_show_intval_si(char *buf, size_t len, const int *x);
-void opt_show_longval_si(char *buf, size_t len, const long *x);
-void opt_show_longlongval_si(char *buf, size_t len, const long long *x);
-void opt_show_uintval_si(char *buf, size_t len, const unsigned int *x);
-void opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x);
-void opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x);
+bool opt_show_intval_si(char *buf, size_t len, const int *x);
+bool opt_show_longval_si(char *buf, size_t len, const long *x);
+bool opt_show_longlongval_si(char *buf, size_t len, const long long *x);
+bool opt_show_uintval_si(char *buf, size_t len, const unsigned int *x);
+bool opt_show_ulongval_si(char *buf, size_t len, const unsigned long *x);
+bool opt_show_ulonglongval_si(char *buf, size_t len, const unsigned long long *x);
 
 
 
@@ -551,7 +553,7 @@ struct opt_table {
        enum opt_type type;
        char *(*cb)(void *arg); /* OPT_NOARG */
        char *(*cb_arg)(const char *optarg, void *arg); /* OPT_HASARG */
-       void (*show)(char *buf, size_t len, const void *arg);
+       bool (*show)(char *buf, size_t len, const void *arg);
        union {
                const void *carg;
                void *arg;
@@ -577,14 +579,14 @@ struct opt_table {
                          char *(*)(const char *, const typeof(*(arg))*), \
                          char *(*)(const char *, const void *),        \
                          (cb)),                                        \
-       typesafe_cb_cast(void (*)(char *buf, size_t, const void *), \
-                        void (*)(char *buf, size_t, const typeof(*(arg))*), (show))
+       typesafe_cb_cast(bool (*)(char *buf, size_t, const void *), \
+                        bool (*)(char *buf, size_t, const typeof(*(arg))*), (show))
 
 /* Non-typesafe register function. */
 void _opt_register(const char *names, enum opt_type type,
                   char *(*cb)(void *arg),
                   char *(*cb_arg)(const char *optarg, void *arg),
-                  void (*show)(char *buf, size_t len, const void *arg),
+                  bool (*show)(char *buf, size_t len, const void *arg),
                   const void *arg, const char *desc);
 
 /* We use this to get typechecking for OPT_SUBTABLE */
index ddec6f13e13b66051797ccca148459d88d89f028..03e6986dd191954c7f14491353db1adfe0e51d51 100644 (file)
@@ -4,15 +4,24 @@
 #include <ccan/opt/helpers.c>
 #include <ccan/opt/parse.c>
 
-static void show_10(char *buf, size_t len, const void *arg UNNEEDED)
+static bool show_10(char *buf, size_t len, const void *arg UNNEEDED)
 {
        memset(buf, 'X', 10);
        buf[10] = '\0';
+       return true;
 }
 
-static void show_max(char *buf, size_t len, const void *arg UNNEEDED)
+static bool show_10_false(char *buf, size_t len, const void *arg UNNEEDED)
+{
+       memset(buf, 'X', 10);
+       buf[10] = '\0';
+       return false;
+}
+
+static bool show_max(char *buf, size_t len, const void *arg UNNEEDED)
 {
        memset(buf, 'X', OPT_SHOW_LEN);
+       return true;
 }
 
 /* Test add_desc helper. */
@@ -22,7 +31,7 @@ int main(void)
        char *ret;
        size_t len, max;
 
-       plan_tests(30);
+       plan_tests(32);
 
        opt.show = NULL;
        opt.names = "01234";
@@ -113,6 +122,14 @@ int main(void)
                   "        (default: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...)\n") == 0);
        free(ret); len = max = 0;
 
+       /* With show function which fails doesn't print. */
+       opt.show = show_10_false;
+       ret = add_desc(NULL, &len, &max, 7, 41, &opt);
+       ok1(len < max);
+       ret[len] = '\0';
+       ok1(strcmp(ret, "01234  0123456789 0\n") == 0);
+       free(ret); len = max = 0;
+
        /* With added " <arg>".  Fits, just. */
        opt.show = NULL;
        opt.type = OPT_HASARG;
index 700748be0c2a0127eff8a773bfea191f6ace2500..61199fb4676dbdeaa8a5cdf81a6fba7a27d5de5d 100644 (file)
@@ -21,9 +21,10 @@ char *test_arg(const char *optarg, const char *arg)
        return NULL;
 }
 
-void show_arg(char *buf, size_t len, const char *arg)
+bool show_arg(char *buf, size_t len, const char *arg)
 {
        strncpy(buf, arg, len);
+       return true;
 }
 
 char *err_output = NULL;
index 64641ec4f1d354e00e7fd77bda4699957ebc322a..3ada62d117c048ef666f5078d874c5bcc6a47129 100644 (file)
@@ -13,7 +13,7 @@ void reset_options(void);
 extern unsigned int test_cb_called;
 char *test_noarg(void *arg);
 char *test_arg(const char *optarg, const char *arg);
-void show_arg(char *buf, size_t len, const char *arg);
+bool show_arg(char *buf, size_t len, const char *arg);
 
 extern struct opt_table short_table[];
 extern struct opt_table long_table[];
index e96298382c3d018f16b55281115ceace40164939..568e4661d8098bf1fd009a169867b0d369339fb2 100644 (file)
@@ -151,20 +151,20 @@ static char *add_desc(char *base, size_t *len, size_t *max,
        if (opt->show) {
                char buf[OPT_SHOW_LEN + sizeof("...")];
                strcpy(buf + OPT_SHOW_LEN, "...");
-               opt->show(buf, OPT_SHOW_LEN, opt->u.arg);
+               if (opt->show(buf, OPT_SHOW_LEN, opt->u.arg)) {
+                       /* If it doesn't fit on this line, indent. */
+                       if (off + strlen(" (default: ") + strlen(buf) + strlen(")")
+                           > width) {
+                               base = add_indent(base, len, max, indent);
+                       } else {
+                               /* Remove \n. */
+                               (*len)--;
+                       }
 
-               /* If it doesn't fit on this line, indent. */
-               if (off + strlen(" (default: ") + strlen(buf) + strlen(")")
-                   > width) {
-                       base = add_indent(base, len, max, indent);
-               } else {
-                       /* Remove \n. */
-                       (*len)--;
+                       base = add_str(base, len, max, " (default: ");
+                       base = add_str(base, len, max, buf);
+                       base = add_str(base, len, max, ")\n");
                }
-
-               base = add_str(base, len, max, " (default: ");
-               base = add_str(base, len, max, buf);
-               base = add_str(base, len, max, ")\n");
        }
        return base;
 }