tdb2: copy tdb1's changed expansion logic.
[ccan] / ccan / opt / opt.c
index 8f67740036e7e5c5ac53bb3c2abe8d5a9ccc7fce..094b15c7e1b48c25aed1256aa741921ad8091f52 100644 (file)
@@ -1,3 +1,4 @@
+/* Licensed under GPLv3+ - see LICENSE file for details */
 #include <ccan/opt/opt.h>
 #include <string.h>
 #include <errno.h>
@@ -106,7 +107,9 @@ static void check_opt(const struct opt_table *entry)
        const char *p;
        unsigned len;
 
-       if (entry->type != OPT_HASARG && entry->type != OPT_NOARG)
+       if (entry->type != OPT_HASARG && entry->type != OPT_NOARG
+           && entry->type != (OPT_EARLY|OPT_HASARG)
+           && entry->type != (OPT_EARLY|OPT_NOARG))
                errx(1, "Option %s: unknown entry type %u",
                     entry->names, entry->type);
 
@@ -150,7 +153,7 @@ 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[OPT_SHOW_LEN], const void *arg),
-                  void *arg, const char *desc)
+                  const void *arg, const char *desc)
 {
        struct opt_table opt;
        opt.names = names;
@@ -158,7 +161,7 @@ void _opt_register(const char *names, enum opt_type type,
        opt.cb = cb;
        opt.cb_arg = cb_arg;
        opt.show = show;
-       opt.arg = arg;
+       opt.u.carg = arg;
        opt.desc = desc;
        check_opt(&opt);
        add_opt(&opt);
@@ -183,7 +186,7 @@ void opt_register_table(const struct opt_table entry[], const char *desc)
        }
        /* We store the table length in arg ptr. */
        if (desc)
-               opt_table[start].arg = (void *)(intptr_t)(opt_count - start);
+               opt_table[start].u.tlen = (opt_count - start);
 }
 
 /* Parse your arguments. */
@@ -195,12 +198,40 @@ bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...))
        /* This helps opt_usage. */
        opt_argv0 = argv[0];
 
-       while ((ret = parse_one(argc, argv, &offset, errlog)) == 1);
+       while ((ret = parse_one(argc, argv, 0, &offset, errlog)) == 1);
 
        /* parse_one returns 0 on finish, -1 on error */
        return (ret == 0);
 }
 
+bool opt_early_parse(int argc, char *argv[],
+                    void (*errlog)(const char *fmt, ...))
+{
+       int ret;
+       unsigned off = 0;
+       char **tmpargv = malloc(sizeof(argv[0]) * (argc + 1));
+
+       /* We could avoid a copy and skip instead, but this is simple. */
+       memcpy(tmpargv, argv, sizeof(argv[0]) * (argc + 1));
+
+       /* This helps opt_usage. */
+       opt_argv0 = argv[0];
+
+       while ((ret = parse_one(&argc, tmpargv, OPT_EARLY, &off, errlog)) == 1);
+
+       free(tmpargv);
+
+       /* parse_one returns 0 on finish, -1 on error */
+       return (ret == 0);
+}
+
+void opt_free_table(void)
+{
+       free(opt_table);
+       opt_table = NULL;
+       opt_count = opt_num_short = opt_num_short_arg = opt_num_long = 0;
+}
+
 void opt_log_stderr(const char *fmt, ...)
 {
        va_list ap;