X-Git-Url: https://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fopt%2Fopt.c;h=de56299cc34a6259bd45650867e5b856d11116fc;hp=ea27dfa7679f2c8a6e8353558ceec5eff3297e49;hb=cdc32f6d35066fe264a228fe20aa75729e41726e;hpb=b4cf10d83d46b50468ae52fccaeb99a793505467 diff --git a/ccan/opt/opt.c b/ccan/opt/opt.c index ea27dfa7..de56299c 100644 --- a/ccan/opt/opt.c +++ b/ccan/opt/opt.c @@ -14,89 +14,92 @@ struct opt_table *opt_table; unsigned int opt_count, opt_num_short, opt_num_short_arg, opt_num_long; const char *opt_argv0; +/* Returns string after first '-'. */ static const char *first_name(const char *names, unsigned *len) { - *len = strcspn(names + 1, "/"); + *len = strcspn(names + 1, "/= "); return names + 1; } static const char *next_name(const char *names, unsigned *len) { names += *len; - if (!names[0]) + if (names[0] == ' ' || names[0] == '=' || names[0] == '\0') return NULL; return first_name(names + 1, len); } -/* FIXME: Combine with next_opt */ -static const char *first_opt(bool want_long, unsigned *i, unsigned *len) +static const char *first_opt(unsigned *i, unsigned *len) { - const char *p; for (*i = 0; *i < opt_count; (*i)++) { - if (opt_table[*i].flags == OPT_SUBTABLE) + if (opt_table[*i].type == OPT_SUBTABLE) continue; - for (p = first_name(opt_table[*i].names, len); - p; - p = next_name(p, len)) { - if ((p[0] == '-') == want_long) { - if (want_long) { - /* Skip leading "-" */ - (*len)--; - p++; - } - return p; - } - } + return first_name(opt_table[*i].names, len); } return NULL; } -static const char *next_opt(const char *names, bool want_long, - unsigned *i, unsigned *len) +static const char *next_opt(const char *p, unsigned *i, unsigned *len) { - const char *p = next_name(names, len); - for (;;) { - while (p) { - if ((p[0] == '-') == want_long) { - if (want_long) { - /* Skip leading "-" */ - (*len)--; - p++; - } - return p; - } - p = next_name(p, len); - } - do { - (*i)++; - } while (*i < opt_count && opt_table[*i].flags == OPT_SUBTABLE); - if (*i == opt_count) - return NULL; - p = first_name(opt_table[*i].names, len); + for (; *i < opt_count; (*i)++) { + if (opt_table[*i].type == OPT_SUBTABLE) + continue; + if (!p) + return first_name(opt_table[*i].names, len); + p = next_name(p, len); + if (p) + return p; } + return NULL; } static const char *first_lopt(unsigned *i, unsigned *len) { - return first_opt(true, i, len); + const char *p; + for (p = first_opt(i, len); p; p = next_opt(p, i, len)) { + if (p[0] == '-') { + /* Skip leading "-" */ + (*len)--; + p++; + break; + } + } + return p; } -static const char *next_lopt(const char *names, unsigned *i, unsigned *len) +static const char *next_lopt(const char *p, unsigned *i, unsigned *len) { - return next_opt(names, true, i, len); + for (p = next_opt(p, i, len); p; p = next_opt(p, i, len)) { + if (p[0] == '-') { + /* Skip leading "-" */ + (*len)--; + p++; + break; + } + } + return p; } const char *first_sopt(unsigned *i) { - unsigned unused_len; - return first_opt(false, i, &unused_len); + const char *p; + unsigned int len = 0 /* GCC bogus warning */; + + for (p = first_opt(i, &len); p; p = next_opt(p, i, &len)) { + if (p[0] != '-') + break; + } + return p; } -const char *next_sopt(const char *names, unsigned *i) +const char *next_sopt(const char *p, unsigned *i) { - unsigned unused_len = 1; - - return next_opt(names, false, i, &unused_len); + unsigned int len = 1; + for (p = next_opt(p, i, &len); p; p = next_opt(p, i, &len)) { + if (p[0] != '-') + break; + } + return p; } static void check_opt(const struct opt_table *entry) @@ -104,23 +107,44 @@ static void check_opt(const struct opt_table *entry) const char *p; unsigned len; - assert(entry->flags == OPT_HASARG || entry->flags == OPT_NOARG); + if (entry->type != OPT_HASARG && entry->type != OPT_NOARG) + errx(1, "Option %s: unknown entry type %u", + entry->names, entry->type); + + if (!entry->desc) + errx(1, "Option %s: description cannot be NULL", entry->names); + + + if (entry->names[0] != '-') + errx(1, "Option %s: does not begin with '-'", entry->names); - assert(entry->names[0] == '-'); for (p = first_name(entry->names, &len); p; p = next_name(p, &len)) { if (*p == '-') { - assert(len > 1); + if (len == 1) + errx(1, "Option %s: invalid long option '--'", + entry->names); opt_num_long++; } else { - assert(len == 1); - assert(*p != ':'); + if (len != 1) + errx(1, "Option %s: invalid short option" + " '%.*s'", entry->names, len+1, p-1); + if (*p == ':') + errx(1, "Option %s: invalid short option '-:'", + entry->names); opt_num_short++; - if (entry->flags == OPT_HASARG) { + if (entry->type == OPT_HASARG) { opt_num_short_arg++; - /* FIXME: -? with ops breaks getopt_long */ - assert(*p != '?'); + if (*p == '?') + errx(1, "Option %s: '-?' cannot take" + " an argument", entry->names); } } + /* Don't document args unless there are some. */ + if (entry->type == OPT_NOARG) { + if (p[len] == ' ' || p[len] == '=') + errx(1, "Option %s: does not take arguments" + "'%s'", entry->names, p+len+1); + } } } @@ -130,7 +154,7 @@ static void add_opt(const struct opt_table *entry) opt_table[opt_count++] = *entry; } -void _opt_register(const char *names, enum opt_flags flags, +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), @@ -138,7 +162,7 @@ void _opt_register(const char *names, enum opt_flags flags, { struct opt_table opt; opt.names = names; - opt.flags = flags; + opt.type = type; opt.cb = cb; opt.cb_arg = cb_arg; opt.show = show; @@ -156,8 +180,8 @@ void opt_register_table(const struct opt_table entry[], const char *desc) struct opt_table heading = OPT_SUBTABLE(NULL, desc); add_opt(&heading); } - for (i = 0; entry[i].flags != OPT_END; i++) { - if (entry[i].flags == OPT_SUBTABLE) + for (i = 0; entry[i].type != OPT_END; i++) { + if (entry[i].type == OPT_SUBTABLE) opt_register_table(subtable_of(&entry[i]), entry[i].desc); else { @@ -180,7 +204,7 @@ static char *make_optstring(void) str[num++] = ':'; for (p = first_sopt(&i); p; p = next_sopt(p, &i)) { str[num++] = *p; - if (opt_table[i].flags == OPT_HASARG) + if (opt_table[i].type == OPT_HASARG) str[num++] = ':'; } str[num++] = '\0'; @@ -191,7 +215,7 @@ static char *make_optstring(void) static struct option *make_options(void) { struct option *options = malloc(sizeof(*options) * (opt_num_long + 1)); - unsigned int i, num = 0, len; + unsigned int i, num = 0, len = 0 /* GCC bogus warning */; const char *p; for (p = first_lopt(&i, &len); p; p = next_lopt(p, &i, &len)) { @@ -199,7 +223,7 @@ static struct option *make_options(void) memcpy(buf, p, len); buf[len] = 0; options[num].name = buf; - options[num].has_arg = (opt_table[i].flags == OPT_HASARG); + options[num].has_arg = (opt_table[i].type == OPT_HASARG); options[num].flag = NULL; options[num].val = 0; num++; @@ -254,13 +278,6 @@ static void parse_fail(void (*errlog)(const char *fmt, ...), strcspn(longopt, "/"), longopt, problem); } -void dump_optstate(void); -void dump_optstate(void) -{ - printf("opterr = %i, optind = %i, optopt = %i, optarg = %s\n", - opterr, optind, optopt, optarg); -} - /* Parse your arguments. */ bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...)) { @@ -279,7 +296,7 @@ bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...)) while ((ret = getopt_long(*argc, argv, optstring, options, &longidx)) != -1) { char *problem; - const char *name; + const char *name = NULL; /* GCC bogus warning */ /* optopt is 0 if it's an unknown long option, *or* if * -? is a valid short option. */ @@ -301,7 +318,7 @@ bool opt_parse(int *argc, char *argv[], void (*errlog)(const char *fmt, ...)) else e = find_long(longidx, &name); - if (e->flags == OPT_HASARG) + if (e->type == OPT_HASARG) problem = e->cb_arg(optarg, e->arg); else problem = e->cb(e->arg); @@ -330,7 +347,19 @@ void opt_log_stderr(const char *fmt, ...) va_start(ap, fmt); vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void opt_log_stderr_exit(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); va_end(ap); + exit(1); } char *opt_invalid_argument(const char *arg)