diff options
| author | dana <dana@dana.is> | 2026-04-19 12:35:02 -0500 |
|---|---|---|
| committer | dana <dana@dana.is> | 2026-04-19 12:36:10 -0500 |
| commit | 90fa3d2816ee3c770966dd42f548d770d266d2bd (patch) | |
| tree | 043524d84eaa407ebd31bf51dfa4819b6c978bc3 | |
| parent | 54181, 54331: remove support for restricted shell (diff) | |
| download | zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar.gz zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar.bz2 zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar.lz zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar.xz zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.tar.zst zsh-90fa3d2816ee3c770966dd42f548d770d266d2bd.zip | |
54361 (tweaked): zparseopts: print friendlier usage errors, add -n option
tweaked to adjust order of options in documentation
| -rw-r--r-- | ChangeLog | 7 | ||||
| -rw-r--r-- | Completion/Zsh/Command/_zparseopts | 1 | ||||
| -rw-r--r-- | Doc/Zsh/mod_zutil.yo | 8 | ||||
| -rw-r--r-- | Src/Modules/zutil.c | 23 | ||||
| -rw-r--r-- | Test/V12zparseopts.ztst | 59 |
5 files changed, 78 insertions, 20 deletions
@@ -1,3 +1,10 @@ +2026-04-19 dana <dana@dana.is> + + * 54361 (tweaked): Completion/Zsh/Command/_zparseopts, + Doc/Zsh/mod_zutil.yo, Src/Modules/zutil.c, + Test/V12zparseopts.ztst: zparseopts: print friendlier usage + errors, add -n option + 2026-04-14 Oliver Kiddle <opk@zsh.org> * 54181, 54331: Completion/Zsh/Command/_set, diff --git a/Completion/Zsh/Command/_zparseopts b/Completion/Zsh/Command/_zparseopts index ae81937c1..cc5e28a9a 100644 --- a/Completion/Zsh/Command/_zparseopts +++ b/Completion/Zsh/Command/_zparseopts @@ -13,6 +13,7 @@ _arguments -A '-*' : \ '-G[enable GNU-style parsing]' \ '-K[preserve contents of arrays/associations when specs are not matched]' \ '-M[enable mapping among equivalent options with opt1=opt2 spec form]' \ + '-n+[specify program name for usage errors]:program name' \ '-v+[specify array from which to parse options]:array:_parameters -g "*array*"' \ '(-)-[end zparseopts options; specs follow]' \ '*: :->spec' \ diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo index 06b953f69..47daec3cb 100644 --- a/Doc/Zsh/mod_zutil.yo +++ b/Doc/Zsh/mod_zutil.yo @@ -230,7 +230,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(-G) tt(-K) tt(-M) ] [ tt(-a) var(array) ] [ tt(-A) var(assoc) ] [ tt(-v) var(argv) ] [ 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(-n) var(name) ] [ 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 @@ -391,6 +391,12 @@ 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(-n) var(name))( +If this option is given, var(name) is used when printing usage errors +intended for the end user. Otherwise, the name of the calling function +or script is used. Error messages arising from misusage of tt(zparseopts) +itself are not affected by this option. +) 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 diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c index 9e1eabcf1..de070a53d 100644 --- a/Src/Modules/zutil.c +++ b/Src/Modules/zutil.c @@ -1739,6 +1739,7 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) { char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np; char *paramsname = NULL, **params; + char *progname = scriptname ? scriptname : (argzero ? argzero : nam); int del = 0, flags = 0, extract = 0, fail = 0, gnu = 0, keep = 0; Zoptdesc sopts[256], d; Zoptarr a, defarr = NULL; @@ -1808,6 +1809,16 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) } flags |= ZOF_MAP; break; + case 'n': + if (o[2]) + progname = o + 2; + else if (*args) + progname = *args++; + else { + zwarnnam(nam, "missing program name"); + return 1; + } + break; case 'a': if (defarr) { zwarnnam(nam, "default array given more than once"); @@ -1981,9 +1992,9 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) if (!(d = sopts[(unsigned char) *o])) { if (fail) { if (*o != '-' || o > *pp + 1) - zwarnnam(nam, "bad option: -%c", *o); + fprintf(stderr, "%s: bad option: -%c\n", progname, *o); else - zwarnnam(nam, "bad option: -%s", o); + fprintf(stderr, "%s: bad option: -%s\n", progname, o); return 1; } o = NULL; @@ -2002,8 +2013,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && pp[1] && pp[1][0] != '-')) { if (!pp[1]) { - zwarnnam(nam, "missing argument for option: -%s", - d->name); + fprintf(stderr, "%s: missing argument for option: -%s\n", + progname, d->name); return 1; } add_opt_val(d, *++pp); @@ -2045,8 +2056,8 @@ bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func)) (!(d->flags & (ZOF_GNUL | ZOF_GNUS)) && pp[1] && pp[1][0] != '-')) { if (!pp[1]) { - zwarnnam(nam, "missing argument for option: -%s", - d->name); + fprintf(stderr, "%s: missing argument for option: -%s\n", + progname, d->name); return 1; } add_opt_val(d, *++pp); diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst index 5736dd3a1..907134230 100644 --- a/Test/V12zparseopts.ztst +++ b/Test/V12zparseopts.ztst @@ -17,6 +17,18 @@ %test + () { zparseopts -F } -x + () { zparseopts -F - } -x + () { zparseopts -F -- } -x + () { zparseopts -F - a } -x + () { zparseopts -F a } -x +1:zparseopts without option specs, without array +?(anon):zparseopts: missing option descriptions +?(anon): bad option: -x +?(anon): bad option: -x +?(anon):zparseopts: no default array defined: a +?(anon):zparseopts: no default array defined: a + () { local -a optv zparseopts -a optv - a b: c:- z @@ -65,15 +77,15 @@ } $=1 done 0:zparseopts -F -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -a -x -z -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -ax -z -?(anon):zparseopts:2: bad option: --x +?(anon): bad option: --x >ret: 1, optv: , argv: -a --x -z -?(anon):zparseopts:2: bad option: -x +?(anon): bad option: -x >ret: 1, optv: , argv: -axy -?(anon):zparseopts:2: bad option: -- +?(anon): bad option: -- >ret: 1, optv: , argv: -a-xy for 1 in '-a 1 2 3' '1 2 3'; do @@ -218,7 +230,7 @@ print -r - ret: $?, optv: $optv, argv: $argv } -ab1 -c 0:missing optarg -?(anon):zparseopts:2: missing argument for option: -c +?(anon): missing argument for option: -c >ret: 1, optv: , argv: -ab1 -c for spec in -foo: -foo:- -foo::; do @@ -253,11 +265,11 @@ } --foobar 1 2 3 done 0:zparseopts -G, single parameter, without = -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 -?(anon):zparseopts:2: bad option: --foobar +?(anon): bad option: --foobar >ret: 1, optv: , argv: --foobar 1 2 3 for spec in -foo: -foo:- -foo::; do @@ -352,15 +364,15 @@ >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 +?(anon): 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 +?(anon): 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 +?(anon): 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 @@ -382,10 +394,31 @@ done done 0:only -- acts as explicit parsing terminator with -G -?(anon):zparseopts:2: bad option: --baz +?(anon): 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 + + fn1() { + zparseopts -F - a + } + fn2() { + local -a optv + zparseopts -a optv -F - a + } + fn3() { + local -a optv + zparseopts -a optv -nprog -F - a + zparseopts -a optv -n prog -F - a + } + fn1 -x + fn2 -x + fn3 -x +1:zparseopts -n, internal vs external usage errors +?fn1:zparseopts:1: no default array defined: a +?fn2: bad option: -x +?prog: bad option: -x +?prog: bad option: -x |
