about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/datetime.c4
-rw-r--r--Src/Modules/langinfo.c16
-rw-r--r--Src/Modules/mapfile.c34
-rw-r--r--Src/Modules/parameter.c322
-rw-r--r--Src/Modules/system.c2
-rw-r--r--Src/Modules/termcap.c49
-rw-r--r--Src/Modules/terminfo.c45
-rw-r--r--Src/Modules/zftp.c8
-rw-r--r--Src/Zle/compctl.c18
-rw-r--r--Src/Zle/compctl.h6
-rw-r--r--Src/Zle/complete.c22
-rw-r--r--Src/Zle/compresult.c2
-rw-r--r--Src/Zle/computil.c2
-rw-r--r--Src/Zle/zle_hist.c24
-rw-r--r--Src/Zle/zle_main.c6
-rw-r--r--Src/Zle/zle_params.c2
-rw-r--r--Src/Zle/zle_tricky.c6
-rw-r--r--Src/Zle/zleparameter.c18
-rw-r--r--Src/builtin.c190
-rw-r--r--Src/exec.c90
-rw-r--r--Src/hashtable.c170
-rw-r--r--Src/hist.c74
-rw-r--r--Src/init.c2
-rw-r--r--Src/lex.c2
-rw-r--r--Src/linklist.c79
-rw-r--r--Src/module.c50
-rw-r--r--Src/options.c352
-rw-r--r--Src/params.c358
-rw-r--r--Src/parse.c22
-rw-r--r--Src/prompt.c2
-rw-r--r--Src/signals.c8
-rw-r--r--Src/subst.c26
-rw-r--r--Src/utils.c16
-rw-r--r--Src/zsh.h82
34 files changed, 1043 insertions, 1066 deletions
diff --git a/Src/Modules/datetime.c b/Src/Modules/datetime.c
index f01a54ea1..80090a65b 100644
--- a/Src/Modules/datetime.c
+++ b/Src/Modules/datetime.c
@@ -118,8 +118,8 @@ cleanup_(Module m)
 
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     pm = (Param) paramtab->getnode(paramtab, "EPOCHSECONDS");
-    if (pm && (pm->flags & PM_SPECIAL)) {
-	pm->flags &= ~PM_READONLY;
+    if (pm && (pm->node.flags & PM_SPECIAL)) {
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
     return 0;
diff --git a/Src/Modules/langinfo.c b/Src/Modules/langinfo.c
index 10754e36c..d927358ed 100644
--- a/Src/Modules/langinfo.c
+++ b/Src/Modules/langinfo.c
@@ -446,8 +446,8 @@ getlanginfo(UNUSED(HashTable ht), char *name)
     unmetafy(name, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if(name)
@@ -462,9 +462,9 @@ getlanginfo(UNUSED(HashTable ht), char *name)
     {
 	/* zwarn("no such lang info: %s", name, 0); */
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -477,14 +477,14 @@ scanlanginfo(UNUSED(HashTable ht), ScanFunc func, int flags)
 
     pm = (Param) hcalloc(sizeof(struct param));
     pm->gsu.s = &nullsetscalar_gsu;
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.flags = PM_READONLY | PM_SCALAR;
 
     nlcode = &nl_vals[0];
     for (element = (char **)nl_names; *element; element++, nlcode++) {
 	if ((langstr = nl_langinfo(*nlcode)) != NULL) {
 	    pm->u.str = dupstring(langstr);
-	    pm->nam = dupstring(*element);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*element);
+	    func(&pm->node, flags);
 	}
     }
     
@@ -522,7 +522,7 @@ cleanup_(UNUSED(Module m))
 
     if ((pm = (Param) paramtab->getnode(paramtab, langinfo_nam)) &&
 	pm == langinfo_pm) {
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 #endif
diff --git a/Src/Modules/mapfile.c b/Src/Modules/mapfile.c
index 0ba7e6fd9..9f3ca2612 100644
--- a/Src/Modules/mapfile.c
+++ b/Src/Modules/mapfile.c
@@ -119,7 +119,7 @@ static void
 setpmmapfile(Param pm, char *value)
 {
     int fd = -1, len;
-    char *name = ztrdup(pm->nam);
+    char *name = ztrdup(pm->node.nam);
 #ifdef USE_MMAP
     caddr_t mmptr;
 #else
@@ -135,7 +135,7 @@ setpmmapfile(Param pm, char *value)
 
     /* Open the file for writing */
 #ifdef USE_MMAP
-    if (!(pm->flags & PM_READONLY) &&
+    if (!(pm->node.flags & PM_READONLY) &&
 	(fd = open(name, O_RDWR|O_CREAT|O_NOCTTY, 0666)) >= 0 &&
 	(mmptr = (caddr_t)mmap((caddr_t)0, len, PROT_READ | PROT_WRITE,
 			       MMAP_ARGS, fd, (off_t)0)) != (caddr_t)-1) {
@@ -175,11 +175,11 @@ static void
 unsetpmmapfile(Param pm, UNUSED(int exp))
 {
     /* Unlink the file given by pm->nam */
-    char *fname = ztrdup(pm->nam);
+    char *fname = ztrdup(pm->node.nam);
     int dummy;
     unmetafy(fname, &dummy);
 
-    if (!(pm->flags & PM_READONLY))
+    if (!(pm->node.flags & PM_READONLY))
 	unlink(fname);
 
     free(fname);
@@ -198,7 +198,7 @@ setpmmapfiles(Param pm, HashTable ht)
     if (!ht)
 	return;
 
-    if (!(pm->flags & PM_READONLY))
+    if (!(pm->node.flags & PM_READONLY))
 	for (i = 0; i < ht->hsize; i++)
 	    for (hn = ht->nodes[i]; hn; hn = hn->next) {
 		struct value v;
@@ -269,19 +269,19 @@ getpmmapfile(UNUSED(HashTable ht), char *name)
     Param pm = NULL;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR;
     pm->gsu.s = &mapfile_gsu;
-    pm->flags |= (mapfile_pm->flags & PM_READONLY);
+    pm->node.flags |= (mapfile_pm->node.flags & PM_READONLY);
 
     /* Set u.str to contents of file given by name */
-    if ((contents = get_contents(pm->nam)))
+    if ((contents = get_contents(pm->node.nam)))
 	pm->u.str = contents;
     else {
 	pm->u.str = "";
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 
@@ -296,21 +296,21 @@ scanpmmapfile(UNUSED(HashTable ht), ScanFunc func, int flags)
 	return;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR;
+    pm.node.flags = PM_SCALAR;
     pm.gsu.s = &mapfile_gsu;
-    pm.flags |= (mapfile_pm->flags & PM_READONLY);
+    pm.node.flags |= (mapfile_pm->node.flags & PM_READONLY);
 
     /* Here we scan the current directory, calling func() for each file */
-    while ((pm.nam = zreaddir(dir, 1))) {
+    while ((pm.node.nam = zreaddir(dir, 1))) {
 	/*
 	 * Hmmm, it's rather wasteful always to read the contents.
 	 * In fact, it's grotesequely wasteful, since that would mean
 	 * we always read the entire contents of every single file
 	 * in the directory into memory.  Hence just leave it empty.
 	 */
-	pm.nam = dupstring(pm.nam);
+	pm.node.nam = dupstring(pm.node.nam);
 	pm.u.str = "";
-	func((HashNode) &pm, flags);
+	func(&pm.node, flags);
     }
     closedir(dir);
 }
@@ -344,7 +344,7 @@ cleanup_(UNUSED(Module m))
 
     if ((pm = (Param) paramtab->getnode(paramtab, mapfile_nam)) &&
 	pm == mapfile_pm) {
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
     return 0;
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index faa18a92d..2f9f574e0 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -83,10 +83,10 @@ static char *
 paramtypestr(Param pm)
 {
     char *val = NULL;
-    int f = pm->flags;
+    int f = pm->node.flags;
 
     if (!(f & PM_UNSET)) {
-	if (pm->flags & PM_AUTOLOAD)
+	if (pm->node.flags & PM_AUTOLOAD)
 	    return dupstring("undefined");
 
 	switch (PM_TYPE(f)) {
@@ -138,17 +138,17 @@ getpmparameter(UNUSED(HashTable ht), char *name)
     Param rpm, pm = NULL;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
     if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
-	!(rpm->flags & PM_UNSET))
+	!(rpm->node.flags & PM_UNSET))
 	pm->u.str = paramtypestr(rpm);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -160,19 +160,19 @@ scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags)
     HashNode hn;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < realparamtab->hsize; i++)
 	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
-	    if (((Param)hn)->flags & PM_UNSET)
+	    if (((Param)hn)->node.flags & PM_UNSET)
 		continue;
-	    pm.nam = hn->nam;
+	    pm.node.nam = hn->nam;
 	    if (func != scancountparams &&
 		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		 !(flags & SCANPM_WANTKEYS)))
 		pm.u.str = paramtypestr((Param) hn);
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
 }
 
@@ -188,10 +188,10 @@ setpmcommand(Param pm, char *value)
     } else {
 	Cmdnam cn = zshcalloc(sizeof(*cn));
 
-	cn->flags = HASHED;
+	cn->node.flags = HASHED;
 	cn->u.cmd = value;
 
-	cmdnamtab->addnode(cmdnamtab, ztrdup(pm->nam), (HashNode) cn);
+	cmdnamtab->addnode(cmdnamtab, ztrdup(pm->node.nam), &cn->node);
     }
 }
 
@@ -199,7 +199,7 @@ setpmcommand(Param pm, char *value)
 static void
 unsetpmcommand(Param pm, UNUSED(int exp))
 {
-    HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->nam);
+    HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->node.nam);
 
     if (hn)
 	cmdnamtab->freenode(hn);
@@ -225,10 +225,10 @@ setpmcommands(UNUSED(Param pm), HashTable ht)
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
-	    cn->flags = HASHED;
+	    cn->node.flags = HASHED;
 	    cn->u.cmd = ztrdup(getstrvalue(&v));
 
-	    cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), (HashNode) cn);
+	    cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), &cn->node);
 	}
     deleteparamtable(ht);
 }
@@ -250,11 +250,11 @@ getpmcommand(UNUSED(HashTable ht), char *name)
 	cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
     }
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR;
     pm->gsu.s = &pmcommand_gsu;
     if (cmd) {
-	if (cmd->flags & HASHED)
+	if (cmd->node.flags & HASHED)
 	    pm->u.str = cmd->u.cmd;
 	else {
 	    pm->u.str = zhalloc(strlen(*(cmd->u.name)) + strlen(name) + 2);
@@ -264,9 +264,9 @@ getpmcommand(UNUSED(HashTable ht), char *name)
 	}
     } else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -282,27 +282,27 @@ scanpmcommands(UNUSED(HashTable ht), ScanFunc func, int flags)
 	cmdnamtab->filltable(cmdnamtab);
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR;
+    pm.node.flags = PM_SCALAR;
     pm.gsu.s = &pmcommand_gsu;
 
     for (i = 0; i < cmdnamtab->hsize; i++)
 	for (hn = cmdnamtab->nodes[i]; hn; hn = hn->next) {
-	    pm.nam = hn->nam;
+	    pm.node.nam = hn->nam;
 	    cmd = (Cmdnam) hn;
 	    if (func != scancountparams &&
 		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		 !(flags & SCANPM_WANTKEYS))) {
-		if (cmd->flags & HASHED)
+		if (cmd->node.flags & HASHED)
 		    pm.u.str = cmd->u.cmd;
 		else {
 		    pm.u.str = zhalloc(strlen(*(cmd->u.name)) +
-				       strlen(cmd->nam) + 2);
+				       strlen(cmd->node.nam) + 2);
 		    strcpy(pm.u.str, *(cmd->u.name));
 		    strcat(pm.u.str, "/");
-		    strcat(pm.u.str, cmd->nam);
+		    strcat(pm.u.str, cmd->node.nam);
 		}
 	    }
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
 }
 
@@ -328,7 +328,7 @@ setfunction(char *name, char *val, int dis)
     }
     shf = (Shfunc) zalloc(sizeof(*shf));
     shf->funcdef = dupeprog(prog, 0);
-    shf->flags = dis;
+    shf->node.flags = dis;
 
     if (!strncmp(name, "TRAP", 4) &&
 	(sn = getsignum(name + 4)) != -1) {
@@ -347,21 +347,21 @@ setfunction(char *name, char *val, int dis)
 static void
 setpmfunction(Param pm, char *value)
 {
-    setfunction(pm->nam, value, 0);
+    setfunction(pm->node.nam, value, 0);
 }
 
 /**/
 static void
 setpmdisfunction(Param pm, char *value)
 {
-    setfunction(pm->nam, value, DISABLED);
+    setfunction(pm->node.nam, value, DISABLED);
 }
 
 /**/
 static void
 unsetpmfunction(Param pm, UNUSED(int exp))
 {
-    HashNode hn = shfunctab->removenode(shfunctab, pm->nam);
+    HashNode hn = shfunctab->removenode(shfunctab, pm->node.nam);
 
     if (hn)
 	shfunctab->freenode(hn);
@@ -418,17 +418,17 @@ getfunction(UNUSED(HashTable ht), char *name, int dis)
     Param pm = NULL;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR;
     pm->gsu.s = dis ? &pmdisfunction_gsu :  &pmfunction_gsu;
 
     if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
-	(dis ? (shf->flags & DISABLED) : !(shf->flags & DISABLED))) {
-	if (shf->flags & PM_UNDEFINED) {
+	(dis ? (shf->node.flags & DISABLED) : !(shf->node.flags & DISABLED))) {
+	if (shf->node.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" : "")));
+			       ((shf->node.flags & PM_UNALIASED) ?
+				((shf->node.flags & PM_TAGGED) ? "Ut" : "U") :
+				((shf->node.flags & PM_TAGGED) ? "t" : "")));
 	} else {
 	    char *t = getpermtext(shf->funcdef, NULL), *n, *h;
 
@@ -449,9 +449,9 @@ getfunction(UNUSED(HashTable ht), char *name, int dis)
 	}
     } else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -477,23 +477,23 @@ scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
     HashNode hn;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR;
+    pm.node.flags = PM_SCALAR;
     pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
 
     for (i = 0; i < shfunctab->hsize; i++)
 	for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
 	    if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
-		pm.nam = hn->nam;
+		pm.node.nam = hn->nam;
 		if (func != scancountparams &&
 		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		     !(flags & SCANPM_WANTKEYS))) {
-		    if (((Shfunc) hn)->flags & PM_UNDEFINED) {
+		    if (((Shfunc) hn)->node.flags & PM_UNDEFINED) {
 			Shfunc shf = (Shfunc) hn;
 			pm.u.str =
 			    dyncat("builtin autoload -X",
-				   ((shf->flags & PM_UNALIASED) ?
-				    ((shf->flags & PM_TAGGED) ? "Ut" : "U") :
-				    ((shf->flags & PM_TAGGED) ? "t" : "")));
+				   ((shf->node.flags & PM_UNALIASED) ?
+				    ((shf->node.flags & PM_TAGGED) ? "Ut" : "U") :
+				    ((shf->node.flags & PM_TAGGED) ? "t" : "")));
 		    } else {
 			char *t = getpermtext(((Shfunc) hn)->funcdef, NULL), *n;
 
@@ -511,7 +511,7 @@ scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
 			zsfree(t);
 		    }
 		}
-		func((HashNode) &pm, flags);
+		func(&pm.node, flags);
 	    }
 	}
 }
@@ -561,20 +561,20 @@ getbuiltin(UNUSED(HashTable ht), char *name, int dis)
     Builtin bn;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
     if ((bn = (Builtin) builtintab->getnode2(builtintab, name)) &&
-	(dis ? (bn->flags & DISABLED) : !(bn->flags & DISABLED))) {
-	char *t = ((bn->handlerfunc || (bn->flags & BINF_PREFIX)) ?
+	(dis ? (bn->node.flags & DISABLED) : !(bn->node.flags & DISABLED))) {
+	char *t = ((bn->handlerfunc || (bn->node.flags & BINF_PREFIX)) ?
 		   "defined" : "undefined");
 
 	pm->u.str = dupstring(t);
     } else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -600,13 +600,13 @@ scanbuiltins(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
     HashNode hn;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < builtintab->hsize; i++)
 	for (hn = builtintab->nodes[i]; hn; hn = hn->next) {
 	    if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
-		pm.nam = hn->nam;
+		pm.node.nam = hn->nam;
 		if (func != scancountparams &&
 		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		     !(flags & SCANPM_WANTKEYS))) {
@@ -616,7 +616,7 @@ scanbuiltins(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
 
 		    pm.u.str = dupstring(t);
 		}
-		func((HashNode) &pm, flags);
+		func(&pm.node, flags);
 	    }
 	}
 }
@@ -680,10 +680,10 @@ setpmoption(Param pm, char *value)
 
     if (!value || (strcmp(value, "on") && strcmp(value, "off")))
 	zwarn("invalid value: %s", value, 0);
-    else if (!(n = optlookup(pm->nam)))
-	zwarn("no such option: %s", pm->nam, 0);
+    else if (!(n = optlookup(pm->node.nam)))
+	zwarn("no such option: %s", pm->node.nam, 0);
     else if (dosetopt(n, (value && strcmp(value, "off")), 0))
-	zwarn("can't change option: %s", pm->nam, 0);
+	zwarn("can't change option: %s", pm->node.nam, 0);
     zsfree(value);
 }
 
@@ -693,10 +693,10 @@ unsetpmoption(Param pm, UNUSED(int exp))
 {
     int n;
 
-    if (!(n = optlookup(pm->nam)))
-	zwarn("no such option: %s", pm->nam, 0);
+    if (!(n = optlookup(pm->node.nam)))
+	zwarn("no such option: %s", pm->node.nam, 0);
     else if (dosetopt(n, 0, 0))
-	zwarn("can't change option: %s", pm->nam, 0);
+	zwarn("can't change option: %s", pm->node.nam, 0);
 }
 
 /**/
@@ -740,8 +740,8 @@ getpmoption(UNUSED(HashTable ht), char *name)
     int n;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR;
     pm->gsu.s = &pmoption_gsu;
 
     if ((n = optlookup(name)))
@@ -755,9 +755,9 @@ getpmoption(UNUSED(HashTable ht), char *name)
     }
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -769,16 +769,16 @@ scanpmoptions(UNUSED(HashTable ht), ScanFunc func, int flags)
     HashNode hn;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR;
+    pm.node.flags = PM_SCALAR;
     pm.gsu.s = &pmoption_gsu;
 
     for (i = 0; i < optiontab->hsize; i++)
 	for (hn = optiontab->nodes[i]; hn; hn = hn->next) {
 	    int optno = ((Optname) hn)->optno, ison;
-	    pm.nam = hn->nam;
+	    pm.node.nam = hn->nam;
 	    ison = optno < 0 ? !opts[-optno] : opts[optno];
 	    pm.u.str = dupstring(ison ? "on" : "off");
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
 }
 
@@ -791,7 +791,7 @@ static int modpmfound;
 static void
 modpmbuiltinscan(HashNode hn, UNUSED(int dummy))
 {
-    if (!(((Builtin) hn)->flags & BINF_ADDED) &&
+    if (!(((Builtin) hn)->node.flags & BINF_ADDED) &&
 	!strcmp(((Builtin) hn)->optstr, modpmname))
 	modpmfound = 1;
 }
@@ -800,7 +800,7 @@ modpmbuiltinscan(HashNode hn, UNUSED(int dummy))
 static void
 modpmparamscan(HashNode hn, UNUSED(int dummy))
 {
-    if ((((Param) hn)->flags & PM_AUTOLOAD) &&
+    if ((((Param) hn)->node.flags & PM_AUTOLOAD) &&
 	!strcmp(((Param) hn)->u.str, modpmname))
 	modpmfound = 1;
 }
@@ -827,8 +827,8 @@ getpmmodule(UNUSED(HashTable ht), char *name)
     LinkNode node;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if (!type) {
@@ -866,9 +866,9 @@ getpmmodule(UNUSED(HashTable ht), char *name)
 	pm->u.str = dupstring(type);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -885,42 +885,42 @@ scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
     char *loaded = dupstring("loaded");
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (node = firstnode(modules); node; incnode(node)) {
 	m = (Module) getdata(node);
 	if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
-	    pm.nam = m->nam;
+	    pm.node.nam = m->nam;
 	    pm.u.str = ((m->flags & MOD_ALIAS) ?
 			dyncat("alias:", m->u.alias) : loaded);
-	    addlinknode(done, pm.nam);
-	    func((HashNode) &pm, flags);
+	    addlinknode(done, pm.node.nam);
+	    func(&pm.node, flags);
 	}
     }
     pm.u.str = dupstring("autoloaded");
     for (i = 0; i < builtintab->hsize; i++)
 	for (hn = builtintab->nodes[i]; hn; hn = hn->next) {
-	    if (!(((Builtin) hn)->flags & BINF_ADDED) &&
+	    if (!(((Builtin) hn)->node.flags & BINF_ADDED) &&
 		!findmodnode(done, ((Builtin) hn)->optstr)) {
-		pm.nam = ((Builtin) hn)->optstr;
-		addlinknode(done, pm.nam);
-		func((HashNode) &pm, flags);
+		pm.node.nam = ((Builtin) hn)->optstr;
+		addlinknode(done, pm.node.nam);
+		func(&pm.node, flags);
 	    }
 	}
     for (p = condtab; p; p = p->next)
 	if (p->module && !findmodnode(done, p->module)) {
-	    pm.nam = p->module;
-	    addlinknode(done, pm.nam);
-	    func((HashNode) &pm, flags);
+	    pm.node.nam = p->module;
+	    addlinknode(done, pm.node.nam);
+	    func(&pm.node, flags);
 	}
     for (i = 0; i < realparamtab->hsize; i++)
 	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
-	    if ((((Param) hn)->flags & PM_AUTOLOAD) &&
+	    if ((((Param) hn)->node.flags & PM_AUTOLOAD) &&
 		!findmodnode(done, ((Param) hn)->u.str)) {
-		pm.nam = ((Param) hn)->u.str;
-		addlinknode(done, pm.nam);
-		func((HashNode) &pm, flags);
+		pm.node.nam = ((Param) hn)->u.str;
+		addlinknode(done, pm.node.nam);
+		func(&pm.node, flags);
 	    }
 	}
 }
@@ -970,8 +970,8 @@ getpmhistory(UNUSED(HashTable ht), char *name)
     int ok = 1;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if (*name != '0' || name[1]) {
@@ -984,12 +984,12 @@ getpmhistory(UNUSED(HashTable ht), char *name)
 	}
     }
     if (ok && (he = quietgethist(atoi(name))))
-	pm->u.str = dupstring(he->text);
+	pm->u.str = dupstring(he->node.nam);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1002,18 +1002,18 @@ scanpmhistory(UNUSED(HashTable ht), ScanFunc func, int flags)
     char buf[40];
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     while (he) {
 	if (func != scancountparams) {
 	    convbase(buf, he->histnum, 10);
-	    pm.nam = dupstring(buf);
+	    pm.node.nam = dupstring(buf);
 	    if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		!(flags & SCANPM_WANTKEYS))
-		pm.u.str = dupstring(he->text);
+		pm.u.str = dupstring(he->node.nam);
 	}
-	func((HashNode) &pm, flags);
+	func(&pm.node, flags);
 
 	he = up_histent(he);
     }
@@ -1037,8 +1037,8 @@ histwgetfn(UNUSED(Param pm))
 
     while (he) {
 	for (iw = he->nwords - 1; iw >= 0; iw--) {
-	    h = he->text + he->words[iw * 2];
-	    e = he->text + he->words[iw * 2 + 1];
+	    h = he->node.nam + he->words[iw * 2];
+	    e = he->node.nam + he->words[iw * 2 + 1];
 	    sav = *e;
 	    *e = '\0';
 	    addlinknode(l, dupstring(h));
@@ -1087,8 +1087,8 @@ getpmjobtext(UNUSED(HashTable ht), char *name)
     int job;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if ((job = atoi(name)) >= 1 && job <= maxjob &&
@@ -1097,9 +1097,9 @@ getpmjobtext(UNUSED(HashTable ht), char *name)
 	pm->u.str = pmjobtext(job);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1111,7 +1111,7 @@ scanpmjobtexts(UNUSED(HashTable ht), ScanFunc func, int flags)
     char buf[40];
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (job = 1; job <= maxjob; job++) {
@@ -1119,12 +1119,12 @@ scanpmjobtexts(UNUSED(HashTable ht), ScanFunc func, int flags)
 	    !(jobtab[job].stat & STAT_NOPRINT)) {
 	    if (func != scancountparams) {
 		sprintf(buf, "%d", job);
-		pm.nam = dupstring(buf);
+		pm.node.nam = dupstring(buf);
 		if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		    !(flags & SCANPM_WANTKEYS))
 		    pm.u.str = pmjobtext(job);
 	    }
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
     }
 }
@@ -1184,8 +1184,8 @@ getpmjobstate(UNUSED(HashTable ht), char *name)
     int job;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if ((job = atoi(name)) >= 1 && job <= maxjob &&
@@ -1194,9 +1194,9 @@ getpmjobstate(UNUSED(HashTable ht), char *name)
 	pm->u.str = pmjobstate(job);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1208,7 +1208,7 @@ scanpmjobstates(UNUSED(HashTable ht), ScanFunc func, int flags)
     char buf[40];
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (job = 1; job <= maxjob; job++) {
@@ -1216,12 +1216,12 @@ scanpmjobstates(UNUSED(HashTable ht), ScanFunc func, int flags)
 	    !(jobtab[job].stat & STAT_NOPRINT)) {
 	    if (func != scancountparams) {
 		sprintf(buf, "%d", job);
-		pm.nam = dupstring(buf);
+		pm.node.nam = dupstring(buf);
 		if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		    !(flags & SCANPM_WANTKEYS))
 		    pm.u.str = pmjobstate(job);
 	    }
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
     }
 }
@@ -1246,8 +1246,8 @@ getpmjobdir(UNUSED(HashTable ht), char *name)
     int job;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if ((job = atoi(name)) >= 1 && job <= maxjob &&
@@ -1256,9 +1256,9 @@ getpmjobdir(UNUSED(HashTable ht), char *name)
 	pm->u.str = pmjobdir(job);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1270,7 +1270,7 @@ scanpmjobdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
     char buf[40];
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (job = 1; job <= maxjob; job++) {
@@ -1278,12 +1278,12 @@ scanpmjobdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
            !(jobtab[job].stat & STAT_NOPRINT)) {
            if (func != scancountparams) {
 	       sprintf(buf, "%d", job);
-	       pm.nam = dupstring(buf);
+	       pm.node.nam = dupstring(buf);
                if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		   !(flags & SCANPM_WANTKEYS))
 		   pm.u.str = pmjobdir(job);
 	   }
-           func((HashNode) &pm, flags);
+           func(&pm.node, flags);
        }
     }
 }
@@ -1299,9 +1299,9 @@ setpmnameddir(Param pm, char *value)
     else {
 	Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
 
-	nd->flags = 0;
+	nd->node.flags = 0;
 	nd->dir = value;
-	nameddirtab->addnode(nameddirtab, ztrdup(pm->nam), nd);
+	nameddirtab->addnode(nameddirtab, ztrdup(pm->node.nam), nd);
     }
 }
 
@@ -1309,7 +1309,7 @@ setpmnameddir(Param pm, char *value)
 static void
 unsetpmnameddir(Param pm, UNUSED(int exp))
 {
-    HashNode hd = nameddirtab->removenode(nameddirtab, pm->nam);
+    HashNode hd = nameddirtab->removenode(nameddirtab, pm->node.nam);
 
     if (hd)
 	nameddirtab->freenode(hd);
@@ -1328,7 +1328,7 @@ setpmnameddirs(UNUSED(Param pm), HashTable ht)
     for (i = 0; i < nameddirtab->hsize; i++)
 	for (hn = nameddirtab->nodes[i]; hn; hn = next) {
 	    next = hn->next;
-	    if (!(((Nameddir) hn)->flags & ND_USERNAME) &&
+	    if (!(((Nameddir) hn)->node.flags & ND_USERNAME) &&
 		(hd = nameddirtab->removenode(nameddirtab, hn->nam)))
 		nameddirtab->freenode(hd);
 	}
@@ -1348,7 +1348,7 @@ setpmnameddirs(UNUSED(Param pm), HashTable ht)
 	    else {
 		Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
 
-		nd->flags = 0;
+		nd->node.flags = 0;
 		nd->dir = ztrdup(val);
 		nameddirtab->addnode(nameddirtab, ztrdup(hn->nam), nd);
 	    }
@@ -1374,17 +1374,17 @@ getpmnameddir(UNUSED(HashTable ht), char *name)
     Nameddir nd;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR;
     pm->gsu.s = &pmnamedir_gsu;
     if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
-	!(nd->flags & ND_USERNAME))
+	!(nd->node.flags & ND_USERNAME))
 	pm->u.str = dupstring(nd->dir);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1397,18 +1397,18 @@ scanpmnameddirs(UNUSED(HashTable ht), ScanFunc func, int flags)
     Nameddir nd;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR;
+    pm.node.flags = PM_SCALAR;
     pm.gsu.s = &pmnamedir_gsu;
 
     for (i = 0; i < nameddirtab->hsize; i++)
 	for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
-	    if (!((nd = (Nameddir) hn)->flags & ND_USERNAME)) {
-		pm.nam = hn->nam;
+	    if (!((nd = (Nameddir) hn)->node.flags & ND_USERNAME)) {
+		pm.node.nam = hn->nam;
 		if (func != scancountparams &&
 		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		     !(flags & SCANPM_WANTKEYS)))
 		    pm.u.str = dupstring(nd->dir);
-		func((HashNode) &pm, flags);
+		func(&pm.node, flags);
 	    }
 	}
 }
