about summary refs log tree commit diff
path: root/Src/Modules/parameter.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/parameter.c')
-rw-r--r--Src/Modules/parameter.c928
1 files changed, 491 insertions, 437 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 5dce2f958..7005501a8 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -51,13 +51,12 @@ createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan)
     Param pm;
     HashTable ht;
 
-    if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_REMOVABLE|PM_HASHED)))
+    if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_HIDEVAL|
+			   PM_REMOVABLE|PM_HASHED)))
 	return NULL;
 
     pm->level = pm->old ? locallevel : 0;
-    pm->gets.hfn = hashgetfn;
-    pm->sets.hfn = hashsetfn;
-    pm->unsetfn = stdunsetfn;
+    pm->gsu.h = &stdhash_gsu;
     pm->u.hash = ht = newhashtable(0, name, NULL);
 
     ht->hash        = hasher;
@@ -122,6 +121,8 @@ paramtypestr(Param pm)
 	    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
@@ -132,21 +133,14 @@ paramtypestr(Param pm)
 
 /**/
 static HashNode
-getpmparameter(HashTable ht, char *name)
+getpmparameter(UNUSED(HashTable ht), char *name)
 {
     Param rpm, pm = NULL;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &nullsetscalar_gsu;
     if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
 	!(rpm->flags & PM_UNSET))
 	pm->u.str = paramtypestr(rpm);
@@ -159,24 +153,20 @@ getpmparameter(HashTable ht, char *name)
 
 /**/
 static void
