Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] zparseopts: add options -v (argv) and -G (GNU-style parsing)



On Thu 19 Dec 2024, at 08:15, dana wrote:
> for legacy's sake, singly hyphenated long options like -foo are
> still handled the same as short ones, but i can change those too if
> people want

changed my mind about this already. if there's going to be an option for
gnu-style parsing i guess it should be fully gnu-style instead of a
weird hybrid. below patches replace the ones in my previous e-mail. the
-v part is the same. the -G part makes it so that singly and doubly
hyphenated long options are treated the same way, and so that optional
arguments to short options are handled in the posix / getopt_long()
fashion (they must appear in the same parameter)

dana


diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index 9946618d6..80ce78ff0 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(-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
@@ -355,6 +355,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..fa9144a84 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -1713,6 +1713,7 @@ 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;
+    char *paramsname = NULL, **params;
     int del = 0, flags = 0, extract = 0, fail = 0, keep = 0;
     Zoptdesc sopts[256], d;
     Zoptarr a, defarr = NULL;
@@ -1808,6 +1809,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--;
@@ -1901,7 +1916,8 @@ 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++) {
 	if (*o != '-') {
 	    if (extract) {
@@ -2041,12 +2057,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..fa82a9d0b 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


diff --git a/Doc/Zsh/mod_zutil.yo b/Doc/Zsh/mod_zutil.yo
index 80ce78ff0..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(-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(-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
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index fa9144a84..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)
@@ -1714,7 +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;
-    int del = 0, flags = 0, extract = 0, fail = 0, keep = 0;
+    int del = 0, flags = 0, extract = 0, fail = 0, gnu = 0, keep = 0;
     Zoptdesc sopts[256], d;
     Zoptarr a, defarr = NULL;
     Zoptval v;
@@ -1759,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--;
@@ -1864,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;
@@ -1919,6 +1955,7 @@ 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 != '-') {
 	    if (extract) {
 		if (del)
@@ -1927,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;
@@ -1934,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) {
@@ -1947,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);
 	    }
@@ -1972,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);
 	}
diff --git a/Test/V12zparseopts.ztst b/Test/V12zparseopts.ztst
index fa82a9d0b..a2743ea0e 100644
--- a/Test/V12zparseopts.ztst
+++ b/Test/V12zparseopts.ztst
@@ -159,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 - $=specs
+      zparseopts -a optv -D - $=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 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 -D -G - $=specs
+      print -r - ret: $?, optv: $optv, argv: $argv
+    } --foobar 1 2 3
+  done
+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
@@ -178,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




Messages sorted by: Reverse Date, Date, Thread, Author