Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
Re: Replacing getopts with zparseopts
- X-seq: zsh-workers 29312
- From: Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: Re: Replacing getopts with zparseopts
- Date: Tue, 17 May 2011 17:11:25 -0700
- In-reply-to: <110516114446.ZM27388@torch.brasslantern.com>
- List-help: <mailto:zsh-workers-help@zsh.org>
- List-id: Zsh Workers List <zsh-workers.zsh.org>
- List-post: <mailto:zsh-workers@zsh.org>
- Mailing-list: contact zsh-workers-help@xxxxxxx; run by ezmlm
- References: <iqooau$tdf$1@dough.gmane.org> <110515110005.ZM8306@torch.brasslantern.com> <iqp77h$veu$2@dough.gmane.org> <110516114446.ZM27388@torch.brasslantern.com>
[>workers]
On May 16, 11:44am, I wrote:
}
} This might be helpful. With the patch below, one can e.g. do
}
} zparseopts -M d=opt_d -debug=d
}
} and have both the -d and the --debug options stashed in the $opt_d
Hmm, I forgot to mention the more interesting part (shown in the
example I added to mod_zutil.yo): If you combine -M with -A, then
only one field in the associative array is set, and if the "+" spec
is properly applied it collects all arguments of the options:
% set -- -a A -b B -c C
% zparseopts -A opts -M a+:=x b:=c c:=a
% typeset -pm opts x c a
typeset -A opts
opts=(-a ABC )
typeset -a x
x=(-a A -b B -c C)
This eliminates the annoying bit of having to check $opts[(i)a|b|c]
to find out if any one of those synonymous options was used.
I also tweaked the patch to detect loops in the mapping and return
failure with a warning message. Without this, the order of values
in $* affects which descriptions get used, which is confusing.
} There's a remaining buglet here that I haven't decided how
} to handle: Given the above spec, the $d array is also created (or
} reset) but is always empty. The most straightforward fix for this
} would be simply to assert that -M always implies -K.
I came up with a reasonable way to resolve this without needing to
force -M to imply -K.
So here's the new patch for zutils.c (the doc doesn't change). There
currently are no tests for zparseopts -- should we add a whole new
test file V07* or ...?
Index: Src/Modules/zutil.c
===================================================================
diff -c -r1.11 zutil.c
--- Src/Modules/zutil.c 21 Dec 2010 16:41:16 -0000 1.11
+++ Src/Modules/zutil.c 17 May 2011 19:22:30 -0000
@@ -1405,6 +1405,8 @@
#define ZOF_OPT 2
#define ZOF_MULT 4
#define ZOF_SAME 8
+#define ZOF_MAP 16
+#define ZOF_CYC 32
struct zoptarr {
Zoptarr next;
@@ -1459,6 +1461,34 @@
return NULL;
}
+static Zoptdesc
+map_opt_desc(Zoptdesc start)
+{
+ Zoptdesc map = NULL;
+
+ if (!start || !(start->flags & ZOF_MAP))
+ return start;
+
+ map = get_opt_desc(start->arr->name);
+
+ if (!map)
+ return start;
+
+ if (map == start) {
+ start->flags &= ~ZOF_MAP; /* optimize */
+ return start;
+ }
+
+ if (map->flags & ZOF_CYC)
+ return NULL;
+
+ start->flags |= ZOF_CYC;
+ map = map_opt_desc(map);
+ start->flags &= ~ZOF_CYC;
+
+ return map;
+}
+
static void
add_opt_val(Zoptdesc d, char *arg)
{
@@ -1466,6 +1496,10 @@
char *n = dyncat("-", d->name);
int new = 0;
+ Zoptdesc map = map_opt_desc(d);
+ if (map)
+ d = map;
+
if (!(d->flags & ZOF_MULT))
v = d->vals;
if (!v) {
@@ -1513,7 +1547,7 @@
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, f, extract = 0, keep = 0;
+ int del = 0, flags = 0, extract = 0, keep = 0;
Zoptdesc sopts[256], d;
Zoptarr a, defarr = NULL;
Zoptval v;
@@ -1531,6 +1565,7 @@
case '-':
if (o[2])
args--;
+ /* else unreachable, default parsing removes "--" */
o = NULL;
break;
case 'D':
@@ -1557,6 +1592,14 @@
}
keep = 1;
break;
+ case 'M':
+ if (o[2]) {
+ args--;
+ o = NULL;
+ break;
+ }
+ flags |= ZOF_MAP;
+ break;
case 'a':
if (defarr) {
zwarnnam(nam, "default array given more than once");
@@ -1578,6 +1621,10 @@
opt_arrs = defarr;
break;
case 'A':
+ if (assoc) {
+ zwarnnam(nam, "associative array given more than once");
+ return 1;
+ }
if (o[2])
assoc = o + 2;
else if (*args)
@@ -1587,6 +1634,11 @@
return 1;
}
break;
+ default:
+ /* Anything else is an option description */
+ args--;
+ o = NULL;
+ break;
}
if (!o) {
o = "";
@@ -1602,11 +1654,11 @@
return 1;
}
while ((o = dupstring(*args++))) {
+ int f = 0;
if (!*o) {
zwarnnam(nam, "invalid option description: %s", o);
return 1;
}
- f = 0;
for (p = o; *p; p++) {
if (*p == '\\' && p[1])
p++;
@@ -1633,6 +1685,7 @@
a = NULL;
if (*p == '=') {
*p++ = '\0';
+ f |= flags;
if (!(a = get_opt_arr(p))) {
a = (Zoptarr) zhalloc(sizeof(*a));
a->name = p;
@@ -1666,6 +1719,10 @@
opt_descs = d;
if (!o[1])
sopts[STOUC(*o)] = d;
+ if ((flags & ZOF_MAP) && !map_opt_desc(d)) {
+ zwarnnam(nam, "cyclic option mapping: %s", args[-1]);
+ return 1;
+ }
}
np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams);
for (; (o = *pp); pp++) {
@@ -1732,12 +1789,20 @@
add_opt_val(d, NULL);
}
}
+
+ if (flags & ZOF_MAP) {
+ for (d = opt_descs; d; d = d->next)
+ if (d->arr && !d->vals && (d->flags & ZOF_MAP)) {
+ if (d->arr->num == 0 && get_opt_desc(d->arr->name))
+ d->arr->num = -1; /* this is not a real array */
+ }
+ }
if (extract && del)
while (*pp)
*cp++ = *pp++;
for (a = opt_arrs; a; a = a->next) {
- if (!keep || a->num) {
+ if (a->num >= 0 && (!keep || a->num)) {
aval = (char **) zalloc((a->num + 1) * sizeof(char *));
for (ap = aval, v = a->vals; v; ap++, v = v->next) {
if (v->str)
Messages sorted by:
Reverse Date,
Date,
Thread,
Author