X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=ucw%2Fopt.c;h=a388b244e73e62e612d5a07ce06449c09012ad9d;hb=1dc196d10661025b7d658e47af5eb7be131154be;hp=39b5b69a71cd09a503c3968a74a02988cfe257cb;hpb=b1f7cfb12a103c904184af46008f1b147498c174;p=libucw.git diff --git a/ucw/opt.c b/ucw/opt.c index 39b5b69a..a388b244 100644 --- a/ucw/opt.c +++ b/ucw/opt.c @@ -2,6 +2,7 @@ * UCW Library -- Parsing of command line options * * (c) 2013 Jan Moskyto Matejka + * (c) 2014 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. @@ -46,7 +47,7 @@ struct opt_precomputed { }; struct opt_context { - struct opt_precomputed ** opts; + struct opt_precomputed * opts; struct opt_precomputed ** shortopt; struct opt_item ** hooks_before_arg; struct opt_item ** hooks_before_value; @@ -70,26 +71,6 @@ static void opt_failure(const char * mesg, ...) { va_end(args); // FIXME: Does this make a sense after exit()? } -// FIXME: This could be an inline function, couldn't it? -#define OPT_ADD_DEFAULT_ITEM_FLAGS(item, flags) \ - do { \ - if (item->letter >= 256) { \ - if (flags & OPT_VALUE_FLAGS) /* FIXME: Redundant condition */ \ - flags &= ~OPT_VALUE_FLAGS; \ - flags |= OPT_REQUIRED_VALUE; \ - } \ - if (!(flags & OPT_VALUE_FLAGS) && \ - (item->cls == OPT_CL_CALL || item->cls == OPT_CL_USER)) { \ - fprintf(stderr, "You MUST specify some of the value flags for the %c/%s item.\n", item->letter, item->name); \ - ASSERT(0); \ - } \ - else if (!(flags & OPT_VALUE_FLAGS)) /* FIXME: Streamline the conditions */ \ - flags |= opt_default_value_flags[item->cls]; \ - } while (0) - -// FIXME: Is this still useful? Isn't it better to use OPT_ADD_DEFAULT_ITEM_FLAGS during init? -#define OPT_ITEM_FLAGS(item) ((item->flags & OPT_VALUE_FLAGS) ? item->flags : item->flags | opt_default_value_flags[item->cls]) - #define FOREACHLINE(text) for (const char * begin = (text), * end = (text); (*end) && (end = strchrnul(begin, '\n')); begin = end+1) static inline uns uns_min(uns x, uns y) @@ -162,7 +143,7 @@ void opt_help(const struct opt_section * help) { uns eol = strchrnul(item->help, '\n') - item->help; if (valoff > eol) valoff = eol; -#define VAL(it) ((OPT_ITEM_FLAGS(it) & OPT_REQUIRED_VALUE) ? stk_printf("=%.*s", valoff, item->help) : ((OPT_ITEM_FLAGS(it) & OPT_NO_VALUE) ? "" : stk_printf("(=%.*s)", valoff, item->help))) +#define VAL(it) ((it->flags & OPT_REQUIRED_VALUE) ? stk_printf("=%.*s", valoff, item->help) : ((it->flags & OPT_NO_VALUE) ? "" : stk_printf("(=%.*s)", valoff, item->help))) if (item->name) { lines[line][1] = stk_printf("--%s%s", item->name, VAL(item)); if (linelengths[1] < (int) strlen(lines[line][1])) @@ -226,31 +207,31 @@ static struct opt_precomputed * opt_find_item_longopt(struct opt_context * oc, c struct opt_precomputed * candidate = NULL; for (int i=0; iopt_count; i++) { - if (!oc->opts[i]->name) + if (!oc->opts[i].name) continue; - if (!strncmp(oc->opts[i]->name, str, len)) { - if (strlen(oc->opts[i]->name) == len) { - if (oc->opts[i]->count++ && (oc->opts[i]->flags & OPT_SINGLE)) - opt_failure("Option %s appeared the second time.", oc->opts[i]->name); + if (!strncmp(oc->opts[i].name, str, len)) { + if (strlen(oc->opts[i].name) == len) { + if (oc->opts[i].count++ && (oc->opts[i].flags & OPT_SINGLE)) + opt_failure("Option %s appeared the second time.", oc->opts[i].name); - return oc->opts[i]; + return &oc->opts[i]; } if (candidate) - opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, oc->opts[i]->name); + opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, oc->opts[i].name); else - candidate = oc->opts[i]; + candidate = &oc->opts[i]; } - if (!strncmp("no-", str, 3) && !strncmp(oc->opts[i]->name, str+3, len-3)) { - if (strlen(oc->opts[i]->name) == len-3) { - if (oc->opts[i]->count++ && (oc->opts[i]->flags & OPT_SINGLE)) - opt_failure("Option %s appeared the second time.", oc->opts[i]->name); + if (!strncmp("no-", str, 3) && !strncmp(oc->opts[i].name, str+3, len-3)) { + if (strlen(oc->opts[i].name) == len-3) { + if (oc->opts[i].count++ && (oc->opts[i].flags & OPT_SINGLE)) + opt_failure("Option %s appeared the second time.", oc->opts[i].name); - return oc->opts[i]; + return &oc->opts[i]; } if (candidate) - opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, oc->opts[i]->name); + opt_failure("Ambiguous prefix %s: Found matching %s and %s.", str, candidate->name, oc->opts[i].name); else - candidate = oc->opts[i]; + candidate = &oc->opts[i]; } } @@ -449,81 +430,51 @@ static void opt_positional(struct opt_context * oc, char * value) { opt_parse_value(oc, opt, value, 2); } -#define OPT_TRAVERSE_SECTIONS \ - while (item->cls == OPT_CL_SECTION) { \ - if (stk->next) \ - stk = stk->next; \ - else { \ - struct opt_stack * new_stk = alloca(sizeof(*new_stk)); \ - new_stk->prev = stk; \ - stk->next = new_stk; \ - stk = new_stk; \ - } \ - stk->this = item; \ - item = item->u.section->opt; \ - } \ - if (item->cls == OPT_CL_END) { \ - if (!stk->prev) break; \ - item = stk->this; \ - stk = stk->prev; \ - continue; \ +static void opt_count_items(struct opt_context *oc, const struct opt_section *sec) +{ + for (const struct opt_item *item = sec->opt; item->cls != OPT_CL_END; item++) { + if (item->cls == OPT_CL_SECTION) + opt_count_items(oc, item->u.section); + else if (item->cls == OPT_CL_HOOK) { + if (item->flags & OPT_HOOK_BEFORE_ARG) + oc->hooks_before_arg_count++; + else if (item->flags & OPT_HOOK_BEFORE_VALUE) + oc->hooks_before_value_count++; + else if (item->flags & OPT_HOOK_AFTER_VALUE) + oc->hooks_after_value_count++; + else + ASSERT(0); + } else if (item->letter || item->name) { + oc->opt_count++; + if (item->letter > OPT_POSITIONAL_TAIL) + oc->positional_max++; } - -void opt_parse(const struct opt_section * options, char ** argv) { - struct opt_stack { - struct opt_item * this; - struct opt_stack * prev; - struct opt_stack * next; - } * stk = alloca(sizeof(*stk)); - stk->this = NULL; - stk->prev = NULL; - stk->next = NULL; - - struct opt_context * oc = alloca(sizeof(*oc)); - memset(oc, 0, sizeof (*oc)); - - int count = 0; - int hooks = 0; - - for (struct opt_item * item = options->opt; ; item++) { - OPT_TRAVERSE_SECTIONS; - if (item->letter || item->name) - count++; - if (item->cls == OPT_CL_BOOL) - count++; - if (item->letter > 256) - oc->positional_max++; - if (item->cls == OPT_CL_HOOK) - hooks++; } +} - oc->opts = alloca(sizeof(*oc->opts) * count); - oc->shortopt = alloca(sizeof(*oc->shortopt) * (oc->positional_max + 257)); - memset(oc->shortopt, 0, sizeof(*oc->shortopt) * (oc->positional_max + 257)); - oc->hooks_before_arg = alloca(sizeof (*oc->hooks_before_arg) * hooks); - oc->hooks_before_value = alloca(sizeof (*oc->hooks_before_value) * hooks); - oc->hooks_after_value = alloca(sizeof (*oc->hooks_after_value) * hooks); +static void opt_add_default_flags(struct opt_precomputed *opt) +{ + struct opt_item *item = opt->item; + uns flags = opt->flags; - oc->hooks_before_arg_count = 0; - oc->hooks_before_value_count = 0; - oc->hooks_after_value_count = 0; + if (item->letter >= 256) { + flags &= ~OPT_VALUE_FLAGS; + flags |= OPT_REQUIRED_VALUE; + } + if (!(flags & OPT_VALUE_FLAGS)) { + ASSERT(item->cls != OPT_CL_CALL && item->cls != OPT_CL_USER); + flags |= opt_default_value_flags[item->cls]; + } - oc->opt_count = 0; + opt->flags = flags; +} - for (struct opt_item * item = options->opt; ; item++) { - OPT_TRAVERSE_SECTIONS; - if (item->letter || item->name) { - struct opt_precomputed * opt = xmalloc(sizeof(*opt)); - opt->item = item; - opt->flags = item->flags; - opt->count = 0; - opt->name = item->name; - oc->opts[oc->opt_count++] = opt; - if (item->letter) - oc->shortopt[(int) item->letter] = opt; - OPT_ADD_DEFAULT_ITEM_FLAGS(item, opt->flags); - } - if (item->cls == OPT_CL_HOOK) { +static void opt_prepare_items(struct opt_context *oc, const struct opt_section *sec) +{ + for (struct opt_item *item = sec->opt; item->cls != OPT_CL_END; item++) { + if (item->cls == OPT_CL_SECTION) + opt_prepare_items(oc, item->u.section); + else if (item->cls == OPT_CL_HOOK) { if (item->flags & OPT_HOOK_BEFORE_ARG) oc->hooks_before_arg[oc->hooks_before_arg_count++] = item; else if (item->flags & OPT_HOOK_BEFORE_VALUE) @@ -532,8 +483,36 @@ void opt_parse(const struct opt_section * options, char ** argv) { oc->hooks_after_value[oc->hooks_after_value_count++] = item; else ASSERT(0); + } else if (item->letter || item->name) { + struct opt_precomputed * opt = &oc->opts[oc->opt_count++]; + opt->item = item; + opt->flags = item->flags; + opt->count = 0; + opt->name = item->name; + if (item->letter) + oc->shortopt[(int) item->letter] = opt; + opt_add_default_flags(opt); } } +} + +void opt_parse(const struct opt_section * options, char ** argv) { + struct opt_context * oc = alloca(sizeof(*oc)); + memset(oc, 0, sizeof (*oc)); + + opt_count_items(oc, options); + oc->opts = alloca(sizeof(*oc->opts) * oc->opt_count); + oc->shortopt = alloca(sizeof(*oc->shortopt) * (oc->positional_max + 257)); + memset(oc->shortopt, 0, sizeof(*oc->shortopt) * (oc->positional_max + 257)); + oc->hooks_before_arg = alloca(sizeof (*oc->hooks_before_arg) * oc->hooks_before_arg_count); + oc->hooks_before_value = alloca(sizeof (*oc->hooks_before_value) * oc->hooks_before_value_count); + oc->hooks_after_value = alloca(sizeof (*oc->hooks_after_value) * oc->hooks_after_value_count); + + oc->opt_count = 0; + oc->hooks_before_arg_count = 0; + oc->hooks_before_value_count = 0; + oc->hooks_after_value_count = 0; + opt_prepare_items(oc, options); int force_positional = 0; for (int i=0;argv[i];i++) { @@ -570,10 +549,8 @@ void opt_parse(const struct opt_section * options, char ** argv) { } for (int i=0;iopt_count;i++) { - if (!oc->opts[i]) - continue; - if (!oc->opts[i]->count && (oc->opts[i]->flags & OPT_REQUIRED)) - opt_failure("Required option --%s not found.", oc->opts[i]->item->name); + if (!oc->opts[i].count && (oc->opts[i].flags & OPT_REQUIRED)) + opt_failure("Required option --%s not found.", oc->opts[i].item->name); } }