about summary refs log tree commit diff
path: root/Src/Zle
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/comp.h3
-rw-r--r--Src/Zle/compctl.c43
-rw-r--r--Src/Zle/zle_tricky.c128
3 files changed, 93 insertions, 81 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index b0fbf3ac6..ab8d62c8a 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -227,7 +227,8 @@ struct cmatch {
 #define CMF_FILE     1		/* this is a file */
 #define CMF_REMOVE   2		/* remove the suffix */
 #define CMF_PARBR    4		/* paramter expansion with a brace */
-#define CMF_NOLIST   8		/* should not be listed */
+#define CMF_PARNEST  8		/* nested paramter expansion */
+#define CMF_NOLIST  16		/* should not be listed */
 
 
 /* Stuff for completion matcher control. */
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index e9ff83387..31daff24c 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1947,25 +1947,25 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 
 	    if (compcurrent - 1 < na || compcurrent - 1 > nb)
 		return 0;
-
-	    restrict_range(na, nb);
+	    if (mod)
+		restrict_range(na, nb);
 	    return 1;
 	}
     case CVT_RANGEPAT:
 	{
 	    char **p;
 	    int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1;
-	    Comp c;
+	    Patprog pp;
 
 	    i = compcurrent - 1;
 	    if (i < 0 || i >= l)
 		return 0;
 
 	    singsub(&sa);
-	    c = parsereg(sa);
+	    pp = patcompile(sa, PAT_STATIC, NULL);
 
 	    for (i--, p = compwords + i; i >= 0; p--, i--) {
-		if (domatch(*p, c, 0)) {
+		if (pattry(pp, *p)) {
 		    b = i + 1;
 		    t = 1;
 		    break;
@@ -1975,10 +1975,10 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 		int tt = 0;
 
 		singsub(&sb);
-		c = parsereg(sb);
+		pp = patcompile(sb, PAT_STATIC, NULL);
 
 		for (i++, p = compwords + i; i < l; p++, i++) {
-		    if (domatch(*p, c, 0)) {
+		    if (pattry(pp, *p)) {
 			e = i - 1;
 			tt = 1;
 			break;
@@ -1989,7 +1989,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 	    }
 	    if (e < b)
 		t = 0;
-	    if (t)
+	    if (t && mod)
 		restrict_range(b, e);
 	    return t;
 	}
@@ -2011,12 +2011,12 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
     case CVT_PREPAT:
     case CVT_SUFPAT:
 	{
-	    Comp c;
+	    Patprog pp;
 
 	    if (!na)
 		return 0;
 
-	    if (!(c = parsereg(sa)))
+	    if (!(pp = patcompile(sa, PAT_STATIC, 0)))
 		return 0;
 
 	    if (test == CVT_PREPAT) {
@@ -2036,15 +2036,15 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 		for (; l; l--, p += add) {
 		    sav = *p;
 		    *p = '\0';
-		    test = domatch(compprefix, c, 0);
+		    test = pattry(pp, compprefix);
 		    *p = sav;
 		    if (test && !--na)
 			break;
 		}
 		if (!l)
 		    return 0;
-
-		ignore_prefix(p - compprefix);
+		if (mod)
+		    ignore_prefix(p - compprefix);
 	    } else {
 		int l, ol, add;
 		char *p;
@@ -2060,13 +2060,13 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 		    add = -1;
 		}
 		for (; l; l--, p += add)
-		    if (domatch(p, c, 0) && !--na)
+		    if (pattry(pp, p) && !--na)
 			break;
 
 		if (!l)
 		    return 0;
-
-		ignore_suffix(ol - (p - compsuffix));
+		if (mod)
+		    ignore_suffix(ol - (p - compsuffix));
 	    }
 	    return 1;
 	}
@@ -2126,9 +2126,11 @@ bin_compset(char *name, char **argv, char *ops, int func)
     case CVT_RANGEPAT:
 	tokenize(sa);
 	sa = rembslash(sa);
+	remnulargs(sa);
 	if (sb) {
 	    tokenize(sb);
 	    sb = rembslash(sb);
+	    remnulargs(sb);
 	}
 	break;
     case CVT_PRENUM:
@@ -2144,6 +2146,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
 	    na = -1;
 	tokenize(sa);
 	sa = rembslash(sa);
+	remnulargs(sa);
 	break;
     }
     return !do_comp_vars(test, na, sa, nb, sb, 1);
@@ -2469,10 +2472,10 @@ cond_psfix(char **a, int id)
 {
     if (comp_check()) {
 	if (a[1])
-	    return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1),
+	    return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1, 1),
 				0, NULL, 0);
 	else
-	    return do_comp_vars(id, -1, cond_str(a, 0), 0, NULL, 0);
+	    return do_comp_vars(id, -1, cond_str(a, 0, 1), 0, NULL, 0);
     }
     return 0;
 }
