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

Re: Replacing getopts with zparseopts



[>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