about summary refs log tree commit diff
path: root/Src/Zle
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>2000-02-23 15:18:43 +0000
committerTanaka Akira <akr@users.sourceforge.net>2000-02-23 15:18:43 +0000
commit1054071bd60937ae8a9fbc16c1407211c6198a55 (patch)
treed91747424173fe809ec204864df49009874b6282 /Src/Zle
parent2b37049c221501c6ae77e0308634aebcdb10060d (diff)
downloadzsh-1054071bd60937ae8a9fbc16c1407211c6198a55.tar.gz
zsh-1054071bd60937ae8a9fbc16c1407211c6198a55.tar.xz
zsh-1054071bd60937ae8a9fbc16c1407211c6198a55.zip
zsh-workers/9839
Diffstat (limited to 'Src/Zle')
-rw-r--r--Src/Zle/compcore.c1033
-rw-r--r--Src/Zle/compctl.c150
-rw-r--r--Src/Zle/complete.c5
-rw-r--r--Src/Zle/complist.c618
-rw-r--r--Src/Zle/compresult.c88
-rw-r--r--Src/Zle/computil.c226
-rw-r--r--Src/Zle/zle_hist.c8
-rw-r--r--Src/Zle/zle_main.c171
-rw-r--r--Src/Zle/zle_misc.c11
-rw-r--r--Src/Zle/zle_thingy.c4
-rw-r--r--Src/Zle/zle_tricky.c1408
-rw-r--r--Src/Zle/zleparameter.c39
12 files changed, 1822 insertions, 1939 deletions
diff --git a/Src/Zle/compcore.c b/Src/Zle/compcore.c
index 0908fb120..3e4d4c93c 100644
--- a/Src/Zle/compcore.c
+++ b/Src/Zle/compcore.c
@@ -262,167 +262,164 @@ do_completion(Hookdef dummy, Compldat dat)
 {
     int ret = 0, lst = dat->lst, incmd = dat->incmd;
     char *s = dat->s;
+    char *opm;
+    LinkNode n;
 
-    HEAPALLOC {
-	char *opm;
-	LinkNode n;
-
-	pushheap();
-
-	ainfo = fainfo = NULL;
-	matchers = newlinklist();
-
-	zsfree(compqstack);
-	compqstack = ztrdup("\\");
-	if (instring == 2)
-	    compqstack[0] = '"';
-	else if (instring)
-	    compqstack[0] = '\'';
-
-	hasunqu = 0;
-	useline = (lst != COMP_LIST_COMPLETE);
-	useexact = isset(RECEXACT);
-	zsfree(compexactstr);
-	compexactstr = ztrdup("");
-	uselist = (useline ?
-		   ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? 
-		    (isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1);
-	zsfree(comppatmatch);
-	opm = comppatmatch = ztrdup(useglob ? "*" : "");
-	zsfree(comppatinsert);
-	comppatinsert = ztrdup("menu");
-	forcelist = 0;
-	haspattern = 0;
-	complistmax = getiparam("LISTMAX");
-	zsfree(complastprompt);
-	complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
-				 (unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
-				"yes" : "");
-	dolastprompt = 1;
-	zsfree(complist);
-	complist = ztrdup(isset(LISTROWSFIRST) ?
-			  (isset(LISTPACKED) ? "packed rows" : "rows") :
-			  (isset(LISTPACKED) ? "packed" : ""));
-	startauto = isset(AUTOMENU);
-	movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
-	showinglist = 0;
-	hasmatched = 0;
-	minmlen = 1000000;
-	maxmlen = -1;
-
-	/* Make sure we have the completion list and compctl. */
-	if (makecomplist(s, incmd, lst)) {
-	    /* Error condition: feeeeeeeeeeeeep(). */
-	    cs = 0;
-	    foredel(ll);
-	    inststr(origline);
-	    cs = origcs;
-	    clearlist = 1;
-	    ret = 1;
-	    minfo.cur = NULL;
-	    goto compend;
-	}
-	zsfree(lastprebr);
-	zsfree(lastpostbr);
-	lastprebr = lastpostbr = NULL;
-
-	if (comppatmatch && *comppatmatch && comppatmatch != opm)
-	    haspattern = 1;
-	if (!useline && uselist) {
-	    /* All this and the guy only wants to see the list, sigh. */
-	    cs = 0;
-	    foredel(ll);
-	    inststr(origline);
-	    cs = origcs;
-	    showinglist = -2;
-	} else if (useline == 2 && nmatches > 1) {
-	    int first = 1, nm = nmatches;
-	    Cmatch *mc;
+    pushheap();
+
+    ainfo = fainfo = NULL;
+    matchers = newlinklist();
+
+    zsfree(compqstack);
+    compqstack = ztrdup("\\");
+    if (instring == 2)
+	compqstack[0] = '"';
+    else if (instring)
+	compqstack[0] = '\'';
+
+    hasunqu = 0;
+    useline = (lst != COMP_LIST_COMPLETE);
+    useexact = isset(RECEXACT);
+    zsfree(compexactstr);
+    compexactstr = ztrdup("");
+    uselist = (useline ?
+	       ((isset(AUTOLIST) && !isset(BASHAUTOLIST)) ? 
+		(isset(LISTAMBIGUOUS) ? 3 : 2) : 0) : 1);
+    zsfree(comppatmatch);
+    opm = comppatmatch = ztrdup(useglob ? "*" : "");
+    zsfree(comppatinsert);
+    comppatinsert = ztrdup("menu");
+    forcelist = 0;
+    haspattern = 0;
+    complistmax = getiparam("LISTMAX");
+    zsfree(complastprompt);
+    complastprompt = ztrdup(((isset(ALWAYSLASTPROMPT) && zmult == 1) ||
+			     (unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
+			    "yes" : "");
+    dolastprompt = 1;
+    zsfree(complist);
+    complist = ztrdup(isset(LISTROWSFIRST) ?
+		      (isset(LISTPACKED) ? "packed rows" : "rows") :
+		      (isset(LISTPACKED) ? "packed" : ""));
+    startauto = isset(AUTOMENU);
+    movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
+    showinglist = 0;
+    hasmatched = 0;
+    minmlen = 1000000;
+    maxmlen = -1;
+
+    /* Make sure we have the completion list and compctl. */
+    if (makecomplist(s, incmd, lst)) {
+	/* Error condition: feeeeeeeeeeeeep(). */
+	cs = 0;
+	foredel(ll);
+	inststr(origline);
+	cs = origcs;
+	clearlist = 1;
+	ret = 1;
+	minfo.cur = NULL;
+	goto compend;
+    }
+    zsfree(lastprebr);
+    zsfree(lastpostbr);
+    lastprebr = lastpostbr = NULL;
+
+    if (comppatmatch && *comppatmatch && comppatmatch != opm)
+	haspattern = 1;
+    if (!useline && uselist) {
+	/* All this and the guy only wants to see the list, sigh. */
+	cs = 0;
+	foredel(ll);
+	inststr(origline);
+	cs = origcs;
+	showinglist = -2;
+    } else if (useline == 2 && nmatches > 1) {
+	int first = 1, nm = nmatches;
+	Cmatch *mc;
 
-	    menucmp = 1;
-	    menuacc = 0;
+	menucmp = 1;
+	menuacc = 0;
 
-	    for (minfo.group = amatches;
-		 minfo.group && !(minfo.group)->mcount;
-		 minfo.group = (minfo.group)->next);
+	for (minfo.group = amatches;
+	     minfo.group && !(minfo.group)->mcount;
+	     minfo.group = (minfo.group)->next);
 
-	    mc = (minfo.group)->matches;
+	mc = (minfo.group)->matches;
 
-	    while (1) {
-		if (!first)
-		    accept_last();
-		first = 0;
+	while (1) {
+	    if (!first)
+		accept_last();
+	    first = 0;
 
-		if (!--nm)
-		    menucmp = 0;
+	    if (!--nm)
+		menucmp = 0;
 
-		do_single(*mc);
-		minfo.cur = mc;
+	    do_single(*mc);
+	    minfo.cur = mc;
 
-		if (!*++(minfo.cur)) {
-		    do {
-			if (!(minfo.group = (minfo.group)->next))
-			    break;
-		    } while (!(minfo.group)->mcount);
-		    if (!minfo.group)
+	    if (!*++(minfo.cur)) {
+		do {
+		    if (!(minfo.group = (minfo.group)->next))
 			break;
-		    minfo.cur = minfo.group->matches;
-		}
-		mc = minfo.cur;
-	    }
-	    menucmp = 0;
-	    minfo.cur = NULL;
-
-	    if (forcelist)
-		showinglist = -2;
-	    else
-		invalidatelist();
-	} else if (useline) {
-	    /* We have matches. */
-	    if (nmatches > 1) {
-		/* There is more than one match. */
-		ret = do_ambiguous();
-	    } else if (nmatches == 1) {
-		/* Only one match. */
-		Cmgroup m = amatches;
-
-		while (!m->mcount)
-		    m = m->next;
-		minfo.cur = NULL;
-		minfo.asked = 0;
-		do_single(m->matches[0]);
-		if (forcelist) {
-		    if (uselist)
-			showinglist = -2;
-		    else
-			clearlist = 1;
-		} else
-		    invalidatelist();
+		} while (!(minfo.group)->mcount);
+		if (!minfo.group)
+		    break;
+		minfo.cur = minfo.group->matches;
 	    }
-	} else {
-	    invalidatelist();
-	    if (forcelist)
-		clearlist = 1;
-	    cs = 0;
-	    foredel(ll);
-	    inststr(origline);
-	    cs = origcs;
+	    mc = minfo.cur;
 	}
-	/* Print the explanation strings if needed. */
-	if (!showinglist && validlist && usemenu != 2 && nmatches != 1 &&
-	    useline != 2 && (!oldlist || !listshown)) {
-	    onlyexpl = 1;
+	menucmp = 0;
+	minfo.cur = NULL;
+
+	if (forcelist)
 	    showinglist = -2;
+	else
+	    invalidatelist();
+    } else if (useline) {
+	/* We have matches. */
+	if (nmatches > 1) {
+	    /* There is more than one match. */
+	    ret = do_ambiguous();
+	} else if (nmatches == 1) {
+	    /* Only one match. */
+	    Cmgroup m = amatches;
+
+	    while (!m->mcount)
+		m = m->next;
+	    minfo.cur = NULL;
+	    minfo.asked = 0;
+	    do_single(m->matches[0]);
+	    if (forcelist) {
+		if (uselist)
+		    showinglist = -2;
+		else
+		    clearlist = 1;
+	    } else
+		invalidatelist();
 	}
-      compend:
-	for (n = firstnode(matchers); n; incnode(n))
-	    freecmatcher((Cmatcher) getdata(n));
+    } else {
+	invalidatelist();
+	if (forcelist)
+	    clearlist = 1;
+	cs = 0;
+	foredel(ll);
+	inststr(origline);
+	cs = origcs;
+    }
+    /* Print the explanation strings if needed. */
+    if (!showinglist && validlist && usemenu != 2 && nmatches != 1 &&
+	useline != 2 && (!oldlist || !listshown)) {
+	onlyexpl = 1;
+	showinglist = -2;
+    }
+ compend:
+    for (n = firstnode(matchers); n; incnode(n))
+	freecmatcher((Cmatcher) getdata(n));
 
-	ll = strlen((char *)line);
-	if (cs > ll)
-	    cs = ll;
-	popheap();
-    } LASTALLOC;
+    ll = strlen((char *)line);
+    if (cs > ll)
+	cs = ll;
+    popheap();
 
     return ret;
 }
@@ -581,16 +578,11 @@ callcompfunc(char *s, char *fn)
 	if (usea && (!aadd || clwords[0])) {
 	    char **q;
 
-	    PERMALLOC {
-		q = compwords = (char **)
-		    zalloc((clwnum + 1) * sizeof(char *));
-		for (p = clwords + aadd; *p; p++, q++) {
-		    tmp = dupstring(*p);
-		    untokenize(tmp);
-		    *q = ztrdup(tmp);
-		}
-		*q = NULL;
-	    } LASTALLOC;
+	    q = compwords = (char **)
+		zalloc((clwnum + 1) * sizeof(char *));
+	    for (p = clwords + aadd; *p; p++, q++)
+		untokenize(*q = ztrdup(*p));
+	    *q = NULL;
 	} else
 	    compwords = (char **) zcalloc(sizeof(char *));
 
@@ -861,16 +853,14 @@ makecomplist(char *s, int incmd, int lst)
 
 	    return 0;
 	}
-	PERMALLOC {
-	    if (lastmatches) {
-		freematches(lastmatches);
-		lastmatches = NULL;
-	    }
-	    permmatches(1);
-	    amatches = pmatches;
-	    lastpermmnum = permmnum;
-	    lastpermgnum = permgnum;
-	} LASTALLOC;
+	if (lastmatches) {
+	    freematches(lastmatches);
+	    lastmatches = NULL;
+	}
+	permmatches(1);
+	amatches = pmatches;
+	lastpermmnum = permmnum;
+	lastpermgnum = permgnum;
 
 	lastmatches = pmatches;
 	lastlmatches = lmatches;
@@ -1484,19 +1474,17 @@ addmatches(Cadata dat, char **argv)
 
     if (!*argv) {
 	SWITCHHEAPS(compheap) {
-	    HEAPALLOC {
-		/* Select the group in which to store the matches. */
-		gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
-			  ((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
-			  ((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
-		if (dat->group) {
-		    endcmgroup(NULL);
-		    begcmgroup(dat->group, gflags);
-		} else {
-		    endcmgroup(NULL);
-		    begcmgroup("default", 0);
-		}
-	    } LASTALLOC;
+	    /* Select the group in which to store the matches. */
+	    gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
+		      ((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
+		      ((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
+	    if (dat->group) {
+		endcmgroup(NULL);
+		begcmgroup(dat->group, gflags);
+	    } else {
+		endcmgroup(NULL);
+		begcmgroup("default", 0);
+	    }
 	} SWITCHBACKHEAPS;
 
 	return 1;
@@ -1534,349 +1522,344 @@ addmatches(Cadata dat, char **argv)
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
-	HEAPALLOC {
-	    if ((doadd = (!dat->apar && !dat->opar && !dat->dpar)) &&
-		(dat->aflags & CAF_MATCH))
-		hasmatched = 1;
-	    if (dat->apar)
-		aparl = newlinklist();
-	    if (dat->opar)
-		oparl = newlinklist();
-	    if (dat->dpar) {
-		if (*(dat->dpar) == '(')
-		    dparr = NULL;
-		else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
-		    dparr = NULL;
-		dparl = newlinklist();
-	    }
-	    if (dat->exp) {
-		curexpl = (Cexpl) zhalloc(sizeof(struct cexpl));
-		curexpl->count = curexpl->fcount = 0;
-		curexpl->str = dupstring(dat->exp);
-	    } else
-		curexpl = NULL;
+	if ((doadd = (!dat->apar && !dat->opar && !dat->dpar)) &&
+	    (dat->aflags & CAF_MATCH))
+	    hasmatched = 1;
+	if (dat->apar)
+	    aparl = newlinklist();
+	if (dat->opar)
+	    oparl = newlinklist();
+	if (dat->dpar) {
+	    if (*(dat->dpar) == '(')
+		dparr = NULL;
+	    else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
+		dparr = NULL;
+	    dparl = newlinklist();
+	}
+	if (dat->exp) {
+	    curexpl = (Cexpl) zhalloc(sizeof(struct cexpl));
+	    curexpl->count = curexpl->fcount = 0;
+	    curexpl->str = dupstring(dat->exp);
+	} else
+	    curexpl = NULL;
 
-	    /* Store the matcher in our stack of matchers. */
-	    if (dat->match) {
-		mst.next = mstack;
-		mst.matcher = dat->match;
-		mstack = &mst;
+	/* Store the matcher in our stack of matchers. */
+	if (dat->match) {
+	    mst.next = mstack;
+	    mst.matcher = dat->match;
+	    mstack = &mst;
 
-		add_bmatchers(dat->match);
+	    add_bmatchers(dat->match);
 
-		addlinknode(matchers, dat->match);
-		dat->match->refc++;
-	    }
-	    if (mnum && (mstack || bmatchers))
-		update_bmatchers();
-
-	    /* Get the suffixes to ignore. */
-	    if (dat->ign && (aign = get_user_var(dat->ign))) {
-		char **ap, **sp, *tmp;
-		Patprog *pp, prog;
-
-		pign = (Patprog *) zhalloc((arrlen(aign) + 1) * sizeof(Patprog));
-
-		for (ap = sp = aign, pp = pign; (tmp = *ap); ap++) {
-		    tokenize(tmp);
-		    remnulargs(tmp);
-		    if (((tmp[0] == Quest && tmp[1] == Star) ||
-			 (tmp[1] == Quest && tmp[0] == Star)) &&
-			tmp[2] && !haswilds(tmp + 2))
-			untokenize(*sp++ = tmp + 2);
-		    else if ((prog = patcompile(tmp, 0, NULL)))
-			*pp++ = prog;
-		}
-		*sp = NULL;
-		*pp = NULL;
-		if (!*aign)
-		    aign = NULL;
-		if (!*pign)
-		    pign = NULL;
+	    addlinknode(matchers, dat->match);
+	    dat->match->refc++;
+	}
+	if (mnum && (mstack || bmatchers))
+	    update_bmatchers();
+
+	/* Get the suffixes to ignore. */
+	if (dat->ign && (aign = get_user_var(dat->ign))) {
+	    char **ap, **sp, *tmp;
+	    Patprog *pp, prog;
+
+	    pign = (Patprog *) zhalloc((arrlen(aign) + 1) * sizeof(Patprog));
+
+	    for (ap = sp = aign, pp = pign; (tmp = *ap); ap++) {
+		tokenize(tmp);
+		remnulargs(tmp);
+		if (((tmp[0] == Quest && tmp[1] == Star) ||
+		     (tmp[1] == Quest && tmp[0] == Star)) &&
+		    tmp[2] && !haswilds(tmp + 2))
+		    untokenize(*sp++ = tmp + 2);
+		else if ((prog = patcompile(tmp, 0, NULL)))
+		    *pp++ = prog;
 	    }
-	    /* Get the display strings. */
-	    if (dat->disp)
-		if ((disp = get_user_var(dat->disp)))
-		    disp--;
-	    /* Get the contents of the completion variables if we have
-	     * to perform matching. */
-	    if (dat->aflags & CAF_MATCH) {
-		lipre = dupstring(compiprefix);
-		lisuf = dupstring(compisuffix);
-		lpre = dupstring(compprefix);
-		lsuf = dupstring(compsuffix);
-		llpl = strlen(lpre);
-		llsl = strlen(lsuf);
-		/* Test if there is an existing -P prefix. */
-		if (dat->pre && *dat->pre) {
-		    pl = pfxlen(dat->pre, lpre);
-		    llpl -= pl;
-		    lpre += pl;
-		}
+	    *sp = NULL;
+	    *pp = NULL;
+	    if (!*aign)
+		aign = NULL;
+	    if (!*pign)
+		pign = NULL;
+	}
+	/* Get the display strings. */
+	if (dat->disp)
+	    if ((disp = get_user_var(dat->disp)))
+		disp--;
+	/* Get the contents of the completion variables if we have
+	 * to perform matching. */
+	if (dat->aflags & CAF_MATCH) {
+	    lipre = dupstring(compiprefix);
+	    lisuf = dupstring(compisuffix);
+	    lpre = dupstring(compprefix);
+	    lsuf = dupstring(compsuffix);
+	    llpl = strlen(lpre);
+	    llsl = strlen(lsuf);
+	    /* Test if there is an existing -P prefix. */
+	    if (dat->pre && *dat->pre) {
+		pl = pfxlen(dat->pre, lpre);
+		llpl -= pl;
+		lpre += pl;
 	    }
-	    /* Now duplicate the strings we have from the command line. */
-	    if (dat->ipre)
-		dat->ipre = (lipre ? dyncat(lipre, dat->ipre) :
-			     dupstring(dat->ipre));
-	    else if (lipre)
-		dat->ipre = lipre;
-	    if (dat->isuf)
-		dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) :
-			     dupstring(dat->isuf));
-	    else if (lisuf)
-		dat->isuf = lisuf;
-	    if (dat->ppre) {
-		dat->ppre = ((dat->flags & CMF_FILE) ?
-			     tildequote(dat->ppre,
-					!!(dat->aflags & CAF_QUOTE)) :
-			     multiquote(dat->ppre,
-					!!(dat->aflags & CAF_QUOTE)));
-		lpl = strlen(dat->ppre);
-	    } else
-		lpl = 0;
-	    if (dat->psuf) {
-		dat->psuf = multiquote(dat->psuf, !!(dat->aflags & CAF_QUOTE));
-		lsl = strlen(dat->psuf);
-	    } else
-		lsl = 0;
-	    if (dat->aflags & CAF_MATCH) {
-		int ml, gfl = 0;
-		char *globflag = NULL;
+	}
+	/* Now duplicate the strings we have from the command line. */
+	if (dat->ipre)
+	    dat->ipre = (lipre ? dyncat(lipre, dat->ipre) :
+			 dupstring(dat->ipre));
+	else if (lipre)
+	    dat->ipre = lipre;
+	if (dat->isuf)
+	    dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) :
+			 dupstring(dat->isuf));
+	else if (lisuf)
+	    dat->isuf = lisuf;
+	if (dat->ppre) {
+	    dat->ppre = ((dat->flags & CMF_FILE) ?
+			 tildequote(dat->ppre, !!(dat->aflags & CAF_QUOTE)) :
+			 multiquote(dat->ppre, !!(dat->aflags & CAF_QUOTE)));
+	    lpl = strlen(dat->ppre);
+	} else
+	    lpl = 0;
+	if (dat->psuf) {
+	    dat->psuf = multiquote(dat->psuf, !!(dat->aflags & CAF_QUOTE));
+	    lsl = strlen(dat->psuf);
+	} else
+	    lsl = 0;
+	if (dat->aflags & CAF_MATCH) {
+	    int ml, gfl = 0;
+	    char *globflag = NULL;
 
-		if (comppatmatch && *comppatmatch &&
-		    dat->ppre && lpre[0] == '(' && lpre[1] == '#') {
-		    char *p;
+	    if (comppatmatch && *comppatmatch &&
+		dat->ppre && lpre[0] == '(' && lpre[1] == '#') {
+		char *p;
 
-		    for (p = lpre + 2; *p && *p != ')'; p++);
+		for (p = lpre + 2; *p && *p != ')'; p++);
 
-		    if (*p == ')') {
-			char sav = p[1];
+		if (*p == ')') {
+		    char sav = p[1];
 
-			p[1] = '\0';
-			globflag = dupstring(lpre);
-			gfl = p - lpre + 1;
-			p[1] = sav;
+		    p[1] = '\0';
+		    globflag = dupstring(lpre);
+		    gfl = p - lpre + 1;
+		    p[1] = sav;
 
-			lpre = p + 1;
-			llpl -= gfl;
-		    }
+		    lpre = p + 1;
+		    llpl -= gfl;
 		}
-		s = dat->ppre ? dat->ppre : "";
-		if ((ml = match_str(lpre, s, &bpl, 0, NULL, 0, 0, 1)) >= 0) {
-		    if (matchsubs) {
-			Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0, 0);
-
-			tmp->prefix = matchsubs;
-			if (matchlastpart)
-			    matchlastpart->next = tmp;
-			else
-			    matchparts = tmp;
-		    }
-		    pline = matchparts;
-		    lpre += ml;
-		    llpl -= ml;
-		    bcp = ml;
-		    bpadd = strlen(s) - ml;
-		} else {
-		    if (llpl <= lpl && strpfx(lpre, s))
-			lpre = "";
-		    else if (llpl > lpl && strpfx(s, lpre))
-			lpre += lpl;
+	    }
+	    s = dat->ppre ? dat->ppre : "";
+	    if ((ml = match_str(lpre, s, &bpl, 0, NULL, 0, 0, 1)) >= 0) {
+		if (matchsubs) {
+		    Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0, 0);
+
+		    tmp->prefix = matchsubs;
+		    if (matchlastpart)
+			matchlastpart->next = tmp;
 		    else
-			*argv = NULL;
-		    bcp = lpl;
+			matchparts = tmp;
 		}
-		s = dat->psuf ? dat->psuf : "";
-		if ((ml = match_str(lsuf, s, &bsl, 0, NULL, 1, 0, 1)) >= 0) {
-		    if (matchsubs) {
-			Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0,
-					      CLF_SUF);
-
-			tmp->suffix = matchsubs;
-			if (matchlastpart)
-			    matchlastpart->next = tmp;
-			else
-			    matchparts = tmp;
-		    }
-		    sline = revert_cline(matchparts);
-		    lsuf[llsl - ml] = '\0';
-		    llsl -= ml;
-		    bcs = ml;
-		    bsadd = strlen(s) - ml;
-		} else {
-		    if (llsl <= lsl && strsfx(lsuf, s))
-			lsuf = "";
-		    else if (llsl > lsl && strsfx(s, lsuf))
-			lsuf[llsl - lsl] = '\0';
+		pline = matchparts;
+		lpre += ml;
+		llpl -= ml;
+		bcp = ml;
+		bpadd = strlen(s) - ml;
+	    } else {
+		if (llpl <= lpl && strpfx(lpre, s))
+		    lpre = "";
+		else if (llpl > lpl && strpfx(s, lpre))
+		    lpre += lpl;
+		else
+		    *argv = NULL;
+		bcp = lpl;
+	    }
+	    s = dat->psuf ? dat->psuf : "";
+	    if ((ml = match_str(lsuf, s, &bsl, 0, NULL, 1, 0, 1)) >= 0) {
+		if (matchsubs) {
+		    Cline tmp = get_cline(NULL, 0, NULL, 0, NULL, 0, CLF_SUF);
+
+		    tmp->suffix = matchsubs;
+		    if (matchlastpart)
+			matchlastpart->next = tmp;
 		    else
-			*argv = NULL;
-		    bcs = lsl;
+			matchparts = tmp;
 		}
-		if (comppatmatch && *comppatmatch) {
-		    int is = (*comppatmatch == '*');
-		    char *tmp = (char *) zhalloc(2 + llpl + llsl + gfl);
-
-		    if (gfl) {
-			strcpy(tmp, globflag);
-			strcat(tmp, lpre);
-		    } else
-			strcpy(tmp, lpre);
-		    tmp[llpl + gfl] = 'x';
-		    strcpy(tmp + llpl + gfl + is, lsuf);
-
-		    tokenize(tmp);
-		    remnulargs(tmp);
-		    if (haswilds(tmp)) {
-			if (is)
-			    tmp[llpl + gfl] = Star;
-			if ((cp = patcompile(tmp, 0, NULL)))
-			    haspattern = 1;
-		    }
-		}
-	    }
-	    /* Select the group in which to store the matches. */
-	    gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
-		      ((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
-		      ((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
-	    if (dat->group) {
-		endcmgroup(NULL);
-		begcmgroup(dat->group, gflags);
+		sline = revert_cline(matchparts);
+		lsuf[llsl - ml] = '\0';
+		llsl -= ml;
+		bcs = ml;
+		bsadd = strlen(s) - ml;
 	    } else {
-		endcmgroup(NULL);
-		begcmgroup("default", 0);
+		if (llsl <= lsl && strsfx(lsuf, s))
+		    lsuf = "";
+		else if (llsl > lsl && strsfx(s, lsuf))
+		    lsuf[llsl - lsl] = '\0';
+		else
+		    *argv = NULL;
+		bcs = lsl;
 	    }
-	    if (*argv) {
-		if (dat->pre)
-		    dat->pre = dupstring(dat->pre);
-		if (dat->suf)
-		    dat->suf = dupstring(dat->suf);
-		if (!dat->prpre && (dat->prpre = oppre)) {
-		    singsub(&(dat->prpre));
-		    untokenize(dat->prpre);
+	    if (comppatmatch && *comppatmatch) {
+		int is = (*comppatmatch == '*');
+		char *tmp = (char *) zhalloc(2 + llpl + llsl + gfl);
+
+		if (gfl) {
+		    strcpy(tmp, globflag);
+		    strcat(tmp, lpre);
 		} else
-		    dat->prpre = dupstring(dat->prpre);
-		/* Select the set of matches. */
-		oisalt = (dat->aflags & CAF_ALT);
-
-		if (dat->remf) {
-		    dat->remf = dupstring(dat->remf);
-		    dat->rems = NULL;
-		} else if (dat->rems)
-		    dat->rems = dupstring(dat->rems);
-
-		if (lpre)
-		    lpre = ((!(dat->aflags & CAF_QUOTE) &&
-			     (!dat->ppre && (dat->flags & CMF_FILE))) ?
-			    tildequote(lpre, 1) : multiquote(lpre, 1));
-		if (lsuf)
-		    lsuf = multiquote(lsuf, 1);
+		    strcpy(tmp, lpre);
+		tmp[llpl + gfl] = 'x';
+		strcpy(tmp + llpl + gfl + is, lsuf);
+
+		tokenize(tmp);
+		remnulargs(tmp);
+		if (haswilds(tmp)) {
+		    if (is)
+			tmp[llpl + gfl] = Star;
+		    if ((cp = patcompile(tmp, 0, NULL)))
+			haspattern = 1;
+		}
 	    }
-	    /* Walk through the matches given. */
-	    obpl = bpl;
-	    obsl = bsl;
-	    if (!oisalt && (aign || pign)) {
-		int max = 0;
-		char **ap = argv;
-
-		ppl = (dat->ppre ? strlen(dat->ppre) : 0);
-		while ((s = *ap++))
-		    if ((sl = strlen(s)) > max)
-			max = sl;
-		psl = (dat->psuf ? strlen(dat->psuf) : 0);
-		ibuf = (char *) zhalloc(1 + ppl + max + psl);
+	}
+	/* Select the group in which to store the matches. */
+	gflags = (((dat->aflags & CAF_NOSORT ) ? CGF_NOSORT  : 0) |
+		  ((dat->aflags & CAF_UNIQALL) ? CGF_UNIQALL : 0) |
+		  ((dat->aflags & CAF_UNIQCON) ? CGF_UNIQCON : 0));
+	if (dat->group) {
+	    endcmgroup(NULL);
+	    begcmgroup(dat->group, gflags);
+	} else {
+	    endcmgroup(NULL);
+	    begcmgroup("default", 0);
+	}
+	if (*argv) {
+	    if (dat->pre)
+		dat->pre = dupstring(dat->pre);
+	    if (dat->suf)
+		dat->suf = dupstring(dat->suf);
+	    if (!dat->prpre && (dat->prpre = oppre)) {
+		singsub(&(dat->prpre));
+		untokenize(dat->prpre);
+	    } else
+		dat->prpre = dupstring(dat->prpre);
+	    /* Select the set of matches. */
+	    oisalt = (dat->aflags & CAF_ALT);
+
+	    if (dat->remf) {
+		dat->remf = dupstring(dat->remf);
+		dat->rems = NULL;
+	    } else if (dat->rems)
+		dat->rems = dupstring(dat->rems);
+
+	    if (lpre)
+		lpre = ((!(dat->aflags & CAF_QUOTE) &&
+			 (!dat->ppre && (dat->flags & CMF_FILE))) ?
+			tildequote(lpre, 1) : multiquote(lpre, 1));
+	    if (lsuf)
+		lsuf = multiquote(lsuf, 1);
+	}
+	/* Walk through the matches given. */
+	obpl = bpl;
+	obsl = bsl;
+	if (!oisalt && (aign || pign)) {
+	    int max = 0;
+	    char **ap = argv;
+
+	    ppl = (dat->ppre ? strlen(dat->ppre) : 0);
+	    while ((s = *ap++))
+		if ((sl = strlen(s)) > max)
+		    max = sl;
+	    psl = (dat->psuf ? strlen(dat->psuf) : 0);
+	    ibuf = (char *) zhalloc(1 + ppl + max + psl);
+	}
+	for (; (s = *argv); argv++) {
+	    bpl = obpl;
+	    bsl = obsl;
+	    if (disp) {
+		if (!*++disp)
+		    disp = NULL;
 	    }
-	    for (; (s = *argv); argv++) {
-		bpl = obpl;
-		bsl = obsl;
-		if (disp) {
-		    if (!*++disp)
-			disp = NULL;
+	    sl = strlen(s);
+	    isalt = oisalt;
+	    if (!isalt && (aign || pign)) {
+		int il = ppl + sl + psl;
+
+		if (ppl)
+		    memcpy(ibuf, dat->ppre, ppl);
+		strcpy(ibuf + ppl, s);
+		if (psl)
+		    strcpy(ibuf + ppl + sl, dat->psuf);
+
+		if (aign) {
+		    /* Do the suffix-test. If the match has one of the
+		     * suffixes from aign, we put it in the alternate set. */
+		    char **pt = aign;
+		    int filell;
+
+		    for (isalt = 0; !isalt && *pt; pt++)
+			isalt = ((filell = strlen(*pt)) < il &&
+				 !strcmp(*pt, ibuf + il - filell));
 		}
-		sl = strlen(s);
-		isalt = oisalt;
-		if (!isalt && (aign || pign)) {
-		    int il = ppl + sl + psl;
-
-		    if (ppl)
-			memcpy(ibuf, dat->ppre, ppl);
-		    strcpy(ibuf + ppl, s);
-		    if (psl)
-			strcpy(ibuf + ppl + sl, dat->psuf);
-
-		    if (aign) {
-			/* Do the suffix-test. If the match has one of the
-			 * suffixes from aign, we put it in the alternate set. */
-			char **pt = aign;
-			int filell;
-
-			for (isalt = 0; !isalt && *pt; pt++)
-			    isalt = ((filell = strlen(*pt)) < il &&
-				     !strcmp(*pt, ibuf + il - filell));
-		    }
-		    if (!isalt && pign) {
-			Patprog *pt = pign;
+		if (!isalt && pign) {
+		    Patprog *pt = pign;
 
-			for (isalt = 0; !isalt && *pt; pt++)
-			    isalt = pattry(*pt, ibuf);
-		    }
+		    for (isalt = 0; !isalt && *pt; pt++)
+			isalt = pattry(*pt, ibuf);
 		}
-		if (!(dat->aflags & CAF_MATCH)) {
-		    if (dat->aflags & CAF_QUOTE)
-			ms = dupstring(s);
-		    else
-			sl = strlen(ms = multiquote(s, 0));
-		    lc = bld_parts(ms, sl, -1, NULL);
-		    isexact = 0;
-		} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
-					     (!(dat->aflags & CAF_QUOTE) ?
-					      (dat->ppre ||
-					       !(dat->flags & CMF_FILE) ? 1 : 2) : 0),
-					     &bpl, bcp, &bsl, bcs,
-					     &isexact))) {
-		    if (dparr && !*++dparr)
-			dparr = NULL;
-		    continue;
+	    }
+	    if (!(dat->aflags & CAF_MATCH)) {
+		if (dat->aflags & CAF_QUOTE)
+		    ms = dupstring(s);
+		else
+		    sl = strlen(ms = multiquote(s, 0));
+		lc = bld_parts(ms, sl, -1, NULL);
+		isexact = 0;
+	    } else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
+					 (!(dat->aflags & CAF_QUOTE) ?
+					  (dat->ppre ||
+					   !(dat->flags & CMF_FILE) ? 1 : 2) : 0),
+					 &bpl, bcp, &bsl, bcs,
+					 &isexact))) {
+		if (dparr && !*++dparr)
+		    dparr = NULL;
+		continue;
+	    }
+	    if (doadd) {
+		Brinfo bp;
+
+		for (bp = obpl; bp; bp = bp->next)
+		    bp->curpos += bpadd;
+		for (bp = obsl; bp; bp = bp->next)
+		    bp->curpos += bsadd;
+
+		if ((cm = add_match_data(isalt, ms, lc, dat->ipre, NULL,
+					 dat->isuf, dat->pre, dat->prpre,
+					 dat->ppre, pline,
+					 dat->psuf, sline,
+					 dat->suf, dat->flags, isexact))) {
+		    cm->rems = dat->rems;
+		    cm->remf = dat->remf;
+		    if (disp)
+			cm->disp = dupstring(*disp);
 		}
-		if (doadd) {
-		    Brinfo bp;
-
-		    for (bp = obpl; bp; bp = bp->next)
-			bp->curpos += bpadd;
-		    for (bp = obsl; bp; bp = bp->next)
-			bp->curpos += bsadd;
-
-		    if ((cm = add_match_data(isalt, ms, lc, dat->ipre, NULL,
-					     dat->isuf, dat->pre, dat->prpre,
-					     dat->ppre, pline,
-					     dat->psuf, sline,
-					     dat->suf, dat->flags, isexact))) {
-			cm->rems = dat->rems;
-			cm->remf = dat->remf;
-			if (disp)
-			    cm->disp = dupstring(*disp);
-		    }
-		} else {
-		    if (dat->apar)
-			addlinknode(aparl, ms);
-		    if (dat->opar)
-			addlinknode(oparl, s);
-		    if (dat->dpar && dparr) {
-			addlinknode(dparl, *dparr);
-			if (!*++dparr)
-			    dparr = NULL;
-		    }
-		    free_cline(lc);
+	    } else {
+		if (dat->apar)
+		    addlinknode(aparl, ms);
+		if (dat->opar)
+		    addlinknode(oparl, s);
+		if (dat->dpar && dparr) {
+		    addlinknode(dparl, *dparr);
+		    if (!*++dparr)
+			dparr = NULL;
 		}
+		free_cline(lc);
 	    }
-	    if (dat->apar)
-		set_list_array(dat->apar, aparl);
-	    if (dat->opar)
-		set_list_array(dat->opar, oparl);
-	    if (dat->dpar)
-		set_list_array(dat->dpar, dparl);
-	    if (dat->exp)
-		addexpl();
-	} LASTALLOC;
+	}
+	if (dat->apar)
+	    set_list_array(dat->apar, aparl);
+	if (dat->opar)
+	    set_list_array(dat->opar, oparl);
+	if (dat->dpar)
+	    set_list_array(dat->dpar, dparl);
+	if (dat->exp)
+	    addexpl();
     } SWITCHBACKHEAPS;
 
     /* We switched back to the current heap, now restore the stack of
@@ -2379,7 +2362,7 @@ makearray(LinkList l, int type, int flags, int *np, int *nlp, int *llp)
     int n, nl = 0, ll = 0;
 
     /* Build an array for the matches. */
-    rp = ap = (Cmatch *) ncalloc(((n = countlinknodes(l)) + 1) *
+    rp = ap = (Cmatch *) hcalloc(((n = countlinknodes(l)) + 1) *
 				 sizeof(Cmatch));
 
     /* And copy them into it. */
@@ -2487,7 +2470,7 @@ dupmatch(Cmatch m, int nbeg, int nend)
 {
     Cmatch r;
 
-    r = (Cmatch) ncalloc(sizeof(struct cmatch));
+    r = (Cmatch) zcalloc(sizeof(struct cmatch));
 
     r->str = ztrdup(m->str);
     r->ipre = ztrdup(m->ipre);
@@ -2522,7 +2505,7 @@ dupmatch(Cmatch m, int nbeg, int nend)
     r->autoq = ztrdup(m->autoq);
     r->qipl = m->qipl;
     r->qisl = m->qisl;
-    r->disp = dupstring(m->disp);
+    r->disp = ztrdup(m->disp);
 
     return r;
 }
@@ -2559,32 +2542,30 @@ permmatches(int last)
 	fi = 1;
     }
     while (g) {
-	HEAPALLOC {
-	    if (fi)
-		/* We have no matches, try ignoring fignore. */
-		mlist = g->lfmatches;
-	    else
-		mlist = g->lmatches;
-
-	    g->matches = makearray(mlist, 1, g->flags, &nn, &nl, &ll);
-	    g->mcount = nn;
-	    if ((g->lcount = nn - nl) < 0)
-		g->lcount = 0;
-	    g->llcount = ll;
-	    if (g->ylist) {
-		g->lcount = arrlen(g->ylist);
-		smatches = 2;
-	    }
-	    g->expls = (Cexpl *) makearray(g->lexpls, 0, 0, &(g->ecount),
-					   NULL, NULL);
+	if (fi)
+	    /* We have no matches, try ignoring fignore. */
+	    mlist = g->lfmatches;
+	else
+	    mlist = g->lmatches;
+
+	g->matches = makearray(mlist, 1, g->flags, &nn, &nl, &ll);
+	g->mcount = nn;
+	if ((g->lcount = nn - nl) < 0)
+	    g->lcount = 0;
+	g->llcount = ll;
+	if (g->ylist) {
+	    g->lcount = arrlen(g->ylist);
+	    smatches = 2;
+	}
+	g->expls = (Cexpl *) makearray(g->lexpls, 0, 0, &(g->ecount),
+				       NULL, NULL);
 
-	    g->ccount = 0;
-	} LASTALLOC;
+	g->ccount = 0;
 
 	nmatches += g->mcount;
 	smatches += g->lcount;
 
-	n = (Cmgroup) ncalloc(sizeof(struct cmgroup));
+	n = (Cmgroup) zcalloc(sizeof(struct cmgroup));
 
 	if (!lmatches)
 	    lmatches = n;
@@ -2597,8 +2578,7 @@ permmatches(int last)
 
 	n->flags = g->flags;
 	n->mcount = g->mcount;
-	n->matches = p = (Cmatch *) ncalloc((n->mcount + 1) *
-					    sizeof(Cmatch));
+	n->matches = p = (Cmatch *) zcalloc((n->mcount + 1) * sizeof(Cmatch));
 	n->name = ztrdup(g->name);
 	for (q = g->matches; *q; q++, p++)
 	    *p = dupmatch(*q, nbrbeg, nbrend);
@@ -2607,15 +2587,14 @@ permmatches(int last)
 	n->lcount = g->lcount;
 	n->llcount = g->llcount;
 	if (g->ylist)
-	    n->ylist = arrdup(g->ylist);
+	    n->ylist = zarrdup(g->ylist);
 	else
 	    n->ylist = NULL;
 
 	if ((n->ecount = g->ecount)) {
-	    n->expls = ep = (Cexpl *) ncalloc((n->ecount + 1) *
-					      sizeof(Cexpl));
+	    n->expls = ep = (Cexpl *) zcalloc((n->ecount + 1) * sizeof(Cexpl));
 	    for (eq = g->expls; (o = *eq); eq++, ep++) {
-		*ep = e = (Cexpl) ncalloc(sizeof(struct cexpl));
+		*ep = e = (Cexpl) zcalloc(sizeof(struct cexpl));
 		e->count = (fi ? o->fcount : o->count);
 		e->str = ztrdup(o->str);
 	    }
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index dc9f46b0f..fb1717f4d 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -320,9 +320,7 @@ set_gmatcher(char *name, char **argv)
 	q = &(n->next);
     }
     freecmlist(cmatcher);
-    PERMALLOC {
-	cmatcher = cpcmlist(l);
-    } LASTALLOC;
+    cmatcher = cpcmlist(l);
 
     return 1;
 }
@@ -1254,9 +1252,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     cc->gname = ztrdup(cct->gname);
     cc->hpat = ztrdup(cct->hpat);
     cc->hnum = cct->hnum;
-    PERMALLOC {
-	cc->matcher = cpcmatcher(cct->matcher);
-    } LASTALLOC;
+    cc->matcher = cpcmatcher(cct->matcher);
     cc->mstr = ztrdup(cct->mstr);
 
     /* careful with extended completion:  it's already allocated */
@@ -1832,11 +1828,9 @@ ccmakehookfn(Hookdef dummy, struct ccmakedat *dat)
 	    if (lastccused)
 		freelinklist(lastccused, (FreeFunc) freecompctl);
 
-	    PERMALLOC {
-		lastccused = newlinklist();
-		for (n = firstnode(ccused); n; incnode(n))
-		    addlinknode(lastccused, getdata(n));
-	    } LASTALLOC;
+	    lastccused = znewlinklist();
+	    for (n = firstnode(ccused); n; incnode(n))
+		zaddlinknode(lastccused, getdata(n));
 	} else if (ccused)
 	    for (n = firstnode(ccused); n; incnode(n))
 		if (((Compctl) getdata(n)) != &cc_dummy)
@@ -1857,16 +1851,14 @@ ccmakehookfn(Hookdef dummy, struct ccmakedat *dat)
 	    dat->lst = 0;
 	    return 0;
 	}
-	PERMALLOC {
-	    if (lastmatches) {
-		freematches(lastmatches);
-		lastmatches = NULL;
-	    }
-	    permmatches(1);
-	    amatches = pmatches;
-	    lastpermmnum = permmnum;
-	    lastpermgnum = permgnum;
-	} LASTALLOC;
+	if (lastmatches) {
+	    freematches(lastmatches);
+	    lastmatches = NULL;
+	}
+	permmatches(1);
+	amatches = pmatches;
+	lastpermmnum = permmnum;
+	lastpermgnum = permgnum;
 
 	lastmatches = pmatches;
 	lastlmatches = lmatches;
@@ -2277,66 +2269,64 @@ makecomplistctl(int flags)
 
     cdepth++;
     SWITCHHEAPS(compheap) {
-	HEAPALLOC {
-	    int ooffs = offs, lip, lp;
-	    char *str = comp_str(&lip, &lp, 0), *t;
-	    char *os = cmdstr, **ow = clwords, **p, **q, qc;
-	    int on = clwnum, op = clwpos, ois =  instring, oib = inbackt;
-	    char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, *oaq = autoq;
-	    char buf[2];
-
-	    if (compquote && (qc = *compquote)) {
-		if (qc == '`') {
-		    instring = 0;
-		    inbackt = 0;
-		    autoq = "";
-		} else {
-		    buf[0] = qc;
-		    buf[1] = '\0';
-		    instring = (qc == '\'' ? 1 : 2);
-		    inbackt = 0;
-		    autoq = buf;
-		}
-	    } else {
-		instring = inbackt = 0;
+	int ooffs = offs, lip, lp;
+	char *str = comp_str(&lip, &lp, 0), *t;
+	char *os = cmdstr, **ow = clwords, **p, **q, qc;
+	int on = clwnum, op = clwpos, ois =  instring, oib = inbackt;
+	char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, *oaq = autoq;
+	char buf[2];
+
+	if (compquote && (qc = *compquote)) {
+	    if (qc == '`') {
+		instring = 0;
+		inbackt = 0;
 		autoq = "";
+	    } else {
+		buf[0] = qc;
+		buf[1] = '\0';
+		instring = (qc == '\'' ? 1 : 2);
+		inbackt = 0;
+		autoq = buf;
 	    }
-	    qipre = ztrdup(compqiprefix ? compqiprefix : "");
-	    qisuf = ztrdup(compqisuffix ? compqisuffix : "");
-	    isuf = dupstring(compisuffix);
-	    ctokenize(isuf);
-	    remnulargs(isuf);
-	    clwnum = arrlen(compwords);
-	    clwpos = compcurrent - 1;
-	    cmdstr = ztrdup(compwords[0]);
-	    clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
-	    for (p = compwords, q = clwords; *p; p++, q++) {
-		t = dupstring(*p);
-		tokenize(t);
-		remnulargs(t);
-		*q = ztrdup(t);
-	    }
-	    *q = NULL;
-	    offs = lip + lp;
-	    incompfunc = 2;
-	    ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags);
-	    incompfunc = 1;
-	    isuf = oisuf;
-	    zsfree(qipre);
-	    zsfree(qisuf);
-	    qipre = oqp;
-	    qisuf = oqs;
-	    instring = ois;
-	    inbackt = oib;
-	    autoq = oaq;
-	    offs = ooffs;
-	    zsfree(cmdstr);
-	    freearray(clwords);
-	    cmdstr = os;
-	    clwords = ow;
-	    clwnum = on;
-	    clwpos = op;
-	} LASTALLOC;
+	} else {
+	    instring = inbackt = 0;
+	    autoq = "";
+	}
+	qipre = ztrdup(compqiprefix ? compqiprefix : "");
+	qisuf = ztrdup(compqisuffix ? compqisuffix : "");
+	isuf = dupstring(compisuffix);
+	ctokenize(isuf);
+	remnulargs(isuf);
+	clwnum = arrlen(compwords);
+	clwpos = compcurrent - 1;
+	cmdstr = ztrdup(compwords[0]);
+	clwords = (char **) zalloc((clwnum + 1) * sizeof(char *));
+	for (p = compwords, q = clwords; *p; p++, q++) {
+	    t = dupstring(*p);
+	    tokenize(t);
+	    remnulargs(t);
+	    *q = ztrdup(t);
+	}
+	*q = NULL;
+	offs = lip + lp;
+	incompfunc = 2;
+	ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags);
+	incompfunc = 1;
+	isuf = oisuf;
+	zsfree(qipre);
+	zsfree(qisuf);
+	qipre = oqp;
+	qisuf = oqs;
+	instring = ois;
+	inbackt = oib;
+	autoq = oaq;
+	offs = ooffs;
+	zsfree(cmdstr);
+	freearray(clwords);
+	cmdstr = os;
+	clwords = ow;
+	clwnum = on;
+	clwpos = op;
     } SWITCHBACKHEAPS;
     cdepth--;
 
@@ -2967,8 +2957,6 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
     if (incompfunc != 1 && ccstack && findnode(ccstack, cc))
 	return;
 
-    MUSTUSEHEAP("complistflags");
-
     if (!ccstack)
 	ccstack = newlinklist();
     addlinknode(ccstack, cc);
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index e28a67cd4..10d7ea8e4 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1172,10 +1172,7 @@ comp_wrapper(Eprog prog, FuncWrap w, char *name)
 	oqi = ztrdup(compquoting);
 	oqs = ztrdup(compqstack);
 	oaq = ztrdup(autoq);
-
-	PERMALLOC {
-	    owords = arrdup(compwords);
-	} LASTALLOC;
+	owords = zarrdup(compwords);
 
 	runshfunc(prog, w, name);
 
diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c
index 9acccc17a..5a24c0e26 100644
--- a/Src/Zle/complist.c
+++ b/Src/Zle/complist.c
@@ -864,331 +864,327 @@ domenuselect(Hookdef dummy, Chdata dat)
     int i = 0, acc = 0, wishcol = 0, setwish = 0, oe = onlyexpl, wasnext = 0;
     char *s;
 
-    HEAPALLOC {
-	if (fdat || (dummy && (!(s = getsparam("SELECTMIN")) ||
-			       (dat && dat->num < atoi(s))))) {
-	    if (fdat) {
-		fdat->matches = dat->matches;
-		fdat->num = dat->num;
-	    }
-	    LASTALLOC_RETURN 0;
+    if (fdat || (dummy && (!(s = getsparam("SELECTMIN")) ||
+			   (dat && dat->num < atoi(s))))) {
+	if (fdat) {
+	    fdat->matches = dat->matches;
+	    fdat->num = dat->num;
 	}
-	fdat = dat;
-	selectlocalmap(mskeymap);
-	noselect = 0;
-	mselect = (*(minfo.cur))->gnum;
-	for (;;) {
-	    onlyexpl = 0;
-	    showinglist = -2;
-	    zrefresh();
-	    inselect = 1;
-	    if (noselect)
-		break;
-	    selected = 1;
-	    if (!i) {
-		i = mcols * mlines;
-		while (i--)
-		    if (mtab[i])
-			break;
-		if (!i)
+	return 0;
+    }
+    fdat = dat;
+    selectlocalmap(mskeymap);
+    noselect = 0;
+    mselect = (*(minfo.cur))->gnum;
+    for (;;) {
+	onlyexpl = 0;
+	showinglist = -2;
+	zrefresh();
+	inselect = 1;
+	if (noselect)
+	    break;
+	selected = 1;
+	if (!i) {
+	    i = mcols * mlines;
+	    while (i--)
+		if (mtab[i])
 		    break;
-		i = 1;
-	    }
-	    p = mmtabp;
-	    pg = mgtabp;
-	    minfo.cur = *p;
-	    minfo.group = *pg;
-	    if (setwish)
-		wishcol = mcol;
-	    else if (mcol > wishcol) {
-		while (mcol > 0 && p[-1] == minfo.cur)
-		    mcol--, p--, pg--;
-	    } else if (mcol < wishcol) {
-		while (mcol < mcols - 1 && p[1] == minfo.cur)
-		    mcol++, p++, pg++;
-	    }
-	    setwish = wasnext = 0;
-
-	getk:
-
-	    if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak))
+	    if (!i)
 		break;
-	    else if (cmd == Th(z_acceptline)) {
-		acc = 1;
+	    i = 1;
+	}
+	p = mmtabp;
+	pg = mgtabp;
+	minfo.cur = *p;
+	minfo.group = *pg;
+	if (setwish)
+	    wishcol = mcol;
+	else if (mcol > wishcol) {
+	    while (mcol > 0 && p[-1] == minfo.cur)
+		mcol--, p--, pg--;
+	} else if (mcol < wishcol) {
+	    while (mcol < mcols - 1 && p[1] == minfo.cur)
+		mcol++, p++, pg++;
+	}
+	setwish = wasnext = 0;
+
+    getk:
+
+	if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak))
+	    break;
+	else if (cmd == Th(z_acceptline)) {
+	    acc = 1;
+	    break;
+	} else if (cmd == Th(z_acceptandinfernexthistory)) {
+	    Menustack s = (Menustack) zhalloc(sizeof(*s));
+
+	    s->prev = u;
+	    u = s;
+	    s->line = dupstring((char *) line);
+	    s->cs = cs;
+	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
+	    s->amatches = amatches;
+	    s->pmatches = pmatches;
+	    s->lastmatches = lastmatches;
+	    s->lastlmatches = lastlmatches;
+	    s->acc = menuacc;
+	    s->brbeg = dupbrinfo(brbeg, NULL, 1);
+	    s->brend = dupbrinfo(brend, NULL, 1);
+	    s->nbrbeg = nbrbeg;
+	    s->nbrend = nbrend;
+	    s->nmatches = nmatches;
+	    menucmp = menuacc = hasoldlist = 0;
+	    fixsuffix();
+	    validlist = 0;
+	    amatches = pmatches = lastmatches = NULL;
+	    invalidate_list();
+	    menucomplete(zlenoargs);
+	    if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) {
+		noselect = clearlist = listshown = 1;
+		onlyexpl = 0;
+		zrefresh();
 		break;
-	    } else if (cmd == Th(z_acceptandinfernexthistory)) {
-		Menustack s = (Menustack) zhalloc(sizeof(*s));
-
-		s->prev = u;
-		u = s;
-		s->line = dupstring((char *) line);
-		s->cs = cs;
-		memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
-		s->amatches = amatches;
-		s->pmatches = pmatches;
-		s->lastmatches = lastmatches;
-		s->lastlmatches = lastlmatches;
-		s->acc = menuacc;
-		s->brbeg = dupbrinfo(brbeg, NULL);
-		s->brend = dupbrinfo(brend, NULL);
-		s->nbrbeg = nbrbeg;
-		s->nbrend = nbrend;
-		s->nmatches = nmatches;
-		menucmp = menuacc = hasoldlist = 0;
-		fixsuffix();
-		validlist = 0;
-		amatches = pmatches = lastmatches = NULL;
-		invalidate_list();
-		PERMALLOC {
-		    menucomplete(zlenoargs);
-		} LASTALLOC;
-		if (dat->num < 2 || !minfo.cur || !*(minfo.cur)) {
-		    noselect = clearlist = listshown = 1;
-		    onlyexpl = 0;
-		    zrefresh();
-		    break;
+	    }
+	    clearlist = listshown = 1;
+	    mselect = (*(minfo.cur))->gnum;
+	    setwish = wasnext = 1;
+	    continue;
+	} else if (cmd == Th(z_acceptandhold) ||
+		   cmd == Th(z_acceptandmenucomplete)) {
+	    Menustack s = (Menustack) zhalloc(sizeof(*s));
+
+	    s->prev = u;
+	    u = s;
+	    s->line = dupstring((char *) line);
+	    s->cs = cs;
+	    memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
+	    s->amatches = s->pmatches =
+		s->lastmatches = s->lastlmatches = NULL;
+	    s->acc = menuacc;
+	    s->brbeg = dupbrinfo(brbeg, NULL, 1);
+	    s->brend = dupbrinfo(brend, NULL, 1);
+	    s->nbrbeg = nbrbeg;
+	    s->nbrend = nbrend;
+	    s->nmatches = nmatches;
+	    accept_last();
+	    do_menucmp(0);
+	    mselect = (*(minfo.cur))->gnum;
+	    setwish = 1;
+	    continue;
+	} else if (cmd == Th(z_undo)) {
+	    int l;
+
+	    if (!u)
+		goto getk;
+
+	    cs = 0;
+	    foredel(ll);
+	    spaceinline(l = strlen(u->line));
+	    strncpy((char *) line, u->line, l);
+	    cs = u->cs;
+	    menuacc = u->acc;
+	    memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
+	    p = &(minfo.cur);
+	    if (u->lastmatches && lastmatches != u->lastmatches) {
+		if (lastmatches)
+		    freematches(lastmatches);
+		amatches = u->amatches;
+		pmatches = u->pmatches;
+		lastmatches = u->lastmatches;
+		lastlmatches = u->lastlmatches;
+		nmatches = u->nmatches;
+		hasoldlist = 1;
+	    }
+	    freebrinfo(brbeg);
+	    freebrinfo(brend);
+	    brbeg = dupbrinfo(u->brbeg, &lastbrbeg, 0);
+	    brend = dupbrinfo(u->brend, &lastbrend, 0);
+	    nbrbeg = u->nbrbeg;
+	    nbrend = u->nbrend;
+
+	    u = u->prev;
+	    clearlist = 1;
+	    setwish = 1;
+	    listdat.valid = 0;
+	} else if (cmd == Th(z_redisplay)) {
+	    redisplay(zlenoargs);
+	    continue;
+	} else if (cmd == Th(z_clearscreen)) {
+	    clearscreen(zlenoargs);
+	    continue;
+	} else if (cmd == Th(z_downhistory) ||
+		   cmd == Th(z_downlineorhistory) ||
+		   cmd == Th(z_downlineorsearch) ||
+		   cmd == Th(z_vidownlineorhistory)) {
+	    do {
+		if (mline == mlines - 1) {
+		    p -= mline * mcols;
+		    mline = 0;
+		} else {
+		    mline++;
+		    p += mcols;
 		}
-		clearlist = listshown = 1;
-		mselect = (*(minfo.cur))->gnum;
-		setwish = wasnext = 1;
-		continue;
-	    } else if (cmd == Th(z_acceptandhold) ||
-		       cmd == Th(z_acceptandmenucomplete)) {
-		Menustack s = (Menustack) zhalloc(sizeof(*s));
-
-		s->prev = u;
-		u = s;
-		s->line = dupstring((char *) line);
-		s->cs = cs;
-		memcpy(&(s->info), &minfo, sizeof(struct menuinfo));
-		s->amatches = s->pmatches =
-		    s->lastmatches = s->lastlmatches = NULL;
-		s->acc = menuacc;
-		s->brbeg = dupbrinfo(brbeg, NULL);
-		s->brend = dupbrinfo(brend, NULL);
-		s->nbrbeg = nbrbeg;
-		s->nbrend = nbrend;
-		s->nmatches = nmatches;
-		accept_last();
-		do_menucmp(0);
-		mselect = (*(minfo.cur))->gnum;
-		setwish = 1;
-		continue;
-	    } else if (cmd == Th(z_undo)) {
-		int l;
-
-		if (!u)
-		    goto getk;
-
-		cs = 0;
-		foredel(ll);
-		spaceinline(l = strlen(u->line));
-		strncpy((char *) line, u->line, l);
-		cs = u->cs;
-		menuacc = u->acc;
-		memcpy(&minfo, &(u->info), sizeof(struct menuinfo));
-		p = &(minfo.cur);
-		if (u->lastmatches && lastmatches != u->lastmatches) {
-		    if (lastmatches)
-			freematches(lastmatches);
-		    amatches = u->amatches;
-		    pmatches = u->pmatches;
-		    lastmatches = u->lastmatches;
-		    lastlmatches = u->lastlmatches;
-		    nmatches = u->nmatches;
-		    hasoldlist = 1;
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+	    } while (!*p);
+	} else if (cmd == Th(z_uphistory) ||
+		   cmd == Th(z_uplineorhistory) ||
+		   cmd == Th(z_uplineorsearch) ||
+		   cmd == Th(z_viuplineorhistory)) {
+	    do {
+		if (!mline) {
+		    mline = mlines - 1;
+		    p += mline * mcols;
+		} else {
+		    mline--;
+		    p -= mcols;
 		}
-		PERMALLOC {
-		    freebrinfo(brbeg);
-		    freebrinfo(brend);
-		    brbeg = dupbrinfo(u->brbeg, &lastbrbeg);
-		    brend = dupbrinfo(u->brend, &lastbrend);
-		    nbrbeg = u->nbrbeg;
-		    nbrend = u->nbrend;
-		} LASTALLOC;
-		u = u->prev;
-		clearlist = 1;
-		setwish = 1;
-		listdat.valid = 0;
-	    } else if (cmd == Th(z_redisplay)) {
-		redisplay(zlenoargs);
-		continue;
-	    } else if (cmd == Th(z_clearscreen)) {
-		clearscreen(zlenoargs);
-		continue;
-	    } else if (cmd == Th(z_downhistory) ||
-		       cmd == Th(z_downlineorhistory) ||
-		       cmd == Th(z_downlineorsearch) ||
-		       cmd == Th(z_vidownlineorhistory)) {
-		do {
-		    if (mline == mlines - 1) {
-			p -= mline * mcols;
-			mline = 0;
-		    } else {
-			mline++;
-			p += mcols;
-		    }
-		    if (adjust_mcol(wishcol, &p, NULL))
-			continue;
-		} while (!*p);
-	    } else if (cmd == Th(z_uphistory) ||
-		       cmd == Th(z_uplineorhistory) ||
-		       cmd == Th(z_uplineorsearch) ||
-		       cmd == Th(z_viuplineorhistory)) {
-		do {
-		    if (!mline) {
-			mline = mlines - 1;
-			p += mline * mcols;
-		    } else {
-			mline--;
-			p -= mcols;
-		    }
-		    if (adjust_mcol(wishcol, &p, NULL))
-			continue;
-		} while (!*p);
-	    } else if (cmd == Th(z_forwardchar) || cmd == Th(z_viforwardchar)) {
-		int omcol = mcol;
-		Cmatch *op = *p;
-
-		do {
-		    if (mcol == mcols - 1) {
-			p -= mcol;
-			mcol = 0;
-		    } else {
-			mcol++;
-			p++;
-		    }
-		} while (!*p || (mcol != omcol && *p == op));
-		wishcol = mcol;
-	    } else if (cmd == Th(z_backwardchar) || cmd == Th(z_vibackwardchar)) {
-		int omcol = mcol;
-		Cmatch *op = *p;
-
-		do {
-		    if (!mcol) {
-			mcol = mcols - 1;
-			p += mcol;
-		    } else {
-			mcol--;
-			p--;
-		    }
-		} while (!*p || (mcol != omcol && *p == op));
-		wishcol = mcol;
-	    } else if (cmd == Th(z_beginningofbufferorhistory) ||
-		       cmd == Th(z_beginningofline) ||
-		       cmd == Th(z_beginningoflinehist) ||
-		       cmd == Th(z_vibeginningofline)) {
-		p -= mcol;
-		mcol = 0;
-		while (!*p) {
+		if (adjust_mcol(wishcol, &p, NULL))
+		    continue;
+	    } while (!*p);
+	} else if (cmd == Th(z_forwardchar) || cmd == Th(z_viforwardchar)) {
+	    int omcol = mcol;
+	    Cmatch *op = *p;
+
+	    do {
+		if (mcol == mcols - 1) {
+		    p -= mcol;
+		    mcol = 0;
+		} else {
 		    mcol++;
 		    p++;
 		}
-		wishcol = 0;
-	    } else if (cmd == Th(z_endofbufferorhistory) ||
-		       cmd == Th(z_endofline) ||
-		       cmd == Th(z_endoflinehist) ||
-		       cmd == Th(z_viendofline)) {
-		p += mcols - mcol - 1;
-		mcol = mcols - 1;
-		while (!*p) {
+	    } while (!*p || (mcol != omcol && *p == op));
+	    wishcol = mcol;
+	} else if (cmd == Th(z_backwardchar) || cmd == Th(z_vibackwardchar)) {
+	    int omcol = mcol;
+	    Cmatch *op = *p;
+
+	    do {
+		if (!mcol) {
+		    mcol = mcols - 1;
+		    p += mcol;
+		} else {
 		    mcol--;
 		    p--;
 		}
-		wishcol = mcols - 1;
-	    } else if (cmd == Th(z_forwardword) ||
-		       cmd == Th(z_emacsforwardword) ||
-		       cmd == Th(z_viforwardword) ||
-		       cmd == Th(z_viforwardwordend)) {
-		Cmgroup g = *pg;
-		int ol = mline;
-
-		do {
-		    if (mline == mlines - 1) {
-			p -= mline * mcols;
-			pg -= mline * mcols;
-			mline = 0;
-		    } else {
-			mline++;
-			p += mcols;
-			pg += mcols;
-		    }
-		    if (adjust_mcol(wishcol, &p, &pg))
-			continue;
-		} while (ol != mline && (*pg == g || !*pg));
-	    } else if (cmd == Th(z_backwardword) ||
-		       cmd == Th(z_emacsbackwardword) ||
-		       cmd == Th(z_vibackwardword)) {
-		Cmgroup g = *pg;
-		int ol = mline;
-
-		do {
-		    if (!mline) {
-			mline = mlines - 1;
-			p += mline * mcols;
-			pg += mline * mcols;
-		    } else {
-			mline--;
-			p -= mcols;
-			pg -= mcols;
-		    }
-		    if (adjust_mcol(wishcol, &p, &pg))
-			continue;
-		} while (ol != mline && (*pg == g || !*pg));
-	    } else if (cmd == Th(z_completeword) ||
-		       cmd == Th(z_expandorcomplete) ||
-		       cmd == Th(z_expandorcompleteprefix) ||
-		       cmd == Th(z_menucomplete) ||
-		       cmd == Th(z_menuexpandorcomplete) ||
-		       !strcmp(cmd->nam, "menu-select") ||
-		       !strcmp(cmd->nam, "complete-word") ||
-		       !strcmp(cmd->nam, "expand-or-complete") ||
-		       !strcmp(cmd->nam, "expand-or-complete-prefix") ||
-		       !strcmp(cmd->nam, "menu-complete") ||
-		       !strcmp(cmd->nam, "menu-expand-or-complete")) {
-		do_menucmp(0);
-		mselect = (*(minfo.cur))->gnum;
-		setwish = 1;
-		continue;
-	    } else if (cmd == Th(z_reversemenucomplete) ||
-		       !strcmp(cmd->nam, "reverse-menu-complete")) {
-		reversemenucomplete(zlenoargs);
-		mselect = (*(minfo.cur))->gnum;
-		setwish = 1;
-		continue;
-	    } else {
-		ungetkeycmd();
-		break;
+	    } while (!*p || (mcol != omcol && *p == op));
+	    wishcol = mcol;
+	} else if (cmd == Th(z_beginningofbufferorhistory) ||
+		   cmd == Th(z_beginningofline) ||
+		   cmd == Th(z_beginningoflinehist) ||
+		   cmd == Th(z_vibeginningofline)) {
+	    p -= mcol;
+	    mcol = 0;
+	    while (!*p) {
+		mcol++;
+		p++;
 	    }
-	    do_single(**p);
-	    mselect = (**p)->gnum;
-	}
-	if (u)
-	    for (; u; u = u->prev)
-		if (u->lastmatches != lastmatches)
-		    freematches(u->lastmatches);
-
-	selectlocalmap(NULL);
-	mselect = -1;
-	inselect = 0;
-	if (acc) {
-	    menucmp = lastambig = hasoldlist = 0;
-	    do_single(*(minfo.cur));
-	}
-	if (wasnext) {
-	    menucmp = 2;
-	    showinglist = -2;
-	    minfo.asked = 0;
-	}
-	if (!noselect) {
-	    showinglist = -2;
-	    onlyexpl = oe;
-	    if (!smatches)
-		clearlist = 1;
-	    zrefresh();
+	    wishcol = 0;
+	} else if (cmd == Th(z_endofbufferorhistory) ||
+		   cmd == Th(z_endofline) ||
+		   cmd == Th(z_endoflinehist) ||
+		   cmd == Th(z_viendofline)) {
+	    p += mcols - mcol - 1;
+	    mcol = mcols - 1;
+	    while (!*p) {
+		mcol--;
+		p--;
+	    }
+	    wishcol = mcols - 1;
+	} else if (cmd == Th(z_forwardword) ||
+		   cmd == Th(z_emacsforwardword) ||
+		   cmd == Th(z_viforwardword) ||
+		   cmd == Th(z_viforwardwordend)) {
+	    Cmgroup g = *pg;
+	    int ol = mline;
+
+	    do {
+		if (mline == mlines - 1) {
+		    p -= mline * mcols;
+		    pg -= mline * mcols;
+		    mline = 0;
+		} else {
+		    mline++;
+		    p += mcols;
+		    pg += mcols;
+		}
+		if (adjust_mcol(wishcol, &p, &pg))
+		    continue;
+	    } while (ol != mline && (*pg == g || !*pg));
+	} else if (cmd == Th(z_backwardword) ||
+		   cmd == Th(z_emacsbackwardword) ||
+		   cmd == Th(z_vibackwardword)) {
+	    Cmgroup g = *pg;
+	    int ol = mline;
+
+	    do {
+		if (!mline) {
+		    mline = mlines - 1;
+		    p += mline * mcols;
+		    pg += mline * mcols;
+		} else {
+		    mline--;
+		    p -= mcols;
+		    pg -= mcols;
+		}
+		if (adjust_mcol(wishcol, &p, &pg))
+		    continue;
+	    } while (ol != mline && (*pg == g || !*pg));
+	} else if (cmd == Th(z_completeword) ||
+		   cmd == Th(z_expandorcomplete) ||
+		   cmd == Th(z_expandorcompleteprefix) ||
+		   cmd == Th(z_menucomplete) ||
+		   cmd == Th(z_menuexpandorcomplete) ||
+		   !strcmp(cmd->nam, "menu-select") ||
+		   !strcmp(cmd->nam, "complete-word") ||
+		   !strcmp(cmd->nam, "expand-or-complete") ||
+		   !strcmp(cmd->nam, "expand-or-complete-prefix") ||
+		   !strcmp(cmd->nam, "menu-complete") ||
+		   !strcmp(cmd->nam, "menu-expand-or-complete")) {
+	    do_menucmp(0);
+	    mselect = (*(minfo.cur))->gnum;
+	    setwish = 1;
+	    continue;
+	} else if (cmd == Th(z_reversemenucomplete) ||
+		   !strcmp(cmd->nam, "reverse-menu-complete")) {
+	    reversemenucomplete(zlenoargs);
+	    mselect = (*(minfo.cur))->gnum;
+	    setwish = 1;
+	    continue;
+	} else {
+	    ungetkeycmd();
+	    break;
 	}
-	fdat = NULL;
-    } LASTALLOC;
+	do_single(**p);
+	mselect = (**p)->gnum;
+    }
+    if (u)
+	for (; u; u = u->prev)
+	    if (u->lastmatches != lastmatches)
+		freematches(u->lastmatches);
+
+    selectlocalmap(NULL);
+    mselect = -1;
+    inselect = 0;
+    if (acc) {
+	menucmp = lastambig = hasoldlist = 0;
+	do_single(*(minfo.cur));
+    }
+    if (wasnext) {
+	menucmp = 2;
+	showinglist = -2;
+	minfo.asked = 0;
+    }
+    if (!noselect) {
+	showinglist = -2;
+	onlyexpl = oe;
+	if (!smatches)
+	    clearlist = 1;
+	zrefresh();
+    }
+    fdat = NULL;
+
     return (!noselect ^ acc);
 }
 
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index c66557f57..e5d0617ef 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -924,44 +924,40 @@ do_menucmp(int lst)
 	return;
     }
     /* Otherwise go to the next match in the array... */
-    HEAPALLOC {
-	do {
-	    if (!*++(minfo.cur)) {
-		do {
-		    if (!(minfo.group = (minfo.group)->next))
-			minfo.group = amatches;
-		} while (!(minfo.group)->mcount);
-		minfo.cur = minfo.group->matches;
-	    }
-	} while (menuacc &&
-		 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
-	/* ... and insert it into the command line. */
-	metafy_line();
-	do_single(*(minfo.cur));
-	unmetafy_line();
-    } LASTALLOC;
+    do {
+	if (!*++(minfo.cur)) {
+	    do {
+		if (!(minfo.group = (minfo.group)->next))
+		    minfo.group = amatches;
+	    } while (!(minfo.group)->mcount);
+	    minfo.cur = minfo.group->matches;
+	}
+    } while (menuacc &&
+	     !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
+    /* ... and insert it into the command line. */
+    metafy_line();
+    do_single(*(minfo.cur));
+    unmetafy_line();
 }
 
 /**/
 int
 reverse_menu(Hookdef dummy, void *dummy2)
 {
-    HEAPALLOC {
-	do {
-	    if (minfo.cur == (minfo.group)->matches) {
-		do {
-		    if (!(minfo.group = (minfo.group)->prev))
-			minfo.group = lmatches;
-		} while (!(minfo.group)->mcount);
-		minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
-	    } else
-		minfo.cur--;
-	} while (menuacc &&
-		 !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
-	metafy_line();
-	do_single(*(minfo.cur));
-	unmetafy_line();
-    } LASTALLOC;
+    do {
+	if (minfo.cur == (minfo.group)->matches) {
+	    do {
+		if (!(minfo.group = (minfo.group)->prev))
+		    minfo.group = lmatches;
+	    } while (!(minfo.group)->mcount);
+	    minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
+	} else
+	    minfo.cur--;
+    } while (menuacc &&
+	     !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr));
+    metafy_line();
+    do_single(*(minfo.cur));
+    unmetafy_line();
 
     return 0;
 }
@@ -1100,9 +1096,7 @@ num_matches(int normal)
 {
     int alt;
 
-    PERMALLOC {
-	alt = permmatches(0);
-    } LASTALLOC;
+    alt = permmatches(0);
 
     if (normal)
 	return (alt ? 0 : nmatches);
@@ -1118,9 +1112,7 @@ list_lines(void)
 {
     Cmgroup oam;
 
-    PERMALLOC {
-	permmatches(0);
-    } LASTALLOC;
+    permmatches(0);
 
     oam = amatches;
     amatches = pmatches;
@@ -1829,20 +1821,18 @@ list_matches(Hookdef dummy, void *dummy2)
     struct chdata dat;
     int ret;
 
-    HEAPALLOC {
 #ifdef DEBUG
-	/* Sanity check */
-	if (!validlist) {
-	    showmsg("BUG: listmatches called with bogus list");
-	    return 1;
-	}
+    /* Sanity check */
+    if (!validlist) {
+	showmsg("BUG: listmatches called with bogus list");
+	return 1;
+    }
 #endif
 
-	dat.matches = amatches;
-	dat.num = nmatches;
-	dat.cur = NULL;
-	ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
-    } LASTALLOC;
+    dat.matches = amatches;
+    dat.num = nmatches;
+    dat.cur = NULL;
+    ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
 
     return ret;
 }
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 9e6471192..7d8f63fe0 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -130,9 +130,7 @@ cd_init(char *nam, char *sep, char **args, int disp)
 	    zerrnam(nam, "invalid argument: %s", *args, 0);
 	    return 1;
 	}
-	PERMALLOC {
-	    set->strs = arrdup(ap);
-	} LASTALLOC;
+	set->strs = zarrdup(ap);
 
 	if (disp)
 	    cdisp_calc(&(cd_state.disp), set->strs);
@@ -142,9 +140,7 @@ cd_init(char *nam, char *sep, char **args, int disp)
 		zerrnam(nam, "invalid argument: %s", *args, 0);
 		return 1;
 	    }
-	    PERMALLOC {
-		set->matches = arrdup(ap);
-	    } LASTALLOC;
+	    set->matches = zarrdup(ap);
 	    args++;
 	}
 	for (ap = args; *args &&
@@ -153,9 +149,7 @@ cd_init(char *nam, char *sep, char **args, int disp)
 
 	tmp = *args;
 	*args = NULL;
-	PERMALLOC {
-	    set->opts = arrdup(ap);
-	} LASTALLOC;
+	set->opts = zarrdup(ap);
 	if ((*args = tmp))
 	    args++;
     }
@@ -234,9 +228,7 @@ cd_get(char **params)
 	}
 	*sdp = *ssp = *mdp = *msp = NULL;
 
-	PERMALLOC {
-	    p = arrdup(set->opts);
-	} LASTALLOC;
+	p = zarrdup(set->opts);
 
 	setaparam(params[0], p);
 	setaparam(params[1], sd);
@@ -547,21 +539,19 @@ parse_cadef(char *nam, char **args)
 
     /* Looks good. Optimistically allocate the cadef structure. */
 
-    PERMALLOC {
-	ret = (Cadef) zalloc(sizeof(*ret));
-	ret->next = NULL;
-	ret->opts = NULL;
-	ret->args = ret->rest = NULL;
-	ret->defs = arrdup(oargs);
-	ret->ndefs = arrlen(oargs);
-	ret->lastt = time(0);
-	if (single) {
-	    ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
-	    memset(ret->single, 0, 256 * sizeof(Caopt));
-	} else
-	    ret->single = NULL;
-	ret->match = ztrdup(match);
-    } LASTALLOC;
+    ret = (Cadef) zalloc(sizeof(*ret));
+    ret->next = NULL;
+    ret->opts = NULL;
+    ret->args = ret->rest = NULL;
+    ret->defs = zarrdup(oargs);
+    ret->ndefs = arrlen(oargs);
+    ret->lastt = time(0);
+    if (single) {
+	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
+	memset(ret->single, 0, 256 * sizeof(Caopt));
+    } else
+	ret->single = NULL;
+    ret->match = ztrdup(match);
 
     /* Get the definitions. */
 
@@ -752,32 +742,30 @@ parse_cadef(char *nam, char **args)
 	    }
 	    /* Store the option definition. */
 
-	    PERMALLOC {
-		*optp = opt = (Caopt) zalloc(sizeof(*opt));
-		optp = &((*optp)->next);
+	    *optp = opt = (Caopt) zalloc(sizeof(*opt));
+	    optp = &((*optp)->next);
 
-		opt->next = NULL;
-		opt->name = ztrdup(rembslashcolon(name));
-		if (descr)
-		    opt->descr = ztrdup(descr);
-		else if (adpre && oargs && !oargs->next) {
-		    char *d;
+	    opt->next = NULL;
+	    opt->name = ztrdup(rembslashcolon(name));
+	    if (descr)
+		opt->descr = ztrdup(descr);
+	    else if (adpre && oargs && !oargs->next) {
+		char *d;
 
-		    for (d = oargs->descr; *d; d++)
-			if (!iblank(*d))
-			    break;
+		for (d = oargs->descr; *d; d++)
+		    if (!iblank(*d))
+			break;
 
-		    if (*d)
-			opt->descr = tricat(adpre, oargs->descr, adsuf);
-		    else
-			opt->descr = NULL;
-		} else
+		if (*d)
+		    opt->descr = tricat(adpre, oargs->descr, adsuf);
+		else
 		    opt->descr = NULL;
-		opt->xor = xor;
-		opt->type = otype;
-		opt->args = oargs;
-		opt->num = nopts++;
-	    } LASTALLOC;
+	    } else
+		opt->descr = NULL;
+	    opt->xor = xor;
+	    opt->type = otype;
+	    opt->args = oargs;
+	    opt->num = nopts++;
 
 	    if (otype == CAO_DIRECT)
 		ndopts++;
@@ -1064,11 +1052,10 @@ ca_parse_line(Cadef d)
 	state.nth = state.inopt = state.inarg = state.opt = state.arg = 1;
     state.inrest = state.doff = state.singles = state.doff = 0;
     state.curpos = compcurrent;
-    PERMALLOC {
-	state.args = newlinklist();
-	state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList));
-	memset(state.oargs, 0, d->nopts * sizeof(LinkList));
-    } LASTALLOC;
+    state.args = znewlinklist();
+    state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList));
+    memset(state.oargs, 0, d->nopts * sizeof(LinkList));
+
     ca_alloced = 1;
 
     memcpy(&ca_laststate, &state, sizeof(state));
@@ -1089,11 +1076,9 @@ ca_parse_line(Cadef d)
 
 	if (state.def) {
 	    state.arg = 0;
-	    if (state.curopt) {
-		PERMALLOC {
-		    addlinknode(state.oargs[state.curopt->num], ztrdup(line));
-		} LASTALLOC;
-	    }
+	    if (state.curopt)
+		zaddlinknode(state.oargs[state.curopt->num], ztrdup(line));
+
 	    state.opt = (state.def->type == CAA_OPT);
 
 	    if (state.def->type == CAA_REST || state.def->type == CAA_RARGS ||
@@ -1133,9 +1118,8 @@ ca_parse_line(Cadef d)
 	    state.singles = (d->single && (!pe || !*pe) &&
 			     state.curopt->name[1] && !state.curopt->name[2]);
 
-	    PERMALLOC {
-		state.oargs[state.curopt->num] = newlinklist();
-	    } LASTALLOC;
+	    state.oargs[state.curopt->num] = znewlinklist();
+
 	    ca_inactive(d, state.curopt->xor);
 
 	    /* Collect the argument strings. Maybe. */
@@ -1149,9 +1133,8 @@ ca_parse_line(Cadef d)
 		    state.def->type != CAA_RARGS &&
 		    state.def->type != CAA_RREST)
 		    state.def = state.def->next;
-		PERMALLOC {
-		    addlinknode(state.oargs[state.curopt->num], ztrdup(pe));
-		} LASTALLOC;
+
+		zaddlinknode(state.oargs[state.curopt->num], ztrdup(pe));
 	    }
 	    if (state.def)
 		state.opt = 0;
@@ -1174,9 +1157,8 @@ ca_parse_line(Cadef d)
 
 	    for (p = line + 1; p < pe; p++) {
 		if ((tmpopt = d->single[STOUC(*p)])) {
-		    PERMALLOC {
-			state.oargs[tmpopt->num] = newlinklist();
-		    } LASTALLOC;
+		    state.oargs[tmpopt->num] = znewlinklist();
+
 		    ca_inactive(d, tmpopt->xor);
 		}
 	    }
@@ -1189,9 +1171,8 @@ ca_parse_line(Cadef d)
 		    state.def->type != CAA_RARGS &&
 		    state.def->type != CAA_RREST)
 		    state.def = state.def->next;
-		PERMALLOC {
-		    addlinknode(state.oargs[state.curopt->num], ztrdup(pe));
-		} LASTALLOC;
+
+		zaddlinknode(state.oargs[state.curopt->num], ztrdup(pe));
 	    }
 	    if (state.def)
 		state.opt = 0;
@@ -1211,19 +1192,16 @@ ca_parse_line(Cadef d)
 		state.optbeg = state.nargbeg;
 		state.argbeg = cur - 1;
 
-		for (; line; line = compwords[cur++]) {
-		    PERMALLOC {
-			addlinknode(state.args, ztrdup(line));
-		    } LASTALLOC;
-		}
+		for (; line; line = compwords[cur++])
+		    zaddlinknode(state.args, ztrdup(line));
+
 		memcpy(&ca_laststate, &state, sizeof(state));
 		ca_laststate.ddef = NULL;
 		ca_laststate.doff = 0;
 		break;
 	    }
-	    PERMALLOC {
-		addlinknode(state.args, ztrdup(line));
-	    } LASTALLOC;
+	    zaddlinknode(state.args, ztrdup(line));
+
 	    if (state.def && state.def->type != CAA_NORMAL &&
 		state.def->type != CAA_OPT && state.inarg) {
 		state.restbeg = cur;
@@ -1245,10 +1223,10 @@ ca_parse_line(Cadef d)
 
 		if (cur < compcurrent)
 		    memcpy(&ca_laststate, &state, sizeof(state));
-		PERMALLOC {
-		    for (; line; line = compwords[cur++])
-			addlinknode(l, ztrdup(line));
-		} LASTALLOC;
+
+		for (; line; line = compwords[cur++])
+		    zaddlinknode(l, ztrdup(line));
+
 		ca_laststate.ddef = NULL;
 		ca_laststate.doff = 0;
 		break;
@@ -1624,17 +1602,15 @@ parse_cvdef(char *nam, char **args)
     }
     descr = *args++;
 
-    PERMALLOC {
-	ret = (Cvdef) zalloc(sizeof(*ret));
-	ret->descr = ztrdup(descr);
-	ret->hassep = hassep;
-	ret->sep = sep;
-	ret->next = NULL;
-	ret->vals = NULL;
-	ret->defs = arrdup(oargs);
-	ret->ndefs = arrlen(oargs);
-	ret->lastt = time(0);
-    } LASTALLOC;
+    ret = (Cvdef) zalloc(sizeof(*ret));
+    ret->descr = ztrdup(descr);
+    ret->hassep = hassep;
+    ret->sep = sep;
+    ret->next = NULL;
+    ret->vals = NULL;
+    ret->defs = zarrdup(oargs);
+    ret->ndefs = arrlen(oargs);
+    ret->lastt = time(0);
 
     for (valp = &(ret->vals); *args; args++) {
 	p = dupstring(*args);
@@ -1740,17 +1716,15 @@ parse_cvdef(char *nam, char **args)
 	    vtype = CVV_NOARG;
 	    arg = NULL;
 	}
-	PERMALLOC {
-	    *valp = val = (Cvval) zalloc(sizeof(*val));
-	    valp = &((*valp)->next);
-
-	    val->next = NULL;
-	    val->name = ztrdup(name);
-	    val->descr = ztrdup(descr);
-	    val->xor = xor;
-	    val->type = vtype;
-	    val->arg = arg;
-	} LASTALLOC;
+	*valp = val = (Cvval) zalloc(sizeof(*val));
+	valp = &((*valp)->next);
+
+	val->next = NULL;
+	val->name = ztrdup(name);
+	val->descr = ztrdup(descr);
+	val->xor = xor;
+	val->type = vtype;
+	val->arg = arg;
     }
     return ret;
 }
@@ -1837,9 +1811,8 @@ cv_parse_word(Cvdef d)
     state.d = d;
     state.def = NULL;
     state.val = NULL;
-    PERMALLOC {
-	state.vals = (LinkList) newlinklist();
-    } LASTALLOC;
+    state.vals = (LinkList) znewlinklist();
+
     cv_alloced = 1;
 
     if (d->hassep) {
@@ -1856,10 +1829,8 @@ cv_parse_word(Cvdef d)
 		    eq = "";
 
 		if ((ptr = cv_get_val(d, str))) {
-		    PERMALLOC {
-			addlinknode(state.vals, ztrdup(str));
-			addlinknode(state.vals, ztrdup(eq));
-		    } LASTALLOC;
+		    zaddlinknode(state.vals, ztrdup(str));
+		    zaddlinknode(state.vals, ztrdup(eq));
 
 		    cv_inactive(d, ptr->xor);
 		}
@@ -1885,10 +1856,8 @@ cv_parse_word(Cvdef d)
 			eq = "";
 
 		    if ((ptr = cv_get_val(d, str))) {
-			PERMALLOC {
-			    addlinknode(state.vals, ztrdup(str));
-			    addlinknode(state.vals, ztrdup(eq));
-			} LASTALLOC;
+			zaddlinknode(state.vals, ztrdup(str));
+			zaddlinknode(state.vals, ztrdup(eq));
 
 			cv_inactive(d, ptr->xor);
 		    }
@@ -1907,10 +1876,8 @@ cv_parse_word(Cvdef d)
 	    for (str = compprefix; *str; str++) {
 		tmp[0] = *str;
 		if ((ptr = cv_get_val(d, tmp))) {
-		    PERMALLOC {
-			addlinknode(state.vals, ztrdup(tmp));
-			addlinknode(state.vals, ztrdup(""));
-		    } LASTALLOC;
+		    zaddlinknode(state.vals, ztrdup(tmp));
+		    zaddlinknode(state.vals, ztrdup(""));
 
 		    cv_inactive(d, ptr->xor);
 		}
@@ -1918,10 +1885,8 @@ cv_parse_word(Cvdef d)
 	    for (str = compsuffix; *str; str++) {
 		tmp[0] = *str;
 		if ((ptr = cv_get_val(d, tmp))) {
-		    PERMALLOC {
-			addlinknode(state.vals, ztrdup(tmp));
-			addlinknode(state.vals, ztrdup(""));
-		    } LASTALLOC;
+		    zaddlinknode(state.vals, ztrdup(tmp));
+		    zaddlinknode(state.vals, ztrdup(""));
 
 		    cv_inactive(d, ptr->xor);
 		}
@@ -2238,9 +2203,7 @@ settags(char **tags)
 
     comptags[locallevel] = t = (Ctags) zalloc(sizeof(*t));
 
-    PERMALLOC {
-	t->all = arrdup(tags + 1);
-    } LASTALLOC;
+    t->all = zarrdup(tags + 1);
     t->context = ztrdup(*tags);
     t->sets = NULL;
     t->init = 1;
@@ -2332,10 +2295,7 @@ bin_comptags(char *nam, char **args, char *ops, int func)
 	if (comptags[locallevel]->sets) {
 	    char **ret;
 
-	    PERMALLOC {
-		ret = arrdup(comptags[locallevel]->sets->tags);
-	    } LASTALLOC;
-
+	    ret = zarrdup(comptags[locallevel]->sets->tags);
 	    setaparam(args[1], ret);
 	} else
 	    return 1;
@@ -2377,9 +2337,7 @@ bin_comptry(char *nam, char **args, char *ops, int func)
 	if (*args) {
 	    Ctset s = (Ctset) zalloc(sizeof(*s)), l;
 
-	    PERMALLOC {
-		s->tags = arrdup(args);
-	    } LASTALLOC;
+	    s->tags = zarrdup(args);
 	    s->next = NULL;
 
 	    if ((l = comptags[lasttaglevel]->sets)) {
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index b43f00bb3..7fad3845b 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -252,7 +252,7 @@ acceptlineanddownhistory(char **args)
 
     if (!(he = movehistent(quietgethist(histline), 1, HIST_FOREIGN)))
 	return 1;
-    pushnode(bufstack, ztrdup(ZLETEXT(he)));
+    zpushnode(bufstack, ztrdup(ZLETEXT(he)));
     done = 1;
     stackhist = he->histnum;
     return 0;
@@ -506,9 +506,9 @@ pushline(char **args)
 
     if (n < 0)
 	return 1;
-    pushnode(bufstack, metafy((char *) line, ll, META_DUP));
+    zpushnode(bufstack, metafy((char *) line, ll, META_DUP));
     while (--n)
-	pushnode(bufstack, ztrdup(""));
+	zpushnode(bufstack, ztrdup(""));
     stackcs = cs;
     *line = '\0';
     ll = cs = 0;
@@ -902,7 +902,7 @@ acceptandinfernexthistory(char **args)
 	 he; he = movehistent(he, -1, HIST_FOREIGN)) {
 	if (!metadiffer(ZLETEXT(he), (char *) line, ll)) {
 	    he = movehistent(he, 1, HIST_FOREIGN);
-	    pushnode(bufstack, ztrdup(ZLETEXT(he)));
+	    zpushnode(bufstack, ztrdup(ZLETEXT(he)));
 	    stackhist = he->histnum;
 	    return 0;
 	}
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index e39046abb..622cca6d5 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -508,94 +508,94 @@ zleread(char *lp, char *rp, int flags)
     pmpt_attr = txtchange;
     rpromptbuf = promptexpand(rp, 1, NULL, NULL);
     rpmpt_attr = txtchange;
-    PERMALLOC {
-	zlereadflags = flags;
-	histline = curhist;
+
+    zlereadflags = flags;
+    histline = curhist;
 #ifdef HAVE_SELECT
-	FD_ZERO(&foofd);
+    FD_ZERO(&foofd);
 #endif
-	undoing = 1;
-	line = (unsigned char *)zalloc((linesz = 256) + 2);
-	virangeflag = lastcmd = done = cs = ll = mark = 0;
-	vichgflag = 0;
-	viinsbegin = 0;
+    undoing = 1;
+    line = (unsigned char *)zalloc((linesz = 256) + 2);
+    virangeflag = lastcmd = done = cs = ll = mark = 0;
+    vichgflag = 0;
+    viinsbegin = 0;
+    statusline = NULL;
+    selectkeymap("main", 1);
+    selectlocalmap(NULL);
+    fixsuffix();
+    if ((s = (unsigned char *)getlinknode(bufstack))) {
+	setline((char *)s);
+	zsfree((char *)s);
+	if (stackcs != -1) {
+	    cs = stackcs;
+	    stackcs = -1;
+	    if (cs > ll)
+		cs = ll;
+	}
+	if (stackhist != -1) {
+	    histline = stackhist;
+	    stackhist = -1;
+	}
+    }
+    initundo();
+    if (isset(PROMPTCR))
+	putc('\r', shout);
+    if (tmout)
+	alarm(tmout);
+    zleactive = 1;
+    resetneeded = 1;
+    errflag = retflag = 0;
+    lastcol = -1;
+    initmodifier(&zmod);
+    prefixflag = 0;
+    zrefresh();
+    while (!done && !errflag) {
+
 	statusline = NULL;
-	selectkeymap("main", 1);
+	vilinerange = 0;
+	reselectkeymap();
 	selectlocalmap(NULL);
-	fixsuffix();
-	if ((s = (unsigned char *)getlinknode(bufstack))) {
-	    setline((char *)s);
-	    zsfree((char *)s);
-	    if (stackcs != -1) {
-		cs = stackcs;
-		stackcs = -1;
-		if (cs > ll)
-		    cs = ll;
-	    }
-	    if (stackhist != -1) {
-		histline = stackhist;
-		stackhist = -1;
-	    }
+	bindk = getkeycmd();
+	if (!ll && isfirstln && c == eofchar) {
+	    eofsent = 1;
+	    break;
+	}
+	if (bindk) {
+	    if (execzlefunc(bindk, zlenoargs))
+		handlefeep(zlenoargs);
+	    handleprefixes();
+	    /* for vi mode, make sure the cursor isn't somewhere illegal */
+	    if (invicmdmode() && cs > findbol() &&
+		(cs == ll || line[cs] == '\n'))
+		cs--;
+	    if (undoing)
+		handleundo();
+	} else {
+	    errflag = 1;
+	    break;
 	}
-	initundo();
-	if (isset(PROMPTCR))
-	    putc('\r', shout);
-	if (tmout)
-	    alarm(tmout);
-	zleactive = 1;
-	resetneeded = 1;
-	errflag = retflag = 0;
-	lastcol = -1;
-	initmodifier(&zmod);
-	prefixflag = 0;
-	zrefresh();
-	while (!done && !errflag) {
-
-	    statusline = NULL;
-	    vilinerange = 0;
-	    reselectkeymap();
-	    selectlocalmap(NULL);
-	    bindk = getkeycmd();
-	    if (!ll && isfirstln && c == eofchar) {
-		eofsent = 1;
-		break;
-	    }
-	    if (bindk) {
-		if (execzlefunc(bindk, zlenoargs))
-		    handlefeep(zlenoargs);
-		handleprefixes();
-		/* for vi mode, make sure the cursor isn't somewhere illegal */
-		if (invicmdmode() && cs > findbol() &&
-		    (cs == ll || line[cs] == '\n'))
-		    cs--;
-		if (undoing)
-		    handleundo();
-	    } else {
-		errflag = 1;
-		break;
-	    }
 #ifdef HAVE_SELECT
-	    if (baud && !(lastcmd & ZLE_MENUCMP)) {
-		FD_SET(SHTTY, &foofd);
-		tv.tv_sec = 0;
-		if ((tv.tv_usec = cost * costmult) > 500000)
-		    tv.tv_usec = 500000;
-		if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
-					NULL, NULL, &tv) <= 0)
-		    zrefresh();
-	    } else
+	if (baud && !(lastcmd & ZLE_MENUCMP)) {
+	    FD_SET(SHTTY, &foofd);
+	    tv.tv_sec = 0;
+	    if ((tv.tv_usec = cost * costmult) > 500000)
+		tv.tv_usec = 500000;
+	    if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
+				    NULL, NULL, &tv) <= 0)
+		zrefresh();
+	} else
 #endif
-		if (!kungetct)
-		    zrefresh();
-	}
-	statusline = NULL;
-	invalidatelist();
-	trashzle();
-	free(lpromptbuf);
-	free(rpromptbuf);
-	zleactive = zlereadflags = 0;
-	alarm(0);
-    } LASTALLOC;
+	    if (!kungetct)
+		zrefresh();
+    }
+    statusline = NULL;
+    invalidatelist();
+    trashzle();
+    free(lpromptbuf);
+    free(rpromptbuf);
+    zleactive = zlereadflags = 0;
+    alarm(0);
+
     freeundo();
     if (eofsent) {
 	free(line);
@@ -835,9 +835,8 @@ bin_vared(char *name, char **args, char *ops, int func)
 	haso = 1;
     }
     /* edit the parameter value */
-    PERMALLOC {
-	pushnode(bufstack, ztrdup(s));
-    } LASTALLOC;
+    zpushnode(bufstack, ztrdup(s));
+
     varedarg = *args;
     ifl = isfirstln;
     if (ops['e'])
@@ -876,9 +875,7 @@ bin_vared(char *name, char **args, char *ops, int func)
     if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) {
 	char **a;
 
-	PERMALLOC {
-	    a = spacesplit(t, 1);
-	} LASTALLOC;
+	a = spacesplit(t, 1, 0);
 	if (PM_TYPE(pm->flags) == PM_ARRAY)
 	    setaparam(args[0], a);
 	else
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index 4d0669fb6..0e4e58bdb 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -274,7 +274,7 @@ acceptline(char **args)
 int
 acceptandhold(char **args)
 {
-    pushnode(bufstack, metafy((char *)line, ll, META_DUP));
+    zpushnode(bufstack, metafy((char *)line, ll, META_DUP));
     stackcs = cs;
     done = 1;
     return 0;
@@ -745,12 +745,11 @@ executenamedcommand(char *prmt)
 		cmd == Th(z_acceptline) || c == ' ' || c == '\t') {
 		cmdambig = 100;
 
-		HEAPALLOC {
-		    cmdll = newlinklist();
-		    *ptr = 0;
+		cmdll = newlinklist();
+		*ptr = 0;
+
+		scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0);
 
-		    scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0);
-		} LASTALLOC;
 		if (empty(cmdll)) {
 		    feep = 1;
 		    if (listed)
diff --git a/Src/Zle/zle_thingy.c b/Src/Zle/zle_thingy.c
index 86f0f4f1d..25a78c9b9 100644
--- a/Src/Zle/zle_thingy.c
+++ b/Src/Zle/zle_thingy.c
@@ -637,9 +637,7 @@ bin_zle_call(char *name, char **args, char *ops, char func)
     }
 
     t = rthingy(wname);
-    PERMALLOC {
-        ret = execzlefunc(t, args);
-    } LASTALLOC;
+    ret = execzlefunc(t, args);
     unrefthingy(t);
     if (saveflag)
 	zmod = modsave;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 079611015..12fd58b4f 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -696,13 +696,13 @@ docomplete(int lst)
 		    *q = Nularg;
 	    cs = wb;
 	    foredel(we - wb);
-	    HEAPALLOC {
-		untokenize(x = ox = dupstring(w));
-		if (*w == Tilde || *w == Equals || *w == String)
-		    *x = *w;
-		spckword(&x, 0, lincmd, 0);
-		ret = !strcmp(x, ox);
-	    } LASTALLOC;
+
+	    untokenize(x = ox = dupstring(w));
+	    if (*w == Tilde || *w == Equals || *w == String)
+		*x = *w;
+	    spckword(&x, 0, lincmd, 0);
+	    ret = !strcmp(x, ox);
+
 	    untokenize(x);
 	    inststr(x);
 	} else if (COMP_ISEXPAND(lst)) {
@@ -810,7 +810,7 @@ mod_export char *
 dupstrspace(const char *str)
 {
     int len = strlen((char *)str);
-    char *t = (char *) ncalloc(len + 2);
+    char *t = (char *) hcalloc(len + 2);
     strcpy(t, str);
     strcpy(t+len, " ");
     return t;
@@ -868,16 +868,17 @@ freebrinfo(Brinfo p)
 
 /**/
 mod_export Brinfo
-dupbrinfo(Brinfo p, Brinfo *last)
+dupbrinfo(Brinfo p, Brinfo *last, int heap)
 {
     Brinfo ret = NULL, *q = &ret, n = NULL;
 
     while (p) {
-	n = *q = (Brinfo) alloc(sizeof(*n));
+	n = *q = (heap ? (Brinfo) zhalloc(sizeof(*n)) :
+		  (Brinfo) zalloc(sizeof(*n)));
 	q = &(n->next);
 
 	n->next = NULL;
-	n->str = dupstring(p->str);
+	n->str = (heap ? dupstring(p->str) : ztrdup(p->str));
 	n->pos = p->pos;
 	n->qpos = p->qpos;
 	n->curpos = p->curpos;
@@ -946,628 +947,618 @@ get_comp_string(void)
     addx(&tmp);
     linptr = (char *)line;
     pushheap();
-    HEAPALLOC {
-      start:
-	inwhat = IN_NOTHING;
-	/* Now set up the lexer and start it. */
-	parbegin = parend = -1;
-	lincmd = incmdpos;
-	linredir = inredir;
-	zsfree(cmdstr);
-	cmdstr = NULL;
-	zsfree(varname);
-	varname = NULL;
-	insubscr = 0;
-	zleparse = 1;
-	clwpos = -1;
-	lexsave();
-	inpush(dupstrspace((char *) linptr), 0, NULL);
-	strinbeg(0);
-	i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
-
-	/* This loop is possibly the wrong way to do this.  It goes through *
-	 * the previously massaged command line using the lexer.  It stores *
-	 * each token in each command (commands being regarded, roughly, as *
-	 * being separated by tokens | & &! |& || &&).  The loop stops when *
-	 * the end of the command containing the cursor is reached.  It's a *
-	 * simple way to do things, but suffers from an inability to        *
-	 * distinguish actual command arguments from, for example,          *
-	 * filenames in redirections.  (But note that code elsewhere checks *
-	 * if we are completing *in* a redirection.)  The only way to fix   *
-	 * this would be to pass the command line through the parser too,   *
-	 * and get the arguments that way.  Maybe in 3.1...                 */
-	do {
-	    lincmd = ((incmdpos && !ins) || (oins == 2 && i == 2) ||
-		      (ins == 3 && i == 1));
-	    linredir = (inredir && !ins);
-	    oins = ins;
-	    /* Get the next token. */
-	    if (linarr)
-		incmdpos = 0;
-	    ctxtlex();
-
-	    if (tok == LEXERR) {
-		if (!tokstr)
-		    break;
-		for (j = 0, p = tokstr; *p; p++)
-		    if (*p == Snull || *p == Dnull)
-			j++;
-		if (j & 1) {
-		    if (lincmd && strchr(tokstr, '=')) {
-			varq = 1;
-			tok = ENVSTRING;
-		    } else
-			tok = STRING;
-		}
-	    } else if (tok == ENVSTRING)
-		varq = 0;
-	    if (tok == ENVARRAY) {
-		linarr = 1;
-		zsfree(varname);
-		varname = ztrdup(tokstr);
-	    } else if (tok == INPAR)
-		parct++;
-	    else if (tok == OUTPAR) {
-		if (parct)
-		    parct--;
-		else
-		    linarr = 0;
-	    }
-	    if (inredir)
-		rdstr = tokstrings[tok];
-	    if (tok == DINPAR)
-		tokstr = NULL;
 
-	    /* We reached the end. */
-	    if (tok == ENDINPUT)
-		break;
-	    if ((ins && (tok == DO || tok == SEPER)) ||
-		(ins == 2 && i == 2) ||	(ins == 3 && i == 3) ||
-		tok == BAR    || tok == AMPER     ||
-		tok == BARAMP || tok == AMPERBANG ||
-		((tok == DBAR || tok == DAMPER) && !incond)) {
-		/* This is one of the things that separate commands.  If we  *
-		 * already have the things we need (e.g. the token strings), *
-		 * leave the loop.                                           */
-		if (tt)
-		    break;
-		/* Otherwise reset the variables we are collecting data in. */
-		i = tt0 = cp = rd = ins = 0;
-	    }
-	    if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
-			   tok == SELECT || tok == REPEAT || tok == CASE)) {
-		/* The lexer says, this token is in command position, so *
-		 * store the token string (to find the right compctl).   */
-		ins = (tok == REPEAT ? 2 : (tok != STRING));
-		zsfree(cmdstr);
-		cmdstr = ztrdup(tokstr);
-		i = 0;
-	    }
-	    if (!zleparse && !tt0) {
-		/* This is done when the lexer reached the word the cursor is on. */
-		tt = tokstr ? dupstring(tokstr) : NULL;
-		/* If we added a `x', remove it. */
-		if (addedx && tt)
-		    chuck(tt + cs - wb);
-		tt0 = tok;
-		/* Store the number of this word. */
-		clwpos = i;
-		cp = lincmd;
-		rd = linredir;
-		ia = linarr;
-		if (inwhat == IN_NOTHING && incond)
-		    inwhat = IN_COND;
-	    } else if (linredir)
-		continue;
+ start:
+    inwhat = IN_NOTHING;
+    /* Now set up the lexer and start it. */
+    parbegin = parend = -1;
+    lincmd = incmdpos;
+    linredir = inredir;
+    zsfree(cmdstr);
+    cmdstr = NULL;
+    zsfree(varname);
+    varname = NULL;
+    insubscr = 0;
+    zleparse = 1;
+    clwpos = -1;
+    lexsave();
+    inpush(dupstrspace((char *) linptr), 0, NULL);
+    strinbeg(0);
+    i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
+
+    /* This loop is possibly the wrong way to do this.  It goes through *
+     * the previously massaged command line using the lexer.  It stores *
+     * each token in each command (commands being regarded, roughly, as *
+     * being separated by tokens | & &! |& || &&).  The loop stops when *
+     * the end of the command containing the cursor is reached.  It's a *
+     * simple way to do things, but suffers from an inability to        *
+     * distinguish actual command arguments from, for example,          *
+     * filenames in redirections.  (But note that code elsewhere checks *
+     * if we are completing *in* a redirection.)  The only way to fix   *
+     * this would be to pass the command line through the parser too,   *
+     * and get the arguments that way.  Maybe in 3.1...                 */
+    do {
+	lincmd = ((incmdpos && !ins) || (oins == 2 && i == 2) ||
+		  (ins == 3 && i == 1));
+	linredir = (inredir && !ins);
+	oins = ins;
+	/* Get the next token. */
+	if (linarr)
+	    incmdpos = 0;
+	ctxtlex();
+
+	if (tok == LEXERR) {
 	    if (!tokstr)
-		continue;
-	    /* Hack to allow completion after `repeat n do'. */
-	    if (oins == 2 && !i && !strcmp(tokstr, "do"))
-		ins = 3;
-	    /* We need to store the token strings of all words (for some of *
-	     * the more complicated compctl -x things).  They are stored in *
-	     * the clwords array.  Make this array big enough.              */
-	    if (i + 1 == clwsize) {
-		int n;
-		clwords = (char **)realloc(clwords,
-					   (clwsize *= 2) * sizeof(char *));
-		for(n = clwsize; --n > i; )
-		    clwords[n] = NULL;
+		break;
+	    for (j = 0, p = tokstr; *p; p++)
+		if (*p == Snull || *p == Dnull)
+		    j++;
+	    if (j & 1) {
+		if (lincmd && strchr(tokstr, '=')) {
+		    varq = 1;
+		    tok = ENVSTRING;
+		} else
+		    tok = STRING;
 	    }
-	    zsfree(clwords[i]);
-	    /* And store the current token string. */
-	    clwords[i] = ztrdup(tokstr);
-	    sl = strlen(tokstr);
-	    /* Sometimes the lexer gives us token strings ending with *
-	     * spaces we delete the spaces.                           */
-	    while (sl && clwords[i][sl - 1] == ' ' &&
-		   (sl < 2 || (clwords[i][sl - 2] != Bnull &&
-			       clwords[i][sl - 2] != Meta)))
-		clwords[i][--sl] = '\0';
-	    /* If this is the word the cursor is in and we added a `x', *
-	     * remove it.                                               */
-	    if (clwpos == i++ && addedx)
-		chuck(&clwords[i - 1][((cs - wb) >= sl) ?
-				     (sl - 1) : (cs - wb)]);
-	} while (tok != LEXERR && tok != ENDINPUT &&
-		 (tok != SEPER || (zleparse && !tt0)));
-	/* Calculate the number of words stored in the clwords array. */
-	clwnum = (tt || !i) ? i : i - 1;
-	zsfree(clwords[clwnum]);
-	clwords[clwnum] = NULL;
-	t0 = tt0;
-	if (ia) {
-	    lincmd = linredir = 0;
-	    inwhat = IN_ENV;
-	} else {
-	    lincmd = cp;
-	    linredir = rd;
+	} else if (tok == ENVSTRING)
+	    varq = 0;
+	if (tok == ENVARRAY) {
+	    linarr = 1;
+	    zsfree(varname);
+	    varname = ztrdup(tokstr);
+	} else if (tok == INPAR)
+	    parct++;
+	else if (tok == OUTPAR) {
+	    if (parct)
+		parct--;
+	    else
+		linarr = 0;
 	}
-	strinend();
-	inpop();
-	errflag = zleparse = 0;
-	if (parbegin != -1) {
-	    /* We are in command or process substitution if we are not in
-	     * a $((...)). */
-	    if (parend >= 0 && !tmp)
-		line = (unsigned char *) dupstring(tmp = (char *)line);
-	    linptr = (char *) line + ll + addedx - parbegin + 1;
-	    if ((linptr - (char *) line) < 3 || *linptr != '(' ||
-		linptr[-1] != '(' || linptr[-2] != '$') {
-		if (parend >= 0) {
-		    ll -= parend;
-		    line[ll + addedx] = '\0';
-		}
-		lexrestore();
-		goto start;
+	if (inredir)
+	    rdstr = tokstrings[tok];
+	if (tok == DINPAR)
+	    tokstr = NULL;
+
+	/* We reached the end. */
+	if (tok == ENDINPUT)
+	    break;
+	if ((ins && (tok == DO || tok == SEPER)) ||
+	    (ins == 2 && i == 2) ||	(ins == 3 && i == 3) ||
+	    tok == BAR    || tok == AMPER     ||
+	    tok == BARAMP || tok == AMPERBANG ||
+	    ((tok == DBAR || tok == DAMPER) && !incond)) {
+	    /* This is one of the things that separate commands.  If we  *
+	     * already have the things we need (e.g. the token strings), *
+	     * leave the loop.                                           */
+	    if (tt)
+		break;
+	    /* Otherwise reset the variables we are collecting data in. */
+	    i = tt0 = cp = rd = ins = 0;
+	}
+	if (lincmd && (tok == STRING || tok == FOR || tok == FOREACH ||
+		       tok == SELECT || tok == REPEAT || tok == CASE)) {
+	    /* The lexer says, this token is in command position, so *
+	     * store the token string (to find the right compctl).   */
+	    ins = (tok == REPEAT ? 2 : (tok != STRING));
+	    zsfree(cmdstr);
+	    cmdstr = ztrdup(tokstr);
+	    i = 0;
+	}
+	if (!zleparse && !tt0) {
+	    /* This is done when the lexer reached the word the cursor is on. */
+	    tt = tokstr ? dupstring(tokstr) : NULL;
+	    /* If we added a `x', remove it. */
+	    if (addedx && tt)
+		chuck(tt + cs - wb);
+	    tt0 = tok;
+	    /* Store the number of this word. */
+	    clwpos = i;
+	    cp = lincmd;
+	    rd = linredir;
+	    ia = linarr;
+	    if (inwhat == IN_NOTHING && incond)
+		inwhat = IN_COND;
+	} else if (linredir)
+	    continue;
+	if (!tokstr)
+	    continue;
+	/* Hack to allow completion after `repeat n do'. */
+	if (oins == 2 && !i && !strcmp(tokstr, "do"))
+	    ins = 3;
+	/* We need to store the token strings of all words (for some of *
+	 * the more complicated compctl -x things).  They are stored in *
+	 * the clwords array.  Make this array big enough.              */
+	if (i + 1 == clwsize) {
+	    int n;
+	    clwords = (char **)realloc(clwords,
+				       (clwsize *= 2) * sizeof(char *));
+	    for(n = clwsize; --n > i; )
+		clwords[n] = NULL;
+	}
+	zsfree(clwords[i]);
+	/* And store the current token string. */
+	clwords[i] = ztrdup(tokstr);
+	sl = strlen(tokstr);
+	/* Sometimes the lexer gives us token strings ending with *
+	 * spaces we delete the spaces.                           */
+	while (sl && clwords[i][sl - 1] == ' ' &&
+	       (sl < 2 || (clwords[i][sl - 2] != Bnull &&
+			   clwords[i][sl - 2] != Meta)))
+	    clwords[i][--sl] = '\0';
+	/* If this is the word the cursor is in and we added a `x', *
+	 * remove it.                                               */
+	if (clwpos == i++ && addedx)
+	    chuck(&clwords[i - 1][((cs - wb) >= sl) ?
+				 (sl - 1) : (cs - wb)]);
+    } while (tok != LEXERR && tok != ENDINPUT &&
+	     (tok != SEPER || (zleparse && !tt0)));
+    /* Calculate the number of words stored in the clwords array. */
+    clwnum = (tt || !i) ? i : i - 1;
+    zsfree(clwords[clwnum]);
+    clwords[clwnum] = NULL;
+    t0 = tt0;
+    if (ia) {
+	lincmd = linredir = 0;
+	inwhat = IN_ENV;
+    } else {
+	lincmd = cp;
+	linredir = rd;
+    }
+    strinend();
+    inpop();
+    errflag = zleparse = 0;
+    if (parbegin != -1) {
+	/* We are in command or process substitution if we are not in
+	 * a $((...)). */
+	if (parend >= 0 && !tmp)
+	    line = (unsigned char *) dupstring(tmp = (char *)line);
+	linptr = (char *) line + ll + addedx - parbegin + 1;
+	if ((linptr - (char *) line) < 3 || *linptr != '(' ||
+	    linptr[-1] != '(' || linptr[-2] != '$') {
+	    if (parend >= 0) {
+		ll -= parend;
+		line[ll + addedx] = '\0';
 	    }
+	    lexrestore();
+	    goto start;
 	}
+    }
 
-	if (inwhat == IN_MATH)
+    if (inwhat == IN_MATH)
+	s = NULL;
+    else if (!t0 || t0 == ENDINPUT) {
+	/* There was no word (empty line). */
+	s = ztrdup("");
+	we = wb = cs;
+	clwpos = clwnum;
+	t0 = STRING;
+    } else if (t0 == STRING) {
+	/* We found a simple string. */
+	s = ztrdup(clwords[clwpos]);
+    } else if (t0 == ENVSTRING) {
+	char sav;
+	/* The cursor was inside a parameter assignment. */
+
+	if (varq)
+	    tt = clwords[clwpos];
+
+	for (s = tt; iident(*s); s++);
+	sav = *s;
+	*s = '\0';
+	zsfree(varname);
+	varname = ztrdup(tt);
+	*s = sav;
+	if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) {
 	    s = NULL;
-	else if (!t0 || t0 == ENDINPUT) {
-	    /* There was no word (empty line). */
-	    s = ztrdup("");
-	    we = wb = cs;
-	    clwpos = clwnum;
+	    inwhat = IN_MATH;
+	    if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
+		(keypm->flags & PM_HASHED))
+		insubscr = 2;
+	    else
+		insubscr = 1;
+	} else if (*s == '=' && cs > wb + (s - tt)) {
+	    s++;
+	    wb += s - tt;
 	    t0 = STRING;
-	} else if (t0 == STRING) {
-	    /* We found a simple string. */
-	    s = ztrdup(clwords[clwpos]);
-	} else if (t0 == ENVSTRING) {
-	    char sav;
-	    /* The cursor was inside a parameter assignment. */
-
-	    if (varq)
-		tt = clwords[clwpos];
-
-	    for (s = tt; iident(*s); s++);
-	    sav = *s;
-	    *s = '\0';
-	    zsfree(varname);
-	    varname = ztrdup(tt);
-	    *s = sav;
-	    if (skipparens(Inbrack, Outbrack, &s) > 0 || s > tt + cs - wb) {
-		s = NULL;
-		inwhat = IN_MATH;
-		if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
-		    (keypm->flags & PM_HASHED))
-		    insubscr = 2;
-		else
-		    insubscr = 1;
-	    } else if (*s == '=' && cs > wb + (s - tt)) {
-		s++;
-		wb += s - tt;
-		t0 = STRING;
-		s = ztrdup(s);
-		inwhat = IN_ENV;
-	    }
-	    lincmd = 1;
+	    s = ztrdup(s);
+	    inwhat = IN_ENV;
 	}
-	if (we > ll)
-	    we = ll;
-	tt = (char *)line;
+	lincmd = 1;
+    }
+    if (we > ll)
+	we = ll;
+    tt = (char *)line;
+    if (tmp) {
+	line = (unsigned char *)tmp;
+	ll = strlen((char *)line);
+    }
+    if (t0 != STRING && inwhat != IN_MATH) {
 	if (tmp) {
-	    line = (unsigned char *)tmp;
-	    ll = strlen((char *)line);
-	}
-	if (t0 != STRING && inwhat != IN_MATH) {
-	    if (tmp) {
-		tmp = NULL;
-		linptr = (char *)line;
-		lexrestore();
-		addedx = 0;
-		goto start;
-	    }
-	    noaliases = 0;
+	    tmp = NULL;
+	    linptr = (char *)line;
 	    lexrestore();
-	    LASTALLOC_RETURN NULL;
+	    addedx = 0;
+	    goto start;
 	}
-
 	noaliases = 0;
+	lexrestore();
+	return NULL;
+    }
 
-	/* Check if we are in an array subscript.  We simply assume that  *
-	 * we are in a subscript if we are in brackets.  Correct solution *
-	 * is very difficult.  This is quite close, but gets things like  *
-	 * foo[_ wrong (note no $).  If we are in a subscript, treat it   *
-	 * as being in math.                                              */
-	if (inwhat != IN_MATH) {
-	    int i = 0;
-	    char *nnb = (iident(*s) ? s : s + 1), *nb = NULL, *ne = NULL;
-
-	    for (tt = s; ++tt < s + cs - wb;)
-		if (*tt == Inbrack) {
-		    i++;
-		    nb = nnb;
-		    ne = tt;
-		} else if (i && *tt == Outbrack)
-		    i--;
-		else if (!iident(*tt))
-		    nnb = tt + 1;
-	    if (i) {
-		inwhat = IN_MATH;
-		insubscr = 1;
-		if (nb < ne) {
-		    char sav = *ne;
-		    *ne = '\0';
-		    zsfree(varname);
-		    varname = ztrdup(nb);
-		    *ne = sav;
-		    if ((keypm = (Param) paramtab->getnode(paramtab,
-							   varname)) &&
-			(keypm->flags & PM_HASHED))
-			insubscr = 2;
-		}
+    noaliases = 0;
+
+    /* Check if we are in an array subscript.  We simply assume that  *
+     * we are in a subscript if we are in brackets.  Correct solution *
+     * is very difficult.  This is quite close, but gets things like  *
+     * foo[_ wrong (note no $).  If we are in a subscript, treat it   *
+     * as being in math.                                              */
+    if (inwhat != IN_MATH) {
+	int i = 0;
+	char *nnb = (iident(*s) ? s : s + 1), *nb = NULL, *ne = NULL;
+	
+	for (tt = s; ++tt < s + cs - wb;)
+	    if (*tt == Inbrack) {
+		i++;
+		nb = nnb;
+		ne = tt;
+	    } else if (i && *tt == Outbrack)
+		i--;
+	    else if (!iident(*tt))
+		nnb = tt + 1;
+	if (i) {
+	    inwhat = IN_MATH;
+	    insubscr = 1;
+	    if (nb < ne) {
+		char sav = *ne;
+		*ne = '\0';
+		zsfree(varname);
+		varname = ztrdup(nb);
+		*ne = sav;
+		if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
+		    (keypm->flags & PM_HASHED))
+		    insubscr = 2;
 	    }
 	}
-	if (inwhat == IN_MATH) {
-	    if (compfunc || insubscr == 2) {
-		int lev;
-		char *p;
-
-		for (wb = cs - 1, lev = 0; wb > 0; wb--)
-		    if (line[wb] == ']' || line[wb] == ')')
-			lev++;
-		    else if (line[wb] == '[') {
-			if (!lev--)
-			    break;
-		    } else if (line[wb] == '(') {
-			if (!lev && line[wb - 1] == '(')
-			    break;
-			if (lev)
-			    lev--;
-		    }
-		p = (char *) line + wb;
-		wb++;
-		if (wb && (*p == '[' || *p == '(') &&
-		    !skipparens(*p, (*p == '[' ? ']' : ')'), &p)) {
-			we = (p - (char *) line) - 1;
-			if (insubscr == 2)
-			    insubscr = 3;
+    }
+    if (inwhat == IN_MATH) {
+	if (compfunc || insubscr == 2) {
+	    int lev;
+	    char *p;
+
+	    for (wb = cs - 1, lev = 0; wb > 0; wb--)
+		if (line[wb] == ']' || line[wb] == ')')
+		    lev++;
+		else if (line[wb] == '[') {
+		    if (!lev--)
+			break;
+		} else if (line[wb] == '(') {
+		    if (!lev && line[wb - 1] == '(')
+			break;
+		    if (lev)
+			lev--;
 		}
-	    } else {
-		/* In mathematical expression, we complete parameter names  *
-		 * (even if they don't have a `$' in front of them).  So we *
-		 * have to find that name.                                  */
-		for (we = cs; iident(line[we]); we++);
-		for (wb = cs; --wb >= 0 && iident(line[wb]););
-		wb++;
+	    p = (char *) line + wb;
+	    wb++;
+	    if (wb && (*p == '[' || *p == '(') &&
+		!skipparens(*p, (*p == '[' ? ']' : ')'), &p)) {
+		we = (p - (char *) line) - 1;
+		if (insubscr == 2)
+		    insubscr = 3;
 	    }
-	    zsfree(s);
-	    s = zalloc(we - wb + 1);
-	    strncpy(s, (char *) line + wb, we - wb);
-	    s[we - wb] = '\0';
-	    if (wb > 2 && line[wb - 1] == '[' && iident(line[wb - 2])) {
-		int i = wb - 3;
-		unsigned char sav = line[wb - 1];
+	} else {
+	    /* In mathematical expression, we complete parameter names  *
+	     * (even if they don't have a `$' in front of them).  So we *
+	     * have to find that name.                                  */
+	    for (we = cs; iident(line[we]); we++);
+	    for (wb = cs; --wb >= 0 && iident(line[wb]););
+	    wb++;
+	}
+	zsfree(s);
+	s = zalloc(we - wb + 1);
+	strncpy(s, (char *) line + wb, we - wb);
+	s[we - wb] = '\0';
+	if (wb > 2 && line[wb - 1] == '[' && iident(line[wb - 2])) {
+	    int i = wb - 3;
+	    unsigned char sav = line[wb - 1];
 
-		while (i >= 0 && iident(line[i]))
-		    i--;
+	    while (i >= 0 && iident(line[i]))
+		i--;
 
-		line[wb - 1] = '\0';
-		zsfree(varname);
-		varname = ztrdup((char *) line + i + 1);
-		line[wb - 1] = sav;
-		if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
-		    (keypm->flags & PM_HASHED)) {
-		    if (insubscr != 3)
-			insubscr = 2;
-		} else
-		    insubscr = 1;
-	    }
-	}
-	/* This variable will hold the current word in quoted form. */
-	qword = ztrdup(s);
-	offs = cs - wb;
-	if ((p = parambeg(s))) {
-	    for (p = s; *p; p++)
-		if (*p == Dnull)
-		    *p = '"';
-		else if (*p == Snull)
-		    *p = '\'';
+	    line[wb - 1] = '\0';
+	    zsfree(varname);
+	    varname = ztrdup((char *) line + i + 1);
+	    line[wb - 1] = sav;
+	    if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
+		(keypm->flags & PM_HASHED)) {
+		if (insubscr != 3)
+		    insubscr = 2;
+	    } else
+		insubscr = 1;
 	}
-	if ((*s == Snull || *s == Dnull) && !has_real_token(s + 1)) {
-	    char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, "");
-	    int sl = strlen(s);
-
-	    instring = (*s == Snull ? 1 : 2);
-	    zsfree(qipre);
-	    qipre = n;
-	    if (sl > 1 && s[sl - 1] == *s) {
-		n = tricat(q, qisuf, "");
-		zsfree(qisuf);
-		qisuf = n;
-	    }
-	    autoq = ztrdup(q);
+    }
+    /* This variable will hold the current word in quoted form. */
+    qword = ztrdup(s);
+    offs = cs - wb;
+    if ((p = parambeg(s))) {
+	for (p = s; *p; p++)
+	    if (*p == Dnull)
+		*p = '"';
+	    else if (*p == Snull)
+		*p = '\'';
+    }
+    if ((*s == Snull || *s == Dnull) && !has_real_token(s + 1)) {
+	char *q = (*s == Snull ? "'" : "\""), *n = tricat(qipre, q, "");
+	int sl = strlen(s);
+
+	instring = (*s == Snull ? 1 : 2);
+	zsfree(qipre);
+	qipre = n;
+	if (sl > 1 && s[sl - 1] == *s) {
+	    n = tricat(q, qisuf, "");
+	    zsfree(qisuf);
+	    qisuf = n;
 	}
-	/* While building the quoted form, we also clean up the command line. */
-	for (p = s, tt = qword, i = wb; *p; p++, tt++, i++)
-	    if (INULL(*p)) {
-		if (i < cs)
-		    offs--;
-		if (p[1] || *p != Bnull) {
-		    if (*p == Bnull) {
-			*tt = '\\';
-			if (cs == i + 1)
-			    cs++, offs++;
-		    } else {
-			ocs = cs;
-			cs = i;
-			foredel(1);
-			chuck(tt--);
-			if ((cs = ocs) > i--)
-			    cs--;
-			we--;
-		    }
+	autoq = ztrdup(q);
+    }
+    /* While building the quoted form, we also clean up the command line. */
+    for (p = s, tt = qword, i = wb; *p; p++, tt++, i++)
+	if (INULL(*p)) {
+	    if (i < cs)
+		offs--;
+	    if (p[1] || *p != Bnull) {
+		if (*p == Bnull) {
+		    *tt = '\\';
+		    if (cs == i + 1)
+			cs++, offs++;
 		} else {
 		    ocs = cs;
-		    *tt = '\0';
-		    cs = we;
-		    backdel(1);
-		    if (ocs == we)
-			cs = we - 1;
-		    else
-			cs = ocs;
+		    cs = i;
+		    foredel(1);
+		    chuck(tt--);
+		    if ((cs = ocs) > i--)
+			cs--;
 		    we--;
 		}
-		chuck(p--);
+	    } else {
+		ocs = cs;
+		*tt = '\0';
+		cs = we;
+		backdel(1);
+		if (ocs == we)
+		    cs = we - 1;
+		else
+		    cs = ocs;
+		we--;
 	    }
+	    chuck(p--);
+	}
 
-	zsfree(origword);
-	origword = ztrdup(s);
-
-	if (!isset(IGNOREBRACES)) {
-	    /* Try and deal with foo{xxx etc. */
-	    char *curs = s + (isset(COMPLETEINWORD) ? offs : strlen(s));
-	    char *predup = dupstring(s), *dp = predup;
-	    char *bbeg = NULL, *bend = NULL, *dbeg = NULL;
-	    char *lastp = NULL, *firsts = NULL;
-	    int cant = 0, begi = 0, boffs = offs, hascom = 0;
-
-	    for (i = 0, p = s; *p; p++, dp++, i++) {
-		/* careful, ${... is not a brace expansion...
-		 * we try to get braces after a parameter expansion right,
-		 * but this may fail sometimes. sorry.
-		 */
-		if (*p == String || *p == Qstring) {
-		    if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) {
-			char *tp = p + 1;
-
-			if (skipparens(*tp, (*tp == Inbrace ? Outbrace :
-					     (*tp == Inpar ? Outpar : Outbrack)),
-				       &tp)) {
+    zsfree(origword);
+    origword = ztrdup(s);
+
+    if (!isset(IGNOREBRACES)) {
+	/* Try and deal with foo{xxx etc. */
+	char *curs = s + (isset(COMPLETEINWORD) ? offs : strlen(s));
+	char *predup = dupstring(s), *dp = predup;
+	char *bbeg = NULL, *bend = NULL, *dbeg = NULL;
+	char *lastp = NULL, *firsts = NULL;
+	int cant = 0, begi = 0, boffs = offs, hascom = 0;
+
+	for (i = 0, p = s; *p; p++, dp++, i++) {
+	    /* careful, ${... is not a brace expansion...
+	     * we try to get braces after a parameter expansion right,
+	     * but this may fail sometimes. sorry.
+	     */
+	    if (*p == String || *p == Qstring) {
+		if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) {
+		    char *tp = p + 1;
+
+		    if (skipparens(*tp, (*tp == Inbrace ? Outbrace :
+					 (*tp == Inpar ? Outpar : Outbrack)),
+				   &tp)) {
+			tt = NULL;
+			break;
+		    }
+		    i += tp - p;
+		    dp += tp - p;
+		    p = tp;
+		} else {
+		    char *tp = p + 1;
+
+		    for (; *tp == '^' || *tp == Hat ||
+			     *tp == '=' || *tp == Equals ||
+			     *tp == '~' || *tp == Tilde ||
+			     *tp == '#' || *tp == Pound || *tp == '+';
+			 tp++);
+		    if (*tp == Quest || *tp == Star || *tp == String ||
+			*tp == Qstring || *tp == '?' || *tp == '*' ||
+			*tp == '$' || *tp == '-' || *tp == '!' ||
+			*tp == '@')
+			p++, i++;
+		    else {
+			if (idigit(*tp))
+			    while (idigit(*tp))
+				tp++;
+			else if (iident(*tp))
+			    while (iident(*tp))
+				tp++;
+			else {
 			    tt = NULL;
 			    break;
 			}
+			if (*tp == Inbrace) {
+			    cant = 1;
+			    break;
+			}
+			tp--;
 			i += tp - p;
 			dp += tp - p;
 			p = tp;
-		    } else {
-			char *tp = p + 1;
-
-			for (; *tp == '^' || *tp == Hat ||
-				 *tp == '=' || *tp == Equals ||
-				 *tp == '~' || *tp == Tilde ||
-				 *tp == '#' || *tp == Pound || *tp == '+';
-			     tp++);
-			if (*tp == Quest || *tp == Star || *tp == String ||
-			    *tp == Qstring || *tp == '?' || *tp == '*' ||
-			    *tp == '$' || *tp == '-' || *tp == '!' ||
-			    *tp == '@')
-			    p++, i++;
-			else {
-			    if (idigit(*tp))
-				while (idigit(*tp))
-				    tp++;
-			    else if (iident(*tp))
-				while (iident(*tp))
-				    tp++;
-			    else {
-				tt = NULL;
-				break;
-			    }
-			    if (*tp == Inbrace) {
-				cant = 1;
-				break;
-			    }
-			    tp--;
-			    i += tp - p;
-			    dp += tp - p;
-			    p = tp;
-			}
-		    }
-		} else if (p < curs) {
-		    if (*p == Outbrace) {
-			cant = 1;
-			break;
 		    }
-		    if (*p == Inbrace) {
-			if (bbeg) {
-			    Brinfo new;
-			    int len = bend - bbeg;
-
-			    new = (Brinfo) zalloc(sizeof(*new));
-			    nbrbeg++;
+		}
+	    } else if (p < curs) {
+		if (*p == Outbrace) {
+		    cant = 1;
+		    break;
+		}
+		if (*p == Inbrace) {
+		    if (bbeg) {
+			Brinfo new;
+			int len = bend - bbeg;
 
-			    new->next = NULL;
-			    if (lastbrbeg)
-				lastbrbeg->next = new;
-			    else
-				brbeg = new;
-			    lastbrbeg = new;
-
-			    new->next = NULL;
-			    PERMALLOC {
-				new->str = dupstrpfx(bbeg, len);
-				untokenize(new->str);
-			    } LASTALLOC;
-			    new->pos = begi;
-			    *dbeg = '\0';
-			    new->qpos = strlen(quotename(predup, NULL));
-			    *dbeg = '{';
-			    i -= len;
-			    boffs -= len;
-			    strcpy(dbeg, dbeg + len);
-			    dp -= len;
-			}
-			bbeg = lastp = p;
-			dbeg = dp;
-			bend = p + 1;
-			begi = i;
-		    } else if (*p == Comma && bbeg) {
-			bend = p + 1;
-			hascom = 1;
-		    }
-		} else {
-		    if (*p == Inbrace) {
-			cant = 1;
-			break;
-		    }
-		    if (p == curs) {
-			if (bbeg) {
-			    Brinfo new;
-			    int len = bend - bbeg;
+			new = (Brinfo) zalloc(sizeof(*new));
+			nbrbeg++;
 
-			    new = (Brinfo) zalloc(sizeof(*new));
-			    nbrbeg++;
+			new->next = NULL;
+			if (lastbrbeg)
+			    lastbrbeg->next = new;
+			else
+			    brbeg = new;
+			lastbrbeg = new;
 
-			    new->next = NULL;
-			    if (lastbrbeg)
-				lastbrbeg->next = new;
-			    else
-				brbeg = new;
-			    lastbrbeg = new;
-
-			    PERMALLOC {
-				new->str = dupstrpfx(bbeg, len);
-				untokenize(new->str);
-			    } LASTALLOC;
-			    new->pos = begi;
-			    *dbeg = '\0';
-			    new->qpos = strlen(quotename(predup, NULL));
-			    *dbeg = '{';
-			    i -= len;
-			    boffs -= len;
-			    strcpy(dbeg, dbeg + len);
-			    dp -= len;
-			}
-			bbeg = NULL;
+			new->next = NULL;
+			new->str = ztrduppfx(bbeg, len);
+			untokenize(new->str);
+			new->pos = begi;
+			*dbeg = '\0';
+			new->qpos = strlen(quotename(predup, NULL));
+			*dbeg = '{';
+			i -= len;
+			boffs -= len;
+			strcpy(dbeg, dbeg + len);
+			dp -= len;
 		    }
-		    if (*p == Comma) {
-			if (!bbeg)
-			    bbeg = p;
-			hascom = 1;
-		    } else if (*p == Outbrace) {
+		    bbeg = lastp = p;
+		    dbeg = dp;
+		    bend = p + 1;
+		    begi = i;
+		} else if (*p == Comma && bbeg) {
+		    bend = p + 1;
+		    hascom = 1;
+		}
+	    } else {
+		if (*p == Inbrace) {
+		    cant = 1;
+		    break;
+		}
+		if (p == curs) {
+		    if (bbeg) {
 			Brinfo new;
-			int len;
-
-			if (!bbeg)
-			    bbeg = p;
-			len = p + 1 - bbeg;
-			if (!firsts)
-			    firsts = p + 1;
-			
-			new = (Brinfo) zalloc(sizeof(*new));
-			nbrend++;
+			int len = bend - bbeg;
 
-			if (!lastbrend)
-			    lastbrend = new;
+			new = (Brinfo) zalloc(sizeof(*new));
+			nbrbeg++;
 
-			new->next = brend;
-			brend = new;
+			new->next = NULL;
+			if (lastbrbeg)
+			    lastbrbeg->next = new;
+			else
+			    brbeg = new;
+			lastbrbeg = new;
 
-			PERMALLOC {
-			    new->str = dupstrpfx(bbeg, len);
-			    untokenize(new->str);
-			} LASTALLOC;
-			new->pos = dp - predup - len + 1;
-			new->qpos = len;
-			bbeg = NULL;
+			new->str = ztrduppfx(bbeg, len);
+			untokenize(new->str);
+			new->pos = begi;
+			*dbeg = '\0';
+			new->qpos = strlen(quotename(predup, NULL));
+			*dbeg = '{';
+			i -= len;
+			boffs -= len;
+			strcpy(dbeg, dbeg + len);
+			dp -= len;
 		    }
+		    bbeg = NULL;
 		}
-	    }
-	    if (cant) {
-		freebrinfo(brbeg);
-		freebrinfo(brend);
-		brbeg = lastbrbeg = brend = lastbrend = NULL;
-		nbrbeg = nbrend = 0;
-	    } else {
-		if (p == curs && bbeg) {
+		if (*p == Comma) {
+		    if (!bbeg)
+			bbeg = p;
+		    hascom = 1;
+		} else if (*p == Outbrace) {
 		    Brinfo new;
-		    int len = bend - bbeg;
+		    int len;
+
+		    if (!bbeg)
+			bbeg = p;
+		    len = p + 1 - bbeg;
+		    if (!firsts)
+			firsts = p + 1;
 
 		    new = (Brinfo) zalloc(sizeof(*new));
-		    nbrbeg++;
+		    nbrend++;
 
-		    new->next = NULL;
-		    if (lastbrbeg)
-			lastbrbeg->next = new;
-		    else
-			brbeg = new;
-		    lastbrbeg = new;
+		    if (!lastbrend)
+			lastbrend = new;
 
-		    PERMALLOC {
-			new->str = dupstrpfx(bbeg, len);
-			untokenize(new->str);
-		    } LASTALLOC;
-		    new->pos = begi;
-		    *dbeg = '\0';
-		    new->qpos = strlen(quotename(predup, NULL));
-		    *dbeg = '{';
-		    boffs -= len;
-		    strcpy(dbeg, dbeg + len);
+		    new->next = brend;
+		    brend = new;
+
+		    new->str = ztrduppfx(bbeg, len);
+		    untokenize(new->str);
+		    new->pos = dp - predup - len + 1;
+		    new->qpos = len;
+		    bbeg = NULL;
 		}
-		if (brend) {
-		    Brinfo bp, prev = NULL;
-		    int p, l;
-
-		    for (bp = brend; bp; bp = bp->next) {
-			bp->prev = prev;
-			prev = bp;
-			p = bp->pos;
-			l = bp->qpos;
-			bp->pos = strlen(predup + p + l);
-			bp->qpos = strlen(quotename(predup + p + l, NULL));
-			strcpy(predup + p, predup + p + l);
-		    }
+	    }
+	}
+	if (cant) {
+	    freebrinfo(brbeg);
+	    freebrinfo(brend);
+	    brbeg = lastbrbeg = brend = lastbrend = NULL;
+	    nbrbeg = nbrend = 0;
+	} else {
+	    if (p == curs && bbeg) {
+		Brinfo new;
+		int len = bend - bbeg;
+
+		new = (Brinfo) zalloc(sizeof(*new));
+		nbrbeg++;
+
+		new->next = NULL;
+		if (lastbrbeg)
+		    lastbrbeg->next = new;
+		else
+		    brbeg = new;
+		lastbrbeg = new;
+
+		new->str = ztrduppfx(bbeg, len);
+		untokenize(new->str);
+		new->pos = begi;
+		*dbeg = '\0';
+		new->qpos = strlen(quotename(predup, NULL));
+		*dbeg = '{';
+		boffs -= len;
+		strcpy(dbeg, dbeg + len);
+	    }
+	    if (brend) {
+		Brinfo bp, prev = NULL;
+		int p, l;
+
+		for (bp = brend; bp; bp = bp->next) {
+		    bp->prev = prev;
+		    prev = bp;
+		    p = bp->pos;
+		    l = bp->qpos;
+		    bp->pos = strlen(predup + p + l);
+		    bp->qpos = strlen(quotename(predup + p + l, NULL));
+		    strcpy(predup + p, predup + p + l);
 		}
-		if (hascom) {
-		    if (lastp) {
-			char sav = *lastp;
+	    }
+	    if (hascom) {
+		if (lastp) {
+		    char sav = *lastp;
 
-			*lastp = '\0';
-			untokenize(lastprebr = ztrdup(s));
-			*lastp = sav;
-		    }
-		    if ((lastpostbr = ztrdup(firsts)))
-			untokenize(lastpostbr);
+		    *lastp = '\0';
+		    untokenize(lastprebr = ztrdup(s));
+		    *lastp = sav;
 		}
-		zsfree(s);
-		s = ztrdup(predup);
-		offs = boffs;
+		if ((lastpostbr = ztrdup(firsts)))
+		    untokenize(lastpostbr);
 	    }
+	    zsfree(s);
+	    s = ztrdup(predup);
+	    offs = boffs;
 	}
-    } LASTALLOC;
+    }
     lexrestore();
 
     return (char *)s;
@@ -1603,63 +1594,60 @@ doexpansion(char *s, int lst, int olst, int explincmd)
     LinkList vl;
     char *ss;
 
-    DPUTS(useheap, "BUG: useheap in doexpansion()");
-    HEAPALLOC {
-	pushheap();
-	vl = newlinklist();
-	ss = dupstring(s);
-	addlinknode(vl, ss);
-	prefork(vl, 0);
-	if (errflag)
-	    goto end;
-	if (lst == COMP_LIST_EXPAND || lst == COMP_EXPAND) {
-	    int ng = opts[NULLGLOB];
-
-	    opts[NULLGLOB] = 1;
-	    globlist(vl, 1);
-	    opts[NULLGLOB] = ng;
-	}
-	if (errflag)
-	    goto end;
-	if (empty(vl) || !*(char *)peekfirst(vl))
-	    goto end;
-	if (peekfirst(vl) == (void *) ss ||
-		(olst == COMP_EXPAND_COMPLETE &&
-		 !nextnode(firstnode(vl)) && *s == Tilde &&
-		 (ss = dupstring(s), filesubstr(&ss, 0)) &&
-		 !strcmp(ss, (char *)peekfirst(vl)))) {
-	    /* If expansion didn't change the word, try completion if *
-	     * expandorcomplete was called, otherwise, just beep.     */
-	    if (lst == COMP_EXPAND_COMPLETE)
-		docompletion(s, COMP_COMPLETE, explincmd);
-	    goto end;
-	}
-	if (lst == COMP_LIST_EXPAND) {
-	    /* Only the list of expansions was requested. */
-	    ret = listlist(vl);
-	    showinglist = 0;
-	    goto end;
-	}
-	/* Remove the current word and put the expansions there. */
-	cs = wb;
-	foredel(we - wb);
-	while ((ss = (char *)ugetnode(vl))) {
-	    ret = 0;
-	    ss = quotename(ss, NULL);
-	    untokenize(ss);
-	    inststr(ss);
+    pushheap();
+    vl = newlinklist();
+    ss = dupstring(s);
+    addlinknode(vl, ss);
+    prefork(vl, 0);
+    if (errflag)
+	goto end;
+    if (lst == COMP_LIST_EXPAND || lst == COMP_EXPAND) {
+	int ng = opts[NULLGLOB];
+
+	opts[NULLGLOB] = 1;
+	globlist(vl, 1);
+	opts[NULLGLOB] = ng;
+    }
+    if (errflag)
+	goto end;
+    if (empty(vl) || !*(char *)peekfirst(vl))
+	goto end;
+    if (peekfirst(vl) == (void *) ss ||
+	(olst == COMP_EXPAND_COMPLETE &&
+	 !nextnode(firstnode(vl)) && *s == Tilde &&
+	 (ss = dupstring(s), filesubstr(&ss, 0)) &&
+	 !strcmp(ss, (char *)peekfirst(vl)))) {
+	/* If expansion didn't change the word, try completion if *
+	 * expandorcomplete was called, otherwise, just beep.     */
+	if (lst == COMP_EXPAND_COMPLETE)
+	    docompletion(s, COMP_COMPLETE, explincmd);
+	goto end;
+    }
+    if (lst == COMP_LIST_EXPAND) {
+	/* Only the list of expansions was requested. */
+	ret = listlist(vl);
+	showinglist = 0;
+	goto end;
+    }
+    /* Remove the current word and put the expansions there. */
+    cs = wb;
+    foredel(we - wb);
+    while ((ss = (char *)ugetnode(vl))) {
+	ret = 0;
+	ss = quotename(ss, NULL);
+	untokenize(ss);
+	inststr(ss);
 #if 0
-	    if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
-		(cs && line[cs-1] != '/')) {
+	if (olst != COMP_EXPAND_COMPLETE || nonempty(vl) ||
+	    (cs && line[cs-1] != '/')) {
 #endif
-	    if (nonempty(vl)) {
-		spaceinline(1);
-		line[cs++] = ' ';
-	    }
+	if (nonempty(vl)) {
+	    spaceinline(1);
+	    line[cs++] = ' ';
 	}
-      end:
-	popheap();
-    } LASTALLOC;
+    }
+    end:
+    popheap();
 
     return ret;
 }
@@ -2079,61 +2067,59 @@ doexpandhist(void)
     unsigned char *ol;
     int oll, ocs, ne = noerrs, err;
 
-    DPUTS(useheap, "BUG: useheap in doexpandhist()");
-    HEAPALLOC {
-	pushheap();
-	metafy_line();
-	oll = ll;
-	ocs = cs;
-	ol = (unsigned char *)dupstring((char *)line);
-	expanding = 1;
-	excs = cs;
-	ll = cs = 0;
-	lexsave();
-	/* We push ol as it will remain unchanged */
-	inpush((char *) ol, 0, NULL);
-	strinbeg(1);
-	noaliases = 1;
-	noerrs = 1;
-	exlast = inbufct;
-	do {
-	    ctxtlex();
-	} while (tok != ENDINPUT && tok != LEXERR);
-	while (!lexstop)
-	    hgetc();
-	/* We have to save errflags because it's reset in lexrestore. Since  *
-	 * noerrs was set to 1 errflag is true if there was a habort() which *
-	 * means that the expanded string is unusable.                       */
-	err = errflag;
-	noerrs = ne;
-	noaliases = 0;
-	strinend();
-	inpop();
-	zleparse = 0;
-	lexrestore();
-	expanding = 0;
-
-	if (!err) {
-	    cs = excs;
-	    if (strcmp((char *)line, (char *)ol)) {
-		unmetafy_line();
-		/* For vi mode -- reset the beginning-of-insertion pointer   *
-		 * to the beginning of the line.  This seems a little silly, *
-		 * if we are, for example, expanding "exec !!".              */
-		if (viinsbegin > findbol())
-		    viinsbegin = findbol();
-		popheap();
-		LASTALLOC_RETURN 1;
-	    }
+    pushheap();
+    metafy_line();
+    oll = ll;
+    ocs = cs;
+    ol = (unsigned char *)dupstring((char *)line);
+    expanding = 1;
+    excs = cs;
+    ll = cs = 0;
+    lexsave();
+    /* We push ol as it will remain unchanged */
+    inpush((char *) ol, 0, NULL);
+    strinbeg(1);
+    noaliases = 1;
+    noerrs = 1;
+    exlast = inbufct;
+    do {
+	ctxtlex();
+    } while (tok != ENDINPUT && tok != LEXERR);
+    while (!lexstop)
+	hgetc();
+    /* We have to save errflags because it's reset in lexrestore. Since  *
+     * noerrs was set to 1 errflag is true if there was a habort() which *
+     * means that the expanded string is unusable.                       */
+    err = errflag;
+    noerrs = ne;
+    noaliases = 0;
+    strinend();
+    inpop();
+    zleparse = 0;
+    lexrestore();
+    expanding = 0;
+
+    if (!err) {
+	cs = excs;
+	if (strcmp((char *)line, (char *)ol)) {
+	    unmetafy_line();
+	    /* For vi mode -- reset the beginning-of-insertion pointer   *
+	     * to the beginning of the line.  This seems a little silly, *
+	     * if we are, for example, expanding "exec !!".              */
+	    if (viinsbegin > findbol())
+		viinsbegin = findbol();
+	    popheap();
+	    return 1;
 	}
+    }
 
-	strcpy((char *)line, (char *)ol);
-	ll = oll;
-	cs = ocs;
-	unmetafy_line();
+    strcpy((char *)line, (char *)ol);
+    ll = oll;
+    cs = ocs;
+    unmetafy_line();
+
+    popheap();
 
-	popheap();
-    } LASTALLOC;
     return 0;
 }
 
@@ -2166,34 +2152,32 @@ getcurcmd(void)
     int curlincmd;
     char *s = NULL;
 
-    DPUTS(useheap, "BUG: useheap in getcurcmd()");
-    HEAPALLOC {
-	zleparse = 2;
-	lexsave();
-	metafy_line();
-	inpush(dupstrspace((char *) line), 0, NULL);
-	unmetafy_line();
-	strinbeg(1);
-	pushheap();
-	do {
-	    curlincmd = incmdpos;
-	    ctxtlex();
-	    if (tok == ENDINPUT || tok == LEXERR)
-		break;
-	    if (tok == STRING && curlincmd) {
-		zsfree(s);
-		s = ztrdup(tokstr);
-		cmdwb = ll - wordbeg;
-		cmdwe = ll + 1 - inbufct;
-	    }
+    zleparse = 2;
+    lexsave();
+    metafy_line();
+    inpush(dupstrspace((char *) line), 0, NULL);
+    unmetafy_line();
+    strinbeg(1);
+    pushheap();
+    do {
+	curlincmd = incmdpos;
+	ctxtlex();
+	if (tok == ENDINPUT || tok == LEXERR)
+	    break;
+	if (tok == STRING && curlincmd) {
+	    zsfree(s);
+	    s = ztrdup(tokstr);
+	    cmdwb = ll - wordbeg;
+	    cmdwe = ll + 1 - inbufct;
 	}
-	while (tok != ENDINPUT && tok != LEXERR && zleparse);
-	popheap();
-	strinend();
-	inpop();
-	errflag = zleparse = 0;
-	lexrestore();
-    } LASTALLOC;
+    }
+    while (tok != ENDINPUT && tok != LEXERR && zleparse);
+    popheap();
+    strinend();
+    inpop();
+    errflag = zleparse = 0;
+    lexrestore();
+
     return s;
 }
 
@@ -2213,9 +2197,9 @@ processcmd(char **args)
     inststr(bindk->nam);
     inststr(" ");
     untokenize(s);
-    HEAPALLOC {
-	inststr(quotename(s, NULL));
-    } LASTALLOC;
+
+    inststr(quotename(s, NULL));
+
     zsfree(s);
     done = 1;
     return 0;
diff --git a/Src/Zle/zleparameter.c b/Src/Zle/zleparameter.c
index 1ef3c1b40..77417d767 100644
--- a/Src/Zle/zleparameter.c
+++ b/Src/Zle/zleparameter.c
@@ -100,27 +100,24 @@ getpmwidgets(HashTable ht, char *name)
     Param pm = NULL;
     Thingy th;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR | PM_READONLY;
-	pm->sets.cfn = NULL;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = NULL;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if ((th = (Thingy) thingytab->getnode(thingytab, name)) &&
-	    !(th->flags & DISABLED))
-	    pm->u.str = widgetstr(th->widget);
-	else {
-	    pm->u.str = dupstring("");
-	    pm->flags |= PM_UNSET;
-	}
-    } LASTALLOC;
-
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((th = (Thingy) thingytab->getnode(thingytab, name)) &&
+	!(th->flags & DISABLED))
+	pm->u.str = widgetstr(th->widget);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }