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.h39
-rw-r--r--Src/Zle/comp1.c57
-rw-r--r--Src/Zle/comp1.export15
-rw-r--r--Src/Zle/compctl.c260
-rw-r--r--Src/Zle/zle_hist.c6
-rw-r--r--Src/Zle/zle_main.c4
-rw-r--r--Src/Zle/zle_misc.c6
-rw-r--r--Src/Zle/zle_params.c21
-rw-r--r--Src/Zle/zle_refresh.c8
-rw-r--r--Src/Zle/zle_tricky.c912
-rw-r--r--Src/Zle/zle_word.c2
11 files changed, 896 insertions, 434 deletions
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 76ac67114..d7f3610f1 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -103,6 +103,7 @@ struct compctl {
     char *glob;			/* for -g (globbing)                       */
     char *str;			/* for -s (expansion)                      */
     char *func;			/* for -K (function)                       */
+    char *widget;		/* for -i (function)                       */
     char *explain;		/* for -X (explanation)                    */
     char *ylist;		/* for -y (user-defined desc. for listing) */
     char *prefix, *suffix;	/* for -P and -S (prefix, suffix)          */
@@ -284,7 +285,37 @@ struct cline {
 /* Flags for compadd and addmatches(). */
 
 #define CAF_QUOTE    1
-#define CAF_MENU     2
-#define CAF_NOSORT   4
-#define CAF_ALT      8
-#define CAF_MATCH   16
+#define CAF_NOSORT   2
+#define CAF_ALT      4
+#define CAF_MATCH    8
+
+/* Flags for special parameters. */
+
+#define CP_WORDS      (1 <<  0)
+#define CP_CURRENT    (1 <<  1)
+#define CP_PREFIX     (1 <<  2)
+#define CP_SUFFIX     (1 <<  3)
+#define CP_IPREFIX    (1 <<  4)
+#define CP_COMPSTATE  (1 <<  5)
+
+#define CP_REALPARAMS        6
+
+#define CP_NMATCHES   (1 <<  6)
+#define CP_MATCHER    (1 <<  7)
+#define CP_MATCHERSTR (1 <<  8)
+#define CP_MATCHERTOT (1 <<  9)
+#define CP_CONTEXT    (1 << 10)
+#define CP_PARAMETER  (1 << 11)
+#define CP_REDIRECT   (1 << 12)
+#define CP_QUOTE      (1 << 13)
+#define CP_QUOTING    (1 << 14)
+#define CP_RESTORE    (1 << 15)
+#define CP_LIST       (1 << 16)
+#define CP_INSERT     (1 << 17)
+#define CP_EXACT      (1 << 18)
+#define CP_EXACTSTR   (1 << 19)
+#define CP_PATMATCH   (1 << 20)
+
+#define CP_NUM              21
+
+#define CP_ALLMASK    ((1 << CP_NUM) - 1)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index 72f3cea53..ccccf5a34 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -46,10 +46,13 @@ Cmlist cmatcher;
 /**/
 void (*makecompparamsptr) _((void));
 
+/**/
+void (*comp_setunsetptr) _((int, int));
+
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-void (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
+int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char **));
 
 /**/
 char *(*comp_strptr) _((int*, int*, int));
@@ -58,7 +61,7 @@ char *(*comp_strptr) _((int*, int*, int));
 int (*getcpatptr) _((char *, int, char *, int));
 
 /**/
-void (*makecomplistcallptr) _((Compctl));
+int (*makecomplistcallptr) _((Compctl));
 
 /**/
 int (*makecomplistctlptr) _((int));
@@ -96,14 +99,29 @@ int incompfunc;
 /**/
 long compcurrent,
      compnmatches,
-     compmatcher;
+     compmatcher,
+     compmatchertot;
 
 /**/
-char *compcontext,
-     *compcommand,
+char **compwords,
      *compprefix,
      *compsuffix,
-     *compiprefix;
+     *compiprefix,
+     *compmatcherstr,
+     *compcontext,
+     *compparameter,
+     *compredirect,
+     *compquote,
+     *compquoting,
+     *comprestore,
+     *complist,
+     *compinsert,
+     *compexact,
+     *compexactstr,
+     *comppatmatch;
+
+/**/
+Param *comppms;
 
 /* The function rembslash() came from zle_tricky.c, but is now used *
  * in compctl.c, too.                                               */
@@ -154,6 +172,7 @@ freecompctl(Compctl cc)
     zsfree(cc->glob);
     zsfree(cc->str);
     zsfree(cc->func);
+    zsfree(cc->widget);
     zsfree(cc->explain);
     zsfree(cc->ylist);
     zsfree(cc->prefix);
@@ -408,9 +427,14 @@ setup_comp1(Module m)
     cc_first.refc = 10000;
     cc_first.mask = 0;
     cc_first.mask2 = CC_CCCONT;
-    compcontext = compcommand = compprefix = compsuffix =
-	compiprefix = NULL;
+    comppms = NULL;
+    compwords = NULL;
+    compprefix = compsuffix = compiprefix = compmatcherstr = 
+	compcontext = compparameter = compredirect = compquote =
+	compquoting = comprestore = complist = compinsert =
+	compexact = compexactstr = comppatmatch = NULL;
     makecompparamsptr = NULL;
+    comp_setunsetptr = NULL;
     return 0;
 }
 
@@ -437,11 +461,22 @@ finish_comp1(Module m)
     deletehashtable(compctltab);
     zfree(clwords, clwsize * sizeof(char *));
     compctlreadptr = fallback_compctlread;
-    zsfree(compcontext);
-    zsfree(compcommand);
+    freearray(compwords);
     zsfree(compprefix);
-    zsfree(compiprefix);
     zsfree(compsuffix);
+    zsfree(compiprefix);
+    zsfree(compmatcherstr);
+    zsfree(compcontext);
+    zsfree(compparameter);
+    zsfree(compredirect);
+    zsfree(compquote);
+    zsfree(compquoting);
+    zsfree(comprestore);
+    zsfree(complist);
+    zsfree(compinsert);
+    zsfree(compexact);
+    zsfree(compexactstr);
+    zsfree(comppatmatch);
     return 0;
 }
 
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 278006b6a..35b63e7d3 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -13,12 +13,27 @@ compcommand
 compcontext
 compctltab
 compcurrent
+compexact
+compexactstr
+compinsert
 compiprefix
+complist
 compmatcher
+compmatcherstr
+compmatchertot
 compnmatches
+compparameter
+comppatmatch
+comppms
 compprefix
+compredirect
+compquote
+compquoting
+comprestore
+comp_setunsetptr
 comp_strptr
 compsuffix
+compwords
 freecmatcher
 freecmlist
 freecompcond
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index f71d67510..b5c8e4b3f 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -140,7 +140,7 @@ get_gmatcher(char *name, char **argv)
 	while (*argv) {
 	    if ((m = parse_cmatcher(name, *argv)) == pcm_err)
 		return 2;
-	    *q = n = (Cmlist) halloc(sizeof(struct cmlist));
+	    *q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    n->next = NULL;
 	    n->matcher = m;
 	    n->str = *argv++;
@@ -578,6 +578,19 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl)
 		    *argv = "" - 1;
 		}
 		break;
+	    case 'i':
+		if ((*argv)[1]) {
+		    cct.widget = (*argv) + 1;
+		    *argv = "" - 1;
+		} else if (!argv[1]) {
+		    zwarnnam(name, "function name expected after -%c", NULL,
+			    **argv);
+		    return 1;
+		} else {
+		    cct.widget = *++argv;
+		    *argv = "" - 1;
+		}
+		break;
 	    case 'Y':
 		cct.mask |= CC_EXPANDEXPL;
 		goto expl;
@@ -1197,6 +1210,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     zsfree(cc->glob);
     zsfree(cc->str);
     zsfree(cc->func);
+    zsfree(cc->widget);
     zsfree(cc->explain);
     zsfree(cc->ylist);
     zsfree(cc->prefix);
@@ -1217,6 +1231,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     cc->glob = ztrdup(cct->glob);
     cc->str = ztrdup(cct->str);
     cc->func = ztrdup(cct->func);
+    cc->widget = ztrdup(cct->widget);
     cc->explain = ztrdup(cct->explain);
     cc->ylist = ztrdup(cct->ylist);
     cc->prefix = ztrdup(cct->prefix);
@@ -1423,6 +1438,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
 	printif(cc->gname, 'J');
     printif(cc->keyvar, 'k');
     printif(cc->func, 'K');
+    printif(cc->widget, 'i');
     printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X');
     printif(cc->ylist, 'y');
     printif(cc->prefix, 'P');
@@ -1644,7 +1660,7 @@ bin_compctl(char *name, char **argv, char *ops, int func)
 
 /**/
 static int
-bin_complist(char *name, char **argv, char *ops, int func)
+bin_compgen(char *name, char **argv, char *ops, int func)
 {
     Compctl cc;
     int ret = 0;
@@ -1663,7 +1679,7 @@ bin_complist(char *name, char **argv, char *ops, int func)
 	zerrnam(name, "command names illegal", NULL, 0);
 	ret = 1;
     } else
-	makecomplistcallptr(cc);
+	ret = makecomplistcallptr(cc);
 
     freecompctl(cc);
     return ret;
@@ -1677,7 +1693,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     char *ipre = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
     char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
     char *ign = NULL, *rf = NULL, *expl = NULL;
-    int f = 0, a = 0, dm;
+    int f = 0, a = CAF_MATCH, dm;
     Cmatcher match = NULL;
 
     if (incompfunc != 1) {
@@ -1710,7 +1726,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		f |= CMF_NOLIST;
 		break;
 	    case 'U':
-		a |= CAF_MENU;
+		a &= ~CAF_MATCH;
 		break;
 	    case 'P':
 		sp = &pre;
@@ -1749,9 +1765,6 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	    case 'a':
 		a |= CAF_ALT;
 		break;
-	    case 'm':
-		a |= CAF_MATCH;
-		break;
 	    case 'M':
 		sp = &m;
 		e = "matching specification expected after -%c";
@@ -1805,11 +1818,11 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	return 1;
 
     match = cpcmatcher(match);
-    addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
-		  rs, rf, ign, f, a, match, expl, argv);
+    a = addmatchesptr(ipre, ppre, psuf, prpre, pre, suf, group,
+		      rs, rf, ign, f, a, match, expl, argv);
     freecmatcher(match);
 
-    return 0;
+    return a;
 }
 
 /**/
@@ -1824,34 +1837,54 @@ bin_compcall(char *name, char **argv, char *ops, int func)
 			      (ops['D'] ? 0 : CFN_DEFAULT));
 }
 
