]> git.ozlabs.org Git - ccan/blobdiff - ccan/opt/parse.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / opt / parse.c
index 5b2cec8b3d284e0b6795c87355d6ae00cf1290b9..b932bf333571620d0e19edca1b10a82cc70d8397 100644 (file)
@@ -1,4 +1,4 @@
-/* Licensed under GPLv3+ - see LICENSE file for details */
+/* Licensed under GPLv2+ - see LICENSE file for details */
 /* Actual code to parse commandline. */
 #include <ccan/opt/opt.h>
 #include <string.h>
@@ -14,7 +14,8 @@
 /tmp/opt-example: option requires an argument -- 's'
 */
 static int parse_err(void (*errlog)(const char *fmt, ...),
-                    const char *argv0, const char *arg, unsigned len,
+                    const char *argv0,
+                    const char *arg, unsigned len,
                     const char *problem)
 {
        errlog("%s: %.*s: %s", argv0, len, arg, problem);
@@ -28,13 +29,63 @@ static void consume_option(int *argc, char *argv[], unsigned optnum)
        (*argc)--;
 }
 
+/* This sets the len and o to indicate how far it is into the
+ * opt_table's names field. */
+static struct opt_table *opt_find_long_extra(const char *arg,
+                                            const char **optarg,
+                                            unsigned int *len,
+                                            const char **o)
+{
+       unsigned i;
+
+       *optarg = NULL;
+       for (*o = first_lopt(&i, len);
+            *o;
+            *o = next_lopt(*o, &i, len)) {
+               if (strncmp(arg, *o, *len) != 0)
+                       continue;
+               if (arg[*len] == '=')
+                       *optarg = arg + *len + 1;
+               else if (arg[*len] != '\0')
+                       continue;
+               return &opt_table[i];
+
+       }
+       return NULL;
+}
+
+struct opt_table *opt_find_long(const char *arg, const char **optarg)
+{
+       unsigned len;
+       const char *o;
+
+       return opt_find_long_extra(arg, optarg ? optarg : &o, &len, &o);
+}
+
+static struct opt_table *opt_find_short_extra(char arg, const char **o)
+{
+       unsigned i;
+       for (*o = first_sopt(&i); *o; *o = next_sopt(*o, &i)) {
+               if (arg == **o)
+                       return &opt_table[i];
+       }
+       return NULL;
+}
+
+struct opt_table *opt_find_short(char arg)
+{
+       const char *o;
+       return opt_find_short_extra(arg, &o);
+}
+
 /* Returns 1 if argument consumed, 0 if all done, -1 on error. */
 int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
-             void (*errlog)(const char *fmt, ...))
+             void (*errlog)(const char *fmt, ...), bool unknown_ok)
 {
-       unsigned i, arg, len;
+       unsigned arg, len;
        const char *o, *optarg = NULL;
        char *problem = NULL;
+       struct opt_table *ot;
 
        if (getenv("POSIXLY_CORRECT")) {
                /* Don't find options after non-options. */
@@ -58,45 +109,43 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
        /* Long options start with -- */
        if (argv[arg][1] == '-') {
                assert(*offset == 0);
-               for (o = first_lopt(&i, &len); o; o = next_lopt(o, &i, &len)) {
-                       if (strncmp(argv[arg] + 2, o, len) != 0)
-                               continue;
-                       if (argv[arg][2 + len] == '=')
-                               optarg = argv[arg] + 2 + len + 1;
-                       else if (argv[arg][2 + len] != '\0')
-                               continue;
-                       break;
-               }
-               if (!o)
+
+               ot = opt_find_long_extra(argv[arg]+2, &optarg, &len, &o);
+               if (!ot) {
+                       if (unknown_ok)
+                               goto ok;
                        return parse_err(errlog, argv[0],
                                         argv[arg], strlen(argv[arg]),
                                         "unrecognized option");
+               }
+
                /* For error messages, we include the leading '--' */
                o -= 2;
                len += 2;
        } else {
-               /* offset allows us to handle -abc */
-               for (o = first_sopt(&i); o; o = next_sopt(o, &i)) {
-                       if (argv[arg][*offset + 1] != *o)
-                               continue;
-                       (*offset)++;
-                       break;
-               }
-               if (!o)
+               ot = opt_find_short_extra(argv[arg][*offset + 1], &o);
+               if (!ot) {
+                       if (unknown_ok) {
+                               (*offset)++;
+                               goto ok;
+                       }
                        return parse_err(errlog, argv[0],
                                         argv[arg], strlen(argv[arg]),
                                         "unrecognized option");
+               }
+
+               (*offset)++;
                /* For error messages, we include the leading '-' */
                o--;
                len = 2;
        }
 
-       if ((opt_table[i].type & ~OPT_EARLY) == OPT_NOARG) {
+       if (ot->type & OPT_NOARG) {
                if (optarg)
                        return parse_err(errlog, argv[0], o, len,
                                         "doesn't allow an argument");
-               if ((opt_table[i].type & OPT_EARLY) == is_early)
-                       problem = opt_table[i].cb(opt_table[i].u.arg);
+               if ((ot->type & OPT_EARLY) == is_early)
+                       problem = ot->cb(ot->u.arg);
        } else {
                if (!optarg) {
                        /* Swallow any short options as optarg, eg -afile */
@@ -109,17 +158,17 @@ int parse_one(int *argc, char *argv[], enum opt_type is_early, unsigned *offset,
                if (!optarg)
                        return parse_err(errlog, argv[0], o, len,
                                         "requires an argument");
-               if ((opt_table[i].type & OPT_EARLY) == is_early)
-                       problem = opt_table[i].cb_arg(optarg,
-                                                     opt_table[i].u.arg);
+               if ((ot->type & OPT_EARLY) == is_early)
+                       problem = ot->cb_arg(optarg, ot->u.arg);
        }
 
        if (problem) {
                parse_err(errlog, argv[0], o, len, problem);
-               free(problem);
+               opt_alloc.free(problem);
                return -1;
        }
 
+ok:
        /* If no more letters in that short opt, reset offset. */
        if (*offset && !argv[arg][*offset + 1])
                *offset = 0;