From a73c705b0c864a9ce042fca6e72e0c92d4ad8237 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Fri, 16 Dec 2022 23:22:33 +0100 Subject: 51212: remove STOUC() macro This served as a workaround for ancient compilers where casts to unsigned char were broken. --- Src/Modules/zutil.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 2f17c03f1..8a7d0a4c5 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -795,11 +795,11 @@ static char *zformat_substring(char* instr, char **specs, char **outp, if (idigit(*s)) { for (min = 0; idigit(*s); s++) - min = (min * 10) + (int) STOUC(*s) - '0'; + min = (min * 10) + (int) (unsigned char) *s - '0'; } /* Ternary expressions */ - testit = (STOUC(*s) == '('); + testit = ((unsigned char) *s == '('); if (testit && s[1] == '-') { /* Allow %(-1... etc. */ @@ -808,25 +808,25 @@ static char *zformat_substring(char* instr, char **specs, char **outp, } if ((*s == '.' || testit) && idigit(s[1])) { for (max = 0, s++; idigit(*s); s++) - max = (max * 10) + (int) STOUC(*s) - '0'; + max = (max * 10) + (int) (unsigned char) *s - '0'; } else if (*s == '.' || testit) s++; - if (testit && STOUC(*s)) { + if (testit && (unsigned char) *s) { int actval, testval, endcharl; /* Only one number is useful for ternary expressions. */ testval = (min >= 0) ? min : (max >= 0) ? max : 0; - if (specs[STOUC(*s)] && *specs[STOUC(*s)]) { + if (specs[(unsigned char) *s] && *specs[(unsigned char) *s]) { if (presence) { if (testval) #ifdef MULTIBYTE_SUPPORT if (isset(MULTIBYTE)) - actval = MB_METASTRWIDTH(specs[STOUC(*s)]); + actval = MB_METASTRWIDTH(specs[(unsigned char) *s]); else #endif - actval = strlen(specs[STOUC(*s)]); + actval = strlen(specs[(unsigned char) *s]); else actval = 1; actval = right ? (testval < actval) : (testval >= actval); @@ -834,7 +834,7 @@ static char *zformat_substring(char* instr, char **specs, char **outp, if (right) /* put the sign back */ testval *= -1; /* zero means values are equal, i.e. true */ - actval = (int)mathevali(specs[STOUC(*s)]) - testval; + actval = (int) mathevali(specs[(unsigned char) *s]) - testval; } } else actval = presence ? !right : testval; @@ -855,7 +855,7 @@ static char *zformat_substring(char* instr, char **specs, char **outp, return NULL; } else if (skip) { continue; - } else if ((spec = specs[STOUC(*s)])) { + } else if ((spec = specs[(unsigned char) *s])) { int len; if ((len = strlen(spec)) > max && max >= 0) @@ -950,7 +950,7 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) zwarnnam(nam, "invalid argument: %s", *ap); return 1; } - specs[STOUC(ap[0][0])] = ap[0] + 2; + specs[(unsigned char) ap[0][0]] = ap[0] + 2; } out = (char *) zhalloc(olen = 128); @@ -1864,7 +1864,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) d->vals = d->last = NULL; opt_descs = d; if (!o[1]) - sopts[STOUC(*o)] = d; + sopts[(unsigned char) *o] = d; if ((flags & ZOF_MAP) && !map_opt_desc(d)) { zwarnnam(nam, "cyclic option mapping: %s", args[-1]); return 1; @@ -1888,7 +1888,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } if (!(d = lookup_opt(o + 1))) { while (*++o) { - if (!(d = sopts[STOUC(*o)])) { + if (!(d = sopts[(unsigned char) *o])) { if (fail) { if (*o != '-') zwarnnam(nam, "bad option: -%c", *o); -- cgit v1.2.3 From 98a6892cb138a53dc4a265e29e60dbbd813f3d73 Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Thu, 26 Oct 2023 08:27:18 -0700 Subject: 52244: Fix a batch of minor defects reported by Coverity. Coverity defects 1547831, 1547826 (remove unused function), 1521551, 1500752, 1500747, 1401549, 1372423, 1270645, 1255799, 1255792, 1255789, 1255787, 1255782, 1255750 --- ChangeLog | 9 +++++++++ Src/Modules/zutil.c | 6 +++--- Src/Zle/compcore.c | 5 +++-- Src/Zle/compresult.c | 12 ++++-------- Src/builtin.c | 4 +++- Src/glob.c | 3 ++- Src/hist.c | 15 ++++++++++----- Src/input.c | 12 ------------ Src/params.c | 5 ++--- Src/utils.c | 4 ++-- 10 files changed, 38 insertions(+), 37 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index c3d68a6a2..ebfd2731f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2023-10-25 Bart Schaefer + + * 52244: Src/Modules/zutil.c, Src/Zle/compcore.c, + Src/Zle/compresult.c, Src/builtin.c, Src/glob.c, Src/hist.c, + Src/input.c, Src/params.c, Src/utils.c: Coverity defects 1547831, + 1547826 (remove unused function), 1521551, 1500752, 1500747, + 1401549, 1372423, 1270645, 1255799, 1255792, 1255789, 1255787, + 1255782, 1255750 + 2023-10-24 Matthew Martin * github #103: Christian Heusel: Completion/Unix/Command/_zfs: fix diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 8a7d0a4c5..8b863d5c8 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1378,11 +1378,11 @@ rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp) "zregexparse-guard"), !lastval))) { LinkNode aln; char **mend; - int len; + int len = 0; queue_signals(); - mend = getaparam("mend"); - len = atoi(mend[0]); + if ((mend = getaparam("mend"))) + len = atoi(mend[0]); unqueue_signals(); for (i = len; i; i--) diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c index 77fce66e8..9b87cad93 100644 --- a/Src/Zle/compcore.c +++ b/Src/Zle/compcore.c @@ -2249,8 +2249,9 @@ addmatches(Cadata dat, char **argv) llpl = strlen(lpre); llsl = strlen(lsuf); - if (llpl + (int)strlen(compqiprefix) + (int)strlen(lipre) != origlpre - || llsl + (int)strlen(compqisuffix) + (int)strlen(lisuf) != origlsuf) + /* This used to reference compqiprefix and compqisuffix, why? */ + if (llpl + (int)strlen(qipre) + (int)strlen(lipre) != origlpre + || llsl + (int)strlen(qisuf) + (int)strlen(lisuf) != origlsuf) lenchanged = 1; /* Test if there is an existing -P prefix. */ diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index 57789c0f3..cd8c7dd64 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -897,7 +897,7 @@ void do_allmatches(UNUSED(int end)) { int first = 1, nm = nmatches - 1, omc = menucmp, oma = menuacc, e; - Cmatch *mc; + Cmatch *mc = 0; struct menuinfo mi; char *p = (brbeg ? ztrdup(lastbrbeg->str) : NULL); @@ -915,10 +915,10 @@ do_allmatches(UNUSED(int end)) #endif } + if (minfo.group) + mc = (minfo.group)->matches; - mc = (minfo.group)->matches; - - while (1) { + while (mc) { if (!((*mc)->flags & CMF_ALL)) { if (!first) accept_last(); @@ -1731,8 +1731,6 @@ calclist(int showall) width < zterm_columns && nth < g->dcount; nth++, tcol++) { - m = *p; - if (tcol == tcols) { tcol = 0; tlines++; @@ -1994,7 +1992,6 @@ printlist(int over, CLPrintFunc printm, int showall) (listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) { if (pnl) { putc('\n', shout); - pnl = 0; ml++; if (cl >= 0 && --cl <= 1) { cl = -1; @@ -2087,7 +2084,6 @@ printlist(int over, CLPrintFunc printm, int showall) (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) { if (pnl) { putc('\n', shout); - pnl = 0; ml++; if (cl >= 0 && --cl <= 1) { cl = -1; diff --git a/Src/builtin.c b/Src/builtin.c index 31af66c7c..9e08a1dbc 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -6508,6 +6508,7 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) if (OPT_ISSET(ops,'s') && SHTTY == readfd) { struct ttyinfo ti; + memset(&ti, 0, sizeof(struct ttyinfo)); gettyinfo(&ti); saveti = ti; resettty = 1; @@ -6606,7 +6607,8 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func)) else if (resettty && SHTTY != -1) settyinfo(&saveti); if (haso) { - fclose(shout); + if (shout) + fclose(shout); shout = oshout; SHTTY = -1; } diff --git a/Src/glob.c b/Src/glob.c index 63f8a5fa7..bd199ace3 100644 --- a/Src/glob.c +++ b/Src/glob.c @@ -1317,7 +1317,8 @@ zglob(LinkList list, LinkNode np, int nountok) sense = 0; if (qualct) { qn = (struct qual *)hcalloc(sizeof *qn); - qo->or = qn; + if (qo) + qo->or = qn; qo = qn; qualorct++; qualct = 0; diff --git a/Src/hist.c b/Src/hist.c index bfbcd6ede..448dfddbc 100644 --- a/Src/hist.c +++ b/Src/hist.c @@ -1359,7 +1359,8 @@ putoldhistentryontop(short keep_going) do { if (max_unique_ct-- <= 0 || he == hist_ring) { max_unique_ct = 0; - he = hist_ring->down; + if (hist_ring) + he = hist_ring->down; next = hist_ring; break; } @@ -1367,12 +1368,16 @@ putoldhistentryontop(short keep_going) next = he->down; } while (!(he->node.flags & HIST_DUP)); } - if (he != hist_ring->down) { + /* Is it really possible for hist_ring to be NULL here? */ + if (he && (!hist_ring || he != hist_ring->down)) { he->up->down = he->down; he->down->up = he->up; he->up = hist_ring; - he->down = hist_ring->down; - hist_ring->down = he->down->up = he; + if (hist_ring) { + he->down = hist_ring->down; + hist_ring->down = he; + } + he->down->up = he; } hist_ring = he; } @@ -1468,7 +1473,7 @@ should_ignore_line(Eprog prog) mod_export int hend(Eprog prog) { - int flag, hookret, stack_pos = histsave_stack_pos; + int flag, hookret = 0, stack_pos = histsave_stack_pos; /* * save: * 0: don't save diff --git a/Src/input.c b/Src/input.c index dd8f2edc7..d8ac2c0e7 100644 --- a/Src/input.c +++ b/Src/input.c @@ -643,18 +643,6 @@ zstuff(char **out, const char *fn) return len; } -/**/ -char * -ztuff(const char *fn) -{ - char *buf; - off_t len = zstuff(&buf, fn); - if (len > 0) - return buf; - else - return NULL; -} - /* stuff a whole file into the input queue and print it */ /**/ diff --git a/Src/params.c b/Src/params.c index 957656e3f..9f0cbcd67 100644 --- a/Src/params.c +++ b/Src/params.c @@ -6326,10 +6326,9 @@ mod_export Param upscope(Param pm, int reflevel) { Param up = pm->old; - while (pm && up && up->level >= reflevel) { + while (up && up->level >= reflevel) { pm = up; - if (up) - up = up->old; + up = up->old; } return pm; } diff --git a/Src/utils.c b/Src/utils.c index 790625379..0f66984cd 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -7523,8 +7523,8 @@ restoredir(struct dirsav *d) else if (d->level < 0) err = -1; if (d->dev || d->ino) { - stat(".", &sbuf); - if (sbuf.st_ino != d->ino || sbuf.st_dev != d->dev) + if (stat(".", &sbuf) < 0 || + sbuf.st_ino != d->ino || sbuf.st_dev != d->dev) err = -2; } return err; -- cgit v1.2.3 From c72b4a74ef3e5031a72cab13d7d6365e8d7ef0fc Mon Sep 17 00:00:00 2001 From: Bart Schaefer Date: Wed, 24 Jan 2024 17:32:45 -0800 Subject: 52473: zstyle -q for testing existence of a zstyle setting --- ChangeLog | 2 ++ Doc/Zsh/mod_zutil.yo | 7 +++++++ Src/Modules/zutil.c | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index b64c62830..7b30da246 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2024-01-24 Bart Schaefer + * 52473: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c: zstyle -q + * 52468: Src/builtin.c, Src/utils.c: save and restore state of correct TTY when using read -s / -d diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 3cf9e5028..9946618d6 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -11,6 +11,7 @@ xitem(tt(zstyle) [ tt(-L) [ var(metapattern) [ var(style) ] ] ]) xitem(tt(zstyle) [ tt(-e) | tt(-) | tt(-)tt(-) ] var(pattern) var(style) var(string) ...) xitem(tt(zstyle -d) [ var(pattern) [ var(style) ... ] ]) xitem(tt(zstyle -g) var(name) [ var(pattern) [ var(style) ] ]) +xitem(tt(zstyle -q) var(context) var(style)) xitem(tt(zstyle -){tt(a)|tt(b)|tt(s)} var(context) var(style) var(name) [ var(sep) ]) xitem(tt(zstyle -){tt(T)|tt(t)} var(context) var(style) [ var(string) ... ]) item(tt(zstyle -m) var(context) var(style) var(pattern))( @@ -105,6 +106,12 @@ enditem() The other forms can be used to look up or test styles for a given context. startitem() +item(tt(zstyle -q) var(context) var(style))( +Return tt(0) if var(style) is defined in var(context). This does not +evaluate expressions defined by tt(zstyle -e) and does not examine any +values set by var(style). The expected use is to test whether a style +has been defined for var(context) before asserting a new style. +) item(tt(zstyle -s) var(context) var(style) var(name) [ var(sep) ])( The parameter var(name) is set to the value of the style interpreted as a string. If the value contains several strings they are concatenated with diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 8b863d5c8..293a62dcf 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -461,6 +461,28 @@ lookupstyle(char *ctxt, char *style) return found; } +static int +testforstyle(char *ctxt, char *style) +{ + Style s; + Stypat p; + int found = 0; + + s = (Style)zstyletab->getnode2(zstyletab, style); + if (s) { + MatchData match; + savematch(&match); + for (p = s->pats; p; p = p->next) + if (pattry(p->prog, ctxt)) { + found = 1; + break; + } + restorematch(&match); + } + + return !found; /* 0 == success */ +} + static int bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { @@ -570,6 +592,7 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) case 't': min = 2; max = -1; break; case 'T': min = 2; max = -1; break; case 'm': min = 3; max = 3; break; + case 'q': min = 2; max = 2; break; case 'g': min = 1; max = 3; break; default: zwarnnam(nam, "invalid option: %s", args[0]); @@ -723,6 +746,15 @@ bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } break; + case 'q': + { + int success; + queue_signals(); /* Protect PAT_STATIC */ + success = testforstyle(args[1], args[2]); + unqueue_signals(); + return success; + } + break; case 'g': { int ret = 1; -- cgit v1.2.3 From 8e622c25b24fb0b0d6e705fab97960351e123c65 Mon Sep 17 00:00:00 2001 From: Oliver Kiddle Date: Mon, 22 Jan 2024 23:19:23 +0100 Subject: unposted: remove unused variable to silence compiler warning --- ChangeLog | 3 +++ Src/Modules/zutil.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index c85715ef3..240fb0581 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2024-01-28 Oliver Kiddle + * unposted: Src/Modules/zutil.c: remove unused variable to silence + compiler warning + * Jörg Sommer: 52442: Src/zsh.h: Mark hookdef.name as const * Jörg Sommer: 52444: Src/module.c: Mark name argument of some diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 293a62dcf..5eccea7a9 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -997,7 +997,7 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) case 'a': { char **ap, *cp; - int nbc = 0, colon = 0, pre = 0, suf = 0; + int nbc = 0, pre = 0, suf = 0; #ifdef MULTIBYTE_SUPPORT int prechars = 0; #endif /* MULTIBYTE_SUPPORT */ @@ -1012,7 +1012,6 @@ bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) int dchars = 0; #endif /* MULTIBYTE_SUPPORT */ - colon++; if ((d = cp - *ap - nbc) > pre) pre = d; #ifdef MULTIBYTE_SUPPORT -- cgit v1.2.3 From d051857e03d474bf7a122148f323bd90d8c16b36 Mon Sep 17 00:00:00 2001 From: dana Date: Thu, 26 Dec 2024 09:39:11 -0600 Subject: 53260: zparseopts: add options -v (argv) and -G (GNU-style parsing) --- ChangeLog | 3 + Doc/Zsh/mod_zutil.yo | 44 ++++++++++-- Src/Modules/zutil.c | 116 +++++++++++++++++++++++++------ Test/V12zparseopts.ztst | 181 ++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 313 insertions(+), 31 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index 989cc0aa3..9a40cae5e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2024-12-26 dana + * 53260: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: add -v and -G options to zparseopts + * 53257: Doc/Zsh/params.yo, Doc/Zsh/prompt.yo, Src/Modules/zftp.c, Src/Modules/zprof.c, Src/compat.c, Src/exec.c, Src/hist.c, Src/init.c, Src/jobs.c, Src/params.c, diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 9946618d6..76907352f 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -228,7 +228,7 @@ item(tt(zregexparse))( This implements some internals of the tt(_regex_arguments) function. ) findex(zparseopts) -item(tt(zparseopts) [ tt(-D) tt(-E) tt(-F) tt(-K) tt(-M) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ tt(-) ] var(spec) ...)( +item(tt(zparseopts) [ tt(-D) tt(-E) tt(-F) tt(-G) tt(-K) tt(-M) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ tt(-v) var(argv) ] [ tt(-) ] var(spec) ...)( This builtin simplifies the parsing of options in positional parameters, i.e. the set of arguments given by tt($*). Each var(spec) describes one option and must be of the form `var(opt)[tt(=)var(array)]'. If an option @@ -282,19 +282,19 @@ first colon. ) enditem() -In all cases, option-arguments must appear either immediately following the +By default, option-arguments may appear either immediately following the option in the same positional parameter or in the next one. Even an optional argument may appear in the next parameter, unless it begins with a `tt(-)'. -There is no special handling of `tt(=)' as with GNU-style argument parsers; -given the var(spec) `tt(-foo:)', the positional parameter `tt(-)tt(-foo=bar)' -is parsed as `tt(-)tt(-foo)' with an argument of `tt(=bar)'. +Additionally, there is no special consideration given to an `tt(=)' +between an option and its argument. To make parsing use the more common +GNU-style conventions, use the tt(-G) option. When the names of two options that take no arguments overlap, the longest one wins, so that parsing for the var(spec)s `tt(-foo -foobar)' (for example) is unambiguous. However, due to the aforementioned handling of option-arguments, ambiguities may arise when at least one overlapping var(spec) takes an argument, as in `tt(-foo: -foobar)'. In that case, the last matching -var(spec) wins. +var(spec) wins. (This is not an issue with GNU-style parsing.) The options of tt(zparseopts) itself cannot be stacked because, for example, the stack `tt(-DEK)' is indistinguishable from a var(spec) for @@ -338,6 +338,33 @@ Note that the appearance in the positional parameters of an option without its required argument always aborts parsing and returns an error as described above regardless of whether this option is used. ) +item(tt(-G))( +This option specifies that options are parsed in the GNU style, +similar to tt(getopt_long+LPAR()3+RPAR()). In particular: + +Given the var(spec) `tt(-foo:)', the positional parameter +`tt(-)tt(-foo=bar)' is interpreted as option `tt(-)tt(-foo)' with +argument `tt(bar)', rather than argument `tt(=bar)' as is the default, +whilst the positional parameter `tt(-)tt(-foobar)' is considered an +unknown option (unless another var(spec) describes it). This applies +to both singly and doubly hyphenated long options. + +An empty option-argument can be given to its long option in the same +parameter using a trailing `tt(=)'. + +An optional argument to a long option must be given with the +equals syntax, and an optional argument to a short option must +follow it immediately in the same parameter; in both cases the +following parameter is considered unrelated. + +Whenever a long option and its argument are stored in the same array +element, an `tt(=)' is used to separate them. + +A mandatory option-argument given in a separate parameter from its +option (as in `tt(-)tt(-foo) tt(bar)'), or any option-argument given to +a short option in the same parameter, is always treated the same +regardless of whether this option is in effect. +) item(tt(-K))( With this option, the arrays specified with the tt(-a) option and with the `tt(=)var(array)' forms are kept unchanged when none of the var(spec)s for @@ -355,6 +382,11 @@ is found, the values are stored as usual. This changes only the way the values are stored, not the way tt($*) is parsed, so results may be unpredictable if the `var(name)tt(+)' specifier is used inconsistently. ) +item(tt(-v) var(argv))( +With this option, the elements of the named array var(argv) are used as the +positional parameters to parse, rather than those given by tt($*). The +array may be modified according to the tt(-D) option. +) enditem() For example, diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 5eccea7a9..9b2721a09 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1528,12 +1528,14 @@ struct zoptdesc { Zoptval vals, last; }; -#define ZOF_ARG 1 -#define ZOF_OPT 2 -#define ZOF_MULT 4 -#define ZOF_SAME 8 -#define ZOF_MAP 16 -#define ZOF_CYC 32 +#define ZOF_ARG 1 +#define ZOF_OPT 2 +#define ZOF_MULT 4 +#define ZOF_SAME 8 +#define ZOF_MAP 16 +#define ZOF_CYC 32 +#define ZOF_GNUS 64 +#define ZOF_GNUL 128 struct zoptarr { Zoptarr next; @@ -1568,9 +1570,29 @@ static Zoptdesc lookup_opt(char *str) { Zoptdesc p; - for (p = opt_descs; p; p = p->next) { - if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str)) + /* + * Option takes argument, with GNU-style handling of =. This should only + * be set for long options, though we don't care about that here. Unlike + * the default behaviour, matching is unambiguous + */ + if (p->flags & ZOF_GNUL) { + if (!strcmp(p->name, str) || /* Inefficient, whatever */ + (strpfx(p->name, str) && str[strlen(p->name)] == '=')) + return p; + /* + * Option takes argument, default 'cuddled' style. This is weird with + * long options because we naively accept whatever option has a prefix + * match for the given parameter. Thus if you have specs `-foo:` and + * `-foobar:` (or even `-foobar` with no optarg), without the GNU + * setting, the behaviour depends on the order in which they were + * defined. It is documented to work this way though + */ + } else if (p->flags & ZOF_ARG) { + if (strpfx(p->name, str)) + return p; + /* Option takes no argument */ + } else if (!strcmp(p->name, str)) return p; } return NULL; @@ -1641,10 +1663,13 @@ add_opt_val(Zoptdesc d, char *arg) if (d->arr) d->arr->num += (arg ? 2 : 1); } else if (arg) { - char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2); + /* 3 here is '-' + '=' + NUL */ + char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 3); *s = '-'; strcpy(s + 1, d->name); + if (d->flags & ZOF_GNUL) + strcat(s, "="); strcat(s, arg); v->str = s; if (d->arr) @@ -1713,7 +1738,8 @@ static int bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; - int del = 0, flags = 0, extract = 0, fail = 0, keep = 0; + char *paramsname = NULL, **params; + int del = 0, flags = 0, extract = 0, fail = 0, gnu = 0, keep = 0; Zoptdesc sopts[256], d; Zoptarr a, defarr = NULL; Zoptval v; @@ -1758,6 +1784,14 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } fail = 1; break; + case 'G': + if (o[2]) { + args--; + o = NULL; + break; + } + gnu = 1; + break; case 'K': if (o[2]) { args--; @@ -1808,6 +1842,20 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } break; + case 'v': + if (paramsname) { + zwarnnam(nam, "argv array given more than once"); + return 1; + } + if (o[2]) + paramsname = o + 2; + else if (*args) + paramsname = *args++; + else { + zwarnnam(nam, "missing array name"); + return 1; + } + break; default: /* Anything else is an option description */ args--; @@ -1849,6 +1897,9 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) if (*p == ':') { f |= ZOF_ARG; *p = '\0'; + if (gnu) { + f |= o[1] ? ZOF_GNUL : ZOF_GNUS; + } if (*++p == ':') { p++; f |= ZOF_OPT; @@ -1901,8 +1952,10 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) return 1; } } - np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams); + params = getaparam((paramsname = paramsname ? paramsname : "argv")); + np = cp = pp = ((extract && del) ? arrdup(params) : params); for (; (o = *pp); pp++) { + /* Not an option */ if (*o != '-') { if (extract) { if (del) @@ -1911,6 +1964,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } else break; } + /* '-' or '--', end parsing */ if (!o[1] || (o[1] == '-' && !o[2])) { if (del && extract) *cp++ = o; @@ -1918,6 +1972,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) break; } if (!(d = lookup_opt(o + 1))) { + /* No match for whole param, try each character as a short option */ while (*++o) { if (!(d = sopts[(unsigned char) *o])) { if (fail) { @@ -1931,19 +1986,27 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) break; } if (d->flags & ZOF_ARG) { + /* Optarg in same parameter */ if (o[1]) { add_opt_val(d, o + 1); break; + /* + * Mandatory optarg or (if not GNU style) optional optarg in + * next parameter + */ } else if (!(d->flags & ZOF_OPT) || - (pp[1] && pp[1][0] != '-')) { + (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && + pp[1] && pp[1][0] != '-')) { if (!pp[1]) { zwarnnam(nam, "missing argument for option: -%s", d->name); return 1; } add_opt_val(d, *++pp); + /* Missing optional optarg */ } else add_opt_val(d, NULL); + /* No optarg required */ } else add_opt_val(d, NULL); } @@ -1956,21 +2019,37 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) break; } } else { + /* Whole param matches a defined option */ if (d->flags & ZOF_ARG) { char *e = o + strlen(d->name) + 1; - if (*e) + /* GNU style allows an empty optarg in the same parameter */ + if ((d->flags & ZOF_GNUL) && *e == '=') { + add_opt_val(d, ++e); + /* + * Non-empty optarg in same parameter. lookup_opt() test ensures + * that this won't be a GNU-style long option, where this would + * be invalid + */ + } else if (*e) { add_opt_val(d, e); - else if (!(d->flags & ZOF_OPT) || - (pp[1] && pp[1][0] != '-')) { + /* + * Mandatory optarg or (if not GNU style) optional optarg in + * next parameter + */ + } else if (!(d->flags & ZOF_OPT) || + (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && + pp[1] && pp[1][0] != '-')) { if (!pp[1]) { zwarnnam(nam, "missing argument for option: -%s", d->name); return 1; } add_opt_val(d, *++pp); + /* Missing optional optarg */ } else add_opt_val(d, NULL); + /* No optarg required */ } else add_opt_val(d, NULL); } @@ -2041,12 +2120,9 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) if (del) { if (extract) { *cp = NULL; - freearray(pparams); - pparams = zarrdup(np); + setaparam(paramsname, zarrdup(np)); } else { - pp = zarrdup(pp); - freearray(pparams); - pparams = pp; + setaparam(paramsname, zarrdup(pp)); } } return 0; diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst index 816e1d041..a2743ea0e 100644 --- a/Test/V12zparseopts.ztst +++ b/Test/V12zparseopts.ztst @@ -103,6 +103,14 @@ 0:zparseopts -M >ret: 0, optv: --aaa bar, opts: --aaa bar, argv: 1 2 3 + () { + local -a optv argvv=( -a -b -c 1 2 3 ) + zparseopts -D -a optv -v argvv - a b c + print -r - ret: $?, optv: $optv, argvv: $argvv, argv: $argv + } -x -y -z 7 8 9 +0:zparseopts -v +>ret: 0, optv: -a -b -c, argvv: 1 2 3, argv: -x -y -z 7 8 9 + () { local -a optv aa ab zparseopts -a optv - a=aa b:=ab c:- z @@ -151,16 +159,35 @@ >ret: 0, optv: -+ -: -= -\, argv: 1 2 3 >ret: 0, optv: --::: foo, argv: 1 2 3 - for specs in '-foo: -foobar' '-foobar -foo:'; do + for specs in \ + '-foo: -foobar' '-foobar -foo:' '-foo: -foobar:' '-foobar: -foo:' + do + () { + local -a optv + zparseopts -a optv -D - $=specs + print -r - ret: $?, optv: $optv, argv: $argv + } --foobar 1 2 3 + done +0:overlapping option specs without -G (scan order) +>ret: 0, optv: --foobar, argv: 1 2 3 +>ret: 0, optv: --foo bar, argv: 1 2 3 +>ret: 0, optv: --foobar 1, argv: 2 3 +>ret: 0, optv: --foo bar, argv: 1 2 3 + + for specs in \ + '-foo: -foobar' '-foobar -foo:' '-foo: -foobar:' '-foobar: -foo:' + do () { local -a optv - zparseopts -a optv - $=specs + zparseopts -a optv -D -G - $=specs print -r - ret: $?, optv: $optv, argv: $argv } --foobar 1 2 3 done -0:overlapping option specs (scan order) ->ret: 0, optv: --foobar, argv: --foobar 1 2 3 ->ret: 0, optv: --foo bar, argv: --foobar 1 2 3 +0:overlapping option specs with -G (scan order) +>ret: 0, optv: --foobar, argv: 1 2 3 +>ret: 0, optv: --foobar, argv: 1 2 3 +>ret: 0, optv: --foobar 1, argv: 2 3 +>ret: 0, optv: --foobar 1, argv: 2 3 () { local -a optv @@ -170,3 +197,147 @@ 0:missing optarg ?(anon):zparseopts:2: missing argument for option: -c >ret: 1, optv: , argv: -ab1 -c + + for spec in -foo: -foo:- -foo::; do + () { + local -a optv + zparseopts -a optv -D -F - $=spec + print -r - ret: $?, optv: $optv, argv: $argv + } --foo=bar 1 2 3 + done +0:zparseopts without -G, =optarg handling +>ret: 0, optv: --foo =bar, argv: 1 2 3 +>ret: 0, optv: --foo=bar, argv: 1 2 3 +>ret: 0, optv: --foo=bar, argv: 1 2 3 + + for spec in -foo: -foo:- -foo::; do + () { + local -a optv + zparseopts -a optv -D -F -G - $=spec + print -r - ret: $?, optv: $optv, argv: $argv + } --foo=bar 1 2 3 + done +0:zparseopts -G, single parameter, with = +>ret: 0, optv: --foo bar, argv: 1 2 3 +>ret: 0, optv: --foo=bar, argv: 1 2 3 +>ret: 0, optv: --foo=bar, argv: 1 2 3 + + for spec in -foo: -foo:- -foo:: ; do + () { + local -a optv + zparseopts -a optv -D -F -G - $=spec + print -r - ret: $?, optv: $optv, argv: $argv + } --foobar 1 2 3 + done +0:zparseopts -G, single parameter, without = +?(anon):zparseopts:2: bad option: --foobar +>ret: 1, optv: , argv: --foobar 1 2 3 +?(anon):zparseopts:2: bad option: --foobar +>ret: 1, optv: , argv: --foobar 1 2 3 +?(anon):zparseopts:2: bad option: --foobar +>ret: 1, optv: , argv: --foobar 1 2 3 + + for spec in -foo: -foo:- -foo::; do + () { + local -a optv + zparseopts -a optv -D -F -G - $=spec + print -r - ret: $?, optv: $optv, argv: $argv + } --foo bar 1 2 3 + done +0:zparseopts -G, separate parameters +>ret: 0, optv: --foo bar, argv: 1 2 3 +>ret: 0, optv: --foo=bar, argv: 1 2 3 +>ret: 0, optv: --foo, argv: bar 1 2 3 + + for spec in -foo: -foo:- -foo::; do + () { + local -a optv + zparseopts -a optv -D -F -G - $=spec + print -r - ret: $?, optv: ${(j< >)${(q+)optv}}, argv: $argv + } --foo= 1 2 3 + done +0:zparseopts -G, empty optarg +>ret: 0, optv: --foo '', argv: 1 2 3 +>ret: 0, optv: '--foo=', argv: 1 2 3 +>ret: 0, optv: '--foo=', argv: 1 2 3 + + for gopt in '' -G; do + for spec args in \ + f: '-fbar 1 2 3' \ + f: '-f=bar 1 2 3' \ + f: '-f bar 1 2 3' \ + f:- '-fbar 1 2 3' \ + f:- '-f=bar 1 2 3' \ + f:- '-f bar 1 2 3' \ + f:: '-fbar 1 2 3' \ + f:: '-f=bar 1 2 3' \ + f:: '-f bar 1 2 3' + do + () { + local -a optv + zparseopts -a optv -D -F $gopt - $=spec + print -r - ret: $?, gopt: $gopt, optv: $optv, argv: $argv + } $=args + done + done +0:short options, with and without -G +>ret: 0, gopt: , optv: -f bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -f =bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -f bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: , optv: -f=bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: , optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: , optv: -f=bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f =bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f=bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -fbar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f=bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -f, argv: bar 1 2 3 + + for gopt in '' -G; do + for spec args in \ + foo: '-foobar 1 2 3' \ + foo: '-foo=bar 1 2 3' \ + foo: '-foo bar 1 2 3' \ + foo:- '-foobar 1 2 3' \ + foo:- '-foo=bar 1 2 3' \ + foo:- '-foo bar 1 2 3' \ + foo:: '-foobar 1 2 3' \ + foo:: '-foo=bar 1 2 3' \ + foo:: '-foo bar 1 2 3' + do + () { + local -a optv + zparseopts -a optv -D -F $gopt - $=spec + print -r - ret: $?, gopt: $gopt, optv: $optv, argv: $argv + } $=args + done + done +0:Sun-style long options, with and without -G +>ret: 0, gopt: , optv: -foo bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foo =bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foo bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foobar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foo=bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foobar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foobar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foo=bar, argv: 1 2 3 +>ret: 0, gopt: , optv: -foobar, argv: 1 2 3 +?(anon):zparseopts:2: bad option: -f +>ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 +>ret: 0, gopt: -G, optv: -foo bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -foo bar, argv: 1 2 3 +?(anon):zparseopts:2: bad option: -f +>ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 +>ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 +?(anon):zparseopts:2: bad option: -f +>ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 +>ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 +>ret: 0, gopt: -G, optv: -foo, argv: bar 1 2 3 -- cgit v1.2.3 From 494fcd1799d4d2d236d3183de12b0c99ceb83b1c Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 13 Apr 2025 17:15:53 -0500 Subject: 53482: zparseopts -G: always add options with optional args to array with = --- ChangeLog | 6 ++++++ Src/Modules/zutil.c | 6 +++--- Test/V12zparseopts.ztst | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index 4b4913252..39b488e14 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2025-04-19 dana + + * 53482: Src/Modules/zutil.c, + Src/Modules/Test/V12zparseopts.ztst: with `zparseopts -G`, + always add options options with optional args to array with = + 2025-04-15 Bart Schaefer * 53454: Src/hist.c: fix interrupt handling in savehistfile() diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 9b2721a09..ef99303d2 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1662,15 +1662,15 @@ add_opt_val(Zoptdesc d, char *arg) v->str = NULL; if (d->arr) d->arr->num += (arg ? 2 : 1); - } else if (arg) { + } else if (arg || d->flags & ZOF_GNUL) { /* 3 here is '-' + '=' + NUL */ - char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 3); + char *s = (char *) zhalloc(strlen(d->name) + strlen(arg ? arg : "") + 3); *s = '-'; strcpy(s + 1, d->name); if (d->flags & ZOF_GNUL) strcat(s, "="); - strcat(s, arg); + strcat(s, arg ? arg : ""); v->str = s; if (d->arr) d->arr->num += 1; diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst index a2743ea0e..e465d0e0c 100644 --- a/Test/V12zparseopts.ztst +++ b/Test/V12zparseopts.ztst @@ -247,7 +247,7 @@ 0:zparseopts -G, separate parameters >ret: 0, optv: --foo bar, argv: 1 2 3 >ret: 0, optv: --foo=bar, argv: 1 2 3 ->ret: 0, optv: --foo, argv: bar 1 2 3 +>ret: 0, optv: --foo=, argv: bar 1 2 3 for spec in -foo: -foo:- -foo::; do () { @@ -340,4 +340,4 @@ ?(anon):zparseopts:2: bad option: -f >ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 >ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 ->ret: 0, gopt: -G, optv: -foo, argv: bar 1 2 3 +>ret: 0, gopt: -G, optv: -foo=, argv: bar 1 2 3 -- cgit v1.2.3 From 8c3c45732131433645686cdb6bbbb8974230c5a9 Mon Sep 17 00:00:00 2001 From: dana Date: Sun, 13 Apr 2025 18:00:54 -0500 Subject: 53483: zparseopts -G: accept only '--' as parsing terminator --- ChangeLog | 4 ++++ Doc/Zsh/mod_zutil.yo | 14 +++++++++----- Src/Modules/zutil.c | 6 +++--- Test/V12zparseopts.ztst | 25 +++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 8 deletions(-) (limited to 'Src/Modules/zutil.c') diff --git a/ChangeLog b/ChangeLog index 39b488e14..73127d0f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2025-04-19 dana + * 53483: Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: with `zparseopts -G`, accept only + '--' as parsing terminator + * 53482: Src/Modules/zutil.c, Src/Modules/Test/V12zparseopts.ztst: with `zparseopts -G`, always add options options with optional args to array with = diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 76907352f..19f9989f4 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -242,8 +242,8 @@ Note that it is an error to give any var(spec) without an Unless the tt(-E) option is given, parsing stops at the first string that isn't described by one of the var(spec)s. Even with tt(-E), -parsing always stops at a positional parameter equal to `tt(-)' or -`tt(-)tt(-)'. See also tt(-F). +parsing always stops at a positional parameter equal to `tt(-)tt(-)' or +(without tt(-G)) `tt(-)'. See also tt(-F). The var(opt) description must be one of the following. Any of the special characters can appear in the option name provided it is preceded by a @@ -314,9 +314,9 @@ as the values. item(tt(-D))( If this option is given, all options found are removed from the positional parameters of the calling shell or shell function, up to but not including -any not described by the var(spec)s. If the first such parameter is `tt(-)' -or `tt(-)tt(-)', it is removed as well. This is similar to using the -tt(shift) builtin. +any not described by the var(spec)s. If the first such parameter is +`tt(-)tt(-)' or (without tt(-G)) `tt(-)', it is removed as well. This is +similar to using the tt(shift) builtin. ) item(tt(-E))( This changes the parsing rules to em(not) stop at the first string @@ -364,6 +364,10 @@ A mandatory option-argument given in a separate parameter from its option (as in `tt(-)tt(-foo) tt(bar)'), or any option-argument given to a short option in the same parameter, is always treated the same regardless of whether this option is in effect. + +Lastly, when this option is active, only `tt(-)tt(-)' is treated as an +explicit option-parsing terminator in the parsed arguments; a single +`tt(-)' is considered a normal operand. ) item(tt(-K))( With this option, the arrays specified with the tt(-a) option and with the diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index ef99303d2..676fe1872 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1955,8 +1955,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) params = getaparam((paramsname = paramsname ? paramsname : "argv")); np = cp = pp = ((extract && del) ? arrdup(params) : params); for (; (o = *pp); pp++) { - /* Not an option */ - if (*o != '-') { + /* Not an option. With GNU style, this includes '-' */ + if (*o != '-' || (gnu && !o[1])) { if (extract) { if (del) *cp++ = o; @@ -1964,7 +1964,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } else break; } - /* '-' or '--', end parsing */ + /* '--' or (with non-GNU style, see above) '-', end parsing */ if (!o[1] || (o[1] == '-' && !o[2])) { if (del && extract) *cp++ = o; diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst index e465d0e0c..e6139ea5e 100644 --- a/Test/V12zparseopts.ztst +++ b/Test/V12zparseopts.ztst @@ -341,3 +341,28 @@ >ret: 1, gopt: -G, optv: , argv: -foobar 1 2 3 >ret: 0, gopt: -G, optv: -foo=bar, argv: 1 2 3 >ret: 0, gopt: -G, optv: -foo=, argv: bar 1 2 3 + + for term in - --; do + # With -D -E -G + () { + local -a optv + zparseopts -a optv -D -E -F -G - -foo -bar + print -r - ret: $?, term: $term, optv: $optv, argv: $argv + } --foo x --bar $term --baz + for gopt in '' -G; do + # With -D + with/without -G + () { + local -a optv + zparseopts -a optv -D -F $gopt - -foo -bar + print -r - ret: $?, term: $term, gopt: $gopt, optv: $optv, argv: $argv + } --foo $term --bar + done + done +0:only -- acts as explicit parsing terminator with -G +?(anon):zparseopts:2: bad option: --baz +>ret: 1, term: -, optv: , argv: --foo x --bar - --baz +>ret: 0, term: -, gopt: , optv: --foo, argv: --bar +>ret: 0, term: -, gopt: -G, optv: --foo, argv: - --bar +>ret: 0, term: --, optv: --foo --bar, argv: x -- --baz +>ret: 0, term: --, gopt: , optv: --foo, argv: --bar +>ret: 0, term: --, gopt: -G, optv: --foo, argv: --bar -- cgit v1.2.3