+/* Definitions for the special parameters. Note that these have to match the
+ * order of the CP_* bits in comp.h */
+
 #define VAR(X) ((void *) (&(X)))
 static struct compparam {
     char *name;
     int type;
     void *var;
 } compparams[] = {
+    { "words", PM_ARRAY, VAR(compwords) },
     { "CURRENT", PM_INTEGER, VAR(compcurrent) },
-    { "CONTEXT", PM_SCALAR, VAR(compcontext) },
-    { "COMMAND", PM_SCALAR, VAR(compcommand) },
     { "PREFIX", PM_SCALAR, VAR(compprefix) },
     { "SUFFIX", PM_SCALAR, VAR(compsuffix) },
     { "IPREFIX", PM_SCALAR, VAR(compiprefix) },
-    { "NMATCHES", PM_INTEGER, VAR(compnmatches) },
-    { "MATCHER", PM_INTEGER, VAR(compmatcher) },
+    { NULL, 0, NULL },
+
+    { "nmatches", PM_INTEGER, VAR(compnmatches) },
+    { "matcher", PM_INTEGER, VAR(compmatcher) },
+    { "matcher_string", PM_SCALAR, VAR(compmatcherstr) },
+    { "total_matchers", PM_INTEGER, VAR(compmatchertot) },
+    { "context", PM_SCALAR, VAR(compcontext) },
+    { "parameter", PM_SCALAR, VAR(compparameter) },
+    { "redirect", PM_SCALAR, VAR(compredirect) },
+    { "quote", PM_SCALAR, VAR(compquote) },
+    { "quoting", PM_SCALAR, VAR(compquoting) },
+    { "restore", PM_SCALAR, VAR(comprestore) },
+    { "list", PM_SCALAR, VAR(complist) },
+    { "insert", PM_SCALAR, VAR(compinsert) },
+    { "exact", PM_SCALAR, VAR(compexact) },
+    { "exact_string", PM_SCALAR, VAR(compexactstr) },
+    { "pattern_match", PM_SCALAR, VAR(comppatmatch) },
     { NULL, 0, NULL }
 };
 
-/**/
-void makecompparams(void)
+#define COMPSTATENAME "compstate"
+
+static struct compparam *
+addcompparams(struct compparam *cp)
 {
-    struct compparam *cp;
+    Param *pp = comppms + (cp - compparams);
 
-    for (cp = compparams; cp->name; cp++) {
+    for (; cp->name; cp++, pp++) {
 	Param pm = createparam(cp->name, cp->type | PM_SPECIAL|PM_REMOVABLE);
 	if (!pm)
 	    pm = (Param) paramtab->getnode(paramtab, cp->name);
-	DPUTS(!pm, "param not set in makecompparams");
+	DPUTS(!pm, "param not set in addcompparams");
 
+	*pp = pm;
 	pm->level = locallevel;
 	pm->u.data = cp->var;
 	switch(PM_TYPE(cp->type)) {
@@ -1862,18 +1895,115 @@ void makecompparams(void)
 	case PM_INTEGER:
 	    pm->sets.ifn = intvarsetfn;
 	    pm->gets.ifn = intvargetfn;
+	    pm->ct = 10;
+	    break;
+	case PM_ARRAY:
+	    pm->sets.afn = arrvarsetfn;
+	    pm->gets.afn = arrvargetfn;
 	    break;
 	}
 	pm->unsetfn = compunsetfn;
     }
+    return cp;
+}
+
+/**/
+void
+makecompparams(void)
+{
+    struct compparam *cp;
+    Param cpm;
+    HashTable tht;
+
+    cp = addcompparams(compparams);
+
+    if (!(cpm = createparam(COMPSTATENAME, PM_SPECIAL|PM_REMOVABLE|PM_HASHED)))
+	cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME);
+    DPUTS(!cpm, "param not set in makecompparams");
+
+    comppms[cp - compparams] = cpm;
+    tht = paramtab;
+    cpm->level = locallevel;
+    cpm->gets.hfn = get_compstate;
+    cpm->sets.hfn = set_compstate;
+    cpm->unsetfn = compunsetfn;
+    cpm->u.hash = paramtab = newparamtable(17, COMPSTATENAME);
+    addcompparams(cp + 1);
+    paramtab = tht;
+}
+
+/**/
+static HashTable
+get_compstate(Param pm)
+{
+    return pm->u.hash;
+}
+
+/**/
+static void
+set_compstate(Param pm, HashTable ht)
+{
+    struct compparam *cp;
+    Param *pp;
+    HashNode hn;
+    int i;
+    struct value v;
+    char *str;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next)
+	    for (cp = compparams + CP_REALPARAMS,
+		 pp = comppms + CP_REALPARAMS; cp->name; cp++, pp++)
+		if (!strcmp(hn->nam, cp->name)) {
+		    v.isarr = v.inv = v.a = 0;
+		    v.b = -1;
+		    v.arr = NULL;
+		    v.pm = (Param) hn;
+		    if (cp->type == PM_INTEGER)
+			*((long *) cp->var) = getintvalue(&v);
+		    else if ((str = getstrvalue(&v))) {
+			zsfree(*((char **) cp->var));
+			*((char **) cp->var) = ztrdup(str);
+		    }
+		    (*pp)->flags &= ~PM_UNSET;
+
+		    break;
+		}
 }
 
 /**/
 static void
 compunsetfn(Param pm, int exp)
 {
-    if (exp)
-	stdunsetfn(pm, exp);
+    if (exp) {
+	if (PM_TYPE(pm->flags) == PM_SCALAR) {
+	    zsfree(*((char **) pm->u.data));
+	    *((char **) pm->u.data) = ztrdup("");
+	} else if (PM_TYPE(pm->flags) == PM_ARRAY) {
+	    freearray(*((char ***) pm->u.data));
+	    *((char ***) pm->u.data) = zcalloc(sizeof(char *));
+	}
+	pm->flags |= PM_UNSET;
+    }
+}
+
+/**/
+void
+comp_setunset(int set, int unset)
+{
+    Param *p;
+
+    if (!comppms)
+	return;
+
+    set &= CP_ALLMASK;
+    unset &= CP_ALLMASK;
+    for (p = comppms; set || unset; set >>= 1, unset >>= 1, p++) {
+	if (set & 1)
+	    (*p)->flags &= ~PM_UNSET;
+	if (unset & 1)
+	    (*p)->flags |= PM_UNSET;
+    }
 }
 
 /**/
@@ -1883,29 +2013,51 @@ comp_wrapper(List list, FuncWrap w, char *name)
     if (incompfunc != 1)
 	return 1;
     else {
-	char *octxt, *ocmd, *opre, *osuf, *oipre;
+	char *orest, *opre, *osuf, *oipre, **owords;
 	long ocur;
-
+	int unset = 0, m, sm;
+	Param *pp;
+
+	m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
+	    CP_IPREFIX | CP_RESTORE;
+	for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
+	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
+		unset |= sm;
+	}
+	orest = comprestore;
+	comprestore = ztrdup("auto");
 	ocur = compcurrent;
-	octxt = dupstring(compcontext);
-	ocmd = dupstring(compcommand);
 	opre = dupstring(compprefix);
 	osuf = dupstring(compsuffix);
 	oipre = dupstring(compiprefix);
 
+	HEAPALLOC {
+	    owords = arrdup(compwords);
+	} LASTALLOC;
+
 	runshfunc(list, w, name);
 
-	compcurrent = ocur;
-	zsfree(compcontext);
-	compcontext = ztrdup(octxt);
-	zsfree(compcommand);
-	compcommand = ztrdup(ocmd);
-	zsfree(compprefix);
-	compprefix = ztrdup(opre);
-	zsfree(compsuffix);
-	compsuffix = ztrdup(osuf);
-	zsfree(compiprefix);
-	compiprefix = ztrdup(oipre);
+	if (comprestore && !strcmp(comprestore, "auto")) {
+	    compcurrent = ocur;
+	    zsfree(compprefix);
+	    compprefix = ztrdup(opre);
+	    zsfree(compsuffix);
+	    compsuffix = ztrdup(osuf);
+	    zsfree(compiprefix);
+	    compiprefix = ztrdup(oipre);
+	    freearray(compwords);
+	    PERMALLOC {
+		compwords = arrdup(owords);
+	    } LASTALLOC;
+	    comp_setunset(CP_COMPSTATE |
+			  (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
+				     CP_SUFFIX | CP_IPREFIX | CP_RESTORE)),
+			  unset);
+	} else
+	    comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE),
+			  (unset & CP_RESTORE));
+	zsfree(comprestore);
+	comprestore = orest;
 
 	return 0;
     }
@@ -1942,20 +2094,14 @@ comp_check(void)
 static void
 restrict_range(int b, int e)
 {
-    int i = e - b;
+    int i = e - b + 1;
     char **p = (char **) zcalloc((i + 1) * sizeof(char *)), **q, **pp;
 
-    for (q = p, pp = pparams + b + 1; i; i--, q++, pp++)
+    for (q = p, pp = compwords + b; i; i--, q++, pp++)
 	*q = ztrdup(*pp);
-    zsfree(compcommand);
-    compcommand = ztrdup(pparams[b]);
-    freearray(pparams);
-    pparams = p;
-    zsfree(compcontext);
-    if ((compcurrent -= b + 1))
-	compcontext = ztrdup("argument");
-    else
-	compcontext = ztrdup("command");
+    freearray(compwords);
+    compwords = p;
+    compcurrent -= b;
 }
 
 /**/
