about summary refs log tree commit diff
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
parent2b37049c221501c6ae77e0308634aebcdb10060d (diff)
downloadzsh-1054071bd60937ae8a9fbc16c1407211c6198a55.tar.gz
zsh-1054071bd60937ae8a9fbc16c1407211c6198a55.tar.xz
zsh-1054071bd60937ae8a9fbc16c1407211c6198a55.zip
zsh-workers/9839
-rw-r--r--Src/Builtins/sched.c4
-rw-r--r--Src/Modules/example.c4
-rw-r--r--Src/Modules/mapfile.c47
-rw-r--r--Src/Modules/parameter.c660
-rw-r--r--Src/Modules/zftp.c22
-rw-r--r--Src/Modules/zprof.c34
-rw-r--r--Src/Modules/zpty.c4
-rw-r--r--Src/Modules/zutil.c84
-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
-rw-r--r--Src/builtin.c209
-rw-r--r--Src/cond.c2
-rw-r--r--Src/exec.c269
-rw-r--r--Src/glob.c24
-rw-r--r--Src/hist.c11
-rw-r--r--Src/init.c36
-rw-r--r--Src/jobs.c11
-rw-r--r--Src/lex.c47
-rw-r--r--Src/linklist.c36
-rw-r--r--Src/loop.c2
-rw-r--r--Src/main.c3
-rw-r--r--Src/math.c3
-rw-r--r--Src/mem.c46
-rw-r--r--Src/module.c62
-rw-r--r--Src/params.c320
-rw-r--r--Src/parse.c24
-rw-r--r--Src/pattern.c88
-rw-r--r--Src/prompt.c9
-rw-r--r--Src/signals.c40
-rw-r--r--Src/subst.c36
-rw-r--r--Src/utils.c127
-rw-r--r--Src/zsh.h88
42 files changed, 2868 insertions, 3245 deletions
diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c
index 9dcdd9ece..f00a0da38 100644
--- a/Src/Builtins/sched.c
+++ b/Src/Builtins/sched.c
@@ -143,9 +143,7 @@ bin_sched(char *nam, char **argv, char *ops, int func)
     of scheduled commands. */
     sch = (struct schedcmd *) zcalloc(sizeof *sch);
     sch->time = t;
-    PERMALLOC {
-	sch->cmd = zjoin(argv, ' ');
-    } LASTALLOC;
+    sch->cmd = zjoin(argv, ' ', 0);
     sch->next = NULL;
     for (sch2 = (struct schedcmd *)&schedcmds; sch2->next; sch2 = sch2->next);
     sch2->next = sch;
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index 0b15fa064..40620fa96 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -70,9 +70,7 @@ bin_example(char *nam, char **args, char *ops, int func)
     zsfree(strparam);
     strparam = ztrdup(*oargs ? *oargs : "");
     freearray(arrparam);
-    PERMALLOC {
-	arrparam = arrdup(oargs);
-    } LASTALLOC;
+    arrparam = zarrdup(oargs);
     return 0;
 }
 
diff --git a/Src/Modules/mapfile.c b/Src/Modules/mapfile.c
index 5bbc17eca..52c57a75c 100644
--- a/Src/Modules/mapfile.c
+++ b/Src/Modules/mapfile.c
@@ -248,7 +248,7 @@ get_contents(char *fname)
     val = NULL;
     if ((fd = open(fname, O_RDONLY | O_NOCTTY)) >= 0) {
 	LinkList ll;
-	MUSTUSEHEAP("mapfile:get_contents");
+
 	if ((ll = readoutput(fd, 1)))
 	    val = peekfirst(ll);
     }
@@ -264,30 +264,27 @@ getpmmapfile(HashTable ht, char *name)
     char *contents;
     Param pm = NULL;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmmapfile;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmmapfile;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-
-	pm->flags |= (mapfile_pm->flags & PM_READONLY);
-
-	/* Set u.str to contents of file given by name */
-	if ((contents = get_contents(pm->nam)))
-	    pm->u.str = contents;
-	else {
-	    pm->u.str = "";
-	    pm->flags |= PM_UNSET;
-	}
-    } LASTALLOC;
-
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = setpmmapfile;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmmapfile;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    pm->flags |= (mapfile_pm->flags & PM_READONLY);
+
+    /* Set u.str to contents of file given by name */
+    if ((contents = get_contents(pm->nam)))
+	pm->u.str = contents;
+    else {
+	pm->u.str = "";
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 84a70e4c6..d9ae607bc 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -136,27 +136,24 @@ getpmparameter(HashTable ht, char *name)
 {
     Param rpm, pm = NULL;
 
-    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 ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
-	    !(rpm->flags & PM_UNSET))
-	    pm->u.str = paramtypestr(rpm);
-	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 ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
+	!(rpm->flags & PM_UNSET))
+	pm->u.str = paramtypestr(rpm);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -257,34 +254,30 @@ getpmcommand(HashTable ht, char *name)
 	cmdnamtab->filltable(cmdnamtab);
 	cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
     }
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmcommand;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmcommand;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if (cmd) {
-	    if (cmd->flags & HASHED)
-		pm->u.str = cmd->u.cmd;
-	    else {
-		pm->u.str = zhalloc(strlen(*(cmd->u.name)) +
-				    strlen(name) + 2);
-		strcpy(pm->u.str, *(cmd->u.name));
-		strcat(pm->u.str, "/");
-		strcat(pm->u.str, name);
-	    }
-	} else {
-	    pm->u.str = dupstring("");
-	    pm->flags |= PM_UNSET;
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = setpmcommand;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmcommand;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if (cmd) {
+	if (cmd->flags & HASHED)
+	    pm->u.str = cmd->u.cmd;
+	else {
+	    pm->u.str = zhalloc(strlen(*(cmd->u.name)) + strlen(name) + 2);
+	    strcpy(pm->u.str, *(cmd->u.name));
+	    strcat(pm->u.str, "/");
+	    strcat(pm->u.str, name);
 	}
-    } LASTALLOC;
-
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -344,32 +337,28 @@ setfunction(char *name, char *val, int dis)
 
     val = metafy(val, strlen(val), META_REALLOC);
 
-    HEAPALLOC {
-	prog = parse_string(val, 1);
-    } LASTALLOC;
+    prog = parse_string(val, 1);
 
     if (!prog || prog == &dummy_eprog) {
 	zwarn("invalid function definition", value, 0);
 	zsfree(val);
 	return;
     }
-    PERMALLOC {
-	shf = (Shfunc) zalloc(sizeof(*shf));
-	shf->funcdef = dupeprog(prog);
-	shf->flags = dis;
-
-	if (!strncmp(name, "TRAP", 4) &&
-	    (sn = getsignum(name + 4)) != -1) {
-	    if (settrap(sn, shf->funcdef)) {
-		freeeprog(shf->funcdef);
-		zfree(shf, sizeof(*shf));
-		zsfree(val);
-		LASTALLOC_RETURN;
-	    }
-	    sigtrapped[sn] |= ZSIG_FUNC;
+    shf = (Shfunc) zalloc(sizeof(*shf));
+    shf->funcdef = zdupeprog(prog);
+    shf->flags = dis;
+
+    if (!strncmp(name, "TRAP", 4) &&
+	(sn = getsignum(name + 4)) != -1) {
+	if (settrap(sn, shf->funcdef)) {
+	    freeeprog(shf->funcdef);
+	    zfree(shf, sizeof(*shf));
+	    zsfree(val);
+	    return;
 	}
-	shfunctab->addnode(shfunctab, ztrdup(name), shf);
-    } LASTALLOC;
+	sigtrapped[sn] |= ZSIG_FUNC;
+    }
+    shfunctab->addnode(shfunctab, ztrdup(name), shf);
     zsfree(val);
 }
 
@@ -442,41 +431,38 @@ getfunction(HashTable ht, char *name, int dis)
     Shfunc shf;
     Param pm = NULL;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = (dis ? setpmdisfunction : setpmfunction);
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmfunction;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-
-	if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
-	    (dis ? (shf->flags & DISABLED) : !(shf->flags & DISABLED))) {
-	    if (shf->flags & PM_UNDEFINED) {
-		pm->u.str = dyncat("builtin autoload -X",
-				   ((shf->flags & PM_UNALIASED) ?
-				    ((shf->flags & PM_TAGGED) ? "Ut" : "U") :
-				    ((shf->flags & PM_TAGGED) ? "t" : "")));
-	    } else {
-		char *t = getpermtext(shf->funcdef, NULL), *h;
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = (dis ? setpmdisfunction : setpmfunction);
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmfunction;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
+	(dis ? (shf->flags & DISABLED) : !(shf->flags & DISABLED))) {
+	if (shf->flags & PM_UNDEFINED) {
+	    pm->u.str = dyncat("builtin autoload -X",
+			       ((shf->flags & PM_UNALIASED) ?
+				((shf->flags & PM_TAGGED) ? "Ut" : "U") :
+				((shf->flags & PM_TAGGED) ? "t" : "")));
+	} else {
+	    char *t = getpermtext(shf->funcdef, NULL), *h;
 
-		h = dupstring(t);
-		zsfree(t);
-		unmetafy(h, NULL);
+	    h = dupstring(t);
+	    zsfree(t);
+	    unmetafy(h, NULL);
 
-		pm->u.str = h;
-	    }
-	} else {
-	    pm->u.str = dupstring("");
-	    pm->flags |= PM_UNSET;
+	    pm->u.str = h;
 	}
-    } LASTALLOC;
-
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -583,30 +569,27 @@ getbuiltin(HashTable ht, char *name, int dis)
     Param pm = NULL;
     Builtin bn;
 
-    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 ((bn = (Builtin) builtintab->getnode2(builtintab, name)) &&
-	    (dis ? (bn->flags & DISABLED) : !(bn->flags & DISABLED))) {
-	    char *t = ((bn->handlerfunc || (bn->flags & BINF_PREFIX)) ?
-		       "defined" : "undefined");
-
-	    pm->u.str = dupstring(t);
-	} 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 ((bn = (Builtin) builtintab->getnode2(builtintab, name)) &&
+	(dis ? (bn->flags & DISABLED) : !(bn->flags & DISABLED))) {
+	char *t = ((bn->handlerfunc || (bn->flags & BINF_PREFIX)) ?
+		   "defined" : "undefined");
+
+	pm->u.str = dupstring(t);
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -775,27 +758,24 @@ getpmoption(HashTable ht, char *name)
     Param pm = NULL;
     int n;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmoption;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmoption;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-
-	if ((n = optlookup(name)))
-	    pm->u.str = dupstring(opts[n] ? "on" : "off");
-	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->sets.cfn = setpmoption;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmoption;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((n = optlookup(name)))
+	pm->u.str = dupstring(opts[n] ? "on" : "off");
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -871,57 +851,54 @@ getpmmodule(HashTable ht, char *name)
     char *type = NULL;
     LinkNode node;
 
-    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 (!type) {
-	    Module m;
-
-	    for (node = firstnode(modules); node; incnode(node)) {
-		m = (Module) getdata(node);
-		if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
-		    !strcmp(name, m->nam)) {
-		    type = "loaded";
-		    break;
-		}
-	    }
-	}
-	modpmname = name;
-	modpmfound = 0;
-	if (!type) {
-	    scanhashtable(builtintab, 0, 0, 0, modpmbuiltinscan, 0);
-	    if (!modpmfound) {
-		Conddef p;
-
-		for (p = condtab; p; p = p->next)
-		    if (p->module && !strcmp(name, p->module)) {
-			modpmfound = 1;
-			break;
-		    }
-		if (!modpmfound)
-		    scanhashtable(realparamtab, 0, 0, 0, modpmparamscan, 0);
+    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 (!type) {
+	Module m;
+
+	for (node = firstnode(modules); node; incnode(node)) {
+	    m = (Module) getdata(node);
+	    if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
+		!strcmp(name, m->nam)) {
+		type = "loaded";
+		break;
 	    }
-	    if (modpmfound)
-		type = "autoloaded";
 	}
-	if (type)
-	    pm->u.str = dupstring(type);
-	else {
-	    pm->u.str = dupstring("");
-	    pm->flags |= PM_UNSET;
+    }
+    modpmname = name;
+    modpmfound = 0;
+    if (!type) {
+	scanhashtable(builtintab, 0, 0, 0, modpmbuiltinscan, 0);
+	if (!modpmfound) {
+	    Conddef p;
+
+	    for (p = condtab; p; p = p->next)
+		if (p->module && !strcmp(name, p->module)) {
+		    modpmfound = 1;
+		    break;
+		}
+	    if (!modpmfound)
+		scanhashtable(realparamtab, 0, 0, 0, modpmparamscan, 0);
 	}
-    } LASTALLOC;
-
+	if (modpmfound)
+	    type = "autoloaded";
+    }
+    if (type)
+	pm->u.str = dupstring(type);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -991,12 +968,10 @@ static void
 dirssetfn(Param pm, char **x)
 {
     if (!incleanup) {
-	PERMALLOC {
-	    freelinklist(dirstack, freestr);
-	    dirstack = newlinklist();
-	    while (x && *x)
-		addlinknode(dirstack, ztrdup(*x++));
-	} LASTALLOC;
+	freelinklist(dirstack, freestr);
+	dirstack = znewlinklist();
+	while (x && *x)
+	    zaddlinknode(dirstack, ztrdup(*x++));
     }
     if (x)
 	freearray(x);
@@ -1026,26 +1001,23 @@ getpmhistory(HashTable ht, char *name)
     Param pm = NULL;
     Histent he;
 
-    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 ((he = quietgethist(atoi(name))))
-	    pm->u.str = dupstring(he->text);
-	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 ((he = quietgethist(atoi(name))))
+	pm->u.str = dupstring(he->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1145,29 +1117,26 @@ getpmjobtext(HashTable ht, char *name)
     Param pm = NULL;
     int job;
 
-    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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
-	    jobtab[job].stat && jobtab[job].procs &&
-	    !(jobtab[job].stat & STAT_NOPRINT))
-	    pm->u.str = pmjobtext(job);
-	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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobtext(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1251,29 +1220,26 @@ getpmjobstate(HashTable ht, char *name)
     Param pm = NULL;
     int job;
 
-    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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
-	    jobtab[job].stat && jobtab[job].procs &&
-	    !(jobtab[job].stat & STAT_NOPRINT))
-	    pm->u.str = pmjobstate(job);
-	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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobstate(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1329,29 +1295,26 @@ getpmjobdir(HashTable ht, char *name)
     Param pm = NULL;
     int job;
 
-    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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
-           jobtab[job].stat && jobtab[job].procs &&
-           !(jobtab[job].stat & STAT_NOPRINT))
-           pm->u.str = pmjobdir(job);
-       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 ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobdir(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1462,27 +1425,24 @@ getpmnameddir(HashTable ht, char *name)
     Param pm = NULL;
     Nameddir nd;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmnameddir;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmnameddir;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
-	    !(nd->flags & ND_USERNAME))
-	    pm->u.str = dupstring(nd->dir);
-	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->sets.cfn = setpmnameddir;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmnameddir;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	!(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1529,27 +1489,24 @@ getpmuserdir(HashTable ht, char *name)
 
     nameddirtab->filltable(nameddirtab);
 
-    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 ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
-	    (nd->flags & ND_USERNAME))
-	    pm->u.str = dupstring(nd->dir);
-	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 ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -1715,30 +1672,27 @@ getalias(HashTable ht, char *name, int global, int dis)
     Param pm = NULL;
     Alias al;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
-			(dis ? setpmdisralias : setpmralias));
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmalias;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if ((al = (Alias) aliastab->getnode2(aliastab, name)) &&
-	    ((global && (al->flags & ALIAS_GLOBAL)) ||
-	     (!global && !(al->flags & ALIAS_GLOBAL))) &&
-	    (dis ? (al->flags & DISABLED) : !(al->flags & DISABLED)))
-	    pm->u.str = dupstring(al->text);
-	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->sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
+		    (dis ? setpmdisralias : setpmralias));
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmalias;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((al = (Alias) aliastab->getnode2(aliastab, name)) &&
+	((global && (al->flags & ALIAS_GLOBAL)) ||
+	 (!global && !(al->flags & ALIAS_GLOBAL))) &&
+	(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED)))
+	pm->u.str = dupstring(al->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 0df035c74..64565c9e1 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -2887,17 +2887,15 @@ newsession(char *nm)
     }
 
     if (!nptr) {
-	PERMALLOC {
-	    zfsess = (Zftp_session) zcalloc(sizeof(struct zftp_session));
-	    zfsess->name = ztrdup(nm);
-	    zfsess->cfd = zfsess->dfd = -1;
-	    zfsess->params = (char **) zcalloc(sizeof(zfparams));
-	    addlinknode(zfsessions, zfsess);
+	zfsess = (Zftp_session) zcalloc(sizeof(struct zftp_session));
+	zfsess->name = ztrdup(nm);
+	zfsess->cfd = zfsess->dfd = -1;
+	zfsess->params = (char **) zcalloc(sizeof(zfparams));
+	zaddlinknode(zfsessions, zfsess);
 
-	    zfsesscnt++;
-	    zfstatusp = (int *)zrealloc(zfstatusp, sizeof(int)*zfsesscnt);
-	    zfstatusp[zfsessno] = 0;
-	} LASTALLOC;
+	zfsesscnt++;
+	zfstatusp = (int *)zrealloc(zfstatusp, sizeof(int)*zfsesscnt);
+	zfstatusp[zfsessno] = 0;
     }
 
     zfsetparam("ZFTP_SESSION", ztrdup(zfsess->name), ZFPM_READONLY);