@@ -2481,8 +2484,8 @@ cond_psfix(char **a, int id)
 static int
 cond_range(char **a, int id)
 {
-    return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0), 0,
-			(id ? cond_str(a, 1) : NULL), 0);
+    return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0, 1), 0,
+			(id ? cond_str(a, 1, 1) : NULL), 0);
 }
 
 static struct builtin bintab[] = {
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 9f4fa0c93..347eb9ffa 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -163,7 +163,7 @@ static int ispattern, haspattern;
  * from the whole word we are completing and the second one from that    *
  * part of the word that was identified as a possible filename.          */
 
-static Comp patcomp, filecomp;
+static Patprog patcomp, filecomp;
 
 /* We store the following prefixes/suffixes:                               *
  * lpre/lsuf -- what's on the line                                         *
@@ -728,7 +728,7 @@ check_param(char *s, int set, int test)
     if ((*p == String || *p == Qstring) && p[1] != Inpar && p[1] != Inbrack) {
 	/* This is really a parameter expression (not $(...) or $[...]). */
 	char *b = p + 1, *e = b;
-	int n = 0, br = 1;
+	int n = 0, br = 1, nest = 0;
 
 	if (*b == Inbrace) {
 	    char *tb = b;
@@ -740,6 +740,10 @@ check_param(char *s, int set, int test)
 	    /* Ignore the possible (...) flags. */
 	    b++, br++;
 	    n = skipparens(Inpar, Outpar, &b);
+
+	    for (tb = p - 1; tb > s && *tb != Outbrace && *tb != Inbrace; tb--);
+	    if (tb > s && *tb == Inbrace && (tb[-1] == String || *tb == Qstring))
+		nest = 1;
 	}
 
 	/* Ignore the stuff before the parameter name. */
@@ -788,9 +792,11 @@ check_param(char *s, int set, int test)
 	     * global variables. */
 
 	    if (set) {
-		if (br >= 2)
+		if (br >= 2) {
 		    mflags |= CMF_PARBR;
-
+		    if (nest)
+			mflags |= CMF_PARNEST;
+		}
 		/* Get the prefix (anything up to the character before the name). */
 		isuf = dupstring(e);
 		untokenize(isuf);
@@ -2542,9 +2548,12 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
 	    lm = NULL;
 	} else {
 	    /* No matcher and different characters: l does not match w. */
+	    if (test)
+		return 0;
+
 	    abort_match();
 
-	    return (test ? 0 : -1);
+	    return -1;
 	}
     }
     /* If this is a recursive call, we just return if l matched w or not. */
@@ -2600,7 +2609,7 @@ match_str(char *l, char *w, int *bp, int *rwlp, int sfx, int test)
  * and the suffix don't match the word w. */
 
 static char *
-comp_match(char *pfx, char *sfx, char *w, Comp cp,
+comp_match(char *pfx, char *sfx, char *w, Patprog cp,
 	   Cline *clp, int qu, int *bpl, int *bsl, int *exact)
 {
     char *r = NULL;
@@ -2610,7 +2619,7 @@ comp_match(char *pfx, char *sfx, char *w, Comp cp,
 	int wl;
 
 	r = w;
-	if (!domatch(r, cp, 0))
+	if (!pattry(cp, r))
 	    return NULL;
     
 	r = (qu ? quotename(r, NULL) : dupstring(r));
@@ -2868,7 +2877,8 @@ join_strs(int la, char *sa, int lb, char *sb)
 			    *ap += mp->wlen; *alp -= mp->wlen;
 			    *bp += bl; *blp -= bl;
 			    t = 1;
-			}
+			} else
+			    t = 0;
 		    }
 		}
 	    }
