openenvutils/commandshell/shell/src/modules/parameter.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/openenvutils/commandshell/shell/src/modules/parameter.c	Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,2008 @@
+// parameter.c - parameter interface to zsh internals
+//
+// © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
+//
+/*
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1999 Sven Wischnowsky
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Sven Wischnowsky and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "parameter.mdh"
+#include "parameter.pro"
+
+#ifdef __SYMBIAN32__
+#ifdef __WINSCW__
+#pragma warn_unusedarg off
+#pragma warn_possunwant off
+#endif//__WINSCW__
+#endif//__SYMBIAN32__
+
+/* This says if we are cleaning up when the module is unloaded. */
+
+static int incleanup;
+
+/* Empty dummy function for special hash parameters. */
+
+/**/
+static void
+shempty(void)
+{
+}
+
+/* Create a simple special hash parameter. */
+
+/**/
+static Param
+createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan)
+{
+    Param pm;
+    HashTable ht;
+
+    if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_HIDEVAL|
+			   PM_REMOVABLE|PM_HASHED)))
+	return NULL;
+
+    pm->level = pm->old ? locallevel : 0;
+    pm->gsu.h = &stdhash_gsu;
+    pm->u.hash = ht = newhashtable(0, name, NULL);
+
+    ht->hash        = hasher;
+    ht->emptytable  = (TableFunc) shempty;
+    ht->filltable   = NULL;
+    ht->addnode     = (AddNodeFunc) shempty;
+    ht->getnode     = ht->getnode2 = get;
+    ht->removenode  = (RemoveNodeFunc) shempty;
+    ht->disablenode = NULL;
+    ht->enablenode  = NULL;
+    ht->freenode    = (FreeNodeFunc) shempty;
+    ht->printnode   = printparamnode;
+    ht->scantab     = scan;
+
+    return pm;
+}
+
+/* Functions for the parameters special parameter. */
+
+/* Return a string describing the type of a parameter. */
+
+/**/
+static char *
+paramtypestr(Param pm)
+{
+    char *val = NULL;
+    int f = pm->flags;
+
+    if (!(f & PM_UNSET)) {
+	if (pm->flags & PM_AUTOLOAD)
+	    return dupstring("undefined");
+
+	switch (PM_TYPE(f)) {
+	case PM_SCALAR:  val = "scalar"; break;
+	case PM_ARRAY:   val = "array"; break;
+	case PM_INTEGER: val = "integer"; break;
+	case PM_EFLOAT:
+	case PM_FFLOAT:  val = "float"; break;
+	case PM_HASHED:  val = "association"; break;
+	}
+	DPUTS(!val, "BUG: type not handled in parameter");
+	val = dupstring(val);
+	if (pm->level)
+	    val = dyncat(val, "-local");
+	if (f & PM_LEFT)
+	    val = dyncat(val, "-left");
+	if (f & PM_RIGHT_B)
+	    val = dyncat(val, "-right_blanks");
+	if (f & PM_RIGHT_Z)
+	    val = dyncat(val, "-right_zeros");
+	if (f & PM_LOWER)
+	    val = dyncat(val, "-lower");
+	if (f & PM_UPPER)
+	    val = dyncat(val, "-upper");
+	if (f & PM_READONLY)
+	    val = dyncat(val, "-readonly");
+	if (f & PM_TAGGED)
+	    val = dyncat(val, "-tag");
+	if (f & PM_EXPORTED)
+	    val = dyncat(val, "-export");
+	if (f & PM_UNIQUE)
+	    val = dyncat(val, "-unique");
+	if (f & PM_HIDE)
+	    val = dyncat(val, "-hide");
+	if (f & PM_HIDEVAL)
+	    val = dyncat(val, "-hideval");
+	if (f & PM_SPECIAL)
+	    val = dyncat(val, "-special");
+    } else
+	val = dupstring("");
+
+    return val;
+}
+
+/**/
+static HashNode
+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->gsu.s = &nullsetscalar_gsu;
+    if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
+	!(rpm->flags & PM_UNSET))
+	pm->u.str = paramtypestr(rpm);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmparameters(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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)
+		continue;
+	    pm.nam = hn->nam;
+	    if (func != scancountparams &&
+		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		 !(flags & SCANPM_WANTKEYS)))
+		pm.u.str = paramtypestr((Param) hn);
+	    func((HashNode) &pm, flags);
+	}
+}
+
+/* Functions for the commands special parameter. */
+
+/**/
+static void
+setpmcommand(Param pm, char *value)
+{
+    if (isset(RESTRICTED)) {
+	zwarn("restricted: %s", value, 0);
+	zsfree(value);
+    } else {
+	Cmdnam cn = zshcalloc(sizeof(*cn));
+
+	cn->flags = HASHED;
+	cn->u.cmd = value;
+
+	cmdnamtab->addnode(cmdnamtab, ztrdup(pm->nam), (HashNode) cn);
+    }
+}
+
+/**/
+static void
+unsetpmcommand(Param pm, UNUSED(int exp))
+{
+    HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->nam);
+
+    if (hn)
+	cmdnamtab->freenode(hn);
+}
+
+/**/
+static void
+setpmcommands(UNUSED(Param pm), HashTable ht)
+{
+    int i;
+    HashNode hn;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    Cmdnam cn = zshcalloc(sizeof(*cn));
+	    struct value v;
+
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    cn->flags = HASHED;
+	    cn->u.cmd = ztrdup(getstrvalue(&v));
+
+	    cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), (HashNode) cn);
+	}
+    deleteparamtable(ht);
+}
+
+static const struct gsu_scalar pmcommand_gsu =
+{ strgetfn, setpmcommand, unsetpmcommand };
+
+
+/**/
+static HashNode
+getpmcommand(UNUSED(HashTable ht), char *name)
+{
+    Cmdnam cmd;
+    Param pm = NULL;
+
+    if (!(cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name)) &&
+	isset(HASHLISTALL)) {
+	cmdnamtab->filltable(cmdnamtab);
+	cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
+    }
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->gsu.s = &pmcommand_gsu;
+    if (cmd) {
+	if (cmd->flags & HASHED)
+	    pm->u.str = cmd->u.cmd;
+	else {
+	    pm->u.str = zhalloc(strlen(*(cmd->u.name)) + strlen(name) + 2);
+	    strcpy(pm->u.str, *(cmd->u.name));
+	    strcat(pm->u.str, "/");
+	    strcat(pm->u.str, name);
+	}
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmcommands(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Cmdnam cmd;
+
+    if (isset(HASHLISTALL))
+	cmdnamtab->filltable(cmdnamtab);
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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;
+	    cmd = (Cmdnam) hn;
+	    if (func != scancountparams &&
+		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		 !(flags & SCANPM_WANTKEYS))) {
+		if (cmd->flags & HASHED)
+		    pm.u.str = cmd->u.cmd;
+		else {
+		    pm.u.str = zhalloc(strlen(*(cmd->u.name)) +
+				       strlen(cmd->nam) + 2);
+		    strcpy(pm.u.str, *(cmd->u.name));
+		    strcat(pm.u.str, "/");
+		    strcat(pm.u.str, cmd->nam);
+		}
+	    }
+	    func((HashNode) &pm, flags);
+	}
+}
+
+/* Functions for the functions special parameter. */
+
+/**/
+static void
+setfunction(char *name, char *val, int dis)
+{
+    char *value = dupstring(val);
+    Shfunc shf;
+    Eprog prog;
+    int sn;
+
+    val = metafy(val, strlen(val), META_REALLOC);
+
+    prog = parse_string(val);
+
+    if (!prog || prog == &dummy_eprog) {
+	zwarn("invalid function definition", value, 0);
+	zsfree(val);
+	return;
+    }
+    shf = (Shfunc) zalloc(sizeof(*shf));
+    shf->funcdef = dupeprog(prog, 0);
+    shf->flags = dis;
+
+    if (!strncmp(name, "TRAP", 4) &&
+	(sn = getsignum(name + 4)) != -1) {
+	if (settrap(sn, shf->funcdef)) {
+	    freeeprog(shf->funcdef);
+	    zfree(shf, sizeof(*shf));
+	    zsfree(val);
+	    return;
+	}
+	sigtrapped[sn] |= ZSIG_FUNC;
+    }
+    shfunctab->addnode(shfunctab, ztrdup(name), shf);
+    zsfree(val);
+}
+
+/**/
+static void
+setpmfunction(Param pm, char *value)
+{
+    setfunction(pm->nam, value, 0);
+}
+
+/**/
+static void
+setpmdisfunction(Param pm, char *value)
+{
+    setfunction(pm->nam, value, DISABLED);
+}
+
+/**/
+static void
+unsetpmfunction(Param pm, UNUSED(int exp))
+{
+    HashNode hn = shfunctab->removenode(shfunctab, pm->nam);
+
+    if (hn)
+	shfunctab->freenode(hn);
+}
+
+/**/
+static void
+setfunctions(UNUSED(Param pm), HashTable ht, int dis)
+{
+    int i;
+    HashNode hn;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    struct value v;
+
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    setfunction(hn->nam, ztrdup(getstrvalue(&v)), dis);
+	}
+    deleteparamtable(ht);
+}
+
+/**/
+static void
+setpmfunctions(Param pm, HashTable ht)
+{
+    setfunctions(pm, ht, 0);
+}
+
+/**/
+static void
+setpmdisfunctions(Param pm, HashTable ht)
+{
+    setfunctions(pm, ht, DISABLED);
+}
+
+static const struct gsu_scalar pmfunction_gsu =
+{ strgetfn, setpmfunction, unsetpmfunction };
+static const struct gsu_scalar pmdisfunction_gsu =
+{ strgetfn, setpmdisfunction, unsetpmfunction };
+
+/**/
+static HashNode
+getfunction(UNUSED(HashTable ht), char *name, int dis)
+{
+    Shfunc shf;
+    Param pm = NULL;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->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) {
+	    pm->u.str = dyncat("builtin autoload -X",
+			       ((shf->flags & PM_UNALIASED) ?
+				((shf->flags & PM_TAGGED) ? "Ut" : "U") :
+				((shf->flags & PM_TAGGED) ? "t" : "")));
+	} else {
+	    char *t = getpermtext(shf->funcdef, NULL), *n, *h;
+
+	    if (shf->funcdef->flags & EF_RUN) {
+		n = nicedupstring(name);
+		h = (char *) zhalloc(strlen(t) + strlen(n) + 9);
+		h[0] = '\t';
+		strcpy(h + 1, t);
+		strcat(h, "\n\t");
+		strcat(h, n);
+		strcat(h, " \"$@\"");
+	    } else
+		h = dyncat("\t", t);
+	    zsfree(t);
+	    unmetafy(h, NULL);
+
+	    pm->u.str = h;
+	}
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static HashNode
+getpmfunction(HashTable ht, char *name)
+{
+    return getfunction(ht, name, 0);
+}
+
+/**/
+static HashNode
+getpmdisfunction(HashTable ht, char *name)
+{
+    return getfunction(ht, name, DISABLED);
+}
+
+/**/
+static void
+scanfunctions(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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;
+		if (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS))) {
+		    if (((Shfunc) hn)->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" : "")));
+		    } else {
+			char *t = getpermtext(((Shfunc) hn)->funcdef, NULL), *n;
+
+			if (((Shfunc) hn)->funcdef->flags & EF_RUN) {
+			    n = nicedupstring(hn->nam);
+			    pm.u.str = (char *) zhalloc(strlen(t) + strlen(n) + 9);
+			    pm.u.str[0] = '\t';
+			    strcpy(pm.u.str + 1, t);
+			    strcat(pm.u.str, "\n\t");
+			    strcat(pm.u.str, n);
+			    strcat(pm.u.str, " \"$@\"");
+			} else
+			    pm.u.str = dyncat("\t", t);
+			unmetafy(pm.u.str, NULL);
+			zsfree(t);
+		    }
+		}
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/**/
+static void
+scanpmfunctions(HashTable ht, ScanFunc func, int flags)
+{
+    scanfunctions(ht, func, flags, 0);
+}
+
+/**/
+static void
+scanpmdisfunctions(HashTable ht, ScanFunc func, int flags)
+{
+    scanfunctions(ht, func, flags, DISABLED);
+}
+
+/* Functions for the funcstack special parameter. */
+
+/**/
+static char **
+funcstackgetfn(UNUSED(Param pm))
+{
+    Funcstack f;
+    int num;
+    char **ret, **p;
+
+    for (f = funcstack, num = 0; f; f = f->prev, num++);
+
+    ret = (char **) zhalloc((num + 1) * sizeof(char *));
+
+    for (f = funcstack, p = ret; f; f = f->prev, p++)
+	*p = f->name;
+    *p = NULL;
+
+    return ret;
+}
+
+/* Functions for the builtins special parameter. */
+
+/**/
+static HashNode
+getbuiltin(UNUSED(HashTable ht), char *name, int dis)
+{
+    Param pm = NULL;
+    Builtin bn;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->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)) ?
+		   "defined" : "undefined");
+
+	pm->u.str = dupstring(t);
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static HashNode
+getpmbuiltin(HashTable ht, char *name)
+{
+    return getbuiltin(ht, name, 0);
+}
+
+/**/
+static HashNode
+getpmdisbuiltin(HashTable ht, char *name)
+{
+    return getbuiltin(ht, name, DISABLED);
+}
+
+/**/
+static void
+scanbuiltins(UNUSED(HashTable ht), ScanFunc func, int flags, int dis)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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;
+		if (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS))) {
+		    char *t = ((((Builtin) hn)->handlerfunc ||
+				(hn->flags & BINF_PREFIX)) ?
+			       "defined" : "undefined");
+
+		    pm.u.str = dupstring(t);
+		}
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/**/
+static void
+scanpmbuiltins(HashTable ht, ScanFunc func, int flags)
+{
+    scanbuiltins(ht, func, flags, 0);
+}
+
+/**/
+static void
+scanpmdisbuiltins(HashTable ht, ScanFunc func, int flags)
+{
+    scanbuiltins(ht, func, flags, DISABLED);
+}
+
+/* Functions for the reswords special parameter. */
+
+/**/
+static char **
+getreswords(int dis)
+{
+    int i;
+    HashNode hn;
+    char **ret, **p;
+
+    p = ret = (char **) zhalloc((reswdtab->ct + 1) * sizeof(char *));
+
+    for (i = 0; i < reswdtab->hsize; i++)
+	for (hn = reswdtab->nodes[i]; hn; hn = hn->next)
+	    if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED))
+		*p++ = dupstring(hn->nam);
+    *p = NULL;
+
+    return ret;
+}
+
+/**/
+static char **
+reswordsgetfn(UNUSED(Param pm))
+{
+    return getreswords(0);
+}
+
+/**/
+static char **
+disreswordsgetfn(UNUSED(Param pm))
+{
+    return getreswords(DISABLED);
+}
+
+/* Functions for the options special parameter. */
+
+/**/
+static void
+setpmoption(Param pm, char *value)
+{
+    int n;
+
+    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 (dosetopt(n, (value && strcmp(value, "off")), 0))
+	zwarn("can't change option: %s", pm->nam, 0);
+    zsfree(value);
+}
+
+/**/
+static void
+unsetpmoption(Param pm, UNUSED(int exp))
+{
+    int n;
+
+    if (!(n = optlookup(pm->nam)))
+	zwarn("no such option: %s", pm->nam, 0);
+    else if (dosetopt(n, 0, 0))
+	zwarn("can't change option: %s", pm->nam, 0);
+}
+
+/**/
+static void
+setpmoptions(UNUSED(Param pm), HashTable ht)
+{
+    int i;
+    HashNode hn;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    struct value v;
+	    char *val;
+
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    val = getstrvalue(&v);
+	    if (!val || (strcmp(val, "on") && strcmp(val, "off")))
+		zwarn("invalid value: %s", val, 0);
+	    else if (dosetopt(optlookup(hn->nam),
+			      (val && strcmp(val, "off")), 0))
+		zwarn("can't change option: %s", hn->nam, 0);
+	}
+    deleteparamtable(ht);
+}
+
+static const struct gsu_scalar pmoption_gsu =
+{ strgetfn, setpmoption, unsetpmoption };
+
+/**/
+static HashNode
+getpmoption(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    int n;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->gsu.s = &pmoption_gsu;
+
+    if ((n = optlookup(name)))
+    {
+	int ison;
+	if (n > 0)
+	    ison = opts[n];
+	else
+	    ison = !opts[-n];
+	pm->u.str = dupstring(ison ? "on" : "off");
+    }
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmoptions(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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;
+	    ison = optno < 0 ? !opts[-optno] : opts[optno];
+	    pm.u.str = dupstring(ison ? "on" : "off");
+	    func((HashNode) &pm, flags);
+	}
+}
+
+/* Functions for the modules special parameter. */
+
+static char *modpmname;
+static int modpmfound;
+
+/**/
+static void
+modpmbuiltinscan(HashNode hn, UNUSED(int dummy))
+{
+    if (!(((Builtin) hn)->flags & BINF_ADDED) &&
+	!strcmp(((Builtin) hn)->optstr, modpmname))
+	modpmfound = 1;
+}
+
+/**/
+static void
+modpmparamscan(HashNode hn, UNUSED(int dummy))
+{
+    if ((((Param) hn)->flags & PM_AUTOLOAD) &&
+	!strcmp(((Param) hn)->u.str, modpmname))
+	modpmfound = 1;
+}
+
+/**/
+static int
+findmodnode(LinkList l, char *nam)
+{
+    LinkNode node;
+
+    for (node = firstnode(l); node; incnode(node))
+	if (!strcmp(nam, (char *) getdata(node)))
+	    return 1;
+
+    return 0;
+}
+
+/**/
+static HashNode
+getpmmodule(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    char *type = NULL;
+    LinkNode node;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+
+    if (!type) {
+	Module m;
+
+	for (node = firstnode(modules); node; incnode(node)) {
+	    m = (Module) getdata(node);
+	    if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
+		!strcmp(name, m->nam)) {
+		type = ((m->flags & MOD_ALIAS) ?
+			dyncat("alias:", m->u.alias) : "loaded");
+		break;
+	    }
+	}
+    }
+    modpmname = name;
+    modpmfound = 0;
+    if (!type) {
+	scanhashtable(builtintab, 0, 0, 0, modpmbuiltinscan, 0);
+	if (!modpmfound) {
+	    Conddef p;
+
+	    for (p = condtab; p; p = p->next)
+		if (p->module && !strcmp(name, p->module)) {
+		    modpmfound = 1;
+		    break;
+		}
+	    if (!modpmfound)
+		scanhashtable(realparamtab, 0, 0, 0, modpmparamscan, 0);
+	}
+	if (modpmfound)
+	    type = "autoloaded";
+    }
+    if (type)
+	pm->u.str = dupstring(type);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    LinkList done = newlinklist();
+    LinkNode node;
+    Module m;
+    Conddef p;
+    char *loaded = dupstring("loaded");
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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.u.str = ((m->flags & MOD_ALIAS) ?
+			dyncat("alias:", m->u.alias) : loaded);
+	    addlinknode(done, pm.nam);
+	    func((HashNode) &pm, 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) &&
+		!findmodnode(done, ((Builtin) hn)->optstr)) {
+		pm.nam = ((Builtin) hn)->optstr;
+		addlinknode(done, pm.nam);
+		func((HashNode) &pm, 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);
+	}
+    for (i = 0; i < realparamtab->hsize; i++)
+	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
+	    if ((((Param) hn)->flags & PM_AUTOLOAD) &&
+		!findmodnode(done, ((Param) hn)->u.str)) {
+		pm.nam = ((Param) hn)->u.str;
+		addlinknode(done, pm.nam);
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/* Functions for the dirstack special parameter. */
+
+/**/
+static void
+dirssetfn(UNUSED(Param pm), char **x)
+{
+    char **ox = x;
+
+    if (!incleanup) {
+	freelinklist(dirstack, freestr);
+	dirstack = znewlinklist();
+	while (x && *x)
+	    zaddlinknode(dirstack, ztrdup(*x++));
+    }
+    if (ox)
+	freearray(ox);
+}
+
+/**/
+static char **
+dirsgetfn(UNUSED(Param pm))
+{
+    int l = countlinknodes(dirstack);
+    char **ret = (char **) zhalloc((l + 1) * sizeof(char *)), **p;
+    LinkNode n;
+
+    for (n = firstnode(dirstack), p = ret; n; incnode(n), p++)
+	*p = dupstring((char *) getdata(n));
+    *p = NULL;
+
+    return ret;
+}
+
+/* Functions for the history special parameter. */
+
+/**/
+static HashNode
+getpmhistory(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    Histent he;
+    char *p;
+    int ok = 1;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+
+    if (*name != '0' || name[1]) {
+	if (*name == '0')
+	    ok = 0;
+	else {
+	    for (p = name; *p && idigit(*p); p++);
+	    if (*p)
+		ok = 0;
+	}
+    }
+    if (ok && (he = quietgethist(atoi(name))))
+	pm->u.str = dupstring(he->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmhistory(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i = addhistnum(curhist, -1, HIST_FOREIGN);
+    Histent he = gethistent(i, GETHIST_UPWARD);
+    char buf[40];
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.gsu.s = &nullsetscalar_gsu;
+
+    while (he) {
+	if (func != scancountparams) {
+	    convbase(buf, he->histnum, 10);
+	    pm.nam = dupstring(buf);
+	    if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		!(flags & SCANPM_WANTKEYS))
+		pm.u.str = dupstring(he->text);
+	}
+	func((HashNode) &pm, flags);
+
+	he = up_histent(he);
+    }
+}
+
+/* Function for the historywords special parameter. */
+
+/**/
+static char **
+histwgetfn(UNUSED(Param pm))
+{
+    char **ret, **p, *h, *e, sav;
+    LinkList l = newlinklist(), ll;
+    LinkNode n;
+    int i = addhistnum(curhist, -1, HIST_FOREIGN), iw;
+    Histent he = gethistent(i, GETHIST_UPWARD);
+
+    if ((ll = bufferwords(NULL, NULL, NULL)))
+        for (n = firstnode(ll); n; incnode(n))
+            pushnode(l, getdata(n));
+
+    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];
+	    sav = *e;
+	    *e = '\0';
+	    addlinknode(l, dupstring(h));
+	    *e = sav;
+	}
+	he = up_histent(he);
+    }
+    ret = (char **) zhalloc((countlinknodes(l) + 1) * sizeof(char *));
+
+    for (p = ret, n = firstnode(l); n; incnode(n), p++)
+	*p = (char *) getdata(n);
+    *p = NULL;
+
+    return ret;
+}
+
+/* Functions for the jobtexts special parameter. */
+
+/**/
+static char *
+pmjobtext(int job)
+{
+    Process pn;
+    int len = 1;
+    char *ret;
+
+    for (pn = jobtab[job].procs; pn; pn = pn->next)
+	len += strlen(pn->text) + 3;
+
+    ret = (char *) zhalloc(len);
+    ret[0] = '\0';
+
+    for (pn = jobtab[job].procs; pn; pn = pn->next) {
+	strcat(ret, pn->text);
+	if (pn->next)
+	    strcat(ret, " | ");
+    }
+    return ret;
+}
+
+/**/
+static HashNode
+getpmjobtext(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+
+    if ((job = atoi(name)) >= 1 && job <= maxjob &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobtext(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobtexts(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.gsu.s = &nullsetscalar_gsu;
+
+    for (job = 1; job <= maxjob; job++) {
+	if (jobtab[job].stat && jobtab[job].procs &&
+	    !(jobtab[job].stat & STAT_NOPRINT)) {
+	    if (func != scancountparams) {
+		sprintf(buf, "%d", job);
+		pm.nam = dupstring(buf);
+		if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		    !(flags & SCANPM_WANTKEYS))
+		    pm.u.str = pmjobtext(job);
+	    }
+	    func((HashNode) &pm, flags);
+	}
+    }
+}
+
+/* Functions for the jobstates special parameter. */
+
+/**/
+static char *
+pmjobstate(int job)
+{
+    Process pn;
+    char buf[256], buf2[128], *ret, *state, *cp;
+
+    if (job == curjob)
+	cp = ":+";
+    else if (job == prevjob)
+	cp = ":-";
+    else
+	cp = ":";
+
+    if (jobtab[job].stat & STAT_DONE)
+	ret = dyncat("done", cp);
+    else if (jobtab[job].stat & STAT_STOPPED)
+	ret = dyncat("suspended", cp);
+    else
+	ret = dyncat("running", cp);
+
+    for (pn = jobtab[job].procs; pn; pn = pn->next) {
+
+	if (pn->status == SP_RUNNING)
+	    state = "running";
+	else if (WIFEXITED(pn->status)) {
+	    if (WEXITSTATUS(pn->status))
+		sprintf((state = buf2), "exit %d", (pn->status));
+	    else
+		state = "done";
+	} else if (WIFSTOPPED(pn->status))
+	    state = sigmsg(WSTOPSIG(pn->status));
+	else if (WCOREDUMP(pn->status))
+	    sprintf((state = buf2), "%s (core dumped)",
+		    sigmsg(WTERMSIG(pn->status)));
+	else
+	    state = sigmsg(WTERMSIG(pn->status));
+
+	sprintf(buf, ":%d=%s", (int)pn->pid, state);
+
+	ret = dyncat(ret, buf);
+    }
+    return ret;
+}
+
+/**/
+static HashNode
+getpmjobstate(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+
+    if ((job = atoi(name)) >= 1 && job <= maxjob &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobstate(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobstates(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.gsu.s = &nullsetscalar_gsu;
+
+    for (job = 1; job <= maxjob; job++) {
+	if (jobtab[job].stat && jobtab[job].procs &&
+	    !(jobtab[job].stat & STAT_NOPRINT)) {
+	    if (func != scancountparams) {
+		sprintf(buf, "%d", job);
+		pm.nam = dupstring(buf);
+		if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		    !(flags & SCANPM_WANTKEYS))
+		    pm.u.str = pmjobstate(job);
+	    }
+	    func((HashNode) &pm, flags);
+	}
+    }
+}
+
+/* Functions for the jobdirs special parameter. */
+
+/**/
+static char *
+pmjobdir(int job)
+{
+    char *ret;
+
+    ret = dupstring(jobtab[job].pwd ? jobtab[job].pwd : pwd);
+    return ret;
+}
+
+/**/
+static HashNode
+getpmjobdir(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+
+    if ((job = atoi(name)) >= 1 && job <= maxjob &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobdir(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.flags = PM_SCALAR | PM_READONLY;
+    pm.gsu.s = &nullsetscalar_gsu;
+
+    for (job = 1; job <= maxjob; job++) {
+       if (jobtab[job].stat && jobtab[job].procs &&
+           !(jobtab[job].stat & STAT_NOPRINT)) {
+           if (func != scancountparams) {
+	       sprintf(buf, "%d", job);
+	       pm.nam = dupstring(buf);
+               if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		   !(flags & SCANPM_WANTKEYS))
+		   pm.u.str = pmjobdir(job);
+	   }
+           func((HashNode) &pm, flags);
+       }
+    }
+}
+
+/* Functions for the nameddirs special parameter. */
+
+/**/
+static void
+setpmnameddir(Param pm, char *value)
+{
+    if (!value)
+	zwarn("invalid value: ''", NULL, 0);
+    else {
+	Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
+
+	nd->flags = 0;
+	nd->dir = value;
+	nameddirtab->addnode(nameddirtab, ztrdup(pm->nam), nd);
+    }
+}
+
+/**/
+static void
+unsetpmnameddir(Param pm, UNUSED(int exp))
+{
+    HashNode hd = nameddirtab->removenode(nameddirtab, pm->nam);
+
+    if (hd)
+	nameddirtab->freenode(hd);
+}
+
+/**/
+static void
+setpmnameddirs(UNUSED(Param pm), HashTable ht)
+{
+    int i;
+    HashNode hn, next, hd;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < nameddirtab->hsize; i++)
+	for (hn = nameddirtab->nodes[i]; hn; hn = next) {
+	    next = hn->next;
+	    if (!(((Nameddir) hn)->flags & ND_USERNAME) &&
+		(hd = nameddirtab->removenode(nameddirtab, hn->nam)))
+		nameddirtab->freenode(hd);
+	}
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    struct value v;
+	    char *val;
+
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    if (!(val = getstrvalue(&v)))
+		zwarn("invalid value: ''", NULL, 0);
+	    else {
+		Nameddir nd = (Nameddir) zshcalloc(sizeof(*nd));
+
+		nd->flags = 0;
+		nd->dir = ztrdup(val);
+		nameddirtab->addnode(nameddirtab, ztrdup(hn->nam), nd);
+	    }
+	}
+
+    /* The INTERACTIVE stuff ensures that the dirs are not immediatly removed
+     * when the sub-pms are deleted. */
+
+    i = opts[INTERACTIVE];
+    opts[INTERACTIVE] = 0;
+    deleteparamtable(ht);
+    opts[INTERACTIVE] = i;
+}
+
+static const struct gsu_scalar pmnamedir_gsu =
+{ strgetfn, setpmnameddir, unsetpmnameddir };
+
+/**/
+static HashNode
+getpmnameddir(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    Nameddir nd;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->gsu.s = &pmnamedir_gsu;
+    if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	!(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmnameddirs(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Nameddir nd;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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 (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS)))
+		    pm.u.str = dupstring(nd->dir);
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/* Functions for the userdirs special parameter. */
+
+/**/
+static HashNode
+getpmuserdir(UNUSED(HashTable ht), char *name)
+{
+    Param pm = NULL;
+    Nameddir nd;
+
+    nameddirtab->filltable(nameddirtab);
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->gsu.s = &nullsetscalar_gsu;
+    if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmuserdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Nameddir nd;
+
+    nameddirtab->filltable(nameddirtab);
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    pm.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 (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS)))
+		    pm.u.str = dupstring(nd->dir);
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/* Functions for the raliases, galiases and saliases special parameters. */
+
+/**/
+static void
+setalias(HashTable ht, Param pm, char *value, int flags)
+{
+    ht->addnode(ht, ztrdup(pm->nam),
+		createaliasnode(value, flags));
+}
+
+/**/
+static void
+setpmralias(Param pm, char *value)
+{
+    setalias(aliastab, pm, value, 0);
+}
+
+/**/
+static void
+setpmdisralias(Param pm, char *value)
+{
+    setalias(aliastab, pm, value, DISABLED);
+}
+
+/**/
+static void
+setpmgalias(Param pm, char *value)
+{
+    setalias(aliastab, pm, value, ALIAS_GLOBAL);
+}
+
+/**/
+static void
+setpmdisgalias(Param pm, char *value)
+{
+    setalias(aliastab, pm, value, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static void
+setpmsalias(Param pm, char *value)
+{
+    setalias(sufaliastab, pm, value, ALIAS_SUFFIX);
+}
+
+/**/
+static void
+setpmdissalias(Param pm, char *value)
+{
+    setalias(sufaliastab, pm, value, ALIAS_SUFFIX|DISABLED);
+}
+
+/**/
+static void
+unsetpmalias(Param pm, UNUSED(int exp))
+{
+    HashNode hd = aliastab->removenode(aliastab, pm->nam);
+
+    if (hd)
+	aliastab->freenode(hd);
+}
+
+/**/
+static void
+unsetpmsalias(Param pm, UNUSED(int exp))
+{
+    HashNode hd = sufaliastab->removenode(sufaliastab, pm->nam);
+
+    if (hd)
+	sufaliastab->freenode(hd);
+}
+
+/**/
+static void
+setaliases(HashTable alht, UNUSED(Param pm), HashTable ht, int flags)
+{
+    int i;
+    HashNode hn, next, hd;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < alht->hsize; i++)
+	for (hn = alht->nodes[i]; hn; hn = next) {
+	    next = hn->next;
+	    /*
+	     * The following respects the DISABLED flag, e.g.
+	     * we get a different behaviour for raliases and dis_raliases.
+	     * The predecessor to this code didn't do that; presumably
+	     * that was a bug.
+	     */
+	    if (flags == ((Alias)hn)->flags &&
+		(hd = alht->removenode(alht, hn->nam)))
+		alht->freenode(hd);
+	}
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    struct value v;
+	    char *val;
+
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    if ((val = getstrvalue(&v)))
+		alht->addnode(alht, ztrdup(hn->nam),
+			      createaliasnode(ztrdup(val), flags));
+	}
+    deleteparamtable(ht);
+}
+
+/**/
+static void
+setpmraliases(Param pm, HashTable ht)
+{
+    setaliases(aliastab, pm, ht, 0);
+}
+
+/**/
+static void
+setpmdisraliases(Param pm, HashTable ht)
+{
+    setaliases(aliastab, pm, ht, DISABLED);
+}
+
+/**/
+static void
+setpmgaliases(Param pm, HashTable ht)
+{
+    setaliases(aliastab, pm, ht, ALIAS_GLOBAL);
+}
+
+/**/
+static void
+setpmdisgaliases(Param pm, HashTable ht)
+{
+    setaliases(aliastab, pm, ht, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static void
+setpmsaliases(Param pm, HashTable ht)
+{
+    setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX);
+}
+
+/**/
+static void
+setpmdissaliases(Param pm, HashTable ht)
+{
+    setaliases(sufaliastab, pm, ht, ALIAS_SUFFIX|DISABLED);
+}
+
+static const struct gsu_scalar pmralias_gsu =
+{ strgetfn, setpmralias, unsetpmalias };
+static const struct gsu_scalar pmgalias_gsu =
+{ strgetfn, setpmgalias, unsetpmalias };
+static const struct gsu_scalar pmsalias_gsu =
+{ strgetfn, setpmsalias, unsetpmsalias };
+static const struct gsu_scalar pmdisralias_gsu =
+{ strgetfn, setpmdisralias, unsetpmalias };
+static const struct gsu_scalar pmdisgalias_gsu =
+{ strgetfn, setpmdisgalias, unsetpmalias };
+static const struct gsu_scalar pmdissalias_gsu =
+{ strgetfn, setpmdissalias, unsetpmsalias };
+
+/**/
+static void
+assignaliasdefs(Param pm, int flags)
+{
+    pm->flags = PM_SCALAR;
+
+    /* we really need to squirrel the flags away somewhere... */
+    switch (flags) {
+    case 0:
+	pm->gsu.s = &pmralias_gsu;
+	break;
+
+    case ALIAS_GLOBAL:
+	pm->gsu.s = &pmgalias_gsu;
+	break;
+
+    case ALIAS_SUFFIX:
+	pm->gsu.s = &pmsalias_gsu;
+	break;
+
+    case DISABLED:
+	pm->gsu.s = &pmdisralias_gsu;
+	break;
+
+    case ALIAS_GLOBAL|DISABLED:
+	pm->gsu.s = &pmdisgalias_gsu;
+	break;
+
+    case ALIAS_SUFFIX|DISABLED:
+	pm->gsu.s = &pmdissalias_gsu;
+	break;
+    }
+}
+
+/**/
+static HashNode
+getalias(HashTable alht, UNUSED(HashTable ht), char *name, int flags)
+{
+    Param pm = NULL;
+    Alias al;
+
+    pm = (Param) hcalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+
+    assignaliasdefs(pm, flags);
+
+    if ((al = (Alias) alht->getnode2(alht, name)) &&
+	flags == al->flags)
+	pm->u.str = dupstring(al->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static HashNode
+getpmralias(HashTable ht, char *name)
+{
+    return getalias(aliastab, ht, name, 0);
+}
+
+/**/
+static HashNode
+getpmdisralias(HashTable ht, char *name)
+{
+    return getalias(aliastab, ht, name, DISABLED);
+}
+
+/**/
+static HashNode
+getpmgalias(HashTable ht, char *name)
+{
+    return getalias(aliastab, ht, name, ALIAS_GLOBAL);
+}
+
+/**/
+static HashNode
+getpmdisgalias(HashTable ht, char *name)
+{
+    return getalias(aliastab, ht, name, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static HashNode
+getpmsalias(HashTable ht, char *name)
+{
+    return getalias(sufaliastab, ht, name, ALIAS_SUFFIX);
+}
+
+/**/
+static HashNode
+getpmdissalias(HashTable ht, char *name)
+{
+    return getalias(sufaliastab, ht, name, ALIAS_SUFFIX|DISABLED);
+}
+
+/**/
+static void
+scanaliases(HashTable alht, UNUSED(HashTable ht), ScanFunc func,
+	    int pmflags, int alflags)
+{
+    struct param pm;
+    int i;
+    Alias al;
+
+    memset((void *)&pm, 0, sizeof(struct param));
+    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;
+		if (func != scancountparams &&
+		    ((pmflags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(pmflags & SCANPM_WANTKEYS)))
+		    pm.u.str = dupstring(al->text);
+		func((HashNode) &pm, pmflags);
+	    }
+	}
+}
+
+/**/
+static void
+scanpmraliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(aliastab, ht, func, flags, 0);
+}
+
+/**/
+static void
+scanpmdisraliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(aliastab, ht, func, flags, DISABLED);
+}
+
+/**/
+static void
+scanpmgaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL);
+}
+
+/**/
+static void
+scanpmdisgaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL|DISABLED);
+}
+
+/**/
+static void
+scanpmsaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX);
+}
+
+/**/
+static void
+scanpmdissaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED);
+}
+
+/* Table for defined parameters. */
+
+struct pardef {
+    char *name;
+    int flags;
+    GetNodeFunc getnfn;
+    ScanTabFunc scantfn;
+    GsuHash hash_gsu;
+    GsuArray array_gsu;
+    Param pm;
+};
+
+/*
+ * This is a duplicate of nullsethash_gsu.  On some systems
+ * (such as Cygwin) we can't put a pointer to an imported variable
+ * in a compile-time initialiser, so we use this instead.
+ */
+static const struct gsu_hash pmnullsethash_gsu =
+{ hashgetfn, nullsethashfn, nullunsetfn };
+static const struct gsu_hash pmcommands_gsu =
+{ hashgetfn, setpmcommands, stdunsetfn };
+static const struct gsu_hash pmfunctions_gsu =
+{ hashgetfn, setpmfunctions, stdunsetfn };
+static const struct gsu_hash pmdisfunctions_gsu =
+{ hashgetfn, setpmdisfunctions, stdunsetfn };
+static const struct gsu_hash pmoptions_gsu =
+{ hashgetfn, setpmoptions, stdunsetfn };
+static const struct gsu_hash pmnameddirs_gsu =
+{ hashgetfn, setpmnameddirs, stdunsetfn };
+static const struct gsu_hash pmraliases_gsu =
+{ hashgetfn, setpmraliases, stdunsetfn };
+static const struct gsu_hash pmgaliases_gsu =
+{ hashgetfn, setpmgaliases, stdunsetfn };
+static const struct gsu_hash pmsaliases_gsu =
+{ hashgetfn, setpmsaliases, stdunsetfn };
+static const struct gsu_hash pmdisraliases_gsu =
+{ hashgetfn, setpmdisraliases, stdunsetfn };
+static const struct gsu_hash pmdisgaliases_gsu =
+{ hashgetfn, setpmdisgaliases, stdunsetfn };
+static const struct gsu_hash pmdissaliases_gsu =
+{ hashgetfn, setpmdissaliases, stdunsetfn };
+
+static const struct gsu_array funcstack_gsu =
+{ funcstackgetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array reswords_gsu =
+{ reswordsgetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array disreswords_gsu =
+{ disreswordsgetfn, arrsetfn, stdunsetfn };
+static const struct gsu_array dirs_gsu =
+{ dirsgetfn, dirssetfn, stdunsetfn };
+static const struct gsu_array historywords_gsu =
+{ histwgetfn, arrsetfn, stdunsetfn };
+
+static struct pardef partab[] = {
+    { "parameters", PM_READONLY,
+      getpmparameter, scanpmparameters, &pmnullsethash_gsu,
+      NULL, NULL },
+    { "commands", 0,
+      getpmcommand, scanpmcommands, &pmcommands_gsu,
+      NULL, NULL },
+    { "functions", 0,
+      getpmfunction, scanpmfunctions, &pmfunctions_gsu,
+      NULL, NULL },
+    { "dis_functions", 0,
+      getpmdisfunction, scanpmdisfunctions, &pmdisfunctions_gsu,
+      NULL, NULL },
+    { "funcstack", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      &funcstack_gsu, NULL },
+    { "builtins", PM_READONLY,
+      getpmbuiltin, scanpmbuiltins, NULL,
+      NULL, NULL },
+    { "dis_builtins", PM_READONLY,
+      getpmdisbuiltin, scanpmdisbuiltins,
+      NULL, NULL, },
+    { "reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      &reswords_gsu, NULL },
+    { "dis_reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      &disreswords_gsu, NULL },
+    { "options", 0,
+      getpmoption, scanpmoptions, &pmoptions_gsu,
+      NULL, NULL },
+    { "modules", PM_READONLY,
+      getpmmodule, scanpmmodules, NULL,
+      NULL, NULL },
+    { "dirstack", PM_ARRAY|PM_SPECIAL|PM_REMOVABLE,
+      NULL, NULL, NULL,
+      &dirs_gsu, NULL },
+    { "history", PM_READONLY,
+      getpmhistory, scanpmhistory, NULL,
+      NULL, NULL,  },
+    { "historywords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      &historywords_gsu, NULL },
+    { "jobtexts", PM_READONLY,
+      getpmjobtext, scanpmjobtexts, NULL,
+      NULL, NULL },
+    { "jobstates", PM_READONLY,
+      getpmjobstate, scanpmjobstates, NULL,
+      NULL, NULL },
+    { "jobdirs", PM_READONLY,
+      getpmjobdir, scanpmjobdirs, NULL,
+      NULL, NULL },
+    { "nameddirs", 0,
+      getpmnameddir, scanpmnameddirs, &pmnameddirs_gsu,
+      NULL, NULL },
+    { "userdirs", PM_READONLY,
+      getpmuserdir, scanpmuserdirs, NULL,
+      NULL, NULL },
+    { "aliases", 0,
+      getpmralias, scanpmraliases, &pmraliases_gsu,
+      NULL, NULL },
+    { "galiases", 0,
+      getpmgalias, scanpmgaliases, &pmgaliases_gsu,
+      NULL, NULL },
+    { "saliases", 0,
+      getpmsalias, scanpmsaliases, &pmsaliases_gsu,
+      NULL, NULL },
+    { "dis_aliases", 0,
+      getpmdisralias, scanpmdisraliases, &pmdisraliases_gsu,
+      NULL, NULL },
+    { "dis_galiases", 0,
+      getpmdisgalias, scanpmdisgaliases, &pmdisgaliases_gsu,
+      NULL, NULL },
+    { "dis_saliases", 0,
+      getpmdissalias, scanpmdissaliases, &pmdissaliases_gsu,
+      NULL, NULL },
+    { NULL, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    incleanup = 0;
+
+    return 0;
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+    /* Create the special associative arrays.
+     * As an example for autoloaded parameters, this is probably a bad
+     * example, because the zsh core doesn't support creation of
+     * special hashes, yet. */
+
+    struct pardef *def;
+
+    for (def = partab; def->name; def++) {
+	unsetparam(def->name);
+
+	if (def->getnfn) {
+	    if (!(def->pm = createspecialhash(def->name, def->getnfn,
+					      def->scantfn)))
+		return 1;
+	    def->pm->flags |= def->flags;
+	    if (def->hash_gsu)
+		def->pm->gsu.h = def->hash_gsu;
+	} else {
+	    if (!(def->pm = createparam(def->name, def->flags | PM_HIDE|
+					PM_HIDEVAL | PM_REMOVABLE)))
+		return 1;
+	    def->pm->gsu.a = def->array_gsu;
+	}
+    }
+    return 0;
+}
+
+/**/
+int
+cleanup_(UNUSED(Module m))
+{
+    Param pm;
+    struct pardef *def;
+
+    incleanup = 1;
+
+    for (def = partab; def->name; def++) {
+	if ((pm = (Param) paramtab->getnode(paramtab, def->name)) &&
+	    pm == def->pm) {
+	    pm->flags &= ~PM_READONLY;
+	    unsetparam_pm(pm, 0, 1);
+	}
+    }
+    return 0;
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}