@@ -3221,9 +3219,7 @@ boot_(Module m)
 	/* default preferences if user deletes variable */
 	zfprefs = ZFPF_SNDP|ZFPF_PASV;
     
-	PERMALLOC {
-	    zfsessions = newlinklist();
-	} LASTALLOC;
+	zfsessions = znewlinklist();
 	newsession("default");
     }
 
diff --git a/Src/Modules/zprof.c b/Src/Modules/zprof.c
index 59fea3154..5c602ec18 100644
--- a/Src/Modules/zprof.c
+++ b/Src/Modules/zprof.c
@@ -224,28 +224,24 @@ zprof_wrapper(Eprog prog, FuncWrap w, char *name)
     double prev, now;
 
     if (!(f = findpfunc(name))) {
-	PERMALLOC {
-	    f = (Pfunc) zalloc(sizeof(*f));
-	    f->name = ztrdup(name);
-	    f->calls = 0;
-	    f->time = f->self = 0.0;
-	    f->next = calls;
-	    calls = f;
-	    ncalls++;
-	} LASTALLOC;
+	f = (Pfunc) zalloc(sizeof(*f));
+	f->name = ztrdup(name);
+	f->calls = 0;
+	f->time = f->self = 0.0;
+	f->next = calls;
+	calls = f;
+	ncalls++;
     }
     if (stack) {
 	if (!(a = findparc(stack->p, f))) {
-	    PERMALLOC {
-		a = (Parc) zalloc(sizeof(*a));
-		a->from = stack->p;
-		a->to = f;
-		a->calls = 0;
-		a->time = a->self = 0.0;
-		a->next = arcs;
-		arcs = a;
-		narcs++;
-	    } LASTALLOC;
+	    a = (Parc) zalloc(sizeof(*a));
+	    a->from = stack->p;
+	    a->to = f;
+	    a->calls = 0;
+	    a->time = a->self = 0.0;
+	    a->next = arcs;
+	    arcs = a;
+	    narcs++;
 	}
     }
     sf.prev = stack;
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 088979514..250b769a3 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -307,9 +307,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
     p = (Ptycmd) zalloc(sizeof(*p));
 
     p->name = ztrdup(pname);
-    PERMALLOC {
-	p->args = arrdup(args);
-    } LASTALLOC;
+    p->args = zarrdup(args);
     p->fd = master;
     p->pid = pid;
     p->echo = echo;
diff --git a/Src/Modules/zutil.c b/Src/Modules/zutil.c
index 8c552433f..f2a3ed34c 100644
--- a/Src/Modules/zutil.c
+++ b/Src/Modules/zutil.c
@@ -115,9 +115,7 @@ setstypat(Style s, char *pat, Patprog prog, char **vals)
 
 	    if (p->vals)
 		freearray(p->vals);
-	    PERMALLOC {
-		p->vals = arrdup(vals);
-	    } LASTALLOC;
+	    p->vals = zarrdup(vals);
 
 	    return;
 	}
@@ -127,9 +125,7 @@ setstypat(Style s, char *pat, Patprog prog, char **vals)
     p = (Stypat) zalloc(sizeof(*p));
     p->pat = ztrdup(pat);
     p->prog = prog;
-    PERMALLOC {
-	p->vals = arrdup(vals);
-    } LASTALLOC;
+    p->vals = zarrdup(vals);
     p->next = NULL;
 
     /* Calculate the weight. */
@@ -353,9 +349,7 @@ bin_zstyle(char *nam, char **args, char *ops, int func)
 	    int val;
 
 	    if ((s = lookupstyle(args[1], args[2])) && s->vals[0]) {
-		PERMALLOC {
-		    ret = sepjoin(s->vals, (args[4] ? args[4] : " "));
-		} LASTALLOC;
+		ret = sepjoin(s->vals, (args[4] ? args[4] : " "), 0);
 		val = 0;
 	    } else {
 		ret = ztrdup("");
@@ -397,16 +391,12 @@ bin_zstyle(char *nam, char **args, char *ops, int func)
 	    int val;
 
 	    if ((s = lookupstyle(args[1], args[2]))) {
-		PERMALLOC {
-		    ret = arrdup(s->vals);
-		} LASTALLOC;
+		ret = zarrdup(s->vals);
 		val = 0;
 	    } else {
 		char *dummy = NULL;
 
-		PERMALLOC {
-		    ret = arrdup(&dummy);
-		} LASTALLOC;
+		ret = zarrdup(&dummy);
 		val = 1;
 	    }
 	    if (args[0][1] == 'a')
@@ -697,14 +687,12 @@ savematch(MatchData *m)
 {
     char **a;
 
-    PERMALLOC {
-	a = getaparam("match");
-	m->match = a ? arrdup(a) : NULL;
-	a = getaparam("mbegin");
-	m->mbegin = a ? arrdup(a) : NULL;
-	a = getaparam("mend");
-	m->mend = a ? arrdup(a) : NULL;
-    } LASTALLOC;
+    a = getaparam("match");
+    m->match = a ? zarrdup(a) : NULL;
+    a = getaparam("mbegin");
+    m->mbegin = a ? zarrdup(a) : NULL;
+    a = getaparam("mend");
+    m->mend = a ? zarrdup(a) : NULL;
 }
 
 static void
@@ -770,7 +758,7 @@ connectstates(LinkList out, LinkList in)
 
 	for (innode = firstnode(in); innode; innode = nextnode(innode)) {
 	    RParseBranch *inbranch = getdata(innode);
-	    RParseBranch *br = ncalloc(sizeof(*br));
+	    RParseBranch *br = hcalloc(sizeof(*br));
 
 	    br->state = inbranch->state;
 	    br->actions = newlinklist();
@@ -804,7 +792,7 @@ rparseelt(RParseResult *result, jmp_buf *perr)
 	      (3 <= l && s[l - 2] == '/' && (s[l - 1] == '+' ||
 					     s[l - 1] == '-'))))
 	    return 1;
-	st = ncalloc(sizeof(*st));
+	st = hcalloc(sizeof(*st));
 	st->branches = newlinklist();
 	st->cutoff = s[l - 1];
 	if (s[l - 1] == '/') {
@@ -830,7 +818,7 @@ rparseelt(RParseResult *result, jmp_buf *perr)
 	    int l = patternlen + 12; /* (#b)((#B)...)...* */
 	    if(lookahead)
 	        l += lookaheadlen + 4; /* (#B)... */
-	    cp = st->pattern = ncalloc(l);
+	    cp = st->pattern = hcalloc(l);
 	    strcpy(cp, "(#b)((#B)");
 	    cp += 9;
 	    strcpy(cp, pattern);
@@ -849,7 +837,7 @@ rparseelt(RParseResult *result, jmp_buf *perr)
 	if ((s = *rparseargs) && *s == '-') {
 	    rparseargs++;
 	    l = strlen(s);
-	    st->guard = ncalloc(l);
+	    st->guard = hcalloc(l);
 	    memcpy(st->guard, s + 1, l - 1);
 	    st->guard[l - 1] = '\0';
 	} else
@@ -857,19 +845,19 @@ rparseelt(RParseResult *result, jmp_buf *perr)
 	if ((s = *rparseargs) && *s == ':') {
 	    rparseargs++;
 	    l = strlen(s);
-	    st->action = ncalloc(l);
+	    st->action = hcalloc(l);
 	    memcpy(st->action, s + 1, l - 1);
 	    st->action[l - 1] = '\0';
 	} else
 	    st->action = NULL;
 	result->nullacts = NULL;
 	result->in = newlinklist();
-	br = ncalloc(sizeof(*br));
+	br = hcalloc(sizeof(*br));
 	br->state = st;
 	br->actions = newlinklist();
 	addlinknode(result->in, br);
 	result->out = newlinklist();
-	br = ncalloc(sizeof(*br));
+	br = hcalloc(sizeof(*br));
 	br->state = st;
 	br->actions = newlinklist();
 	addlinknode(result->out, br);
@@ -948,7 +936,7 @@ rparseseq(RParseResult *result, jmp_buf *perr)
 
     while (1) {
 	if ((s = *rparseargs) && s[0] == '{' && s[(l = strlen(s)) - 1] == '}') {
-	    char *action = ncalloc(l - 1);
+	    char *action = hcalloc(l - 1);
 	    LinkNode ln;
 
 	    rparseargs++;
@@ -1136,22 +1124,21 @@ bin_zregexparse(char *nam, char **args, char *ops, int func)
     opts[EXTENDEDGLOB] = 1;
 
     rparseargs = args + 3;
-    HEAPALLOC {
-	pushheap();
-        rparsestates = newlinklist();
-	if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) {
-	    if (*rparseargs)
-		zwarnnam(nam, "invalid regex : %s", *rparseargs, 0);
-	    else
-		zwarnnam(nam, "not enough regex arguments", NULL, 0);
-	    ret = 3;
-	} else
-	    ret = 0;
 
-	if (!ret)
-	    ret = rmatch(&result, subj, var1, var2, ops['c']);
-        popheap();
-    } LASTALLOC;
+    pushheap();
+    rparsestates = newlinklist();
+    if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) {
+	if (*rparseargs)
+	    zwarnnam(nam, "invalid regex : %s", *rparseargs, 0);
+	else
+	    zwarnnam(nam, "not enough regex arguments", NULL, 0);
+	ret = 3;
+    } else
+	ret = 0;
+
+    if (!ret)
+	ret = rmatch(&result, subj, var1, var2, ops['c']);
+    popheap();
 
     opts[EXTENDEDGLOB] = oldextendedglob;
     return ret;
@@ -1511,10 +1498,7 @@ bin_zparseopts(char *nam, char **args, char *ops, int func)
 	sethparam(assoc, aval);
     }
     if (del) {
-	PERMALLOC {
-	    pp = arrdup(pp);
-	} LASTALLOC;
-
+	pp = zarrdup(pp);
 	freearray(pparams);
 	pparams = pp;
     }
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;
 }
 
diff --git a/Src/builtin.c b/Src/builtin.c
index 537ef6b2d..bf29e0d33 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -548,9 +548,7 @@ bin_set(char *nam, char **args, char *ops, int func)
     } else {
 	/* set shell arguments */
 	freearray(pparams);
-	PERMALLOC {
-	    pparams = arrdup(args);
-	} LASTALLOC;
+	pparams = zarrdup(args);
     }
     return 0;
 }
@@ -609,15 +607,13 @@ bin_dirs(char *name, char **argv, char *ops, int func)
 	return 0;
     }
     /* replace the stack with the specified directories */
-    PERMALLOC {
-	l = newlinklist();
-	if (*argv) {
-	    while (*argv)
-		addlinknode(l, ztrdup(*argv++));
-	    freelinklist(dirstack, freestr);
-	    dirstack = l;
-	}
-    } LASTALLOC;
+    l = znewlinklist();
+    if (*argv) {
+	while (*argv)
+	    zaddlinknode(l, ztrdup(*argv++));
+	freelinklist(dirstack, freestr);
+	dirstack = l;
+    }
     return 0;
 }
 
@@ -699,13 +695,11 @@ bin_cd(char *nam, char **argv, char *ops, int func)
     }
   brk:
     chasinglinks = ops['P'] || (isset(CHASELINKS) && !ops['L']);
-    PERMALLOC {
-	pushnode(dirstack, ztrdup(pwd));
-	if (!(dir = cd_get_dest(nam, argv, ops, func))) {
-	    zsfree(getlinknode(dirstack));
-	    LASTALLOC_RETURN 1;
-	}
-    } LASTALLOC;
+    zpushnode(dirstack, ztrdup(pwd));
+    if (!(dir = cd_get_dest(nam, argv, ops, func))) {
+	zsfree(getlinknode(dirstack));
+	return 1;
+    }
     cd_new_pwd(func, dir);
 
     if (stat(unmeta(pwd), &st1) < 0) {
@@ -744,9 +738,9 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
 	if (func == BIN_PUSHD && unset(PUSHDTOHOME))
 	    dir = nextnode(firstnode(dirstack));
 	if (dir)
-	    insertlinknode(dirstack, dir, getlinknode(dirstack));
+	    zinsertlinknode(dirstack, dir, getlinknode(dirstack));
 	else if (func != BIN_POPD)
-	    pushnode(dirstack, ztrdup(home));
+	    zpushnode(dirstack, ztrdup(home));
     } else if (!argv[1]) {
 	int dd;
 	char *end;
@@ -767,8 +761,8 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
 	    }
 	}
 	if (!dir)
-	    pushnode(dirstack, ztrdup(strcmp(argv[0], "-")
-				      ? (doprintdir--, argv[0]) : oldpwd));
+	    zpushnode(dirstack, ztrdup(strcmp(argv[0], "-")
+				       ? (doprintdir--, argv[0]) : oldpwd));
     } else {
 	char *u, *d;
 	int len1, len2, len3;
@@ -784,7 +778,7 @@ cd_get_dest(char *nam, char **argv, char *ops, int func)
 	strncpy(d, pwd, len3);
 	strcpy(d + len3, argv[1]);
 	strcat(d, u + len1);
-	pushnode(dirstack, d);
+	zpushnode(dirstack, d);
 	doprintdir++;
     }
 