@@ -2907,7 +2917,7 @@ cmp_anchors(Cline o, Cline n, int join)
     /* First try the exact strings. */
     if ((!(o->flags & CLF_LINE) && o->wlen == n->wlen &&
 	 (!o->word || !strncmp(o->word, n->word, o->wlen))) ||
-	(line = ((!o->line && !n->line) ||
+	(line = ((!o->line && !n->line && !o->wlen && !n->wlen) ||
 		 (o->llen == n->llen && o->line && n->line &&
 		  !strncmp(o->line, n->line, o->llen))))) {
 	if (line) {
@@ -3419,6 +3429,11 @@ join_clines(Cline o, Cline n)
 	    }
 	    /* Now see if they have matching anchors. If not, cut the list. */
 	    if (!(o->flags & CLF_MID) && !cmp_anchors(o, n, 1)) {
+#if 0
+		/* This used to search forward for matching anchors.
+		 * Unfortunately this does the wrong thing if the prefixes
+		 * before the differing anchors match nicely. */
+
 		Cline t, tn;
 
 		for (t = n; (tn = t->next) && !cmp_anchors(o, tn, 1); t = tn);
@@ -3427,6 +3442,7 @@ join_clines(Cline o, Cline n)
 		    n = tn;
 		    continue;
 		} else {
+#endif
 		    if (o->flags & CLF_SUF)
 			break;
 
@@ -3434,7 +3450,10 @@ join_clines(Cline o, Cline n)
 		    o->wlen = 0;
 		    free_cline(o->next);
 		    o->next = NULL;
+		    o->flags |= CLF_MISS;
+#if 0
 		}
+#endif
 	    }
 	    /* Ok, they are equal, now join the sub-lists. */
 	    if (o->flags & CLF_MID)
@@ -3726,7 +3745,7 @@ int
 addmatches(Cadata dat, char **argv)
 {
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
-    char **aign = NULL, **dparr = NULL, oaq = autoq;
+    char **aign = NULL, **dparr = NULL, oaq = autoq, *oppre = dat->ppre;
     char *oqp = qipre, *oqs = qisuf, qc;
     int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
     int oisalt = 0, isalt, isexact, doadd, ois = instring, oib = inbackt;
@@ -3734,7 +3753,7 @@ addmatches(Cadata dat, char **argv)
     Cmatch cm;
     struct cmlist mst;
     Cmlist oms = mstack;
-    Comp cp = NULL;
+    Patprog cp = NULL;
     LinkList aparl = NULL, oparl = NULL, dparl = NULL;
 
     if (compquote && (qc = *compquote)) {
@@ -3798,13 +3817,8 @@ addmatches(Cadata dat, char **argv)
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
 	    if (dat->aflags & CAF_MATCH) {
-		if (dat->aflags & CAF_QUOTE) {
-		    lipre = dupstring(compiprefix);
-		    lisuf = dupstring(compisuffix);
-		} else {
-		    lipre = quotename(compiprefix, NULL);
-		    lisuf = quotename(compisuffix, NULL);
-		}
+		lipre = dupstring(compiprefix);
+		lisuf = dupstring(compisuffix);
 		lpre = dupstring(compprefix);
 		lsuf = dupstring(compsuffix);
 		llpl = strlen(lpre);
@@ -3830,7 +3844,7 @@ addmatches(Cadata dat, char **argv)
 		    if (haswilds(tmp)) {
 			if (is)
 			    tmp[llpl] = Star;
-			if ((cp = parsereg(tmp)))
+			if ((cp = patcompile(tmp, 0, NULL)))
 			    haspattern = 1;
 		    }
 		}
@@ -3847,12 +3861,21 @@ addmatches(Cadata dat, char **argv)
 	    else if (lisuf)
 		dat->isuf = lisuf;
 	    if (dat->ppre) {
-		dat->ppre = dupstring(dat->ppre);
+		if (!(dat->aflags & CAF_QUOTE)) {
+		    dat->ppre = quotename(dat->ppre, NULL);
+		    if ((dat->flags & CMF_FILE) &&
+			dat->ppre[0] == '\\' && dat->ppre[1] == '~')
+			chuck(dat->ppre);
+		} else
+		    dat->ppre = dupstring(dat->ppre);
 		lpl = strlen(dat->ppre);
 	    } else
 		lpl = 0;
 	    if (dat->psuf) {
-		dat->psuf = dupstring(dat->psuf);
+		if (!(dat->aflags & CAF_QUOTE))
+		    dat->psuf = quotename(dat->psuf, NULL);
+		else
+		    dat->psuf = dupstring(dat->psuf);
 		lsl = strlen(dat->psuf);
 	    } else
 		lsl = 0;
@@ -3877,7 +3900,7 @@ addmatches(Cadata dat, char **argv)
 		    dat->pre = dupstring(dat->pre);
 		if (dat->suf)
 		    dat->suf = dupstring(dat->suf);
-		if (!dat->prpre && (dat->prpre = dat->ppre)) {
+		if (!dat->prpre && (dat->prpre = oppre)) {
 		    singsub(&(dat->prpre));
 		    untokenize(dat->prpre);
 		} else
@@ -3901,22 +3924,6 @@ addmatches(Cadata dat, char **argv)
 		    dat->rems = NULL;
 		} else if (dat->rems)
 		    dat->rems = dupstring(dat->rems);
-
-		/* Probably quote the prefix and suffix for testing. */
-		if (!(dat->aflags & CAF_QUOTE)) {
-		    if (!cp && (dat->aflags & CAF_MATCH)) {
-			lpre = quotename(lpre, NULL);
-			lsuf = quotename(lsuf, NULL);
-		    }
-		    if (dat->ppre) {
-			dat->ppre = quotename(dat->ppre, NULL);
-			if ((dat->flags & CMF_FILE) &&
-			    dat->ppre[0] == '\\' && dat->ppre[1] == '~')
-			    chuck(dat->ppre);
-		    }
-		    if (dat->psuf)
-			dat->psuf = quotename(dat->psuf, NULL);
-		}
 	    }
 	    /* Walk through the matches given. */
 	    for (; (s = *argv); argv++) {
@@ -4340,7 +4347,7 @@ gen_matches_files(int dirs, int execs, int all)
 		addwhat = execs ? -8 : -5;
 		if (filecomp)
 		    /* If we have a pattern for the filename check, use it. */
-		    test = domatch(n, filecomp, 0);
+		    test = pattry(filecomp, n);
 		else {
 		    /* Otherwise use the prefix and suffix strings directly. */
 		    e = n + strlen(n) - fsl;
@@ -5024,8 +5031,6 @@ comp_str(int *ipl, int *pl, int untok)
 	remnulargs(p);
 	ctokenize(s);
 	remnulargs(s);
-	ctokenize(ip);
-	remnulargs(ip);
     }
     lp = strlen(p);
     ls = strlen(s);
@@ -5563,14 +5568,14 @@ static int
 makecomplistpc(char *os, int incmd)
 {
     Patcomp pc;
-    Comp pat;
+    Patprog pat;
     char *s = findcmd(cmdstr, 1);
     int ret = 0;
 
     for (pc = patcomps; pc; pc = pc->next) {
-	if ((pat = parsereg(pc->pat)) &&
-	    (domatch(cmdstr, pat, 0) ||
-	     (s && domatch(s, pat, 0)))) {
+	if ((pat = patcompile(pc->pat, PAT_STATIC, NULL)) &&
+	    (pattry(pat, cmdstr) ||
+	     (s && pattry(pat, s)))) {
 	    makecomplistcc(pc->cc, os, incmd);
 	    ret |= 2;
 	    if (!(ccont & CC_CCCONT))
@@ -5666,7 +5671,7 @@ makecomplistext(Compctl occ, char *os, int incmd)
 {
     Compctl compc;
     Compcond or, cc;
-    Comp comp;
+    Patprog pprog;
     int compadd, m = 0, d = 0, t, tt, i, j, a, b, ins;
     char *sc = NULL, *s, *ss;
 
@@ -5752,8 +5757,8 @@ makecomplistext(Compctl occ, char *os, int incmd)
 			if (cc->type == CCT_CURPAT ||
 			    cc->type == CCT_WORDPAT) {
 			    tokenize(ss = dupstring(cc->u.s.s[i]));
-			    t = ((comp = parsereg(ss)) &&
-				 domatch(s, comp, 0));
+			    t = ((pprog = patcompile(ss, PAT_STATIC, NULL)) &&
+				 pattry(pprog, s));
 			} else
 			    t = (!strcmp(s, rembslash(cc->u.s.s[i])));
 			break;
@@ -5767,8 +5772,8 @@ makecomplistext(Compctl occ, char *os, int incmd)
 				sc = rembslash(cc->u.l.a[i]);
 			    if (cc->type == CCT_RANGESTR ?
 				!strncmp(s, sc, strlen(sc)) :
-				((comp = parsereg(sc)) &&
-				 domatch(s, comp, 0))) {
+				((pprog = patcompile(sc, PAT_STATIC, 0)) &&
+				 pattry(pprog, s))) {
 				zsfree(s);
 				brange = j + 1;
 				t = 1;
@@ -5785,8 +5790,8 @@ makecomplistext(Compctl occ, char *os, int incmd)
 				    sc = rembslash(cc->u.l.b[i]);
 				if (cc->type == CCT_RANGESTR ?
 				    !strncmp(s, sc, strlen(sc)) :
-				    ((comp = parsereg(sc)) &&
-				     domatch(s, comp, 0))) {
+				    ((pprog = patcompile(sc, PAT_STATIC, 0)) &&
+				     pattry(pprog, s))) {
 				    zsfree(s);
 				    erange = j - 1;
 				    t = clwpos <= erange;
@@ -6050,7 +6055,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    strcpy(p + rpl + 1, rsuf);
 	} else
 	    strcpy(p + rpl, rsuf);
-	patcomp = parsereg(p);
+	patcomp = patcompile(p, 0, NULL);
 	haspattern = 1;
     }
     if (!patcomp) {
@@ -6148,7 +6153,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 		(!comppatmatch || *comppatmatch == '*'))
 		p[t2++] = Star;
 	    strcpy(p + t2, fsuf);
-	    filecomp = parsereg(p);
+	    filecomp = patcompile(p, 0, NULL);
 	}
 	if (!filecomp) {
 	    untokenize(fpre);
@@ -6567,7 +6572,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     }
     if (cc->hpat) {
 	/* We have a pattern to take things from the history. */
-	Comp compc = NULL;
+	Patprog pprogc = NULL;
 	char *e, *h, hpatsav;
 	Histent he;
 	int i = addhistnum(curhist,-1,HIST_FOREIGN), n = cc->hnum;
@@ -6577,7 +6582,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    char *thpat = dupstring(cc->hpat);
 
 	    tokenize(thpat);
-	    compc = parsereg(thpat);
+	    pprogc = patcompile(thpat, 0, NULL);
 	}
 	/* n holds the number of history line we have to search. */
 	if (!n)
@@ -6594,7 +6599,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 		/* We now have a word from the history, ignore it *
 		 * if it begins with a quote or `$'.              */
 		if (*h != '\'' && *h != '"' && *h != '`' && *h != '$' &&
-		    (!compc || domatch(h, compc, 0)))
+		    (!pprogc || pattry(pprogc, h)))
 		    /* Otherwise add it if it was matched. */
 		    addmatch(dupstring(h), NULL);
 		if (hpatsav)
@@ -7729,6 +7734,8 @@ do_single(Cmatch m)
 	    minfo.insc++;
 	    if (minfo.we)
 		minfo.end += minfo.insc;
+	    if (m->flags & CMF_PARNEST)
+		havesuff = 1;
 	}
 	if ((m->flags & CMF_FILE) || (m->ripre && isset(AUTOPARAMSLASH))) {
 	    /* If we have a filename or we completed a parameter name      *
@@ -7742,11 +7749,12 @@ do_single(Cmatch m)
 		t = 1;
 	    else {
 		/* Build the path name. */
-		if (m->ripre && !*psuf) {
+		if (m->ripre && !*psuf && !(m->flags & CMF_PARNEST)) {
 		    int ne = noerrs;
 
-		    p = (char *) zhalloc(strlen(m->ripre) + strlen(str) + 1);
-		    sprintf(p, "%s%s", m->ripre, str);
+		    p = (char *) zhalloc(strlen(m->ripre) + strlen(str) + 2);
+		    sprintf(p, "%s%s%c", m->ripre, str,
+			    ((m->flags & CMF_PARBR) ? Outbrace : '\0'));
 		    noerrs = 1;
 		    parsestr(p);
 		    singsub(&p);