From b63778e00f529b6e32d3cbd3b2700cef0f690d5f Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sat, 21 May 2022 22:59:50 -0500 Subject: [PATCH] Accept unambiguous --longopt abbreviations. --- lib/args.c | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/lib/args.c b/lib/args.c index ce748948..36745148 100644 --- a/lib/args.c +++ b/lib/args.c @@ -386,7 +386,7 @@ void get_optflags(void) struct getoptflagstate gof; struct opts *catch; unsigned long long saveflags; - char *letters[]={"s",""}; + char *letters[]={"s",""}, *ss; // Option parsing is a two stage process: parse the option string into // a struct opts list, then use that list to process argv[]; @@ -419,6 +419,8 @@ void get_optflags(void) gof.arg++; if (*gof.arg=='-') { struct longopts *lo; + struct arg_list *al = 0, *al2; + int ii; gof.arg++; // Handle -- @@ -427,22 +429,42 @@ void get_optflags(void) continue; } - // do we match a known --longopt? + // unambiguously match the start of a known --longopt? check_help(toys.argv+gof.argc); for (lo = gof.longopts; lo; lo = lo->next) { - if (!strncmp(gof.arg, lo->str, lo->len)) { - if (!gof.arg[lo->len]) gof.arg = 0; - else if (gof.arg[lo->len] == '=' && lo->opt->type) - gof.arg += lo->len; - else continue; - // It's a match. - catch = lo->opt; - break; + for (ii = 0; iilen; ii++) if (gof.arg[ii] != lo->str[ii]) break; + if (!gof.arg[ii] || (gof.arg[ii]=='=' && lo->opt->type)) { + al2 = xmalloc(sizeof(struct arg_list)); + al2->next = al; + al2->arg = (void *)lo; + al = al2; + + // Exact match is unambigous even when longer options available + if (ii==lo->len) { + llist_traverse(al, free); + al = 0; + + break; + } } } - + // How many matches? + if (al) { + *libbuf = 0; + if (al->next) for (ss = libbuf, al2 = al; al2; al2 = al2->next) { + lo = (void *)al2->arg; + ss += sprintf(ss, " %.*s"+(al2==al), lo->len, lo->str); + } else lo = (void *)al->arg; + llist_traverse(al, free); + if (*libbuf) error_exit("bad --%s (%s)", gof.arg, libbuf); + } + // One unambiguous match? + if (lo) { + catch = lo->opt; + if (!gof.arg[lo->len]) gof.arg = 0; + else gof.arg += lo->len; // Should we handle this --longopt as a non-option argument? - if (!lo && gof.noerror) { + } else if (gof.noerror) { gof.arg -= 2; goto notflag; } -- 2.39.2