about summary refs log tree commit diff
path: root/Src/Zle/computil.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle/computil.c')
-rw-r--r--Src/Zle/computil.c288
1 files changed, 212 insertions, 76 deletions
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 709e8f1ab..29a5fcb21 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -304,6 +304,7 @@ 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 */
 };
 
 /* Description for an option. */
@@ -317,6 +318,7 @@ struct caopt {
     Caarg args;			/* option arguments */
     int active;			/* still allowed on command line */
     int num;			/* it's the num'th option */
+    char *set;			/* set name, shared */
 };
 
 #define CAO_NEXT    1
@@ -335,7 +337,10 @@ struct caarg {
     char *end;			/* end-pattern for ::<pat>:... */
     char *opt;			/* option name if for an option */
     int num;			/* it's the num'th argument */
+    int min;			/* it's also this argument, using opt. args */
+    int direct;			/* number was given directly */
     int active;			/* still allowed on command line */
+    char *set;			/* set name, shared */
 };
 
 #define CAA_NORMAL 1
@@ -393,6 +398,7 @@ freecadef(Cadef d)
 	Caopt p, n;
 
 	zsfree(d->match);
+	zsfree(d->set);
 	if (d->defs)
 	    freearray(d->defs);
 
@@ -454,7 +460,8 @@ bslashcolon(char *s)
 /* Parse an argument definition. */
 
 static Caarg
-parse_caarg(int mult, int type, int num, char *oname, char **def)
+parse_caarg(int mult, int type, int num, int opt, char *oname, char **def,
+	    char *set)
 {
     Caarg ret = (Caarg) zalloc(sizeof(*ret));
     char *p = *def, *d, sav;
@@ -463,8 +470,11 @@ parse_caarg(int mult, int type, int num, char *oname, char **def)
     ret->descr = ret->action = ret->end = NULL;
     ret->xor = NULL;
     ret->num = num;
+    ret->min = num - opt;
     ret->type = type;
     ret->opt = ztrdup(oname);
+    ret->direct = 0;
+    ret->set = set;
 
     /* Get the description. */
 
@@ -498,16 +508,22 @@ parse_caarg(int mult, int type, int num, char *oname, char **def)
 /* Parse an array of definitions. */
 
 static Cadef
-parse_cadef(char *nam, char **args)
+parse_cadef(char *nam, char **args, int multi)
 {
     Cadef ret;
     Caopt *optp;
+    Caarg argp;
     char **oargs = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor;
-    char *adpre, *adsuf;
+    char *adpre, *adsuf, *set = NULL, *doset = NULL;
     int single = 0, anum = 1, xnum, nopts, ndopts, nodopts;
 
     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++);
@@ -551,6 +567,7 @@ parse_cadef(char *nam, char **args)
     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));
@@ -561,6 +578,10 @@ parse_cadef(char *nam, char **args)
     /* Get the definitions. */
 
     for (optp = &(ret->opts); *args; args++) {
+        if (args[0][0] == '-' && !args[0][1]) {
+	    doset = set;
+	    continue;
+	}
 	p = dupstring(*args);
 	xnum = 0;
 	if (*p == '(') {
@@ -689,7 +710,7 @@ parse_cadef(char *nam, char **args)
 		/* There's at least one argument. */
 
 		Caarg *oargp = &oargs;
-		int atype, rest, oanum = 1;
+		int atype, rest, oanum = 1, onum = 0;
 		char *end;
 
 		/* Loop over the arguments. */
@@ -736,7 +757,10 @@ parse_cadef(char *nam, char **args)
 
 		    /* And the definition. */
 
-		    *oargp = parse_caarg(!rest, atype, oanum++, name, &p);
+		    *oargp = parse_caarg(!rest, atype, oanum++, onum,
+					 name, &p, doset);
+		    if (atype == CAA_OPT)
+			onum++;
 		    if (end)
 			(*oargp)->end = ztrdup(end);
 		    oargp = &((*oargp)->next);
@@ -751,6 +775,7 @@ parse_cadef(char *nam, char **args)
 	    optp = &((*optp)->next);
 
 	    opt->next = NULL;
+	    opt->set = doset;
 	    opt->name = ztrdup(rembslashcolon(name));
 	    if (descr)
 		opt->descr = ztrdup(descr);
@@ -810,15 +835,15 @@ parse_cadef(char *nam, char **args)
 		} else
 		    type = CAA_RARGS;
 	    }