@@ -1425,17 +1425,17 @@ getpmuserdir(UNUSED(HashTable ht), char *name)
     nameddirtab->filltable(nameddirtab);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
     if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
-	(nd->flags & ND_USERNAME))
+	(nd->node.flags & ND_USERNAME))
 	pm->u.str = dupstring(nd->dir);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1450,18 +1450,18 @@ scanpmuserdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
     nameddirtab->filltable(nameddirtab);
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < nameddirtab->hsize; i++)
 	for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
-	    if ((nd = (Nameddir) hn)->flags & ND_USERNAME) {
-		pm.nam = hn->nam;
+	    if ((nd = (Nameddir) hn)->node.flags & ND_USERNAME) {
+		pm.node.nam = hn->nam;
 		if (func != scancountparams &&
 		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		     !(flags & SCANPM_WANTKEYS)))
 		    pm.u.str = dupstring(nd->dir);
-		func((HashNode) &pm, flags);
+		func(&pm.node, flags);
 	    }
 	}
 }
@@ -1472,7 +1472,7 @@ scanpmuserdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
 static void
 setalias(HashTable ht, Param pm, char *value, int flags)
 {
-    ht->addnode(ht, ztrdup(pm->nam),
+    ht->addnode(ht, ztrdup(pm->node.nam),
 		createaliasnode(value, flags));
 }
 
@@ -1522,7 +1522,7 @@ setpmdissalias(Param pm, char *value)
 static void
 unsetpmalias(Param pm, UNUSED(int exp))
 {
-    HashNode hd = aliastab->removenode(aliastab, pm->nam);
+    HashNode hd = aliastab->removenode(aliastab, pm->node.nam);
 
     if (hd)
 	aliastab->freenode(hd);
@@ -1532,7 +1532,7 @@ unsetpmalias(Param pm, UNUSED(int exp))
 static void
 unsetpmsalias(Param pm, UNUSED(int exp))
 {
-    HashNode hd = sufaliastab->removenode(sufaliastab, pm->nam);
+    HashNode hd = sufaliastab->removenode(sufaliastab, pm->node.nam);
 
     if (hd)
 	sufaliastab->freenode(hd);
@@ -1557,7 +1557,7 @@ setaliases(HashTable alht, UNUSED(Param pm), HashTable ht, int flags)
 	     * The predecessor to this code didn't do that; presumably
 	     * that was a bug.
 	     */
-	    if (flags == ((Alias)hn)->flags &&
+	    if (flags == ((Alias)hn)->node.flags &&
 		(hd = alht->removenode(alht, hn->nam)))
 		alht->freenode(hd);
 	}
@@ -1638,7 +1638,7 @@ static const struct gsu_scalar pmdissalias_gsu =
 static void
 assignaliasdefs(Param pm, int flags)
 {
-    pm->flags = PM_SCALAR;
+    pm->node.flags = PM_SCALAR;
 
     /* we really need to squirrel the flags away somewhere... */
     switch (flags) {
@@ -1676,18 +1676,18 @@ getalias(HashTable alht, UNUSED(HashTable ht), char *name, int flags)
     Alias al;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
+    pm->node.nam = dupstring(name);
 
     assignaliasdefs(pm, flags);
 
     if ((al = (Alias) alht->getnode2(alht, name)) &&
-	flags == al->flags)
+	flags == al->node.flags)
 	pm->u.str = dupstring(al->text);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -1745,14 +1745,14 @@ scanaliases(HashTable alht, UNUSED(HashTable ht), ScanFunc func,
     assignaliasdefs(&pm, alflags);
 
     for (i = 0; i < alht->hsize; i++)
-	for (al = (Alias) alht->nodes[i]; al; al = (Alias) al->next) {
-	    if (alflags == al->flags) {
-		pm.nam = al->nam;
+	for (al = (Alias) alht->nodes[i]; al; al = (Alias) al->node.next) {
+	    if (alflags == al->node.flags) {
+		pm.node.nam = al->node.nam;
 		if (func != scancountparams &&
 		    ((pmflags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		     !(pmflags & SCANPM_WANTKEYS)))
-		    pm.u.str = dupstring(al->text);
-		func((HashNode) &pm, pmflags);
+		    pm.u.str = dupstring(al->node.nam);
+		func(&pm.node, pmflags);
 	    }
 	}
 }
@@ -1958,7 +1958,7 @@ boot_(UNUSED(Module m))
 	    if (!(def->pm = createspecialhash(def->name, def->getnfn,
 					      def->scantfn)))
 		return 1;
-	    def->pm->flags |= def->flags;
+	    def->pm->node.flags |= def->flags;
 	    if (def->hash_gsu)
 		def->pm->gsu.h = def->hash_gsu;
 	} else {
@@ -1983,7 +1983,7 @@ cleanup_(UNUSED(Module m))
     for (def = partab; def->name; def++) {
 	if ((pm = (Param) paramtab->getnode(paramtab, def->name)) &&
 	    pm == def->pm) {
-	    pm->flags &= ~PM_READONLY;
+	    pm->node.flags &= ~PM_READONLY;
 	    unsetparam_pm(pm, 0, 1);
 	}
     }
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index 3f932c9fa..7b1c08a95 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -376,7 +376,7 @@ tidyparam(Param pm)
 {
     if (!pm)
 	return;
-    pm->flags &= ~PM_READONLY;
+    pm->node.flags &= ~PM_READONLY;
     unsetparam_pm(pm, 0, 1);
 }
 
diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c
index 8573477c5..9e7ee57ae 100644
--- a/Src/Modules/termcap.c
+++ b/Src/Modules/termcap.c
@@ -233,8 +233,8 @@ gettermcap(UNUSED(HashTable ht), char *name)
     unmetafy(name, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_READONLY;
     u = buf;
 
     /* logic in the following cascade copied from echotc, above */
@@ -242,8 +242,8 @@ gettermcap(UNUSED(HashTable ht), char *name)
     if ((num = tgetnum(name)) != -1) {
 	pm->gsu.i = &nullsetinteger_gsu;
 	pm->u.val = num;
-	pm->flags |= PM_INTEGER;
-	return (HashNode) pm;
+	pm->node.flags |= PM_INTEGER;
+	return &pm->node;
     }
 
     pm->gsu.s = &nullsetscalar_gsu;
@@ -252,25 +252,22 @@ gettermcap(UNUSED(HashTable ht), char *name)
 	break;
     case 0:
 	pm->u.str = dupstring("no");
-	pm->flags |= PM_SCALAR;
-	return (HashNode) pm;
+	pm->node.flags |= PM_SCALAR;
+	return &pm->node;
     default:
 	pm->u.str = dupstring("yes");
-	pm->flags |= PM_SCALAR;
-	return (HashNode) pm;
+	pm->node.flags |= PM_SCALAR;
+	return &pm->node;
     }
-    if ((tcstr = tgetstr(name, &u)) != NULL && tcstr != (char *)-1)
-    {
+    if ((tcstr = tgetstr(name, &u)) != NULL && tcstr != (char *)-1) {
 	pm->u.str = dupstring(tcstr);
-	pm->flags |= PM_SCALAR;
-    }
-    else
-    {
+	pm->node.flags |= PM_SCALAR;
+    } else {
 	/* zwarn("no such capability: %s", name, 0); */
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -332,37 +329,37 @@ scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags)
     pm = (Param) hcalloc(sizeof(struct param));
     u = buf;
 
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
     for (capcode = (char **)boolcodes; *capcode; capcode++) {
 	if ((num = ztgetflag(*capcode)) != -1) {
 	    pm->u.str = num ? dupstring("yes") : dupstring("no");
-	    pm->nam = dupstring(*capcode);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capcode);
+	    func(&pm->node, flags);
 	}
     }
 
-    pm->flags = PM_READONLY | PM_INTEGER;
+    pm->node.flags = PM_READONLY | PM_INTEGER;
     pm->gsu.i = &nullsetinteger_gsu;
 
     for (capcode = (char **)numcodes; *capcode; capcode++) {
 	if ((num = tgetnum(*capcode)) != -1) {
 	    pm->u.val = num;
-	    pm->nam = dupstring(*capcode);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capcode);
+	    func(&pm->node, flags);
 	}
     }
 
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
     for (capcode = (char **)strcodes; *capcode; capcode++) {
 	if ((tcstr = (char *)tgetstr(*capcode,&u)) != NULL &&
 	    tcstr != (char *)-1) {
 	    pm->u.str = dupstring(tcstr);
-	    pm->nam = dupstring(*capcode);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capcode);
+	    func(&pm->node, flags);
 	}
     }
 }
@@ -403,7 +400,7 @@ cleanup_(Module m)
 
     if ((pm = (Param) paramtab->getnode(paramtab, termcap_nam)) &&
 	pm == termcap_pm) {
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 #endif
diff --git a/Src/Modules/terminfo.c b/Src/Modules/terminfo.c
index 610df5a6d..4c8dce3ce 100644
--- a/Src/Modules/terminfo.c
+++ b/Src/Modules/terminfo.c
@@ -200,33 +200,28 @@ getterminfo(UNUSED(HashTable ht), char *name)
     unmetafy(name, &len);
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_READONLY;
 
     if (((num = tigetnum(name)) != -1) && (num != -2)) {
 	pm->u.val = num;
-	pm->flags |= PM_INTEGER;
+	pm->node.flags |= PM_INTEGER;
 	pm->gsu.i = &nullsetinteger_gsu;
-    }
-    else if ((num = tigetflag(name)) != -1) {
+    } else if ((num = tigetflag(name)) != -1) {
 	pm->u.str = num ? dupstring("yes") : dupstring("no");
-	pm->flags |= PM_SCALAR;
+	pm->node.flags |= PM_SCALAR;
 	pm->gsu.s = &nullsetscalar_gsu;
-    }
-    else if ((tistr = (char *)tigetstr(name)) != NULL && tistr != (char *)-1)
-    {
+    } else if ((tistr = (char *)tigetstr(name)) != NULL && tistr != (char *)-1) {
 	pm->u.str = dupstring(tistr);
-	pm->flags |= PM_SCALAR;
+	pm->node.flags |= PM_SCALAR;
 	pm->gsu.s = &nullsetscalar_gsu;
-    }
-    else
-    {
+    } else {
 	/* zwarn("no such capability: %s", name, 0); */
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
 	pm->gsu.s = &nullsetscalar_gsu;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -309,37 +304,37 @@ scanterminfo(UNUSED(HashTable ht), ScanFunc func, int flags)
 
     pm = (Param) hcalloc(sizeof(struct param));
 
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
     for (capname = (char **)boolnames; *capname; capname++) {
 	if ((num = tigetflag(*capname)) != -1) {
 	    pm->u.str = num ? dupstring("yes") : dupstring("no");
-	    pm->nam = dupstring(*capname);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capname);
+	    func(&pm->node, flags);
 	}
     }
 
-    pm->flags = PM_READONLY | PM_INTEGER;
+    pm->node.flags = PM_READONLY | PM_INTEGER;
     pm->gsu.i = &nullsetinteger_gsu;
 
     for (capname = (char **)numnames; *capname; capname++) {
 	if (((num = tigetnum(*capname)) != -1) && (num != -2)) {
 	    pm->u.val = num;
-	    pm->nam = dupstring(*capname);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capname);
+	    func(&pm->node, flags);
 	}
     }
 
-    pm->flags = PM_READONLY | PM_SCALAR;
+    pm->node.flags = PM_READONLY | PM_SCALAR;
     pm->gsu.s = &nullsetscalar_gsu;
 
     for (capname = (char **)strnames; *capname; capname++) {
 	if ((tistr = (char *)tigetstr(*capname)) != NULL &&
 	    tistr != (char *)-1) {
 	    pm->u.str = dupstring(tistr);
-	    pm->nam = dupstring(*capname);
-	    func((HashNode) pm, flags);
+	    pm->node.nam = dupstring(*capname);
+	    func(&pm->node, flags);
 	}
     }
 }
@@ -383,7 +378,7 @@ cleanup_(Module m)
 
     if ((pm = (Param) paramtab->getnode(paramtab, terminfo_nam)) &&
 	pm == terminfo_pm) {
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 #endif
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 96417f613..803f517c6 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -497,17 +497,17 @@ zfsetparam(char *name, void *val, int flags)
     int type = (flags & ZFPM_INTEGER) ? PM_INTEGER : PM_SCALAR;
 
     if (!(pm = (Param) paramtab->getnode(paramtab, name))
-	|| (pm->flags & PM_UNSET)) {
+	|| (pm->node.flags & PM_UNSET)) {
 	/*
 	 * just make it readonly when creating, in case user
 	 * *really* knows what they're doing
 	 */
 	if ((pm = createparam(name, type)) && (flags & ZFPM_READONLY))
-	    pm->flags |= PM_READONLY;
+	    pm->node.flags |= PM_READONLY;
     } else if (flags & ZFPM_IFUNSET) {
 	pm = NULL;
     }
-    if (!pm || PM_TYPE(pm->flags) != type) {
+    if (!pm || PM_TYPE(pm->node.flags) != type) {
 	/* parameters are funny, you just never know */
 	if (type == PM_SCALAR)
 	    zsfree((char *)val);
@@ -531,7 +531,7 @@ zfunsetparam(char *name)
     Param pm;
 
     if ((pm = (Param) paramtab->getnode(paramtab, name))) {
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 }
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 8b72abf07..1c994ef64 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -93,7 +93,7 @@ freecompctlp(HashNode hn)
 {
     Compctlp ccp = (Compctlp) hn;
 
-    zsfree(ccp->nam);
+    zsfree(ccp->node.nam);
     freecompctl(ccp->cc);
     zfree(ccp, sizeof(struct compctlp));
 }
@@ -1342,7 +1342,7 @@ compctl_process_cc(char **s, Compctl cc)
 	    if (compctl_name_pat(&n))
 		delpatcomp(n);
 	    else if ((ccp = (Compctlp) compctltab->removenode(compctltab, n)))
-		compctltab->freenode((HashNode) ccp);
+		compctltab->freenode(&ccp->node);
 	}
     } else {
 	/* Add the compctl just read to the hash table */
@@ -1570,7 +1570,7 @@ printcompctlp(HashNode hn, int printflags)
     Compctlp ccp = (Compctlp) hn;
 
     /* Function needed for use by scanhashtable() */
-    printcompctl(ccp->nam, ccp->cc, printflags, 0);
+    printcompctl(ccp->node.nam, ccp->cc, printflags, 0);
 }
 
 /* Main entry point for the `compctl' builtin */
@@ -1979,7 +1979,7 @@ addmatch(char *s, char *t)
 	isfile = CMF_FILE;
     } else if (addwhat == CC_QUOTEFLAG || addwhat == -2  ||
 	      (addwhat == -3 && !(hn->flags & DISABLED)) ||
-	      (addwhat == -4 && (PM_TYPE(pm->flags) == PM_SCALAR) &&
+	      (addwhat == -4 && (PM_TYPE(pm->node.flags) == PM_SCALAR) &&
 	       !pm->level && (tt = pm->gsu.s->getfn(pm)) && *tt == '/') ||
 	      (addwhat == -9 && !(hn->flags & PM_UNSET) && !pm->level) ||
 	      (addwhat > 0 &&
@@ -2255,9 +2255,9 @@ gen_matches_files(int dirs, int execs, int all)
 static LinkNode
 findnode(LinkList list, void *dat)
 {
-    LinkNode tmp = list->first;
+    LinkNode tmp = firstnode(list);
 
-    while (tmp && tmp->dat != dat) tmp = tmp->next;
+    while (tmp && getdata(tmp) != dat) incnode(tmp);
 
     return tmp;
 }
@@ -3692,7 +3692,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    if (!errflag)
 		/* And add the resulting words as matches. */
 		for (n = firstnode(foo); n; incnode(n))
-		    addmatch((char *)n->dat, NULL);
+		    addmatch(getdata(n), NULL);
 	}
 	opts[NULLGLOB] = ng;
 	we = oowe;
@@ -3720,8 +3720,8 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	while (n-- && he) {
 	    int iwords;
 	    for (iwords = he->nwords - 1; iwords >= 0; iwords--) {
-		h = he->text + he->words[iwords*2];
-		e = he->text + he->words[iwords*2+1];
+		h = he->node.nam + he->words[iwords*2];
+		e = he->node.nam + he->words[iwords*2+1];
 		hpatsav = *e;
 		*e = '\0';
 		/* We now have a word from the history, ignore it *
diff --git a/Src/Zle/compctl.h b/Src/Zle/compctl.h
index 9a8ba5692..dcfebb71b 100644
--- a/Src/Zle/compctl.h
+++ b/Src/Zle/compctl.h
@@ -1,5 +1,5 @@
 /*
- * comp.h - header file for completion
+ * compctl.h - header file for completion
  *
  * This file is part of zsh, the Z shell.
  *
@@ -37,9 +37,7 @@ typedef struct patcomp   *Patcomp;
 /* node for compctl hash table (compctltab) */
 
 struct compctlp {
-    HashNode next;		/* next in hash chain               */
-    char *nam;			/* command name                     */
-    int flags;			/* CURRENTLY UNUSED                 */
+    struct hashnode node;
     Compctl cc;			/* pointer to the compctl desc.     */
 };
 
diff --git a/Src/Zle/complete.c b/Src/Zle/complete.c
index c70c8c191..1da9c7f19 100644
--- a/Src/Zle/complete.c
+++ b/Src/Zle/complete.c
@@ -1148,7 +1148,7 @@ set_compstate(UNUSED(Param pm), HashTable ht)
 			zsfree(*((char **) cp->var));
 			*((char **) cp->var) = ztrdup(str);
 		    }
-		    (*pp)->flags &= ~PM_UNSET;
+		    (*pp)->node.flags &= ~PM_UNSET;
 
 		    break;
 		}
@@ -1229,18 +1229,18 @@ compunsetfn(Param pm, int exp)
 {
     if (exp) {
 	if (pm->u.data) {
-	    if (PM_TYPE(pm->flags) == PM_SCALAR) {
+	    if (PM_TYPE(pm->node.flags) == PM_SCALAR) {
 		zsfree(*((char **) pm->u.data));
 		*((char **) pm->u.data) = ztrdup("");
-	    } else if (PM_TYPE(pm->flags) == PM_ARRAY) {
+	    } else if (PM_TYPE(pm->node.flags) == PM_ARRAY) {
 		freearray(*((char ***) pm->u.data));
 		*((char ***) pm->u.data) = zshcalloc(sizeof(char *));
-	    } else if (PM_TYPE(pm->flags) == PM_HASHED) {
+	    } else if (PM_TYPE(pm->node.flags) == PM_HASHED) {
 		deleteparamtable(pm->u.hash);
 		pm->u.hash = NULL;
 	    }
 	}
-    } else if (PM_TYPE(pm->flags) == PM_HASHED) {
+    } else if (PM_TYPE(pm->node.flags) == PM_HASHED) {
 	Param *p;
 	int i;
 
@@ -1272,9 +1272,9 @@ comp_setunset(int rset, int runset, int kset, int kunset)
 	for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
 	    if (*p) {
 		if (rset & 1)
-		    (*p)->flags &= ~PM_UNSET;
+		    (*p)->node.flags &= ~PM_UNSET;
 		if (runset & 1)
-		    (*p)->flags |= PM_UNSET;
+		    (*p)->node.flags |= PM_UNSET;
 	    }
 	}
     }
@@ -1282,9 +1282,9 @@ comp_setunset(int rset, int runset, int kset, int kunset)
 	for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) {
 	    if (*p) {
 		if (kset & 1)
-		    (*p)->flags &= ~PM_UNSET;
+		    (*p)->node.flags &= ~PM_UNSET;
 		if (kunset & 1)
-		    (*p)->flags |= PM_UNSET;
+		    (*p)->node.flags |= PM_UNSET;
 	    }
 	}
     }
@@ -1306,10 +1306,10 @@ comp_wrapper(Eprog prog, FuncWrap w, char *name)
 	m = CP_WORDS | CP_REDIRS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
 	    CP_IPREFIX | CP_ISUFFIX | CP_QIPREFIX | CP_QISUFFIX;
 	for (pp = comprpms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
-	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
+	    if ((m & 1) && ((*pp)->node.flags & PM_UNSET))
 		runset |= sm;
 	}
-	if (compkpms[CPN_RESTORE]->flags & PM_UNSET)
+	if (compkpms[CPN_RESTORE]->node.flags & PM_UNSET)
 	    kunset = CP_RESTORE;
 	orest = comprestore;
 	comprestore = ztrdup("auto");
diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c
index 4c31dab1b..2aa382cb5 100644
--- a/Src/Zle/compresult.c
+++ b/Src/Zle/compresult.c
@@ -1062,7 +1062,7 @@ do_single(Cmatch m)
 			    n = p + 1;
 
 			if ((pm = (Param) paramtab->getnode(paramtab, n)) &&
-			    PM_TYPE(pm->flags) != PM_SCALAR)
+			    PM_TYPE(pm->node.flags) != PM_SCALAR)
 			    tryit = 0;
 		    }
 		    if (tryit) {
diff --git a/Src/Zle/computil.c b/Src/Zle/computil.c
index 6bc02e36d..af813a376 100644
--- a/Src/Zle/computil.c
+++ b/Src/Zle/computil.c
@@ -3371,7 +3371,7 @@ bin_compquote(char *nam, char **args, Options ops, UNUSED(int func))
 	name = dupstring(name);
 	queue_signals();
 	if ((v = getvalue(&vbuf, &name, 0))) {
-	    switch (PM_TYPE(v->pm->flags)) {
+	    switch (PM_TYPE(v->pm->node.flags)) {
 	    case PM_SCALAR:
 		setstrvalue(v, ztrdup(comp_quote(getstrvalue(v), 
 						 OPT_ISSET(ops,'p'))));
diff --git a/Src/Zle/zle_hist.c b/Src/Zle/zle_hist.c
index af4529489..da8f9244e 100644
--- a/Src/Zle/zle_hist.c
+++ b/Src/Zle/zle_hist.c
@@ -84,7 +84,7 @@ zletext(Histent ent, struct zle_text *zt)
 	return;
     }
 
-    duptext = ztrdup(ent->text);
+    duptext = ztrdup(ent->node.nam);
     zt->text = stringaszleline(duptext, 0, &zt->len, NULL, NULL);
     zsfree(duptext);
     zt->alloced = 1;
@@ -318,7 +318,7 @@ acceptlineanddownhistory(UNUSED(char **args))
     Histent he = quietgethist(histline);
 
     if (he && (he = movehistent(he, 1, HIST_FOREIGN))) {
-	zpushnode(bufstack, ztrdup(he->text));
+	zpushnode(bufstack, ztrdup(he->node.nam));
 	stackhist = he->histnum;
     }
     done = 1;
@@ -375,7 +375,7 @@ historysearchbackward(char **args)
 	return 1;
     }
     while ((he = movehistent(he, -1, hist_skip_flags))) {
-	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
+	if (isset(HISTFINDNODUPS) && he->node.flags & HIST_DUP)
 	    continue;
 	zletext(he, &zt);
 	if (zlinecmp(zt.text, zt.len, str, hp) < 0 &&
@@ -434,7 +434,7 @@ historysearchforward(char **args)
 	return 1;
     }
     while ((he = movehistent(he, 1, hist_skip_flags))) {
-	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
+	if (isset(HISTFINDNODUPS) && he->node.flags & HIST_DUP)
 	    continue;
 	zletext(he, &zt);
 	if (zlinecmp(zt.text, zt.len, str, hp) < (he->histnum == curhist) &&
@@ -627,8 +627,8 @@ insertlastword(char **args)
 	s = (char *)getdata(node);
 	t = s + strlen(s);
     } else {
-	s = he->text + he->words[2*n-2];
-	t = he->text + he->words[2*n-1];
+	s = he->node.nam + he->words[2*n-2];
+	t = he->node.nam + he->words[2*n-1];
     }
 
     save = *t;
@@ -672,7 +672,7 @@ zle_setline(Histent he)
 	if ((zlecs = zlell) && invicmdmode())
 	    zlecs--;
     } else {
-	setline(he->text, ZSL_COPY|ZSL_TOEND);
+	setline(he->node.nam, ZSL_COPY|ZSL_TOEND);
     }
     setlastline();
     clearlist = 1;
@@ -985,7 +985,7 @@ doisearch(char **args, int dir)
 		zletextfree(&zt);
 		zletext(he, &zt);
 		pos = (dir == 1) ? 0 : zt.len;
-		skip_line = isset(HISTFINDNODUPS) ? !!(he->flags & HIST_DUP)
+		skip_line = isset(HISTFINDNODUPS) ? !!(he->node.flags & HIST_DUP)
 		    : (zt.len == last_len &&
 		       !ZS_memcmp(zt.text, last_line, zt.len));
 	    }
@@ -1186,7 +1186,7 @@ acceptandinfernexthistory(char **args)
 
     if (!(he = infernexthist(hist_ring, args)))
 	return 1;
-    zpushnode(bufstack, ztrdup(he->text));
+    zpushnode(bufstack, ztrdup(he->node.nam));
     done = 1;
     stackhist = he->histnum;
     return 0;
@@ -1397,7 +1397,7 @@ virepeatsearch(UNUSED(char **args))
     if (!(he = quietgethist(histline)))
 	return 1;
     while ((he = movehistent(he, visrchsense, hist_skip_flags))) {
-	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
+	if (isset(HISTFINDNODUPS) && he->node.flags & HIST_DUP)
 	    continue;
 	zletext(he, &zt);
 	if (zlinecmp(zt.text, zt.len, zleline, zlell) &&
@@ -1452,7 +1452,7 @@ historybeginningsearchbackward(char **args)
     if (!(he = quietgethist(histline)))
 	return 1;
     while ((he = movehistent(he, -1, hist_skip_flags))) {
-	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
+	if (isset(HISTFINDNODUPS) && he->node.flags & HIST_DUP)
 	    continue;
 	zletext(he, &zt);
 	if (zlinecmp(zt.text, zt.len, zleline, zlecs) < 0 &&
@@ -1491,7 +1491,7 @@ historybeginningsearchforward(char **args)
     if (!(he = quietgethist(histline)))
 	return 1;
     while ((he = movehistent(he, 1, hist_skip_flags))) {
-	if (isset(HISTFINDNODUPS) && he->flags & HIST_DUP)
+	if (isset(HISTFINDNODUPS) && he->node.flags & HIST_DUP)
 	    continue;
 	zletext(he, &zt);
 	if (zlinecmp(zt.text, zt.len, zleline, zlecs) <
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index a4ea10339..f21dea9cc 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -1129,7 +1129,7 @@ execzlefunc(Thingy func, char **args)
 	    makezleparams(0);
 	    sfcontext = SFC_WIDGET;
 	    opts[XTRACE] = 0;
-	    ret = doshfunc(w->u.fnnam, prog, largs, shf->flags, 1);
+	    ret = doshfunc(w->u.fnnam, prog, largs, shf->node.flags, 1);
 	    opts[XTRACE] = oxt;
 	    sfcontext = osc;
 	    endparamscope();
@@ -1384,7 +1384,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
     }
     queue_signals();
     pm = (Param) paramtab->getnode(paramtab, args[0]);
-    if (pm && (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED))) {
+    if (pm && (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED))) {
 	char **a;
 
 	/*
@@ -1393,7 +1393,7 @@ bin_vared(char *name, char **args, Options ops, UNUSED(int func))
 	 */
 	a = spacesplit(t, 1, 0, 1);
 	zsfree(t);
-	if (PM_TYPE(pm->flags) == PM_ARRAY)
+	if (PM_TYPE(pm->node.flags) == PM_ARRAY)
 	    setaparam(args[0], a);
 	else
 	    sethparam(args[0], a);
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index 145836442..f2fc153f6 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -156,7 +156,7 @@ makezleparams(int ro)
 		break;
 	}
 	if ((zp->type & PM_UNSET) && (zmod.flags & MOD_MULT))
-	    pm->flags &= ~PM_UNSET;
+	    pm->node.flags &= ~PM_UNSET;
     }
 }
 
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 09cbb0a92..ee4bfbb7f 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -1305,7 +1305,7 @@ get_comp_string(void)
 	    s = NULL;
 	    inwhat = IN_MATH;
 	    if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
-		(keypm->flags & PM_HASHED))
+		(keypm->node.flags & PM_HASHED))
 		insubscr = 2;
 	    else
 		insubscr = 1;
@@ -1381,7 +1381,7 @@ get_comp_string(void)
 		varname = ztrdup(nb);
 		*ne = sav;
 		if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
-		    (keypm->flags & PM_HASHED))
+		    (keypm->node.flags & PM_HASHED))
 		    insubscr = 2;
 	    }
 	}
@@ -1436,7 +1436,7 @@ get_comp_string(void)
 	    varname = ztrdup(zlemetaline + i + 1);
 	    zlemetaline[wb - 1] = sav;
 	    if ((keypm = (Param) paramtab->getnode(paramtab, varname)) &&
-		(keypm->flags & PM_HASHED)) {
+		(keypm->node.flags & PM_HASHED)) {
 		if (insubscr != 3)
 		    insubscr = 2;
 	    } else
diff --git a/Src/Zle/zleparameter.c b/Src/Zle/zleparameter.c
index bf6b60479..e2e8186f2 100644
--- a/Src/Zle/zleparameter.c
+++ b/Src/Zle/zleparameter.c
@@ -99,8 +99,8 @@ getpmwidgets(UNUSED(HashTable ht), char *name)
     Thingy th;
 
     pm = (Param) hcalloc(sizeof(struct param));
-    pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->node.nam = dupstring(name);
+    pm->node.flags = PM_SCALAR | PM_READONLY;
     pm->gsu.s = &nullsetscalar_gsu;
 
     if ((th = (Thingy) thingytab->getnode(thingytab, name)) &&
@@ -108,9 +108,9 @@ getpmwidgets(UNUSED(HashTable ht), char *name)
 	pm->u.str = widgetstr(th->widget);
     else {
 	pm->u.str = dupstring("");
-	pm->flags |= PM_UNSET;
+	pm->node.flags |= PM_UNSET;
     }
-    return (HashNode) pm;
+    return &pm->node;
 }
 
 /**/
