openenvutils/commandshell/shell/src/modules/parameter.c
author William Roberts <williamr@symbian.org>
Fri, 23 Apr 2010 14:37:17 +0100
branchRCL_3
changeset 22 c82a39b81a38
parent 4 0fdb7f6b0309
permissions -rw-r--r--
Rework addition of Symbian splash screen to reduce the source impact (uses SVG from Bug 2414) Notes: by using the OPTION SOURCEDIR parameter in the mifconv extension instructions, I can arrange to use the same source file name in sfimage, without having to export over the original Nokia file. This means that the name inside splashscreen.mbg is the same, which removes the need for the conditional compilation in SplashScreen.cpp, and gets rid of sf_splashscreen.mmp.

/*
* Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/


/*
 * 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;
}