-scanpmparameters(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    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)) ||
@@ -192,10 +182,11 @@ scanpmparameters(HashTable ht, ScanFunc func, int flags)
 static void
 setpmcommand(Param pm, char *value)
 {
-    if (isset(RESTRICTED))
+    if (isset(RESTRICTED)) {
 	zwarn("restricted: %s", value, 0);
-    else {
-	Cmdnam cn = zcalloc(sizeof(*cn));
+	zsfree(value);
+    } else {
+	Cmdnam cn = zshcalloc(sizeof(*cn));
 
 	cn->flags = HASHED;
 	cn->u.cmd = value;
@@ -206,7 +197,7 @@ setpmcommand(Param pm, char *value)
 
 /**/
 static void
-unsetpmcommand(Param pm, int exp)
+unsetpmcommand(Param pm, UNUSED(int exp))
 {
     HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->nam);
 
@@ -216,7 +207,7 @@ unsetpmcommand(Param pm, int exp)
 
 /**/
 static void
-setpmcommands(Param pm, HashTable ht)
+setpmcommands(UNUSED(Param pm), HashTable ht)
 {
     int i;
     HashNode hn;
@@ -226,11 +217,11 @@ setpmcommands(Param pm, HashTable ht)
 
     for (i = 0; i < ht->hsize; i++)
 	for (hn = ht->nodes[i]; hn; hn = hn->next) {
-	    Cmdnam cn = zcalloc(sizeof(*cn));
+	    Cmdnam cn = zshcalloc(sizeof(*cn));
 	    struct value v;
 
-	    v.isarr = v.inv = v.a = 0;
-	    v.b = -1;
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
@@ -242,9 +233,13 @@ setpmcommands(Param pm, HashTable ht)
     deleteparamtable(ht);
 }
 
+static const struct gsu_scalar pmcommand_gsu =
+{ strgetfn, setpmcommand, unsetpmcommand };
+
+
 /**/
 static HashNode
-getpmcommand(HashTable ht, char *name)
+getpmcommand(UNUSED(HashTable ht), char *name)
 {
     Cmdnam cmd;
     Param pm = NULL;
@@ -254,17 +249,10 @@ getpmcommand(HashTable ht, char *name)
 	cmdnamtab->filltable(cmdnamtab);
 	cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
     }
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR;
-    pm->sets.cfn = setpmcommand;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmcommand;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &pmcommand_gsu;
     if (cmd) {
 	if (cmd->flags & HASHED)
 	    pm->u.str = cmd->u.cmd;
@@ -283,7 +271,7 @@ getpmcommand(HashTable ht, char *name)
 
 /**/
 static void
-scanpmcommands(HashTable ht, ScanFunc func, int flags)
+scanpmcommands(UNUSED(HashTable ht), ScanFunc func, int flags)
 {
     struct param pm;
     int i;
@@ -293,15 +281,9 @@ scanpmcommands(HashTable ht, ScanFunc func, int flags)
     if (isset(HASHLISTALL))
 	cmdnamtab->filltable(cmdnamtab);
 
+    memset((void *)&pm, 0, sizeof(struct param));
     pm.flags = PM_SCALAR;
-    pm.sets.cfn = setpmcommand;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmcommand;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &pmcommand_gsu;
 
     for (i = 0; i < cmdnamtab->hsize; i++)
 	for (hn = cmdnamtab->nodes[i]; hn; hn = hn->next) {
@@ -337,7 +319,7 @@ setfunction(char *name, char *val, int dis)
 
     val = metafy(val, strlen(val), META_REALLOC);
 
-    prog = parse_string(val, 1);
+    prog = parse_string(val);
 
     if (!prog || prog == &dummy_eprog) {
 	zwarn("invalid function definition", value, 0);
@@ -378,7 +360,7 @@ setpmdisfunction(Param pm, char *value)
 
 /**/
 static void
-unsetpmfunction(Param pm, int exp)
+unsetpmfunction(Param pm, UNUSED(int exp))
 {
     HashNode hn = shfunctab->removenode(shfunctab, pm->nam);
 
@@ -388,7 +370,7 @@ unsetpmfunction(Param pm, int exp)
 
 /**/
 static void
-setfunctions(Param pm, HashTable ht, int dis)
+setfunctions(UNUSED(Param pm), HashTable ht, int dis)
 {
     int i;
     HashNode hn;
@@ -400,8 +382,8 @@ setfunctions(Param pm, HashTable ht, int dis)
 	for (hn = ht->nodes[i]; hn; hn = hn->next) {
 	    struct value v;
 
-	    v.isarr = v.inv = v.a = 0;
-	    v.b = -1;
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
@@ -424,24 +406,22 @@ 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(HashTable ht, char *name, int dis)
+getfunction(UNUSED(HashTable ht), char *name, int dis)
 {
     Shfunc shf;
     Param pm = NULL;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR;
-    pm->sets.cfn = (dis ? setpmdisfunction : setpmfunction);
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmfunction;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = dis ? &pmdisfunction_gsu :  &pmfunction_gsu;
 
     if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
 	(dis ? (shf->flags & DISABLED) : !(shf->flags & DISABLED))) {
@@ -451,9 +431,18 @@ getfunction(HashTable ht, char *name, int dis)
 				((shf->flags & PM_TAGGED) ? "Ut" : "U") :
 				((shf->flags & PM_TAGGED) ? "t" : "")));
 	} else {
-	    char *t = getpermtext(shf->funcdef, NULL), *h;
-
-	    h = dupstring(t);
+	    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);
 
@@ -482,21 +471,15 @@ getpmdisfunction(HashTable ht, char *name)
 
 /**/
 static void
-scanfunctions(HashTable ht, ScanFunc func, int flags, int dis)
+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.sets.cfn = (dis ? setpmdisfunction : setpmfunction);
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmcommand;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = dis ? &pmdisfunction_gsu : &pmfunction_gsu;
 
     for (i = 0; i < shfunctab->hsize; i++)
 	for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
@@ -513,9 +496,18 @@ scanfunctions(HashTable ht, ScanFunc func, int flags, int dis)
 				    ((shf->flags & PM_TAGGED) ? "Ut" : "U") :
 				    ((shf->flags & PM_TAGGED) ? "t" : "")));
 		    } else {
-			char *t = getpermtext(((Shfunc) hn)->funcdef, NULL);
-
-			pm.u.str = dupstring(t);
+			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);
 		    }
@@ -543,7 +535,7 @@ scanpmdisfunctions(HashTable ht, ScanFunc func, int flags)
 
 /**/
 static char **
-funcstackgetfn(Param pm)
+funcstackgetfn(UNUSED(Param pm))
 {
     Funcstack f;
     int num;
@@ -564,22 +556,15 @@ funcstackgetfn(Param pm)
 
 /**/
 static HashNode
-getbuiltin(HashTable ht, char *name, int dis)
+getbuiltin(UNUSED(HashTable ht), char *name, int dis)
 {
     Param pm = NULL;
     Builtin bn;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    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)) ?
@@ -609,21 +594,15 @@ getpmdisbuiltin(HashTable ht, char *name)
 
 /**/
 static void
-scanbuiltins(HashTable ht, ScanFunc func, int flags, int dis)
+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.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < builtintab->hsize; i++)
 	for (hn = builtintab->nodes[i]; hn; hn = hn->next) {
@@ -680,14 +659,14 @@ getreswords(int dis)
 
 /**/
 static char **
-reswordsgetfn(Param pm)
+reswordsgetfn(UNUSED(Param pm))
 {
     return getreswords(0);
 }
 
 /**/
 static char **
-disreswordsgetfn(Param pm)
+disreswordsgetfn(UNUSED(Param pm))
 {
     return getreswords(DISABLED);
 }
@@ -711,7 +690,7 @@ setpmoption(Param pm, char *value)
 
 /**/
 static void
-unsetpmoption(Param pm, int exp)
+unsetpmoption(Param pm, UNUSED(int exp))
 {
     int n;
 
@@ -723,7 +702,7 @@ unsetpmoption(Param pm, int exp)
 
 /**/
 static void
-setpmoptions(Param pm, HashTable ht)
+setpmoptions(UNUSED(Param pm), HashTable ht)
 {
     int i;
     HashNode hn;
@@ -736,8 +715,8 @@ setpmoptions(Param pm, HashTable ht)
 	    struct value v;
 	    char *val;
 
-	    v.isarr = v.inv = v.a = 0;
-	    v.b = -1;
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
@@ -751,27 +730,30 @@ setpmoptions(Param pm, HashTable ht)
     deleteparamtable(ht);
 }
 
+static const struct gsu_scalar pmoption_gsu =
+{ strgetfn, setpmoption, unsetpmoption };
+
 /**/
 static HashNode
-getpmoption(HashTable ht, char *name)
+getpmoption(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     int n;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR;
-    pm->sets.cfn = setpmoption;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmoption;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &pmoption_gsu;
 
     if ((n = optlookup(name)))
-	pm->u.str = dupstring(opts[n] ? "on" : "off");
+    {
+	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;
@@ -781,21 +763,15 @@ getpmoption(HashTable ht, char *name)
 
 /**/
 static void
-scanpmoptions(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = setpmoption;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmoption;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &pmoption_gsu;
 
     for (i = 0; i < optiontab->hsize; i++)
 	for (hn = optiontab->nodes[i]; hn; hn = hn->next) {
@@ -814,7 +790,7 @@ static int modpmfound;
 
 /**/
 static void
-modpmbuiltinscan(HashNode hn, int dummy)
+modpmbuiltinscan(HashNode hn, UNUSED(int dummy))
 {
     if (!(((Builtin) hn)->flags & BINF_ADDED) &&
 	!strcmp(((Builtin) hn)->optstr, modpmname))
@@ -823,7 +799,7 @@ modpmbuiltinscan(HashNode hn, int dummy)
 
 /**/
 static void
-modpmparamscan(HashNode hn, int dummy)
+modpmparamscan(HashNode hn, UNUSED(int dummy))
 {
     if ((((Param) hn)->flags & PM_AUTOLOAD) &&
 	!strcmp(((Param) hn)->u.str, modpmname))
@@ -845,23 +821,16 @@ findmodnode(LinkList l, char *nam)
 
 /**/
 static HashNode
-getpmmodule(HashTable ht, char *name)
+getpmmodule(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     char *type = NULL;
     LinkNode node;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &nullsetscalar_gsu;
 
     if (!type) {
 	Module m;
@@ -870,7 +839,8 @@ getpmmodule(HashTable ht, char *name)
 	    m = (Module) getdata(node);
 	    if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
 		!strcmp(name, m->nam)) {
-		type = "loaded";
+		type = ((m->flags & MOD_ALIAS) ?
+			dyncat("alias:", m->u.alias) : "loaded");
 		break;
 	    }
 	}
@@ -904,7 +874,7 @@ getpmmodule(HashTable ht, char *name)
 
 /**/
 static void
-scanpmmodules(HashTable ht, ScanFunc func, int flags)
+scanpmmodules(UNUSED(HashTable ht), ScanFunc func, int flags)
 {
     struct param pm;
     int i;
@@ -913,23 +883,18 @@ scanpmmodules(HashTable ht, ScanFunc func, int flags)
     LinkNode node;
     Module m;
     Conddef p;
+    char *loaded = dupstring("loaded");
 
+    memset((void *)&pm, 0, sizeof(struct param));
     pm.flags = PM_SCALAR | PM_READONLY;
-    pm.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
-
-    pm.u.str = dupstring("builtin");
-    pm.u.str = dupstring("loaded");
+    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);
 	}
@@ -965,7 +930,7 @@ scanpmmodules(HashTable ht, ScanFunc func, int flags)
 
 /**/
 static void
-dirssetfn(Param pm, char **x)
+dirssetfn(UNUSED(Param pm), char **x)
 {
     char **ox = x;
 
@@ -981,7 +946,7 @@ dirssetfn(Param pm, char **x)
 
 /**/
 static char **
-dirsgetfn(Param pm)
+dirsgetfn(UNUSED(Param pm))
 {
     int l = countlinknodes(dirstack);
     char **ret = (char **) zhalloc((l + 1) * sizeof(char *)), **p;
@@ -998,23 +963,28 @@ dirsgetfn(Param pm)
 
 /**/
 static HashNode
-getpmhistory(HashTable ht, char *name)
+getpmhistory(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     Histent he;
+    char *p;
+    int ok = 1;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
-    if ((he = quietgethist(atoi(name))))
+    pm->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("");
@@ -1025,26 +995,20 @@ getpmhistory(HashTable ht, char *name)
 
 /**/
 static void
-scanpmhistory(HashTable ht, ScanFunc func, int flags)
+scanpmhistory(UNUSED(HashTable ht), ScanFunc func, int flags)
 {
     struct param pm;
     int i = addhistnum(curhist, -1, HIST_FOREIGN);
-    Histent he = quietgethistent(i, GETHIST_UPWARD);
+    Histent he = gethistent(i, GETHIST_UPWARD);
     char buf[40];
 
+    memset((void *)&pm, 0, sizeof(struct param));
     pm.flags = PM_SCALAR | PM_READONLY;
-    pm.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &nullsetscalar_gsu;
 
     while (he) {
 	if (func != scancountparams) {
-	    sprintf(buf, "%d", he->histnum);
+	    convbase(buf, he->histnum, 10);
 	    pm.nam = dupstring(buf);
 	    if ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
 		!(flags & SCANPM_WANTKEYS))
@@ -1060,13 +1024,17 @@ scanpmhistory(HashTable ht, ScanFunc func, int flags)
 
 /**/
 static char **
-histwgetfn(Param pm)
+histwgetfn(UNUSED(Param pm))
 {
     char **ret, **p, *h, *e, sav;
-    LinkList l = newlinklist();
+    LinkList l = newlinklist(), ll;
     LinkNode n;
     int i = addhistnum(curhist, -1, HIST_FOREIGN), iw;
-    Histent he = quietgethistent(i, GETHIST_UPWARD);
+    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--) {
@@ -1114,24 +1082,17 @@ pmjobtext(int job)
 
 /**/
 static HashNode
-getpmjobtext(HashTable ht, char *name)
+getpmjobtext(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     int job;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
-
-    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+    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);
@@ -1144,23 +1105,17 @@ getpmjobtext(HashTable ht, char *name)
 
 /**/
 static void
-scanpmjobtexts(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
-
-    for (job = 1; job < MAXJOB; job++) {
+    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) {
@@ -1182,14 +1137,21 @@ static char *
 pmjobstate(int job)
 {
     Process pn;
-    char buf[256], buf2[128], *ret, *state;
+    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 = dupstring("done");
+	ret = dyncat("done", cp);
     else if (jobtab[job].stat & STAT_STOPPED)
-	ret = dupstring("suspended");
+	ret = dyncat("suspended", cp);
     else
-	ret = dupstring("running");
+	ret = dyncat("running", cp);
 
     for (pn = jobtab[job].procs; pn; pn = pn->next) {
 
@@ -1208,7 +1170,7 @@ pmjobstate(int job)
 	else
 	    state = sigmsg(WTERMSIG(pn->status));
 
-	sprintf(buf, ":%d=%s", pn->pid, state);
+	sprintf(buf, ":%d=%s", (int)pn->pid, state);
 
 	ret = dyncat(ret, buf);
     }
@@ -1217,24 +1179,17 @@ pmjobstate(int job)
 
 /**/
 static HashNode
-getpmjobstate(HashTable ht, char *name)
+getpmjobstate(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     int job;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
-
-    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+    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);
@@ -1247,23 +1202,17 @@ getpmjobstate(HashTable ht, char *name)
 
 /**/
 static void
-scanpmjobstates(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
-
-    for (job = 1; job < MAXJOB; job++) {
+    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) {
@@ -1292,24 +1241,17 @@ pmjobdir(int job)
 
 /**/
 static HashNode
-getpmjobdir(HashTable ht, char *name)
+getpmjobdir(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     int job;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
-
-    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+    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);
@@ -1322,23 +1264,17 @@ getpmjobdir(HashTable ht, char *name)
 
 /**/
 static void
-scanpmjobdirs(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
-
-    for (job = 1; job < MAXJOB; job++) {
+    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) {
@@ -1359,16 +1295,20 @@ scanpmjobdirs(HashTable ht, ScanFunc func, int flags)
 static void
 setpmnameddir(Param pm, char *value)
 {
-    if (!value || *value != '/' || strlen(value) >= PATH_MAX)
-	zwarn("invalid value: %s", value, 0);
-    else
-	adduserdir(pm->nam, value, 0, 1);
-    zsfree(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, int exp)
+unsetpmnameddir(Param pm, UNUSED(int exp))
 {
     HashNode hd = nameddirtab->removenode(nameddirtab, pm->nam);
 
@@ -1378,7 +1318,7 @@ unsetpmnameddir(Param pm, int exp)
 
 /**/
 static void
-setpmnameddirs(Param pm, HashTable ht)
+setpmnameddirs(UNUSED(Param pm), HashTable ht)
 {
     int i;
     HashNode hn, next, hd;
@@ -1399,16 +1339,20 @@ setpmnameddirs(Param pm, HashTable ht)
 	    struct value v;
 	    char *val;
 
-	    v.isarr = v.inv = v.a = 0;
-	    v.b = -1;
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
-	    if (!(val = getstrvalue(&v)) || *val != '/' ||
-		strlen(val) >= PATH_MAX)
-		zwarn("invalid value: %s", val, 0);
-	    else
-		adduserdir(hn->nam, val, 0, 1);
+	    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
@@ -1420,24 +1364,20 @@ setpmnameddirs(Param pm, HashTable ht)
     opts[INTERACTIVE] = i;
 }
 
+static const struct gsu_scalar pmnamedir_gsu =
+{ strgetfn, setpmnameddir, unsetpmnameddir };
+
 /**/
 static HashNode
-getpmnameddir(HashTable ht, char *name)
+getpmnameddir(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     Nameddir nd;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR;
-    pm->sets.cfn = setpmnameddir;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmnameddir;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &pmnamedir_gsu;
     if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
 	!(nd->flags & ND_USERNAME))
 	pm->u.str = dupstring(nd->dir);
@@ -1450,22 +1390,16 @@ getpmnameddir(HashTable ht, char *name)
 
 /**/
 static void
-scanpmnameddirs(HashTable ht, ScanFunc func, int flags)
+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.sets.cfn = setpmnameddir;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmnameddir;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &pmnamedir_gsu;
 
     for (i = 0; i < nameddirtab->hsize; i++)
 	for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
@@ -1484,24 +1418,17 @@ scanpmnameddirs(HashTable ht, ScanFunc func, int flags)
 
 /**/
 static HashNode
-getpmuserdir(HashTable ht, char *name)
+getpmuserdir(UNUSED(HashTable ht), char *name)
 {
     Param pm = NULL;
     Nameddir nd;
 
     nameddirtab->filltable(nameddirtab);
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
     pm->flags = PM_SCALAR | PM_READONLY;
-    pm->sets.cfn = NULL;
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = NULL;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
+    pm->gsu.s = &nullsetscalar_gsu;
     if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
 	(nd->flags & ND_USERNAME))
 	pm->u.str = dupstring(nd->dir);
@@ -1514,7 +1441,7 @@ getpmuserdir(HashTable ht, char *name)
 
 /**/
 static void
-scanpmuserdirs(HashTable ht, ScanFunc func, int flags)
+scanpmuserdirs(UNUSED(HashTable ht), ScanFunc func, int flags)
 {
     struct param pm;
     int i;
@@ -1523,15 +1450,9 @@ scanpmuserdirs(HashTable ht, ScanFunc func, int flags)
 
     nameddirtab->filltable(nameddirtab);
 
+    memset((void *)&pm, 0, sizeof(struct param));
     pm.flags = PM_SCALAR | PM_READONLY;
-    pm.sets.cfn = NULL;
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = NULL;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
+    pm.gsu.s = &nullsetscalar_gsu;
 
     for (i = 0; i < nameddirtab->hsize; i++)
 	for (hn = nameddirtab->nodes[i]; hn; hn = hn->next) {
@@ -1546,54 +1467,61 @@ scanpmuserdirs(HashTable ht, ScanFunc func, int flags)
 	}
 }
 
-/* Functions for the regularaliases and globalaliases special parameters. */
+/* Functions for the raliases, galiases and saliases special parameters. */
 
 /**/
 static void
-setralias(Param pm, char *value, int dis)
+setalias(HashTable ht, Param pm, char *value, int flags)
 {
-    aliastab->addnode(aliastab, ztrdup(pm->nam), createaliasnode(value, dis));
+    ht->addnode(ht, ztrdup(pm->nam),
+		createaliasnode(value, flags));
 }
 
 /**/
 static void
 setpmralias(Param pm, char *value)
 {
-    setralias(pm, value, 0);
+    setalias(aliastab, pm, value, 0);
 }
 
 /**/
 static void
 setpmdisralias(Param pm, char *value)
 {
-    setralias(pm, value, DISABLED);
+    setalias(aliastab, pm, value, DISABLED);
 }
 
 /**/
 static void
-setgalias(Param pm, char *value, int dis)
+setpmgalias(Param pm, char *value)
 {
-    aliastab->addnode(aliastab, ztrdup(pm->nam),
-		      createaliasnode(value, dis | ALIAS_GLOBAL));
+    setalias(aliastab, pm, value, ALIAS_GLOBAL);
 }
 
 /**/
 static void
-setpmgalias(Param pm, char *value)
+setpmdisgalias(Param pm, char *value)
 {
-    setgalias(pm, value, 0);
+    setalias(aliastab, pm, value, ALIAS_GLOBAL|DISABLED);
 }
 
 /**/
 static void
-setpmdisgalias(Param pm, char *value)
+setpmsalias(Param pm, char *value)
 {
-    setgalias(pm, value, DISABLED);
+    setalias(sufaliastab, pm, value, ALIAS_SUFFIX);
 }
 
 /**/
 static void
-unsetpmalias(Param pm, int exp)
+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);
 
@@ -1603,7 +1531,17 @@ unsetpmalias(Param pm, int exp)
 
 /**/
 static void
-setaliases(Param pm, HashTable ht, int global, int dis)
+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;
@@ -1611,13 +1549,18 @@ setaliases(Param pm, HashTable ht, int global, int dis)
     if (!ht)
 	return;
 
-    for (i = 0; i < aliastab->hsize; i++)
-	for (hn = aliastab->nodes[i]; hn; hn = next) {
+    for (i = 0; i < alht->hsize; i++)
+	for (hn = alht->nodes[i]; hn; hn = next) {
 	    next = hn->next;
-	    if (((global && (((Alias) hn)->flags & ALIAS_GLOBAL)) ||
-		 (!global && !(((Alias) hn)->flags & ALIAS_GLOBAL))) &&
-		(hd = aliastab->removenode(aliastab, hn->nam)))
-		aliastab->freenode(hd);
+	    /*
+	     * 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++)
@@ -1625,16 +1568,14 @@ setaliases(Param pm, HashTable ht, int global, int dis)
 	    struct value v;
 	    char *val;
 
-	    v.isarr = v.inv = v.a = 0;
-	    v.b = -1;
+	    v.isarr = v.inv = v.start = 0;
+	    v.end = -1;
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
 	    if ((val = getstrvalue(&v)))
-		aliastab->addnode(aliastab, ztrdup(hn->nam),
-				  createaliasnode(ztrdup(val),
-						  (global ? ALIAS_GLOBAL : 0) |
-						  (dis ? DISABLED : 0)));
+		alht->addnode(alht, ztrdup(hn->nam),
+			      createaliasnode(ztrdup(val), flags));
 	}
     deleteparamtable(ht);
 }
@@ -1643,53 +1584,105 @@ setaliases(Param pm, HashTable ht, int global, int dis)
 static void
 setpmraliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 0, 0);
+    setaliases(aliastab, pm, ht, 0);
 }
 
 /**/
 static void
 setpmdisraliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 0, DISABLED);
+    setaliases(aliastab, pm, ht, DISABLED);
 }
 
 /**/
 static void
 setpmgaliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 1, 0);
+    setaliases(aliastab, pm, ht, ALIAS_GLOBAL);
 }
 
 /**/
 static void
 setpmdisgaliases(Param pm, HashTable ht)
 {
-    setaliases(pm, ht, 1, DISABLED);
+    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 ht, char *name, int global, int dis)
+getalias(HashTable alht, UNUSED(HashTable ht), char *name, int flags)
 {
     Param pm = NULL;
     Alias al;
 
-    pm = (Param) zhalloc(sizeof(struct param));
+    pm = (Param) hcalloc(sizeof(struct param));
     pm->nam = dupstring(name);
-    pm->flags = PM_SCALAR;
-    pm->sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
-		    (dis ? setpmdisralias : setpmralias));
-    pm->gets.cfn = strgetfn;
-    pm->unsetfn = unsetpmalias;
-    pm->ct = 0;
-    pm->env = NULL;
-    pm->ename = NULL;
-    pm->old = NULL;
-    pm->level = 0;
-    if ((al = (Alias) aliastab->getnode2(aliastab, name)) &&
-	((global && (al->flags & ALIAS_GLOBAL)) ||
-	 (!global && !(al->flags & ALIAS_GLOBAL))) &&
-	(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED)))
+
+    assignaliasdefs(pm, flags);
+
+    if ((al = (Alias) alht->getnode2(alht, name)) &&
+	flags == al->flags)
 	pm->u.str = dupstring(al->text);
     else {
 	pm->u.str = dupstring("");
@@ -1702,61 +1695,65 @@ getalias(HashTable ht, char *name, int global, int dis)
 static HashNode
 getpmralias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 0, 0);
+    return getalias(aliastab, ht, name, 0);
 }
 
 /**/
 static HashNode
 getpmdisralias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 0, 0);
+    return getalias(aliastab, ht, name, DISABLED);
 }
 
 /**/
 static HashNode
 getpmgalias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 1, 0);
+    return getalias(aliastab, ht, name, ALIAS_GLOBAL);
 }
 
 /**/
 static HashNode
 getpmdisgalias(HashTable ht, char *name)
 {
-    return getalias(ht, name, 1, DISABLED);
+    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 ht, ScanFunc func, int flags, int global, int dis)
+scanaliases(HashTable alht, UNUSED(HashTable ht), ScanFunc func,
+	    int pmflags, int alflags)
 {
     struct param pm;
     int i;
-    HashNode hn;
     Alias al;
 
-    pm.flags = PM_SCALAR;
-    pm.sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
-		   (dis ? setpmdisralias : setpmralias));
-    pm.gets.cfn = strgetfn;
-    pm.unsetfn = unsetpmalias;
-    pm.ct = 0;
-    pm.env = NULL;
-    pm.ename = NULL;
-    pm.old = NULL;
-    pm.level = 0;
-
-    for (i = 0; i < aliastab->hsize; i++)
-	for (hn = aliastab->nodes[i]; hn; hn = hn->next) {
-	    if (((global && ((al = (Alias) hn)->flags & ALIAS_GLOBAL)) ||
-		 (!global && !((al = (Alias) hn)->flags & ALIAS_GLOBAL))) &&
-		(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED))) {
-		pm.nam = hn->nam;
+    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 &&
-		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
-		     !(flags & SCANPM_WANTKEYS)))
+		    ((pmflags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(pmflags & SCANPM_WANTKEYS)))
 		    pm.u.str = dupstring(al->text);
-		func((HashNode) &pm, flags);
+		func((HashNode) &pm, pmflags);
 	    }
 	}
 }
@@ -1765,28 +1762,42 @@ scanaliases(HashTable ht, ScanFunc func, int flags, int global, int dis)
 static void
 scanpmraliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 0, 0);
+    scanaliases(aliastab, ht, func, flags, 0);
 }
 
 /**/
 static void
 scanpmdisraliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 0, DISABLED);
+    scanaliases(aliastab, ht, func, flags, DISABLED);
 }
 
 /**/
 static void
 scanpmgaliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 1, 0);
+    scanaliases(aliastab, ht, func, flags, ALIAS_GLOBAL);
 }
 
 /**/
 static void
 scanpmdisgaliases(HashTable ht, ScanFunc func, int flags)
 {
-    scanaliases(ht, func, flags, 1, DISABLED);
+    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. */
@@ -1796,89 +1807,134 @@ struct pardef {
     int flags;
     GetNodeFunc getnfn;
     ScanTabFunc scantfn;
-    void (*hsetfn) _((Param, HashTable));
-    void (*setfn) _((Param, char **));
-    char **(*getfn) _((Param));
-    void (*unsetfn) _((Param, int));
+    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, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmparameter, scanpmparameters, &pmnullsethash_gsu,
+      NULL, NULL },
     { "commands", 0,
-      getpmcommand, scanpmcommands, setpmcommands,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmcommand, scanpmcommands, &pmcommands_gsu,
+      NULL, NULL },
     { "functions", 0,
-      getpmfunction, scanpmfunctions, setpmfunctions,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmfunction, scanpmfunctions, &pmfunctions_gsu,
+      NULL, NULL },
     { "dis_functions", 0,
-      getpmdisfunction, scanpmdisfunctions, setpmdisfunctions,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmdisfunction, scanpmdisfunctions, &pmdisfunctions_gsu,
+      NULL, NULL },
     { "funcstack", PM_ARRAY|PM_SPECIAL|PM_READONLY,
       NULL, NULL, NULL,
-      arrsetfn, funcstackgetfn, stdunsetfn, NULL },
+      &funcstack_gsu, NULL },
     { "builtins", PM_READONLY,
-      getpmbuiltin, scanpmbuiltins, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmbuiltin, scanpmbuiltins, NULL,
+      NULL, NULL },
     { "dis_builtins", PM_READONLY,
-      getpmdisbuiltin, scanpmdisbuiltins, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmdisbuiltin, scanpmdisbuiltins,
+      NULL, NULL, },
     { "reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
       NULL, NULL, NULL,
-      arrsetfn, reswordsgetfn, stdunsetfn, NULL },
+      &reswords_gsu, NULL },
     { "dis_reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
       NULL, NULL, NULL,
-      arrsetfn, disreswordsgetfn, stdunsetfn, NULL },
+      &disreswords_gsu, NULL },
     { "options", 0,
-      getpmoption, scanpmoptions, setpmoptions,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmoption, scanpmoptions, &pmoptions_gsu,
+      NULL, NULL },
     { "modules", PM_READONLY,
-      getpmmodule, scanpmmodules, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmmodule, scanpmmodules, NULL,
+      NULL, NULL },
     { "dirstack", PM_ARRAY|PM_SPECIAL|PM_REMOVABLE,
       NULL, NULL, NULL,
-      dirssetfn, dirsgetfn, stdunsetfn, NULL },
+      &dirs_gsu, NULL },
     { "history", PM_READONLY,
-      getpmhistory, scanpmhistory, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmhistory, scanpmhistory, NULL,
+      NULL, NULL,  },
     { "historywords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
       NULL, NULL, NULL,
-      arrsetfn, histwgetfn, stdunsetfn, NULL },
+      &historywords_gsu, NULL },
     { "jobtexts", PM_READONLY,
-      getpmjobtext, scanpmjobtexts, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmjobtext, scanpmjobtexts, NULL,
+      NULL, NULL },
     { "jobstates", PM_READONLY,
-      getpmjobstate, scanpmjobstates, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmjobstate, scanpmjobstates, NULL,
+      NULL, NULL },
     { "jobdirs", PM_READONLY,
-      getpmjobdir, scanpmjobdirs, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmjobdir, scanpmjobdirs, NULL,
+      NULL, NULL },
     { "nameddirs", 0,
-      getpmnameddir, scanpmnameddirs, setpmnameddirs,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmnameddir, scanpmnameddirs, &pmnameddirs_gsu,
+      NULL, NULL },
     { "userdirs", PM_READONLY,
-      getpmuserdir, scanpmuserdirs, hashsetfn,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmuserdir, scanpmuserdirs, NULL,
+      NULL, NULL },
     { "aliases", 0,
-      getpmralias, scanpmraliases, setpmraliases,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmralias, scanpmraliases, &pmraliases_gsu,
+      NULL, NULL },
     { "galiases", 0,
-      getpmgalias, scanpmgaliases, setpmgaliases,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmgalias, scanpmgaliases, &pmgaliases_gsu,
+      NULL, NULL },
+    { "saliases", 0,
+      getpmsalias, scanpmsaliases, &pmsaliases_gsu,
+      NULL, NULL },
     { "dis_aliases", 0,
-      getpmdisralias, scanpmdisraliases, setpmdisraliases,
-      NULL, NULL, stdunsetfn, NULL },
+      getpmdisralias, scanpmdisraliases, &pmdisraliases_gsu,
+      NULL, NULL },
     { "dis_galiases", 0,
-      getpmdisgalias, scanpmdisgaliases, setpmdisgaliases,
-      NULL, NULL, stdunsetfn, NULL },
-    { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+      getpmdisgalias, scanpmdisgaliases, &pmdisgaliases_gsu,
+      NULL, NULL },
+    { "dis_saliases", 0,
+      getpmdissalias, scanpmdissaliases, &pmdissaliases_gsu,
+      NULL, NULL },
+    { NULL, 0, NULL, NULL, NULL, NULL, NULL }
 };
 
 /**/
 int
-setup_(Module m)
+setup_(UNUSED(Module m))
 {
     incleanup = 0;
 
@@ -1887,7 +1943,7 @@ setup_(Module m)
 
 /**/
 int
-boot_(Module m)
+boot_(UNUSED(Module m))
 {
     /* Create the special associative arrays.
      * As an example for autoloaded parameters, this is probably a bad
@@ -1904,15 +1960,13 @@ boot_(Module m)
 					      def->scantfn)))
 		return 1;
 	    def->pm->flags |= def->flags;
-	    if (def->hsetfn)
-		def->pm->sets.hfn = def->hsetfn;
+	    if (def->hash_gsu)
+		def->pm->gsu.h = def->hash_gsu;
 	} else {
-	    if (!(def->pm = createparam(def->name, def->flags | PM_HIDE |
-					PM_REMOVABLE)))
+	    if (!(def->pm = createparam(def->name, def->flags | PM_HIDE|
+					PM_HIDEVAL | PM_REMOVABLE)))
 		return 1;
-	    def->pm->sets.afn = def->setfn;
-	    def->pm->gets.afn = def->getfn;
-	    def->pm->unsetfn = def->unsetfn;
+	    def->pm->gsu.a = def->array_gsu;
 	}
     }
     return 0;
@@ -1920,7 +1974,7 @@ boot_(Module m)
 
 /**/
 int
-cleanup_(Module m)
+cleanup_(UNUSED(Module m))
 {
     Param pm;
     struct pardef *def;
@@ -1939,7 +1993,7 @@ cleanup_(Module m)
 
 /**/
 int
-finish_(Module m)
+finish_(UNUSED(Module m))
 {
     return 0;
 }