@@ -122,17 +122,17 @@ scanpmwidgets(UNUSED(HashTable ht), ScanFunc func, int flags)
     HashNode hn;
 
     memset((void *)&pm, 0, sizeof(struct param));
-    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.node.flags = PM_SCALAR | PM_READONLY;
     pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < thingytab->hsize; i++)
 	for (hn = thingytab->nodes[i]; hn; hn = hn->next) {
-	    pm.nam = hn->nam;
+	    pm.node.nam = hn->nam;
 	    if (func != scancountparams &&
 		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		 !(flags & SCANPM_WANTKEYS)))
 		pm.u.str = widgetstr(((Thingy) hn)->widget);
-	    func((HashNode) &pm, flags);
+	    func(&pm.node, flags);
 	}
 }
 
@@ -207,7 +207,7 @@ boot_(UNUSED(Module m))
 	    if (!(def->pm = createspecialhash(def->name, def->getnfn,
 					      def->scantfn)))
 		return 1;
-	    def->pm->flags |= def->flags;
+	    def->pm->node.flags |= def->flags;
 	    if (def->hash_gsu)
 		def->pm->gsu.h = def->hash_gsu;
 	} else {
@@ -229,7 +229,7 @@ cleanup_(UNUSED(Module m))
     for (def = partab; def->name; def++) {
 	if ((pm = (Param) paramtab->getnode(paramtab, def->name)) &&
 	    pm == def->pm) {
-	    pm->flags &= ~PM_READONLY;
+	    pm->node.flags &= ~PM_READONLY;
 	    unsetparam_pm(pm, 0, 1);
 	}
     }
diff --git a/Src/builtin.c b/Src/builtin.c
index 1345b3006..cff2ebe46 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -175,22 +175,22 @@ printbuiltinnode(HashNode hn, int printflags)
     Builtin bn = (Builtin) hn;
 
     if (printflags & PRINT_WHENCE_WORD) {
-	printf("%s: builtin\n", bn->nam);
+	printf("%s: builtin\n", bn->node.nam);
 	return;
     }
 
     if (printflags & PRINT_WHENCE_CSH) {
-	printf("%s: shell built-in command\n", bn->nam);
+	printf("%s: shell built-in command\n", bn->node.nam);
 	return;
     }
 
     if (printflags & PRINT_WHENCE_VERBOSE) {
-	printf("%s is a shell builtin\n", bn->nam);
+	printf("%s is a shell builtin\n", bn->node.nam);
 	return;
     }
 
     /* default is name only */
-    printf("%s\n", bn->nam);
+    printf("%s\n", bn->node.nam);
 }
 
 /**/