@@ -1219,7 +1213,7 @@ bin_fc(char *nam, char **argv, char *ops, int func)
 	remhist();
     /* put foo=bar type arguments into the substitution list */
     while (*argv && equalsplit(*argv, &s)) {
-	Asgment a = (Asgment) alloc(sizeof *a);
+	Asgment a = (Asgment) zhalloc(sizeof *a);
 
 	if (!asgf)
 	    asgf = asgl = a;
@@ -1353,7 +1347,7 @@ fcsubs(char **sp, struct asgment *sub)
 	oldpos = s;
 	/* loop over occurences of oldstr in s, replacing them with newstr */
 	while ((newpos = (char *)strstr(oldpos, oldstr))) {
-	    newmem = (char *) alloc(1 + (newpos - s)
+	    newmem = (char *) zhalloc(1 + (newpos - s)
 			+ strlen(newstr) + strlen(newpos + strlen(oldstr)));
 	    ztrncpy(newmem, s, newpos - s);
 	    strcat(newmem, newstr);
@@ -1761,26 +1755,24 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	 * We need to use the special setting function to re-initialise
 	 * the special parameter to empty.
 	 */
-	HEAPALLOC {
-	    switch (PM_TYPE(pm->flags)) {
-	    case PM_SCALAR:
-		pm->sets.cfn(pm, ztrdup(""));
-		break;
-	    case PM_INTEGER:
-		pm->sets.ifn(pm, 0);
-		break;
-	    case PM_EFLOAT:
-	    case PM_FFLOAT:
-		pm->sets.ffn(pm, 0.0);
-		break;
-	    case PM_ARRAY:
-		pm->sets.afn(pm, mkarray(NULL));
-		break;
-	    case PM_HASHED:
-		pm->sets.hfn(pm, newparamtable(17, pm->nam));
-		break;
-	    }
-	} LASTALLOC;
+	switch (PM_TYPE(pm->flags)) {
+	case PM_SCALAR:
+	    pm->sets.cfn(pm, ztrdup(""));
+	    break;
+	case PM_INTEGER:
+	    pm->sets.ifn(pm, 0);
+	    break;
+	case PM_EFLOAT:
+	case PM_FFLOAT:
+	    pm->sets.ffn(pm, 0.0);
+	    break;
+	case PM_ARRAY:
+	    pm->sets.afn(pm, mkarray(NULL));
+	    break;
+	case PM_HASHED:
+	    pm->sets.hfn(pm, newparamtable(17, pm->nam));
+	    break;
+	}
     }
     pm->flags |= (on & PM_READONLY);
     if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) {
@@ -1944,7 +1936,6 @@ bin_typeset(char *name, char **argv, char *ops, int func)
 
     /* With the -m option, treat arguments as glob patterns */
     if (ops['m']) {
-	MUSTUSEHEAP("typeset -m");
 	while ((asg = getasg(*argv++))) {
 	    LinkList pmlist = newlinklist();
 	    LinkNode pmnode;
@@ -2739,7 +2730,7 @@ bin_print(char *name, char **args, char *ops, int func)
     }
     /* compute lengths, and interpret according to -P, -D, -e, etc. */
     argc = arrlen(args);
-    len = (int *)ncalloc(argc * sizeof(int));
+    len = (int *) hcalloc(argc * sizeof(int));
     for(n = 0; n < argc; n++) {
 	/* first \ sequences */
 	if (!ops['e'] && (ops['R'] || ops['r'] || ops['E']))
@@ -2763,7 +2754,7 @@ bin_print(char *name, char **args, char *ops, int func)
 	if(ops['D']) {
 	    Nameddir d = finddir(args[n]);
 	    if(d) {
-		char *arg = alloc(strlen(args[n]) + 1);
+		char *arg = zhalloc(strlen(args[n]) + 1);
 		sprintf(arg, "~%s%s", d->nam,
 			args[n] + strlen(d->dir));
 		args[n] = arg;
@@ -2774,9 +2765,7 @@ bin_print(char *name, char **args, char *ops, int func)
 
     /* -z option -- push the arguments onto the editing buffer stack */
     if (ops['z']) {
-	PERMALLOC {
-	    pushnode(bufstack, sepjoin(args, NULL));
-	} LASTALLOC;
+	zpushnode(bufstack, sepjoin(args, NULL, 0));
 	return 0;
     }
     /* -s option -- add the arguments to the history list */
@@ -2784,26 +2773,24 @@ bin_print(char *name, char **args, char *ops, int func)
 	int nwords = 0, nlen, iwords;
 	char **pargs = args;
 
-	PERMALLOC {
-	    ent = prepnexthistent(++curhist);
-	    while (*pargs++)
-		nwords++;
-	    if ((ent->nwords = nwords)) {
-		ent->words = (short *)zalloc(nwords*2*sizeof(short));
-		nlen = iwords = 0;
-		for (pargs = args; *pargs; pargs++) {
-		    ent->words[iwords++] = nlen;
-		    nlen += strlen(*pargs);
-		    ent->words[iwords++] = nlen;
-		    nlen++;
-		}
-	    } else
-		ent->words = (short *)NULL;
-	    ent->text = zjoin(args, ' ');
-	    ent->stim = ent->ftim = time(NULL);
-	    ent->flags = 0;
-	    addhistnode(histtab, ent->text, ent);
-	} LASTALLOC;
+	ent = prepnexthistent(++curhist);
+	while (*pargs++)
+	    nwords++;
+	if ((ent->nwords = nwords)) {
+	    ent->words = (short *)zalloc(nwords*2*sizeof(short));
+	    nlen = iwords = 0;
+	    for (pargs = args; *pargs; pargs++) {
+		ent->words[iwords++] = nlen;
+		nlen += strlen(*pargs);
+		ent->words[iwords++] = nlen;
+		nlen++;
+	    }
+	} else
+	    ent->words = (short *)NULL;
+	ent->text = zjoin(args, ' ', 0);
+	ent->stim = ent->ftim = time(NULL);
+	ent->flags = 0;
+	addhistnode(histtab, ent->text, ent);
 	return 0;
     }
     /* -u and -p -- output to other than standard output */
@@ -2985,9 +2972,7 @@ bin_shift(char *name, char **argv, char *ops, int func)
 		    ret++;
 		    continue;
 		}
-                PERMALLOC {
-		    s = arrdup(s + num);
-                } LASTALLOC;
+		s = zarrdup(s + num);
                 setaparam(*argv, s);
             }
     } else {
@@ -3197,42 +3182,40 @@ zexit(int val, int from_signal)
 {
     static int in_exit;
 
-    HEAPALLOC {
-	if (isset(MONITOR) && !stopmsg && !from_signal) {
-	    scanjobs();    /* check if jobs need printing           */
-	    if (isset(CHECKJOBS))
-	        checkjobs();   /* check if any jobs are running/stopped */
-	    if (stopmsg) {
-		stopmsg = 2;
-		LASTALLOC_RETURN;
-	    }
-	}
-	if (in_exit++ && from_signal) {
+    if (isset(MONITOR) && !stopmsg && !from_signal) {
+	scanjobs();    /* check if jobs need printing           */
+	if (isset(CHECKJOBS))
+	    checkjobs();   /* check if any jobs are running/stopped */
+	if (stopmsg) {
+	    stopmsg = 2;
 	    LASTALLOC_RETURN;
 	}
-	if (isset(MONITOR)) {
-	    /* send SIGHUP to any jobs left running  */
-	    killrunjobs(from_signal);
-	}
-	if (isset(RCS) && interact) {
-	    if (!nohistsave)
-		savehistfile(NULL, 1, HFILE_USE_OPTIONS);
-	    if (islogin && !subsh) {
-		sourcehome(".zlogout");
+    }
+    if (in_exit++ && from_signal)
+	    return;
+
+    if (isset(MONITOR)) {
+	/* send SIGHUP to any jobs left running  */
+	killrunjobs(from_signal);
+    }
+    if (isset(RCS) && interact) {
+	if (!nohistsave)
+	    savehistfile(NULL, 1, HFILE_USE_OPTIONS);
+	if (islogin && !subsh) {
+	    sourcehome(".zlogout");
 #ifdef GLOBAL_ZLOGOUT
-		if (isset(RCS) && isset(GLOBALRCS))
-		    source(GLOBAL_ZLOGOUT);
+	    if (isset(RCS) && isset(GLOBALRCS))
+		source(GLOBAL_ZLOGOUT);
 #endif
-	    }
 	}
-	if (sigtrapped[SIGEXIT])
-	    dotrap(SIGEXIT);
-	runhookdef(EXITHOOK, NULL);
-	if (mypid != getpid())
-	    _exit(val);
-	else
-	    exit(val);
-    } LASTALLOC;
+    }
+    if (sigtrapped[SIGEXIT])
+	dotrap(SIGEXIT);
+    runhookdef(EXITHOOK, NULL);
+    if (mypid != getpid())
+	_exit(val);
+    else
+	exit(val);
 }
 
 /* . (dot), source */
@@ -3251,11 +3234,9 @@ bin_dot(char *name, char **argv, char *ops, int func)
 	return 0;
     old = pparams;
     /* get arguments for the script */
-    if (argv[1]) {
-	PERMALLOC {
-	    pparams = arrdup(argv + 1);
-	} LASTALLOC;
-    }
+    if (argv[1])
+	pparams = zarrdup(argv + 1);
+
     enam = arg0 = ztrdup(*argv);
     if (isset(FUNCTIONARGZERO)) {
 	old0 = argzero;
@@ -3336,7 +3317,7 @@ bin_eval(char *nam, char **argv, char *ops, int func)
 {
     Eprog prog;
 
-    prog = parse_string(zjoin(argv, ' '), 0);
+    prog = parse_string(zjoin(argv, ' ', 1), 0);
     if (!prog) {
 	errflag = 0;
 	return 1;
@@ -3906,9 +3887,7 @@ bin_trap(char *name, char **argv, char *ops, int func)
 	    zwarnnam(name, "undefined signal: %s", *argv, 0);
 	    break;
 	}
-	PERMALLOC {
-	    t = dupeprog(prog);
-	} LASTALLOC;
+	t = zdupeprog(prog);
 	if (settrap(sig, t))
 	    freeeprog(t);
     }
diff --git a/Src/cond.c b/Src/cond.c
index 30e267009..87c89ea92 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -420,7 +420,7 @@ static void
 tracemodcond(char *name, char **args, int inf)
 {
     char **aptr;
-    MUSTUSEHEAP("tracemodcond");
+
     args = arrdup(args);
     for (aptr = args; *aptr; aptr++)
 	untokenize(*aptr);
diff --git a/Src/exec.c b/Src/exec.c
index cdfd06bba..e4d1be03d 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1237,7 +1237,7 @@ makecline(LinkList list)
     char **argv, **ptr;
 
     /* A bigger argv is necessary for executing scripts */
-    ptr = argv = 2 + (char **) ncalloc((countlinknodes(list) + 4) *
+    ptr = argv = 2 + (char **) hcalloc((countlinknodes(list) + 4) *
 				       sizeof(char *));
 
     if (isset(XTRACE)) {
@@ -1402,7 +1402,7 @@ addfd(int forked, int *save, struct multio **mfds, int fd1, int fd2, int rflag)
 
     if (!mfds[fd1] || unset(MULTIOS)) {
 	if(!mfds[fd1]) {		/* starting a new multio */
-	    mfds[fd1] = (struct multio *) alloc(sizeof(struct multio));
+	    mfds[fd1] = (struct multio *) zhalloc(sizeof(struct multio));
 	    if (!forked && save[fd1] == -2)
 		save[fd1] = (fd1 == fd2) ? -1 : movefd(fd1);
 	}
@@ -2326,8 +2326,6 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
     char *s;
     wordcode ac;
 
-    MUSTUSEHEAP("save_params()");
-    
     *restore_p = newlinklist();
     *remove_p = newlinklist();
 
@@ -2338,7 +2336,7 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
 		paramtab->removenode(paramtab, s);
 	    } else if (!(pm->flags & PM_READONLY) &&
 		       (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) {
-		Param tpm = (Param) alloc(sizeof *tpm);
+		Param tpm = (Param) zhalloc(sizeof *tpm);
 		tpm->nam = s;
 		copyparam(tpm, pm, 1);
 		pm = tpm;
@@ -2671,7 +2669,7 @@ readoutput(int in, int qt)
 
     fin = fdopen(in, "r");
     ret = newlinklist();
-    ptr = buf = (char *) ncalloc(bsiz = 64);
+    ptr = buf = (char *) hcalloc(bsiz = 64);
     while ((c = fgetc(fin)) != EOF || errno == EINTR) {
 	if (c == EOF) {
 	    errno = 0;
@@ -2684,7 +2682,7 @@ readoutput(int in, int qt)
 	    cnt++;
 	}
 	if (++cnt >= bsiz) {
-	    char *pp = (char *) ncalloc(bsiz *= 2);
+	    char *pp = (char *) hcalloc(bsiz *= 2);
 
 	    memcpy(pp, buf, cnt - 1);
 	    ptr = (buf = pp) + cnt - 1;
@@ -2702,7 +2700,7 @@ readoutput(int in, int qt)
 	}
 	addlinknode(ret, buf);
     } else {
-	char **words = spacesplit(buf, 0);
+	char **words = spacesplit(buf, 0, 1);
 
 	while (*words) {
 	    if (isset(GLOBSUBST))
@@ -2752,11 +2750,11 @@ getoutputfile(char *cmd)
 	return NULL;
 
     nam = ztrdup(nam);
-    PERMALLOC {
-	if (!jobtab[thisjob].filelist)
-	    jobtab[thisjob].filelist = newlinklist();
-	addlinknode(jobtab[thisjob].filelist, nam);
-    } LASTALLOC;
+
+    if (!jobtab[thisjob].filelist)
+	jobtab[thisjob].filelist = znewlinklist();
+    zaddlinknode(jobtab[thisjob].filelist, nam);
+
     child_block();
     fd = open(nam, O_WRONLY | O_CREAT | O_EXCL | O_NOCTTY, 0600);
 
@@ -2830,16 +2828,15 @@ getproc(char *cmd)
     if (!(pnam = namedpipe()))
 	return NULL;
 #else
-    pnam = ncalloc(strlen(PATH_DEV_FD) + 6);
+    pnam = hcalloc(strlen(PATH_DEV_FD) + 6);
 #endif
     if (!(prog = parsecmd(cmd)))
 	return NULL;
 #ifndef PATH_DEV_FD
-    PERMALLOC {
-	if (!jobtab[thisjob].filelist)
-	    jobtab[thisjob].filelist = newlinklist();
-	addlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
-    } LASTALLOC;
+    if (!jobtab[thisjob].filelist)
+	jobtab[thisjob].filelist = znewlinklist();
+    zaddlinknode(jobtab[thisjob].filelist, ztrdup(pnam));
+
     if (zfork()) {
 #else
     mpipe(pipes);
@@ -3024,40 +3021,37 @@ execfuncdef(Estate state, int do_exec)
     if (htok)
 	execsubst(names);
 
-    PERMALLOC {
-	while ((s = (char *) ugetnode(names))) {
-	    prog = (Eprog) zalloc(sizeof(*prog));
-	    prog->heap = 0;
-	    prog->len = len;
-	    prog->npats = npats;
-	    prog->pats = pp = (Patprog *) zalloc(len);
-	    prog->prog = (Wordcode) (prog->pats + npats);
-	    for (i = npats; i--; pp++)
-		*pp = dummy_patprog1;
-	    memcpy(prog->prog, state->pc, plen);
-	    prog->strs = (char *) (prog->prog + nprg);
-	    prog->shf = NULL;
-
-	    shf = (Shfunc) zalloc(sizeof(*shf));
-	    shf->funcdef = prog;
-	    shf->flags = 0;
-
-	    /* is this shell function a signal trap? */
-	    if (!strncmp(s, "TRAP", 4) &&
-		(signum = getsignum(s + 4)) != -1) {
-		if (settrap(signum, shf->funcdef)) {
-		    freeeprog(shf->funcdef);
-		    zfree(shf, sizeof(*shf));
-		    state->pc = end;
-		    LASTALLOC_RETURN 1;
-		}
-		sigtrapped[signum] |= ZSIG_FUNC;
+    while ((s = (char *) ugetnode(names))) {
+	prog = (Eprog) zalloc(sizeof(*prog));
+	prog->heap = 0;
+	prog->len = len;
+	prog->npats = npats;
+	prog->pats = pp = (Patprog *) zalloc(len);
+	prog->prog = (Wordcode) (prog->pats + npats);
+	for (i = npats; i--; pp++)
+	    *pp = dummy_patprog1;
+	memcpy(prog->prog, state->pc, plen);
+	prog->strs = (char *) (prog->prog + nprg);
+	prog->shf = NULL;
+
+	shf = (Shfunc) zalloc(sizeof(*shf));
+	shf->funcdef = prog;
+	shf->flags = 0;
+
+	/* is this shell function a signal trap? */
+	if (!strncmp(s, "TRAP", 4) &&
+	    (signum = getsignum(s + 4)) != -1) {
+	    if (settrap(signum, shf->funcdef)) {
+		freeeprog(shf->funcdef);
+		zfree(shf, sizeof(*shf));
+		state->pc = end;
+		return 1;
 	    }
-	    shfunctab->addnode(shfunctab, ztrdup(s), shf);
+	    sigtrapped[signum] |= ZSIG_FUNC;
 	}
-    } LASTALLOC;
-
-    if(isset(HISTNOFUNCTIONS))
+	shfunctab->addnode(shfunctab, ztrdup(s), shf);
+    }
+    if (isset(HISTNOFUNCTIONS))
 	remhist();
     state->pc = end;
     return 0;
@@ -3150,9 +3144,7 @@ execautofn(Estate state, int do_exec)
 	}
     } else {
 	freeeprog(shf->funcdef);
-	PERMALLOC {
-	    shf->funcdef = dupeprog(stripkshdef(prog, shf->nam));
-	} LASTALLOC;
+	shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
 	shf->flags &= ~PM_UNDEFINED;
     }
     popheap();
@@ -3182,9 +3174,7 @@ loadautofn(Shfunc shf)
     }
     if (!prog)
 	prog = &dummy_eprog;
-    PERMALLOC {
-	shf->funcdef = dupeprog(stripkshdef(prog, shf->nam));
-    } LASTALLOC;
+    shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
     shf->flags &= ~PM_UNDEFINED;
 
     popheap();
@@ -3207,89 +3197,87 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
     int obreaks = breaks;
     struct funcstack fstack;
 
-    HEAPALLOC {
-	pushheap();
-	if (trapreturn < 0)
-	    trapreturn--;
-	oldlastval = lastval;
-
-	starttrapscope();
-
-	tab = pparams;
-	oldscriptname = scriptname;
-	scriptname = dupstring(name);
-	oldzoptind = zoptind;
-	zoptind = 1;
-	oldoptcind = optcind;
-	optcind = 0;
-
-	/* We need to save the current options even if LOCALOPTIONS is *
-	 * not currently set.  That's because if it gets set in the    *
-	 * function we need to restore the original options on exit.   */
-	memcpy(saveopts, opts, sizeof(opts));
-
-	if (flags & PM_TAGGED)
-	    opts[XTRACE] = 1;
-	opts[PRINTEXITVALUE] = 0;
-	if (doshargs) {
-	    LinkNode node;
-
-	    node = doshargs->first;
-	    pparams = x = (char **) zcalloc(((sizeof *x) *
-					     (1 + countlinknodes(doshargs))));
-	    if (isset(FUNCTIONARGZERO)) {
-		oargv0 = argzero;
-		argzero = ztrdup((char *) node->dat);
-	    }
-	    node = node->next;
-	    for (; node; node = node->next, x++)
-		*x = ztrdup((char *) node->dat);
-	} else {
-	    pparams = (char **) zcalloc(sizeof *pparams);
-	    if (isset(FUNCTIONARGZERO)) {
-		oargv0 = argzero;
-		argzero = ztrdup(argzero);
-	    }
-	}
-	fstack.name = dupstring(name);
-	fstack.prev = funcstack;
-	funcstack = &fstack;
-	runshfunc(prog, wrappers, fstack.name);
-	funcstack = fstack.prev;
-	if (retflag) {
-	    retflag = 0;
-	    breaks = obreaks;
-	}
-	freearray(pparams);
-	if (oargv0) {
-	    zsfree(argzero);
-	    argzero = oargv0;
-	}
-	optcind = oldoptcind;
-	zoptind = oldzoptind;
-	scriptname = oldscriptname;
-	pparams = tab;
-
-	if (isset(LOCALOPTIONS)) {
-	    /* restore all shell options except PRIVILEGED and RESTRICTED */
-	    saveopts[PRIVILEGED] = opts[PRIVILEGED];
-	    saveopts[RESTRICTED] = opts[RESTRICTED];
-	    memcpy(opts, saveopts, sizeof(opts));
-	} else {
-	    /* just restore a couple. */
-	    opts[XTRACE] = saveopts[XTRACE];
-	    opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
-	    opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
-	}
+    pushheap();
+    if (trapreturn < 0)
+	trapreturn--;
+    oldlastval = lastval;
+
+    starttrapscope();
+
+    tab = pparams;
+    oldscriptname = scriptname;
+    scriptname = dupstring(name);
+    oldzoptind = zoptind;
+    zoptind = 1;
+    oldoptcind = optcind;
+    optcind = 0;
+
+    /* We need to save the current options even if LOCALOPTIONS is *
+     * not currently set.  That's because if it gets set in the    *
+     * function we need to restore the original options on exit.   */
+    memcpy(saveopts, opts, sizeof(opts));
+
+    if (flags & PM_TAGGED)
+	opts[XTRACE] = 1;
+    opts[PRINTEXITVALUE] = 0;
+    if (doshargs) {
+	LinkNode node;
+
+	node = doshargs->first;
+	pparams = x = (char **) zcalloc(((sizeof *x) *
+					 (1 + countlinknodes(doshargs))));
+	if (isset(FUNCTIONARGZERO)) {
+	    oargv0 = argzero;
+	    argzero = ztrdup((char *) node->dat);
+	}
+	node = node->next;
+	for (; node; node = node->next, x++)
+	    *x = ztrdup((char *) node->dat);
+    } else {
+	pparams = (char **) zcalloc(sizeof *pparams);
+	if (isset(FUNCTIONARGZERO)) {
+	    oargv0 = argzero;
+	    argzero = ztrdup(argzero);
+	}
+    }
+    fstack.name = dupstring(name);
+    fstack.prev = funcstack;
+    funcstack = &fstack;
+    runshfunc(prog, wrappers, fstack.name);
+    funcstack = fstack.prev;
+    if (retflag) {
+	retflag = 0;
+	breaks = obreaks;
+    }
+    freearray(pparams);
+    if (oargv0) {
+	zsfree(argzero);
+	argzero = oargv0;
+    }
+    optcind = oldoptcind;
+    zoptind = oldzoptind;
+    scriptname = oldscriptname;
+    pparams = tab;
+
+    if (isset(LOCALOPTIONS)) {
+	/* restore all shell options except PRIVILEGED and RESTRICTED */
+	saveopts[PRIVILEGED] = opts[PRIVILEGED];
+	saveopts[RESTRICTED] = opts[RESTRICTED];
+	memcpy(opts, saveopts, sizeof(opts));
+    } else {
+	/* just restore a couple. */
+	opts[XTRACE] = saveopts[XTRACE];
+	opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
+	opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+    }
 
-	endtrapscope();
+    endtrapscope();
 
-	if (trapreturn < -1)
-	    trapreturn++;
-	if (noreturnval)
-	    lastval = oldlastval;
-	popheap();
-    } LASTALLOC;
+    if (trapreturn < -1)
+	trapreturn++;
+    if (noreturnval)
+	lastval = oldlastval;
+    popheap();
 }
 
 /* This finally executes a shell function and any function wrappers     *
@@ -3354,9 +3342,8 @@ getfpfunc(char *s)
 		    close(fd);
 		    d[len] = '\0';
 		    d = metafy(d, len, META_REALLOC);
-		    HEAPALLOC {
-			r = parse_string(d, 1);
-		    } LASTALLOC;
+
+		    r = parse_string(d, 1);
 
 		    zfree(d, len + 1);
 
diff --git a/Src/glob.c b/Src/glob.c
index a9f90f4a8..05bfbbafb 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -296,7 +296,7 @@ insert(char *s, int checked)
 	if (gf_listtypes || S_ISDIR(mode)) {
 	    int ll = strlen(s);
 
-	    news = (char *)ncalloc(ll + 2);
+	    news = (char *) hcalloc(ll + 2);
 	    strcpy(news, s);
 	    news[ll] = file_type(mode);
 	    news[ll + 1] = '\0';
@@ -625,7 +625,7 @@ parsecomplist(char *instr)
 	instr += (3 + follow);
 
 	/* Now get the next path component if there is one. */
-	l1 = (Complist) alloc(sizeof *l1);
+	l1 = (Complist) zhalloc(sizeof *l1);
 	if ((l1->next = parsecomplist(instr)) == NULL) {
 	    errflag = 1;
 	    return NULL;
@@ -650,7 +650,7 @@ parsecomplist(char *instr)
 		pdflag = 1;
 		instr++;
 	    }
-	    l1 = (Complist) alloc(sizeof *l1);
+	    l1 = (Complist) zhalloc(sizeof *l1);
 	    l1->pat = p1;
 	    l1->closure = 1 + pdflag;
 	    l1->follow = 0;
@@ -665,7 +665,7 @@ parsecomplist(char *instr)
 	if (*instr == '/' || !*instr) {
 	    int ef = *instr == '/';
 
-	    l1 = (Complist) alloc(sizeof *l1);
+	    l1 = (Complist) zhalloc(sizeof *l1);
 	    l1->pat = p1;
 	    l1->closure = 0;
 	    l1->next = ef ? parsecomplist(instr+1) : NULL;
@@ -885,7 +885,6 @@ glob(LinkList list, LinkNode np, int nountok)
 				        /* return */
     struct globdata saved;		/* saved glob state              */
 
-    MUSTUSEHEAP("glob");
     if (unset(GLOBOPT) || !haswilds(ostr)) {
 	if (!nountok)
 	    untokenize(ostr);
@@ -1611,7 +1610,7 @@ xpandredir(struct redir *fn, LinkList tab)
 	while ((nam = (char *)ugetnode(&fake))) {
 	    /* Loop over matches, duplicating the *
 	     * redirection for each file found.   */
-	    ff = (struct redir *)alloc(sizeof *ff);
+	    ff = (struct redir *) zhalloc(sizeof *ff);
 	    *ff = *fn;
 	    ff->name = nam;
 	    addlinknode(tab, ff);
@@ -1755,12 +1754,12 @@ xpandbraces(LinkList list, LinkNode *np)
 	    if (*p) {
 		c1 = p - ccl;
 		if (imeta(c1)) {
-		    str = ncalloc(len + 1);
+		    str = hcalloc(len + 1);
 		    str[pl] = Meta;
 		    str[pl+1] = c1 ^ 32;
 		    strcpy(str + pl + 2, str2);
 		} else {
-		    str = ncalloc(len);
+		    str = hcalloc(len);
 		    str[pl] = c1;
 		    strcpy(str + pl + 1, str2);
 		}
@@ -1791,7 +1790,7 @@ xpandbraces(LinkList list, LinkNode *np)
 	}
 	/* Concatenate the string before the braces (str3), the section *
 	 * just found (str4) and the text after the braces (str2)       */
-	zz = (char *)ncalloc(prev + (str - str4) + strlen(str2) + 1);
+	zz = (char *) hcalloc(prev + (str - str4) + strlen(str2) + 1);
 	ztrncpy(zz, str3, prev);
 	strncat(zz, str4, str - str4);
 	strcat(zz, str2);
@@ -1894,7 +1893,7 @@ get_match_ret(char *s, int b, int e, int fl, char *replstr)
     if (bl)
 	buf[bl - 1] = '\0';
 
-    rr = r = (char *)ncalloc(ll);
+    rr = r = (char *) hcalloc(ll);
 
     if (fl & SUB_MATCH) {
 	/* copy matched portion to new buffer */
@@ -1978,7 +1977,7 @@ compgetmatch(char *pat, int *flp, char **replstrp)
  * This is called from paramsubst to get the match for ${foo#bar} etc.
  * fl is a set of the SUB_* flags defined in zsh.h
  * *sp points to the string we have to modify. The n'th match will be
- * returned in *sp. ncalloc is used to get memory for the result string.
+ * returned in *sp. The heap is used to get memory for the result string.
  * replstr is the replacement string from a ${.../orig/repl}, in
  * which case pat is the original.
  *
@@ -2009,7 +2008,7 @@ getmatcharr(char ***ap, char *pat, int fl, int n, char *replstr)
     if (!(p = compgetmatch(pat, &fl, &replstr)))
 	return;
 
-    *ap = pp = ncalloc(sizeof(char *) * (arrlen(arr) + 1));
+    *ap = pp = hcalloc(sizeof(char *) * (arrlen(arr) + 1));
     while ((*pp = *arr++))
 	if (igetmatch(pp, p, fl, n, replstr))
 	    pp++;
@@ -2022,7 +2021,6 @@ igetmatch(char **sp, Patprog p, int fl, int n, char *replstr)
     char *s = *sp, *t, sav;
     int i, l = strlen(*sp), ml = ztrlen(*sp), matched = 1;
 
-    MUSTUSEHEAP("igetmatch");	/* presumably covered by prefork() test */
     repllist = NULL;
 
     /* perform must-match test for complex closures */
diff --git a/Src/hist.c b/Src/hist.c
index c14dc645d..e922f30aa 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -987,9 +987,8 @@ hend(void)
 	    fflush(shout);
 	}
 	if (flag & HISTFLAG_RECALL) {
-	    PERMALLOC {
-		pushnode(bufstack, ptr);
-	    } LASTALLOC;
+	    zpushnode(bufstack, ptr);
+
 	    save = 0;
 	} else
 	    zsfree(ptr);
@@ -1420,7 +1419,7 @@ convamps(char *out, char *in, int inlen)
 	    slen += inlen - 1, sdup = 1;
     if (!sdup)
 	return out;
-    ret = pp = (char *)alloc(slen + 1);
+    ret = pp = (char *) zhalloc(slen + 1);
     for (ptr = out; *ptr; ptr++)
 	if (*ptr == '\\')
 	    *pp++ = *++ptr;
@@ -1522,7 +1521,7 @@ quote(char **tr)
 	} else if (inblank(*ptr) && !inquotes && ptr[-1] != '\\')
 	    len += 2;
     ptr = *str;
-    *str = rptr = (char *)alloc(len);
+    *str = rptr = (char *) zhalloc(len);
     *rptr++ = '\'';
     for (; *ptr; ptr++)
 	if (*ptr == '\'') {
@@ -1559,7 +1558,7 @@ quotebreak(char **tr)
 	else if (inblank(*ptr))
 	    len += 2;
     ptr = *str;
-    *str = rptr = (char *)alloc(len);
+    *str = rptr = (char *) zhalloc(len);
     *rptr++ = '\'';
     for (; *ptr;)
 	if (*ptr == '\'') {
diff --git a/Src/init.c b/Src/init.c
index 9832ddf4a..f35336fbf 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -87,13 +87,6 @@ mod_export int (*getkeyptr) _((int));
 /**/
 mod_export sigset_t sigchld_mask;
 
-#ifdef DEBUG
-/* depth of allocation type stack */
-
-/**/
-mod_export int alloc_stackp;
-#endif
-
 /**/
 mod_export struct hookdef zshhooks[] = {
     HOOKDEF("exit", NULL, HOOKF_ALL),
@@ -106,9 +99,6 @@ void
 loop(int toplevel, int justonce)
 {
     Eprog prog;
-#ifdef DEBUG
-    int oasp = toplevel ? 0 : alloc_stackp;
-#endif
 
     pushheap();
     for (;;) {
@@ -138,12 +128,11 @@ loop(int toplevel, int justonce)
 		LinkList args;
 		int osc = sfcontext;
 
-		PERMALLOC {
-		    args = newlinklist();
-		    addlinknode(args, "preexec");
-		    if (hist_ring)
-			addlinknode(args, hist_ring->text);
-		} LASTALLOC;
+		args = znewlinklist();
+		zaddlinknode(args, "preexec");
+		if (hist_ring)
+		    zaddlinknode(args, hist_ring->text);
+
 		sfcontext = SFC_HOOK;
 		doshfunc("preexec", preprog, args, 0, 1);
 		sfcontext = osc;
@@ -159,7 +148,6 @@ loop(int toplevel, int justonce)
 	    if (toplevel)
 		noexitct = 0;
 	}
-	DPUTS(alloc_stackp != oasp, "BUG: alloc_stackp changed in loop()");
 	if (ferror(stderr)) {
 	    zerr("write error", NULL, 0);
 	    clearerr(stderr);
@@ -263,7 +251,7 @@ parseargs(char **argv)
 	argv++;
     }
     doneoptions:
-    paramlist = newlinklist();
+    paramlist = znewlinklist();
     if (cmd) {
 	if (!*argv) {
 	    zerr("string expected after -%s", cmd, 0);
@@ -284,7 +272,7 @@ parseargs(char **argv)
 	    argv++;
 	}
 	while (*argv)
-	    addlinknode(paramlist, ztrdup(*argv++));
+	    zaddlinknode(paramlist, ztrdup(*argv++));
     } else
 	opts[SHINSTDIN] = 1;
     if(isset(SINGLECOMMAND))
@@ -642,8 +630,8 @@ setupvals(void)
     watch    = mkarray(NULL);
     psvar    = mkarray(NULL);
     module_path = mkarray(ztrdup(MODULE_DIR));
-    modules = newlinklist();
-    linkedmodules = newlinklist();
+    modules = znewlinklist();
+    linkedmodules = znewlinklist();
 
     /* Set default prompts */
     if(unset(INTERACTIVE)) {
@@ -743,9 +731,9 @@ setupvals(void)
     trapreturn = 0;
     noerrexit = -1;
     nohistsave = 1;
-    dirstack = newlinklist();
-    bufstack = newlinklist();
-    prepromptfns = newlinklist();
+    dirstack = znewlinklist();
+    bufstack = znewlinklist();
+    prepromptfns = znewlinklist();
     hsubl = hsubr = NULL;
     lastpid = 0;
     bshin = SHIN ? fdopen(SHIN, "r") : stdin;
diff --git a/Src/jobs.c b/Src/jobs.c
index cfa977bef..29520a91b 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -565,13 +565,10 @@ should_report_time(Job j)
     if (j->stat & STAT_TIMED)
 	return 1;
 
-    HEAPALLOC {
-	if (!(v = getvalue(&vbuf, &s, 0)) ||
-	    (reporttime = getintvalue(v)) < 0) {
-	    LASTALLOC_RETURN 0;
-	}
-    } LASTALLOC;
-
+    if (!(v = getvalue(&vbuf, &s, 0)) ||
+	(reporttime = getintvalue(v)) < 0) {
+	return 0;
+    }
     /* can this ever happen? */
     if (!j->procs)
 	return 0;
diff --git a/Src/lex.c b/Src/lex.c
index 595481775..1031b57e2 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -575,7 +575,6 @@ gettok(void)
     int c, d;
     int peekfd = -1, peek;
 
-    MUSTUSEHEAP("gettok");
   beginning:
     tokstr = NULL;
     while (iblank(c = hgetc()) && !lexstop);
@@ -587,7 +586,7 @@ gettok(void)
     /* word includes the last character read and possibly \ before ! */
     if (dbparens) {
 	len = 0;
-	bptr = tokstr = (char *)ncalloc(bsiz = 32);
+	bptr = tokstr = (char *) hcalloc(bsiz = 32);
 	hungetc(c);
 	cmdpush(CS_MATH);
 	c = dquote_parse(infor ? ';' : ')', 0);
@@ -702,7 +701,7 @@ gettok(void)
 	    }
 	    if (incmdpos) {
 		len = 0;
-		bptr = tokstr = (char *)ncalloc(bsiz = 32);
+		bptr = tokstr = (char *) hcalloc(bsiz = 32);
 		return cmd_or_math(CS_MATH) ? DINPAR : INPAR;
 	    }
 	} else if (d == ')')
@@ -849,7 +848,7 @@ gettokstr(int c, int sub)
     peek = STRING;
     if (!sub) {
 	len = 0;
-	bptr = tokstr = (char *)ncalloc(bsiz = 32);
+	bptr = tokstr = (char *) hcalloc(bsiz = 32);
     }
     for (;;) {
 	int act;
@@ -1392,28 +1391,26 @@ parsestr(char *s)
 {
     int l = strlen(s), err;
 
-    HEAPALLOC {
-	lexsave();
+    lexsave();
+    untokenize(s);
+    inpush(dupstring(s), 0, NULL);
+    strinbeg(0);
+    len = 0;
+    bptr = tokstr = s;
+    bsiz = l + 1;
+    err = dquote_parse('\0', 1);
+    *bptr = '\0';
+    strinend();
+    inpop();
+    DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
+    lexrestore();
+    if (err) {
 	untokenize(s);
-	inpush(dupstring(s), 0, NULL);
-	strinbeg(0);
-	len = 0;
-	bptr = tokstr = s;
-	bsiz = l + 1;
-	err = dquote_parse('\0', 1);
-	*bptr = '\0';
-	strinend();
-	inpop();
-	DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty.");
-	lexrestore();
-	if (err) {
-	    untokenize(s);
-	    if (err > 32 && err < 127)
-		zerr("parse error near `%c'", NULL, err);
-	    else
-		zerr("parse error", NULL, 0);
-	}
-    } LASTALLOC;
+	if (err > 32 && err < 127)
+	    zerr("parse error near `%c'", NULL, err);
+	else
+	    zerr("parse error", NULL, 0);
+    }
     return err;
 }
 
diff --git a/Src/linklist.c b/Src/linklist.c
index 76c32a62d..e449957da 100644
--- a/Src/linklist.c
+++ b/Src/linklist.c
@@ -38,7 +38,19 @@ newlinklist(void)
 {
     LinkList list;
 
-    list = (LinkList) ncalloc(sizeof *list);
+    list = (LinkList) zhalloc(sizeof *list);
+    list->first = NULL;
+    list->last = (LinkNode) list;
+    return list;
+}
+
+/**/
+mod_export LinkList
+znewlinklist(void)
+{
+    LinkList list;
+
+    list = (LinkList) zalloc(sizeof *list);
     list->first = NULL;
     list->last = (LinkNode) list;
     return list;
@@ -53,7 +65,25 @@ insertlinknode(LinkList list, LinkNode node, void *dat)
     LinkNode tmp, new;
 
     tmp = node->next;
-    node->next = new = (LinkNode) ncalloc(sizeof *tmp);
+    node->next = new = (LinkNode) zhalloc(sizeof *tmp);
+    new->last = node;
+    new->dat = dat;
+    new->next = tmp;
+    if (tmp)
+	tmp->last = new;
+    else
+	list->last = new;
+    return new;
+}
+
+/**/
+mod_export LinkNode
+zinsertlinknode(LinkList list, LinkNode node, void *dat)
+{
+    LinkNode tmp, new;
+
+    tmp = node->next;
+    node->next = new = (LinkNode) zalloc(sizeof *tmp);
     new->last = node;
     new->dat = dat;
     new->next = tmp;
@@ -227,8 +257,6 @@ newsizedlist(int size)
     LinkList list;
     LinkNode node;
 
-    MUSTUSEHEAP("newsizedlist()");
-
     list = (LinkList) zhalloc(sizeof(struct linklist) +
 			      (size * sizeof(struct linknode)));
 
diff --git a/Src/loop.c b/Src/loop.c
index 829b36d64..2459d65b8 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -296,7 +296,7 @@ selectlist(LinkList l, size_t start)
 
     trashzle();
     ct = countlinknodes(l);
-    ap = arr = (char **)alloc((countlinknodes(l) + 1) * sizeof(char **));
+    ap = arr = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char **));
 
     for (n = (LinkNode) firstnode(l); n; incnode(n))
 	*ap++ = (char *)getdata(n);
diff --git a/Src/main.c b/Src/main.c
index 51e929bc7..aaa4186e2 100644
--- a/Src/main.c
+++ b/Src/main.c
@@ -39,8 +39,6 @@ main(int argc, char **argv)
     setlocale(LC_ALL, "");
 #endif
 
-    global_permalloc();
-
     init_hackzero(argv, environ);
 
     for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++);
@@ -79,7 +77,6 @@ main(int argc, char **argv)
     init_io();
     setupvals();
     init_signals();
-    global_heapalloc();
     init_bltinmods();
     run_init_scripts();
     init_misc();
diff --git a/Src/math.c b/Src/math.c
index 936794b9b..a3609d429 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -515,7 +515,7 @@ callmathfunc(char *o)
 	    while (*a) {
 		if (*a) {
 		    argc++;
- 		    q = (mnumber *)zhalloc(sizeof(mnumber));
+ 		    q = (mnumber *) zhalloc(sizeof(mnumber));
 		    *q = mathevall(a, ARGPREC, &a);
 		    addlinknode(l, q);
 		    if (errflag || mtok != COMMA)
@@ -864,7 +864,6 @@ mathevall(char *s, int prek, char **ep)
     struct mathvalue *xstack = 0, nstack[STACKSZ];
     mnumber ret;
 
-    MUSTUSEHEAP("mathevall");
     if (mlevel++) {
 	xlastbase = lastbase;
 	xnoeval = noeval;
diff --git a/Src/mem.c b/Src/mem.c
index d6fb293d0..1e627cd99 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -54,9 +54,6 @@
 	Memory allocated in this way does not have to be freed explicitly;
 	it will all be freed when the pool is destroyed.  In fact,
 	attempting to free this memory may result in a core dump.
-	The pair of pointers ncalloc and alloc may point to either
-	zalloc & zcalloc or zhalloc & hcalloc; permalloc() sets them to the
-	former, and heapalloc() sets them to the latter.
 
 	If possible, the heaps are allocated using mmap() so that the
 	(*real*) heap isn't filled up with empty zsh heaps. If mmap()
@@ -81,17 +78,6 @@
 #endif
 #endif
 
-/* != 0 if we are allocating in the heaplist */
- 
-/**/
-mod_export int useheap;
-
-/* Current allocation pointers.  ncalloc() is either zalloc() or zhalloc(); *
- * alloc() is either zcalloc() or hcalloc().                               */
-
-/**/
-mod_export void *(*ncalloc) _((size_t)), *(*alloc) _((size_t));
-
 #ifdef ZSH_MEM_WARNING
 # ifndef DEBUG
 #  define DEBUG 1
@@ -115,35 +101,7 @@ union mem_align {
 #define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
 #define HEAPFREE (16384 - H_ISIZE)
 
-/* set default allocation to heap stack */
-
-/**/
-mod_export int
-global_heapalloc(void)
-{
-    int luh = useheap;
-
-    alloc = hcalloc;
-    ncalloc = zhalloc;
-    useheap = 1;
-    return luh;
-}
-
-/* set default allocation to malloc() */
-
-/**/
-mod_export int
-global_permalloc(void)
-{
-    int luh = useheap;
-
-    alloc = zcalloc;
-    ncalloc = zalloc;
-    useheap = 0;
-    return luh;
-}
-
-/* list of zsh heap */
+/* list of zsh heaps */
 
 static Heap heaps;
 
@@ -556,7 +514,7 @@ dupstring(const char *s)
 
     if (!s)
 	return NULL;
-    t = (char *)ncalloc(strlen((char *)s) + 1);
+    t = (char *) zhalloc(strlen((char *)s) + 1);
     strcpy(t, s);
     return t;
 }
diff --git a/Src/module.c b/Src/module.c
index a7e3ad329..63e0dc2f6 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -77,17 +77,15 @@ register_module(char *n, Module_func setup, Module_func boot,
 {
     Linkedmod m;
 
-    PERMALLOC {
-	m = (Linkedmod) zalloc(sizeof(*m));
+    m = (Linkedmod) zalloc(sizeof(*m));
 
-	m->name = ztrdup(n);
-	m->setup = setup;
-	m->boot = boot;
-	m->cleanup = cleanup;
-	m->finish = finish;
+    m->name = ztrdup(n);
+    m->setup = setup;
+    m->boot = boot;
+    m->cleanup = cleanup;
+    m->finish = finish;
 
-	addlinknode(linkedmodules, m);
-    } LASTALLOC;
+    zaddlinknode(linkedmodules, m);
 }
 
 /* Check if a module is linked in. */
@@ -119,9 +117,7 @@ addbuiltin(Builtin b)
 	return 1;
     if (bn)
 	builtintab->freenode(builtintab->removenode(builtintab, b->nam));
-    PERMALLOC {
-	builtintab->addnode(builtintab, b->nam, b);
-    } LASTALLOC;
+    builtintab->addnode(builtintab, b->nam, b);
     return 0;
 }
 
@@ -684,9 +680,8 @@ load_module(char const *name)
 	    m->u.linked = linked;
 	    m->flags |= MOD_SETUP | MOD_LINKED;
 	}
-	PERMALLOC {
-	    node = addlinknode(modules, m);
-	} LASTALLOC;
+	node = zaddlinknode(modules, m);
+
 	if ((set = setup_module(m)) || boot_module(m)) {
 	    if (!set)
 		finish_module(m);
@@ -796,21 +791,19 @@ add_dep(char *name, char *from)
     LinkNode node;
     Module m;
 
-    PERMALLOC {
-	if (!(node = find_module(name))) {
-	    m = zcalloc(sizeof(*m));
-	    m->nam = ztrdup(name);
-	    addlinknode(modules, m);
-	} else
-	    m = (Module) getdata(node);
-	if (!m->deps)
-	    m->deps = newlinklist();
-	for (node = firstnode(m->deps);
-	     node && strcmp((char *) getdata(node), from);
-	     incnode(node));
-	if (!node)
-	    addlinknode(m->deps, ztrdup(from));
-    } LASTALLOC;
+    if (!(node = find_module(name))) {
+	m = zcalloc(sizeof(*m));
+	m->nam = ztrdup(name);
+	zaddlinknode(modules, m);
+    } else
+	m = (Module) getdata(node);
+    if (!m->deps)
+	m->deps = znewlinklist();
+    for (node = firstnode(m->deps);
+	 node && strcmp((char *) getdata(node), from);
+	 incnode(node));
+    if (!node)
+	zaddlinknode(m->deps, ztrdup(from));
 }
 
 /**/
@@ -1481,9 +1474,7 @@ addhookdef(Hookdef h)
 
     h->next = hooktab;
     hooktab = h;
-    PERMALLOC {
-	h->funcs = newlinklist();
-    } LASTALLOC;
+    h->funcs = znewlinklist();
 
     return 0;
 }
@@ -1545,9 +1536,8 @@ deletehookdefs(char const *nam, Hookdef h, int size)
 int
 addhookdeffunc(Hookdef h, Hookfn f)
 {
-    PERMALLOC {
-	addlinknode(h->funcs, (void *) f);
-    } LASTALLOC;
+    zaddlinknode(h->funcs, (void *) f);
+
     return 0;
 }
 
diff --git a/Src/params.c b/Src/params.c
index 41c86fd93..d5c419daf 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -408,11 +408,10 @@ scanparamvals(HashNode hn, int flags)
 char **
 paramvalarr(HashTable ht, int flags)
 {
-    MUSTUSEHEAP("paramvalarr");
     numparamvals = 0;
     if (ht)
 	scanhashtable(ht, 0, 0, PM_UNSET, scancountparams, flags);
-    paramvals = (char **) alloc((numparamvals + 1) * sizeof(char *));
+    paramvals = (char **) zhalloc((numparamvals + 1) * sizeof(char *));
     if (ht) {
 	numparamvals = 0;
 	scanhashtable(ht, 0, 0, PM_UNSET, scanparamvals, flags);
@@ -468,87 +467,85 @@ createparamtable(void)
 
     noerrs = 2;
 
-    HEAPALLOC {
-	/* Add the standard non-special parameters which have to    *
-	 * be initialized before we copy the environment variables. *
-	 * We don't want to override whatever values the users has  *
-	 * given them in the environment.                           */
-	opts[ALLEXPORT] = 0;
-	setiparam("MAILCHECK", 60);
-	setiparam("LOGCHECK", 60);
-	setiparam("KEYTIMEOUT", 40);
-	setiparam("LISTMAX", 100);
+    /* Add the standard non-special parameters which have to    *
+     * be initialized before we copy the environment variables. *
+     * We don't want to override whatever values the users has  *
+     * given them in the environment.                           */
+    opts[ALLEXPORT] = 0;
+    setiparam("MAILCHECK", 60);
+    setiparam("LOGCHECK", 60);
+    setiparam("KEYTIMEOUT", 40);
+    setiparam("LISTMAX", 100);
 #ifdef HAVE_SELECT
-	setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
+    setiparam("BAUD", getbaudrate(&shttyinfo));  /* get the output baudrate */
 #endif
-	setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
-	setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
-	setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
-	setsparam("WATCHFMT", ztrdup(default_watchfmt));
-	setsparam("HOST", ztrdup(hostnam));
-	setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username));
-
-	/* Copy the environment variables we are inheriting to dynamic *
-	 * memory, so we can do mallocs and frees on it.               */
-	num_env = arrlen(environ);
-	new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1));
-	*new_environ = NULL;
-
-	/* Now incorporate environment variables we are inheriting *
-	 * into the parameter hash table.                          */
-	for (envp = new_environ, envp2 = environ; *envp2; envp2++) {
-	    for (str = *envp2; *str && *str != '='; str++);
-	    if (*str == '=') {
-		iname = NULL;
-		*str = '\0';
-		if (!idigit(**envp2) && isident(*envp2) && !strchr(*envp2, '[')) {
-		    iname = *envp2;
-		    if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
-			 !(pm->flags & PM_DONTIMPORT)) &&
-			(pm = setsparam(iname, metafy(str + 1, -1, META_DUP))) &&
-			!(pm->flags & PM_EXPORTED)) {
-			*str = '=';
-			pm->flags |= PM_EXPORTED;
-			pm->env = *envp++ = ztrdup(*envp2);
-			*envp = NULL;
-			if (pm->flags & PM_SPECIAL)
-			    pm->env = replenv(pm->env, getsparam(pm->nam),
-					      pm->flags);
-		    }
+    setsparam("FCEDIT", ztrdup(DEFAULT_FCEDIT));
+    setsparam("TMPPREFIX", ztrdup(DEFAULT_TMPPREFIX));
+    setsparam("TIMEFMT", ztrdup(DEFAULT_TIMEFMT));
+    setsparam("WATCHFMT", ztrdup(default_watchfmt));
+    setsparam("HOST", ztrdup(hostnam));
+    setsparam("LOGNAME", ztrdup((str = getlogin()) && *str ? str : cached_username));
+
+    /* Copy the environment variables we are inheriting to dynamic *
+     * memory, so we can do mallocs and frees on it.               */
+    num_env = arrlen(environ);
+    new_environ = (char **) zalloc(sizeof(char *) * (num_env + 1));
+    *new_environ = NULL;
+
+    /* Now incorporate environment variables we are inheriting *
+     * into the parameter hash table.                          */
+    for (envp = new_environ, envp2 = environ; *envp2; envp2++) {
+	for (str = *envp2; *str && *str != '='; str++);
+	if (*str == '=') {
+	    iname = NULL;
+	    *str = '\0';
+	    if (!idigit(**envp2) && isident(*envp2) && !strchr(*envp2, '[')) {
+		iname = *envp2;
+		if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
+		     !(pm->flags & PM_DONTIMPORT)) &&
+		    (pm = setsparam(iname, metafy(str + 1, -1, META_DUP))) &&
+		    !(pm->flags & PM_EXPORTED)) {
+		    *str = '=';
+		    pm->flags |= PM_EXPORTED;
+		    pm->env = *envp++ = ztrdup(*envp2);
+		    *envp = NULL;
+		    if (pm->flags & PM_SPECIAL)
+			pm->env = replenv(pm->env, getsparam(pm->nam),
+					  pm->flags);
 		}
-		*str = '=';
 	    }
+	    *str = '=';
 	}
-	environ = new_environ;
-	opts[ALLEXPORT] = oae;
+    }
+    environ = new_environ;
+    opts[ALLEXPORT] = oae;
 
-	pm = (Param) paramtab->getnode(paramtab, "HOME");
-	if (!(pm->flags & PM_EXPORTED)) {
-	    pm->flags |= PM_EXPORTED;
-	    pm->env = addenv("HOME", home, pm->flags);
-	}
-	pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
-	if (!(pm->flags & PM_EXPORTED)) {
-	    pm->flags |= PM_EXPORTED;
-	    pm->env = addenv("LOGNAME", pm->u.str, pm->flags);
-	}
-	pm = (Param) paramtab->getnode(paramtab, "SHLVL");
-	if (!(pm->flags & PM_EXPORTED))
-	    pm->flags |= PM_EXPORTED;
-	sprintf(buf, "%d", (int)++shlvl);
-	pm->env = addenv("SHLVL", buf, pm->flags);
-
-	/* Add the standard non-special parameters */
-	set_pwd_env();
-	setsparam("MACHTYPE", ztrdup(MACHTYPE));
-	setsparam("OSTYPE", ztrdup(OSTYPE));
-	setsparam("TTY", ztrdup(ttystrname));
-	setsparam("VENDOR", ztrdup(VENDOR));
-	setsparam("ZSH_NAME", ztrdup(zsh_name));
-	setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION));
-	setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
-	for (t = sigs; (*sigptr++ = ztrdup(*t++)); );
-    } LASTALLOC;
+    pm = (Param) paramtab->getnode(paramtab, "HOME");
+    if (!(pm->flags & PM_EXPORTED)) {
+	pm->flags |= PM_EXPORTED;
+	pm->env = addenv("HOME", home, pm->flags);
+    }
+    pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
+    if (!(pm->flags & PM_EXPORTED)) {
+	pm->flags |= PM_EXPORTED;
+	pm->env = addenv("LOGNAME", pm->u.str, pm->flags);
+    }
+    pm = (Param) paramtab->getnode(paramtab, "SHLVL");
+    if (!(pm->flags & PM_EXPORTED))
+	pm->flags |= PM_EXPORTED;
+    sprintf(buf, "%d", (int)++shlvl);
+    pm->env = addenv("SHLVL", buf, pm->flags);
+
+    /* Add the standard non-special parameters */
+    set_pwd_env();
+    setsparam("MACHTYPE", ztrdup(MACHTYPE));
+    setsparam("OSTYPE", ztrdup(OSTYPE));
+    setsparam("TTY", ztrdup(ttystrname));
+    setsparam("VENDOR", ztrdup(VENDOR));
+    setsparam("ZSH_NAME", ztrdup(zsh_name));
+    setsparam("ZSH_VERSION", ztrdup(ZSH_VERSION));
+    setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
+    for (t = sigs; (*sigptr++ = ztrdup(*t++)); );
 
     noerrs = 0;
 }
@@ -634,7 +631,7 @@ createparam(char *name, int flags)
 	if (isset(ALLEXPORT) && !oldpm)
 	    flags |= PM_EXPORTED;
     } else {
-	pm = (Param) alloc(sizeof *pm);
+	pm = (Param) zhalloc(sizeof *pm);
 	pm->nam = nulstring;
     }
     pm->flags = flags & ~PM_LOCAL;
@@ -656,29 +653,27 @@ copyparam(Param tpm, Param pm, int toplevel)
      * to set the parameter, so must be permanently allocated (in accordance
      * with sets.?fn() usage).
      */
-    PERMALLOC {
-	tpm->flags = pm->flags;
-	if (!toplevel)
-	    tpm->flags &= ~PM_SPECIAL;
-	switch (PM_TYPE(pm->flags)) {
-	case PM_SCALAR:
-	    tpm->u.str = ztrdup(pm->gets.cfn(pm));
-	    break;
-	case PM_INTEGER:
-	    tpm->u.val = pm->gets.ifn(pm);
-	    break;
-	case PM_EFLOAT:
-	case PM_FFLOAT:
-	    tpm->u.dval = pm->gets.ffn(pm);
-	    break;
-	case PM_ARRAY:
-	    tpm->u.arr = arrdup(pm->gets.afn(pm));
-	    break;
-	case PM_HASHED:
-	    tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
-	    break;
-	}
-    } LASTALLOC;
+    tpm->flags = pm->flags;
+    if (!toplevel)
+	tpm->flags &= ~PM_SPECIAL;
+    switch (PM_TYPE(pm->flags)) {
+    case PM_SCALAR:
+	tpm->u.str = ztrdup(pm->gets.cfn(pm));
+	break;
+    case PM_INTEGER:
+	tpm->u.val = pm->gets.ifn(pm);
+	break;
+    case PM_EFLOAT:
+    case PM_FFLOAT:
+	tpm->u.dval = pm->gets.ffn(pm);
+	break;
+    case PM_ARRAY:
+	tpm->u.arr = zarrdup(pm->gets.afn(pm));
+	break;
+    case PM_HASHED:
+	tpm->u.hash = copyparamtable(pm->gets.hfn(pm), pm->nam);
+	break;
+    }
     /*
      * If called from inside an associative array, that array is later going
      * to be passed as a real parameter, so we need the gets and sets
@@ -949,14 +944,14 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w)
 	    l = strlen(s);
 	    if (a2) {
 		if (!l || *s != '*') {
-		    d = (char *) ncalloc(l + 2);
+		    d = (char *) hcalloc(l + 2);
 		    *d = '*';
 		    strcpy(d + 1, s);
 		    s = d;
 		}
 	    } else {
 		if (!l || s[l - 1] != '*') {
-		    d = (char *) ncalloc(l + 2);
+		    d = (char *) hcalloc(l + 2);
 		    strcpy(d, s);
 		    strcat(d, "*");
 		    s = d;
@@ -1010,7 +1005,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w)
 				return r;
 		}
 	    } else if (word) {
-		ta = sepsplit(d = s = getstrvalue(v), sep, 1);
+		ta = sepsplit(d = s = getstrvalue(v), sep, 1, 1);
 		len = arrlen(ta);
 		if (beg < 0)
 		    beg += len;
@@ -1296,63 +1291,62 @@ getstrvalue(Value v)
 
     if (!v)
 	return hcalloc(1);
-    HEAPALLOC {
-	if (v->inv && !(v->pm->flags & PM_HASHED)) {
-	    sprintf(buf, "%d", v->a);
-	    s = dupstring(buf);
-	    LASTALLOC_RETURN s;
-	}
 
-	switch(PM_TYPE(v->pm->flags)) {
-	case PM_HASHED:
-	    /* (!v->isarr) should be impossible unless emulating ksh */
-	    if (!v->isarr && emulation == EMULATE_KSH) {
-		s = dupstring("[0]");
-		if (getindex(&s, v) == 0)
-		    s = getstrvalue(v);
-		LASTALLOC_RETURN s;
-	    } /* else fall through */
-	case PM_ARRAY:
-	    ss = getvaluearr(v);
-	    if (v->isarr)
-		s = sepjoin(ss, NULL);
-	    else {
-		if (v->a < 0)
-		    v->a += arrlen(ss);
-		s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a];
-	    }
-	    LASTALLOC_RETURN s;
-	case PM_INTEGER:
-	    convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct);
-	    s = dupstring(buf);
-	    break;
-	case PM_EFLOAT:
-	case PM_FFLOAT:
-	    s = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct,
-			  v->pm->flags, NULL);
-	    break;
-	case PM_SCALAR:
-	    s = v->pm->gets.cfn(v->pm);
-	    break;
-	default:
-	    s = NULL;
-	    DPUTS(1, "BUG: param node without valid type");
-	    break;
-	}
+    if (v->inv && !(v->pm->flags & PM_HASHED)) {
+	sprintf(buf, "%d", v->a);
+	s = dupstring(buf);
+	return s;
+    }
 
-	if (v->a == 0 && v->b == -1) {
-	    LASTALLOC_RETURN s;
+    switch(PM_TYPE(v->pm->flags)) {
+    case PM_HASHED:
+	/* (!v->isarr) should be impossible unless emulating ksh */
+	if (!v->isarr && emulation == EMULATE_KSH) {
+	    s = dupstring("[0]");
+	    if (getindex(&s, v) == 0)
+		s = getstrvalue(v);
+	    return s;
+	} /* else fall through */
+    case PM_ARRAY:
+	ss = getvaluearr(v);
+	if (v->isarr)
+	    s = sepjoin(ss, NULL, 1);
+	else {
+	    if (v->a < 0)
+		v->a += arrlen(ss);
+	    s = (v->a >= arrlen(ss) || v->a < 0) ? (char *) hcalloc(1) : ss[v->a];
 	}
-	if (v->a < 0)
-	    v->a += strlen(s);
-	if (v->b < 0)
-	    v->b += strlen(s);
-	s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a);
-	if (v->b < v->a)
-	    s[0] = '\0';
-	else if (v->b - v->a < (int)strlen(s))
-	    s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0';
-    } LASTALLOC;
+	return s;
+    case PM_INTEGER:
+	convbase(buf, v->pm->gets.ifn(v->pm), v->pm->ct);
+	s = dupstring(buf);
+	break;
+    case PM_EFLOAT:
+    case PM_FFLOAT:
+	s = convfloat(v->pm->gets.ffn(v->pm), v->pm->ct, v->pm->flags, NULL);
+	break;
+    case PM_SCALAR:
+	s = v->pm->gets.cfn(v->pm);
+	break;
+    default:
+	s = NULL;
+	DPUTS(1, "BUG: param node without valid type");
+	break;
+    }
+
+    if (v->a == 0 && v->b == -1)
+	return s;
+
+    if (v->a < 0)
+	v->a += strlen(s);
+    if (v->b < 0)
+	v->b += strlen(s);
+    s = (v->a > (int)strlen(s)) ? dupstring("") : dupstring(s + v->a);
+    if (v->b < v->a)
+	s[0] = '\0';
+    else if (v->b - v->a < (int)strlen(s))
+	s[v->b - v->a + 1 + (s[v->b - v->a] == Meta)] = '\0';
+
     return s;
 }
 
@@ -1386,7 +1380,7 @@ getarrvalue(Value v)
     if (v->a > arrlen(s) || v->a < 0)
 	s = arrdup(nular);
     else
-	s = arrdup(s) + v->a;
+	s = arrdup(s + v->a);
     if (v->b < v->a)
 	s[0] = NULL;
     else if (v->b - v->a < arrlen(s))
@@ -1449,7 +1443,6 @@ setstrvalue(Value v, char *val)
     v->pm->flags &= ~PM_UNSET;
     switch (PM_TYPE(v->pm->flags)) {
     case PM_SCALAR:
-	MUSTUSEHEAP("setstrvalue");
 	if (v->a == 0 && v->b == -1) {
 	    (v->pm->sets.cfn) (v->pm, val);
 	    if (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z) && !v->pm->ct)
@@ -1499,7 +1492,6 @@ setstrvalue(Value v, char *val)
 	}
 	break;
     case PM_ARRAY:
-	MUSTUSEHEAP("setstrvalue");
 	{
 	    char **ss = (char **) zalloc(2 * sizeof(char *));
 
@@ -2234,7 +2226,7 @@ char *
 colonarrgetfn(Param pm)
 {
     char ***dptr = (char ***)pm->u.data;
-    return *dptr ? zjoin(*dptr, ':') : "";
+    return *dptr ? zjoin(*dptr, ':', 1) : "";
 }
 
 /**/
@@ -2693,7 +2685,6 @@ arrfixenv(char *s, char **t)
     int len_s;
     Param pm;
 
-    MUSTUSEHEAP("arrfixenv");
     pm = (Param) paramtab->getnode(paramtab, s);
     /*
      * Only one level of a parameter can be exported.  Unless
@@ -2703,7 +2694,7 @@ arrfixenv(char *s, char **t)
 	cmdnamtab->emptytable(cmdnamtab);
     if (isset(ALLEXPORT) ? !!pm->old : pm->level)
 	return;
-    u = t ? zjoin(t, ':') : "";
+    u = t ? zjoin(t, ':', 1) : "";
     len_s = strlen(s);
     for (ep = environ; *ep; ep++)
 	if (!strncmp(*ep, s, len_s) && (*ep)[len_s] == '=') {
@@ -2883,7 +2874,6 @@ convfloat(double dval, int digits, int flags, FILE *fout)
 {
     char fmt[] = "%.*e";
 
-    MUSTUSEHEAP("convfloat");
     /*
      * The difficulty with the buffer size is that a %f conversion
      * prints all digits before the decimal point: with 64 bit doubles,
diff --git a/Src/parse.c b/Src/parse.c
index 2351b1501..85e70935f 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -998,7 +998,7 @@ par_case(int *complex)
 
 		incasepat = 1;
 		incmdpos = 0;
-		str2 = ncalloc(sl + 2);
+		str2 = hcalloc(sl + 2);
 		strcpy(str2, str);
 		str2[sl] = Bar;
 		str2[sl+1] = '\0';
@@ -1042,7 +1042,7 @@ par_case(int *complex)
 
 		    if (tok != STRING)
 			YYERRORV(oecused);
-		    str2 = ncalloc(sl + strlen(tokstr) + 1);
+		    str2 = hcalloc(sl + strlen(tokstr) + 1);
 		    strcpy(str2, str);
 		    strcpy(str2 + sl, tokstr);
 		    str = str2;
@@ -2008,7 +2008,7 @@ yyerror(int noerr)
 
 /**/
 mod_export Eprog
-dupeprog(Eprog p)
+zdupeprog(Eprog p)
 {
     Eprog r;
     int i;
@@ -2017,14 +2017,15 @@ dupeprog(Eprog p)
     if (p == &dummy_eprog)
 	return p;
 
-    r = (Eprog) ncalloc(sizeof(*r));
-    r->heap = useheap;
+    r = (Eprog) zalloc(sizeof(*r));
+    r->heap = 0;
     r->len = p->len;
     r->npats = p->npats;
-    pp = r->pats = (Patprog *) ncalloc(r->len);
+    pp = r->pats = (Patprog *) zcalloc(r->len);
     r->prog = (Wordcode) (r->pats + r->npats);
     r->strs = ((char *) r->prog) + (p->strs - ((char *) p->prog));
     memcpy(r->prog, p->prog, r->len - (p->npats * sizeof(Patprog)));
+    r->shf = NULL;
 
     for (i = r->npats; i--; pp++)
 	*pp = dummy_patprog1;
@@ -2038,11 +2039,8 @@ static LinkList eprog_free;
 mod_export void
 freeeprog(Eprog p)
 {
-    if (p && p != &dummy_eprog) {
-	PERMALLOC {
-	    addlinknode(eprog_free, p);
-	} LASTALLOC;
-    }
+    if (p && p != &dummy_eprog)
+	zaddlinknode(eprog_free, p);
 }
 
 /**/
@@ -2191,7 +2189,5 @@ init_eprog(void)
     dummy_eprog.prog = &dummy_eprog_code;
     dummy_eprog.strs = NULL;
 
-    PERMALLOC {
-	eprog_free = newlinklist();
-    } LASTALLOC;
+    eprog_free = znewlinklist();
 }
diff --git a/Src/pattern.c b/Src/pattern.c
index 1c4abbfb4..4cfdc1336 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -1357,9 +1357,7 @@ pattryrefs(Patprog prog, char *string, int *nump, int *begp, int *endp)
 		char *str;
 		int mlen = ztrsub(patinput, patinstart);
 
-		PERMALLOC {
-		    str = dupstrpfx(patinstart, patinput - patinstart);
-		} LASTALLOC;
+		str = ztrduppfx(patinstart, patinput - patinstart);
 		setsparam("MATCH", str);
 		setiparam("MBEGIN", (zlong)(patoffset + !isset(KSHARRAYS)));
 		setiparam("MEND",
@@ -1406,42 +1404,40 @@ pattryrefs(Patprog prog, char *string, int *nump, int *begp, int *endp)
 		sp = patbeginp;
 		ep = patendp;
 
-		PERMALLOC {
-		    for (i = 0; i < prog->patnpar; i++) {
-			if (parsfound & (1 << i)) {
-			    matcharr[i] = dupstrpfx(*sp, *ep - *sp);
-			    /*
-			     * mbegin and mend give indexes into the string
-			     * in the standard notation, i.e. respecting
-			     * KSHARRAYS, and with the end index giving
-			     * the last character, not one beyond.
-			     * For example, foo=foo; [[ $foo = (f)oo ]] gives
-			     * (without KSHARRAYS) indexes 1 and 1, which
-			     * corresponds to indexing as ${foo[1,1]}.
-			     */
-			    sprintf(numbuf, "%ld",
-				    (long)(ztrsub(*sp, patinstart) + 
-					   patoffset +
-					   !isset(KSHARRAYS)));
-			    mbeginarr[i] = ztrdup(numbuf);
-			    sprintf(numbuf, "%ld",
-				    (long)(ztrsub(*ep, patinstart) + 
-					   patoffset +
-					   !isset(KSHARRAYS) - 1));
-			    mendarr[i] = ztrdup(numbuf);
-			} else {
-			    /* Pattern wasn't set: either it was in an
-			     * unmatched branch, or a hashed parenthesis
-			     * that didn't match at all.
-			     */
-			    matcharr[i] = ztrdup("");
-			    mbeginarr[i] = ztrdup("-1");
-			    mendarr[i] = ztrdup("-1");
-			}
-			sp++;
-			ep++;
+		for (i = 0; i < prog->patnpar; i++) {
+		    if (parsfound & (1 << i)) {
+			matcharr[i] = ztrduppfx(*sp, *ep - *sp);
+			/*
+			 * mbegin and mend give indexes into the string
+			 * in the standard notation, i.e. respecting
+			 * KSHARRAYS, and with the end index giving
+			 * the last character, not one beyond.
+			 * For example, foo=foo; [[ $foo = (f)oo ]] gives
+			 * (without KSHARRAYS) indexes 1 and 1, which
+			 * corresponds to indexing as ${foo[1,1]}.
+			 */
+			sprintf(numbuf, "%ld",
+				(long)(ztrsub(*sp, patinstart) + 
+				       patoffset +
+				       !isset(KSHARRAYS)));
+			mbeginarr[i] = ztrdup(numbuf);
+			sprintf(numbuf, "%ld",
+				(long)(ztrsub(*ep, patinstart) + 
+				       patoffset +
+				       !isset(KSHARRAYS) - 1));
+			mendarr[i] = ztrdup(numbuf);
+		    } else {
+			/* Pattern wasn't set: either it was in an
+			 * unmatched branch, or a hashed parenthesis
+			 * that didn't match at all.
+			 */
+			matcharr[i] = ztrdup("");
+			mbeginarr[i] = ztrdup("-1");
+			mendarr[i] = ztrdup("-1");
 		    }
-		} LASTALLOC;
+		    sp++;
+		    ep++;
+		}
 		setaparam("match", matcharr);
 		setaparam("mbegin", mbeginarr);
 		setaparam("mend", mendarr);
@@ -2245,22 +2241,6 @@ static int patrepeat(Upat p)
     return count;
 }
 
-/* Duplicate a patprog. */
-
-/**/
-Patprog
-duppatprog(Patprog prog)
-{
-    if (prog && prog != dummy_patprog1 && prog != dummy_patprog2) {
-	Patprog ret = (Patprog) alloc(prog->size);
-
-	memcpy(ret, prog, prog->size);
-
-	return ret;
-    }
-    return prog;
-}
-
 /* Free a patprog. */
 
 /**/
diff --git a/Src/prompt.c b/Src/prompt.c
index 1b5cded10..23d5aaf4e 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -149,11 +149,10 @@ promptexpand(char *s, int ns, char *rs, char *Rs)
     if (isset(PROMPTSUBST)) {
 	int olderr = errflag;
 
-	HEAPALLOC {
-	    s = dupstring(s);
-	    if (!parsestr(s))
-		singsub(&s);
-	} LASTALLOC;
+	s = dupstring(s);
+	if (!parsestr(s))
+	    singsub(&s);
+
 	/* Ignore errors in prompt substitution */
 	errflag = olderr;
     }
diff --git a/Src/signals.c b/Src/signals.c
index 05ac465fb..d97e50dc2 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -531,10 +531,9 @@ handler(int sig)
         if (sigtrapped[SIGALRM]) {
 	    int tmout;
             dotrap(SIGALRM);
-	    HEAPALLOC {
-		if ((tmout = getiparam("TMOUT")))
-		    alarm(tmout);           /* reset the alarm */
-	    } LASTALLOC;
+
+	    if ((tmout = getiparam("TMOUT")))
+		alarm(tmout);           /* reset the alarm */
         } else {
 	    int idle = ttyidlegetfn(NULL);
 	    int tmout = getiparam("TMOUT");
@@ -671,14 +670,12 @@ dosavetrap(int sig, int level)
 	st->list = sigfuncs[sig];
 	sigfuncs[sig] = NULL;
     }
-    PERMALLOC {
-	if (!savetraps)
-	    savetraps = newlinklist();
-	/*
-	 * Put this at the front of the list
-	 */
-	insertlinknode(savetraps, (LinkNode)savetraps, st);
-    } LASTALLOC;
+    if (!savetraps)
+	savetraps = znewlinklist();
+    /*
+     * Put this at the front of the list
+     */
+    zinsertlinknode(savetraps, (LinkNode)savetraps, st);
 }
 
 /**/
@@ -900,23 +897,22 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
     if (*sigtr & ZSIG_FUNC) {
 	int osc = sfcontext;
 
-	PERMALLOC {
-	    args = newlinklist();
-	    name = (char *) zalloc(5 + strlen(sigs[sig]));
-	    sprintf(name, "TRAP%s", sigs[sig]);
-	    addlinknode(args, name);
-	    sprintf(num, "%d", sig);
-	    addlinknode(args, num);
-	} LASTALLOC;
+	args = znewlinklist();
+	name = (char *) zalloc(5 + strlen(sigs[sig]));
+	sprintf(name, "TRAP%s", sigs[sig]);
+	zaddlinknode(args, name);
+	sprintf(num, "%d", sig);
+	zaddlinknode(args, num);
+
 	trapreturn = -1;
 	sfcontext = SFC_SIGNAL;
 	doshfunc(name, sigfn, args, 0, 1);
 	sfcontext = osc;
 	freelinklist(args, (FreeFunc) NULL);
 	zsfree(name);
-    } else HEAPALLOC {
+    } else
 	execode(sigfn, 1, 0);
-    } LASTALLOC;
+
     if (trapreturn > 0)
 	trapret = trapreturn;
     else if (errflag)
diff --git a/Src/subst.c b/Src/subst.c
index 2db3e3739..62ff69beb 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -51,7 +51,6 @@ prefork(LinkList list, int flags)
 {
     LinkNode node;
 
-    MUSTUSEHEAP("prefork");
     for (node = firstnode(list); node; incnode(node)) {
 	char *str, c;
 
@@ -187,7 +186,7 @@ stringsubst(LinkList list, LinkNode node, int ssub)
 	    l2 = strlen(s);
 	    if (nonempty(pl)) {
 		LinkNode n = lastnode(pl);
-		str2 = (char *) ncalloc(l1 + l2 + 1);
+		str2 = (char *) hcalloc(l1 + l2 + 1);
 		strcpy(str2, str3);
 		strcpy(str2 + l1, s);
 		setdata(node, str2);
@@ -196,7 +195,7 @@ stringsubst(LinkList list, LinkNode node, int ssub)
 		l1 = 0;
 		l2 = strlen(s);
 	    }
-	    str2 = (char *) ncalloc(l1 + l2 + strlen(str) + 1);
+	    str2 = (char *) hcalloc(l1 + l2 + strlen(str) + 1);
 	    if (l1)
 		strcpy(str2, str3);
 	    strcpy(str2 + l1, s);
@@ -273,7 +272,7 @@ multsub(char **s, char ***a, int *isarr, char *sep)
 	return 0;
     }
     if ((l = countlinknodes(&foo))) {
-	p = r = ncalloc((l + 1) * sizeof(char*));
+	p = r = hcalloc((l + 1) * sizeof(char*));
 	while (nonempty(&foo))
 	    *p++ = (char *)ugetnode(&foo);
 	*p = NULL;
@@ -283,7 +282,7 @@ multsub(char **s, char ***a, int *isarr, char *sep)
 	    mult_isarr = omi;
 	    return 0;
 	}
-	*s = sepjoin(r, NULL);
+	*s = sepjoin(r, NULL, 1);
 	mult_isarr = omi;
 	if (isarr)
 	    *isarr = 0;
@@ -433,7 +432,7 @@ strcatsub(char **d, char *pb, char *pe, char *src, int l, char *s, int glbsub,
 	if (glbsub)
 	    tokenize(dest);
     } else {
-	*d = dest = ncalloc(pl + l + (s ? strlen(s) : 0) + 1);
+	*d = dest = hcalloc(pl + l + (s ? strlen(s) : 0) + 1);
 	strncpy(dest, pb, pl);
 	dest += pl;
 	strcpy(dest, src);
@@ -1041,7 +1040,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	*s = 0;
 	if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) {
 	    isarr = -1;
-	    aval = alloc(sizeof(char *));
+	    aval = (char **) hcalloc(sizeof(char *));
 	    aspar = 0;
 	} else if (aspar)
 	    idbeg = val;
@@ -1167,7 +1166,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		    else
 			while (iblank(*t))
 			    t++;
-		    val = (char *)ncalloc(fwidth + 1);
+		    val = (char *) hcalloc(fwidth + 1);
 		    val[fwidth] = '\0';
 		    if ((t0 = strlen(t)) > fwidth)
 			t0 = fwidth;
@@ -1186,7 +1185,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 				if (!*t || !idigit(*t))
 				    zero = 0;
 			    }
-			    t = (char *)ncalloc(fwidth + 1);
+			    t = (char *) hcalloc(fwidth + 1);
 			    memset(t, (((v->pm->flags & PM_RIGHT_B) || !zero) ?
 				       ' ' : '0'), fwidth);
 			    if ((t0 = strlen(val)) > fwidth)
@@ -1194,7 +1193,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 			    strcpy(t + (fwidth - t0), val);
 			    val = t;
 			} else {
-			    t = (char *)ncalloc(fwidth + 1);
+			    t = (char *) hcalloc(fwidth + 1);
 			    t[fwidth] = '\0';
 			    strncpy(t, val + strlen(val) - fwidth, fwidth);
 			    val = t;
@@ -1226,7 +1225,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	if (nojoin)
 	    isarr = -1;
 	if (qt && !getlen && isarr > 0) {
-	    val = sepjoin(aval, sep);
+	    val = sepjoin(aval, sep, 1);
 	    isarr = 0;
 	}
     }
@@ -1376,7 +1375,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		if (arrasg) {
 		    char *arr[2], **t, **a, **p;
 		    if (spsep || spbreak) {
-			aval = sepsplit(val, spsep, 0);
+			aval = sepsplit(val, spsep, 0, 1);
 			isarr = 2;
 			sep = spsep = NULL;
 			spbreak = 0;
@@ -1501,7 +1500,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		else {
 		    char *ss;
 		    char **ap = aval;
-		    char **pp = aval = (char **)ncalloc(sizeof(char *) * (arrlen(aval) + 1));
+		    char **pp = aval = (char **) hcalloc(sizeof(char *) *
+							 (arrlen(aval) + 1));
 
 		    while ((*pp = *ap++)) {
 			ss = s;
@@ -1575,9 +1575,9 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
      * It means that we must join arrays and should not split words. */
     if (ssub || spbreak || spsep || sep) {
 	if (isarr)
-	    val = sepjoin(aval, sep), isarr = 0;
+	    val = sepjoin(aval, sep, 1), isarr = 0;
 	if (!ssub && (spbreak || spsep)) {
-	    aval = sepsplit(val, spsep, 0);
+	    aval = sepsplit(val, spsep, 0, 1);
 	    if (!aval || !aval[0])
 		val = dupstring("");
 	    else if (!aval[1])
@@ -1755,7 +1755,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	    if (aptr > (char *) getdata(n) &&
 		aptr[-1] == Dnull && *fstr == Dnull)
 		*--aptr = '\0', fstr++;
-	    y = (char *)ncalloc((aptr - ostr) + strlen(fstr) + 1);
+	    y = (char *) hcalloc((aptr - ostr) + strlen(fstr) + 1);
 	    strcpy(y, ostr);
 	    *str = y + (aptr - ostr);
 	    strcpy(*str, fstr);
@@ -1910,8 +1910,8 @@ arithsubst(char *a, char **bptr, char *rest)
 	b = convfloat(v.u.d, 0, 0, NULL);
     else
 	convbase(buf, v.u.l, 0);
-    t = *bptr = (char *)ncalloc(strlen(*bptr) + strlen(b) + 
-				strlen(rest) + 1);
+    t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) + 
+				 strlen(rest) + 1);
     t--;
     while ((*++t = *s++));
     t--;
diff --git a/Src/utils.c b/Src/utils.c
index c5d0f760e..9b0d2cd40 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -734,24 +734,23 @@ checkmailpath(char **s)
 
 	    if (lock) {
 		char *fn;
-		HEAPALLOC {
-		    pushheap();
-		    l = newlinklist();
-		    while ((fn = zreaddir(lock, 1)) && !errflag) {
-			if (u)
-			    sprintf(buf, "%s/%s?%s", *s, fn, u);
-			else
-			    sprintf(buf, "%s/%s", *s, fn);
-			addlinknode(l, dupstring(buf));
-			ct++;
-		    }
-		    closedir(lock);
-		    ap = arr = (char **) alloc(ct * sizeof(char *));
 
-		    while ((*ap++ = (char *)ugetnode(l)));
-		    checkmailpath(arr);
-		    popheap();
-		} LASTALLOC;
+		pushheap();
+		l = newlinklist();
+		while ((fn = zreaddir(lock, 1)) && !errflag) {
+		    if (u)
+			sprintf(buf, "%s/%s?%s", *s, fn, u);
+		    else
+			sprintf(buf, "%s/%s", *s, fn);
+		    addlinknode(l, dupstring(buf));
+		    ct++;
+		}
+		closedir(lock);
+		ap = arr = (char **) zhalloc(ct * sizeof(char *));
+
+		while ((*ap++ = (char *)ugetnode(l)));
+		checkmailpath(arr);
+		popheap();
 	    }
 	} else {
 	    if (st.st_size && st.st_atime <= st.st_mtime &&
@@ -765,15 +764,14 @@ checkmailpath(char **s)
 		    memcpy(usav, underscore, underscoreused);
 
 		    setunderscore(*s);
-		    HEAPALLOC {
-			u = dupstring(u);
-			if (! parsestr(u)) {
-			    singsub(&u);
-			    zputs(u, shout);
-			    fputc('\n', shout);
-			    fflush(shout);
-			}
-		    } LASTALLOC;
+
+		    u = dupstring(u);
+		    if (! parsestr(u)) {
+			singsub(&u);
+			zputs(u, shout);
+			fputc('\n', shout);
+			fflush(shout);
+		    }
 		    setunderscore(usav);
 		}
 	    }
@@ -1490,11 +1488,11 @@ spckword(char **s, int hist, int cmd, int ask)
 		if (strncmp(guess, best, preflen))
 		    return;
 		/* replace the temporarily expanded prefix with the original */
-		u = (char *) ncalloc(t - *s + strlen(best + preflen) + 1);
+		u = (char *) hcalloc(t - *s + strlen(best + preflen) + 1);
 		strncpy(u, *s, t - *s);
 		strcpy(u + (t - *s), best + preflen);
 	    } else {
-		u = (char *) ncalloc(strlen(best) + 2);
+		u = (char *) hcalloc(strlen(best) + 2);
 		strcpy(u + 1, best);
 	    }
 	    best = u;
@@ -1631,7 +1629,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
 
 /**/
 mod_export char *
-zjoin(char **arr, int delim)
+zjoin(char **arr, int delim, int heap)
 {
     int len = 0;
     char **s, *ret, *ptr;
@@ -1640,7 +1638,7 @@ zjoin(char **arr, int delim)
 	len += strlen(*s) + 1;
     if (!len)
 	return "";
-    ptr = ret = (char *) ncalloc(len);
+    ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zcalloc(len));
     for (s = arr; *s; s++) {
 	strucpy(&ptr, *s);
 	if (delim)
@@ -1702,18 +1700,20 @@ skipwsep(char **s)
 
 /**/
 mod_export char **
-spacesplit(char *s, int allownull)
+spacesplit(char *s, int allownull, int heap)
 {
     char *t, **ret, **ptr;
+    int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1);
+    char *(*dup)(char *) = (heap ? dupstring : ztrdup);
 
-    ptr = ret = (char **) ncalloc(sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1));
+    ptr = ret = (heap ? (char **) hcalloc(l) : (char **) zcalloc(l));
 
     t = s;
     skipwsep(&s);
     if (*s && isep(*s == Meta ? s[1] ^ 32 : *s))
-	*ptr++ = dupstring(allownull ? "" : nulstring);
+	*ptr++ = dup(allownull ? "" : nulstring);
     else if (!allownull && t != s)
-	*ptr++ = dupstring("");
+	*ptr++ = dup("");
     while (*s) {
 	if (isep(*s == Meta ? s[1] ^ 32 : *s)) {
 	    if (*s == Meta)
@@ -1724,15 +1724,16 @@ spacesplit(char *s, int allownull)
 	t = s;
 	findsep(&s, NULL);
 	if (s > t || allownull) {
-	    *ptr = (char *) ncalloc((s - t) + 1);
+	    *ptr = (heap ? (char *) hcalloc((s - t) + 1) :
+		    (char *) zcalloc((s - t) + 1));
 	    ztrncpy(*ptr++, t, s - t);
 	} else
-	    *ptr++ = dupstring(nulstring);
+	    *ptr++ = dup(nulstring);
 	t = s;
 	skipwsep(&s);
     }
     if (!allownull && t != s)
-	*ptr++ = dupstring("");
+	*ptr++ = dup("");
     *ptr = NULL;
     return ret;
 }
@@ -1849,7 +1850,7 @@ wordcount(char *s, char *sep, int mul)
 
 /**/
 mod_export char *
-sepjoin(char **s, char *sep)
+sepjoin(char **s, char *sep, int heap)
 {
     char *r, *p, **t;
     int l, sl;
@@ -1865,7 +1866,7 @@ sepjoin(char **s, char *sep)
     }
     sl = strlen(sep);
     for (t = s, l = 1 - sl; *t; l += strlen(*t) + sl, t++);
-    r = p = (char *) ncalloc(l);
+    r = p = (heap ? (char *) hcalloc(l) : (char *) zcalloc(l));
     t = s;
     while (*t) {
 	strucpy(&p, *t);
@@ -1878,22 +1879,24 @@ sepjoin(char **s, char *sep)
 
 /**/
 char **
-sepsplit(char *s, char *sep, int allownull)
+sepsplit(char *s, char *sep, int allownull, int heap)
 {
     int n, sl;
     char *t, *tt, **r, **p;
 
     if (!sep)
-	return spacesplit(s, allownull);
+	return spacesplit(s, allownull, heap);
 
     sl = strlen(sep);
     n = wordcount(s, sep, 1);
-    r = p = (char **) ncalloc((n + 1) * sizeof(char *));
+    r = p = (heap ? (char **) hcalloc((n + 1) * sizeof(char *)) :
+	     (char **) zcalloc((n + 1) * sizeof(char *)));
 
     for (t = s; n--;) {
 	tt = t;
 	findsep(&t, sep);
-	*p = (char *) ncalloc(t - tt + 1);
+	*p = (heap ? (char *) hcalloc(t - tt + 1) :
+	      (char *) zcalloc(t - tt + 1));
 	strncpy(*p, tt, t - tt);
 	(*p)[t - tt] = '\0';
 	p++;
@@ -2026,43 +2029,23 @@ arrdup(char **s)
 {
     char **x, **y;
 
-    y = x = (char **) ncalloc(sizeof(char *) * (arrlen(s) + 1));
+    y = x = (char **) zhalloc(sizeof(char *) * (arrlen(s) + 1));
 
     while ((*x++ = dupstring(*s++)));
-    return y;
-}
-
-/* Duplicate a list of strings. */
 
-/**/
-LinkList
-listdup(LinkList l)
-{
-    if (!l)
-	return NULL;
-    else {
-	LinkList r = newlinklist();
-	LinkNode n;
-
-	for (n = firstnode(l); n; incnode(n))
-	    addlinknode(r, dupstring((char *) getdata(n)));
-
-	return r;
-    }
+    return y;
 }
 
 /**/
-char **
-listarr(LinkList l)
+mod_export char **
+zarrdup(char **s)
 {
     char **x, **y;
-    LinkNode n;
 
-    x = y = (char **) ncalloc((countlinknodes(l) + 1) * sizeof(char *));
+    y = x = (char **) zalloc(sizeof(char *) * (arrlen(s) + 1));
+
+    while ((*x++ = ztrdup(*s++)));
 
-    for (n = firstnode(l); n; incnode(n))
-	*x++ = dupstring((char *) getdata(n));
-    *x = NULL;
     return y;
 }
 
@@ -2771,7 +2754,7 @@ bslashquote(const char *s, char **e, int instring)
 {
     const char *u, *tt;
     char *v;
-    char *buf = ncalloc(4 * strlen(s) + 1);
+    char *buf = hcalloc(4 * strlen(s) + 1);
     int sf = 0;
 
     tt = v = buf;
@@ -3277,7 +3260,7 @@ strsfx(char *s, char *t)
 mod_export char *
 dupstrpfx(const char *s, int len)
 {
-    char *r = ncalloc(len + 1);
+    char *r = zhalloc(len + 1);
 
     memcpy(r, s, len);
     r[len] = '\0';
diff --git a/Src/zsh.h b/Src/zsh.h
index e3c7184f7..332bae9fd 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -337,21 +337,23 @@ struct linklist {
 
 /* Macros for manipulating link lists */
 
-#define addlinknode(X,Y) insertlinknode(X,(X)->last,Y)
-#define uaddlinknode(X,Y) uinsertlinknode(X,(X)->last,Y)
-#define empty(X)     ((X)->first == NULL)
-#define nonempty(X)  ((X)->first != NULL)
-#define firstnode(X) ((X)->first)
-#define getaddrdata(X) (&((X)->dat))
-#define getdata(X)   ((X)->dat)
-#define setdata(X,Y) ((X)->dat = (Y))
-#define lastnode(X)  ((X)->last)
-#define nextnode(X)  ((X)->next)
-#define prevnode(X)  ((X)->last)
-#define peekfirst(X) ((X)->first->dat)
-#define pushnode(X,Y) insertlinknode(X,(LinkNode) X,Y)
-#define incnode(X) (X = nextnode(X))
-#define firsthist() (hist_ring? hist_ring->down->histnum : curhist)
+#define addlinknode(X,Y)    insertlinknode(X,(X)->last,Y)
+#define zaddlinknode(X,Y)   zinsertlinknode(X,(X)->last,Y)
+#define uaddlinknode(X,Y)   uinsertlinknode(X,(X)->last,Y)
+#define empty(X)            ((X)->first == NULL)
+#define nonempty(X)         ((X)->first != NULL)
+#define firstnode(X)        ((X)->first)
+#define getaddrdata(X)      (&((X)->dat))
+#define getdata(X)          ((X)->dat)
+#define setdata(X,Y)        ((X)->dat = (Y))
+#define lastnode(X)         ((X)->last)
+#define nextnode(X)         ((X)->next)
+#define prevnode(X)         ((X)->last)
+#define peekfirst(X)        ((X)->first->dat)
+#define pushnode(X,Y)       insertlinknode(X,(LinkNode) X,Y)
+#define zpushnode(X,Y)      zinsertlinknode(X,(LinkNode) X,Y)
+#define incnode(X)          (X = nextnode(X))
+#define firsthist()         (hist_ring? hist_ring->down->histnum : curhist)
 #define setsizednode(X,Y,Z) ((X)->first[(Y)].dat = (void *) (Z))
 
 /* stack allocated linked lists */
@@ -483,7 +485,7 @@ typedef wordcode *Wordcode;
 typedef struct eprog *Eprog;
 
 struct eprog {
-    int heap;			/* != 0 if this is in heap memory */
+    int heap;			/* != 0 if in heap memory */
     int len;			/* total block length */
     int npats;			/* Patprog cache size */
     Patprog *pats;		/* the memory block, the patterns */
@@ -1590,53 +1592,13 @@ struct heap {
 #endif
 ;
 
-#ifndef DEBUG
-# define HEAPALLOC	do { int nonlocal_useheap = global_heapalloc(); do
+# define LASTALLOC_RETURN return
 
-# define PERMALLOC	do { int nonlocal_useheap = global_permalloc(); do
+# define NEWHEAPS(h)    do { Heap _switch_oldheaps = h = new_heaps(); do
+# define OLDHEAPS       while (0); old_heaps(_switch_oldheaps); } while (0);
 
-# define LASTALLOC	while (0); \
-			if (nonlocal_useheap) global_heapalloc(); \
-			else global_permalloc(); \
-		} while(0)
-
-# define LASTALLOC_RETURN \
-			if ((nonlocal_useheap ? global_heapalloc() : \
-			     global_permalloc()), 0) {;} else return
-
-# define NEWHEAPS(h)    do { Heap oldheaps = h = new_heaps(); do
-# define OLDHEAPS       while (0); old_heaps(oldheaps); } while (0);
-
-# define SWITCHHEAPS(h)  do { Heap oldheaps = switch_heaps(h); do
-# define SWITCHBACKHEAPS while (0); switch_heaps(oldheaps); } while (0);
-
-#else
-# define HEAPALLOC	do { int nonlocal_useheap = global_heapalloc(); \
-			alloc_stackp++; do
-
-# define PERMALLOC	do { int nonlocal_useheap = global_permalloc(); \
-			alloc_stackp++; do
-
-# define LASTALLOC	while (0); alloc_stackp--; \
-			if (nonlocal_useheap) global_heapalloc(); \
-			else global_permalloc(); \
-		} while(0)
-
-# define LASTALLOC_RETURN \
-			if ((nonlocal_useheap ? global_heapalloc() : \
-			    global_permalloc()),alloc_stackp--,0){;}else return
-
-# define NEWHEAPS(h)    do { Heap oldheaps = h = new_heaps(); \
-                        alloc_stackp++; do
-# define OLDHEAPS       while (0); alloc_stackp--; \
-                        old_heaps(oldheaps); } while (0);
-
-# define SWITCHHEAPS(h)  do { Heap oldheaps = switch_heaps(h); \
-                         alloc_stackp++; do
-# define SWITCHBACKHEAPS while (0); alloc_stackp--; \
-                         switch_heaps(oldheaps); } while (0);
-
-#endif
+# define SWITCHHEAPS(h)  do { Heap _switch_oldheaps = switch_heaps(h); do
+# define SWITCHBACKHEAPS while (0); switch_heaps(_switch_oldheaps); } while (0);
 
 /****************/
 /* Debug macros */
@@ -1644,12 +1606,8 @@ struct heap {
 
 #ifdef DEBUG
 # define DPUTS(X,Y) if (!(X)) {;} else dputs(Y)
-# define MUSTUSEHEAP(X) if (useheap) {;} else \
-		fprintf(stderr, "BUG: permanent allocation in %s\n", X), \
-		fflush(stderr)
 #else
 # define DPUTS(X,Y)
-# define MUSTUSEHEAP(X)
 #endif
 
 /**************************/