@@ -1988,7 +2134,7 @@ cond_position(char **a, int id)
 {
     if (comp_check()) {
 	int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : b);
-	int l = arrlen(pparams), t, i = compcurrent - 1;
+	int l = arrlen(compwords), t, i = compcurrent - 1;
 
 	if (b > 0)
 	    b--;
@@ -2018,7 +2164,7 @@ cond_word(char **a, int id)
 {
     if (comp_check()) {
 	int o = ((id & 2) ? compcurrent : 0) + cond_val(a, 0);
-	int l = arrlen(pparams);
+	int l = arrlen(compwords);
 	char *s;
 
 	if (o < 0)
@@ -2028,7 +2174,7 @@ cond_word(char **a, int id)
 	if (o < 0 || o >= l)
 	    return 0;
 
-	s = pparams[o];
+	s = compwords[o];
 	return ((id & 1) ? cond_match(a, 1, s) : !strcmp(s, cond_str(a, 1)));
     }
     return 0;
@@ -2068,7 +2214,7 @@ cond_words(char **a, int id)
 {
     if (comp_check()) {
 	int b = cond_val(a, 0), e = (a[1] ? cond_val(a, 1) : -1);
-	int l = arrlen(pparams);
+	int l = arrlen(compwords);
 
 	return (l >= b && l <= e);
     }
@@ -2081,7 +2227,7 @@ cond_range(char **a, int id)
 {
     if (comp_check()) {
 	char *s, **p;
-	int i, l = arrlen(pparams), t = 0, b = 0, e = l - 1;
+	int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1;
 	Comp c;
 
 	i = compcurrent - 1;
@@ -2095,7 +2241,7 @@ cond_range(char **a, int id)
 	} else
 	    s = cond_str(a, 0);
 
-	for (i--, p = pparams + i; i >= 0; p--, i--) {
+	for (i--, p = compwords + i; i >= 0; p--, i--) {
 	    if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
 		b = i + 1;
 		t = 1;
@@ -2112,7 +2258,7 @@ cond_range(char **a, int id)
 	    } else
 		s = cond_str(a, 1);
 
-	    for (i++, p = pparams + i; i < l; p++, i++) {
+	    for (i++, p = compwords + i; i < l; p++, i++) {
 		if (((id & 1) ? domatch(*p, c, 0) : !strcmp(*p, s))) {
 		    e = i - 1;
 		    tt = 1;
@@ -2151,7 +2297,7 @@ cond_matcher(char **a, int id)
 
 static struct builtin bintab[] = {
     BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL),
-    BUILTIN("complist", 0, bin_complist, 1, -1, 0, NULL, NULL),
+    BUILTIN("compgen", 0, bin_compgen, 1, -1, 0, NULL, NULL),
     BUILTIN("compadd", 0, bin_compadd, 0, -1, 0, NULL, NULL),
     BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL),
 };
@@ -2185,6 +2331,7 @@ setup_compctl(Module m)
 {
     compctltab->printnode = printcompctlp;
     makecompparamsptr = makecompparams;
+    comp_setunsetptr = comp_setunset;
     return 0;
 }
 
@@ -2217,6 +2364,7 @@ finish_compctl(Module m)
 {
     compctltab->printnode = NULL;
     makecompparamsptr = NULL;
+    comp_setunsetptr = NULL;
     return 0;
 }
 
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index a4b3866e5..2def5f03a 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -653,7 +653,7 @@ get_isrch_spot(int num, int *hlp, int *posp, int *csp, int *lenp, int *dirp, int
 static void
 doisearch(int dir)
 {
-    char *s, *ibuf = halloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR;
+    char *s, *ibuf = zhalloc(80), *sbuf = ibuf + FIRST_SEARCH_CHAR;
     int sbptr = 0, top_spot = 0, pos, sibuf = 80;
     int nomatch = 0, skip_line = 0, skip_pos = 0;
     int odir = dir, sens = zmult == 1 ? 3 : 1;
@@ -936,7 +936,7 @@ static int visrchsense;
 static int
 getvisrchstr(void)
 {
-    char *sbuf = halloc(80);
+    char *sbuf = zhalloc(80);
     int sptr = 1, ret = 0, ssbuf = 80;
     Thingy cmd;
     char *okeymap = curkeymapname;
@@ -1001,7 +1001,7 @@ getvisrchstr(void)
 	    }
 	  ins:
 	    if(sptr == ssbuf - 1) {
-		char *newbuf = halloc(ssbuf *= 2);
+		char *newbuf = zhalloc(ssbuf *= 2);
 		strcpy(newbuf, sbuf);
 		statusline = sbuf = newbuf;
 	    }
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 277d154a6..97d012f7b 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -154,10 +154,14 @@ zsetterm(void)
 #  ifdef OXTABS
     ti.tio.c_oflag &= ~OXTABS;
 #  else
+#   ifdef XTABS
     ti.tio.c_oflag &= ~XTABS;
+#   endif
 #  endif
 # endif
+#ifdef ONLCR
     ti.tio.c_oflag |= ONLCR;
+#endif
     ti.tio.c_cc[VQUIT] =
 # ifdef VDISCARD
 	ti.tio.c_cc[VDISCARD] =
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index ea8874010..1c25cd7eb 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -567,7 +567,7 @@ makequote(char *str, size_t *len)
 	if (*l == '\'')
 	    qtct++;
     *len += 2 + qtct*3;
-    l = ol = (char *)halloc(*len);
+    l = ol = (char *)zhalloc(*len);
     *l++ = '\'';
     for (; str < end; str++)
 	if (*str == '\'') {
@@ -613,7 +613,7 @@ executenamedcommand(char *prmt)
     char *okeymap = curkeymapname;
 
     clearlist = 1;
-    cmdbuf = halloc(l + NAMLEN + 2);
+    cmdbuf = zhalloc(l + NAMLEN + 2);
     strcpy(cmdbuf, prmt);
     statusline = cmdbuf;
     selectkeymap("main", 1);
@@ -794,7 +794,7 @@ makeparamsuffix(int br, int n)
     if(br) {
 	suffixlen['#'] = suffixlen['%'] = suffixlen['?'] = n;
 	suffixlen['-'] = suffixlen['+'] = suffixlen['='] = n;
-	/*{*/ suffixlen['}'] = n;
+	/*{*/ suffixlen['}'] = suffixlen['/'] = n;
     }
 }
 
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 7e15d3d8b..2a35ac416 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -67,6 +67,8 @@ static struct zleparam {
         zleunsetfn, NULL },
     { "keys", PM_ARRAY | PM_READONLY, NULL, FN(get_keys),
         zleunsetfn, NULL },
+    { "NUMERIC", PM_INTEGER | PM_READONLY, FN(set_numeric), FN(get_numeric),
+        zleunsetfn, NULL },
     { NULL, 0, NULL, NULL, NULL, NULL }
 };
 
@@ -97,6 +99,7 @@ makezleparams(int ro)
 	    case PM_INTEGER:
 		pm->sets.ifn = (void (*) _((Param, long))) zp->setfn;
 		pm->gets.ifn = (long (*) _((Param))) zp->getfn;
+		pm->ct = 10;
 		break;
 	}
 	pm->unsetfn = zp->unsetfn;
@@ -225,9 +228,9 @@ get_keys(Param pm)
 {
     char **r, **q, *p, *k, c;
 
-    r = (char **) halloc((strlen(keybuf) + 1) * sizeof(char *));
+    r = (char **) zhalloc((strlen(keybuf) + 1) * sizeof(char *));
     for (q = r, p = keybuf; (c = *p); q++, p++) {
-	k = *q = (char *) halloc(5);
+	k = *q = (char *) zhalloc(5);
 	if (c & 0x80) {
 	    *k++ = 'M';
 	    *k++ = '-';
@@ -244,3 +247,17 @@ get_keys(Param pm)
 
     return r;
 }
+
+/**/
+static void
+set_numeric(Param pm, long x)
+{
+    zmult = x;
+}
+
+/**/
+static long
+get_numeric(Param pm)
+{
+    return zmult;
+}
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 9e07676e8..b9f39b70b 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -266,7 +266,11 @@ zrefresh(void)
 
 /* Nov 96: <mason>  I haven't checked how complete this is.  sgtty stuff may
    or may not work */
+#if defined(SGTABTYPE)
     oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE);
+#else
+    oxtabs = 0;
+#endif
 
     cleareol = 0;		/* unset */
     more_start = more_end = 0;	/* unset */
@@ -615,7 +619,7 @@ refreshline(int ln)
     if (cleareol 		/* request to clear to end of line */
 	|| !nllen 		/* no line buffer given */
 	|| (ln == 0 && (put_rpmpt != oput_rpmpt))) {	/* prompt changed */
-	p1 = halloc(winw + 2);
+	p1 = zhalloc(winw + 2);
 	if (nllen)
 	    strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', winw - nllen);
@@ -627,7 +631,7 @@ refreshline(int ln)
 	    nl = p1;		/* don't keep the padding for prompt line */
 	nllen = winw;
     } else if (ollen > nllen) { /* make new line at least as long as old */
-	p1 = halloc(ollen + 1);
+	p1 = zhalloc(ollen + 1);
 	strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', ollen - nllen);
 	p1[ollen] = '\0';
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 4b42640e1..f01ffbf1c 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -73,9 +73,10 @@ static int wb, we;
 static int offs;
 
 /* These control the type of completion that will be done.  They are    *
- * affected by the choice of ZLE command and by relevant shell options. */
+ * affected by the choice of ZLE command and by relevant shell options. *
+ * usemenu is set to 2 if we have to start automenu.                    */
 
-static int usemenu, useglob;
+static int usemenu, useglob, useexact, useline, uselist;
 
 /* != 0 if we are in the middle of a menu completion */
 
@@ -125,7 +126,7 @@ static int validlist;
 
 /* This flag is non-zero if we are completing a pattern (with globcomplete) */
 
-static int ispattern;
+static int ispattern, haspattern;
 
 /* Two patterns used when doing glob-completion.  The first one is built *
  * from the whole word we are completing and the second one from that    *
@@ -168,12 +169,6 @@ static int addwhat;
 
 static char *qword;
 
-/* This is non-zero if we are doing a menu-completion and this is not the *
- * first call (e.g. when automenu is set and menu-completion was entered  *
- * due to this). */
-
-static int amenu;
-
 /* The current group of matches. */
 
 static Cmgroup mgroup;
@@ -322,7 +317,7 @@ completecall(void)
 void
 completeword(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (c == '\t' && usetab())
 	selfinsert();
@@ -351,7 +346,7 @@ menucomplete(void)
 void
 listchoices(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     docomplete(COMP_LIST_COMPLETE);
 }
@@ -371,7 +366,7 @@ deletecharorlist(void)
     Cmgroup mg = menugrp;
     Cmatch *mc = menucur;
 
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (cs != ll) {
 	fixsuffix();
@@ -398,7 +393,7 @@ expandword(void)
 void
 expandorcomplete(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     if (c == '\t' && usetab())
 	selfinsert();
@@ -427,7 +422,7 @@ menuexpandorcomplete(void)
 void
 listexpand(void)
 {
-    usemenu = isset(MENUCOMPLETE);
+    usemenu = !!isset(MENUCOMPLETE);
     useglob = isset(GLOBCOMPLETE);
     docomplete(COMP_LIST_EXPAND);
 }
@@ -492,9 +487,9 @@ acceptandmenucomplete(void)
 }
 
 /* These are flags saying if we are completing in the command *
- * position or in a redirection.                              */
+ * position, in a redirection, or in a parameter expansion.   */
 
-static int lincmd, linredir;
+static int lincmd, linredir, ispar;
 
 /* The string for the redirection operator. */
 
@@ -513,10 +508,10 @@ static char *varname;
 
 static int insubscr;
 
-/* 1 if we are completing in a string */
+/* 1 if we are completing in a quoted string (or inside `...`) */
 
 /**/
-int instring;
+int instring, inbackt;
 
 /* Convenience macro for calling bslashquote() (formerly quotename()). *
  * This uses the instring variable above.                              */
@@ -601,6 +596,87 @@ cmphaswilds(char *str)
     return 0;
 }
 
+/* Check if we have to complete a parameter name. */
+
+static char *
+check_param(char *s, int set)
+{
+    char *p;
+
+    ispar = 0;
+    /* Try to find a `$'. */
+    for (p = s + offs; p > s && *p != String; p--);
+    if (*p == String) {
+	/* Handle $$'s */
+	while (p > s && p[-1] == String)
+	    p--;
+	while (p[1] == String && p[2] == String)
+	    p += 2;
+    }
+    if (*p == String &&	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;
+
+	if (*b == Inbrace) {
+	    /* If this is a ${...}, ignore the possible (...) flags. */
+	    b++, br++;
+	    n = skipparens(Inpar, Outpar, &b);
+	}
+
+	/* Ignore the stuff before the parameter name. */
+	for (; *b; b++)
+	    if (*b != '^' && *b != Hat &&
+		*b != '=' && *b != Equals &&
+		*b != '~' && *b != Tilde)
+		break;
+	if (*b == '#' || *b == Pound || *b == '+')
+	    b++;
+
+	e = b;
+	/* Find the end of the name. */
+	if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
+	    *e == '?'   || *e == '*'  || *e == '$'    ||
+	    *e == '-'   || *e == '!'  || *e == '@')
+	    e++;
+	else if (idigit(*e))
+	    while (idigit(*e))
+		e++;
+	else if (iident(*e))
+	    while (iident(*e) ||
+		   (comppatmatch && *comppatmatch &&
+		    (*e == Star || *e == Quest)))
+		e++;
+
+	/* Now make sure that the cursor is inside the name. */
+	if (offs <= e - s && offs >= b - s && n <= 0) {
+	    /* It is. */
+	    /* If we were called from makecomplistflags(), we have to set the
+	     * global variables. */
+	    if (set) {
+		if (br >= 2)
+		    mflags |= CMF_PARBR;
+
+		/* Get the prefix (anything up to the character before the name). */
+		lpsuf = dupstring(quotename(e, NULL, NULL, NULL));
+		*e = '\0';
+		lpsl = strlen(lpsuf);
+		ripre = dupstring(s);
+		ripre[b - s] = '\0';
+		ipre = dupstring(quotename(ripre, NULL, NULL, NULL));
+		untokenize(ipre);
+	    }
+	    /* And adjust wb, we, and offs again. */
+	    offs -= b - s;
+	    wb = cs - offs;
+	    we = wb + e - b;
+	    ispar = (br >= 2 ? 2 : 1);
+	    return b;
+	}
+    }
+    return NULL;
+}
+
 /* The main entry point for completion. */
 
 /**/
@@ -625,9 +701,9 @@ docomplete(int lst)
 
     /* Check if we have to start a menu-completion (via automenu). */
 
-    if ((amenu = (isset(AUTOMENU) && lastambig &&
-		  (!isset(BASHAUTOLIST) || lastambig == 2))))
-	usemenu = 1;
+    if (isset(AUTOMENU) && lastambig &&
+	(!isset(BASHAUTOLIST) || lastambig == 2))
+	usemenu = 2;
 
     /* Expand history references before starting completion.  If anything *
      * changed, do no more.                                               */
@@ -910,7 +986,7 @@ addx(char **ptmp)
 	(instring && (line[cs] == '"' || line[cs] == '\'')) ||
 	(addspace = (comppref && !iblank(line[cs])))) {
 	*ptmp = (char *)line;
-	line = (unsigned char *)halloc(strlen((char *)line) + 3 + addspace);
+	line = (unsigned char *)zhalloc(strlen((char *)line) + 3 + addspace);
 	memcpy(line, *ptmp, cs);
 	line[cs] = 'x';
 	if (addspace)
@@ -999,6 +1075,7 @@ get_comp_string(void)
 	else if (*p == '\\' && p[1] && !(k & 1))
 	    p++;
     instring = (j & 1) ? 2 : (k & 1);
+    inbackt = (i & 1);
     addx(&tmp);
     if (instring) {
 	/* Yes, we are in a string. */
@@ -1010,7 +1087,7 @@ get_comp_string(void)
 	 * What??  Why that??  Well, we want to be able to complete *
 	 * inside strings.  The lexer code gives us no help here,   *
 	 * so we have to cheat.  We remove the quotes, the lexer    *
-	 * will than treat the words in the strings normally and we *
+	 * will then treat the words in the strings normally and we *
 	 * can complete them.                                       *
 	 * This is completely the wrong thing to do, but it's       *
 	 * occasionally useful, and we can't handle quotes properly *
@@ -1551,7 +1628,7 @@ getcline(char *l, int ll, char *w, int wl, int fl)
     if ((r = freecl))
 	freecl = r->next;
     else
-	r = (Cline) halloc(sizeof(*r));
+	r = (Cline) zhalloc(sizeof(*r));
 
     r->next = NULL;
     r->line = l;
@@ -1626,7 +1703,7 @@ add_bmatchers(Cmatcher m)
     for (; m; m = m->next) {
 	if ((!m->flags && m->wlen > 0 && m->llen > 0) ||
 	    (m->flags == CMF_RIGHT && m->wlen == -1 && !m->llen)) {
-	    *q = n = (Cmlist) halloc(sizeof(struct cmlist));
+	    *q = n = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    n->matcher = m;
 	    q = &(n->next);
 	}
@@ -1796,7 +1873,7 @@ join_strs(int la, char *sa, int lb, char *sb)
 	    if (!t)
 		break;
 	} else {
-	    if (rr <= mp->llen) {
+	    if (rr <= 1) {
 		char *or = rs;
 
 		rs = realloc(rs, (rl += 20));
@@ -1850,7 +1927,7 @@ join_ends(Cline o, Cline n, int *olp, int *nlp)
 	} else {
 	    /* Different anchors, see if we can find matching anchors
 	     * further down the lists. */
-	    Cline to, tn;
+	    Cline to, tn = NULL;
 	    int t = 0;
 
 	    /* But first build the common prefix. */
@@ -3337,6 +3414,7 @@ match_pfx(char *l, char *w, Cline *nlp, int *lp, Cline *rlp, int *bplp)
 	}
     }
     while (ll && lw) {
+	t = 0;
 	/* First try the matchers. */
 	for (ms = mstack; ms; ms = ms->next) {
 	    for (mp = ms->matcher; mp; mp = mp->next) {
@@ -3578,6 +3656,7 @@ match_sfx(char *l, char *w, Cline *nlp, int *lp, int *bslp)
 	}
     }
     while (ll && lw) {
+	t = 0;
 	for (ms = mstack; ms; ms = ms->next) {
 	    for (mp = ms->matcher; mp; mp = mp->next) {
 		if (lm == mp)
@@ -3774,7 +3853,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl
 		 * in the cline struct in the middle. */
 		pml = strlen(p);
 		sml = strlen(s);
-		r = (char *) halloc(pml + sml + last->llen + 1);
+		r = (char *) zhalloc(pml + sml + last->llen + 1);
 		strcpy(r, p);
 		strncpy(r + pml, last->line, last->llen);
 		strcpy(r + pml + last->llen, s);
@@ -3824,7 +3903,7 @@ comp_match(char *pfx, char *sfx, char *w, Cline *clp, int qu, int *bpl, int *bsl
 static void
 inststrlen(char *str, int move, int len)
 {
-    if (!len)
+    if (!len || !str)
 	return;
     if (len == -1)
 	len = strlen(str);
@@ -3902,30 +3981,28 @@ instmatch(Cmatch m)
  * the matches. */
 
 /**/
-void
+int
 addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 	   char *suf, char *group, char *rems, char *remf, char *ign,
 	   int flags, int aflags, Cmatcher match, char *exp, char **argv)
 {
-    char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre, *lsuf, **aign = NULL;
-    int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl, llsl;
-    Aminfo ai;
+    char *s, *t, *e, *me, *ms, *lipre = NULL, *lpre = NULL, *lsuf = NULL;
+    char **aign = NULL;
+    int lpl, lsl, i, pl, sl, test, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
+    Aminfo ai = NULL;
     Cline lc = NULL;
-    LinkList l;
+    LinkList l = NULL;
     Cmatch cm;
     struct cmlist mst;
     Cmlist oms = mstack;
-
-    /* Use menu-completion (-U)? */
-    if ((aflags & CAF_MENU) && isset(AUTOMENU))
-	usemenu = 1;
+    Comp cp = NULL;
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
 	    if (exp) {
-		expl = (Cexpl) halloc(sizeof(struct cexpl));
+		expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
 		expl->str = dupstring(exp);
 	    } else
@@ -3954,9 +4031,30 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 	    if (aflags & CAF_MATCH) {
 		lipre = dupstring(compiprefix);
 		lpre = dupstring(compprefix);
-		llpl = strlen(lpre);
 		lsuf = dupstring(compsuffix);
+		llpl = strlen(lpre);
 		llsl = strlen(lsuf);
+		/* Test if there is an existing -P prefix. */
+		if (pre && *pre) {
+		    pl = pfxlen(pre, lpre);
+		    llpl -= pl;
+		    lpre += pl;
+		}
+		if (comppatmatch && *comppatmatch) {
+		    char *tmp = (char *) zhalloc(2 + llpl + llsl);
+
+		    strcpy(tmp, lpre);
+		    tmp[llpl] = 'x';
+		    strcpy(tmp + llpl + 1, lsuf);
+
+		    tokenize(tmp);
+		    remnulargs(tmp);
+		    if (haswilds(tmp)) {
+			tmp[llpl] = Star;
+			if ((cp = parsereg(tmp)))
+			    haspattern = 1;
+		    }
+		}
 	    }
 	    /* Now duplicate the strings we have from the command line. */
 	    if (ipre)
@@ -3973,50 +4071,71 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		lsl = strlen(psuf);
 	    } else
 		lsl = 0;
-	    if (pre)
-		pre = dupstring(pre);
-	    if (suf)
-		suf = dupstring(suf);
-	    if (!prpre && (prpre = ppre)) {
-		singsub(&prpre);
-		untokenize(prpre);
-	    } else
-		prpre = dupstring(prpre);
-	    /* Select the group in which to store the matches. */
-	    if (group) {
-		endcmgroup(NULL);
-		begcmgroup(group, (aflags & CAF_NOSORT));
-		if (aflags & CAF_NOSORT)
-		    mgroup->flags |= CGF_NOSORT;
-	    } else {
-		endcmgroup(NULL);
-		begcmgroup("default", 0);
-	    }
-	    /* Select the set of matches. */
-	    if (aflags & CAF_ALT) {
-		l = fmatches;
-		ai = fainfo;
-	    } else {
-		l = matches;
-		ai = ainfo;
+	    if (aflags & CAF_MATCH) {
+		s = ppre ? ppre : "";
+		if (llpl <= lpl && strpfx(lpre, s)) {
+		    llpl = 0;
+		    lpre = "";
+		} else if (llpl > lpl && strpfx(s, lpre)) {
+		    llpl -= lpl;
+		    lpre += lpl;
+		} else
+		    *argv = NULL;
+		s = psuf ? psuf : "";
+		if (llsl <= lsl && strsfx(lsuf, s)) {
+		    llsl = 0;
+		    lsuf = "";
+		} else if (llsl > lsl && strsfx(s, lsuf)) {
+		    lsuf[llsl - lsl] = '\0';
+		    llsl -= lsl;
+		} else
+		    *argv = NULL;
 	    }
-	    if (remf) {
-		remf = dupstring(remf);
-		rems = NULL;
-	    } else if (rems)
-		rems = dupstring(rems);
-	    /* Build the common -P prefix. */
-    	    if (ai->pprefix) {
+	    if (*argv) {
 		if (pre)
-		    ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
-		else
-		    ai->pprefix[0] = '\0';
-	    } else
-		ai->pprefix = dupstring(pre ? pre : "");
-
+		    pre = dupstring(pre);
+		if (suf)
+		    suf = dupstring(suf);
+		if (!prpre && (prpre = ppre)) {
+		    singsub(&prpre);
+		    untokenize(prpre);
+		} else
+		    prpre = dupstring(prpre);
+		/* Select the group in which to store the matches. */
+		if (group) {
+		    endcmgroup(NULL);
+		    begcmgroup(group, (aflags & CAF_NOSORT));
+		    if (aflags & CAF_NOSORT)
+			mgroup->flags |= CGF_NOSORT;
+		} else {
+		    endcmgroup(NULL);
+		    begcmgroup("default", 0);
+		}
+		/* Select the set of matches. */
+		if (aflags & CAF_ALT) {
+		    l = fmatches;
+		    ai = fainfo;
+		} else {
+		    l = matches;
+		    ai = ainfo;
+		}
+		if (remf) {
+		    remf = dupstring(remf);
+		    rems = NULL;
+		} else if (rems)
+		    rems = dupstring(rems);
+		/* Build the common -P prefix. */
+		if (ai->pprefix) {
+		    if (pre)
+			ai->pprefix[pfxlen(ai->pprefix, pre)] = '\0';
+		    else
+			ai->pprefix[0] = '\0';
+		} else
+		    ai->pprefix = dupstring(pre ? pre : "");
+	    }
 	    /* Walk through the matches given. */
 	    for (; (s = dupstring(*argv)); argv++) {
-		sl = strlen(s);
+		sl = pl = strlen(s);
 		lc = NULL;
 		ms = NULL;
 		bpl = brpl;
@@ -4042,19 +4161,26 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		}
 		if (aflags & CAF_MATCH) {
 		    /* Do the matching. */
-		    test = (sl >= llpl + llsl &&
-			    strpfx(lpre, s) && strsfx(lsuf, s));
-		    if (!test && mstack &&
-			(ms = comp_match(lpre, lsuf, s,
-					 &lc, (aflags & CAF_QUOTE),
-					 &bpl, &bsl)))
-			test = 1;
-
-		    if (!test)
-			continue;
-		    pl = sl - llsl;
-		    me = s + sl - llsl;
-		    e = s + llpl;
+		    if (cp) {
+			if ((test = domatch(s, cp, 0)))
+			    e = me = s + sl;
+			else
+			    continue;
+		    } else {
+			test = (sl >= llpl + llsl &&
+				strpfx(lpre, s) && strsfx(lsuf, s));
+			if (!test && mstack &&
+			    (ms = comp_match(lpre, lsuf, s,
+					     &lc, (aflags & CAF_QUOTE),
+					     &bpl, &bsl)))
+			    test = 1;
+
+			if (!test)
+			    continue;
+			pl = sl - llsl;
+			me = s + sl - llsl;
+			e = s + llpl;
+		    }
 		} else {
 		    e = s;
 		    me = s + sl;
@@ -4072,14 +4198,15 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		if (!ms) {
 		    if (sl < ai->minlen)
 			ai->minlen = sl;
-		    if (!mstack && ai->firstm &&
+		    if (!cp && !mstack && ai->firstm &&
 			(i = sfxlen(ai->firstm->str, s)) < ai->suflen)
 			ai->suflen = i;
 		}
 		t = s;
 		if (ppre)
 		    t = dyncat(ppre, t);
-		if (!ms && mstack) {
+		lc = NULL;
+		if (!cp && !ms && (mstack || psuf)) {
 		    int bl = ((aflags & CAF_MATCH) ? llpl : 0);
 		    Cline *clp = &lc, tlc;
 		    char *ss = dupstring(s), *ee = me + (ss - s);
@@ -4109,7 +4236,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 			clp = &(tlc->next);
 		    }
 		    *clp = NULL;
-		} else if (mstack) {
+		} else if (!cp && mstack) {
 		    Cline tlc;
 
 		    if (ppre && *ppre) {
@@ -4148,7 +4275,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		    lc = tlc;
 		} else
 		    ai->iprefix = "";
-		if (!ms && !mstack) {
+		if (!ms && !mstack && !lc) {
 		    if ((aflags & CAF_MATCH) || ai->cpl > pl)
 			ai->cpl = pl;
 		    if ((aflags & CAF_MATCH) || ai->csl > lsl)
@@ -4164,12 +4291,12 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		ai->count++;
 
 		/* Finally add the match. */
-		cm = (Cmatch) halloc(sizeof(struct cmatch));
+		cm = (Cmatch) zhalloc(sizeof(struct cmatch));
 		cm->ppre = ppre;
 		cm->psuf = psuf;
 		cm->prpre = prpre;
 		cm->str = (ms ? ms : dupstring(s));
-		cm->ipre = cm->ripre = ipre;
+		cm->ipre = cm->ripre = (ipre && *ipre ? ipre : NULL);
 		cm->pre = pre;
 		cm->suf = suf;
 		cm->flags = flags;
@@ -4179,7 +4306,7 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		cm->rems = rems;
 		addlinknode(l, cm);
 
-		if (expl) {
+		if (exp) {
 		    if (l == matches)
 			expl->count++;
 		    else
@@ -4188,12 +4315,24 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
 		if (!ms) {
 		    if (!ai->firstm)
 			ai->firstm = cm;
-		    if ((aflags & CAF_MATCH) && !(e - (s + pl))) {
-			if (!ai->exact)
+		    if (!cp && (aflags & CAF_MATCH) && !(e - (s + pl))) {
+			if (!ai->exact) {
 			    ai->exact = 1;
-			else {
+			    zsfree(compexactstr);
+			    compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1);
+			    if (ppre) {
+				strcpy(e, ppre);
+				e += lpl;
+			    }
+			    strcpy(e, s);
+			    e += sl;
+			    if (psuf)
+				strcpy(e, psuf);
+			    comp_setunsetptr(CP_EXACTSTR, 0);
+			} else {
 			    ai->exact = 2;
 			    cm = NULL;
+			    comp_setunsetptr(0, CP_EXACTSTR);
 			}
 			ai->exactm = cm;
 		    }
@@ -4208,6 +4347,8 @@ addmatches(char *ipre, char *ppre, char *psuf, char *prpre, char *pre,
     /* We switched back to the current heap, now restore the stack of
      * matchers. */
     mstack = oms;
+
+    return (mnum == nm);
 }
 
 /* This adds a match to the list of matches.  The string to add is given   *
@@ -4252,6 +4393,7 @@ addmatch(char *s, char *t)
 
     if (incompfunc)
 	s = dupstring(s);
+    e = s + sl;
     if (!addwhat) {
 	test = 1;
     } else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
@@ -4318,7 +4460,7 @@ addmatch(char *s, char *t)
 		e += s - t;
 	    }
 	    if (cc) {
-		tt = (char *)halloc(lppl + lpsl + sl + 1);
+		tt = (char *)zhalloc(lppl + lpsl + sl + 1);
 		tt[0] = '\0';
 		if (lppre)
 		    strcpy(tt, lppre);
@@ -4353,7 +4495,7 @@ addmatch(char *s, char *t)
 		 (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) ||
 		  ((addwhat & CC_EXCMDS)  && !(hn->flags & DISABLED)))) ||
 		((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) {
-	if (sl >= rpl + rsl || mstack) {
+	if (sl >= rpl + rsl || mstack || cp) {
 	    if (cp) {
 		test = domatch(s, patcomp, 0);
 		e = s + sl;
@@ -4413,7 +4555,7 @@ addmatch(char *s, char *t)
     t = s;
     if (lppre)
 	t = dyncat(lppre, t);
-    if (!ms && mstack) {
+    if (!ispattern && !ms && mstack) {
 	Cline *clp = &lc, tlc;
 	char *ss = dupstring(s), *ee = e + (ss - s);
 
@@ -4481,7 +4623,7 @@ addmatch(char *s, char *t)
     ai->count++;
 
     /* Allocate and fill the match structure. */
-    cm = (Cmatch) halloc(sizeof(struct cmatch));
+    cm = (Cmatch) zhalloc(sizeof(struct cmatch));
     if (ispattern) {
 	if (lpsuf && *lpsuf && strsfx(lpsuf, s)) {
 	    s[sl - lpsl] = '\0';
@@ -4532,11 +4674,29 @@ addmatch(char *s, char *t)
 
 	/* Do we have an exact match? More than one? */
 	if (!ispattern && !(e - (s + pl))) {
-	    if (!ai->exact)
+	    if (!ai->exact) {
 		ai->exact = 1;
-	    else {
+		if (incompfunc) {
+		    int lpl = (cm->ppre ? strlen(cm->ppre) : 0);
+		    int lsl = (cm->psuf ? strlen(cm->psuf) : 0);
+
+		    zsfree(compexactstr);
+		    compexactstr = e = (char *) zalloc(lpl + sl + lsl + 1);
+		    if (cm->ppre) {
+			strcpy(e, cm->ppre);
+			e += lpl;
+		    }
+		    strcpy(e, s);
+		    e += sl;
+		    if (cm->psuf)
+			strcpy(e, cm->psuf);
+		    comp_setunsetptr(CP_EXACTSTR, 0);
+		}
+	    } else {
 		ai->exact = 2;
 		cm = NULL;
+		if (incompfunc)
+		    comp_setunsetptr(0, CP_EXACTSTR);
 	    }
 	    ai->exactm = cm;
 	}
@@ -4688,7 +4848,6 @@ dumphashtable(HashTable ht, int what)
     for (i = 0; i < ht->hsize; i++)
 	for (hn = ht->nodes[i]; hn; hn = hn->next)
 	    addmatch(hn->nam, (char *) hn);
-
 }
 
 /* ScanFunc used by maketildelist() et al. */
@@ -4797,7 +4956,7 @@ gen_matches_files(int dirs, int execs, int all)
 			strcpy(p + o, psuf);
 
 			/* Do we have to use globbing? */
-			if (ispattern || (ns && isset(GLOBCOMPLETE))) {
+			if (ispattern || (ns && comppatmatch && *comppatmatch)) {
 			    /* Yes, so append a `*' if needed. */
 			    if (ns) {
 				int tl = strlen(p);
@@ -4847,6 +5006,15 @@ docompletion(char *s, int lst, int incmd)
 	ainfo = fainfo = NULL;
 	matchers = newlinklist();
 
+	useline = (lst != COMP_LIST_COMPLETE);
+	useexact = (isset(RECEXACT) && usemenu != 1);
+	uselist = (useline ?
+		   ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? 
+		    (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1);
+	zsfree(comppatmatch);
+	comppatmatch = ztrdup(useglob ? "yes" : "");
+	haspattern = 0;
+
 	/* Make sure we have the completion list and compctl. */
 	if (makecomplist(s, incmd, lst)) {
 	    /* Error condition: feeeeeeeeeeeeep(). */
@@ -4854,23 +5022,26 @@ docompletion(char *s, int lst, int incmd)
 	    clearlist = 1;
 	    goto compend;
 	}
-	if (lst == COMP_LIST_COMPLETE)
+	if (!useline && uselist)
 	    /* All this and the guy only wants to see the list, sigh. */
 	    showinglist = -2;
-	else {
+	else if (useline) {
 	    /* We have matches. */
 	    if (nmatches > 1)
-		/* There are more than one match. */
+		/* There is more than one match. */
 		do_ambiguous();
 
 	    else if (nmatches == 1) {
 		/* Only one match. */
-		while (!amatches->mcount)
-		    amatches = amatches->next;
-		do_single(amatches->matches[0]);
+		Cmgroup m = amatches;
+
+		while (!m->mcount)
+		    m = m->next;
+		do_single(m->matches[0]);
 		invalidatelist();
 	    }
-	}
+	} else
+	    invalidatelist();
 
 	/* Print the explanation strings if needed. */
 	if (!showinglist && validlist && nmatches != 1) {
@@ -4928,33 +5099,47 @@ callcompfunc(char *s, char *fn)
     int lv = lastval;
     
     if ((list = getshfunc(fn)) != &dummy_list) {
-	LinkList args = newlinklist();
 	char **p, *tmp;
-	int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
-	
-	addlinknode(args, fn);
-	
+	int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	Param *ocpms = comppms;
+
+	comppms = (Param *) zalloc(CP_NUM * sizeof(Param));
+
+	set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
+		     CP_EXACTSTR | (useglob ? 0 : CP_PATMATCH));
 	zsfree(compcontext);
-	zsfree(compcommand);
-	compcommand = "";
-	if (inwhat == IN_MATH) {
+	zsfree(compparameter);
+	zsfree(compredirect);
+	compparameter = compredirect = "";
+	if (ispar)
+	    compcontext = (ispar == 2 ? "brace_parameter" : "parameter");
+	else if (inwhat == IN_MATH) {
 	    if (insubscr) {
 		compcontext = "subscript";
-		compcommand = varname ? varname : "";
+		if (varname) {
+		    compparameter = varname;
+		    set |= CP_PARAMETER;
+		}
 	    } else
 		compcontext = "math";
 	    usea = 0;
-	} else if (lincmd)
-	    compcontext = (insubscr ? "subscript" : "command");
-	else if (linredir) {
+	} else if (lincmd) {
+	    if (insubscr) {
+		compcontext = "subscript";
+		set |= CP_PARAMETER;
+	    } else
+		compcontext = "command";
+	} else if (linredir) {
 	    compcontext = "redirect";
 	    if (rdstr)
-		compcommand = rdstr;
+		compredirect = rdstr;
+	    set |= CP_REDIRECT;
 	} else
 	    switch (inwhat) {
 	    case IN_ENV:
-		compcontext = "value";
-		compcommand = varname;
+		compcontext = "array_value";
+		compparameter = varname;
+		set |= CP_PARAMETER;
 		if (!clwpos) {
 		    clwpos = 1;
 		    zsfree(clwords[1]);
@@ -4966,61 +5151,141 @@ callcompfunc(char *s, char *fn)
 		compcontext = "condition";
 		break;
 	    default:
-		if (cmdstr) {
-		    compcontext = "argument";
-		    compcommand = cmdstr;
-		} else {
+		if (cmdstr)
+		    compcontext = "command";
+		else {
 		    compcontext = "value";
+		    set |= CP_PARAMETER;
 		    if (clwords[0])
-			compcommand = clwords[0];
+			compparameter = clwords[0];
+		    aadd = 1;
 		}
-		aadd = 1;
 	    }
 	compcontext = ztrdup(compcontext);
-	tmp = quotename(compcommand, NULL, NULL, NULL);
-	untokenize(tmp);
-	compcommand = ztrdup(tmp);
-	if (usea && (!aadd || clwords[0]))
-	    for (p = clwords + aadd; *p; p++) {
-		tmp = dupstring(*p);
-		untokenize(tmp);
-		addlinknode(args, tmp);
+	if (compwords)
+	    freearray(compwords);
+	if (usea && (!aadd || clwords[0])) {
+	    char **q;
+
+	    PERMALLOC {
+		q = compwords = (char **)
+		    zalloc((clwnum - aadd + 1) * sizeof(char *));
+		for (p = clwords + aadd; *p; p++, q++) {
+		    tmp = dupstring(*p);
+		    untokenize(tmp);
+		    *q = ztrdup(tmp);
+		}
+		*q = NULL;
+	    } LASTALLOC;
+	} else
+	    compwords = (char **) zcalloc(sizeof(char *));
+
+	compparameter = ztrdup(compparameter);
+	compredirect = ztrdup(compredirect);
+	zsfree(compquote);
+	zsfree(compquoting);
+	if (instring) {
+	    if (instring == 1) {
+		compquote = ztrdup("\'");
+		compquoting = ztrdup("single");
+	    } else {
+		compquote = ztrdup("\"");
+		compquoting = ztrdup("double");
 	    }
+	    set |= CP_QUOTE | CP_QUOTING;
+	} else if (inbackt) {
+	    compquote = ztrdup("`");
+	    compquoting = ztrdup("backtick");
+	} else {
+	    compquote = ztrdup("");
+	    compquoting = ztrdup("");
+	}
+	untokenize(s = dupstring(s));
 	zsfree(compprefix);
 	zsfree(compsuffix);
 	if (unset(COMPLETEINWORD)) {
-	    tmp = quotename(s, NULL, NULL, NULL);
-	    untokenize(tmp);
-	    compprefix = ztrdup(tmp);
+	    compprefix = ztrdup(s);
 	    compsuffix = ztrdup("");
 	} else {
 	    char *ss = s + offs, sav;
-	    
-	    tmp = quotename(s, &ss, NULL, NULL);
+
 	    sav = *ss;
 	    *ss = '\0';
-	    untokenize(tmp);
-	    compprefix = ztrdup(tmp);
+	    compprefix = ztrdup(s);
 	    *ss = sav;
-	    untokenize(ss);
 	    compsuffix = ztrdup(ss);
 	}
 	zsfree(compiprefix);
 	compiprefix = ztrdup("");
-	compcurrent = (usea ? (clwpos + 1 - aadd) : 1);
+	compcurrent = (usea ? (clwpos + 1 - aadd) : 0);
 	compnmatches = mnum;
+
+	zsfree(complist);
+	switch (uselist) {
+	case 0: complist = ""; set &= ~CP_LIST; break;
+	case 1: complist = "list"; break;
+	case 2: complist = "autolist"; break;
+	case 3: complist = "ambiguous"; break;
+	}
+	complist = ztrdup(complist);
+	zsfree(compinsert);
+	if (useline) {
+	    switch (usemenu) {
+	    case 0: compinsert = "unambiguous"; break;
+	    case 1: compinsert = "menu"; break;
+	    case 2: compinsert = "automenu"; break;
+	    }
+	} else {
+	    compinsert = "";
+	    set &= ~CP_INSERT;
+	}
+	compinsert = ztrdup(compinsert);
+	if (useexact)
+	    compexact = ztrdup("accept");
+	else {
+	    compexact = ztrdup("");
+	    set &= ~CP_EXACT;
+	}
 	incompfunc = 1;
 	startparamscope();
 	makecompparamsptr();
+	comp_setunsetptr(set, ~set);
 	makezleparams(1);
 	sfcontext = SFC_CWIDGET;
 	NEWHEAPS(compheap) {
-	    doshfunc(fn, list, args, 0, 1);
+	    doshfunc(fn, list, NULL, 0, 1);
 	} OLDHEAPS;
 	sfcontext = osc;
 	endparamscope();
 	lastcmd = 0;
 	incompfunc = icf;
+
+	if (!complist)
+	    uselist = 0;
+	else if (!strcmp(complist, "list"))
+	    uselist = 1;
+	else if (!strcmp(complist, "auto") || !strcmp(complist, "autolist"))
+	    uselist = 2;
+	else if (!strcmp(complist, "ambig") || !strcmp(complist, "ambiguous"))
+	    uselist = 3;
+	else
+	    uselist = 0;
+	if (!compinsert)
+	    useline = 0;
+	else if (!strcmp(compinsert, "unambig") ||
+		 !strcmp(compinsert, "unambiguous"))
+	    useline = 1, usemenu = 0;
+	else if (!strcmp(compinsert, "menu"))
+	    useline = 1, usemenu = 1;
+	else if (!strcmp(compinsert, "auto") ||
+		 !strcmp(compinsert, "automenu"))
+	    useline = 1, usemenu = 2;
+	else
+	    useline = usemenu = 0;
+	useexact = (compexact && !strcmp(compexact, "accept"));
+
+	zfree(comppms, CP_NUM * sizeof(Param));
+	comppms = ocpms;
     }
     lastval = lv;
 }
@@ -5047,7 +5312,11 @@ makecomplist(char *s, int incmd, int lst)
 {
     struct cmlist ms;
     Cmlist m;
-    char *os = s;
+    char *p, *os = s;
+
+    /* Inside $... ? */
+    if ((p = check_param(s, 0)))
+	os = s = p;
 
     /* We build a copy of the list of matchers to use to make sure that this
      * works even if a shell function called from the completion code changes
@@ -5055,22 +5324,27 @@ makecomplist(char *s, int incmd, int lst)
 
     if ((m = cmatcher)) {
 	Cmlist mm, *mp = &mm;
+	int n;
 
-	for (; m; m = m->next) {
-	    *mp = (Cmlist) halloc(sizeof(struct cmlist));
+	for (n = 0; m; m = m->next, n++) {
+	    *mp = (Cmlist) zhalloc(sizeof(struct cmlist));
 	    (*mp)->matcher = m->matcher;
 	    (*mp)->next = NULL;
+	    (*mp)->str = dupstring(m->str);
 	    mp = &((*mp)->next);
 	    addlinknode(matchers, m->matcher);
 	    m->matcher->refc++;
 	}
 	m = mm;
-    }
-    compmatcher = 1;
+	compmatcher = 1;
+	compmatchertot = n;
+    } else
+	compmatcher = 0;
 
     /* Walk through the global matchers. */
     for (;;) {
 	bmatchers = NULL;
+	zsfree(compmatcherstr);
 	if (m) {
 	    ms.next = NULL;
 	    ms.matcher = m->matcher;
@@ -5080,9 +5354,11 @@ makecomplist(char *s, int incmd, int lst)
 	     * when building new parts for the string to insert into the 
 	     * line. */
 	    add_bmatchers(m->matcher);
-	} else
+	    compmatcherstr = ztrdup(m->str);
+	} else {
 	    mstack = NULL;
-
+	    compmatcherstr = ztrdup("");
+	}
 	ainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
 	fainfo = (Aminfo) hcalloc(sizeof(struct aminfo));
 
@@ -5140,33 +5416,6 @@ makecomplist(char *s, int incmd, int lst)
 /* This should probably be moved into tokenize(). */
 
 /**/
-static char *
-ctokenize(char *p)
-{
-    char *r = p;
-    int bslash = 0;
-
-    tokenize(p);
-
-    for (p = r; *p; p++) {
-	if (*p == '\\')
-	    bslash = 1;
-	else {
-	    if (*p == '$' || *p == '=' || *p == '{' || *p == '}') {
-		if (bslash)
-		    p[-1] = Bnull;
-		else
-		    *p = (*p == '$' ? String :
-			  (*p == '=' ? Equals :
-			   (*p == '{' ? Inbrace : Outbrace)));
-	    }
-	    bslash = 0;
-	}
-    }
-    return r;
-}
-
-/**/
 char *
 comp_str(int *ipl, int *pl, int untok)
 {
@@ -5177,17 +5426,17 @@ comp_str(int *ipl, int *pl, int untok)
     int lp, ls, lip;
 
     if (!untok) {
-	ctokenize(p);
+	tokenize(p);
 	remnulargs(p);
-	ctokenize(s);
+	tokenize(s);
 	remnulargs(s);
-	ctokenize(ip);
+	tokenize(ip);
 	remnulargs(ip);
     }
     ls = strlen(s);
     lip = strlen(ip);
     lp = strlen(p);
-    str = halloc(lip + lp + ls + 1);
+    str = zhalloc(lip + lp + ls + 1);
     strcpy(str, ip);
     strcat(str, p);
     strcat(str, s);
@@ -5201,9 +5450,11 @@ comp_str(int *ipl, int *pl, int untok)
 }
 
 /**/
-void
+int
 makecomplistcall(Compctl cc)
 {
+    int nm = mnum;
+
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
 	    int ooffs = offs, lip, lp;
@@ -5217,6 +5468,8 @@ makecomplistcall(Compctl cc)
 	    compnmatches = mnum;
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
+
+    return (mnum == nm);
 }
 
 /* A simple counter to avoid endless recursion between old and new style *
@@ -5243,24 +5496,20 @@ makecomplistctl(int flags)
 	    char *os = cmdstr, **ow = clwords, **p, **q;
 	    int on = clwnum, op = clwpos;
 
-	    clwnum = arrlen(pparams) + 1;
+	    clwnum = arrlen(compwords);
 	    clwpos = compcurrent - 1;
-	    cmdstr = ztrdup(compcommand);
+	    cmdstr = ztrdup(compwords[0]);
 	    clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
-	    clwords[0] = ztrdup(cmdstr);
-	    for (p = pparams, q = clwords + 1; *p; p++, q++) {
+	    for (p = compwords, q = clwords; *p; p++, q++) {
 		t = dupstring(*p);
-		ctokenize(t);
+		tokenize(t);
 		remnulargs(t);
 		*q = ztrdup(t);
 	    }
 	    *q = NULL;
 	    offs = lip + lp;
 	    incompfunc = 2;
-	    ret = makecomplistglobal(str,
-				     (!clwpos &&
-				      !strcmp(compcontext, "command")),
-				     COMP_COMPLETE, flags);
+	    ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags);
 	    incompfunc = 1;
 	    offs = ooffs;
 	    compnmatches = mnum;
@@ -5499,7 +5748,7 @@ makecomplistext(Compctl occ, char *os, int incmd)
     Compcond or, cc;
     Comp comp;
     int compadd, m = 0, d = 0, t, tt, i, j, a, b;
-    char *sc, *s, *ss;
+    char *sc = NULL, *s, *ss;
 
     /* This loops over the patterns separated by `-'s. */
     for (compc = occ->ext; compc; compc = compc->next) {
@@ -5669,7 +5918,7 @@ findnode(LinkList list, void *dat)
 static void
 makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 {
-    int t, sf1, sf2, ooffs, um = usemenu, delit, ispar = 0;
+    int t, sf1, sf2, ooffs, um = usemenu, delit, oaw;
     char *p, *sd = NULL, *tt, *s1, *s2, *os =  dupstring(s);
     struct cmlist ms;
 
@@ -5678,6 +5927,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (incompfunc != 1 && findnode(ccstack, cc))
 	return;
 
+    MUSTUSEHEAP("complistflags");
+
     addlinknode(ccstack, cc);
 
     if (incompfunc != 1 && allccs) {
@@ -5711,7 +5962,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (cc->mask2 & CC_NOSORT)
 	mgroup->flags |= CGF_NOSORT;
     if (cc->explain) {
-	expl = (Cexpl) halloc(sizeof(struct cexpl));
+	expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 	expl->count = expl->fcount = 0;
     }
     else
@@ -5781,79 +6032,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    s[suffixll - sl] = '\0';
     }
     /* Do we have one of the special characters `~' and `=' at the beginning? */
-    if ((ic = *s) != Tilde && ic != Equals)
+    if (incompfunc || ((ic = *s) != Tilde && ic != Equals))
 	ic = 0;
 
     /* Check if we have to complete a parameter name... */
-
-    /* Try to find a `$'. */
-    for (p = s + offs; p > s && *p != String; p--);
-    if (*p == String) {
-	/* Handle $$'s */
-	while (p > s && p[-1] == String)
-	    p--;
-	while (p[1] == String && p[2] == String)
-	    p += 2;
-    }
-    if (*p == String &&	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;
-
-	if (*b == Inbrace) {
-	    /* If this is a ${...}, ignore the possible (...) flags. */
-	    b++, br++;
-	    n = skipparens(Inpar, Outpar, &b);
-	}
-
-	/* Ignore the stuff before the parameter name. */
-	for (; *b; b++)
-	    if (*b != '^' && *b != Hat &&
-		*b != '=' && *b != Equals &&
-		*b != '~' && *b != Tilde)
-		break;
-	if (*b == '#' || *b == Pound || *b == '+')
-	    b++;
-
-	e = b;
-	/* Find the end of the name. */
-	if (*e == Quest || *e == Star || *e == String || *e == Qstring ||
-	    *e == '?'   || *e == '*'  || *e == '$'    ||
-	    *e == '-'   || *e == '!'  || *e == '@')
-	    e++;
-	else if (idigit(*e))
-	    while (idigit(*e))
-		e++;
-	else if (iident(*e))
-	    while (iident(*e) ||
-		   (useglob && (*e == Star || *e == Quest)))
-		e++;
-
-	/* Now make sure that the cursor is inside the name. */
-	if (offs <= e - s && offs >= b - s && n <= 0) {
-	    /* It is. */
-	    if (br >= 2)
-		mflags |= CMF_PARBR;
-
-	    /* Get the prefix (anything up to the character before the name). */
-	    lpsuf = dupstring(quotename(e, NULL, NULL, NULL));
-	    *e = '\0';
-	    lpsl = strlen(lpsuf);
-	    ripre = dupstring(s);
-	    ripre[b - s] = '\0';
-	    ipre = dupstring(quotename(ripre, NULL, NULL, NULL));
-	    untokenize(ipre);
-	    ispar = 1;
-	    /* And adjust wb, we, and offs again. */
-	    offs -= b - s;
-	    wb = cs - offs;
-	    we = wb + e - b;
-	    s = b;
-	    /* And now make sure that we complete parameter names. */
-	    cc = &cc_dummy;
-	    cc_dummy.refc = 10000;
-	    cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
-	}
+    if (!incompfunc && (p = check_param(s, 1))) {
+	s = p;
+	/* And now make sure that we complete parameter names. */
+	cc = &cc_dummy;
+	cc_dummy.refc = 10000;
+	cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
     }
     ooffs = offs;
     /* If we have to ignore the word, do that. */
@@ -5861,12 +6049,13 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	delit = 1;
 	*s = '\0';
 	offs = 0;
-	if (isset(AUTOMENU)) usemenu = 1;
+	if (isset(AUTOMENU))
+	    usemenu = 1;
     }
 
     /* Compute line prefix/suffix. */
     lpl = offs;
-    lpre = halloc(lpl + 1);
+    lpre = zhalloc(lpl + 1);
     memcpy(lpre, s, lpl);
     lpre[lpl] = '\0';
     lsuf = dupstring(s + offs);
@@ -5905,6 +6094,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    if (!s1)
 		s1 = p;
 	}
+    rsl = strlen(rsuf);
     for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++)
 	if (itok(*p))
 	    t |= sf2 ? 4 : 2;
@@ -5917,7 +6107,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
     /* But if we were asked not to do glob completion, we never treat the *
      * thing as a pattern.                                                */
-    if (!useglob)
+    if (!comppatmatch || !*comppatmatch)
 	ispattern = 0;
 
     if (ispattern) {
@@ -5930,6 +6120,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	} else
 	    strcpy(p + rpl, rsuf);
 	patcomp = parsereg(p);
+	haspattern = 1;
     }
     if (!patcomp) {
 	untokenize(rpre);
@@ -5963,6 +6154,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    line[cs] = 0;
 	    lppre = dupstring((char *) (line + wb));
 	    line[cs] = save;
+	    if (brbeg && *brbeg)
+		strcpy(lppre + brpl, lppre + brpl + strlen(brbeg));
 	    if ((p = strrchr(lppre, '/'))) {
 		p[1] = '\0';
 		lppl = strlen(lppre);
@@ -5979,8 +6172,14 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    char save = line[we];
 
 	    line[we] = 0;
-	    lpsuf = strchr(dupstring((char *) (line + cs)), '/');
+	    lpsuf = dupstring((char *) (line + cs));
 	    line[we] = save;
+	    if (brend && *brend) {
+		char *p = lpsuf + brsl - (cs - wb);
+
+		strcpy(p, p + strlen(brend));
+	    }
+	    lpsuf = strchr(lpsuf, '/');
 	    lpsl = (lpsuf ? strlen(lpsuf) : 0);
 	}
 	else {
@@ -5994,7 +6193,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	/* And the suffix. */
 	fsuf = dupstrpfx(rsuf, s2 - rsuf);
 
-	if (useglob && (ispattern & 2)) {
+	if (comppatmatch && *comppatmatch && (ispattern & 2)) {
 	    int t2;
 
 	    /* We have to use globbing, so compute the pattern from *
@@ -6079,10 +6278,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 		    if ((pp = get_user_var(cc->withd))) {
 			dirs = npp =
-			    (char**) halloc(sizeof(char *)*(arrlen(pp)+1));
+			    (char**) zhalloc(sizeof(char *)*(arrlen(pp)+1));
 			while (*pp) {
 			    pl = strlen(*pp);
-			    tp = (char *) halloc(strlen(*pp) + tl);
+			    tp = (char *) zhalloc(strlen(*pp) + tl);
 			    strcpy(tp, *pp);
 			    tp[pl] = '/';
 			    strcpy(tp + pl + 1, ppre);
@@ -6098,7 +6297,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 			char *tp;
 			int pl = strlen(cc->withd);
 
-			ta[0] = tp = (char *) halloc(strlen(ppre) + pl + 2);
+			ta[0] = tp = (char *) zhalloc(strlen(ppre) + pl + 2);
 			strcpy(tp, cc->withd);
 			tp[pl] = '/';
 			strcpy(tp + pl + 1, ppre);
@@ -6270,7 +6469,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	if (isset(AUTOCD) && isset(CDABLEVARS))
 	    dumphashtable(paramtab, -4);
     }
-    addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
+    oaw = addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG;
 
     if (cc->mask & CC_NAMED)
 	/* Add named directories. */
@@ -6278,12 +6477,16 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (cc->mask & CC_OPTIONS)
 	/* Add option names. */
 	dumphashtable(optiontab, addwhat);
-    if (cc->mask & CC_VARS)
+    if (cc->mask & CC_VARS) {
 	/* And parameter names. */
 	dumphashtable(paramtab, -9);
-    if (cc->mask & CC_BINDINGS)
+	addwhat = oaw;
+    }
+    if (cc->mask & CC_BINDINGS) {
 	/* And zle function names... */
 	dumphashtable(thingytab, CC_BINDINGS);
+	addwhat = oaw;
+    }
     if (cc->keyvar) {
 	/* This adds things given to the compctl -k flag *
 	 * (from a parameter or a list of words).        */
@@ -6293,54 +6496,53 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    while (*usr)
 		addmatch(*usr++, NULL);
     }
-    if (cc->mask & CC_USERS)
+    if (cc->mask & CC_USERS) {
 	/* Add user names. */
 	maketildelist();
+	addwhat = oaw;
+    }
+    if (cc->widget)
+	callcompfunc(os, cc->widget);
     if (cc->func) {
-	if (cc->func[0] == ' ')
-	    /* Temporary hack for access to new style completione. */
-	    callcompfunc(os, cc->func + 1);
-	else {
-	    /* This handles the compctl -K flag. */
-	    List list;
-	    char **r;
-	    int lv = lastval;
+	/* This handles the compctl -K flag. */
+	List list;
+	char **r;
+	int lv = lastval;
 	    
-	    /* Get the function. */
-	    if ((list = getshfunc(cc->func)) != &dummy_list) {
-		/* We have it, so build a argument list. */
-		LinkList args = newlinklist();
-		int osc = sfcontext;
-		
-		addlinknode(args, cc->func);
+	/* Get the function. */
+	if ((list = getshfunc(cc->func)) != &dummy_list) {
+	    /* We have it, so build a argument list. */
+	    LinkList args = newlinklist();
+	    int osc = sfcontext;
 		
-		if (delit) {
-		    p = dupstrpfx(os, ooffs);
-		    untokenize(p);
-		    addlinknode(args, p);
-		    p = dupstring(os + ooffs);
-		    untokenize(p);
-		    addlinknode(args, p);
-		} else {
-		    addlinknode(args, lpre);
-		    addlinknode(args, lsuf);
-		}
+	    addlinknode(args, cc->func);
 		
-		/* This flag allows us to use read -l and -c. */
-		if (incompfunc != 1)
-		    incompctlfunc = 1;
-		sfcontext = SFC_COMPLETE;
-		/* Call the function. */
-		doshfunc(cc->func, list, args, 0, 1);
-		sfcontext = osc;
-		incompctlfunc = 0;
-		/* And get the result from the reply parameter. */
-		if ((r = get_user_var("reply")))
-		    while (*r)
-			addmatch(*r++, NULL);
+	    if (delit) {
+		p = dupstrpfx(os, ooffs);
+		untokenize(p);
+		addlinknode(args, p);
+		p = dupstring(os + ooffs);
+		untokenize(p);
+		addlinknode(args, p);
+	    } else {
+		addlinknode(args, lpre);
+		addlinknode(args, lsuf);
 	    }
-	    lastval = lv;
+		
+	    /* This flag allows us to use read -l and -c. */
+	    if (incompfunc != 1)
+		incompctlfunc = 1;
+	    sfcontext = SFC_COMPLETE;
+	    /* Call the function. */
+	    doshfunc(cc->func, list, args, 0, 1);
+	    sfcontext = osc;
+	    incompctlfunc = 0;
+	    /* And get the result from the reply parameter. */
+	    if ((r = get_user_var("reply")))
+		while (*r)
+		    addmatch(*r++, NULL);
 	}
+	lastval = lv;
     }
     if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) {
 	/* Get job names. */
@@ -6378,7 +6580,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	 * get the words we have to expand.                        */
 	zleparse = 1;
 	lexsave();
-	tmpbuf = (char *)halloc(strlen(cc->str) + 5);
+	tmpbuf = (char *)zhalloc(strlen(cc->str) + 5);
 	sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */
 	inpush(tmpbuf, 0, NULL);
 	strinbeg();
@@ -6456,9 +6658,12 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if ((t = cc->mask & CC_BUILTINS))
 	/* Add builtins. */
 	dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
-    if ((t = cc->mask & CC_EXTCMDS))
+    if ((t = cc->mask & CC_EXTCMDS)) {
 	/* Add external commands */
+	if (isset(HASHLISTALL))
+	    cmdnamtab->filltable(cmdnamtab);
 	dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
+    }
     if ((t = cc->mask & CC_RESWDS))
 	/* Add reserved words */
 	dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS)));
@@ -6486,7 +6691,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    for (ln = firstnode(matches); ln; ln = nextnode(ln)) {
 		m = (Cmatch) getdata(ln);
 		if (m->ppre) {
-		    char *p = (char *) halloc(strlen(m->ppre) + strlen(m->str) +
+		    char *p = (char *) zhalloc(strlen(m->ppre) + strlen(m->str) +
 					      strlen(m->psuf) + 1);
 
 		    sprintf(p, "%s%s%s", m->ppre, m->str, m->psuf);
@@ -6654,7 +6859,7 @@ get_user_var(char *nam)
 
 	if ((val = getsparam(nam))) {
 	    arr = (char **)ncalloc(2*sizeof(char *));
-	    arr[0] = val;
+	    arr[0] = (incompfunc ? dupstring(val) : val);
 	    arr[1] = NULL;
 	}
 	return arr;
@@ -6763,7 +6968,10 @@ makearray(LinkList l, int s, int *np, int *nlp)
 	    if ((*ap)->flags & CMF_NOLIST)
 		nl++;
 	*cp = NULL;
-    }
+    } else
+	for (ap = rp; *ap; ap++)
+	    if ((*ap)->flags & CMF_NOLIST)
+		nl++;
     if (np)
 	*np = n;
     if (nlp)
@@ -6795,7 +7003,7 @@ begcmgroup(char *n, int nu)
 	    p = p->next;
 	}
     }
-    mgroup = (Cmgroup) halloc(sizeof(struct cmgroup));
+    mgroup = (Cmgroup) zhalloc(sizeof(struct cmgroup));
     mgroup->name = dupstring(n);
     mgroup->flags = mgroup->lcount = mgroup->mcount = 0;
     mgroup->matches = NULL;
@@ -6858,8 +7066,8 @@ dupmatch(Cmatch m)
     r->ppre = ztrdup(m->ppre);
     r->psuf = ztrdup(m->psuf);
     r->prpre = ztrdup(m->prpre);
-    r->pre = m->pre;
-    r->suf = m->suf;
+    r->pre = ztrdup(m->pre);
+    r->suf = ztrdup(m->suf);
     r->flags = m->flags;
     r->brpl = m->brpl;
     r->brsl = m->brsl;
@@ -6975,6 +7183,8 @@ freematch(Cmatch m)
     zsfree(m->ripre);
     zsfree(m->ppre);
     zsfree(m->psuf);
+    zsfree(m->pre);
+    zsfree(m->suf);
     zsfree(m->prpre);
     zsfree(m->rems);
     zsfree(m->remf);
@@ -7030,15 +7240,14 @@ freematches(void)
 static void
 do_ambiguous(void)
 {
-    int p = (usemenu || ispattern), atend = (cs == we);
+    int p = (usemenu || haspattern), atend = (cs == we);
 
     menucmp = 0;
 
     /* If we have to insert the first match, call do_single().  This is *
      * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
      * completion into an unambiguous one.                              */
-    if (ainfo && ainfo->exact == 1 && isset(RECEXACT) && !(fromcomp & FC_LINE) &&
-	(usemenu == 0 || unset(AUTOMENU))) {
+    if (ainfo && ainfo->exact == 1 && useexact && !(fromcomp & FC_LINE)) {
 	do_single(ainfo->exactm);
 	invalidatelist();
 	return;
@@ -7049,7 +7258,7 @@ do_ambiguous(void)
      * unambiguous prefix.                                               */
     lastambig = 1;
 
-    if(p) {
+    if (p) {
 	/* p is set if we are in a position to start using menu completion *
 	 * due to one of the menu completion options, or due to the        *
 	 * menu-complete-word command, or due to using GLOB_COMPLETE which *
@@ -7152,7 +7361,7 @@ do_ambiguous(void)
 	 * prefix was inserted, return now, bypassing the list-displaying  *
 	 * code.  On the way, invalidate the list and note that we don't   *
 	 * want to enter an AUTO_MENU imediately.                          */
-	if(isset(LISTAMBIGUOUS) && la) {
+	if (uselist == 3 && la) {
 	    int fc = fromcomp;
 
 	    invalidatelist();
@@ -7165,8 +7374,7 @@ do_ambiguous(void)
      * if it is needed.                                                     */
     if (isset(LISTBEEP))
 	feep();
-    if (isset(AUTOLIST) && !isset(BASHAUTOLIST) && !amenu && !showinglist &&
-	smatches >= 2)
+    if (uselist && usemenu != 2 && !showinglist && smatches >= 2)
 	showinglist = -2;
 }
 
@@ -7264,7 +7472,7 @@ do_single(Cmatch m)
 	    struct stat buf;
 
 	    /* Build the path name. */
-	    if (ispattern || ic || m->ripre) {
+	    if (haspattern || ic || m->ripre) {
 		int ne = noerrs;
 
 		noerrs = 1;
@@ -7620,14 +7828,14 @@ listmatches(void)
 	char **pp = g->ylist;
 
 	if ((e = g->expls)) {
-	    if (pnl) {
-		putc('\n', shout);
-		pnl = 0;
-	    }
 	    while (*e) {
 		if ((*e)->count) {
+		    if (pnl) {
+			putc('\n', shout);
+			pnl = 0;
+		    }
 		    printfmt((*e)->str, (*e)->count, 1);
-		    putc('\n', shout);
+		    pnl = 1;
 		}
 		e++;
 	    }
@@ -7670,7 +7878,7 @@ listmatches(void)
 	    }
 	}
 	else if (g->lcount) {
-	    int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a;
+	    int n = g->lcount, nl = (n + ncols - 1) / ncols, nc = nl, i, j, a = 0;
 	    Cmatch *q;
 
 	    if (n && pnl) {
@@ -7691,7 +7899,7 @@ listmatches(void)
 			struct stat buf;
 			char *pb;
 
-			pb = (char *) halloc((m->prpre ? strlen(m->prpre) : 0) +
+			pb = (char *) zhalloc((m->prpre ? strlen(m->prpre) : 0) +
 					     3 + strlen(m->str));
 			sprintf(pb, "%s%s", (m->prpre ? m->prpre : "./"),
 				m->str);
diff --git a/Src/Zle/zle_word.c b/Src/Zle/zle_word.c
index afd860066..f446d1769 100644
--- a/Src/Zle/zle_word.c
+++ b/Src/Zle/zle_word.c
@@ -465,7 +465,7 @@ transposewords(void)
 	    return;
 	}
 	for (p1 = p2; p1 && iword(line[p1 - 1]); p1--);
-	pp = temp = (char *)halloc(p4 - p1 + 1);
+	pp = temp = (char *)zhalloc(p4 - p1 + 1);
 	struncpy(&pp, (char *) line + p3, p4 - p3);
 	struncpy(&pp, (char *) line + p2, p3 - p2);
 	struncpy(&pp, (char *) line + p1, p2 - p1);