@@ -199,8 +199,8 @@ freebuiltinnode(HashNode hn)
 {
     Builtin bn = (Builtin) hn;
  
-    if(!(bn->flags & BINF_ADDED)) {
-	zsfree(bn->nam);
+    if(!(bn->node.flags & BINF_ADDED)) {
+	zsfree(bn->node.nam);
 	zsfree(bn->optstr);
 	zfree(bn, sizeof(struct builtin));
     }
@@ -251,11 +251,11 @@ execbuiltin(LinkList args, Builtin bn)
 
     if (!bn->handlerfunc) {
 	zwarnnam(name, "autoload failed", NULL, 0);
-	deletebuiltin(bn->nam);
+	deletebuiltin(bn->node.nam);
 	return 1;
     }
     /* get some information about the command */
-    flags = bn->flags;
+    flags = bn->node.flags;
     optstr = bn->optstr;
 
     /* Set up the argument list. */
@@ -735,14 +735,14 @@ set_pwd_env(void)
     /* update the PWD and OLDPWD shell parameters */
 
     pm = (Param) paramtab->getnode(paramtab, "PWD");
-    if (pm && PM_TYPE(pm->flags) != PM_SCALAR) {
-	pm->flags &= ~PM_READONLY;
+    if (pm && PM_TYPE(pm->node.flags) != PM_SCALAR) {
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 
     pm = (Param) paramtab->getnode(paramtab, "OLDPWD");
-    if (pm && PM_TYPE(pm->flags) != PM_SCALAR) {
-	pm->flags &= ~PM_READONLY;
+    if (pm && PM_TYPE(pm->node.flags) != PM_SCALAR) {
+	pm->node.flags &= ~PM_READONLY;
 	unsetparam_pm(pm, 0, 1);
     }
 
@@ -750,10 +750,10 @@ set_pwd_env(void)
     setsparam("OLDPWD", ztrdup(oldpwd));
 
     pm = (Param) paramtab->getnode(paramtab, "PWD");
-    if (!(pm->flags & PM_EXPORTED))
+    if (!(pm->node.flags & PM_EXPORTED))
 	addenv(pm, pwd);
     pm = (Param) paramtab->getnode(paramtab, "OLDPWD");
-    if (!(pm->flags & PM_EXPORTED))
+    if (!(pm->node.flags & PM_EXPORTED))
 	addenv(pm, oldpwd);
 }
 
@@ -1589,7 +1589,7 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
     }
 
     for (;;) {
-	s = dupstring(ent->text);
+	s = dupstring(ent->node.nam);
 	/* this if does the pattern matching, if required */
 	if (!pprog || pattry(pprog, s)) {
 	    /* perform substitution */
@@ -1600,7 +1600,7 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
 		char buf[DIGBUFSIZE];
 		convbase(buf, ent->histnum, 10);
 		fprintf(f, "%5s%c ", buf,
-			ent->flags & HIST_FOREIGN? '*' : ' ');
+			ent->node.flags & HIST_FOREIGN ? '*' : ' ');
 	    }
 	    /* output actual time (and possibly date) of execution of the
 	       command, if required */
@@ -1799,13 +1799,13 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      * handled in createparam().  Here we just avoid using it for the
      * present tests if it's unset.
      */
-    usepm = pm && !(pm->flags & PM_UNSET);
+    usepm = pm && !(pm->node.flags & PM_UNSET);
 
     /*
      * We need to compare types with an existing pm if special,
      * even if that's unset
      */
-    if (pm && (pm->flags & PM_SPECIAL))
+    if (pm && (pm->node.flags & PM_SPECIAL))
 	usepm = 1;
 
     /*
@@ -1822,8 +1822,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 * local.  It can be applied either to the special or in the
 	 * typeset/local statement for the local variable.
 	 */
-	if ((pm->flags & PM_SPECIAL)
-	    && !(on & PM_HIDE) && !(pm->flags & PM_HIDE & ~off))
+	if ((pm->node.flags & PM_SPECIAL)
+	    && !(on & PM_HIDE) && !(pm->node.flags & PM_HIDE & ~off))
 	    newspecial = NS_NORMAL;
 	usepm = 0;
     }
@@ -1831,7 +1831,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
     /* attempting a type conversion, or making a tied colonarray? */
     tc = 0;
     if (usepm || newspecial != NS_NONE) {
-	int chflags = ((off & pm->flags) | (on & ~pm->flags)) &
+	int chflags = ((off & pm->node.flags) | (on & ~pm->node.flags)) &
 	    (PM_INTEGER|PM_EFLOAT|PM_FFLOAT|PM_HASHED|
 	     PM_ARRAY|PM_TIED|PM_AUTOLOAD);
 	/* keep the parameter if just switching between floating types */
@@ -1847,9 +1847,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      */
     if ((readonly =
 	 ((usepm || newspecial != NS_NONE) && 
-	  (off & pm->flags & PM_READONLY))) ||
+	  (off & pm->node.flags & PM_READONLY))) ||
 	tc) {
-	if (pm->flags & PM_SPECIAL) {
+	if (pm->node.flags & PM_SPECIAL) {
 	    int err = 1;
 	    if (!readonly && !strcmp(pname, "SECONDS"))
 	    {
@@ -1889,7 +1889,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 			pname, 0);
 		return NULL;
 	    }
-	} else if (pm->flags & PM_AUTOLOAD) {
+	} else if (pm->node.flags & PM_AUTOLOAD) {
 	    zerrnam(cname, "%s: can't change type of autoloaded parameter",
 		    pname, 0);
 	    return NULL;
@@ -1911,37 +1911,37 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	on &= ~PM_LOCAL;
 	if (!on && !roff && !value) {
 	    if (OPT_ISSET(ops,'p'))
-		paramtab->printnode((HashNode)pm, PRINT_TYPESET);
+		paramtab->printnode(&pm->node, PRINT_TYPESET);
 	    else if (unset(TYPESETSILENT) || OPT_ISSET(ops,'m'))
-		paramtab->printnode((HashNode)pm, PRINT_INCLUDEVALUE);
+		paramtab->printnode(&pm->node, PRINT_INCLUDEVALUE);
 	    return pm;
 	}
-	if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 	    zerrnam(cname, "%s: restricted", pname, 0);
 	    return pm;
 	}
-	if ((on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) {
+	if ((on & PM_UNIQUE) && !(pm->node.flags & PM_READONLY & ~off)) {
 	    Param apm;
 	    char **x;
-	    if (PM_TYPE(pm->flags) == PM_ARRAY) {
+	    if (PM_TYPE(pm->node.flags) == PM_ARRAY) {
 		x = (*pm->gsu.a->getfn)(pm);
 		uniqarray(x);
-		if (pm->flags & PM_SPECIAL) {
+		if (pm->node.flags & PM_SPECIAL) {
 		    if (zheapptr(x))
 			x = zarrdup(x);
 		    (*pm->gsu.a->setfn)(pm, x);
 		} else if (pm->ename && x)
 		    arrfixenv(pm->ename, x);
-	    } else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
+	    } else if (PM_TYPE(pm->node.flags) == PM_SCALAR && pm->ename &&
 		       (apm =
 			(Param) paramtab->getnode(paramtab, pm->ename))) {
 		x = (*apm->gsu.a->getfn)(apm);
 		uniqarray(x);
 		if (x)
-		    arrfixenv(pm->nam, x);
+		    arrfixenv(pm->node.nam, x);
 	    }
 	}
-	pm->flags = (pm->flags | (on & ~PM_READONLY)) & ~(off | PM_UNSET);
+	pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~(off | PM_UNSET);
 	if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
 	    if (typeset_setwidth(cname, pm, ops, on, 0))
 		return NULL;
@@ -1950,11 +1950,11 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    if (typeset_setbase(cname, pm, ops, on, 0))
 		return NULL;
 	}
-	if (!(pm->flags & (PM_ARRAY|PM_HASHED))) {
-	    if (pm->flags & PM_EXPORTED) {
-		if (!(pm->flags & PM_UNSET) && !pm->env && !value)
+	if (!(pm->node.flags & (PM_ARRAY|PM_HASHED))) {
+	    if (pm->node.flags & PM_EXPORTED) {
+		if (!(pm->node.flags & PM_UNSET) && !pm->env && !value)
 		    addenv(pm, getsparam(pname));
-	    } else if (pm->env && !(pm->flags & PM_HASHELEM))
+	    } else if (pm->env && !(pm->node.flags & PM_HASHELEM))
 		delenv(pm);
 	    if (value && !(pm = setsparam(pname, ztrdup(value))))
 		return NULL;
@@ -1962,9 +1962,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    zwarnnam(cname, "can't assign new value for array %s", pname, 0);
 	    return NULL;
 	}
-	pm->flags |= (on & PM_READONLY);
+	pm->node.flags |= (on & PM_READONLY);
 	if (OPT_ISSET(ops,'p'))
-	    paramtab->printnode((HashNode)pm, PRINT_TYPESET);
+	    paramtab->printnode(&pm->node, PRINT_TYPESET);
 	return pm;
     }
 
@@ -1976,9 +1976,9 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      */
     if (tc) {
 	/* Maintain existing readonly/exported status... */
-	on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->flags;
+	on |= ~off & (PM_READONLY|PM_EXPORTED) & pm->node.flags;
 	/* ...but turn off existing readonly so we can delete it */
-	pm->flags &= ~PM_READONLY;
+	pm->node.flags &= ~PM_READONLY;
 	/*
 	 * If we're just changing the type, we should keep the
 	 * variable at the current level of localness.
@@ -1988,7 +1988,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 * Try to carry over a value, but not when changing from,
 	 * to, or between non-scalar types.
 	 */
-	if (!value && !((pm->flags|on) & (PM_ARRAY|PM_HASHED)))
+	if (!value && !((pm->node.flags|on) & (PM_ARRAY|PM_HASHED)))
 	    value = dupstring(getsparam(pname));
 	/* pname may point to pm->nam which is about to disappear */
 	pname = dupstring(pname);
@@ -1997,7 +1997,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 
     if (newspecial != NS_NONE) {
 	Param tpm, pm2;
-	if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 	    zerrnam(cname, "%s: restricted", pname, 0);
 	    return pm;
 	}
@@ -2008,7 +2008,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 */
 	tpm = (Param) zshcalloc(sizeof *tpm);
 
-	tpm->nam = pm->nam;
+	tpm->node.nam = pm->node.nam;
 	if (pm->ename &&
 	    (pm2 = (Param) paramtab->getnode(paramtab, pm->ename)) &&
 	    pm2->level == locallevel) {
@@ -2023,7 +2023,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	     * of the environment entry in tpm->env, rather than relying
 	     * on the restored value to provide it.
 	     */
-	    tpm->flags = pm->flags | PM_NORESTORE;
+	    tpm->node.flags = pm->node.flags | PM_NORESTORE;
 	} else {
 	    copyparam(tpm, pm, 1);
 	}
@@ -2040,7 +2040,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 * The remaining on/off flags should be harmless to use,
 	 * because we've checked for unpleasant surprises above.
 	 */
-	pm->flags = (PM_TYPE(pm->flags) | on | PM_SPECIAL) & ~off;
+	pm->node.flags = (PM_TYPE(pm->node.flags) | on | PM_SPECIAL) & ~off;
 	if (newspecial == NS_SECONDS) {
 	    /* We save off the raw internal value of the SECONDS var */
 	    tpm->u.dval = getrawseconds();
@@ -2087,7 +2087,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 		return NULL;
 	    value = NULL;
 	    keeplocal = 0;
-	    on = pm->flags;
+	    on = pm->node.flags;
 	} else {
 	    zerrnam(cname,
 		    "%s: array elements must be scalar", pname, 0);
@@ -2116,7 +2116,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	return NULL;
     }
 
-    if (altpm && PM_TYPE(pm->flags) == PM_SCALAR) {
+    if (altpm && PM_TYPE(pm->node.flags) == PM_SCALAR) {
 	/*
 	 * It seems safer to set this here than in createparam(),
 	 * to make sure we only ever use the colonarr functions
@@ -2137,7 +2137,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	pm->level = keeplocal;
     else if (on & PM_LOCAL)
 	pm->level = locallevel;
-    if (value && !(pm->flags & (PM_ARRAY|PM_HASHED))) {
+    if (value && !(pm->node.flags & (PM_ARRAY|PM_HASHED))) {
 	Param ipm = pm;
 	if (!(pm = setsparam(pname, ztrdup(value))))
 	    return NULL;
@@ -2146,12 +2146,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 		  "BUG: parameter recreated with wrong flags");
 	    unsetparam_pm(ipm, 0, 1);
 	}
-    } else if (newspecial != NS_NONE && !(pm->old->flags & PM_NORESTORE)) {
+    } else if (newspecial != NS_NONE && !(pm->old->node.flags & PM_NORESTORE)) {
 	/*
 	 * We need to use the special setting function to re-initialise
 	 * the special parameter to empty.
 	 */
-	switch (PM_TYPE(pm->flags)) {
+	switch (PM_TYPE(pm->node.flags)) {
 	case PM_SCALAR:
 	    pm->gsu.s->setfn(pm, ztrdup(""));
 	    break;
@@ -2166,12 +2166,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    pm->gsu.a->setfn(pm, mkarray(NULL));
 	    break;
 	case PM_HASHED:
-	    pm->gsu.h->setfn(pm, newparamtable(17, pm->nam));
+	    pm->gsu.h->setfn(pm, newparamtable(17, pm->node.nam));
 	    break;
 	}
     }
-    pm->flags |= (on & PM_READONLY);
-    if (value && (pm->flags & (PM_ARRAY|PM_HASHED))) {
+    pm->node.flags |= (on & PM_READONLY);
+    if (value && (pm->node.flags & (PM_ARRAY|PM_HASHED))) {
 	zerrnam(cname, "%s: can't assign initial value for array", pname, 0);
 	/* the only safe thing to do here seems to be unset the param */
 	unsetparam_pm(pm, 0, 1);
@@ -2179,7 +2179,7 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
     }
 
     if (OPT_ISSET(ops,'p'))
-	paramtab->printnode((HashNode)pm, PRINT_TYPESET);
+	paramtab->printnode(&pm->node, PRINT_TYPESET);
 
     return pm;
 }
@@ -2326,11 +2326,11 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	 * exported and pass that along.  Isn't the world complicated?
 	 */
 	if ((pm = (Param) paramtab->getnode(paramtab, asg0.name))
-	    && !(pm->flags & PM_UNSET)
+	    && !(pm->node.flags & PM_UNSET)
 	    && (locallevel == pm->level || !(on & PM_LOCAL))) {
-	    if (!asg0.value && !(PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)))
+	    if (!asg0.value && !(PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)))
 		oldval = ztrdup(getsparam(asg0.name));
-	    on |= (pm->flags & PM_EXPORTED);
+	    on |= (pm->node.flags & PM_EXPORTED);
 	}
 	/*
 	 * Create the tied array; this is normal except that
@@ -2417,17 +2417,17 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 	     */
 	    for (i = 0; i < paramtab->hsize; i++) {
 		for (pm = (Param) paramtab->nodes[i]; pm;
-		     pm = (Param) pm->next) {
-		    if (((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
-			(pm->flags & PM_UNSET))
+		     pm = (Param) pm->node.next) {
+		    if (((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) ||
+			(pm->node.flags & PM_UNSET))
 			continue;
-		    if (pattry(pprog, pm->nam))
+		    if (pattry(pprog, pm->node.nam))
 			addlinknode(pmlist, pm);
 		}
 	    }
 	    for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) {
 		pm = (Param) getdata(pmnode);
-		if (!typeset_single(name, pm->nam, pm, func, on, off, roff,
+		if (!typeset_single(name, pm->node.nam, pm, func, on, off, roff,
 				    asg->value, NULL, ops, 0))
 		    returnval = 1;
 	    }
@@ -2456,7 +2456,7 @@ bin_typeset(char *name, char **argv, Options ops, int func)
 int
 eval_autoload(Shfunc shf, char *name, Options ops, int func)
 {
-    if (!(shf->flags & PM_UNDEFINED))
+    if (!(shf->node.flags & PM_UNDEFINED))
 	return 1;
 
     if (shf->funcdef) {
@@ -2537,7 +2537,7 @@ bin_functions(char *name, char **argv, Options ops, int func)
 		shf = (Shfunc) zshcalloc(sizeof *shf);
 		shfunctab->addnode(shfunctab, ztrdup(scriptname), shf);
 	    }
-	    shf->flags = on;
+	    shf->node.flags = on;
 	    ret = eval_autoload(shf, scriptname, ops, func);
 	} else {
 	    if (OPT_ISSET(ops,'U') && !OPT_ISSET(ops,'u'))
@@ -2565,13 +2565,13 @@ bin_functions(char *name, char **argv, Options ops, int func)
 		    /* apply the options to all functions matching the glob pattern */
 		    for (i = 0; i < shfunctab->hsize; i++) {
 			for (shf = (Shfunc) shfunctab->nodes[i]; shf;
-			     shf = (Shfunc) shf->next)
-			    if (pattry(pprog, shf->nam) &&
-				!(shf->flags & DISABLED)) {
-				shf->flags = (shf->flags |
+			     shf = (Shfunc) shf->node.next)
+			    if (pattry(pprog, shf->node.nam) &&
+				!(shf->node.flags & DISABLED)) {
+				shf->node.flags = (shf->node.flags |
 					      (on & ~PM_UNDEFINED)) & ~off;
 				if (OPT_ISSET(ops,'X') &&
-				    eval_autoload(shf, shf->nam, ops, func)) {
+				    eval_autoload(shf, shf->node.nam, ops, func)) {
 				    returnval = 1;
 				}
 			    }
@@ -2596,13 +2596,13 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    /* if any flag was given */
 	    if (on|off) {
 		/* turn on/off the given flags */
-		shf->flags = (shf->flags | (on & ~PM_UNDEFINED)) & ~off;
+		shf->node.flags = (shf->node.flags | (on & ~PM_UNDEFINED)) & ~off;
 		if (OPT_ISSET(ops,'X') && 
-		    eval_autoload(shf, shf->nam, ops, func))
+		    eval_autoload(shf, shf->node.nam, ops, func))
 		    returnval = 1;
 	    } else
 		/* no flags, so just print */
-		shfunctab->printnode((HashNode) shf, pflags);
+		shfunctab->printnode(&shf->node, pflags);
 	} else if (on & PM_UNDEFINED) {
 	    int signum = -1, ok = 1;
 
@@ -2618,21 +2618,21 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    /* Add a new undefined (autoloaded) function to the *
 	     * hash table with the corresponding flags set.     */
 	    shf = (Shfunc) zshcalloc(sizeof *shf);
-	    shf->flags = on;
+	    shf->node.flags = on;
 	    shf->funcdef = mkautofn(shf);
 	    shfunctab->addnode(shfunctab, ztrdup(*argv), shf);
 
 	    if (signum != -1) {
 		if (settrap(signum, NULL, ZSIG_FUNC)) {
 		    shfunctab->removenode(shfunctab, *argv);
-		    shfunctab->freenode((HashNode)shf);
+		    shfunctab->freenode(&shf->node);
 		    returnval = 1;
 		    ok = 0;
 		}
 	    }
 
 	    if (ok && OPT_ISSET(ops,'X') &&
-		eval_autoload(shf, shf->nam, ops, func))
+		eval_autoload(shf, shf->node.nam, ops, func))
 		returnval = 1;
 	} else
 	    returnval = 1;
@@ -2694,10 +2694,10 @@ bin_unset(char *name, char **argv, Options ops, int func)
 		for (i = 0; i < paramtab->hsize; i++) {
 		    for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
 			/* record pointer to next, since we may free this one */
-			next = (Param) pm->next;
-			if ((!(pm->flags & PM_RESTRICTED) ||
+			next = (Param) pm->node.next;
+			if ((!(pm->node.flags & PM_RESTRICTED) ||
 			     unset(RESTRICTED)) &&
-			    pattry(pprog, pm->nam)) {
+			    pattry(pprog, pm->node.nam)) {
 			    unsetparam_pm(pm, 0, 1);
 			    match++;
 			}
@@ -2738,11 +2738,11 @@ bin_unset(char *name, char **argv, Options ops, int func)
 	 */
 	if (!pm)
 	    continue;
-	else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
-	    zerrnam(name, "%s: restricted", pm->nam, 0);
+	else if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	    zerrnam(name, "%s: restricted", pm->node.nam, 0);
 	    returnval = 1;
 	} else if (ss) {
-	    if (PM_TYPE(pm->flags) == PM_HASHED) {
+	    if (PM_TYPE(pm->node.flags) == PM_HASHED) {
 		HashTable tht = paramtab;
 		if ((paramtab = pm->gsu.h->getfn(pm))) {
 		    *--sse = 0;
@@ -3047,11 +3047,11 @@ bin_hash(char *name, char **argv, Options ops, UNUSED(int func))
 		 * so define an entry for the table.    */
 		if(OPT_ISSET(ops,'d')) {
 		    Nameddir nd = hn = zshcalloc(sizeof *nd);
-		    nd->flags = 0;
+		    nd->node.flags = 0;
 		    nd->dir = ztrdup(asg->value);
 		} else {
 		    Cmdnam cn = hn = zshcalloc(sizeof *cn);
-		    cn->flags = HASHED;
+		    cn->node.flags = HASHED;
 		    cn->u.cmd = ztrdup(asg->value);
 		}
 		ht->addnode(ht, ztrdup(asg->name), hn);
@@ -3241,9 +3241,9 @@ bin_alias(char *name, char **argv, Options ops, UNUSED(int func))
 	    /* display alias if appropriate */
 	    if (!type_opts || ht == sufaliastab ||
 		(OPT_ISSET(ops,'r') && 
-		 !(a->flags & (ALIAS_GLOBAL|ALIAS_SUFFIX))) ||
-		(OPT_ISSET(ops,'g') && (a->flags & ALIAS_GLOBAL)))
-		ht->printnode((HashNode) a, printflags);
+		 !(a->node.flags & (ALIAS_GLOBAL|ALIAS_SUFFIX))) ||
+		(OPT_ISSET(ops,'g') && (a->node.flags & ALIAS_GLOBAL)))
+		ht->printnode(&a->node, printflags);
 	} else
 	    returnval = 1;
     }
@@ -3385,8 +3385,8 @@ bin_print(char *name, char **args, Options ops, int func)
 	    d = finddir(args[n]);
 	    if(d) {
 		int dirlen = strlen(d->dir);
-		char *arg = zhalloc(len[n] - dirlen + strlen(d->nam) + 2);
-		sprintf(arg, "~%s%s", d->nam, args[n] + dirlen);
+		char *arg = zhalloc(len[n] - dirlen + strlen(d->node.nam) + 2);
+		sprintf(arg, "~%s%s", d->node.nam, args[n] + dirlen);
 		args[n] = arg;
 		len[n] = strlen(args[n]);
 	    }
@@ -3579,10 +3579,10 @@ bin_print(char *name, char **args, Options ops, int func)
 		}
 	    } else
 		ent->words = (short *)NULL;
-	    ent->text = zjoin(args, ' ', 0);
+	    ent->node.nam = zjoin(args, ' ', 0);
 	    ent->stim = ent->ftim = time(NULL);
-	    ent->flags = 0;
-	    addhistnode(histtab, ent->text, ent);
+	    ent->node.flags = 0;
+	    addhistnode(histtab, ent->node.nam, ent);
 	    unqueue_signals();
 	    return 0;
 	}
@@ -3901,11 +3901,11 @@ bin_print(char *name, char **args, Options ops, int func)
 	    zpushnode(bufstack, buf);
 	} else {
 	    ent = prepnexthistent();
-	    ent->text = buf;
+	    ent->node.nam = buf;
 	    ent->stim = ent->ftim = time(NULL);
-	    ent->flags = 0;
+	    ent->node.flags = 0;
 	    ent->words = (short *)NULL;
-	    addhistnode(histtab, ent->text, ent);
+	    addhistnode(histtab, ent->node.nam, ent);
 	}
 	unqueue_signals();
     }
diff --git a/Src/exec.c b/Src/exec.c
index 6c68c5c7d..bb0e4161e 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -570,7 +570,7 @@ execute(UNUSED(Cmdnam cmdname), int dash, int defpath)
 	if ((cn = (Cmdnam) cmdnamtab->getnode(cmdnamtab, arg0))) {
 	    char nn[PATH_MAX], *dptr;
 
-	    if (cn->flags & HASHED)
+	    if (cn->node.flags & HASHED)
 		strcpy(nn, cn->u.cmd);
 	    else {
 		for (pp = path; pp < cn->u.name; pp++)
@@ -589,7 +589,7 @@ execute(UNUSED(Cmdnam cmdname), int dash, int defpath)
 		    }
 		strcpy(nn, cn->u.name ? *(cn->u.name) : "");
 		strcat(nn, "/");
-		strcat(nn, cn->nam);
+		strcat(nn, cn->node.nam);
 	    }
 	    ee = zexecve(nn, argv);
 
@@ -653,7 +653,7 @@ findcmd(char *arg0, int docopy)
     if (cn) {
 	char nn[PATH_MAX];
 
-	if (cn->flags & HASHED)
+	if (cn->node.flags & HASHED)
 	    strcpy(nn, cn->u.cmd);
 	else {
 	    for (pp = path; pp < cn->u.name; pp++)
@@ -668,7 +668,7 @@ findcmd(char *arg0, int docopy)
 		}
 	    strcpy(nn, cn->u.name ? *(cn->u.name) : "");
 	    strcat(nn, "/");
-	    strcat(nn, cn->nam);
+	    strcat(nn, cn->node.nam);
 	}
 	RET_IF_COM(nn);
     }
@@ -701,14 +701,14 @@ isreallycom(Cmdnam cn)
 {
     char fullnam[MAXCMDLEN];
 
-    if (cn->flags & HASHED)
+    if (cn->node.flags & HASHED)
 	strcpy(fullnam, cn->u.cmd);
     else if (!cn->u.name)
 	return 0;
     else {
 	strcpy(fullnam, *(cn->u.name));
 	strcat(fullnam, "/");
-	strcat(fullnam, cn->nam);
+	strcat(fullnam, cn->node.nam);
     }
     return iscom(fullnam);
 }
@@ -751,7 +751,7 @@ hashcmd(char *arg0, char **pp)
 	return NULL;
 
     cn = (Cmdnam) zshcalloc(sizeof *cn);
-    cn->flags = 0;
+    cn->node.flags = 0;
     cn->u.name = pp;
     cmdnamtab->addnode(cmdnamtab, ztrdup(arg0), cn);
 
@@ -1432,7 +1432,7 @@ checkclobberparam(struct redir *f)
     if (!(v = getvalue(&vbuf, &s, 0)))
 	return 1;
 
-    if (v->pm->flags & PM_READONLY) {
+    if (v->pm->node.flags & PM_READONLY) {
 	zwarn("can't allocate file descriptor to readonly parameter %s",
 	      f->varid, 0);
 	/* don't flag a system error for this */
@@ -1729,8 +1729,8 @@ addvars(Estate state, Wordcode pc, int addflags)
 	    if ((addflags & ADDVAR_EXPORT) && !strchr(name, '[')) {
 		if ((addflags & ADDVAR_RESTRICT) && isset(RESTRICTED) &&
 		    (pm = (Param) paramtab->removenode(paramtab, name)) &&
-		    (pm->flags & PM_RESTRICTED)) {
-		    zerr("%s: restricted", pm->nam, 0);
+		    (pm->node.flags & PM_RESTRICTED)) {
+		    zerr("%s: restricted", pm->node.nam, 0);
 		    zsfree(val);
 		    state->pc = opc;
 		    return;
@@ -1938,7 +1938,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 			if (nextnode(firstnode(args)))
 			    next = (char *) getdata(nextnode(firstnode(args)));
 		    } else {
-			hn = (HashNode)&commandbn;
+			hn = &commandbn.node;
 			is_builtin = 1;
 			break;
 		    }
@@ -2145,7 +2145,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 
 	    hn = cmdnamtab->getnode(cmdnamtab, cmdarg);
 	    if (hn && trycd && !isreallycom((Cmdnam)hn)) {
-		if (!(((Cmdnam)hn)->flags & HASHED)) {
+		if (!(((Cmdnam)hn)->node.flags & HASHED)) {
 		    checkpath = path;
 		    dohashcmd = 1;
 		}
@@ -2379,7 +2379,7 @@ execcmd(Estate state, int input, int output, int how, int last1)
 
 		    if (!(v = getvalue(&vbuf, &s, 0))) {
 			bad = 1;
-		    } else if (v->pm->flags & PM_READONLY) {
+		    } else if (v->pm->node.flags & PM_READONLY) {
 			bad = 2;
 		    } else {
 			fn->fd1 = (int)getintvalue(v);
@@ -2692,12 +2692,12 @@ save_params(Estate state, Wordcode pc, LinkList *restore_p, LinkList *remove_p)
 	if ((pm = (Param) paramtab->getnode(paramtab, s))) {
 	    if (pm->env)
 		delenv(pm);
-	    if (!(pm->flags & PM_SPECIAL)) {
+	    if (!(pm->node.flags & PM_SPECIAL)) {
 		paramtab->removenode(paramtab, s);
-	    } else if (!(pm->flags & PM_READONLY) &&
-		       (unset(RESTRICTED) || !(pm->flags & PM_RESTRICTED))) {
+	    } else if (!(pm->node.flags & PM_READONLY) &&
+		       (unset(RESTRICTED) || !(pm->node.flags & PM_RESTRICTED))) {
 		Param tpm = (Param) hcalloc(sizeof *tpm);
-		tpm->nam = pm->nam;
+		tpm->node.nam = pm->node.nam;
 		copyparam(tpm, pm, 1);
 		pm = tpm;
 	    }
@@ -2723,8 +2723,8 @@ restore_params(LinkList restorelist, LinkList removelist)
     /* remove temporary parameters */
     while ((s = (char *) ugetnode(removelist))) {
 	if ((pm = (Param) paramtab->getnode(paramtab, s)) &&
-	    !(pm->flags & PM_SPECIAL)) {
-	    pm->flags &= ~PM_READONLY;
+	    !(pm->node.flags & PM_SPECIAL)) {
+	    pm->node.flags &= ~PM_READONLY;
 	    unsetparam_pm(pm, 0, 0);
 	}
     }
@@ -2732,14 +2732,14 @@ restore_params(LinkList restorelist, LinkList removelist)
     if (restorelist) {
 	/* restore saved parameters */
 	while ((pm = (Param) ugetnode(restorelist))) {
-	    if (pm->flags & PM_SPECIAL) {
-		Param tpm = (Param) paramtab->getnode(paramtab, pm->nam);
+	    if (pm->node.flags & PM_SPECIAL) {
+		Param tpm = (Param) paramtab->getnode(paramtab, pm->node.nam);
 
-		DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) ||
-		      !(pm->flags & PM_SPECIAL),
+		DPUTS(!tpm || PM_TYPE(pm->node.flags) != PM_TYPE(tpm->node.flags) ||
+		      !(pm->node.flags & PM_SPECIAL),
 		      "BUG: in restoring special parameters");
-		tpm->flags = pm->flags;
-		switch (PM_TYPE(pm->flags)) {
+		tpm->node.flags = pm->node.flags;
+		switch (PM_TYPE(pm->node.flags)) {
 		case PM_SCALAR:
 		    tpm->gsu.s->setfn(tpm, pm->u.str);
 		    break;
@@ -2759,8 +2759,8 @@ restore_params(LinkList restorelist, LinkList removelist)
 		}
 		pm = tpm;
 	    } else
-		paramtab->addnode(paramtab, pm->nam, pm);
-	    if ((pm->flags & PM_EXPORTED) && ((s = getsparam(pm->nam))))
+		paramtab->addnode(paramtab, pm->node.nam, pm);
+	    if ((pm->node.flags & PM_EXPORTED) && ((s = getsparam(pm->node.nam))))
 		addenv(pm, s);
 	}
     }
@@ -3533,7 +3533,7 @@ execfuncdef(Estate state, UNUSED(int do_exec))
 
 	shf = (Shfunc) zalloc(sizeof(*shf));
 	shf->funcdef = prog;
-	shf->flags = 0;
+	shf->node.flags = 0;
 
 	/* is this shell function a signal trap? */
 	if (!strncmp(s, "TRAP", 4) &&
@@ -3596,7 +3596,7 @@ execshfunc(Shfunc shf, LinkList args)
     cmdsp = 0;
     if ((osfc = sfcontext) == SFC_NONE)
 	sfcontext = SFC_DIRECT;
-    doshfunc(shf->nam, shf->funcdef, args, shf->flags, 0);
+    doshfunc(shf->node.nam, shf->funcdef, args, shf->node.flags, 0);
     sfcontext = osfc;
     free(cmdstack);
     cmdstack = ocs;
@@ -3623,7 +3623,7 @@ execautofn(Estate state, UNUSED(int do_exec))
 	return 1;
 
     oldscriptname = scriptname;
-    scriptname = dupstring(shf->nam);
+    scriptname = dupstring(shf->node.nam);
     execode(shf->funcdef, 1, 0);
     scriptname = oldscriptname;
 
@@ -3639,21 +3639,21 @@ loadautofn(Shfunc shf, int fksh, int autol)
 
     pushheap();
 
-    noaliases = (shf->flags & PM_UNALIASED);
-    prog = getfpfunc(shf->nam, &ksh);
+    noaliases = (shf->node.flags & PM_UNALIASED);
+    prog = getfpfunc(shf->node.nam, &ksh);
     noaliases = noalias;
 
     if (ksh == 1) {
 	ksh = fksh;
 	if (ksh == 1)
-	    ksh = (shf->flags & PM_KSHSTORED) ? 2 :
-		  (shf->flags & PM_ZSHSTORED) ? 0 : 1;
+	    ksh = (shf->node.flags & PM_KSHSTORED) ? 2 :
+		  (shf->node.flags & PM_ZSHSTORED) ? 0 : 1;
     }
 
     if (prog == &dummy_eprog) {
 	/* We're not actually in the function; decrement locallevel */
 	locallevel--;
-	zwarn("%s: function definition file not found", shf->nam, 0);
+	zwarn("%s: function definition file not found", shf->node.nam, 0);
 	locallevel++;
 	popheap();
 	return NULL;
@@ -3669,13 +3669,13 @@ loadautofn(Shfunc shf, int fksh, int autol)
 		shf->funcdef = prog;
 	    else
 		shf->funcdef = dupeprog(prog, 0);
-	    shf->flags &= ~PM_UNDEFINED;
+	    shf->node.flags &= ~PM_UNDEFINED;
 	} else {
-	    VARARR(char, n, strlen(shf->nam) + 1);
-	    strcpy(n, shf->nam);
+	    VARARR(char, n, strlen(shf->node.nam) + 1);
+	    strcpy(n, shf->node.nam);
 	    execode(prog, 1, 0);
 	    shf = (Shfunc) shfunctab->getnode(shfunctab, n);
-	    if (!shf || (shf->flags & PM_UNDEFINED)) {
+	    if (!shf || (shf->node.flags & PM_UNDEFINED)) {
 		/* We're not actually in the function; decrement locallevel */
 		locallevel--;
 		zwarn("%s: function not defined by file", n, 0);
@@ -3687,10 +3687,10 @@ loadautofn(Shfunc shf, int fksh, int autol)
     } else {
 	freeeprog(shf->funcdef);
 	if (prog->flags & EF_MAP)
-	    shf->funcdef = stripkshdef(prog, shf->nam);
+	    shf->funcdef = stripkshdef(prog, shf->node.nam);
 	else
-	    shf->funcdef = dupeprog(stripkshdef(prog, shf->nam), 0);
-	shf->flags &= ~PM_UNDEFINED;
+	    shf->funcdef = dupeprog(stripkshdef(prog, shf->node.nam), 0);
+	shf->node.flags &= ~PM_UNDEFINED;
     }
     popheap();
 
@@ -3760,16 +3760,16 @@ doshfunc(char *name, Eprog prog, LinkList doshargs, int flags, int noreturnval)
     if (doshargs) {
 	LinkNode node;
 
-	node = doshargs->first;
+	node = firstnode(doshargs);
 	pparams = x = (char **) zshcalloc(((sizeof *x) *
 					 (1 + countlinknodes(doshargs))));
 	if (isset(FUNCTIONARGZERO)) {
 	    oargv0 = argzero;
-	    argzero = ztrdup((char *) node->dat);
+	    argzero = ztrdup(getdata(node));
 	}
 	node = node->next;
 	for (; node; node = node->next, x++)
-	    *x = ztrdup((char *) node->dat);
+	    *x = ztrdup(getdata(node));
     } else {
 	pparams = (char **) zshcalloc(sizeof *pparams);
 	if (isset(FUNCTIONARGZERO)) {
diff --git a/Src/hashtable.c b/Src/hashtable.c
index d24fb31cb..9a2f12c9c 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -640,7 +640,7 @@ hashdir(char **dirp)
     while ((fn = zreaddir(dir, 1))) {
 	if (!cmdnamtab->getnode(cmdnamtab, fn)) {
 	    cn = (Cmdnam) zshcalloc(sizeof *cn);
-	    cn->flags = 0;
+	    cn->node.flags = 0;
 	    cn->u.name = dirp;
 	    cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
 	}
@@ -655,7 +655,7 @@ hashdir(char **dirp)
 	    *exe = 0;
 	    if (!cmdnamtab->getnode(cmdnamtab, fn)) {
 		cn = (Cmdnam) zshcalloc(sizeof *cn);
-		cn->flags = 0;
+		cn->node.flags = 0;
 		cn->u.name = dirp;
 		cmdnamtab->addnode(cmdnamtab, ztrdup(fn), cn);
 	    }
@@ -686,8 +686,8 @@ freecmdnamnode(HashNode hn)
 {
     Cmdnam cn = (Cmdnam) hn;
  
-    zsfree(cn->nam);
-    if (cn->flags & HASHED)
+    zsfree(cn->node.nam);
+    if (cn->node.flags & HASHED)
 	zsfree(cn->u.cmd);
  
     zfree(cn, sizeof(struct cmdnam));
@@ -702,36 +702,36 @@ printcmdnamnode(HashNode hn, int printflags)
     Cmdnam cn = (Cmdnam) hn;
 
     if (printflags & PRINT_WHENCE_WORD) {
-	printf("%s: %s\n", cn->nam, (cn->flags & HASHED) ? 
+	printf("%s: %s\n", cn->node.nam, (cn->node.flags & HASHED) ? 
 	       "hashed" : "command");
 	return;
     }
 
     if ((printflags & PRINT_WHENCE_CSH) || (printflags & PRINT_WHENCE_SIMPLE)) {
-	if (cn->flags & HASHED) {
+	if (cn->node.flags & HASHED) {
 	    zputs(cn->u.cmd, stdout);
 	    putchar('\n');
 	} else {
 	    zputs(*(cn->u.name), stdout);
 	    putchar('/');
-	    zputs(cn->nam, stdout);
+	    zputs(cn->node.nam, stdout);
 	    putchar('\n');
 	}
 	return;
     }
 
     if (printflags & PRINT_WHENCE_VERBOSE) {
-	if (cn->flags & HASHED) {
-	    nicezputs(cn->nam, stdout);
+	if (cn->node.flags & HASHED) {
+	    nicezputs(cn->node.nam, stdout);
 	    printf(" is hashed to ");
 	    nicezputs(cn->u.cmd, stdout);
 	    putchar('\n');
 	} else {
-	    nicezputs(cn->nam, stdout);
+	    nicezputs(cn->node.nam, stdout);
 	    printf(" is ");
 	    nicezputs(*(cn->u.name), stdout);
 	    putchar('/');
-	    nicezputs(cn->nam, stdout);
+	    nicezputs(cn->node.nam, stdout);
 	    putchar('\n');
 	}
 	return;
@@ -740,21 +740,21 @@ printcmdnamnode(HashNode hn, int printflags)
     if (printflags & PRINT_LIST) {
 	printf("hash ");
 
-	if(cn->nam[0] == '-')
+	if(cn->node.nam[0] == '-')
 	    printf("-- ");
     }
 
-    if (cn->flags & HASHED) {
-	quotedzputs(cn->nam, stdout);
+    if (cn->node.flags & HASHED) {
+	quotedzputs(cn->node.nam, stdout);
 	putchar('=');
 	quotedzputs(cn->u.cmd, stdout);
 	putchar('\n');
     } else {
-	quotedzputs(cn->nam, stdout);
+	quotedzputs(cn->node.nam, stdout);
 	putchar('=');
 	quotedzputs(*(cn->u.name), stdout);
 	putchar('/');
-	quotedzputs(cn->nam, stdout);
+	quotedzputs(cn->node.nam, stdout);
 	putchar('\n');
     }
 }
@@ -833,9 +833,9 @@ enableshfuncnode(HashNode hn, UNUSED(int flags))
 {
     Shfunc shf = (Shfunc) hn;
 
-    shf->flags &= ~DISABLED;
-    if (!strncmp(shf->nam, "TRAP", 4)) {
-	int signum = getsignum(shf->nam + 4);
+    shf->node.flags &= ~DISABLED;
+    if (!strncmp(shf->node.nam, "TRAP", 4)) {
+	int signum = getsignum(shf->node.nam + 4);
 	if (signum != -1) {
 	    settrap(signum, NULL, ZSIG_FUNC);
 	}
@@ -848,7 +848,7 @@ freeshfuncnode(HashNode hn)
 {
     Shfunc shf = (Shfunc) hn;
 
-    zsfree(shf->nam);
+    zsfree(shf->node.nam);
     if (shf->funcdef)
 	freeeprog(shf->funcdef);
     zfree(shf, sizeof(struct shfunc));
@@ -866,27 +866,27 @@ printshfuncnode(HashNode hn, int printflags)
     if ((printflags & PRINT_NAMEONLY) ||
 	((printflags & PRINT_WHENCE_SIMPLE) &&
 	!(printflags & PRINT_WHENCE_FUNCDEF))) {
-	zputs(f->nam, stdout);
+	zputs(f->node.nam, stdout);
 	putchar('\n');
 	return;
     }
  
     if ((printflags & (PRINT_WHENCE_VERBOSE|PRINT_WHENCE_WORD)) &&
 	!(printflags & PRINT_WHENCE_FUNCDEF)) {
-	nicezputs(f->nam, stdout);
+	nicezputs(f->node.nam, stdout);
 	printf((printflags & PRINT_WHENCE_WORD) ? ": function\n" :
 	       " is a shell function\n");
 	return;
     }
  
-    quotedzputs(f->nam, stdout);
-    if (f->funcdef || f->flags & PM_UNDEFINED) {
+    quotedzputs(f->node.nam, stdout);
+    if (f->funcdef || f->node.flags & PM_UNDEFINED) {
 	printf(" () {\n\t");
-	if (f->flags & PM_UNDEFINED)
+	if (f->node.flags & PM_UNDEFINED)
 	    printf("%c undefined\n\t", hashchar);
 	else
 	    t = getpermtext(f->funcdef, NULL);
-	if (f->flags & PM_TAGGED)
+	if (f->node.flags & PM_TAGGED)
 	    printf("%c traced\n\t", hashchar);
 	if (!t) {
 	    char *fopt = "Utkz";
@@ -897,13 +897,13 @@ printshfuncnode(HashNode hn, int printflags)
 
 	    zputs("builtin autoload -X", stdout);
 	    for (fl=0;fopt[fl];fl++)
-		if (f->flags & flgs[fl]) putchar(fopt[fl]);
+		if (f->node.flags & flgs[fl]) putchar(fopt[fl]);
 	} else {
 	    zputs(t, stdout);
 	    zsfree(t);
 	    if (f->funcdef->flags & EF_RUN) {
 		printf("\n\t");
-		quotedzputs(f->nam, stdout);
+		quotedzputs(f->node.nam, stdout);
 		printf(" \"$@\"");
 	    }
 	}   
@@ -920,31 +920,31 @@ printshfuncnode(HashNode hn, int printflags)
 /* Nodes for reserved word hash table */
 
 static struct reswd reswds[] = {
-    {NULL, "!", 0, BANG},
-    {NULL, "[[", 0, DINBRACK},
-    {NULL, "{", 0, INBRACE},
-    {NULL, "}", 0, OUTBRACE},
-    {NULL, "case", 0, CASE},
-    {NULL, "coproc", 0, COPROC},
-    {NULL, "do", 0, DOLOOP},
-    {NULL, "done", 0, DONE},
-    {NULL, "elif", 0, ELIF},
-    {NULL, "else", 0, ELSE},
-    {NULL, "end", 0, ZEND},
-    {NULL, "esac", 0, ESAC},
-    {NULL, "fi", 0, FI},
-    {NULL, "for", 0, FOR},
-    {NULL, "foreach", 0, FOREACH},
-    {NULL, "function", 0, FUNC},
-    {NULL, "if", 0, IF},
-    {NULL, "nocorrect", 0, NOCORRECT},
-    {NULL, "repeat", 0, REPEAT},
-    {NULL, "select", 0, SELECT},
-    {NULL, "then", 0, THEN},
-    {NULL, "time", 0, TIME},
-    {NULL, "until", 0, UNTIL},
-    {NULL, "while", 0, WHILE},
-    {NULL, NULL, 0, 0}
+    {{NULL, "!", 0}, BANG},
+    {{NULL, "[[", 0}, DINBRACK},
+    {{NULL, "{", 0}, INBRACE},
+    {{NULL, "}", 0}, OUTBRACE},
+    {{NULL, "case", 0}, CASE},
+    {{NULL, "coproc", 0}, COPROC},
+    {{NULL, "do", 0}, DOLOOP},
+    {{NULL, "done", 0}, DONE},
+    {{NULL, "elif", 0}, ELIF},
+    {{NULL, "else", 0}, ELSE},
+    {{NULL, "end", 0}, ZEND},
+    {{NULL, "esac", 0}, ESAC},
+    {{NULL, "fi", 0}, FI},
+    {{NULL, "for", 0}, FOR},
+    {{NULL, "foreach", 0}, FOREACH},
+    {{NULL, "function", 0}, FUNC},
+    {{NULL, "if", 0}, IF},
+    {{NULL, "nocorrect", 0}, NOCORRECT},
+    {{NULL, "repeat", 0}, REPEAT},
+    {{NULL, "select", 0}, SELECT},
+    {{NULL, "then", 0}, THEN},
+    {{NULL, "time", 0}, TIME},
+    {{NULL, "until", 0}, UNTIL},
+    {{NULL, "while", 0}, WHILE},
+    {{NULL, NULL, 0}, 0}
 };
 
 /* hash table containing the reserved words */
@@ -975,8 +975,8 @@ createreswdtable(void)
     reswdtab->freenode    = NULL;
     reswdtab->printnode   = printreswdnode;
 
-    for (rw = reswds; rw->nam; rw++)
-	reswdtab->addnode(reswdtab, rw->nam, rw);
+    for (rw = reswds; rw->node.nam; rw++)
+	reswdtab->addnode(reswdtab, rw->node.nam, rw);
 }
 
 /* Print a reserved word */
@@ -988,22 +988,22 @@ printreswdnode(HashNode hn, int printflags)
     Reswd rw = (Reswd) hn;
 
     if (printflags & PRINT_WHENCE_WORD) {
-	printf("%s: reserved\n", rw->nam);
+	printf("%s: reserved\n", rw->node.nam);
 	return;
     }
 
     if (printflags & PRINT_WHENCE_CSH) {
-	printf("%s: shell reserved word\n", rw->nam);
+	printf("%s: shell reserved word\n", rw->node.nam);
 	return;
     }
 
     if (printflags & PRINT_WHENCE_VERBOSE) {
-	printf("%s is a reserved word\n", rw->nam);
+	printf("%s is a reserved word\n", rw->node.nam);
 	return;
     }
 
     /* default is name only */
-    printf("%s\n", rw->nam);
+    printf("%s\n", rw->node.nam);
 }
 
 /********************************/
@@ -1071,7 +1071,7 @@ createaliasnode(char *txt, int flags)
     Alias al;
 
     al = (Alias) zshcalloc(sizeof *al);
-    al->flags = flags;
+    al->node.flags = flags;
     al->text = txt;
     al->inuse = 0;
     return al;
@@ -1083,7 +1083,7 @@ freealiasnode(HashNode hn)
 {
     Alias al = (Alias) hn;
  
-    zsfree(al->nam);
+    zsfree(al->node.nam);
     zsfree(al->text);
     zfree(al, sizeof(struct alias));
 }
@@ -1097,13 +1097,13 @@ printaliasnode(HashNode hn, int printflags)
     Alias a = (Alias) hn;
 
     if (printflags & PRINT_NAMEONLY) {
-	zputs(a->nam, stdout);
+	zputs(a->node.nam, stdout);
 	putchar('\n');
 	return;
     }
 
     if (printflags & PRINT_WHENCE_WORD) {
-	printf("%s: alias\n", a->nam);
+	printf("%s: alias\n", a->node.nam);
 	return;
     }
 
@@ -1114,11 +1114,11 @@ printaliasnode(HashNode hn, int printflags)
     }
 
     if (printflags & PRINT_WHENCE_CSH) {
-	nicezputs(a->nam, stdout);
+	nicezputs(a->node.nam, stdout);
 	printf(": ");
-	if (a->flags & ALIAS_SUFFIX)
+	if (a->node.flags & ALIAS_SUFFIX)
 	    printf("suffix ");
-	else if (a->flags & ALIAS_GLOBAL)
+	else if (a->node.flags & ALIAS_GLOBAL)
 	    printf("globally ");
 	printf ("aliased to ");
 	nicezputs(a->text, stdout);
@@ -1127,11 +1127,11 @@ printaliasnode(HashNode hn, int printflags)
     }
 
     if (printflags & PRINT_WHENCE_VERBOSE) {
-	nicezputs(a->nam, stdout);
+	nicezputs(a->node.nam, stdout);
 	printf(" is a");
-	if (a->flags & ALIAS_SUFFIX)
+	if (a->node.flags & ALIAS_SUFFIX)
 	    printf(" suffix");
-	else if (a->flags & ALIAS_GLOBAL)
+	else if (a->node.flags & ALIAS_GLOBAL)
 	    printf(" global");
 	else
 	    printf("n");
@@ -1143,18 +1143,18 @@ printaliasnode(HashNode hn, int printflags)
 
     if (printflags & PRINT_LIST) {
 	printf("alias ");
-	if (a->flags & ALIAS_SUFFIX)
+	if (a->node.flags & ALIAS_SUFFIX)
 	    printf("-s ");
-	else if (a->flags & ALIAS_GLOBAL)
+	else if (a->node.flags & ALIAS_GLOBAL)
 	    printf("-g ");
 
 	/* If an alias begins with `-', then we must output `-- ' *
 	 * first, so that it is not interpreted as an option.     */
-	if(a->nam[0] == '-')
+	if(a->node.nam[0] == '-')
 	    printf("-- ");
     }
 
-    quotedzputs(a->nam, stdout);
+    quotedzputs(a->node.nam, stdout);
     putchar('=');
     quotedzputs(a->text, stdout);
 
@@ -1394,7 +1394,7 @@ freenameddirnode(HashNode hn)
 {
     Nameddir nd = (Nameddir) hn;
  
-    zsfree(nd->nam);
+    zsfree(nd->node.nam);
     zsfree(nd->dir);
     zfree(nd, sizeof(struct nameddir));
 }
@@ -1408,7 +1408,7 @@ printnameddirnode(HashNode hn, int printflags)
     Nameddir nd = (Nameddir) hn;
 
     if (printflags & PRINT_NAMEONLY) {
-	zputs(nd->nam, stdout);
+	zputs(nd->node.nam, stdout);
 	putchar('\n');
 	return;
     }
@@ -1416,11 +1416,11 @@ printnameddirnode(HashNode hn, int printflags)
     if (printflags & PRINT_LIST) {
       printf("hash -d ");
 
-      if(nd->nam[0] == '-')
+      if(nd->node.nam[0] == '-')
 	    printf("-- ");
     }
 
-    quotedzputs(nd->nam, stdout);
+    quotedzputs(nd->node.nam, stdout);
     putchar('=');
     quotedzputs(nd->dir, stdout);
     putchar('\n');
@@ -1511,11 +1511,11 @@ addhistnode(HashTable ht, char *nam, void *nodeptr)
     HashNode oldnode = addhashnode2(ht, nam, nodeptr);
     Histent he = (Histent)nodeptr;
     if (oldnode && oldnode != (HashNode)nodeptr) {
-	if (he->flags & HIST_MAKEUNIQUE
-	 || (he->flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
+	if (he->node.flags & HIST_MAKEUNIQUE
+	 || (he->node.flags & HIST_FOREIGN && (Histent)oldnode == he->up)) {
 	    (void) addhashnode2(ht, oldnode->nam, oldnode); /* restore hash */
-	    he->flags |= HIST_DUP;
-	    he->flags &= ~HIST_MAKEUNIQUE;
+	    he->node.flags |= HIST_DUP;
+	    he->node.flags &= ~HIST_MAKEUNIQUE;
 	}
 	else {
 	    oldnode->flags |= HIST_DUP;
@@ -1524,7 +1524,7 @@ addhistnode(HashTable ht, char *nam, void *nodeptr)
 	}
     }
     else
-	he->flags &= ~HIST_MAKEUNIQUE;
+	he->node.flags &= ~HIST_MAKEUNIQUE;
 }
 
 /**/
@@ -1542,10 +1542,10 @@ freehistdata(Histent he, int unlink)
     if (!he)
 	return;
 
-    if (!(he->flags & (HIST_DUP | HIST_TMPSTORE)))
-	removehashnode(histtab, he->text);
+    if (!(he->node.flags & (HIST_DUP | HIST_TMPSTORE)))
+	removehashnode(histtab, he->node.nam);
 
-    zsfree(he->text);
+    zsfree(he->node.nam);
     if (he->nwords)
 	zfree(he->words, he->nwords*2*sizeof(short));
 
diff --git a/Src/hist.c b/Src/hist.c
index 1a9140801..64c5c4fef 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -862,8 +862,8 @@ histremovedups(void)
     Histent he, next;
     for (he = hist_ring; he; he = next) {
 	next = up_histent(he);
-	if (he->flags & HIST_DUP)
-	    freehistnode((HashNode)he);
+	if (he->node.flags & HIST_DUP)
+	    freehistnode(&he->node);
     }
 }
 
@@ -892,13 +892,13 @@ movehistent(Histent he, int n, int xflags)
     while (n < 0) {
 	if (!(he = up_histent(he)))
 	    return NULL;
-	if (!(he->flags & xflags))
+	if (!(he->node.flags & xflags))
 	    n++;
     }
     while (n > 0) {
 	if (!(he = down_histent(he)))
 	    return NULL;
-	if (!(he->flags & xflags))
+	if (!(he->node.flags & xflags))
 	    n--;
     }
     checkcurline(he);
@@ -955,7 +955,7 @@ putoldhistentryontop(short keep_going)
     static Histent next = NULL;
     Histent he = keep_going? next : hist_ring->down;
     next = he->down;
-    if (isset(HISTEXPIREDUPSFIRST) && !(he->flags & HIST_DUP)) {
+    if (isset(HISTEXPIREDUPSFIRST) && !(he->node.flags & HIST_DUP)) {
 	static zlong max_unique_ct = 0;
 	if (!keep_going)
 	    max_unique_ct = savehistsiz;
@@ -968,7 +968,7 @@ putoldhistentryontop(short keep_going)
 	    }
 	    he = next;
 	    next = he->down;
-	} while (!(he->flags & HIST_DUP));
+	} while (!(he->node.flags & HIST_DUP));
     }
     if (he != hist_ring->down) {
 	he->up->down = he->down;
@@ -989,9 +989,9 @@ prepnexthistent(void)
 
     if (curline_in_ring)
 	unlinkcurline();
-    if (hist_ring && hist_ring->flags & HIST_TMPSTORE) {
+    if (hist_ring && hist_ring->node.flags & HIST_TMPSTORE) {
 	curhist--;
-	freehistnode((HashNode)hist_ring);
+	freehistnode(&hist_ring->node);
     }
 
     if (histlinect < histsiz) {
@@ -1132,12 +1132,12 @@ hend(Eprog prog)
     }
     if (save || *chline == ' ') {
 	Histent he;
-	for (he = hist_ring; he && he->flags & HIST_FOREIGN;
+	for (he = hist_ring; he && he->node.flags & HIST_FOREIGN;
 	     he = up_histent(he)) ;
-	if (he && he->flags & HIST_TMPSTORE) {
+	if (he && he->node.flags & HIST_TMPSTORE) {
 	    if (he == hist_ring)
 		curline.histnum = curhist--;
-	    freehistnode((HashNode)he);
+	    freehistnode(&he->node);
 	}
     }
     if (save) {
@@ -1160,30 +1160,30 @@ hend(Eprog prog)
 	}
 	newflags = save > 0? 0 : HIST_TMPSTORE;
 	if ((isset(HISTIGNOREDUPS) || isset(HISTIGNOREALLDUPS)) && save > 0
-	 && hist_ring && histstrcmp(chline, hist_ring->text) == 0) {
+	 && hist_ring && histstrcmp(chline, hist_ring->node.nam) == 0) {
 	    /* This history entry compares the same as the previous.
 	     * In case minor changes were made, we overwrite the
 	     * previous one with the current one.  This also gets the
 	     * timestamp right.  Perhaps, preserve the HIST_OLD flag.
 	     */
 	    he = hist_ring;
-	    newflags |= he->flags & HIST_OLD; /* Avoid re-saving */
+	    newflags |= he->node.flags & HIST_OLD; /* Avoid re-saving */
 	    freehistdata(he, 0);
 	    curline.histnum = curhist;
 	} else
 	    he = prepnexthistent();
 
-	he->text = ztrdup(chline);
+	he->node.nam = ztrdup(chline);
 	he->stim = time(NULL);
 	he->ftim = 0L;
-	he->flags = newflags;
+	he->node.flags = newflags;
 
 	if ((he->nwords = chwordpos/2)) {
 	    he->words = (short *)zalloc(chwordpos * sizeof(short));
 	    memcpy(he->words, chwords, chwordpos * sizeof(short));
 	}
 	if (!(newflags & HIST_TMPSTORE))
-	    addhistnode(histtab, he->text, he);
+	    addhistnode(histtab, he->node.nam, he);
     }
     zfree(chline, hlinesz);
     zfree(chwords, chwordlen*sizeof(short));
@@ -1383,10 +1383,10 @@ hconsearch(char *str, int *marg)
     Histent he;
 
     for (he = up_histent(hist_ring); he; he = up_histent(he)) {
-	if (he->flags & HIST_FOREIGN)
+	if (he->node.flags & HIST_FOREIGN)
 	    continue;
-	if ((s = strstr(he->text, str))) {
-	    int pos = s - he->text;
+	if ((s = strstr(he->node.nam, str))) {
+	    int pos = s - he->node.nam;
 	    while (t1 < he->nwords && he->words[2*t1] <= pos)
 		t1++;
 	    *marg = t1 - 1;
@@ -1406,9 +1406,9 @@ hcomsearch(char *str)
     int len = strlen(str);
 
     for (he = up_histent(hist_ring); he; he = up_histent(he)) {
-	if (he->flags & HIST_FOREIGN)
+	if (he->node.flags & HIST_FOREIGN)
 	    continue;
-	if (strncmp(he->text, str, len) == 0)
+	if (strncmp(he->node.nam, str, len) == 0)
 	    return he->histnum;
     }
     return -1;
@@ -1599,7 +1599,7 @@ mod_export void
 checkcurline(Histent he)
 {
     if (he->histnum == curhist && (histactive & HA_ACTIVE)) {
-	curline.text = chline;
+	curline.node.nam = chline;
 	curline.nwords = chwordpos/2;
 	curline.words = chwords;
     }
@@ -1641,7 +1641,7 @@ getargs(Histent elist, int arg1, int arg2)
     }
 
     pos1 = words[2*arg1];
-    return dupstrpfx(elist->text + pos1, words[2*arg2+1] - pos1);
+    return dupstrpfx(elist->node.nam + pos1, words[2*arg2+1] - pos1);
 }
 
 /**/
@@ -1811,10 +1811,10 @@ resizehistents(void)
 	/* The reason we don't just call freehistnode(hist_ring->down) is
 	 * so that we can honor the HISTEXPIREDUPSFIRST setting. */
 	putoldhistentryontop(0);
-	freehistnode((HashNode)hist_ring);
+	freehistnode(&hist_ring->node);
 	while (histlinect > histsiz) {
 	    putoldhistentryontop(1);
-	    freehistnode((HashNode)hist_ring);
+	    freehistnode(&hist_ring->node);
 	}
     }
 }
@@ -1974,8 +1974,8 @@ readhistfile(char *fn, int err, int readflags)
 	    }
 
 	    he = prepnexthistent();
-	    he->text = ztrdup(pt);
-	    he->flags = newflags;
+	    he->node.nam = ztrdup(pt);
+	    he->node.flags = newflags;
 	    if ((he->stim = stim) == 0)
 		he->stim = he->ftim = tim;
 	    else if (ftim < stim)
@@ -2008,9 +2008,9 @@ readhistfile(char *fn, int err, int readflags)
 		memcpy(he->words, wordlist, nwordpos*sizeof(short));
 	    } else
 		he->words = (short *)NULL;
-	    addhistnode(histtab, he->text, he);
-	    if (he->flags & HIST_DUP) {
-		freehistnode((HashNode)he);
+	    addhistnode(histtab, he->node.nam, he);
+	    if (he->node.flags & HIST_DUP) {
+		freehistnode(&he->node);
 		curhist--;
 	    }
 	}
@@ -2043,7 +2043,7 @@ savehistfile(char *fn, int err, int writeflags)
 	return;
     if (writeflags & HFILE_FAST) {
 	he = gethistent(lasthist.next_write_ev, GETHIST_DOWNWARD);
-	while (he && he->flags & HIST_OLD) {
+	while (he && he->node.flags & HIST_OLD) {
 	    lasthist.next_write_ev = he->histnum + 1;
 	    he = down_histent(he);
 	}
@@ -2103,14 +2103,14 @@ savehistfile(char *fn, int err, int writeflags)
     }
     if (out) {
 	for (; he && he->histnum <= xcurhist; he = down_histent(he)) {
-	    if ((writeflags & HFILE_SKIPDUPS && he->flags & HIST_DUP)
-	     || (writeflags & HFILE_SKIPFOREIGN && he->flags & HIST_FOREIGN)
-	     || he->flags & HIST_TMPSTORE)
+	    if ((writeflags & HFILE_SKIPDUPS && he->node.flags & HIST_DUP)
+	     || (writeflags & HFILE_SKIPFOREIGN && he->node.flags & HIST_FOREIGN)
+	     || he->node.flags & HIST_TMPSTORE)
 		continue;
 	    if (writeflags & HFILE_SKIPOLD) {
-		if (he->flags & HIST_OLD)
+		if (he->node.flags & HIST_OLD)
 		    continue;
-		he->flags |= HIST_OLD;
+		he->node.flags |= HIST_OLD;
 		if (writeflags & HFILE_USE_OPTIONS)
 		    lasthist.next_write_ev = he->histnum + 1;
 	    }
@@ -2119,7 +2119,7 @@ savehistfile(char *fn, int err, int writeflags)
 		lasthist.stim = he->stim;
 		histfile_linect++;
 	    }
-	    t = start = he->text;
+	    t = start = he->node.nam;
 	    if (extended_history) {
 		fprintf(out, ": %ld:%ld;", (long)he->stim,
 			he->ftim? (long)(he->ftim - he->stim) : 0L);
diff --git a/Src/init.c b/Src/init.c
index 2bb5e0dbd..2ddef9e0a 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -149,7 +149,7 @@ loop(int toplevel, int justonce)
 		/* If curline got dumped from the history, we don't know
 		 * what the user typed. */
 		if (hist_ring && curline.histnum == curhist)
-		    zaddlinknode(args, hist_ring->text);
+		    zaddlinknode(args, hist_ring->node.nam);
 		else
 		    zaddlinknode(args, "");
 		zaddlinknode(args, getjobtext(prog, NULL));
diff --git a/Src/lex.c b/Src/lex.c
index 3ab099daf..55920a142 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1606,7 +1606,7 @@ exalias(void)
 		
 		an = (Alias) aliastab->getnode(aliastab, yytext);
 		if (an && !an->inuse &&
-		    ((an->flags & ALIAS_GLOBAL) || incmdpos || inalmore)) {
+		    ((an->node.flags & ALIAS_GLOBAL) || incmdpos || inalmore)) {
 		    inpush(an->text, INP_ALIAS, an);
 		    if (an->text[0] == ' ')
 			aliasspaceflag = 1;
diff --git a/Src/linklist.c b/Src/linklist.c
index 35233f549..5cbe684d1 100644
--- a/Src/linklist.c
+++ b/Src/linklist.c
@@ -39,8 +39,8 @@ newlinklist(void)
     LinkList list;
 
     list = (LinkList) zhalloc(sizeof *list);
-    list->first = NULL;
-    list->last = (LinkNode) list;
+    list->list.first = NULL;
+    list->list.last = &list->node;
     return list;
 }
 
@@ -51,8 +51,8 @@ znewlinklist(void)
     LinkList list;
 
     list = (LinkList) zalloc(sizeof *list);
-    list->first = NULL;
-    list->last = (LinkNode) list;
+    list->list.first = NULL;
+    list->list.last = &list->node;
     return list;
 }
 
@@ -72,7 +72,7 @@ insertlinknode(LinkList list, LinkNode node, void *dat)
     if (tmp)
 	tmp->last = new;
     else
-	list->last = new;
+	list->list.last = new;
     return new;
 }
 
@@ -90,7 +90,7 @@ zinsertlinknode(LinkList list, LinkNode node, void *dat)
     if (tmp)
 	tmp->last = new;
     else
-	list->last = new;
+	list->list.last = new;
     return new;
 }
 
@@ -107,7 +107,7 @@ uinsertlinknode(LinkList list, LinkNode node, LinkNode new)
     if (tmp)
 	tmp->last = new;
     else
-	list->last = new;
+	list->list.last = new;
     return new;
 }
 
@@ -120,15 +120,15 @@ insertlinklist(LinkList l, LinkNode where, LinkList x)
     LinkNode nx;
 
     nx = where->next;
-    if (!l->first)
+    if (!firstnode(l))
 	return;
-    where->next = l->first;
-    l->last->next = nx;
-    l->first->last = where;
+    where->next = firstnode(l);
+    l->list.last->next = nx;
+    l->list.first->last = where;
     if (nx)
-	nx->last = l->last;
+	nx->last = lastnode(l);
     else
-	x->last = l->last;
+	x->list.last = lastnode(l);
 }
 
 /* Pop the top node off a linked list and free it. */
@@ -140,15 +140,15 @@ getlinknode(LinkList list)
     void *dat;
     LinkNode node;
 
-    if (!(node = list->first))
+    if (!(node = firstnode(list)))
 	return NULL;
     dat = node->dat;
-    list->first = node->next;
+    list->list.first = node->next;
     if (node->next)
-	node->next->last = (LinkNode) list;
+	node->next->last = &list->node;
     else
-	list->last = (LinkNode) list;
-    zfree(node, sizeof(struct linknode));
+	list->list.last = &list->node;
+    zfree(node, sizeof *node);
     return dat;
 }
 
@@ -161,14 +161,14 @@ ugetnode(LinkList list)
     void *dat;
     LinkNode node;
 
-    if (!(node = list->first))
+    if (!(node = firstnode(list)))
 	return NULL;
     dat = node->dat;
-    list->first = node->next;
+    list->list.first = node->next;
     if (node->next)
-	node->next->last = (LinkNode) list;
+	node->next->last = &list->node;
     else
-	list->last = (LinkNode) list;
+	list->list.last = &list->node;
     return dat;
 }
 
@@ -184,9 +184,9 @@ remnode(LinkList list, LinkNode nd)
     if (nd->next)
 	nd->next->last = nd->last;
     else
-	list->last = nd->last;
+	list->list.last = nd->last;
     dat = nd->dat;
-    zfree(nd, sizeof(struct linknode));
+    zfree(nd, sizeof *nd);
 
     return dat;
 }
@@ -203,7 +203,7 @@ uremnode(LinkList list, LinkNode nd)
     if (nd->next)
 	nd->next->last = nd->last;
     else
-	list->last = nd->last;
+	list->list.last = nd->last;
     dat = nd->dat;
     return dat;
 }
@@ -216,13 +216,13 @@ freelinklist(LinkList list, FreeFunc freefunc)
 {
     LinkNode node, next;
 
-    for (node = list->first; node; node = next) {
+    for (node = firstnode(list); node; node = next) {
 	next = node->next;
 	if (freefunc)
 	    freefunc(node->dat);
-	zfree(node, sizeof(struct linknode));
+	zfree(node, sizeof *node);
     }
-    zfree(list, sizeof(struct linklist));
+    zfree(list, sizeof *list);
 }
 
 /* Count the number of nodes in a linked list */
@@ -242,12 +242,12 @@ countlinknodes(LinkList list)
 mod_export void
 rolllist(LinkList l, LinkNode nd)
 {
-    l->last->next = l->first;
-    l->first->last = l->last;
-    l->first = nd;
-    l->last = nd->last;
-    nd->last = (LinkNode) l;
-    l->last->next = 0;
+    l->list.last->next = firstnode(l);
+    l->list.first->last = lastnode(l);
+    l->list.first = nd;
+    l->list.last = nd->last;
+    nd->last = &l->node;
+    l->list.last->next = 0;
 }
 
 /**/
@@ -257,16 +257,15 @@ newsizedlist(int size)
     LinkList list;
     LinkNode node;
 
-    list = (LinkList) zhalloc(sizeof(struct linklist) +
-			      (size * sizeof(struct linknode)));
+    list = (LinkList) zhalloc(sizeof *list + (size * sizeof *node));
 
-    list->first = (LinkNode) (list + 1);
-    for (node = list->first; size; size--, node++) {
+    list->list.first = &list[1].node;
+    for (node = firstnode(list); size; size--, node++) {
 	node->last = node - 1;
 	node->next = node + 1;
     }
-    list->last = node - 1;
-    list->first->last = (LinkNode) list;
+    list->list.last = node - 1;
+    list->list.first->last = &list->node;
     node[-1].next = NULL;
 
     return list;
diff --git a/Src/module.c b/Src/module.c
index ee493ad0c..17daffc2d 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -133,12 +133,12 @@ module_linked(char const *name)
 int
 addbuiltin(Builtin b)
 {
-    Builtin bn = (Builtin) builtintab->getnode2(builtintab, b->nam);
-    if (bn && (bn->flags & BINF_ADDED))
+    Builtin bn = (Builtin) builtintab->getnode2(builtintab, b->node.nam);
+    if (bn && (bn->node.flags & BINF_ADDED))
 	return 1;
     if (bn)
-	builtintab->freenode(builtintab->removenode(builtintab, b->nam));
-    builtintab->addnode(builtintab, b->nam, b);
+	builtintab->freenode(builtintab->removenode(builtintab, b->node.nam));
+    builtintab->addnode(builtintab, b->node.nam, b);
     return 0;
 }
 
@@ -158,13 +158,13 @@ addbuiltins(char const *nam, Builtin binl, int size)
 
     for(n = 0; n < size; n++) {
 	Builtin b = &binl[n];
-	if(b->flags & BINF_ADDED)
+	if(b->node.flags & BINF_ADDED)
 	    continue;
 	if(addbuiltin(b)) {
-	    zwarnnam(nam, "name clash when adding builtin `%s'", b->nam, 0);
+	    zwarnnam(nam, "name clash when adding builtin `%s'", b->node.nam, 0);
 	    hadf = 1;
 	} else {
-	    b->flags |= BINF_ADDED;
+	    b->node.flags |= BINF_ADDED;
 	    hads = 2;
 	}
     }
@@ -227,7 +227,7 @@ int
 add_autobin(char *nam, char *module)
 {
     Builtin bn = zshcalloc(sizeof(*bn));
-    bn->nam = ztrdup(nam);
+    bn->node.nam = ztrdup(nam);
     bn->optstr = ztrdup(module);
     return addbuiltin(bn);
 }
@@ -244,7 +244,7 @@ deletebuiltin(char *nam)
     bn = (Builtin) builtintab->removenode(builtintab, nam);
     if (!bn)
 	return -1;
-    builtintab->freenode((HashNode)bn);
+    builtintab->freenode(&bn->node);
     return 0;
 }
 
@@ -265,14 +265,14 @@ deletebuiltins(char const *nam, Builtin binl, int size)
 
     for(n = 0; n < size; n++) {
 	Builtin b = &binl[n];
-	if(!(b->flags & BINF_ADDED))
+	if(!(b->node.flags & BINF_ADDED))
 	    continue;
-	if(deletebuiltin(b->nam)) {
-	    zwarnnam(nam, "builtin `%s' already deleted", b->nam, 0);
+	if(deletebuiltin(b->node.nam)) {
+	    zwarnnam(nam, "builtin `%s' already deleted", b->node.nam, 0);
 	    hadf = 1;
 	} else
 	    hads = 2;
-	b->flags &= ~BINF_ADDED;
+	b->node.flags &= ~BINF_ADDED;
     }
     return hadf ? hads : 1;
 }
@@ -941,20 +941,20 @@ autoloadscan(HashNode hn, int printflags)
 {
     Builtin bn = (Builtin) hn;
 
-    if(bn->flags & BINF_ADDED)
+    if(bn->node.flags & BINF_ADDED)
 	return;
     if(printflags & PRINT_LIST) {
 	fputs("zmodload -ab ", stdout);
 	if(bn->optstr[0] == '-')
 	    fputs("-- ", stdout);
 	quotedzputs(bn->optstr, stdout);
-	if(strcmp(bn->nam, bn->optstr)) {
+	if(strcmp(bn->node.nam, bn->optstr)) {
 	    putchar(' ');
-	    quotedzputs(bn->nam, stdout);
+	    quotedzputs(bn->node.nam, stdout);
 	}
     } else {
-	nicezputs(bn->nam, stdout);
-	if(strcmp(bn->nam, bn->optstr)) {
+	nicezputs(bn->node.nam, stdout);
+	if(strcmp(bn->node.nam, bn->optstr)) {
 	    fputs(" (", stdout);
 	    nicezputs(bn->optstr, stdout);
 	    putchar(')');
@@ -1262,7 +1262,7 @@ bin_zmodload_auto(char *nam, char **args, Options ops)
 		    zwarnnam(nam, "%s: no such builtin", *args, 0);
 		    ret = 1;
 		}
-	    } else if (bn->flags & BINF_ADDED) {
+	    } else if (bn->node.flags & BINF_ADDED) {
 		zwarnnam(nam, "%s: builtin is already defined", *args, 0);
 		ret = 1;
 	    } else
@@ -1418,11 +1418,11 @@ printautoparams(HashNode hn, int lon)
 {
     Param pm = (Param) hn;
 
-    if (pm->flags & PM_AUTOLOAD) {
+    if (pm->node.flags & PM_AUTOLOAD) {
 	if (lon)
-	    printf("zmodload -ap %s %s\n", pm->u.str, pm->nam);
+	    printf("zmodload -ap %s %s\n", pm->u.str, pm->node.nam);
 	else
-	    printf("%s (%s)\n", pm->nam, pm->u.str);
+	    printf("%s (%s)\n", pm->node.nam, pm->u.str);
     }
 }
 
@@ -1442,7 +1442,7 @@ bin_zmodload_param(char *nam, char **args, Options ops)
 		    zwarnnam(nam, "%s: no such parameter", *args, 0);
 		    ret = 1;
 		}
-	    } else if (!(pm->flags & PM_AUTOLOAD)) {
+	    } else if (!(pm->node.flags & PM_AUTOLOAD)) {
 		zwarnnam(nam, "%s: parameter is already defined", *args, 0);
 		ret = 1;
 	    } else
@@ -1925,7 +1925,7 @@ addparamdef(Paramdef d)
 	 * If no get/set/unset class, use the appropriate
 	 * variable type.
 	 */
-	switch (PM_TYPE(pm->flags)) {
+	switch (PM_TYPE(pm->node.flags)) {
 	case PM_SCALAR:
 	    pm->gsu.s = &varscalar_gsu;
 	    break;
@@ -2075,7 +2075,7 @@ add_autoparam(char *nam, char *module)
 
     pm = setsparam(nam, ztrdup(module));
 
-    pm->flags |= PM_AUTOLOAD;
+    pm->node.flags |= PM_AUTOLOAD;
     unqueue_signals();
 }
 
diff --git a/Src/options.c b/Src/options.c
index 9400e5f89..bae429e94 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -62,172 +62,172 @@ mod_export HashTable optiontab;
 #define OPT_SPECIAL	(1<<6)	/* option should never be set by emulate() */
 #define OPT_ALIAS	(1<<7)	/* option is an alias to an other option */
 
-#define defset(X) (!!((X)->flags & emulation))
+#define defset(X) (!!((X)->node.flags & emulation))
 
 /*
  * Note that option names should usually be fewer than 20 characters long
  * to avoid formatting problems.
  */
 static struct optname optns[] = {
-{NULL, "aliases",	      OPT_EMULATE|OPT_ALL,	 ALIASESOPT},
-{NULL, "allexport",	      OPT_EMULATE,		 ALLEXPORT},
-{NULL, "alwayslastprompt",    OPT_ALL,			 ALWAYSLASTPROMPT},
-{NULL, "alwaystoend",	      0,			 ALWAYSTOEND},
-{NULL, "appendhistory",	      OPT_ALL,			 APPENDHISTORY},
-{NULL, "autocd",	      OPT_EMULATE,		 AUTOCD},
-{NULL, "autocontinue",	      0,			 AUTOCONTINUE},
-{NULL, "autolist",	      OPT_ALL,			 AUTOLIST},
-{NULL, "automenu",	      OPT_ALL,			 AUTOMENU},
-{NULL, "autonamedirs",	      0,			 AUTONAMEDIRS},
-{NULL, "autoparamkeys",	      OPT_ALL,			 AUTOPARAMKEYS},
-{NULL, "autoparamslash",      OPT_ALL,			 AUTOPARAMSLASH},
-{NULL, "autopushd",	      0,			 AUTOPUSHD},
-{NULL, "autoremoveslash",     OPT_ALL,			 AUTOREMOVESLASH},
-{NULL, "autoresume",	      0,			 AUTORESUME},
-{NULL, "badpattern",	      OPT_EMULATE|OPT_NONBOURNE, BADPATTERN},
-{NULL, "banghist",	      OPT_NONBOURNE,		 BANGHIST},
-{NULL, "bareglobqual",        OPT_EMULATE|OPT_ZSH,       BAREGLOBQUAL},
-{NULL, "bashautolist",	      0,                         BASHAUTOLIST},
-{NULL, "beep",		      OPT_ALL,			 BEEP},
-{NULL, "bgnice",	      OPT_EMULATE|OPT_NONBOURNE, BGNICE},
-{NULL, "braceccl",	      OPT_EMULATE,		 BRACECCL},
-{NULL, "bsdecho",	      OPT_EMULATE|OPT_SH,	 BSDECHO},
-{NULL, "caseglob",	      OPT_ALL,			 CASEGLOB},
-{NULL, "cbases",	      0,			 CBASES},
-{NULL, "cdablevars",	      OPT_EMULATE,		 CDABLEVARS},
-{NULL, "chasedots",	      OPT_EMULATE,		 CHASEDOTS},
-{NULL, "chaselinks",	      OPT_EMULATE,		 CHASELINKS},
-{NULL, "checkjobs",	      OPT_EMULATE|OPT_ZSH,	 CHECKJOBS},
-{NULL, "clobber",	      OPT_EMULATE|OPT_ALL,	 CLOBBER},
-{NULL, "completealiases",     0,			 COMPLETEALIASES},
-{NULL, "completeinword",      0,			 COMPLETEINWORD},
-{NULL, "correct",	      0,			 CORRECT},
-{NULL, "correctall",	      0,			 CORRECTALL},
-{NULL, "cshjunkiehistory",    OPT_EMULATE|OPT_CSH,	 CSHJUNKIEHISTORY},
-{NULL, "cshjunkieloops",      OPT_EMULATE|OPT_CSH,	 CSHJUNKIELOOPS},
-{NULL, "cshjunkiequotes",     OPT_EMULATE|OPT_CSH,	 CSHJUNKIEQUOTES},
-{NULL, "cshnullcmd",	      OPT_EMULATE|OPT_CSH,	 CSHNULLCMD},
-{NULL, "cshnullglob",	      OPT_EMULATE|OPT_CSH,	 CSHNULLGLOB},
-{NULL, "emacs",		      0,			 EMACSMODE},
-{NULL, "equals",	      OPT_EMULATE|OPT_ZSH,	 EQUALS},
-{NULL, "errexit",	      OPT_EMULATE,		 ERREXIT},
-{NULL, "errreturn",	      OPT_EMULATE,		 ERRRETURN},
-{NULL, "exec",		      OPT_ALL,			 EXECOPT},
-{NULL, "extendedglob",	      OPT_EMULATE,		 EXTENDEDGLOB},
-{NULL, "extendedhistory",     OPT_CSH,			 EXTENDEDHISTORY},
-{NULL, "evallineno",	      OPT_EMULATE|OPT_ZSH,	 EVALLINENO},
-{NULL, "flowcontrol",	      OPT_ALL,			 FLOWCONTROL},
-{NULL, "functionargzero",     OPT_EMULATE|OPT_NONBOURNE, FUNCTIONARGZERO},
-{NULL, "glob",		      OPT_EMULATE|OPT_ALL,	 GLOBOPT},
-{NULL, "globalexport",        OPT_EMULATE|OPT_ZSH,	 GLOBALEXPORT},
-{NULL, "globalrcs",           OPT_ALL,			 GLOBALRCS},
-{NULL, "globassign",	      OPT_EMULATE|OPT_CSH,	 GLOBASSIGN},
-{NULL, "globcomplete",	      0,			 GLOBCOMPLETE},
-{NULL, "globdots",	      OPT_EMULATE,		 GLOBDOTS},
-{NULL, "globsubst",	      OPT_EMULATE|OPT_NONZSH,	 GLOBSUBST},
-{NULL, "hashcmds",	      OPT_ALL,			 HASHCMDS},
-{NULL, "hashdirs",	      OPT_ALL,			 HASHDIRS},
-{NULL, "hashlistall",	      OPT_ALL,			 HASHLISTALL},
-{NULL, "histallowclobber",    0,			 HISTALLOWCLOBBER},
-{NULL, "histbeep",	      OPT_ALL,			 HISTBEEP},
-{NULL, "histexpiredupsfirst", 0,			 HISTEXPIREDUPSFIRST},
-{NULL, "histfindnodups",      0,			 HISTFINDNODUPS},
-{NULL, "histignorealldups",   0,			 HISTIGNOREALLDUPS},
-{NULL, "histignoredups",      0,			 HISTIGNOREDUPS},
-{NULL, "histignorespace",     0,			 HISTIGNORESPACE},
-{NULL, "histnofunctions",     0,			 HISTNOFUNCTIONS},
-{NULL, "histnostore",	      0,			 HISTNOSTORE},
-{NULL, "histreduceblanks",    0,			 HISTREDUCEBLANKS},
-{NULL, "histsavebycopy",      OPT_ALL,			 HISTSAVEBYCOPY},
-{NULL, "histsavenodups",      0,			 HISTSAVENODUPS},
-{NULL, "histverify",	      0,			 HISTVERIFY},
-{NULL, "hup",		      OPT_EMULATE|OPT_ZSH,	 HUP},
-{NULL, "ignorebraces",	      OPT_EMULATE|OPT_SH,	 IGNOREBRACES},
-{NULL, "ignoreeof",	      0,			 IGNOREEOF},
-{NULL, "incappendhistory",    0,			 INCAPPENDHISTORY},
-{NULL, "interactive",	      OPT_SPECIAL,		 INTERACTIVE},
-{NULL, "interactivecomments", OPT_BOURNE,		 INTERACTIVECOMMENTS},
-{NULL, "ksharrays",	      OPT_EMULATE|OPT_BOURNE,	 KSHARRAYS},
-{NULL, "kshautoload",	      OPT_EMULATE|OPT_BOURNE,	 KSHAUTOLOAD},
-{NULL, "kshglob",             OPT_EMULATE|OPT_KSH,       KSHGLOB},
-{NULL, "kshoptionprint",      OPT_EMULATE|OPT_KSH,	 KSHOPTIONPRINT},
-{NULL, "kshtypeset",          OPT_EMULATE|OPT_KSH,	 KSHTYPESET},
-{NULL, "listambiguous",	      OPT_ALL,			 LISTAMBIGUOUS},
-{NULL, "listbeep",	      OPT_ALL,			 LISTBEEP},
-{NULL, "listpacked",	      0,			 LISTPACKED},
-{NULL, "listrowsfirst",	      0,			 LISTROWSFIRST},
-{NULL, "listtypes",	      OPT_ALL,			 LISTTYPES},
-{NULL, "localoptions",	      OPT_EMULATE|OPT_KSH,	 LOCALOPTIONS},
-{NULL, "localtraps",	      OPT_EMULATE|OPT_KSH,	 LOCALTRAPS},
-{NULL, "login",		      OPT_SPECIAL,		 LOGINSHELL},
-{NULL, "longlistjobs",	      0,			 LONGLISTJOBS},
-{NULL, "magicequalsubst",     OPT_EMULATE,		 MAGICEQUALSUBST},
-{NULL, "mailwarning",	      0,			 MAILWARNING},
-{NULL, "markdirs",	      0,			 MARKDIRS},
-{NULL, "menucomplete",	      0,			 MENUCOMPLETE},
-{NULL, "monitor",	      OPT_SPECIAL,		 MONITOR},
-{NULL, "multios",	      OPT_EMULATE|OPT_ZSH,	 MULTIOS},
-{NULL, "nomatch",	      OPT_EMULATE|OPT_NONBOURNE, NOMATCH},
-{NULL, "notify",	      OPT_ZSH,			 NOTIFY},
-{NULL, "nullglob",	      OPT_EMULATE,		 NULLGLOB},
-{NULL, "numericglobsort",     OPT_EMULATE,		 NUMERICGLOBSORT},
-{NULL, "octalzeroes",         OPT_EMULATE|OPT_SH,	 OCTALZEROES},
-{NULL, "overstrike",	      0,			 OVERSTRIKE},
-{NULL, "pathdirs",	      OPT_EMULATE,		 PATHDIRS},
-{NULL, "posixbuiltins",	      OPT_EMULATE|OPT_BOURNE,	 POSIXBUILTINS},
-{NULL, "printeightbit",       0,                         PRINTEIGHTBIT},
-{NULL, "printexitvalue",      0,			 PRINTEXITVALUE},
-{NULL, "privileged",	      OPT_SPECIAL,		 PRIVILEGED},
-{NULL, "promptbang",	      OPT_KSH,			 PROMPTBANG},
-{NULL, "promptcr",	      OPT_ALL,			 PROMPTCR},
-{NULL, "promptpercent",	      OPT_NONBOURNE,		 PROMPTPERCENT},
-{NULL, "promptsp",	      OPT_ALL,			 PROMPTSP},
-{NULL, "promptsubst",	      OPT_KSH,			 PROMPTSUBST},
-{NULL, "pushdignoredups",     OPT_EMULATE,		 PUSHDIGNOREDUPS},
-{NULL, "pushdminus",	      OPT_EMULATE,		 PUSHDMINUS},
-{NULL, "pushdsilent",	      0,			 PUSHDSILENT},
-{NULL, "pushdtohome",	      OPT_EMULATE,		 PUSHDTOHOME},
-{NULL, "rcexpandparam",	      OPT_EMULATE,		 RCEXPANDPARAM},
-{NULL, "rcquotes",	      OPT_EMULATE,		 RCQUOTES},
-{NULL, "rcs",		      OPT_ALL,			 RCS},
-{NULL, "recexact",	      0,			 RECEXACT},
-{NULL, "restricted",	      OPT_SPECIAL,		 RESTRICTED},
-{NULL, "rmstarsilent",	      OPT_BOURNE,		 RMSTARSILENT},
-{NULL, "rmstarwait",	      0,			 RMSTARWAIT},
-{NULL, "sharehistory",	      OPT_KSH,			 SHAREHISTORY},
-{NULL, "shfileexpansion",     OPT_EMULATE|OPT_BOURNE,	 SHFILEEXPANSION},
-{NULL, "shglob",	      OPT_EMULATE|OPT_BOURNE,	 SHGLOB},
-{NULL, "shinstdin",	      OPT_SPECIAL,		 SHINSTDIN},
-{NULL, "shnullcmd",           OPT_EMULATE|OPT_BOURNE,	 SHNULLCMD},
-{NULL, "shoptionletters",     OPT_EMULATE|OPT_BOURNE,	 SHOPTIONLETTERS},
-{NULL, "shortloops",	      OPT_EMULATE|OPT_NONBOURNE, SHORTLOOPS},
-{NULL, "shwordsplit",	      OPT_EMULATE|OPT_BOURNE,	 SHWORDSPLIT},
-{NULL, "singlecommand",	      OPT_SPECIAL,		 SINGLECOMMAND},
-{NULL, "singlelinezle",	      OPT_KSH,			 SINGLELINEZLE},
-{NULL, "sunkeyboardhack",     0,			 SUNKEYBOARDHACK},
-{NULL, "transientrprompt",    0,			 TRANSIENTRPROMPT},
-{NULL, "trapsasync",	      0,			 TRAPSASYNC},
-{NULL, "typesetsilent",	      OPT_EMULATE|OPT_BOURNE,	 TYPESETSILENT},
-{NULL, "unset",		      OPT_EMULATE|OPT_BSHELL,	 UNSET},
-{NULL, "verbose",	      0,			 VERBOSE},
-{NULL, "vi",		      0,			 VIMODE},
-{NULL, "warncreateglobal",    0,			 WARNCREATEGLOBAL},
-{NULL, "xtrace",	      0,			 XTRACE},
-{NULL, "zle",		      OPT_SPECIAL,		 USEZLE},
-{NULL, "braceexpand",	      OPT_ALIAS, /* ksh/bash */	 -IGNOREBRACES},
-{NULL, "dotglob",	      OPT_ALIAS, /* bash */	 GLOBDOTS},
-{NULL, "hashall",	      OPT_ALIAS, /* bash */	 HASHCMDS},
-{NULL, "histappend",	      OPT_ALIAS, /* bash */	 APPENDHISTORY},
-{NULL, "histexpand",	      OPT_ALIAS, /* bash */	 BANGHIST},
-{NULL, "log",		      OPT_ALIAS, /* ksh */	 -HISTNOFUNCTIONS},
-{NULL, "mailwarn",	      OPT_ALIAS, /* bash */	 MAILWARNING},
-{NULL, "onecmd",	      OPT_ALIAS, /* bash */	 SINGLECOMMAND},
-{NULL, "physical",	      OPT_ALIAS, /* ksh/bash */	 CHASELINKS},
-{NULL, "promptvars",	      OPT_ALIAS, /* bash */	 PROMPTSUBST},
-{NULL, "stdin",		      OPT_ALIAS, /* ksh */	 SHINSTDIN},
-{NULL, "trackall",	      OPT_ALIAS, /* ksh */	 HASHCMDS},
-{NULL, "dvorak",	      0,			 DVORAK},
-{NULL, NULL, 0, 0}
+{{NULL, "aliases",	      OPT_EMULATE|OPT_ALL},	 ALIASESOPT},
+{{NULL, "allexport",	      OPT_EMULATE},		 ALLEXPORT},
+{{NULL, "alwayslastprompt",   OPT_ALL},			 ALWAYSLASTPROMPT},
+{{NULL, "alwaystoend",	      0},			 ALWAYSTOEND},
+{{NULL, "appendhistory",      OPT_ALL},			 APPENDHISTORY},
+{{NULL, "autocd",	      OPT_EMULATE},		 AUTOCD},
+{{NULL, "autocontinue",	      0},			 AUTOCONTINUE},
+{{NULL, "autolist",	      OPT_ALL},			 AUTOLIST},
+{{NULL, "automenu",	      OPT_ALL},			 AUTOMENU},
+{{NULL, "autonamedirs",	      0},			 AUTONAMEDIRS},
+{{NULL, "autoparamkeys",      OPT_ALL},			 AUTOPARAMKEYS},
+{{NULL, "autoparamslash",     OPT_ALL},			 AUTOPARAMSLASH},
+{{NULL, "autopushd",	      0},			 AUTOPUSHD},
+{{NULL, "autoremoveslash",    OPT_ALL},			 AUTOREMOVESLASH},
+{{NULL, "autoresume",	      0},			 AUTORESUME},
+{{NULL, "badpattern",	      OPT_EMULATE|OPT_NONBOURNE},BADPATTERN},
+{{NULL, "banghist",	      OPT_NONBOURNE},		 BANGHIST},
+{{NULL, "bareglobqual",       OPT_EMULATE|OPT_ZSH},      BAREGLOBQUAL},
+{{NULL, "bashautolist",	      0},                        BASHAUTOLIST},
+{{NULL, "beep",		      OPT_ALL},			 BEEP},
+{{NULL, "bgnice",	      OPT_EMULATE|OPT_NONBOURNE},BGNICE},
+{{NULL, "braceccl",	      OPT_EMULATE},		 BRACECCL},
+{{NULL, "bsdecho",	      OPT_EMULATE|OPT_SH},	 BSDECHO},
+{{NULL, "caseglob",	      OPT_ALL},			 CASEGLOB},
+{{NULL, "cbases",	      0},			 CBASES},
+{{NULL, "cdablevars",	      OPT_EMULATE},		 CDABLEVARS},
+{{NULL, "chasedots",	      OPT_EMULATE},		 CHASEDOTS},
+{{NULL, "chaselinks",	      OPT_EMULATE},		 CHASELINKS},
+{{NULL, "checkjobs",	      OPT_EMULATE|OPT_ZSH},	 CHECKJOBS},
+{{NULL, "clobber",	      OPT_EMULATE|OPT_ALL},	 CLOBBER},
+{{NULL, "completealiases",    0},			 COMPLETEALIASES},
+{{NULL, "completeinword",     0},			 COMPLETEINWORD},
+{{NULL, "correct",	      0},			 CORRECT},
+{{NULL, "correctall",	      0},			 CORRECTALL},
+{{NULL, "cshjunkiehistory",   OPT_EMULATE|OPT_CSH},	 CSHJUNKIEHISTORY},
+{{NULL, "cshjunkieloops",     OPT_EMULATE|OPT_CSH},	 CSHJUNKIELOOPS},
+{{NULL, "cshjunkiequotes",    OPT_EMULATE|OPT_CSH},	 CSHJUNKIEQUOTES},
+{{NULL, "cshnullcmd",	      OPT_EMULATE|OPT_CSH},	 CSHNULLCMD},
+{{NULL, "cshnullglob",	      OPT_EMULATE|OPT_CSH},	 CSHNULLGLOB},
+{{NULL, "emacs",	      0},			 EMACSMODE},
+{{NULL, "equals",	      OPT_EMULATE|OPT_ZSH},	 EQUALS},
+{{NULL, "errexit",	      OPT_EMULATE},		 ERREXIT},
+{{NULL, "errreturn",	      OPT_EMULATE},		 ERRRETURN},
+{{NULL, "exec",		      OPT_ALL},			 EXECOPT},
+{{NULL, "extendedglob",	      OPT_EMULATE},		 EXTENDEDGLOB},
+{{NULL, "extendedhistory",    OPT_CSH},			 EXTENDEDHISTORY},
+{{NULL, "evallineno",	      OPT_EMULATE|OPT_ZSH},	 EVALLINENO},
+{{NULL, "flowcontrol",	      OPT_ALL},			 FLOWCONTROL},
+{{NULL, "functionargzero",    OPT_EMULATE|OPT_NONBOURNE},FUNCTIONARGZERO},
+{{NULL, "glob",		      OPT_EMULATE|OPT_ALL},	 GLOBOPT},
+{{NULL, "globalexport",       OPT_EMULATE|OPT_ZSH},	 GLOBALEXPORT},
+{{NULL, "globalrcs",          OPT_ALL},			 GLOBALRCS},
+{{NULL, "globassign",	      OPT_EMULATE|OPT_CSH},	 GLOBASSIGN},
+{{NULL, "globcomplete",	      0},			 GLOBCOMPLETE},
+{{NULL, "globdots",	      OPT_EMULATE},		 GLOBDOTS},
+{{NULL, "globsubst",	      OPT_EMULATE|OPT_NONZSH},	 GLOBSUBST},
+{{NULL, "hashcmds",	      OPT_ALL},			 HASHCMDS},
+{{NULL, "hashdirs",	      OPT_ALL},			 HASHDIRS},
+{{NULL, "hashlistall",	      OPT_ALL},			 HASHLISTALL},
+{{NULL, "histallowclobber",   0},			 HISTALLOWCLOBBER},
+{{NULL, "histbeep",	      OPT_ALL},			 HISTBEEP},
+{{NULL, "histexpiredupsfirst",0},			 HISTEXPIREDUPSFIRST},
+{{NULL, "histfindnodups",     0},			 HISTFINDNODUPS},
+{{NULL, "histignorealldups",  0},			 HISTIGNOREALLDUPS},
+{{NULL, "histignoredups",     0},			 HISTIGNOREDUPS},
+{{NULL, "histignorespace",    0},			 HISTIGNORESPACE},
+{{NULL, "histnofunctions",    0},			 HISTNOFUNCTIONS},
+{{NULL, "histnostore",	      0},			 HISTNOSTORE},
+{{NULL, "histreduceblanks",   0},			 HISTREDUCEBLANKS},
+{{NULL, "histsavebycopy",     OPT_ALL},			 HISTSAVEBYCOPY},
+{{NULL, "histsavenodups",     0},			 HISTSAVENODUPS},
+{{NULL, "histverify",	      0},			 HISTVERIFY},
+{{NULL, "hup",		      OPT_EMULATE|OPT_ZSH},	 HUP},
+{{NULL, "ignorebraces",	      OPT_EMULATE|OPT_SH},	 IGNOREBRACES},
+{{NULL, "ignoreeof",	      0},			 IGNOREEOF},
+{{NULL, "incappendhistory",   0},			 INCAPPENDHISTORY},
+{{NULL, "interactive",	      OPT_SPECIAL},		 INTERACTIVE},
+{{NULL, "interactivecomments",OPT_BOURNE},		 INTERACTIVECOMMENTS},
+{{NULL, "ksharrays",	      OPT_EMULATE|OPT_BOURNE},	 KSHARRAYS},
+{{NULL, "kshautoload",	      OPT_EMULATE|OPT_BOURNE},	 KSHAUTOLOAD},
+{{NULL, "kshglob",            OPT_EMULATE|OPT_KSH},      KSHGLOB},
+{{NULL, "kshoptionprint",     OPT_EMULATE|OPT_KSH},	 KSHOPTIONPRINT},
+{{NULL, "kshtypeset",         OPT_EMULATE|OPT_KSH},	 KSHTYPESET},
+{{NULL, "listambiguous",      OPT_ALL},			 LISTAMBIGUOUS},
+{{NULL, "listbeep",	      OPT_ALL},			 LISTBEEP},
+{{NULL, "listpacked",	      0},			 LISTPACKED},
+{{NULL, "listrowsfirst",      0},			 LISTROWSFIRST},
+{{NULL, "listtypes",	      OPT_ALL},			 LISTTYPES},
+{{NULL, "localoptions",	      OPT_EMULATE|OPT_KSH},	 LOCALOPTIONS},
+{{NULL, "localtraps",	      OPT_EMULATE|OPT_KSH},	 LOCALTRAPS},
+{{NULL, "login",	      OPT_SPECIAL},		 LOGINSHELL},
+{{NULL, "longlistjobs",	      0},			 LONGLISTJOBS},
+{{NULL, "magicequalsubst",    OPT_EMULATE},		 MAGICEQUALSUBST},
+{{NULL, "mailwarning",	      0},			 MAILWARNING},
+{{NULL, "markdirs",	      0},			 MARKDIRS},
+{{NULL, "menucomplete",	      0},			 MENUCOMPLETE},
+{{NULL, "monitor",	      OPT_SPECIAL},		 MONITOR},
+{{NULL, "multios",	      OPT_EMULATE|OPT_ZSH},	 MULTIOS},
+{{NULL, "nomatch",	      OPT_EMULATE|OPT_NONBOURNE},NOMATCH},
+{{NULL, "notify",	      OPT_ZSH},			 NOTIFY},
+{{NULL, "nullglob",	      OPT_EMULATE},		 NULLGLOB},
+{{NULL, "numericglobsort",    OPT_EMULATE},		 NUMERICGLOBSORT},
+{{NULL, "octalzeroes",        OPT_EMULATE|OPT_SH},	 OCTALZEROES},
+{{NULL, "overstrike",	      0},			 OVERSTRIKE},
+{{NULL, "pathdirs",	      OPT_EMULATE},		 PATHDIRS},
+{{NULL, "posixbuiltins",      OPT_EMULATE|OPT_BOURNE},	 POSIXBUILTINS},
+{{NULL, "printeightbit",      0},                        PRINTEIGHTBIT},
+{{NULL, "printexitvalue",     0},			 PRINTEXITVALUE},
+{{NULL, "privileged",	      OPT_SPECIAL},		 PRIVILEGED},
+{{NULL, "promptbang",	      OPT_KSH},			 PROMPTBANG},
+{{NULL, "promptcr",	      OPT_ALL},			 PROMPTCR},
+{{NULL, "promptpercent",      OPT_NONBOURNE},		 PROMPTPERCENT},
+{{NULL, "promptsp",	      OPT_ALL},			 PROMPTSP},
+{{NULL, "promptsubst",	      OPT_KSH},			 PROMPTSUBST},
+{{NULL, "pushdignoredups",    OPT_EMULATE},		 PUSHDIGNOREDUPS},
+{{NULL, "pushdminus",	      OPT_EMULATE},		 PUSHDMINUS},
+{{NULL, "pushdsilent",	      0},			 PUSHDSILENT},
+{{NULL, "pushdtohome",	      OPT_EMULATE},		 PUSHDTOHOME},
+{{NULL, "rcexpandparam",      OPT_EMULATE},		 RCEXPANDPARAM},
+{{NULL, "rcquotes",	      OPT_EMULATE},		 RCQUOTES},
+{{NULL, "rcs",		      OPT_ALL},			 RCS},
+{{NULL, "recexact",	      0},			 RECEXACT},
+{{NULL, "restricted",	      OPT_SPECIAL},		 RESTRICTED},
+{{NULL, "rmstarsilent",	      OPT_BOURNE},		 RMSTARSILENT},
+{{NULL, "rmstarwait",	      0},			 RMSTARWAIT},
+{{NULL, "sharehistory",	      OPT_KSH},			 SHAREHISTORY},
+{{NULL, "shfileexpansion",    OPT_EMULATE|OPT_BOURNE},	 SHFILEEXPANSION},
+{{NULL, "shglob",	      OPT_EMULATE|OPT_BOURNE},	 SHGLOB},
+{{NULL, "shinstdin",	      OPT_SPECIAL},		 SHINSTDIN},
+{{NULL, "shnullcmd",          OPT_EMULATE|OPT_BOURNE},	 SHNULLCMD},
+{{NULL, "shoptionletters",    OPT_EMULATE|OPT_BOURNE},	 SHOPTIONLETTERS},
+{{NULL, "shortloops",	      OPT_EMULATE|OPT_NONBOURNE},SHORTLOOPS},
+{{NULL, "shwordsplit",	      OPT_EMULATE|OPT_BOURNE},	 SHWORDSPLIT},
+{{NULL, "singlecommand",      OPT_SPECIAL},		 SINGLECOMMAND},
+{{NULL, "singlelinezle",      OPT_KSH},			 SINGLELINEZLE},
+{{NULL, "sunkeyboardhack",    0},			 SUNKEYBOARDHACK},
+{{NULL, "transientrprompt",   0},			 TRANSIENTRPROMPT},
+{{NULL, "trapsasync",	      0},			 TRAPSASYNC},
+{{NULL, "typesetsilent",      OPT_EMULATE|OPT_BOURNE},	 TYPESETSILENT},
+{{NULL, "unset",	      OPT_EMULATE|OPT_BSHELL},	 UNSET},
+{{NULL, "verbose",	      0},			 VERBOSE},
+{{NULL, "vi",		      0},			 VIMODE},
+{{NULL, "warncreateglobal",   0},			 WARNCREATEGLOBAL},
+{{NULL, "xtrace",	      0},			 XTRACE},
+{{NULL, "zle",		      OPT_SPECIAL},		 USEZLE},
+{{NULL, "braceexpand",	      OPT_ALIAS}, /* ksh/bash */ -IGNOREBRACES},
+{{NULL, "dotglob",	      OPT_ALIAS}, /* bash */	 GLOBDOTS},
+{{NULL, "hashall",	      OPT_ALIAS}, /* bash */	 HASHCMDS},
+{{NULL, "histappend",	      OPT_ALIAS}, /* bash */	 APPENDHISTORY},
+{{NULL, "histexpand",	      OPT_ALIAS}, /* bash */	 BANGHIST},
+{{NULL, "log",		      OPT_ALIAS}, /* ksh */	 -HISTNOFUNCTIONS},
+{{NULL, "mailwarn",	      OPT_ALIAS}, /* bash */	 MAILWARNING},
+{{NULL, "onecmd",	      OPT_ALIAS}, /* bash */	 SINGLECOMMAND},
+{{NULL, "physical",	      OPT_ALIAS}, /* ksh/bash */ CHASELINKS},
+{{NULL, "promptvars",	      OPT_ALIAS}, /* bash */	 PROMPTSUBST},
+{{NULL, "stdin",	      OPT_ALIAS}, /* ksh */	 SHINSTDIN},
+{{NULL, "trackall",	      OPT_ALIAS}, /* ksh */	 HASHCMDS},
+{{NULL, "dvorak",	      0},			 DVORAK},
+{{NULL, NULL, 0}, 0}
 };
 
 /* Option letters */
@@ -404,13 +404,13 @@ printoptionnode(HashNode hn, int set)
 	optno = -optno;
     if (isset(KSHOPTIONPRINT)) {
 	if (defset(on))
-	    printf("no%-19s %s\n", on->nam, isset(optno) ? "off" : "on");
+	    printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
 	else
-	    printf("%-21s %s\n", on->nam, isset(optno) ? "on" : "off");
+	    printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
     } else if (set == (isset(optno) ^ defset(on))) {
 	if (set ^ isset(optno))
 	    fputs("no", stdout);
-	puts(on->nam);
+	puts(on->node.nam);
     }
 }
 
@@ -435,8 +435,8 @@ createoptiontable(void)
     optiontab->freenode    = NULL;
     optiontab->printnode   = printoptionnode;
 
-    for (on = optns; on->nam; on++)
-	optiontab->addnode(optiontab, on->nam, on);
+    for (on = optns; on->node.nam; on++)
+	optiontab->addnode(optiontab, on->node.nam, on);
 }
 
 /* Setting of default options */
@@ -451,9 +451,9 @@ setemulate(HashNode hn, int fully)
      * current emulation mode if either it is considered relevant   *
      * to emulation or we are doing a full emulation (as indicated  *
      * by the `fully' parameter).                                   */
-    if (!(on->flags & OPT_ALIAS) &&
-	((fully && !(on->flags & OPT_SPECIAL)) ||
-	 (on->flags & OPT_EMULATE)))
+    if (!(on->node.flags & OPT_ALIAS) &&
+	((fully && !(on->node.flags & OPT_SPECIAL)) ||
+	 (on->node.flags & OPT_EMULATE)))
 	opts[on->optno] = defset(on);
 }
 
@@ -625,7 +625,7 @@ restrictparam(char *nam)
     Param pm = (Param) paramtab->getnode(paramtab, nam);
 
     if (pm) {
-	pm->flags |= PM_SPECIAL | PM_RESTRICTED;
+	pm->node.flags |= PM_SPECIAL | PM_RESTRICTED;
 	return;
     }
     createparam(nam, PM_SCALAR | PM_UNSET | PM_SPECIAL | PM_RESTRICTED);
@@ -734,12 +734,12 @@ printoptionnodestate(HashNode hn, int hadplus)
 
     if (hadplus) {
         if (defset(on) != isset(optno))
-	    printf("set -o %s%s\n", defset(on) ? "no" : "", on->nam);
+	    printf("set -o %s%s\n", defset(on) ? "no" : "", on->node.nam);
     } else {
 	if (defset(on))
-	    printf("no%-19s %s\n", on->nam, isset(optno) ? "off" : "on");
+	    printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");
 	else
-	    printf("%-21s %s\n", on->nam, isset(optno) ? "on" : "off");
+	    printf("%-21s %s\n", on->node.nam, isset(optno) ? "on" : "off");
     }
 }
 
@@ -771,11 +771,11 @@ printoptionlist_printoption(HashNode hn, UNUSED(int ignored))
 {
     Optname on = (Optname) hn;
 
-    if(on->flags & OPT_ALIAS) {
-	printf("  --%-19s  ", on->nam);
+    if(on->node.flags & OPT_ALIAS) {
+	printf("  --%-19s  ", on->node.nam);
 	printoptionlist_printequiv(on->optno);
     } else
-	printf("  --%s\n", on->nam);
+	printf("  --%s\n", on->node.nam);
 }
 
 /**/
@@ -785,5 +785,5 @@ printoptionlist_printequiv(int optno)
     int isneg = optno < 0;
 
     optno *= (isneg ? -1 : 1);
-    printf("  equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].nam);
+    printf("  equivalent to --%s%s\n", isneg ? "no-" : "", optns[optno-1].node.nam);
 }
diff --git a/Src/params.c b/Src/params.c
index 135c40f1d..e2550fbf1 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -240,7 +240,7 @@ typedef struct iparam {
 static initparam special_params[] ={
 #define GSU(X) BR((GsuScalar)(void *)(&(X)))
 #define NULL_GSU BR((GsuScalar)(void *)NULL)
-#define IPDEF1(A,B,C) {NULL,A,PM_INTEGER|PM_SPECIAL|C,BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
+#define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
 IPDEF1("#", pound_gsu, PM_READONLY),
 IPDEF1("ERRNO", errno_gsu, 0),
 IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
@@ -253,7 +253,7 @@ IPDEF1("UID", uid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("EUID", euid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("TTYIDLE", ttyidle_gsu, PM_READONLY),
 
-#define IPDEF2(A,B,C) {NULL,A,PM_SCALAR|PM_SPECIAL|C,BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
+#define IPDEF2(A,B,C) {{NULL,A,PM_SCALAR|PM_SPECIAL|C},BR(NULL),GSU(B),0,0,NULL,NULL,NULL,0}
 IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
 IPDEF2("-", dash_gsu, PM_READONLY),
 IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
@@ -284,7 +284,7 @@ LCIPDEF("LC_TIME"),
 # endif
 #endif /* USE_LOCALE */
 
-#define IPDEF4(A,B) {NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL,BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
+#define IPDEF4(A,B) {{NULL,A,PM_INTEGER|PM_READONLY|PM_SPECIAL},BR((void *)B),GSU(varint_readonly_gsu),10,0,NULL,NULL,NULL,0}
 IPDEF4("!", &lastpid),
 IPDEF4("$", &mypid),
 IPDEF4("?", &lastval),
@@ -292,14 +292,14 @@ IPDEF4("HISTCMD", &curhist),
 IPDEF4("LINENO", &lineno),
 IPDEF4("PPID", &ppid),
 
-#define IPDEF5(A,B,F) {NULL,A,PM_INTEGER|PM_SPECIAL,BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0}
+#define IPDEF5(A,B,F) {{NULL,A,PM_INTEGER|PM_SPECIAL},BR((void *)B),GSU(varinteger_gsu),10,0,NULL,NULL,NULL,0}
 IPDEF5("COLUMNS", &columns, zlevar_gsu),
 IPDEF5("LINES", &lines, zlevar_gsu),
 IPDEF5("OPTIND", &zoptind, varinteger_gsu),
 IPDEF5("SHLVL", &shlvl, varinteger_gsu),
 IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
 
-#define IPDEF7(A,B) {NULL,A,PM_SCALAR|PM_SPECIAL,BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
+#define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
 IPDEF7("OPTARG", &zoptarg),
 IPDEF7("NULLCMD", &nullcmd),
 IPDEF7("POSTEDIT", &postedit),
@@ -315,7 +315,7 @@ IPDEF7("PS4", &prompt4),
 IPDEF7("SPROMPT", &sprompt),
 IPDEF7("0", &argzero),
 
-#define IPDEF8(A,B,C,D) {NULL,A,D|PM_SCALAR|PM_SPECIAL,BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
+#define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
 IPDEF8("CDPATH", &cdpath, "cdpath", 0),
 IPDEF8("FIGNORE", &fignore, "fignore", 0),
 IPDEF8("FPATH", &fpath, "fpath", 0),
@@ -327,13 +327,13 @@ IPDEF8("PSVAR", &psvar, "psvar", 0),
 /* MODULE_PATH is not imported for security reasons */
 IPDEF8("MODULE_PATH", &module_path, "module_path", PM_DONTIMPORT|PM_RESTRICTED),
 
-#define IPDEF9F(A,B,C,D) {NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT,BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
+#define IPDEF9F(A,B,C,D) {{NULL,A,D|PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT},BR((void *)B),GSU(vararray_gsu),0,0,NULL,C,NULL,0}
 #define IPDEF9(A,B,C) IPDEF9F(A,B,C,0)
 IPDEF9F("*", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
 IPDEF9F("@", &pparams, NULL, PM_ARRAY|PM_SPECIAL|PM_DONTIMPORT|PM_READONLY),
-{NULL,NULL,0,BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
+{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
 
-#define IPDEF10(A,B) {NULL,A,PM_ARRAY|PM_SPECIAL,BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
+#define IPDEF10(A,B) {{NULL,A,PM_ARRAY|PM_SPECIAL},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
 
 /* The following parameters are not available in sh/ksh compatibility *
  * mode. All of these have sh compatible equivalents.                */
@@ -360,7 +360,7 @@ IPDEF9F("path", &path, "PATH", PM_RESTRICTED),
 
 IPDEF10("pipestatus", pipestatus_gsu),
 
-{NULL,NULL,0,BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
+{{NULL,NULL,0},BR(NULL),NULL_GSU,0,0,NULL,NULL,NULL,0},
 };
 
 /*
@@ -374,8 +374,8 @@ initparam argvparam_pm = IPDEF9F("", &pparams, NULL, \
 #undef BR
 
 #define IS_UNSET_VALUE(V) \
-	((V) && (!(V)->pm || ((V)->pm->flags & PM_UNSET) || \
-		 !(V)->pm->nam || !*(V)->pm->nam))
+	((V) && (!(V)->pm || ((V)->pm->node.flags & PM_UNSET) || \
+		 !(V)->pm->node.nam || !*(V)->pm->node.nam))
 
 static Param argvparam;
 
@@ -416,14 +416,14 @@ getparamnode(HashTable ht, char *nam)
     HashNode hn = gethashnode2(ht, nam);
     Param pm = (Param) hn;
 
-    if (pm && pm->u.str && (pm->flags & PM_AUTOLOAD)) {
+    if (pm && pm->u.str && (pm->node.flags & PM_AUTOLOAD)) {
 	char *mn = dupstring(pm->u.str);
 
 	if (!load_module(mn))
 	    return NULL;
 	hn = gethashnode2(ht, nam);
-	if (((Param) hn) == pm && (pm->flags & PM_AUTOLOAD)) {
-	    pm->flags &= ~PM_AUTOLOAD;
+	if (((Param) hn) == pm && (pm->node.flags & PM_AUTOLOAD)) {
+	    pm->node.flags &= ~PM_AUTOLOAD;
 	    zwarnnam(nam, "autoload failed", NULL, 0);
 	}
     }
@@ -441,9 +441,9 @@ scancopyparams(HashNode hn, UNUSED(int flags))
     /* Going into a real parameter, so always use permanent storage */
     Param pm = (Param)hn;
     Param tpm = (Param) zshcalloc(sizeof *tpm);
-    tpm->nam = ztrdup(pm->nam);
+    tpm->node.nam = ztrdup(pm->node.nam);
     copyparam(tpm, pm, 0);
-    addhashnode(outtable, tpm->nam, tpm);
+    addhashnode(outtable, tpm->node.nam, tpm);
 }
 
 /**/
@@ -503,23 +503,23 @@ scanparamvals(HashNode hn, int flags)
 	return;
     v.pm = (Param)hn;
     if ((flags & SCANPM_KEYMATCH)) {
-	char *tmp = dupstring(v.pm->nam);
+	char *tmp = dupstring(v.pm->node.nam);
 
 	tokenize(tmp);
 	remnulargs(tmp);
 
 	if (!(prog = patcompile(tmp, 0, NULL)) || !pattry(prog, scanstr))
 	    return;
-    } else if ((flags & SCANPM_MATCHKEY) && !pattry(scanprog, v.pm->nam)) {
+    } else if ((flags & SCANPM_MATCHKEY) && !pattry(scanprog, v.pm->node.nam)) {
 	return;
     }
     foundparam = v.pm;
     if (flags & SCANPM_WANTKEYS) {
-	paramvals[numparamvals++] = v.pm->nam;
+	paramvals[numparamvals++] = v.pm->node.nam;
 	if (!(flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)))
 	    return;
     }
-    v.isarr = (PM_TYPE(v.pm->flags) & (PM_ARRAY|PM_HASHED));
+    v.isarr = (PM_TYPE(v.pm->node.flags) & (PM_ARRAY|PM_HASHED));
     v.inv = 0;
     v.start = 0;
     v.end = -1;
@@ -559,9 +559,9 @@ getvaluearr(Value v)
 {
     if (v->arr)
 	return v->arr;
-    else if (PM_TYPE(v->pm->flags) == PM_ARRAY)
+    else if (PM_TYPE(v->pm->node.flags) == PM_ARRAY)
 	return v->arr = v->pm->gsu.a->getfn(v->pm);
-    else if (PM_TYPE(v->pm->flags) == PM_HASHED) {
+    else if (PM_TYPE(v->pm->node.flags) == PM_HASHED) {
 	v->arr = paramvalarr(v->pm->gsu.h->getfn(v->pm), v->isarr);
 	/* Can't take numeric slices of associative arrays */
 	v->start = 0;
@@ -621,11 +621,11 @@ createparamtable(void)
     paramtab = realparamtab = newparamtable(151, "paramtab");
 
     /* Add the special parameters to the hash table */
-    for (ip = special_params; ip->nam; ip++)
-	paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
+    for (ip = special_params; ip->node.nam; ip++)
+	paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
     if (emulation != EMULATE_SH && emulation != EMULATE_KSH)
-	while ((++ip)->nam)
-	    paramtab->addnode(paramtab, ztrdup(ip->nam), ip);
+	while ((++ip)->node.nam)
+	    paramtab->addnode(paramtab, ztrdup(ip->node.nam), ip);
 
     argvparam = (Param) &argvparam_pm;
 
@@ -673,12 +673,12 @@ createparamtable(void)
 	if (split_env_string(*envp2, &iname, &ivalue)) {
 	    if (!idigit(*iname) && isident(iname) && !strchr(iname, '[')) {
 		if ((!(pm = (Param) paramtab->getnode(paramtab, iname)) ||
-		     !(pm->flags & PM_DONTIMPORT || pm->flags & PM_EXPORTED)) &&
+		     !(pm->node.flags & PM_DONTIMPORT || pm->node.flags & PM_EXPORTED)) &&
 		    (pm = setsparam(iname, metafy(ivalue, -1, META_DUP)))) {
-		    pm->flags |= PM_EXPORTED;
-		    if (pm->flags & PM_SPECIAL)
-			pm->env = mkenvstr (pm->nam,
-					    getsparam(pm->nam), pm->flags);
+		    pm->node.flags |= PM_EXPORTED;
+		    if (pm->node.flags & PM_SPECIAL)
+			pm->env = mkenvstr (pm->node.nam,
+					    getsparam(pm->node.nam), pm->node.flags);
 		    else
 			pm->env = ztrdup(*envp2);
 		    *envp++ = pm->env;
@@ -697,12 +697,12 @@ createparamtable(void)
 	 * (see setupvals()).
 	 */
 	pm = (Param) paramtab->getnode(paramtab, "HOME");
-	pm->flags &= ~PM_UNSET;
-	if (!(pm->flags & PM_EXPORTED))
+	pm->node.flags &= ~PM_UNSET;
+	if (!(pm->node.flags & PM_EXPORTED))
 	    addenv(pm, home);
     }
     pm = (Param) paramtab->getnode(paramtab, "LOGNAME");
-    if (!(pm->flags & PM_EXPORTED))
+    if (!(pm->node.flags & PM_EXPORTED))
 	addenv(pm, pm->u.str);
     pm = (Param) paramtab->getnode(paramtab, "SHLVL");
     sprintf(buf, "%d", (int)++shlvl);
@@ -740,7 +740,7 @@ createparamtable(void)
 mod_export void
 assigngetset(Param pm)
 {
-    switch (PM_TYPE(pm->flags)) {
+    switch (PM_TYPE(pm->node.flags)) {
     case PM_SCALAR:
 	pm->gsu.s = &stdscalar_gsu;
 	break;
@@ -788,17 +788,17 @@ createparam(char *name, int flags)
 	DPUTS(oldpm && oldpm->level > locallevel,
 	      "BUG: old local parameter not deleted");
 	if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
-	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
-		oldpm->flags &= ~PM_UNSET;
-		if ((oldpm->flags & PM_SPECIAL) && oldpm->ename) {
+	    if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL)) {
+		oldpm->node.flags &= ~PM_UNSET;
+		if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) {
 		    Param altpm = 
 			(Param) paramtab->getnode(paramtab, oldpm->ename);
 		    if (altpm)
-			altpm->flags &= ~PM_UNSET;
+			altpm->node.flags &= ~PM_UNSET;
 		}
 		return NULL;
 	    }
-	    if ((oldpm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	    if ((oldpm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
 		zerr("%s: restricted", name, 0);
 		return NULL;
 	    }
@@ -824,11 +824,11 @@ createparam(char *name, int flags)
 	    flags |= PM_EXPORTED;
     } else {
 	pm = (Param) hcalloc(sizeof *pm);
-	pm->nam = nulstring;
+	pm->node.nam = nulstring;
     }
-    pm->flags = flags & ~PM_LOCAL;
+    pm->node.flags = flags & ~PM_LOCAL;
 
-    if(!(pm->flags & PM_SPECIAL))
+    if(!(pm->node.flags & PM_SPECIAL))
 	assigngetset(pm);
     return pm;
 }
@@ -845,12 +845,12 @@ copyparam(Param tpm, Param pm, int toplevel)
      * to set the parameter, so must be permanently allocated (in accordance
      * with sets.?fn() usage).
      */
-    tpm->flags = pm->flags;
+    tpm->node.flags = pm->node.flags;
     tpm->base = pm->base;
     tpm->width = pm->width;
     if (!toplevel)
-	tpm->flags &= ~PM_SPECIAL;
-    switch (PM_TYPE(pm->flags)) {
+	tpm->node.flags &= ~PM_SPECIAL;
+    switch (PM_TYPE(pm->node.flags)) {
     case PM_SCALAR:
 	tpm->u.str = ztrdup(pm->gsu.s->getfn(pm));
 	break;
@@ -865,7 +865,7 @@ copyparam(Param tpm, Param pm, int toplevel)
 	tpm->u.arr = zarrdup(pm->gsu.a->getfn(pm));
 	break;
     case PM_HASHED:
-	tpm->u.hash = copyparamtable(pm->gsu.h->getfn(pm), pm->nam);
+	tpm->u.hash = copyparamtable(pm->gsu.h->getfn(pm), pm->node.nam);
 	break;
     }
     /*
@@ -928,7 +928,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w)
     zlong num = 1, beg = 0, r = 0;
     Patprog pprog = NULL;
 
-    ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
+    ishash = (v->pm && PM_TYPE(v->pm->node.flags) == PM_HASHED);
 
     /* first parse any subscription flags */
     if (v->pm && (*s == '(' || *s == Inpar)) {
@@ -1093,7 +1093,7 @@ getarg(char **str, int *inv, Value v, int a2, zlong *w)
 	if (ishash) {
 	    HashTable ht = v->pm->gsu.h->getfn(v->pm);
 	    if (!ht) {
-		ht = newparamtable(17, v->pm->nam);
+		ht = newparamtable(17, v->pm->node.nam);
 		v->pm->gsu.h->setfn(v->pm, ht);
 	    }
 	    untokenize(s);
@@ -1352,7 +1352,7 @@ getindex(char **pptr, Value v, int dq)
 		} else
 		    start = -ztrlen(t + start + strlen(t));
 	    }
-	    if (start > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED)))
+	    if (start > 0 && (isset(KSHARRAYS) || (v->pm->node.flags & PM_HASHED)))
 		start--;
 	    if (v->isarr != SCANPM_WANTINDEX) {
 		v->inv = 1;
@@ -1465,13 +1465,13 @@ fetchvalue(Value v, char **pptr, int bracks, int flags)
 	if (sav)
 	    *s = sav;
 	*pptr = s;
-	if (!pm || (pm->flags & PM_UNSET))
+	if (!pm || (pm->node.flags & PM_UNSET))
 	    return NULL;
 	if (v)
 	    memset(v, 0, sizeof(*v));
 	else
 	    v = (Value) hcalloc(sizeof *v);
-	if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) {
+	if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
 	    /* Overload v->isarr as the flag bits for hashed arrays. */
 	    v->isarr = flags | (isvarat ? SCANPM_ISVAR_AT : 0);
 	    /* If no flags were passed, we need something to represent *
@@ -1526,13 +1526,13 @@ getstrvalue(Value v)
     if (!v)
 	return hcalloc(1);
 
-    if (v->inv && !(v->pm->flags & PM_HASHED)) {
+    if (v->inv && !(v->pm->node.flags & PM_HASHED)) {
 	sprintf(buf, "%d", v->start);
 	s = dupstring(buf);
 	return s;
     }
 
-    switch(PM_TYPE(v->pm->flags)) {
+    switch(PM_TYPE(v->pm->node.flags)) {
     case PM_HASHED:
 	/* (!v->isarr) should be impossible unless emulating ksh */
 	if (!v->isarr && emulation == EMULATE_KSH) {
@@ -1559,7 +1559,7 @@ getstrvalue(Value v)
     case PM_EFLOAT:
     case PM_FFLOAT:
 	s = convfloat(v->pm->gsu.f->getfn(v->pm),
-		      v->pm->base, v->pm->flags, NULL);
+		      v->pm->base, v->pm->node.flags, NULL);
 	break;
     case PM_SCALAR:
 	s = v->pm->gsu.s->getfn(v->pm);
@@ -1635,9 +1635,9 @@ getintvalue(Value v)
 	return 0;
     if (v->inv)
 	return v->start;
-    if (PM_TYPE(v->pm->flags) == PM_INTEGER)
+    if (PM_TYPE(v->pm->node.flags) == PM_INTEGER)
 	return v->pm->gsu.i->getfn(v->pm);
-    if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT))
+    if (v->pm->node.flags & (PM_EFLOAT|PM_FFLOAT))
 	return (zlong)v->pm->gsu.f->getfn(v->pm);
     return mathevali(getstrvalue(v));
 }
@@ -1653,9 +1653,9 @@ getnumvalue(Value v)
 	mn.u.l = 0;
     } else if (v->inv) {
 	mn.u.l = v->start;
-    } else if (PM_TYPE(v->pm->flags) == PM_INTEGER) {
+    } else if (PM_TYPE(v->pm->node.flags) == PM_INTEGER) {
 	mn.u.l = v->pm->gsu.i->getfn(v->pm);
-    } else if (v->pm->flags & (PM_EFLOAT|PM_FFLOAT)) {
+    } else if (v->pm->node.flags & (PM_EFLOAT|PM_FFLOAT)) {
 	mn.type = MN_FLOAT;
 	mn.u.d = v->pm->gsu.f->getfn(v->pm);
     } else
@@ -1669,7 +1669,7 @@ export_param(Param pm)
 {
     char buf[BDIGBUFSIZE], *val;
 
-    if (PM_TYPE(pm->flags) & (PM_ARRAY|PM_HASHED)) {
+    if (PM_TYPE(pm->node.flags) & (PM_ARRAY|PM_HASHED)) {
 #if 0	/* Requires changes elsewhere in params.c and builtin.c */
 	if (emulation == EMULATE_KSH /* isset(KSHARRAYS) */) {
 	    struct value v;
@@ -1681,11 +1681,11 @@ export_param(Param pm)
 	} else
 #endif
 	    return;
-    } else if (PM_TYPE(pm->flags) == PM_INTEGER)
+    } else if (PM_TYPE(pm->node.flags) == PM_INTEGER)
 	convbase(val = buf, pm->gsu.i->getfn(pm), pm->base);
-    else if (pm->flags & (PM_EFLOAT|PM_FFLOAT))
+    else if (pm->node.flags & (PM_EFLOAT|PM_FFLOAT))
 	val = convfloat(pm->gsu.f->getfn(pm), pm->base,
-			pm->flags, NULL);
+			pm->node.flags, NULL);
     else
 	val = pm->gsu.s->getfn(pm);
 
@@ -1696,27 +1696,27 @@ export_param(Param pm)
 mod_export void
 setstrvalue(Value v, char *val)
 {
-    if (v->pm->flags & PM_READONLY) {
-	zerr("read-only variable: %s", v->pm->nam, 0);
+    if (v->pm->node.flags & PM_READONLY) {
+	zerr("read-only variable: %s", v->pm->node.nam, 0);
 	zsfree(val);
 	return;
     }
-    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
-	zerr("%s: restricted", v->pm->nam, 0);
+    if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	zerr("%s: restricted", v->pm->node.nam, 0);
 	zsfree(val);
 	return;
     }
-    if ((v->pm->flags & PM_HASHED) && (v->isarr & SCANPM_MATCHMANY)) {
-	zerr("%s: attempt to set slice of associative array", v->pm->nam, 0);
+    if ((v->pm->node.flags & PM_HASHED) && (v->isarr & SCANPM_MATCHMANY)) {
+	zerr("%s: attempt to set slice of associative array", v->pm->node.nam, 0);
 	zsfree(val);
 	return;
     }
-    v->pm->flags &= ~PM_UNSET;
-    switch (PM_TYPE(v->pm->flags)) {
+    v->pm->node.flags &= ~PM_UNSET;
+    switch (PM_TYPE(v->pm->node.flags)) {
     case PM_SCALAR:
 	if (v->start == 0 && v->end == -1) {
 	    v->pm->gsu.s->setfn(v->pm, val);
-	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
+	    if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
 		!v->pm->width)
 		v->pm->width = strlen(val);
 	} else {
@@ -1750,7 +1750,7 @@ setstrvalue(Value v, char *val)
 	if (val) {
 	    v->pm->gsu.i->setfn(v->pm, mathevali(val));
 	    zsfree(val);
-	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
+	    if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
 		!v->pm->width)
 		v->pm->width = strlen(val);
 	}
@@ -1764,7 +1764,7 @@ setstrvalue(Value v, char *val)
 	    v->pm->gsu.f->setfn(v->pm, (mn.type & MN_FLOAT) ? mn.u.d :
 			       (double)mn.u.l);
 	    zsfree(val);
-	    if ((v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
+	    if ((v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) &&
 		!v->pm->width)
 		v->pm->width = strlen(val);
 	}
@@ -1784,9 +1784,9 @@ setstrvalue(Value v, char *val)
         }
 	break;
     }
-    if ((!v->pm->env && !(v->pm->flags & PM_EXPORTED) &&
-	 !(isset(ALLEXPORT) && !(v->pm->flags & PM_HASHELEM))) ||
-	(v->pm->flags & PM_ARRAY) || v->pm->ename)
+    if ((!v->pm->env && !(v->pm->node.flags & PM_EXPORTED) &&
+	 !(isset(ALLEXPORT) && !(v->pm->node.flags & PM_HASHELEM))) ||
+	(v->pm->node.flags & PM_ARRAY) || v->pm->ename)
 	return;
     export_param(v->pm);
 }
@@ -1797,15 +1797,15 @@ setnumvalue(Value v, mnumber val)
 {
     char buf[BDIGBUFSIZE], *p;
 
-    if (v->pm->flags & PM_READONLY) {
-	zerr("read-only variable: %s", v->pm->nam, 0);
+    if (v->pm->node.flags & PM_READONLY) {
+	zerr("read-only variable: %s", v->pm->node.nam, 0);
 	return;
     }
-    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
-	zerr("%s: restricted", v->pm->nam, 0);
+    if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	zerr("%s: restricted", v->pm->node.nam, 0);
 	return;
     }
-    switch (PM_TYPE(v->pm->flags)) {
+    switch (PM_TYPE(v->pm->node.flags)) {
     case PM_SCALAR:
     case PM_ARRAY:
 	if ((val.type & MN_INTEGER) || outputradix) {
@@ -1834,38 +1834,38 @@ setnumvalue(Value v, mnumber val)
 mod_export void
 setarrvalue(Value v, char **val)
 {
-    if (v->pm->flags & PM_READONLY) {
-	zerr("read-only variable: %s", v->pm->nam, 0);
+    if (v->pm->node.flags & PM_READONLY) {
+	zerr("read-only variable: %s", v->pm->node.nam, 0);
 	freearray(val);
 	return;
     }
-    if ((v->pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
-	zerr("%s: restricted", v->pm->nam, 0);
+    if ((v->pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	zerr("%s: restricted", v->pm->node.nam, 0);
 	freearray(val);
 	return;
     }
-    if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED))) {
+    if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED))) {
 	freearray(val);
 	zerr("%s: attempt to assign array value to non-array",
-	     v->pm->nam, 0);
+	     v->pm->node.nam, 0);
 	return;
     }
     if (v->start == 0 && v->end == -1) {
-	if (PM_TYPE(v->pm->flags) == PM_HASHED)
+	if (PM_TYPE(v->pm->node.flags) == PM_HASHED)
 	    arrhashsetfn(v->pm, val, 0);
 	else
 	    v->pm->gsu.a->setfn(v->pm, val);
     } else if (v->start == -1 && v->end == 0 &&
-    	    PM_TYPE(v->pm->flags) == PM_HASHED) {
+    	    PM_TYPE(v->pm->node.flags) == PM_HASHED) {
     	arrhashsetfn(v->pm, val, 1);
     } else {
 	char **old, **new, **p, **q, **r;
 	int n, ll, i;
 
-	if ((PM_TYPE(v->pm->flags) == PM_HASHED)) {
+	if ((PM_TYPE(v->pm->node.flags) == PM_HASHED)) {
 	    freearray(val);
 	    zerr("%s: attempt to set slice of associative array",
-		 v->pm->nam, 0);
+		 v->pm->node.nam, 0);
 	    return;
 	}
 	if (v->inv && unset(KSHARRAYS)) {
@@ -1964,7 +1964,7 @@ getaparam(char *s)
     Value v;
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
-	PM_TYPE(v->pm->flags) == PM_ARRAY)
+	PM_TYPE(v->pm->node.flags) == PM_ARRAY)
 	return v->pm->gsu.a->getfn(v->pm);
     return NULL;
 }
@@ -1979,7 +1979,7 @@ gethparam(char *s)
     Value v;
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
-	PM_TYPE(v->pm->flags) == PM_HASHED)
+	PM_TYPE(v->pm->node.flags) == PM_HASHED)
 	return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTVALS);
     return NULL;
 }
@@ -1994,7 +1994,7 @@ gethkparam(char *s)
     Value v;
 
     if (!idigit(*s) && (v = getvalue(&vbuf, &s, 0)) &&
-	PM_TYPE(v->pm->flags) == PM_HASHED)
+	PM_TYPE(v->pm->node.flags) == PM_HASHED)
 	return paramvalarr(v->pm->gsu.h->getfn(v->pm), SCANPM_WANTKEYS);
     return NULL;
 }
@@ -2029,9 +2029,9 @@ assignsparam(char *s, char *val, int flags)
     } else {
 	if (!(v = getvalue(&vbuf, &s, 1)))
 	    createparam(t, PM_SCALAR);
-	else if ((((v->pm->flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) ||
-	    	 (v->pm->flags & PM_HASHED)) &&
-		 !(v->pm->flags & (PM_SPECIAL|PM_TIED)) && 
+	else if ((((v->pm->node.flags & PM_ARRAY) && !(flags & ASSPM_AUGMENT)) ||
+	    	 (v->pm->node.flags & PM_HASHED)) &&
+		 !(v->pm->node.flags & (PM_SPECIAL|PM_TIED)) && 
 		 unset(KSHARRAYS)) {
 	    unsetparam(t);
 	    createparam(t, PM_SCALAR);
@@ -2047,10 +2047,10 @@ assignsparam(char *s, char *val, int flags)
     }
     if ((flags & ASSPM_WARN_CREATE) && v->pm->level == 0)
 	zwarn("scalar parameter %s created globally in function",
-	      v->pm->nam, 0);
+	      v->pm->node.nam, 0);
     if (flags & ASSPM_AUGMENT) {
 	if (v->start == 0 && v->end == -1) {
-	    switch (PM_TYPE(v->pm->flags)) {
+	    switch (PM_TYPE(v->pm->node.flags)) {
 	    case PM_SCALAR:
 		v->start = INT_MAX;  /* just append to scalar value */
 		break;
@@ -2086,7 +2086,7 @@ assignsparam(char *s, char *val, int flags)
 		break;
 	    }
 	} else {
-	    switch (PM_TYPE(v->pm->flags)) {
+	    switch (PM_TYPE(v->pm->node.flags)) {
 	    case PM_SCALAR:
     		if (v->end > 0)
 		    v->start = v->end;
@@ -2148,10 +2148,10 @@ assignaparam(char *s, char **val, int flags)
 	else
 	    flags &= ~ASSPM_WARN_CREATE;
 	*ss = '[';
-	if (v && PM_TYPE(v->pm->flags) == PM_HASHED) {
+	if (v && PM_TYPE(v->pm->node.flags) == PM_HASHED) {
 	    unqueue_signals();
 	    zerr("%s: attempt to set slice of associative array",
-		 v->pm->nam, 0);
+		 v->pm->node.nam, 0);
 	    freearray(val);
 	    errflag = 1;
 	    return NULL;
@@ -2160,9 +2160,9 @@ assignaparam(char *s, char **val, int flags)
     } else {
 	if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
 	    createparam(t, PM_ARRAY);
-	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
-		 !(v->pm->flags & (PM_SPECIAL|PM_TIED))) {
-	    int uniq = v->pm->flags & PM_UNIQUE;
+	else if (!(PM_TYPE(v->pm->node.flags) & (PM_ARRAY|PM_HASHED)) &&
+		 !(v->pm->node.flags & (PM_SPECIAL|PM_TIED))) {
+	    int uniq = v->pm->node.flags & PM_UNIQUE;
 	    if (flags & ASSPM_AUGMENT) {
 	    	/* insert old value at the beginning of the val array */
 		char **new;
@@ -2190,18 +2190,18 @@ assignaparam(char *s, char **val, int flags)
 
     if ((flags & ASSPM_WARN_CREATE) && v->pm->level == 0)
 	zwarn("array parameter %s created globally in function",
-	      v->pm->nam, 0);
+	      v->pm->node.nam, 0);
     if (flags & ASSPM_AUGMENT) {
     	if (v->start == 0 && v->end == -1) {
-	    if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
+	    if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
 	    	v->start = arrlen(v->pm->gsu.a->getfn(v->pm));
 	    	v->end = v->start + 1;
-	    } else if (PM_TYPE(v->pm->flags) & PM_HASHED)
+	    } else if (PM_TYPE(v->pm->node.flags) & PM_HASHED)
 	    	v->start = -1, v->end = 0;
 	} else {
 	    if (v->end > 0)
 		v->start = v->end--;
-	    else if (PM_TYPE(v->pm->flags) & PM_ARRAY) {
+	    else if (PM_TYPE(v->pm->node.flags) & PM_ARRAY) {
 		v->end = arrlen(v->pm->gsu.a->getfn(v->pm)) + v->end;
 		v->start = v->end + 1;
 	    }
@@ -2236,8 +2236,8 @@ sethparam(char *s, char **val)
     queue_signals();
     if (!(v = fetchvalue(&vbuf, &s, 1, SCANPM_ASSIGNING)))
 	createparam(t, PM_HASHED);
-    else if (!(PM_TYPE(v->pm->flags) & PM_HASHED) &&
-	     !(v->pm->flags & PM_SPECIAL)) {
+    else if (!(PM_TYPE(v->pm->node.flags) & PM_HASHED) &&
+	     !(v->pm->node.flags & PM_SPECIAL)) {
 	unsetparam(t);
 	createparam(t, PM_HASHED);
 	v = NULL;
@@ -2355,12 +2355,12 @@ unsetparam_pm(Param pm, int altflag, int exp)
     Param oldpm, altpm;
     char *altremove;
 
-    if ((pm->flags & PM_READONLY) && pm->level <= locallevel) {
-	zerr("read-only variable: %s", pm->nam, 0);
+    if ((pm->node.flags & PM_READONLY) && pm->level <= locallevel) {
+	zerr("read-only variable: %s", pm->node.nam, 0);
 	return 1;
     }
-    if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
-	zerr("%s: restricted", pm->nam, 0);
+    if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
+	zerr("%s: restricted", pm->node.nam, 0);
 	return 1;
     }
 
@@ -2369,7 +2369,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
     else
 	altremove = NULL;
 
-    if (!(pm->flags & PM_UNSET))
+    if (!(pm->node.flags & PM_UNSET))
 	pm->gsu.s->unsetfn(pm, exp);
     if (pm->env)
 	delenv(pm);
@@ -2409,21 +2409,21 @@ unsetparam_pm(Param pm, int altflag, int exp)
      * from the parameter table; they have the PM_REMOVABLE flag.
      */
     if ((pm->level && locallevel >= pm->level) ||
-	(pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
+	(pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
 	return 0;
 
     /* remove parameter node from table */
-    paramtab->removenode(paramtab, pm->nam);
+    paramtab->removenode(paramtab, pm->node.nam);
 
     if (pm->old) {
 	oldpm = pm->old;
-	paramtab->addnode(paramtab, oldpm->nam, oldpm);
-	if ((PM_TYPE(oldpm->flags) == PM_SCALAR) &&
-	    !(pm->flags & PM_HASHELEM) &&
-	    (oldpm->flags & PM_NAMEDDIR) &&
+	paramtab->addnode(paramtab, oldpm->node.nam, oldpm);
+	if ((PM_TYPE(oldpm->node.flags) == PM_SCALAR) &&
+	    !(pm->node.flags & PM_HASHELEM) &&
+	    (oldpm->node.flags & PM_NAMEDDIR) &&
 	    oldpm->gsu.s == &stdscalar_gsu)
-	    adduserdir(oldpm->nam, oldpm->u.str, 0, 0);
-	if (oldpm->flags & PM_EXPORTED) {
+	    adduserdir(oldpm->node.nam, oldpm->u.str, 0, 0);
+	if (oldpm->node.flags & PM_EXPORTED) {
 	    /*
 	     * Re-export the old value which we removed in typeset_single().
 	     * I don't think we need to test for ALL_EXPORT here, since if
@@ -2434,7 +2434,7 @@ unsetparam_pm(Param pm, int altflag, int exp)
 	}
     }
 
-    paramtab->freenode((HashNode) pm); /* free parameter node */
+    paramtab->freenode(&pm->node); /* free parameter node */
 
     return 0;
 }
@@ -2450,23 +2450,23 @@ unsetparam_pm(Param pm, int altflag, int exp)
 mod_export void
 stdunsetfn(Param pm, UNUSED(int exp))
 {
-    switch (PM_TYPE(pm->flags)) {
+    switch (PM_TYPE(pm->node.flags)) {
 	case PM_SCALAR: pm->gsu.s->setfn(pm, NULL); break;
 	case PM_ARRAY:  pm->gsu.a->setfn(pm, NULL); break;
 	case PM_HASHED: pm->gsu.h->setfn(pm, NULL); break;
 	default:
-	    if (!(pm->flags & PM_SPECIAL))
+	    if (!(pm->node.flags & PM_SPECIAL))
 	    	pm->u.str = NULL;
 	    break;
     }
-    if ((pm->flags & (PM_SPECIAL|PM_TIED)) == PM_TIED) {
+    if ((pm->node.flags & (PM_SPECIAL|PM_TIED)) == PM_TIED) {
 	if (pm->ename) {
 	    zsfree(pm->ename);
 	    pm->ename = NULL;
 	}
-	pm->flags &= ~PM_TIED;
+	pm->node.flags &= ~PM_TIED;
     }
-    pm->flags |= PM_UNSET;
+    pm->node.flags |= PM_UNSET;
 }
 
 /* Function to get value of an integer parameter */
@@ -2522,10 +2522,10 @@ strsetfn(Param pm, char *x)
 {
     zsfree(pm->u.str);
     pm->u.str = x;
-    if (!(pm->flags & PM_HASHELEM) &&
-	((pm->flags & PM_NAMEDDIR) || isset(AUTONAMEDIRS))) {
-	pm->flags |= PM_NAMEDDIR;
-	adduserdir(pm->nam, x, 0, 0);
+    if (!(pm->node.flags & PM_HASHELEM) &&
+	((pm->node.flags & PM_NAMEDDIR) || isset(AUTONAMEDIRS))) {
+	pm->node.flags |= PM_NAMEDDIR;
+	adduserdir(pm->node.nam, x, 0, 0);
     }
 }
 
@@ -2548,7 +2548,7 @@ arrsetfn(Param pm, char **x)
 {
     if (pm->u.arr && pm->u.arr != x)
 	freearray(pm->u.arr);
-    if (pm->flags & PM_UNIQUE)
+    if (pm->node.flags & PM_UNIQUE)
 	uniqarray(x);
     pm->u.arr = x;
     /* Arrays tied to colon-arrays may need to fix the environment */
@@ -2608,7 +2608,7 @@ arrhashsetfn(Param pm, char **val, int augment)
     }
     if (alen)
     	if (!(augment && (ht = paramtab = pm->gsu.h->getfn(pm))))
-	    ht = paramtab = newparamtable(17, pm->nam);
+	    ht = paramtab = newparamtable(17, pm->node.nam);
     while (*aptr) {
 	/* The parameter name is ztrdup'd... */
 	v->pm = createparam(*aptr, PM_SCALAR|PM_UNSET);
@@ -2745,14 +2745,14 @@ arrvarsetfn(Param pm, char **x)
 
     if (*dptr != x)
 	freearray(*dptr);
-    if (pm->flags & PM_UNIQUE)
+    if (pm->node.flags & PM_UNIQUE)
 	uniqarray(x);
     /*
      * Special tied arrays point to variables accessible in other
      * ways which need to be set to NULL.  We can't do this
      * with user tied variables since we can leak memory.
      */
-    if ((pm->flags & PM_SPECIAL) && !x)
+    if ((pm->node.flags & PM_SPECIAL) && !x)
 	*dptr = mkarray(NULL);
     else
 	*dptr = x;
@@ -2780,11 +2780,11 @@ colonarrsetfn(Param pm, char *x)
     if (*dptr)
 	freearray(*dptr);
     if (x)
-	*dptr = colonsplit(x, pm->flags & PM_UNIQUE);
+	*dptr = colonsplit(x, pm->node.flags & PM_UNIQUE);
     else
 	*dptr = mkarray(NULL);
     if (pm->ename)
-	arrfixenv(pm->nam, *dptr);
+	arrfixenv(pm->node.nam, *dptr);
     zsfree(x);
 }
 
@@ -2818,13 +2818,13 @@ tiedarrsetfn(Param pm, char *x)
 	    sepbuf[1] = '\0';
 	}
 	*dptr->arrptr = sepsplit(x, sepbuf, 0, 0);
-	if (pm->flags & PM_UNIQUE)
+	if (pm->node.flags & PM_UNIQUE)
 	    uniqarray(*dptr->arrptr);
 	zsfree(x);
     } else
 	*dptr->arrptr = NULL;
     if (pm->ename)
-	arrfixenv(pm->nam, *dptr->arrptr);
+	arrfixenv(pm->node.nam, *dptr->arrptr);
 }
 
 /**/
@@ -2842,8 +2842,8 @@ tiedarrunsetfn(Param pm, UNUSED(int exp))
     pm->u.data = NULL;
     zsfree(pm->ename);
     pm->ename = NULL;
-    pm->flags &= ~PM_TIED;
-    pm->flags |= PM_UNSET;
+    pm->node.flags &= ~PM_TIED;
+    pm->node.flags |= PM_UNSET;
 }
 
 /**/
@@ -2984,7 +2984,7 @@ setrawseconds(double x)
 int
 setsecondstype(Param pm, int on, int off)
 {
-    int newflags = (pm->flags | on) & ~off;
+    int newflags = (pm->node.flags | on) & ~off;
     int tp = PM_TYPE(newflags);
     /* Only one of the numeric types is allowed. */
     if (tp == PM_EFLOAT || tp == PM_FFLOAT)
@@ -2997,7 +2997,7 @@ setsecondstype(Param pm, int on, int off)
     }
     else
 	return 1;
-    pm->flags = newflags;
+    pm->node.flags = newflags;
     return 0;
 }
 
@@ -3219,7 +3219,7 @@ lcsetfn(Param pm, char *x)
 	x = getsparam("LANG");
 
     for (ln = lc_names; ln->name; ln++)
-	if (!strcmp(ln->name, pm->nam))
+	if (!strcmp(ln->name, pm->node.nam))
 	    setlocale(ln->category, x ? x : "");
     unqueue_signals();
 }
@@ -3451,20 +3451,20 @@ arrfixenv(char *s, char **t)
      * ALLEXPORT is set, this must be global.
      */
 
-    if (pm->flags & PM_HASHELEM)
+    if (pm->node.flags & PM_HASHELEM)
 	return;
 
     if (isset(ALLEXPORT))
-	pm->flags |= PM_EXPORTED;
+	pm->node.flags |= PM_EXPORTED;
 
     /*
      * Do not "fix" parameters that were not exported
      */
 
-    if (!(pm->flags & PM_EXPORTED))
+    if (!(pm->node.flags & PM_EXPORTED))
 	return;
 
-    if (pm->flags & PM_TIED)
+    if (pm->node.flags & PM_TIED)
 	joinchar = ((struct tieddata *)pm->u.data)->joinchar;
     else
 	joinchar = ':';
@@ -3567,10 +3567,10 @@ addenv(Param pm, char *value)
     /* First check if there is already an environment *
      * variable matching string `name'. If not, and   *
      * we are not requested to add new, return        */
-    if (findenv(pm->nam, &pos))
+    if (findenv(pm->node.nam, &pos))
 	oldenv = environ[pos];
 
-     newenv = mkenvstr(pm->nam, value, pm->flags);
+     newenv = mkenvstr(pm->node.nam, value, pm->node.flags);
      if (zputenv(newenv)) {
         zsfree(newenv);
 	pm->env = NULL;
@@ -3582,13 +3582,13 @@ addenv(Param pm, char *value)
      * silently reuse existing environment string. This tries to
      * check for both cases
      */
-    if (findenv(pm->nam, &pos)) {
+    if (findenv(pm->node.nam, &pos)) {
 	env = environ[pos];
 	if (env != oldenv)
 	    zsfree(oldenv);
 	if (env != newenv)
 	    zsfree(newenv);
-	pm->flags |= PM_EXPORTED;
+	pm->node.flags |= PM_EXPORTED;
 	pm->env = env;
 	return;
     }
@@ -3788,7 +3788,7 @@ scanendscope(HashNode hn, UNUSED(int flags))
 {
     Param pm = (Param)hn;
     if (pm->level > locallevel) {
-	if ((pm->flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) {
+	if ((pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL) {
 	    /*
 	     * Removable specials are normal in that they can be removed
 	     * to reveal an ordinary parameter beneath.  Here we handle
@@ -3799,29 +3799,29 @@ scanendscope(HashNode hn, UNUSED(int flags))
 	     */
 	    Param tpm = pm->old;
 
-	    if (!strcmp(pm->nam, "SECONDS"))
+	    if (!strcmp(pm->node.nam, "SECONDS"))
 	    {
-		setsecondstype(pm, PM_TYPE(tpm->flags), PM_TYPE(pm->flags));
+		setsecondstype(pm, PM_TYPE(tpm->node.flags), PM_TYPE(pm->node.flags));
 		/*
 		 * We restore SECONDS by restoring its raw internal value
 		 * that we cached off into tpm->u.dval.
 		 */
 		setrawseconds(tpm->u.dval);
-		tpm->flags |= PM_NORESTORE;
+		tpm->node.flags |= PM_NORESTORE;
 	    }
-	    DPUTS(!tpm || PM_TYPE(pm->flags) != PM_TYPE(tpm->flags) ||
-		  !(tpm->flags & PM_SPECIAL),
+	    DPUTS(!tpm || PM_TYPE(pm->node.flags) != PM_TYPE(tpm->node.flags) ||
+		  !(tpm->node.flags & PM_SPECIAL),
 		  "BUG: in restoring scope of special parameter");
 	    pm->old = tpm->old;
-	    pm->flags = (tpm->flags & ~PM_NORESTORE);
+	    pm->node.flags = (tpm->node.flags & ~PM_NORESTORE);
 	    pm->level = tpm->level;
 	    pm->base = tpm->base;
 	    pm->width = tpm->width;
 	    if (pm->env)
 		delenv(pm);
 
-	    if (!(tpm->flags & PM_NORESTORE))
-		switch (PM_TYPE(pm->flags)) {
+	    if (!(tpm->node.flags & PM_NORESTORE))
+		switch (PM_TYPE(pm->node.flags)) {
 		case PM_SCALAR:
 		    pm->gsu.s->setfn(pm, tpm->u.str);
 		    break;
@@ -3841,7 +3841,7 @@ scanendscope(HashNode hn, UNUSED(int flags))
 		}
 	    zfree(tpm, sizeof(*tpm));
 
-	    if (pm->flags & PM_EXPORTED)
+	    if (pm->node.flags & PM_EXPORTED)
 		export_param(pm);
 	} else
 	    unsetparam_pm(pm, 0, 0);
@@ -3863,9 +3863,9 @@ freeparamnode(HashNode hn)
      * know what its value should be.                       */
     if (delunset)
 	pm->gsu.s->unsetfn(pm, 1);
-    zsfree(pm->nam);
+    zsfree(pm->node.nam);
     /* If this variable was tied by the user, ename was ztrdup'd */
-    if (pm->flags & PM_TIED)
+    if (pm->node.flags & PM_TIED)
 	zsfree(pm->ename);
     zfree(pm, sizeof(struct param));
 }
@@ -3912,7 +3912,7 @@ printparamnode(HashNode hn, int printflags)
     Param p = (Param) hn;
     char *t, **u;
 
-    if (p->flags & PM_UNSET)
+    if (p->node.flags & PM_UNSET)
 	return;
 
     if (printflags & PRINT_TYPESET)
@@ -3928,7 +3928,7 @@ printparamnode(HashNode hn, int printflags)
 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
 		if (p->level)
 		    doprint = 1;
-	    } else if (p->flags & pmptr->binflag)
+	    } else if (p->node.flags & pmptr->binflag)
 		doprint = 1;
 
 	    if (doprint) {
@@ -3958,29 +3958,29 @@ printparamnode(HashNode hn, int printflags)
     }
 
     if ((printflags & PRINT_NAMEONLY) ||
-	((p->flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
-	zputs(p->nam, stdout);
+	((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
+	zputs(p->node.nam, stdout);
 	putchar('\n');
 	return;
     }
 
-    quotedzputs(p->nam, stdout);
+    quotedzputs(p->node.nam, stdout);
 
-    if (p->flags & PM_AUTOLOAD) {
+    if (p->node.flags & PM_AUTOLOAD) {
 	putchar('\n');
 	return;
     }
     if (printflags & PRINT_KV_PAIR)
 	putchar(' ');
     else if ((printflags & PRINT_TYPESET) &&
-	     (PM_TYPE(p->flags) == PM_ARRAY || PM_TYPE(p->flags) == PM_HASHED))
-	printf("\n%s=", p->nam);
+	     (PM_TYPE(p->node.flags) == PM_ARRAY || PM_TYPE(p->node.flags) == PM_HASHED))
+	printf("\n%s=", p->node.nam);
     else
 	putchar('=');
 
     /* How the value is displayed depends *
      * on the type of the parameter       */
-    switch (PM_TYPE(p->flags)) {
+    switch (PM_TYPE(p->node.flags)) {
     case PM_SCALAR:
 	/* string: simple output */
 	if (p->gsu.s->getfn && (t = p->gsu.s->getfn(p)))
@@ -3997,7 +3997,7 @@ printparamnode(HashNode hn, int printflags)
     case PM_EFLOAT:
     case PM_FFLOAT:
 	/* float */
-	convfloat(p->gsu.f->getfn(p), p->base, p->flags, stdout);
+	convfloat(p->gsu.f->getfn(p), p->base, p->node.flags, stdout);
 	break;
     case PM_ARRAY:
 	/* array */
diff --git a/Src/parse.c b/Src/parse.c
index 57ff73fbe..1a6146968 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2826,17 +2826,17 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
     Eprog prog;
     WCFunc wcf;
 
-    if (shf->flags & PM_UNDEFINED) {
+    if (shf->node.flags & PM_UNDEFINED) {
 	int ona = noaliases;
 
 	if (!(what & 2)) {
-	    zwarnnam(nam, "function is not loaded: %s", shf->nam, 0);
+	    zwarnnam(nam, "function is not loaded: %s", shf->node.nam, 0);
 	    return 1;
 	}
-	noaliases = (shf->flags & PM_UNALIASED);
-	if (!(prog = getfpfunc(shf->nam, NULL)) || prog == &dummy_eprog) {
+	noaliases = (shf->node.flags & PM_UNALIASED);
+	if (!(prog = getfpfunc(shf->node.nam, NULL)) || prog == &dummy_eprog) {
 	    noaliases = ona;
-	    zwarnnam(nam, "can't load function: %s", shf->nam, 0);
+	    zwarnnam(nam, "can't load function: %s", shf->node.nam, 0);
 	    return 1;
 	}
 	if (prog->dump)
@@ -2844,20 +2844,20 @@ cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs,
 	noaliases = ona;
     } else {
 	if (!(what & 1)) {
-	    zwarnnam(nam, "function is already loaded: %s", shf->nam, 0);
+	    zwarnnam(nam, "function is already loaded: %s", shf->node.nam, 0);
 	    return 1;
 	}
 	prog = dupeprog(shf->funcdef, 1);
     }
     wcf = (WCFunc) zhalloc(sizeof(*wcf));
-    wcf->name = shf->nam;
+    wcf->name = shf->node.nam;
     wcf->prog = prog;
     wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : FDHF_ZSHLOAD);
     addlinknode(progs, wcf);
-    addlinknode(names, shf->nam);
+    addlinknode(names, shf->node.nam);
 
     *hlen += ((sizeof(struct fdhead) / sizeof(wordcode)) +
-	      ((strlen(shf->nam) + sizeof(wordcode)) / sizeof(wordcode)));
+	      ((strlen(shf->node.nam) + sizeof(wordcode)) / sizeof(wordcode)));
     *tlen += (prog->len - (prog->npats * sizeof(Patprog)) +
 	      sizeof(wordcode) - 1) / sizeof(wordcode);
 
@@ -3358,10 +3358,10 @@ dump_autoload(char *nam, char *file, int on, Options ops, int func)
     for (n = firstfdhead(h), e = (FDHead) (h + fdheaderlen(h)); n < e;
 	 n = nextfdhead(n)) {
 	shf = (Shfunc) zshcalloc(sizeof *shf);
-	shf->flags = on;
+	shf->node.flags = on;
 	shf->funcdef = mkautofn(shf);
 	shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf);
-	if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->nam, ops, func))
+	if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->node.nam, ops, func))
 	    ret = 1;
     }
     return ret;
diff --git a/Src/prompt.c b/Src/prompt.c
index e45e9573e..be7dc672c 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -113,7 +113,7 @@ promptpath(char *p, int npath, int tilde)
     Nameddir nd;
 
     if (tilde && ((nd = finddir(p))))
-	modp = tricat("~", nd->nam, p + strlen(nd->dir));
+	modp = tricat("~", nd->node.nam, p + strlen(nd->dir));
 
     if (npath) {
 	char *sptr;
diff --git a/Src/signals.c b/Src/signals.c
index 3abeab647..33e298e34 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -729,10 +729,10 @@ dosavetrap(int sig, int level)
 	if ((shf = (Shfunc)gettrapnode(sig, 1))) {
 	    /* Copy the node for saving */
 	    newshf = (Shfunc) zalloc(sizeof(*newshf));
-	    newshf->nam = ztrdup(shf->nam);
-	    newshf->flags = shf->flags;
+	    newshf->node.nam = ztrdup(shf->node.nam);
+	    newshf->node.flags = shf->node.flags;
 	    newshf->funcdef = dupeprog(shf->funcdef, 0);
-	    if (shf->flags & PM_UNDEFINED)
+	    if (shf->node.flags & PM_UNDEFINED)
 		newshf->funcdef->shf = newshf;
 	}
 #ifdef DEBUG
@@ -979,7 +979,7 @@ endtrapscope(void)
 		DPUTS((sigtrapped[sig] ^ st->flags) & ZSIG_TRAPPED,
 		      "BUG: settrap didn't restore correct ZSIG_TRAPPED");
 		if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC)
-		    shfunctab->addnode(shfunctab, ((Shfunc)st->list)->nam,
+		    shfunctab->addnode(shfunctab, ((Shfunc)st->list)->node.nam,
 				       (Shfunc) st->list);
 	    } else if (sigtrapped[sig])
 		unsettrap(sig);
diff --git a/Src/subst.c b/Src/subst.c
index e6e6cba5b..08fb475d6 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -1580,7 +1580,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 			     hkeys|hvals|
 			     (arrasg ? SCANPM_ASSIGNING : 0)|
 			     (qt ? SCANPM_DQUOTED : 0))) ||
-	    (v->pm && (v->pm->flags & PM_UNSET)))
+	    (v->pm && (v->pm->node.flags & PM_UNSET)))
 	    vunset = 1;
 
 	if (wantt) {
@@ -1588,8 +1588,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	     * Handle the (t) flag: value now becomes the type
 	     * information for the parameter.
 	     */
-	    if (v && v->pm && !(v->pm->flags & PM_UNSET)) {
-		int f = v->pm->flags;
+	    if (v && v->pm && !(v->pm->node.flags & PM_UNSET)) {
+		int f = v->pm->node.flags;
 
 		switch (PM_TYPE(f)) {
 		case PM_SCALAR:  val = "scalar"; break;
@@ -1694,12 +1694,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	     * is called by getarrvalue(); needn't test PM_HASHED.   */
 	    if (v->isarr == SCANPM_WANTINDEX) {
 		isarr = v->isarr = 0;
-		val = dupstring(v->pm->nam);
+		val = dupstring(v->pm->node.nam);
 	    } else
 		aval = getarrvalue(v);
 	} else {
 	    /* Value retrieved from parameter/subexpression is scalar */
-	    if (v->pm->flags & PM_ARRAY) {
+	    if (v->pm->node.flags & PM_ARRAY) {
 		/*
 		 * Although the value is a scalar, the parameter
 		 * itself is an array.  Presumably this is due to
@@ -1729,14 +1729,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		 */
 		val = getstrvalue(v);
 		fwidth = v->pm->width ? v->pm->width : (int)strlen(val);
-		switch (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
+		switch (v->pm->node.flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
 		    char *t;
 		    unsigned int t0;
 
 		case PM_LEFT:
 		case PM_LEFT | PM_RIGHT_Z:
 		    t = val;
-		    if (v->pm->flags & PM_RIGHT_Z)
+		    if (v->pm->node.flags & PM_RIGHT_Z)
 			while (*t == '0')
 			    t++;
 		    else
@@ -1757,7 +1757,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 
 			if (strlen(val) < fwidth) {
 			    char *valprefend = val;
-			    if (v->pm->flags & PM_RIGHT_Z) {
+			    if (v->pm->node.flags & PM_RIGHT_Z) {
 				/*
 				 * This is a documented feature: when deciding
 				 * whether to pad with zeroes, ignore
@@ -1772,7 +1772,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 				 * Allow padding after initial minus
 				 * for numeric variables.
 				 */
-				if ((v->pm->flags &
+				if ((v->pm->node.flags &
 				     (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) &&
 				    *t == '-')
 				    t++;
@@ -1780,7 +1780,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 				 * Allow padding after initial 0x or
 				 * base# for integer variables.
 				 */
-				if (v->pm->flags & PM_INTEGER) {
+				if (v->pm->node.flags & PM_INTEGER) {
 				    if (isset(CBASES) &&
 					t[0] == '0' && t[1] == 'x')
 					t += 2;
@@ -1790,14 +1790,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 				valprefend = t;
 				if (!*t)
 				    zero = 0;
-				else if (v->pm->flags &
+				else if (v->pm->node.flags &
 					 (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) {
 				    /* zero always OK */
 				} else if (!idigit(*t))
 				    zero = 0;
 			    }
 			    t = (char *) hcalloc(fwidth + 1);
-			    memset(t, (((v->pm->flags & PM_RIGHT_B) || !zero) ?
+			    memset(t, (((v->pm->node.flags & PM_RIGHT_B) || !zero) ?
 				       ' ' : '0'), fwidth);
 			    /*
 			     * How can the following trigger?  We
@@ -1827,7 +1827,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		    }
 		    break;
 		}
-		switch (v->pm->flags & (PM_LOWER | PM_UPPER)) {
+		switch (v->pm->node.flags & (PM_LOWER | PM_UPPER)) {
 		    char *t;
 
 		case PM_LOWER:
diff --git a/Src/utils.c b/Src/utils.c
index c735f2105..ef8c23e9e 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -557,7 +557,7 @@ fprintdir(char *s, FILE *f)
 	fputs(unmeta(s), f);
     else {
 	putc('~', f);
-	fputs(unmeta(d->nam), f);
+	fputs(unmeta(d->node.nam), f);
 	fputs(unmeta(s + strlen(d->dir)), f);
     }
 }
@@ -609,7 +609,7 @@ finddir_scan(HashNode hn, UNUSED(int flags))
     Nameddir nd = (Nameddir) hn;
 
     if(nd->diff > finddir_best && !dircmp(nd->dir, finddir_full)
-       && !(nd->flags & ND_NOABBREV)) {
+       && !(nd->node.flags & ND_NOABBREV)) {
 	finddir_last=nd;
 	finddir_best=nd->diff;
     }
@@ -623,7 +623,7 @@ finddir_scan(HashNode hn, UNUSED(int flags))
 Nameddir
 finddir(char *s)
 {
-    static struct nameddir homenode = { NULL, "", 0, NULL, 0 };
+    static struct nameddir homenode = { {NULL, "", 0}, NULL, 0 };
     static int ffsz;
 
     /* Invalidate directory cache if argument is NULL.  This is called *
@@ -650,7 +650,7 @@ finddir(char *s)
     strcpy(finddir_full, s);
     finddir_best=0;
     finddir_last=NULL;
-    finddir_scan((HashNode)&homenode, 0);
+    finddir_scan(&homenode.node, 0);
     scanhashtable(nameddirtab, 0, 0, 0, finddir_scan, 0);
     return finddir_last;
 }
@@ -695,7 +695,7 @@ adduserdir(char *s, char *t, int flags, int always)
 
     /* add the name */
     nd = (Nameddir) zshcalloc(sizeof *nd);
-    nd->flags = flags;
+    nd->node.flags = flags;
     eptr = t + strlen(t);
     while (eptr > t && eptr[-1] == '/')
 	eptr--;
@@ -710,7 +710,7 @@ adduserdir(char *s, char *t, int flags, int always)
 	nd->dir = ztrduppfx(t, eptr - t);
     /* The variables PWD and OLDPWD are not to be displayed as ~PWD etc. */
     if (!strcmp(s, "PWD") || !strcmp(s, "OLDPWD"))
-	nd->flags |= ND_NOABBREV;
+	nd->node.flags |= ND_NOABBREV;
     nameddirtab->addnode(nameddirtab, ztrdup(s), nd);
 }
 
@@ -733,9 +733,9 @@ getnameddir(char *name)
      * begins with a `/'.  If there is, add it to the hash table and   *
      * return the new value.                                           */
     if ((pm = (Param) paramtab->getnode(paramtab, name)) &&
-	    (PM_TYPE(pm->flags) == PM_SCALAR) &&
+	    (PM_TYPE(pm->node.flags) == PM_SCALAR) &&
 	    (str = getsparam(name)) && *str == '/') {
-	pm->flags |= PM_NAMEDDIR;
+	pm->node.flags |= PM_NAMEDDIR;
 	adduserdir(name, str, 0, 1);
 	return str;
     }
diff --git a/Src/zsh.h b/Src/zsh.h
index 63490a34d..fb3697a66 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -330,7 +330,7 @@ enum {
 /**************************/
 
 typedef struct linknode  *LinkNode;
-typedef struct linklist  *LinkList;
+typedef union  linkroot  *LinkList;
 typedef struct hashnode  *HashNode;
 typedef struct hashtable *HashTable;
 
@@ -379,44 +379,50 @@ struct linknode {
 struct linklist {
     LinkNode first;
     LinkNode last;
+    int flags;
+};
+
+union linkroot {
+    struct linklist list;
+    struct linknode node;
 };
 
 /* Macros for manipulating link lists */
 
-#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 firstnode(X)        ((X)->list.first)
+#define lastnode(X)         ((X)->list.last)
+#define peekfirst(X)        (firstnode(X)->dat)
+#define addlinknode(X,Y)    insertlinknode(X,lastnode(X),Y)
+#define zaddlinknode(X,Y)   zinsertlinknode(X,lastnode(X),Y)
+#define uaddlinknode(X,Y)   uinsertlinknode(X,lastnode(X),Y)
+#define empty(X)            (firstnode(X) == NULL)
+#define nonempty(X)         (firstnode(X) != NULL)
 #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 pushnode(X,Y)       insertlinknode(X,&(X)->node,Y)
+#define zpushnode(X,Y)      zinsertlinknode(X,&(X)->node,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))
+#define setsizednode(X,Y,Z) (firstnode(X)[(Y)].dat = (void *) (Z))
 
 /* stack allocated linked lists */
 
-#define local_list0(N) struct linklist N
+#define local_list0(N) union linkroot N
 #define init_list0(N) \
     do { \
-        (N).first = NULL; \
-        (N).last = (LinkNode) &(N); \
+        (N).list.first = NULL; \
+        (N).list.last = &(N).node; \
     } while (0)
-#define local_list1(N) struct linklist N; struct linknode __n0
+#define local_list1(N) union linkroot N; struct linknode __n0
 #define init_list1(N,V0) \
     do { \
-        (N).first = &__n0; \
-        (N).last = &__n0; \
+        (N).list.first = &__n0; \
+        (N).list.last = &__n0; \
         __n0.next = NULL; \
-        __n0.last = (LinkNode) &(N); \
+        __n0.last = &(N).node; \
         __n0.dat = (void *) (V0); \
     } while (0)
 
@@ -908,27 +914,21 @@ struct hashnode {
 /* node in shell option table */
 
 struct optname {
-    HashNode next;		/* next in hash chain */
-    char *nam;			/* hash data */
-    int flags;
+    struct hashnode node;
     int optno;			/* option number */
 };
 
 /* node in shell reserved word hash table (reswdtab) */
 
 struct reswd {
-    HashNode next;		/* next in hash chain        */
-    char *nam;			/* name of reserved word     */
-    int flags;			/* flags                     */
+    struct hashnode node;
     int token;			/* corresponding lexer token */
 };
 
 /* node in alias hash table (aliastab) */
 
 struct alias {
-    HashNode next;		/* next in hash chain       */
-    char *nam;			/* hash data                */
-    int flags;			/* flags for alias types    */
+    struct hashnode node;
     char *text;			/* expansion of alias       */
     int inuse;			/* alias is being expanded  */
 };
@@ -942,9 +942,7 @@ struct alias {
 /* node in command path hash table (cmdnamtab) */
 
 struct cmdnam {
-    HashNode next;		/* next in hash chain */
-    char *nam;			/* hash data          */
-    int flags;
+    struct hashnode node;
     union {
 	char **name;		/* full pathname for external commands */
 	char *cmd;		/* file name for hashed commands       */
@@ -959,9 +957,7 @@ struct cmdnam {
 /* node in shell function hash table (shfunctab) */
 
 struct shfunc {
-    HashNode next;		/* next in hash chain     */
-    char *nam;			/* name of shell function */
-    int flags;			/* various flags          */
+    struct hashnode node;
     Eprog funcdef;		/* function definition    */
 };
 
@@ -1047,9 +1043,7 @@ typedef int (*HandlerFunc) _((char *, char **, Options, int));
 #define NULLBINCMD ((HandlerFunc) 0)
 
 struct builtin {
-    HashNode next;		/* next in hash chain                                 */
-    char *nam;			/* name of builtin                                    */
-    int flags;			/* various flags                                      */
+    struct hashnode node;
     HandlerFunc handlerfunc;	/* pointer to function that executes this builtin     */
     int minargs;		/* minimum number of arguments                        */
     int maxargs;		/* maximum number of arguments, or -1 for no limit    */
@@ -1059,7 +1053,7 @@ struct builtin {
 };
 
 #define BUILTIN(name, flags, handler, min, max, funcid, optstr, defopts) \
-    { NULL, name, flags, handler, min, max, funcid, optstr, defopts }
+    { { NULL, name, flags }, handler, min, max, funcid, optstr, defopts }
 #define BIN_PREFIX(name, flags) \
     BUILTIN(name, flags | BINF_PREFIX, NULLBINCMD, 0, 0, 0, NULL, NULL)
 
@@ -1218,9 +1212,7 @@ struct gsu_hash {
 /* node used in parameter hash table (paramtab) */
 
 struct param {
-    HashNode next;		/* next in hash chain */
-    char *nam;			/* hash data          */
-    int flags;			/* PM_* flags         */
+    struct hashnode node;
 
     /* the value of this parameter */
     union {
@@ -1391,9 +1383,7 @@ enum {
 /* node for named directory hash table (nameddirtab) */
 
 struct nameddir {
-    HashNode next;		/* next in hash chain               */
-    char *nam;			/* directory name                   */
-    int flags;			/* see below                        */
+    struct hashnode node;
     char *dir;			/* the directory in full            */
     int diff;			/* strlen(.dir) - strlen(.nam)      */
 };
@@ -1426,9 +1416,7 @@ struct nameddir {
 /* history entry */
 
 struct histent {
-    HashNode hash_next;		/* next in hash chain               */
-    char *text;			/* the history line itself          */
-    int flags;			/* Misc flags                       */
+    struct hashnode node;
 
     Histent up;			/* previous line (moving upward)    */
     Histent down;		/* next line (moving downward)      */