Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] zparseopts -G: accept only '--' as parsing terminator
- X-seq: zsh-workers 53483
- From: dana <dana@xxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: [PATCH] zparseopts -G: accept only '--' as parsing terminator
- Date: Sun, 13 Apr 2025 22:41:18 -0500
- Archived-at: <https://zsh.org/workers/53483>
- Feedback-id: i9be146f9:Fastmail
- List-id: <zsh-workers.zsh.org>
another change to `zparseopts -G` i was sitting on. this is not a bug,
just something i didn't consider before:
normally zparseopts accepts either '-' or '--' to explicitly terminate
argument parsing. although i normally like that feature, it is a
zsh-specific quirk that i think many are unfamiliar with, and since -G
is aiming for better consistency with getopt_long(3) i feel like it's
probably best if it only takes '--'
dana
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
Messages sorted by:
Reverse Date,
Date,
Thread,
Author