about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorSven Wischnowsky <wischnow@users.sourceforge.net>2000-05-22 09:28:34 +0000
committerSven Wischnowsky <wischnow@users.sourceforge.net>2000-05-22 09:28:34 +0000
commitce90081ea88b97130f6c6758686711bc21c9ab3a (patch)
tree9c4d6d84612694db7e90c9be9346e28b0b0dd730 /Src
parent007cfdff557515bff99cfa71fe894c04b965ab8a (diff)
downloadzsh-ce90081ea88b97130f6c6758686711bc21c9ab3a.tar.gz
zsh-ce90081ea88b97130f6c6758686711bc21c9ab3a.tar.xz
zsh-ce90081ea88b97130f6c6758686711bc21c9ab3a.zip
pat(-) in long-option patterns to say that argument should be completed only after the `='; merge _arguments and _argument_sets; slightly better test when not to complete options (11489)
Diffstat (limited to 'Src')
-rw-r--r--Src/Zle/computil.c547
1 files changed, 349 insertions, 198 deletions
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 462794b64..fc23b5286 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -293,6 +293,7 @@ typedef struct caarg *Caarg;
 
 struct cadef {
     Cadef next;			/* next in cache */
+    Cadef snext;		/* next set */
     Caopt opts;			/* the options */
     int nopts, ndopts, nodopts;	/* number of options/direct/optional direct */
     Caarg args;			/* the normal arguments */
@@ -304,7 +305,8 @@ struct cadef {
     char *match;		/* -M spec to use */
     int argsactive;		/* if arguments are still allowed */
 				/* used while parsing a command line */
-    char *set;			/* set name, shared */
+    char *set;			/* set name prefix (<name>-), shared */
+    char *sname;		/* set name */
     int flags;			/* see CDF_* below */
 };
 
@@ -399,11 +401,14 @@ freecaargs(Caarg a)
 static void
 freecadef(Cadef d)
 {
-    if (d) {
-	Caopt p, n;
+    Cadef s;
+    Caopt p, n;
 
+    while (d) {
+	s = d->snext;
 	zsfree(d->match);
 	zsfree(d->set);
+	zsfree(d->sname);
 	if (d->defs)
 	    freearray(d->defs);
 
@@ -421,6 +426,7 @@ freecadef(Cadef d)
 	if (d->single)
 	    zfree(d->single, 256 * sizeof(Caopt));
 	zfree(d, sizeof(*d));
+	d = s;
     }
 }
 
@@ -510,25 +516,63 @@ parse_caarg(int mult, int type, int num, int opt, char *oname, char **def,
     return ret;
 }
 
+static Cadef
+alloc_cadef(char **args, int single, char *match, int flags)
+{
+    Cadef ret;
+
+    ret = (Cadef) zalloc(sizeof(*ret));
+    ret->next = ret->snext = NULL;
+    ret->opts = NULL;
+    ret->args = ret->rest = NULL;
+    if (args) {
+	ret->defs = zarrdup(args);
+	ret->ndefs = arrlen(args);
+    } else {
+	ret->defs = NULL;
+	ret->ndefs = 0;
+    }
+    ret->lastt = time(0);
+    ret->set = ret->sname = NULL;
+    if (single) {
+	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
+	memset(ret->single, 0, 256 * sizeof(Caopt));
+    } else
+	ret->single = NULL;
+    ret->match = ztrdup(match);
+    ret->flags = flags;
+
+    return ret;
+}
+
+static void
+set_cadef_opts(Cadef def)
+{
+    Caarg argp;
+    int xnum;
+
+    for (argp = def->args, xnum = 0; argp; argp = argp->next) {
+	if (!argp->direct)
+	    argp->min = argp->num - xnum;
+	if (argp->type == CAA_OPT)
+	    xnum++;
+    }
+}
+
 /* Parse an array of definitions. */
 
 static Cadef
-parse_cadef(char *nam, char **args, int multi)
+parse_cadef(char *nam, char **args)
 {
-    Cadef ret;
+    Cadef all, ret;
     Caopt *optp;
-    Caarg argp;
-    char **oargs = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor;
-    char *adpre, *adsuf, *set = NULL, *doset = NULL;
+    char **oargs = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor, **sargs;
+    char *adpre, *adsuf, *axor = NULL, *doset = NULL, **setp = NULL;
     int single = 0, anum = 1, xnum, nopts, ndopts, nodopts, flags = 0;
+    int state = 0;
 
     nopts = ndopts = nodopts = 0;
 
-    if (multi) {
-	if (!args[1])
-	    return NULL;
-	set = tricat(*args++, "-", "");
-    }
     /* First string is the auto-description definition. */
 
     for (p = args[0]; *p && (p[0] != '%' || p[1] != 'd'); p++);
@@ -582,27 +626,47 @@ parse_cadef(char *nam, char **args, int multi)
 
     /* Looks good. Optimistically allocate the cadef structure. */
 
-    ret = (Cadef) zalloc(sizeof(*ret));
-    ret->next = NULL;
-    ret->opts = NULL;
-    ret->args = ret->rest = NULL;
-    ret->defs = zarrdup(oargs);
-    ret->ndefs = arrlen(oargs);
-    ret->lastt = time(0);
-    ret->set = set;
-    if (single) {
-	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
-	memset(ret->single, 0, 256 * sizeof(Caopt));
-    } else
-	ret->single = NULL;
-    ret->match = ztrdup(match);
-    ret->flags = flags;
+    all = ret = alloc_cadef(oargs, single, match, flags);
+    optp = &(ret->opts);
+    single = flags = 0;
+    anum = 1;
+
+    sargs = args;
 
     /* Get the definitions. */
 
-    for (optp = &(ret->opts); *args; args++) {
-        if (args[0][0] == '-' && !args[0][1]) {
-	    doset = set;
+    for (; *args; args++) {
+        if (args[0][0] == '-' && !args[0][1] && args[1]) {
+	    if (!state) {
+		char *p;
+		int l;
+
+		if (setp)
+		    args = setp;
+		p = *++args;
+		l = strlen(p) - 1;
+		if (*p == '(' && p[l] == ')') {
+		    axor = p = dupstring(p + 1);
+		    p[l - 1] = '\0';
+		} else
+		    axor = NULL;
+		ret->set = doset = tricat(p, "-", "");
+		ret->sname = ztrdup(p);
+		state = 1;
+	    } else {
+		setp = args;
+		state = 0;
+		args = sargs - 1;
+		doset = NULL;
+		ret->nopts = nopts;
+		ret->ndopts = ndopts;
+		ret->nodopts = nodopts;
+		set_cadef_opts(ret);
+		ret = ret->snext = alloc_cadef(NULL, single, NULL, flags);
+		optp = &(ret->opts);
+		single = flags = nopts = ndopts = nodopts = 0;
+		anum = 1;
+	    }
 	    continue;
 	}
 	p = dupstring(*args);
@@ -632,16 +696,25 @@ parse_cadef(char *nam, char **args, int multi)
 	    }
 	    /* Oops, end-of-string. */
 	    if (*p != ')') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
+	    if (doset && axor)
+		xnum++;
 	    xor = (char **) zalloc((xnum + 2) * sizeof(char *));
 	    for (node = firstnode(list), xp = xor; node; incnode(node), xp++)
 		*xp = ztrdup((char *) getdata(node));
+	    if (doset && axor)
+		*xp++ = ztrdup(axor);
 	    xp[0] = xp[1] = NULL;
 
 	    p++;
+	} else if (doset && axor) {
+	    xnum = 1;
+	    xor = (char **) zalloc(3 * sizeof(char *));
+	    xor[0] = ztrdup(axor);
+	    xor[1] = xor[2] = NULL;
 	} else
 	    xor = NULL;
 
@@ -676,7 +749,7 @@ parse_cadef(char *nam, char **args, int multi)
 		    p++;
 	    }
 	    if (!p[1]) {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -713,7 +786,7 @@ parse_cadef(char *nam, char **args, int multi)
 			p++;
 
 		if (!*p) {
-		    freecadef(ret);
+		    freecadef(all);
 		    zwarnnam(nam, "invalid option definition: %s", *args, 0);
 		    return NULL;
 		}
@@ -723,7 +796,7 @@ parse_cadef(char *nam, char **args, int multi)
 		descr = NULL;
 
 	    if (c && c != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid option definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -766,7 +839,7 @@ parse_cadef(char *nam, char **args, int multi)
 			    *p = sav;
 			}
 			if (*p != ':') {
-			    freecadef(ret);
+			    freecadef(all);
 			    freecaargs(oargs);
 			    zwarnnam(nam, "invalid option definition: %s",
 				    *args, 0);
@@ -848,12 +921,12 @@ parse_cadef(char *nam, char **args, int multi)
 	    int type = CAA_REST;
 
 	    if (*++p != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
 	    if (ret->rest) {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "doubled rest argument definition: %s", *args, 0);
 		return NULL;
 	    }
@@ -885,7 +958,7 @@ parse_cadef(char *nam, char **args, int multi)
 		anum++;
 
 	    if (*p != ':') {
-		freecadef(ret);
+		freecadef(all);
 		zwarnnam(nam, "invalid argument: %s", *args, 0);
 		return NULL;
 	    }
@@ -905,7 +978,7 @@ parse_cadef(char *nam, char **args, int multi)
 		 pre = tmp, tmp = tmp->next);
 
 	    if (tmp && tmp->num == anum - 1) {
-		freecadef(ret);
+		freecadef(all);
 		freecaargs(arg);
 		zwarnnam(nam, "doubled argument definition: %s", *args, 0);
 		return NULL;
@@ -920,21 +993,16 @@ parse_cadef(char *nam, char **args, int multi)
     ret->nopts = nopts;
     ret->ndopts = ndopts;
     ret->nodopts = nodopts;
+    set_cadef_opts(ret);
 
-    for (argp = ret->args, xnum = 0; argp; argp = argp->next) {
-	if (!argp->direct)
-	    argp->min = argp->num - xnum;
-	if (argp->type == CAA_OPT)
-	    xnum++;
-    }
-    return ret;
+    return all;
 }
 
 /* Given an array of definitions, return the cadef for it. From the cache
  * are newly built. */
 
 static Cadef
-get_cadef(char *nam, char **args, int multi)
+get_cadef(char *nam, char **args)
 {
     Cadef *p, *min, new;
     int i, na = arrlen(args);
@@ -948,7 +1016,7 @@ get_cadef(char *nam, char **args, int multi)
 	    min = p;
     if (i)
 	min = p;
-    if ((new = parse_cadef(nam, args, multi))) {
+    if ((new = parse_cadef(nam, args))) {
 	freecadef(*min);
 	*min = new;
     }
@@ -1120,7 +1188,10 @@ ca_inactive(Cadef d, char **xor, int cur, int opts)
 
 /* State when parsing a command line. */
 
+typedef struct castate *Castate;
+
 struct castate {
+    Castate snext;
     Cadef d;
     int nopts;
     Caarg def, ddef;
@@ -1134,10 +1205,23 @@ struct castate {
 static struct castate ca_laststate;
 static int ca_parsed = 0, ca_alloced = 0;
 
+static void
+freecastate(Castate s)
+{
+    int i;
+    LinkList *p;
+
+    freelinklist(s->args, freestr);
+    for (i = s->nopts, p = s->oargs; i--; p++)
+	if (*p)
+	    freelinklist(*p, freestr);
+    zfree(s->oargs, s->d->nopts * sizeof(LinkList));
+}
+
 /* Parse a command line. */
 
 static int
-ca_parse_line(Cadef d, int multi)
+ca_parse_line(Cadef d, int multi, int first)
 {
     Caarg adef, ddef;
     Caopt ptr, wasopt, dopt;
@@ -1148,16 +1232,17 @@ ca_parse_line(Cadef d, int multi)
 
     /* Free old state. */
 
-    if (ca_alloced) {
-	int i = ca_laststate.nopts;
-	LinkList *p = ca_laststate.oargs;
-
-	freelinklist(ca_laststate.args, freestr);
-	while (i--)
-	    if (*p++)
-		freelinklist(p[-1], freestr);
+    if (first && ca_alloced) {
+	Castate s = &ca_laststate, ss;
+	int f = 1;
 
-	zfree(ca_laststate.oargs, ca_laststate.d->nopts * sizeof(LinkList));
+	while (s) {
+	    ss = s->snext;
+	    freecastate(s);
+	    if (!f)
+		zfree(s, sizeof(*s));
+	    s = ss;
+	}
     }
     /* Mark everything as active. */
 
@@ -1171,6 +1256,7 @@ ca_parse_line(Cadef d, int multi)
 
     /* Default values for the state. */
 
+    state.snext = NULL;
     state.d = d;
     state.nopts = d->nopts;
     state.def = state.ddef = NULL;
@@ -1482,16 +1568,13 @@ ca_colonlist(LinkList l)
 }
 
 static void
-ca_set_data(char *opt, Caarg arg, char **args, int single)
+ca_set_data(LinkList descr, LinkList act, LinkList subc,
+	    char *opt, Caarg arg, int single)
 {
-    LinkList descr, act, subc;
+    LinkNode dnode, anode;
     char nbuf[40], *buf;
     int restr = 0, onum, miss = 0, rest, oopt = 1, lopt = 0, addopt;
 
-    descr = newlinklist();
-    act = newlinklist();
-    subc = newlinklist();
-
  rec:
 
     addopt = (opt ? 0 : ca_laststate.oopt);
@@ -1503,33 +1586,40 @@ ca_set_data(char *opt, Caarg arg, char **args, int single)
 	if (!opt && !lopt && oopt > 0)
 	    oopt = 0;
 
-	addlinknode(descr, arg->descr);
-	addlinknode(act, arg->action);
+	for (dnode = firstnode(descr), anode = firstnode(act);
+	     dnode; incnode(dnode), incnode(anode))
+	    if (!strcmp((char *) getdata(dnode), arg->descr) &&
+		!strcmp((char *) getdata(anode), arg->action))
+		break;
 
-	if (!restr) {
-	    if ((restr = (arg->type == CAA_RARGS)))
-		restrict_range(ca_laststate.optbeg, ca_laststate.argend);
-	    else if ((restr = (arg->type == CAA_RREST)))
-		restrict_range(ca_laststate.argbeg, ca_laststate.argend);
-	}
-	if (arg->opt) {
-	    buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) +
-				   strlen(arg->opt) + 40);
-	    if (arg->num > 0 && arg->type < CAA_REST)
-		sprintf(buf, "%soption%s-%d",
-			(arg->set ? arg->set : ""), arg->opt, arg->num);
-	    else
-		sprintf(buf, "%soption%s-rest",
-			(arg->set ? arg->set : ""), arg->opt);
-	} else if (arg->num > 0) {
-	    sprintf(nbuf, "argument-%d", arg->num);
-	    buf = (arg->set ? dyncat(arg->set, nbuf) : dupstring(nbuf));
-	} else
-	    buf = (arg->set ? dyncat(arg->set, "argument-rest") :
-		   dupstring("argument-rest"));
+	if (!dnode) {
+	    addlinknode(descr, arg->descr);
+	    addlinknode(act, arg->action);
 
-	addlinknode(subc, buf);
+	    if (!restr) {
+		if ((restr = (arg->type == CAA_RARGS)))
+		    restrict_range(ca_laststate.optbeg, ca_laststate.argend);
+		else if ((restr = (arg->type == CAA_RREST)))
+		    restrict_range(ca_laststate.argbeg, ca_laststate.argend);
+	    }
+	    if (arg->opt) {
+		buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) +
+				       strlen(arg->opt) + 40);
+		if (arg->num > 0 && arg->type < CAA_REST)
+		    sprintf(buf, "%soption%s-%d",
+			    (arg->set ? arg->set : ""), arg->opt, arg->num);
+		else
+		    sprintf(buf, "%soption%s-rest",
+			    (arg->set ? arg->set : ""), arg->opt);
+	    } else if (arg->num > 0) {
+		sprintf(nbuf, "argument-%d", arg->num);
+		buf = (arg->set ? dyncat(arg->set, nbuf) : dupstring(nbuf));
+	    } else
+		buf = (arg->set ? dyncat(arg->set, "argument-rest") :
+		       dupstring("argument-rest"));
 
+	    addlinknode(subc, buf);
+	}
 	if (single)
 	    break;
 
@@ -1565,15 +1655,13 @@ ca_set_data(char *opt, Caarg arg, char **args, int single)
 
 	goto rec;
     }
-    set_list_array(args[0], descr);
-    set_list_array(args[1], act);
-    set_list_array(args[2], subc);
 }
 
 static int
 bin_comparguments(char *nam, char **args, char *ops, int func)
 {
     int min, max, n;
+    Castate lstate = &ca_laststate;
 
     if (incompfunc != 1) {
 	zwarnnam(nam, "can only be called from completion function", NULL, 0);
@@ -1588,8 +1676,7 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	return 1;
     }
     switch (args[0][1]) {
-    case 'i':
-    case 'I': min = 2; max = -1; break;
+    case 'i': min = 2; max = -1; break;
     case 'D': min = 3; max =  3; break;
     case 'O': min = 4; max =  4; break;
     case 'L': min = 3; max =  4; break;
@@ -1611,171 +1698,235 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
     }
     switch (args[0][1]) {
     case 'i':
-    case 'I':
 	if (compcurrent > 1 && compwords[0]) {
 	    Cadef def;
-	    int cap = ca_parsed;
-	    LinkList cax = ca_xor;
+	    int cap = ca_parsed, multi, first = 1, use, ret = 0;
+	    LinkList cax = ca_xor, nx;
+	    LinkNode node;
+	    Castate states = NULL, sp;
+	    char *xor[2];
 
 	    ca_parsed = 0;
+	    xor[1] = NULL;
 
-	    if (args[0][1] == 'I') {
-		char **xor;
+	    if (!(def = get_cadef(nam, args + 1)))
+		return 1;
 
-		if (!(def = get_cadef(nam, args + 2, 1)))
-		    return 1;
+	    multi = !!def->snext;
+	    ca_parsed = cap;
+	    ca_xor = (multi ? newlinklist() : NULL);
 
-		ca_parsed = cap;
-		ca_xor = newlinklist();
-		if ((xor = getaparam(args[1]))) {
-		    if (arrcontains(xor, args[2], 0) ||
-			ca_inactive(def, xor, compcurrent, 0)) {
-			ca_xor = cax;
-			return 1;
+	    while (def) {
+		use = !ca_parse_line(def, multi, first);
+		nx = ca_xor;
+		ca_xor = NULL;
+		while ((def = def->snext)) {
+		    if (nx) {
+			for (node = firstnode(nx); node; incnode(node)) {
+			    xor[0] = (char *) getdata(node);
+			    if (!strcmp(xor[0], def->sname) ||
+				ca_inactive(def, xor, compcurrent, 0))
+				break;
+			}
+			if (!node)
+			    break;
 		    }
 		}
-		if (ca_parse_line(def, 1)) {
-		    ca_xor = cax;
-		    return 1;
+		ca_xor = nx;
+		if (use && def) {
+		    sp = (Castate) zalloc(sizeof(*sp));
+		    memcpy(sp, &ca_laststate, sizeof(*sp));
+		    sp->snext = states;
+		    states = sp;
+		} else if (!use && !def) {
+		    if (states) {
+			freecastate(&ca_laststate);
+			memcpy(&ca_laststate, states, sizeof(*sp));
+			sp = states->snext;
+			zfree(states, sizeof(*states));
+			states = sp;
+		    } else
+			ret = 1;
 		}
-		set_list_array(args[1], ca_xor);
-	    } else {
-		if (!(def = get_cadef(nam, args + 1, 0)))
-		    return 1;
-
-		ca_parsed = cap;
-		ca_xor = NULL;
-		ca_parse_line(def, 0);
+		first = 0;
 	    }
 	    ca_xor = cax;
 	    ca_parsed = 1;
+	    ca_laststate.snext = states;
 
-	    return 0;
+	    return ret;
 	}
 	return 1;
 
     case 'D':
 	{
-	    Caarg arg = ca_laststate.def;
-
-	    if (arg) {
-		if (ca_laststate.doff > 0)
-		    ignore_prefix(ca_laststate.doff);
-
-		ca_set_data(arg->opt, arg, args + 1, (ca_laststate.doff > 0));
-
-		return 0;
+	    LinkList descr, act, subc;
+	    Caarg arg;
+	    int ign = 0, ret = 1;
+
+	    descr = newlinklist();
+	    act = newlinklist();
+	    subc = newlinklist();
+
+	    while (lstate) {
+		arg = lstate->def;
+
+		if (arg) {
+		    ret = 0;
+		    if (!ign && lstate->doff > 0) {
+			ign = 1;
+			ignore_prefix(lstate->doff);
+		    }
+		    ca_set_data(descr, act, subc, arg->opt, arg,
+				(lstate->doff > 0));
+		}
+		lstate = lstate->snext;
 	    }
-	    return 1;
+	    if (!ret) {
+		set_list_array(args[1], descr);
+		set_list_array(args[2], act);
+		set_list_array(args[3], subc);
+	    }
+	    return ret;
 	}
     case 'O':
-	if (ca_laststate.actopts &&
-	    (ca_laststate.opt || (ca_laststate.doff && ca_laststate.def) ||
-	     (ca_laststate.def &&
-	      (ca_laststate.def->type == CAA_OPT ||
-	       (ca_laststate.def->type >= CAA_RARGS &&
-		ca_laststate.def->num < 0)))) &&
-	    (!ca_laststate.def || ca_laststate.def->type < CAA_RARGS ||
-	     (ca_laststate.def->type == CAA_RARGS ?
-	      (ca_laststate.curpos == ca_laststate.argbeg + 1) :
-	      (compcurrent == 1)))) {
+	{
 	    LinkList next = newlinklist();
 	    LinkList direct = newlinklist();
 	    LinkList odirect = newlinklist();
 	    LinkList equal = newlinklist(), l;
 	    Caopt p;
 	    char *str;
-
-	    for (p = ca_laststate.d->opts; p; p = p->next) {
-		if (p->active) {
-		    switch (p->type) {
-		    case CAO_NEXT:    l = next;    break;
-		    case CAO_DIRECT:  l = direct;  break;
-		    case CAO_ODIRECT: l = odirect; break;
-		    default:          l = equal;   break;
+	    int ret = 1;
+
+	    for (; lstate; lstate = lstate->snext) {
+		if (lstate->actopts &&
+		    (lstate->opt || (lstate->doff && lstate->def) ||
+		     (lstate->def &&
+		      (lstate->def->type == CAA_OPT ||
+		       (lstate->def->type >= CAA_RARGS &&
+			lstate->def->num < 0)))) &&
+		    (!lstate->def || lstate->def->type < CAA_RARGS ||
+		     (lstate->def->type == CAA_RARGS ?
+		      (lstate->curpos == lstate->argbeg + 1) :
+		      (compcurrent == 1)))) {
+		    ret = 0;
+		    for (p = lstate->d->opts; p; p = p->next) {
+			if (p->active) {
+			    switch (p->type) {
+			    case CAO_NEXT:    l = next;    break;
+			    case CAO_DIRECT:  l = direct;  break;
+			    case CAO_ODIRECT: l = odirect; break;
+			    default:          l = equal;   break;
+			    }
+			    if (p->descr) {
+				char *n = bslashcolon(p->name);
+				int len = strlen(n) + strlen(p->descr) + 2;
+
+				str = (char *) zhalloc(len);
+				strcpy(str, n);
+				strcat(str, ":");
+				strcat(str, p->descr);
+			    } else
+				str = bslashcolon(p->name);
+			    addlinknode(l, str);
+			}
 		    }
-		    if (p->descr) {
-			char *n = bslashcolon(p->name);
-			int len = strlen(n) + strlen(p->descr) + 2;
-
-			str = (char *) zhalloc(len);
-			strcpy(str, n);
-			strcat(str, ":");
-			strcat(str, p->descr);
-		    } else
-			str = bslashcolon(p->name);
-		    addlinknode(l, str);
 		}
 	    }
-	    set_list_array(args[1], next);
-	    set_list_array(args[2], direct);
-	    set_list_array(args[3], odirect);
-	    set_list_array(args[4], equal);
+	    if (!ret) {
+		set_list_array(args[1], next);
+		set_list_array(args[2], direct);
+		set_list_array(args[3], odirect);
+		set_list_array(args[4], equal);
 
-	    return 0;
+		return 0;
+	    }
+	    return (ca_laststate.singles ? 2 : 1);
 	}
-	return (ca_laststate.singles ? 2 : 1);
     case 'L':
 	{
-	    Caopt opt = ca_get_opt(ca_laststate.d, args[1], 1, NULL);
+	    LinkList descr, act, subc;
+	    Caopt opt;
+	    int ret = 1;
 
-	    if (opt && opt->args) {
-		ca_set_data(opt->name, opt->args, args + 2, 1);
+	    descr = newlinklist();
+	    act = newlinklist();
+	    subc = newlinklist();
 
-		return 0;
+	    while (lstate) {
+		opt = ca_get_opt(lstate->d, args[1], 1, NULL);
+
+		if (opt && opt->args) {
+		    ret = 0;
+		    ca_set_data(descr, act, subc, opt->name, opt->args, 1);
+		}
+		lstate = lstate->snext;
 	    }
-	    return 1;
+	    if (!ret) {
+		set_list_array(args[2], descr);
+		set_list_array(args[3], act);
+		set_list_array(args[4], subc);
+	    }
+	    return ret;
 	}
     case 's':
-	if (ca_laststate.d->single && ca_laststate.singles &&
-	    ca_laststate.actopts && ca_laststate.opt) {
-	    setsparam(args[1],
-		      ztrdup((ca_laststate.ddef && ca_laststate.dopt) ?
-			     (ca_laststate.dopt->type == CAO_DIRECT ?
-			      "direct" :
-			      ((ca_laststate.dopt->type == CAO_OEQUAL ||
-				ca_laststate.dopt->type == CAO_EQUAL) ?
-			       "equal" : "next")) : ""));
-	    return 0;
-	}
+	for (; lstate; lstate = lstate->snext)
+	    if (lstate->d->single && lstate->singles &&
+		lstate->actopts && lstate->opt) {
+		setsparam(args[1],
+			  ztrdup((lstate->ddef && lstate->dopt) ?
+				 (lstate->dopt->type == CAO_DIRECT ?
+				  "direct" :
+				  ((lstate->dopt->type == CAO_OEQUAL ||
+				    lstate->dopt->type == CAO_EQUAL) ?
+				   "equal" : "next")) : ""));
+		return 0;
+	    }
 	return 1;
     case 'M':
 	setsparam(args[1], ztrdup(ca_laststate.d->match));
 	return 0;
     case 'a':
-	return !(ca_laststate.d->args || ca_laststate.d->rest);
+	for (; lstate; lstate = lstate->snext)
+	    if (lstate->d->args || lstate->d->rest)
+		return 0;
+	return 1;
     case 'W':
 	{
+	    Castate s;
 	    char **ret, **p;
 	    LinkNode n;
 	    LinkList *a;
 	    Caopt o;
 	    int num;
 
-	    ret = p = zalloc((countlinknodes(ca_laststate.args) + 1) *
-			     sizeof(char *));
+	    for (num = 0, s = lstate; s; s = s->snext)
+		num += countlinknodes(s->args);
 
-	    for (n = firstnode(ca_laststate.args); n; incnode(n))
-		*p++ = ztrdup((char *) getdata(n));
+	    ret = p = zalloc((num + 1) * sizeof(char *));
+
+	    for (s = lstate; s; s = s->snext)
+		for (n = firstnode(s->args); n; incnode(n))
+		    *p++ = ztrdup((char *) getdata(n));
 	    *p = NULL;
 
 	    setaparam(args[1], ret);
 
-	    for (num = 0, o = ca_laststate.d->opts, a = ca_laststate.oargs; o;
-		 o = o->next, a++)
-		if (*a)
-		    num += 2;
+	    for (num = 0, s = lstate; s; s = s->snext)
+		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
+		    if (*a)
+			num += 2;
 
 	    ret = p = zalloc((num + 1) * sizeof(char *));
 
-	    for (o = ca_laststate.d->opts, a = ca_laststate.oargs; o;
-		 o = o->next, a++) {
-		if (*a) {
-		    *p++ = (o->set ? tricat(o->set, o->name, "") :
-			    ztrdup(o->name));
-		    *p++ = ca_colonlist(*a);
-		}
-	    }
+	    for (s = lstate; s; s = s->snext)
+		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
+		    if (*a) {
+			*p++ = (o->set ? tricat(o->set, o->name, "") :
+				ztrdup(o->name));
+			*p++ = ca_colonlist(*a);
+		    }
 	    *p = NULL;
 
 	    sethparam(args[2], ret);