-	    ret->rest = parse_caarg(0, type, -1, NULL, &p);
+	    ret->rest = parse_caarg(0, type, -1, 0, NULL, &p, doset);
 	    ret->rest->xor = xor;
 	} else {
 	    /* It's a normal argument definition. */
 
-	    int type = CAA_NORMAL;
+	    int type = CAA_NORMAL, direct;
 	    Caarg arg, tmp, pre;
 
-	    if (idigit(*p)) {
+	    if ((direct = idigit(*p))) {
 		/* Argment number is given. */
 		int num = 0;
 
@@ -840,8 +865,9 @@ parse_cadef(char *nam, char **args)
 		type = CAA_OPT;
 		p++;
 	    }
-	    arg = parse_caarg(0, type, anum - 1, NULL, &p);
+	    arg = parse_caarg(0, type, anum - 1, 0, NULL, &p, doset);
 	    arg->xor = xor;
+	    arg->direct = direct;
 
 	    /* Sort the new definition into the existing list. */
 
@@ -865,7 +891,13 @@ parse_cadef(char *nam, char **args)
     ret->nopts = nopts;
     ret->ndopts = ndopts;
     ret->nodopts = nodopts;
-    
+
+    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;
 }
 
@@ -873,7 +905,7 @@ parse_cadef(char *nam, char **args)
  * are newly built. */
 
 static Cadef
-get_cadef(char *nam, char **args)
+get_cadef(char *nam, char **args, int multi)
 {
     Cadef *p, *min, new;
     int i, na = arrlen(args);
@@ -887,7 +919,7 @@ get_cadef(char *nam, char **args)
 	    min = p;
     if (i)
 	min = p;
-    if ((new = parse_cadef(nam, args))) {
+    if ((new = parse_cadef(nam, args, multi))) {
 	freecadef(*min);
 	*min = new;
     }
@@ -974,10 +1006,10 @@ ca_get_arg(Cadef d, int n)
     if (d->argsactive) {
 	Caarg a = d->args;
 
-	while (a && a->num < n)
+	while (a && (n < a->min || n > a->num))
 	    a = a->next;
 
-	if (a && a->num == n && a->active)
+	if (a && a->min <= n && a->num >= n && a->active)
 	    return a;
 
 	return (d->rest && d->rest->active ? d->rest : NULL);
@@ -987,20 +1019,32 @@ ca_get_arg(Cadef d, int n)
 
 /* Use a xor list, marking options as inactive. */
 
-static void
-ca_inactive(Cadef d, char **xor)
+static LinkList ca_xor;
+
+static int
+ca_inactive(Cadef d, char **xor, int cur)
 {
-    if (xor) {
+    if (xor && cur <= compcurrent) {
 	Caopt opt;
-
-	for (; *xor; xor++) {
-	    if (xor[0][0] == ':' && !xor[0][1])
+	char *x;
+	int sl = (d->set ? strlen(d->set) : -1);
+
+	for (; (x = *xor); xor++) {
+	    if (ca_xor)
+		addlinknode(ca_xor, x);
+	    if (sl > 0) {
+		if (strpfx(d->set, x))
+		    x += sl;
+		else if (!strncmp(d->set, x, sl - 1))
+		    return 1;
+	    }
+	    if (x[0] == ':' && !x[1])
 		d->argsactive = 0;
-	    else if (xor[0][0] == '*' && !xor[0][1]) {
+	    else if (x[0] == '*' && !x[1]) {
 		if (d->rest)
 		    d->rest->active = 0;
-	    } else if (xor[0][0] >= '0' && xor[0][0] <= '9') {
-		int n = atoi(xor[0]);
+	    } else if (x[0] >= '0' && x[0] <= '9') {
+		int n = atoi(x);
 		Caarg a = d->args;
 
 		while (a && a->num < n)
@@ -1008,10 +1052,11 @@ ca_inactive(Cadef d, char **xor)
 
 		if (a && a->num == n)
 		    a->active = 0;
-	    } else if ((opt = ca_get_opt(d, *xor, 1, NULL)))
+	    } else if ((opt = ca_get_opt(d, x, 1, NULL)))
 		opt->active = 0;
 	}
     }
+    return 0;
 }
 
 /* State when parsing a command line. */
@@ -1022,7 +1067,7 @@ struct castate {
     Caarg def, ddef;
     Caopt curopt;
     int opt, arg, argbeg, optbeg, nargbeg, restbeg, curpos;
-    int inopt, inrest, inarg, nth, doff, singles;
+    int inopt, inrest, inarg, nth, doff, singles, oopt;
     LinkList args;
     LinkList *oargs;
 };
@@ -1030,10 +1075,10 @@ struct castate {
 static struct castate ca_laststate;
 static int ca_parsed = 0, ca_alloced = 0;
 
-/* Pars a command line. */
+/* Parse a command line. */
 
-static void
-ca_parse_line(Cadef d)
+static int
+ca_parse_line(Cadef d, int multi)
 {
     Caarg adef, ddef;
     Caopt ptr, wasopt;
@@ -1073,7 +1118,7 @@ ca_parse_line(Cadef d)
     state.curopt = NULL;
     state.argbeg = state.optbeg = state.nargbeg = state.restbeg =
 	state.nth = state.inopt = state.inarg = state.opt = state.arg = 1;
-    state.inrest = state.doff = state.singles = state.doff = 0;
+    state.inrest = state.doff = state.singles = state.doff = state.oopt = 0;
     state.curpos = compcurrent;
     state.args = znewlinklist();
     state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList));
@@ -1086,7 +1131,7 @@ ca_parse_line(Cadef d)
     if (!compwords[1]) {
 	ca_laststate.opt = ca_laststate.arg = 0;
 
-	return;
+	return 0;
     }
     /* Loop over the words from the line. */
 
@@ -1095,7 +1140,8 @@ ca_parse_line(Cadef d)
 	ddef = adef = NULL;
 	doff = state.singles = 0;
 
-	ca_inactive(d, argxor);
+	if (ca_inactive(d, argxor, cur))
+	    return 1;
 
 	/* We've a definition for an argument, skip to the next. */
 
@@ -1104,7 +1150,8 @@ ca_parse_line(Cadef d)
 	    if (state.curopt)
 		zaddlinknode(state.oargs[state.curopt->num], ztrdup(line));
 
-	    state.opt = (state.def->type == CAA_OPT);
+	    if ((state.opt = (state.def->type == CAA_OPT)) && state.def->opt)
+		state.oopt++;
 
 	    if (state.def->type == CAA_REST || state.def->type == CAA_RARGS ||
 		state.def->type == CAA_RREST) {
@@ -1145,7 +1192,8 @@ ca_parse_line(Cadef d)
 
 	    state.oargs[state.curopt->num] = znewlinklist();
 
-	    ca_inactive(d, state.curopt->xor);
+	    if (ca_inactive(d, state.curopt->xor, cur))
+		return 1;
 
 	    /* Collect the argument strings. Maybe. */
 
@@ -1184,7 +1232,8 @@ ca_parse_line(Cadef d)
 		if ((tmpopt = d->single[STOUC(*p)])) {
 		    state.oargs[tmpopt->num] = znewlinklist();
 
-		    ca_inactive(d, tmpopt->xor);
+		    if (ca_inactive(d, tmpopt->xor, cur))
+			return 1;
 		}
 	    }
 	    if (state.def &&
@@ -1203,12 +1252,16 @@ ca_parse_line(Cadef d)
 		state.opt = 0;
 	    else
 		state.curopt = NULL;
-	} else if (state.arg) {
+	} else if (multi && (*line == '-' || *line == '+') && cur != compcurrent)
+	    return 1;
+	else if (state.arg) {
 	    /* Otherwise it's a normal argument. */
 	    if (state.inopt) {
 		state.inopt = 0;
 		state.nargbeg = cur - 1;
 	    }
+	    if (!d->args && !d->rest)
+		return 1;
 	    if ((adef = state.def = ca_get_arg(d, state.nth)) &&
 		(state.def->type == CAA_RREST ||
 		 state.def->type == CAA_RARGS)) {
@@ -1291,6 +1344,7 @@ ca_parse_line(Cadef d)
 	    }
 	}
     }
+    return 0;
 }
 
 /* Build a colon-list from a list. */
@@ -1327,6 +1381,88 @@ ca_colonlist(LinkList l)
 	return ztrdup("");
 }
 
+static void
+ca_set_data(char *opt, Caarg arg, char **args, int single)
+{
+    LinkList descr, act, subc;
+    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);
+
+    for (; arg && (arg->num < 0 ||
+		   (arg->min <= ca_laststate.nth + addopt &&
+		    arg->num >= ca_laststate.nth));) {
+	if ((lopt = arg->type == CAA_OPT) && !opt && oopt > 0)
+	    oopt = 0;
+
+	addlinknode(descr, arg->descr);
+	addlinknode(act, arg->action);
+
+	if (!restr) {
+	    if ((restr = (arg->type == CAA_RARGS)))
+		restrict_range(ca_laststate.optbeg, arrlen(compwords) - 1);
+	    else if ((restr = (arg->type == CAA_RREST)))
+		restrict_range(ca_laststate.argbeg, arrlen(compwords) - 1);
+	}
+	if (arg->opt) {
+	    buf = (char *) zhalloc((arg->set ? strlen(arg->set) : 0) +
+				   strlen(arg->opt) + 40);
+	    if (arg->num > 0)
+		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;
+
+	if (!opt && arg->num >= 0 && !arg->next && miss)
+	    arg = ca_laststate.d->rest;
+	else {
+	    onum = arg->num;
+	    rest = (onum != arg->min && onum == ca_laststate.nth);
+	    if ((arg = arg->next)) {
+		if (arg->num != onum + 1)
+		    miss = 1;
+	    } else if (rest || (oopt > 0 && !opt)) {
+		arg = ca_laststate.d->rest;
+		oopt = -1;
+	    }
+	}
+    }
+    if (!single && opt && lopt) {
+	opt = NULL;
+	arg = ca_get_arg(ca_laststate.d, ca_laststate.nth);
+
+	goto rec;
+    }
+    if (!opt && oopt > 0) {
+	oopt = -1;
+	arg = ca_laststate.d->rest;
+
+	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)
 {
@@ -1340,14 +1476,14 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	zwarnnam(nam, "invalid argument: %s", args[0], 0);
 	return 1;
     }
-    if (args[0][1] != 'i' && !ca_parsed) {
+    if (args[0][1] != 'i' && args[0][1] != 'I' && !ca_parsed) {
 	zwarnnam(nam, "no parsed state", NULL, 0);
 	return 1;
     }
     switch (args[0][1]) {
-    case 'i': min = 2; max = -1; break;
-    case 'D': min = 2; max =  2; break;
-    case 'C': min = 1; max =  1; break;
+    case 'i':
+    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;
     case 's': min = 1; max =  1; break;
@@ -1368,17 +1504,43 @@ 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 = get_cadef(nam, args + 1);
+	    Cadef def;
 	    int cap = ca_parsed;
+	    LinkList cax = ca_xor;
 
 	    ca_parsed = 0;
 
-	    if (!def)
-		return 1;
+	    if (args[0][1] == 'I') {
+		char **xor;
+
+		if (!(def = get_cadef(nam, args + 2, 1)))
+		    return 1;
 
-	    ca_parsed = cap;
-	    ca_parse_line(def);
+		ca_parsed = cap;
+		ca_xor = newlinklist();
+		if ((xor = getaparam(args[1]))) {
+		    if (arrcontains(xor, args[2], 0) ||
+			ca_inactive(def, xor, compcurrent)) {
+			ca_xor = cax;
+			return 1;
+		    }
+		}
+		if (ca_parse_line(def, 1)) {
+		    ca_xor = cax;
+		    return 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);
+	    }
+	    ca_xor = cax;
 	    ca_parsed = 1;
 
 	    return 0;
@@ -1390,35 +1552,11 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	    Caarg arg = ca_laststate.def;
 
 	    if (arg) {
-		setsparam(args[1], ztrdup(arg->descr));
-		setsparam(args[2], ztrdup(arg->action));
-
 		if (ca_laststate.doff > 0)
 		    ignore_prefix(ca_laststate.doff);
-		if (arg->type == CAA_RARGS)
-		    restrict_range(ca_laststate.optbeg,
-				   arrlen(compwords) - 1);
-		else if (arg->type == CAA_RREST)
-		    restrict_range(ca_laststate.argbeg,
-				   arrlen(compwords) - 1);
-		return 0;
-	    }
-	    return 1;
-	}
-    case 'C':
-	{
-	    Caarg arg = ca_laststate.def;
 
-	    if (arg) {
-		char buf[20];
+		ca_set_data(arg->opt, arg, args + 1, (ca_laststate.doff > 0));
 
-		if (arg->num > 0)
-		    sprintf(buf, "%d", arg->num);
-		else
-		    strcpy(buf, "rest");
-
-		setsparam(args[1], (arg->opt ? tricat(arg->opt, "-", buf) :
-				    tricat("argument-", buf, "")));
 		return 0;
 	    }
 	    return 1;
@@ -1474,11 +1612,7 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	    Caopt opt = ca_get_opt(ca_laststate.d, args[1], 1, NULL);
 
 	    if (opt && opt->args) {
-		setsparam(args[2], ztrdup(opt->args->descr));
-		setsparam(args[3], ztrdup(opt->args->action));
-
-		if (args[4])
-		    setsparam(args[4], tricat(opt->name, "-1", ""));
+		ca_set_data(opt->name, opt->args, args + 2, 1);
 
 		return 0;
 	    }
@@ -1528,7 +1662,8 @@ bin_comparguments(char *nam, char **args, char *ops, int func)
 	    for (o = ca_laststate.d->opts, a = ca_laststate.oargs; o;
 		 o = o->next, a++) {
 		if (*a) {
-		    *p++ = ztrdup(o->name);
+		    *p++ = (o->set ? tricat(o->set, o->name, "") :
+			    ztrdup(o->name));
 		    *p++ = ca_colonlist(*a);
 		}
 	    }
@@ -1740,7 +1875,7 @@ parse_cvdef(char *nam, char **args)
 		vtype = CVV_OPT;
 	    } else
 		vtype = CVV_ARG;
-	    arg = parse_caarg(0, 0, 0, name, &p);
+	    arg = parse_caarg(0, 0, 0, 0, name, &p, NULL);
 	} else {
 	    vtype = CVV_NOARG;
 	    arg = NULL;
@@ -2243,6 +2378,7 @@ settags(int level, char **tags)
 
 /* Check if an array contains a string. */
 
+/**/
 static int
 arrcontains(char **a, char *s, int colon)
 {