about summary refs log tree commit diff
path: root/Src/Modules
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:49:47 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:49:47 +0000
commit48525452555a24b9d41748f26b4b77f160f01220 (patch)
treed814ca2f017d9d843fec7d286fefbca78244beb5 /Src/Modules
parente025336f2f6d9f107ee1e03b9900f04af0544ba9 (diff)
downloadzsh-48525452555a24b9d41748f26b4b77f160f01220.tar.gz
zsh-48525452555a24b9d41748f26b4b77f160f01220.tar.xz
zsh-48525452555a24b9d41748f26b4b77f160f01220.zip
Updated from list as far as 10376
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/parameter.c1699
-rw-r--r--Src/Modules/zpty.c153
2 files changed, 1615 insertions, 237 deletions
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index 2257933f5..e8e387a59 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -30,6 +30,10 @@
 #include "parameter.mdh"
 #include "parameter.pro"
 
+/* This says if we are cleaning up when the module is unloaded. */
+
+static int incleanup;
+
 /* Empty dummy function for special hash parameters. */
 
 /**/
@@ -47,14 +51,14 @@ createspecialhash(char *name, GetNodeFunc get, ScanTabFunc scan)
     Param pm;
     HashTable ht;
 
-    if (!(pm = createparam(name, PM_SPECIAL|PM_REMOVABLE|PM_HASHED)))
+    if (!(pm = createparam(name, PM_SPECIAL|PM_HIDE|PM_REMOVABLE|PM_HASHED)))
 	return NULL;
 
     pm->level = pm->old ? locallevel : 0;
     pm->gets.hfn = hashgetfn;
     pm->sets.hfn = hashsetfn;
     pm->unsetfn = stdunsetfn;
-    pm->u.hash = ht = newhashtable(7, name, NULL);
+    pm->u.hash = ht = newhashtable(0, name, NULL);
 
     ht->hash        = hasher;
     ht->emptytable  = (TableFunc) shempty;
@@ -83,14 +87,21 @@ paramtypestr(Param pm)
     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)
@@ -109,6 +120,10 @@ paramtypestr(Param pm)
 	    val = dyncat(val, "-export");
 	if (f & PM_UNIQUE)
 	    val = dyncat(val, "-unique");
+	if (f & PM_HIDE)
+	    val = dyncat(val, "-hide");
+	if (f & PM_SPECIAL)
+	    val = dyncat(val, "-special");
     } else
 	val = dupstring("");
 
@@ -121,27 +136,24 @@ getpmparameter(HashTable ht, char *name)
 {
     Param rpm, pm = NULL;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR | PM_READONLY;
-	pm->sets.cfn = NULL;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = NULL;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
-	    !(rpm->flags & PM_UNSET))
-	    pm->u.str = paramtypestr(rpm);
-	else {
-	    pm->u.str = "";
-	    pm->flags |= PM_UNSET;
-	}
-    } LASTALLOC;
-
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((rpm = (Param) realparamtab->getnode(realparamtab, name)) &&
+	!(rpm->flags & PM_UNSET))
+	pm->u.str = paramtypestr(rpm);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -166,7 +178,9 @@ scanpmparameters(HashTable ht, ScanFunc func, int flags)
     for (i = 0; i < realparamtab->hsize; i++)
 	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
 	    pm.nam = hn->nam;
-	    if (func != scancountparams)
+	    if (func != scancountparams &&
+		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		 !(flags & SCANPM_WANTKEYS)))
 		pm.u.str = paramtypestr((Param) hn);
 	    func((HashNode) &pm, flags);
 	}
@@ -179,12 +193,12 @@ static void
 setpmcommand(Param pm, char *value)
 {
     if (isset(RESTRICTED))
-	zwarnnam(NULL, "restricted: %s", value, 0);
+	zwarn("restricted: %s", value, 0);
     else {
 	Cmdnam cn = zcalloc(sizeof(*cn));
 
 	cn->flags = HASHED;
-	cn->u.cmd = ztrdup(value);
+	cn->u.cmd = value;
 
 	cmdnamtab->addnode(cmdnamtab, ztrdup(pm->nam), (HashNode) cn);
     }
@@ -207,6 +221,9 @@ setpmcommands(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 = zcalloc(sizeof(*cn));
@@ -222,6 +239,7 @@ setpmcommands(Param pm, HashTable ht)
 
 	    cmdnamtab->addnode(cmdnamtab, ztrdup(hn->nam), (HashNode) cn);
 	}
+    deleteparamtable(ht);
 }
 
 /**/
@@ -236,34 +254,30 @@ getpmcommand(HashTable ht, char *name)
 	cmdnamtab->filltable(cmdnamtab);
 	cmd = (Cmdnam) cmdnamtab->getnode(cmdnamtab, name);
     }
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmcommand;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmcommand;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-	if (cmd) {
-	    if (cmd->flags & HASHED)
-		pm->u.str = cmd->u.cmd;
-	    else {
-		pm->u.str = zhalloc(strlen(*(cmd->u.name)) +
-				    strlen(name) + 2);
-		strcpy(pm->u.str, *(cmd->u.name));
-		strcat(pm->u.str, "/");
-		strcat(pm->u.str, name);
-	    }
-	} else {
-	    pm->u.str = "";
-	    pm->flags |= PM_UNSET;
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = setpmcommand;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmcommand;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if (cmd) {
+	if (cmd->flags & HASHED)
+	    pm->u.str = cmd->u.cmd;
+	else {
+	    pm->u.str = zhalloc(strlen(*(cmd->u.name)) + strlen(name) + 2);
+	    strcpy(pm->u.str, *(cmd->u.name));
+	    strcat(pm->u.str, "/");
+	    strcat(pm->u.str, name);
 	}
-    } LASTALLOC;
-
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -293,7 +307,9 @@ scanpmcommands(HashTable ht, ScanFunc func, int flags)
 	for (hn = cmdnamtab->nodes[i]; hn; hn = hn->next) {
 	    pm.nam = hn->nam;
 	    cmd = (Cmdnam) hn;
-	    if (func != scancountparams) {
+	    if (func != scancountparams &&
+		((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		 !(flags & SCANPM_WANTKEYS))) {
 		if (cmd->flags & HASHED)
 		    pm.u.str = cmd->u.cmd;
 		else {
@@ -312,43 +328,37 @@ scanpmcommands(HashTable ht, ScanFunc func, int flags)
 
 /**/
 static void
-setfunction(char *name, char *value)
+setfunction(char *name, char *val, int dis)
 {
-    char *val;
+    char *value = dupstring(val);
     Shfunc shf;
-    List list;
+    Eprog prog;
     int sn;
 
-    val = ztrdup(value);
     val = metafy(val, strlen(val), META_REALLOC);
 
-    HEAPALLOC {
-	list = parse_string(val);
-    } LASTALLOC;
+    prog = parse_string(val, 1);
 
-    if (!list || list == &dummy_list) {
-	zwarnnam(NULL, "invalid function definition", val, 0);
+    if (!prog || prog == &dummy_eprog) {
+	zwarn("invalid function definition", value, 0);
 	zsfree(val);
 	return;
     }
-    PERMALLOC {
-	shf = (Shfunc) zalloc(sizeof(*shf));
-	shf->funcdef = (List) dupstruct(list);
-	shf->flags = 0;
-
-	if (!strncmp(name, "TRAP", 4) &&
-	    (sn = getsignum(name + 4)) != -1) {
-	    if (settrap(sn, shf->funcdef)) {
-		freestruct(shf->funcdef);
-		zfree(shf, sizeof(*shf));
-		zsfree(val);
-		LASTALLOC_RETURN;
-	    }
-	    sigtrapped[sn] |= ZSIG_FUNC;
+    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;
 	}
-	shfunctab->addnode(shfunctab, ztrdup(name), shf);
-    } LASTALLOC;
-
+	sigtrapped[sn] |= ZSIG_FUNC;
+    }
+    shfunctab->addnode(shfunctab, ztrdup(name), shf);
     zsfree(val);
 }
 
@@ -356,7 +366,14 @@ setfunction(char *name, char *value)
 static void
 setpmfunction(Param pm, char *value)
 {
-    setfunction(pm->nam, value);
+    setfunction(pm->nam, value, 0);
+}
+
+/**/
+static void
+setpmdisfunction(Param pm, char *value)
+{
+    setfunction(pm->nam, value, DISABLED);
 }
 
 /**/
@@ -371,11 +388,14 @@ unsetpmfunction(Param pm, int exp)
 
 /**/
 static void
-setpmfunctions(Param pm, HashTable ht)
+setfunctions(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;
@@ -385,62 +405,100 @@ setpmfunctions(Param pm, HashTable ht)
 	    v.arr = NULL;
 	    v.pm = (Param) hn;
 
-	    setfunction(hn->nam, getstrvalue(&v));
+	    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 HashNode
-getpmfunction(HashTable ht, char *name)
+getfunction(HashTable ht, char *name, int dis)
 {
     Shfunc shf;
     Param pm = NULL;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmfunction;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmfunction;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-
-	if ((shf = (Shfunc) shfunctab->getnode(shfunctab, name))) {
-	    if (shf->flags & PM_UNDEFINED)
-		pm->u.str = "undefined";
-	    else {
-		char *t = getpermtext((void *) dupstruct((void *)
-							 shf->funcdef)), *h;
-
-		h = dupstring(t);
-		zsfree(t);
-		unmetafy(h, NULL);
-
-		pm->u.str = h;
-	    }
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = (dis ? setpmdisfunction : setpmfunction);
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmfunction;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((shf = (Shfunc) shfunctab->getnode2(shfunctab, name)) &&
+	(dis ? (shf->flags & DISABLED) : !(shf->flags & DISABLED))) {
+	if (shf->flags & PM_UNDEFINED) {
+	    pm->u.str = dyncat("builtin autoload -X",
+			       ((shf->flags & PM_UNALIASED) ?
+				((shf->flags & PM_TAGGED) ? "Ut" : "U") :
+				((shf->flags & PM_TAGGED) ? "t" : "")));
 	} else {
-	    pm->u.str = "";
-	    pm->flags |= PM_UNSET;
+	    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;
 	}
-    } LASTALLOC;
-
+    } 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
-scanpmfunctions(HashTable ht, ScanFunc func, int flags)
+scanfunctions(HashTable ht, ScanFunc func, int flags, int dis)
 {
     struct param pm;
     int i;
     HashNode hn;
 
     pm.flags = PM_SCALAR;
-    pm.sets.cfn = setpmcommand;
+    pm.sets.cfn = (dis ? setpmdisfunction : setpmfunction);
     pm.gets.cfn = strgetfn;
     pm.unsetfn = unsetpmcommand;
     pm.ct = 0;
@@ -451,16 +509,32 @@ scanpmfunctions(HashTable ht, ScanFunc func, int flags)
 
     for (i = 0; i < shfunctab->hsize; i++)
 	for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
-	    if (!(hn->flags & DISABLED)) {
+	    if (dis ? (hn->flags & DISABLED) : !(hn->flags & DISABLED)) {
 		pm.nam = hn->nam;
-		if (func != scancountparams) {
-		    if (((Shfunc) hn)->flags & PM_UNDEFINED)
-			pm.u.str = "undefined";
-		    else {
-			char *t = getpermtext((void *)
-					      dupstruct((void *) ((Shfunc) hn)->funcdef));
-
-			unmetafy((pm.u.str = dupstring(t)), NULL);
+		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);
 		    }
 		}
@@ -469,6 +543,173 @@ scanpmfunctions(HashTable ht, ScanFunc func, int 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(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(HashTable ht, char *name, int dis)
+{
+    Param pm = NULL;
+    Builtin bn;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((bn = (Builtin) builtintab->getnode2(builtintab, name)) &&
+	(dis ? (bn->flags & DISABLED) : !(bn->flags & DISABLED))) {
+	char *t = ((bn->handlerfunc || (bn->flags & BINF_PREFIX)) ?
+		   "defined" : "undefined");
+
+	pm->u.str = dupstring(t);
+    } else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+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(HashTable ht, ScanFunc func, int flags, int dis)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    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 (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(Param pm)
+{
+    return getreswords(0);
+}
+
+/**/
+static char **
+disreswordsgetfn(Param pm)
+{
+    return getreswords(DISABLED);
+}
+
 /* Functions for the options special parameter. */
 
 /**/
@@ -478,11 +719,12 @@ setpmoption(Param pm, char *value)
     int n;
 
     if (!value || (strcmp(value, "on") && strcmp(value, "off")))
-	zwarnnam(NULL, "invalid value: %s", value, 0);
+	zwarn("invalid value: %s", value, 0);
     else if (!(n = optlookup(pm->nam)))
-	zwarnnam(NULL, "no such option: %s", pm->nam, 0);
+	zwarn("no such option: %s", pm->nam, 0);
     else if (dosetopt(n, (value && strcmp(value, "off")), 0))
-	zwarnnam(NULL, "can't change option: %s", pm->nam, 0);
+	zwarn("can't change option: %s", pm->nam, 0);
+    zsfree(value);
 }
 
 /**/
@@ -492,9 +734,9 @@ unsetpmoption(Param pm, int exp)
     int n;
 
     if (!(n = optlookup(pm->nam)))
-	zwarnnam(NULL, "no such option: %s", pm->nam, 0);
+	zwarn("no such option: %s", pm->nam, 0);
     else if (dosetopt(n, 0, 0))
-	zwarnnam(NULL, "can't change option: %s", pm->nam, 0);
+	zwarn("can't change option: %s", pm->nam, 0);
 }
 
 /**/
@@ -504,6 +746,9 @@ setpmoptions(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;
@@ -516,11 +761,12 @@ setpmoptions(Param pm, HashTable ht)
 
 	    val = getstrvalue(&v);
 	    if (!val || (strcmp(val, "on") && strcmp(val, "off")))
-		zwarnnam(NULL, "invalid value: %s", val, 0);
+		zwarn("invalid value: %s", val, 0);
 	    else if (dosetopt(optlookup(hn->nam),
 			      (val && strcmp(val, "off")), 0))
-		zwarnnam(NULL, "can't change option: %s", hn->nam, 0);
+		zwarn("can't change option: %s", hn->nam, 0);
 	}
+    deleteparamtable(ht);
 }
 
 /**/
@@ -530,27 +776,24 @@ getpmoption(HashTable ht, char *name)
     Param pm = NULL;
     int n;
 
-    HEAPALLOC {
-	pm = (Param) zhalloc(sizeof(struct param));
-	pm->nam = dupstring(name);
-	pm->flags = PM_SCALAR;
-	pm->sets.cfn = setpmoption;
-	pm->gets.cfn = strgetfn;
-	pm->unsetfn = unsetpmoption;
-	pm->ct = 0;
-	pm->env = NULL;
-	pm->ename = NULL;
-	pm->old = NULL;
-	pm->level = 0;
-
-	if ((n = optlookup(name)))
-	    pm->u.str = dupstring(opts[n] ? "on" : "off");
-	else {
-	    pm->u.str = "";
-	    pm->flags |= PM_UNSET;
-	}
-    } LASTALLOC;
-
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = setpmoption;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmoption;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((n = optlookup(name)))
+	pm->u.str = dupstring(opts[n] ? "on" : "off");
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
     return (HashNode) pm;
 }
 
@@ -574,89 +817,1147 @@ scanpmoptions(HashTable ht, ScanFunc func, int flags)
 
     for (i = 0; i < optiontab->hsize; i++)
 	for (hn = optiontab->nodes[i]; hn; hn = hn->next) {
+	    int optno = ((Optname) hn)->optno, ison;
 	    pm.nam = hn->nam;
-	    pm.u.str = opts[((Optname) hn)->optno] ? "on" : "off";
+	    ison = optno < 0 ? !opts[-optno] : opts[optno];
+	    pm.u.str = dupstring(ison ? "on" : "off");
 	    func((HashNode) &pm, flags);
 	}
 }
 
-/* Names and Params for the special parameters. */
+/* Functions for the modules special parameter. */
 
-#define PAR_NAM "parameters"
-#define CMD_NAM "commands"
-#define FUN_NAM "functions"
-#define OPT_NAM "options"
+static char *modpmname;
+static int modpmfound;
 
-static Param parpm, cmdpm, funpm, optpm;
+/**/
+static void
+modpmbuiltinscan(HashNode hn, int dummy)
+{
+    if (!(((Builtin) hn)->flags & BINF_ADDED) &&
+	!strcmp(((Builtin) hn)->optstr, modpmname))
+	modpmfound = 1;
+}
+
+/**/
+static void
+modpmparamscan(HashNode hn, 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(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    char *type = NULL;
+    LinkNode node;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if (!type) {
+	Module m;
+
+	for (node = firstnode(modules); node; incnode(node)) {
+	    m = (Module) getdata(node);
+	    if (m->u.handle && !(m->flags & MOD_UNLOAD) &&
+		!strcmp(name, m->nam)) {
+		type = "loaded";
+		break;
+	    }
+	}
+    }
+    modpmname = name;
+    modpmfound = 0;
+    if (!type) {
+	scanhashtable(builtintab, 0, 0, 0, modpmbuiltinscan, 0);
+	if (!modpmfound) {
+	    Conddef p;
+
+	    for (p = condtab; p; p = p->next)
+		if (p->module && !strcmp(name, p->module)) {
+		    modpmfound = 1;
+		    break;
+		}
+	    if (!modpmfound)
+		scanhashtable(realparamtab, 0, 0, 0, modpmparamscan, 0);
+	}
+	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(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    LinkList done = newlinklist();
+    LinkNode node;
+    Module m;
+    Conddef p;
+
+    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");
+    for (node = firstnode(modules); node; incnode(node)) {
+	m = (Module) getdata(node);
+	if (m->u.handle && !(m->flags & MOD_UNLOAD)) {
+	    pm.nam = m->nam;
+	    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(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(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(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    Histent he;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((he = quietgethist(atoi(name))))
+	pm->u.str = dupstring(he->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmhistory(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i = addhistnum(curhist, -1, HIST_FOREIGN);
+    Histent he = quietgethistent(i, GETHIST_UPWARD);
+    char buf[40];
+
+    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;
+
+    while (he) {
+	if (func != scancountparams) {
+	    sprintf(buf, "%d", he->histnum);
+	    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(Param pm)
+{
+    char **ret, **p, *h, *e, sav;
+    LinkList l = newlinklist();
+    LinkNode n;
+    int i = addhistnum(curhist, -1, HIST_FOREIGN), iw;
+    Histent he = quietgethistent(i, GETHIST_UPWARD);
+
+    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(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobtext(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobtexts(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    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++) {
+	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;
+
+    if (jobtab[job].stat & STAT_DONE)
+	ret = dupstring("done");
+    else if (jobtab[job].stat & STAT_STOPPED)
+	ret = dupstring("suspended");
+    else
+	ret = dupstring("running");
+
+    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", pn->pid, state);
+
+	ret = dyncat(ret, buf);
+    }
+    return ret;
+}
+
+/**/
+static HashNode
+getpmjobstate(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobstate(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobstates(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    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++) {
+	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(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    int job;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+
+    if ((job = atoi(name)) >= 1 && job < MAXJOB &&
+	jobtab[job].stat && jobtab[job].procs &&
+	!(jobtab[job].stat & STAT_NOPRINT))
+	pm->u.str = pmjobdir(job);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmjobdirs(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int job;
+    char buf[40];
+
+    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++) {
+       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 || *value != '/' || strlen(value) >= PATH_MAX)
+	zwarn("invalid value: %s", value, 0);
+    else
+	adduserdir(pm->nam, value, 0, 1);
+    zsfree(value);
+}
+
+/**/
+static void
+unsetpmnameddir(Param pm, int exp)
+{
+    HashNode hd = nameddirtab->removenode(nameddirtab, pm->nam);
+
+    if (hd)
+	nameddirtab->freenode(hd);
+}
+
+/**/
+static void
+setpmnameddirs(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.a = 0;
+	    v.b = -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);
+	}
+
+    /* 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 HashNode
+getpmnameddir(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    Nameddir nd;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = setpmnameddir;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmnameddir;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	!(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmnameddirs(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Nameddir nd;
+
+    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;
+
+    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(HashTable ht, char *name)
+{
+    Param pm = NULL;
+    Nameddir nd;
+
+    nameddirtab->filltable(nameddirtab);
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR | PM_READONLY;
+    pm->sets.cfn = NULL;
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = NULL;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((nd = (Nameddir) nameddirtab->getnode(nameddirtab, name)) &&
+	(nd->flags & ND_USERNAME))
+	pm->u.str = dupstring(nd->dir);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmuserdirs(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Nameddir nd;
+
+    nameddirtab->filltable(nameddirtab);
+
+    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 (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 regularaliases and globalaliases special parameters. */
+
+/**/
+static void
+setralias(Param pm, char *value, int dis)
+{
+    aliastab->addnode(aliastab, ztrdup(pm->nam), createaliasnode(value, dis));
+}
+
+/**/
+static void
+setpmralias(Param pm, char *value)
+{
+    setralias(pm, value, 0);
+}
+
+/**/
+static void
+setpmdisralias(Param pm, char *value)
+{
+    setralias(pm, value, DISABLED);
+}
+
+/**/
+static void
+setgalias(Param pm, char *value, int dis)
+{
+    aliastab->addnode(aliastab, ztrdup(pm->nam),
+		      createaliasnode(value, dis | ALIAS_GLOBAL));
+}
+
+/**/
+static void
+setpmgalias(Param pm, char *value)
+{
+    setgalias(pm, value, 0);
+}
+
+/**/
+static void
+setpmdisgalias(Param pm, char *value)
+{
+    setgalias(pm, value, DISABLED);
+}
+
+/**/
+static void
+unsetpmalias(Param pm, int exp)
+{
+    HashNode hd = aliastab->removenode(aliastab, pm->nam);
+
+    if (hd)
+	aliastab->freenode(hd);
+}
+
+/**/
+static void
+setaliases(Param pm, HashTable ht, int global, int dis)
+{
+    int i;
+    HashNode hn, next, hd;
+
+    if (!ht)
+	return;
+
+    for (i = 0; i < aliastab->hsize; i++)
+	for (hn = aliastab->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);
+	}
+
+    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.a = 0;
+	    v.b = -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)));
+	}
+    deleteparamtable(ht);
+}
+
+/**/
+static void
+setpmraliases(Param pm, HashTable ht)
+{
+    setaliases(pm, ht, 0, 0);
+}
+
+/**/
+static void
+setpmdisraliases(Param pm, HashTable ht)
+{
+    setaliases(pm, ht, 0, DISABLED);
+}
+
+/**/
+static void
+setpmgaliases(Param pm, HashTable ht)
+{
+    setaliases(pm, ht, 1, 0);
+}
+
+/**/
+static void
+setpmdisgaliases(Param pm, HashTable ht)
+{
+    setaliases(pm, ht, 1, DISABLED);
+}
+
+/**/
+static HashNode
+getalias(HashTable ht, char *name, int global, int dis)
+{
+    Param pm = NULL;
+    Alias al;
+
+    pm = (Param) zhalloc(sizeof(struct param));
+    pm->nam = dupstring(name);
+    pm->flags = PM_SCALAR;
+    pm->sets.cfn = (global ? (dis ? setpmdisgalias : setpmgalias) :
+		    (dis ? setpmdisralias : setpmralias));
+    pm->gets.cfn = strgetfn;
+    pm->unsetfn = unsetpmalias;
+    pm->ct = 0;
+    pm->env = NULL;
+    pm->ename = NULL;
+    pm->old = NULL;
+    pm->level = 0;
+    if ((al = (Alias) aliastab->getnode2(aliastab, name)) &&
+	((global && (al->flags & ALIAS_GLOBAL)) ||
+	 (!global && !(al->flags & ALIAS_GLOBAL))) &&
+	(dis ? (al->flags & DISABLED) : !(al->flags & DISABLED)))
+	pm->u.str = dupstring(al->text);
+    else {
+	pm->u.str = dupstring("");
+	pm->flags |= PM_UNSET;
+    }
+    return (HashNode) pm;
+}
+
+/**/
+static HashNode
+getpmralias(HashTable ht, char *name)
+{
+    return getalias(ht, name, 0, 0);
+}
+
+/**/
+static HashNode
+getpmdisralias(HashTable ht, char *name)
+{
+    return getalias(ht, name, 0, 0);
+}
+
+/**/
+static HashNode
+getpmgalias(HashTable ht, char *name)
+{
+    return getalias(ht, name, 1, 0);
+}
+
+/**/
+static HashNode
+getpmdisgalias(HashTable ht, char *name)
+{
+    return getalias(ht, name, 1, DISABLED);
+}
+
+/**/
+static void
+scanaliases(HashTable ht, ScanFunc func, int flags, int global, int dis)
+{
+    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;
+		if (func != scancountparams &&
+		    ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) ||
+		     !(flags & SCANPM_WANTKEYS)))
+		    pm.u.str = dupstring(al->text);
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/**/
+static void
+scanpmraliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(ht, func, flags, 0, 0);
+}
+
+/**/
+static void
+scanpmdisraliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(ht, func, flags, 0, DISABLED);
+}
+
+/**/
+static void
+scanpmgaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(ht, func, flags, 1, 0);
+}
+
+/**/
+static void
+scanpmdisgaliases(HashTable ht, ScanFunc func, int flags)
+{
+    scanaliases(ht, func, flags, 1, DISABLED);
+}
+
+/* Table for defined parameters. */
+
+struct pardef {
+    char *name;
+    int flags;
+    GetNodeFunc getnfn;
+    ScanTabFunc scantfn;
+    void (*hsetfn) _((Param, HashTable));
+    void (*setfn) _((Param, char **));
+    char **(*getfn) _((Param));
+    void (*unsetfn) _((Param, int));
+    Param pm;
+};
+
+static struct pardef partab[] = {
+    { "parameters", PM_READONLY,
+      getpmparameter, scanpmparameters, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "commands", 0,
+      getpmcommand, scanpmcommands, setpmcommands,
+      NULL, NULL, stdunsetfn, NULL },
+    { "functions", 0,
+      getpmfunction, scanpmfunctions, setpmfunctions,
+      NULL, NULL, stdunsetfn, NULL },
+    { "dis_functions", 0,
+      getpmdisfunction, scanpmdisfunctions, setpmdisfunctions,
+      NULL, NULL, stdunsetfn, NULL },
+    { "funcstack", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      arrsetfn, funcstackgetfn, stdunsetfn, NULL },
+    { "builtins", PM_READONLY,
+      getpmbuiltin, scanpmbuiltins, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "dis_builtins", PM_READONLY,
+      getpmdisbuiltin, scanpmdisbuiltins, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      arrsetfn, reswordsgetfn, stdunsetfn, NULL },
+    { "dis_reswords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      arrsetfn, disreswordsgetfn, stdunsetfn, NULL },
+    { "options", 0,
+      getpmoption, scanpmoptions, setpmoptions,
+      NULL, NULL, stdunsetfn, NULL },
+    { "modules", PM_READONLY,
+      getpmmodule, scanpmmodules, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "dirstack", PM_ARRAY|PM_SPECIAL|PM_REMOVABLE,
+      NULL, NULL, NULL,
+      dirssetfn, dirsgetfn, stdunsetfn, NULL },
+    { "history", PM_READONLY,
+      getpmhistory, scanpmhistory, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "historywords", PM_ARRAY|PM_SPECIAL|PM_READONLY,
+      NULL, NULL, NULL,
+      arrsetfn, histwgetfn, stdunsetfn, NULL },
+    { "jobtexts", PM_READONLY,
+      getpmjobtext, scanpmjobtexts, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "jobstates", PM_READONLY,
+      getpmjobstate, scanpmjobstates, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "jobdirs", PM_READONLY,
+      getpmjobdir, scanpmjobdirs, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "nameddirs", 0,
+      getpmnameddir, scanpmnameddirs, setpmnameddirs,
+      NULL, NULL, stdunsetfn, NULL },
+    { "userdirs", PM_READONLY,
+      getpmuserdir, scanpmuserdirs, hashsetfn,
+      NULL, NULL, stdunsetfn, NULL },
+    { "aliases", 0,
+      getpmralias, scanpmraliases, setpmraliases,
+      NULL, NULL, stdunsetfn, NULL },
+    { "galiases", 0,
+      getpmgalias, scanpmgaliases, setpmgaliases,
+      NULL, NULL, stdunsetfn, NULL },
+    { "dis_aliases", 0,
+      getpmdisralias, scanpmdisraliases, setpmdisraliases,
+      NULL, NULL, stdunsetfn, NULL },
+    { "dis_galiases", 0,
+      getpmdisgalias, scanpmdisgaliases, setpmdisgaliases,
+      NULL, NULL, stdunsetfn, NULL },
+    { NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
+};
 
 /**/
 int
-setup_parameter(Module m)
+setup_(Module m)
 {
+    incleanup = 0;
+
     return 0;
 }
 
 /**/
 int
-boot_parameter(Module m)
+boot_(Module m)
 {
     /* Create the special associative arrays.
      * As an example for autoloaded parameters, this is probably a bad
-     * example, because we the zsh core doesn't support creation of
+     * example, because the zsh core doesn't support creation of
      * special hashes, yet. */
 
-    unsetparam(PAR_NAM);
-    if (!(parpm = createspecialhash(PAR_NAM, getpmparameter,
-				    scanpmparameters)))
-	return 1;
-    parpm->flags |= PM_READONLY;
-    unsetparam(CMD_NAM);
-    if (!(cmdpm = createspecialhash(CMD_NAM, getpmcommand,
-				    scanpmcommands)))
-	return 1;
-    cmdpm->sets.hfn = setpmcommands;
-    unsetparam(FUN_NAM);
-    if (!(funpm = createspecialhash(FUN_NAM, getpmfunction,
-				    scanpmfunctions)))
-	return 1;
-    funpm->sets.hfn = setpmfunctions;
-    unsetparam(OPT_NAM);
-    if (!(optpm = createspecialhash(OPT_NAM, getpmoption,
-				    scanpmoptions)))
-	return 1;
-    optpm->sets.hfn = setpmoptions;
+    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->hsetfn)
+		def->pm->sets.hfn = def->hsetfn;
+	} else {
+	    if (!(def->pm = createparam(def->name, def->flags | PM_HIDE |
+					PM_REMOVABLE)))
+		return 1;
+	    def->pm->sets.afn = def->setfn;
+	    def->pm->gets.afn = def->getfn;
+	    def->pm->unsetfn = def->unsetfn;
+	}
+    }
     return 0;
 }
 
-#ifdef MODULE
-
 /**/
 int
-cleanup_parameter(Module m)
+cleanup_(Module m)
 {
     Param pm;
+    struct pardef *def;
 
-    /* Remove the special parameters if they are still the same. */
+    incleanup = 1;
 
-    if ((pm = (Param) paramtab->getnode(paramtab, PAR_NAM)) && pm == parpm) {
-	pm->flags &= ~PM_READONLY;
-	unsetparam_pm(pm, 0, 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);
+	}
     }
-    if ((pm = (Param) paramtab->getnode(paramtab, CMD_NAM)) && pm == cmdpm)
-	unsetparam_pm(pm, 0, 1);
-    if ((pm = (Param) paramtab->getnode(paramtab, FUN_NAM)) && pm == funpm)
-	unsetparam_pm(pm, 0, 1);
-    if ((pm = (Param) paramtab->getnode(paramtab, OPT_NAM)) && pm == optpm)
-	unsetparam_pm(pm, 0, 1);
     return 0;
 }
 
 /**/
 int
-finish_parameter(Module m)
+finish_(Module m)
 {
     return 0;
 }
-
-#endif
diff --git a/Src/Modules/zpty.c b/Src/Modules/zpty.c
index 088979514..26896525c 100644
--- a/Src/Modules/zpty.c
+++ b/Src/Modules/zpty.c
@@ -30,6 +30,13 @@
 #include "zpty.mdh"
 #include "zpty.pro"
 
+/* The number of bytes we normally read when given no pattern and the
+ * upper bound on the number of bytes we read (even if we are give a
+ * pattern). */
+
+#define READ_LEN 1024
+#define READ_MAX (1024 * 1024)
+
 typedef struct ptycmd *Ptycmd;
 
 struct ptycmd {
@@ -158,7 +165,7 @@ get_pty(int *master, int *slave)
 
 #else /* ! __osf__ */
 
-#if __SVR4
+#if defined(__SVR4) || defined(sinix)
 
 #include <sys/stropts.h>
 
@@ -167,11 +174,12 @@ get_pty(int *master, int *slave)
 {
     int mfd, sfd;
     char *name;
+    int ret;
 
     if ((mfd = open("/dev/ptmx", O_RDWR)) < 0)
 	return 1;
 
-    if (!(name = ptsname(mfd)) || grantpt(mfd) || unlockpt(mfd)) {
+    if (grantpt(mfd) || unlockpt(mfd) || !(name = ptsname(mfd))) {
 	close(mfd);
 	return 1;
     }
@@ -179,20 +187,31 @@ get_pty(int *master, int *slave)
 	close(mfd);
 	return 1;
     }
-    if (ioctl(sfd, I_PUSH, "ptem") ||
-	ioctl(sfd, I_PUSH, "ldterm") ||
-	ioctl(sfd, I_PUSH, "ttcompat")) {
-	close(mfd);
-	close(sfd);
-	return 1;
-    }
+    if ((ret = ioctl(sfd, I_FIND, "ptem")) != 1)
+       if (ret == -1 || ioctl(sfd, I_PUSH, "ptem") == -1) {
+	   close(mfd);
+	   close(sfd);
+	   return 1;
+       }
+    if ((ret = ioctl(sfd, I_FIND, "ldterm")) != 1)
+       if (ret == -1 || ioctl(sfd, I_PUSH, "ldterm") == -1) {
+	   close(mfd);
+	   close(sfd);
+	   return 1;
+       }
+    if ((ret = ioctl(sfd, I_FIND, "ttcompat")) != 1)
+       if (ret == -1 || ioctl(sfd, I_PUSH, "ttcompat") == -1) {
+	   close(mfd);
+	   close(sfd);
+	   return 1;
+       }
     *master = mfd;
     *slave = sfd;
 
     return 0;
 }
 
-#else /* ! __SVR4 */
+#else /* ! (defined(__SVR4) || defind(sinix)) */
 
 static int
 get_pty(int *master, int *slave)
@@ -242,17 +261,17 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
     char *cmd;
 
     if (!(cmd = findcmd(*args, 1))) {
-	zerrnam(nam, "unknown command: %s", *args, 0);
+	zwarnnam(nam, "unknown command: %s", *args, 0);
 	return 1;
     }
     if (get_pty(&master, &slave)) {
-	zerrnam(nam, "can't open pseudo terminal", NULL, 0);
+	zwarnnam(nam, "can't open pseudo terminal", NULL, 0);
 	return 1;
     }
     if ((pid = fork()) == -1) {
 	close(master);
 	close(slave);
-	zerrnam(nam, "couldn't create pty command: %s", pname, 0);
+	zwarnnam(nam, "couldn't create pty command: %s", pname, 0);
 	return 1;
     } else if (!pid) {
 	if (!echo) {
@@ -298,6 +317,8 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
 
 	close(slave);
 
+	setpgrp(0L, getpid());
+
 	execve(cmd, args, environ);
 	exit(0);
     }
@@ -307,9 +328,7 @@ newptycmd(char *nam, char *pname, char **args, int echo, int block)
     p = (Ptycmd) zalloc(sizeof(*p));
 
     p->name = ztrdup(pname);
-    PERMALLOC {
-	p->args = arrdup(args);
-    } LASTALLOC;
+    p->args = zarrdup(args);
     p->fd = master;
     p->pid = pid;
     p->echo = echo;
@@ -343,7 +362,9 @@ deleteptycmd(Ptycmd cmd)
     zsfree(p->name);
     freearray(p->args);
 
-    kill(p->pid, SIGHUP);
+    /* We kill the process group the command put itself in. */
+
+    kill(-(p->pid), SIGHUP);
 
     zclose(cmd->fd);
 
@@ -375,7 +396,7 @@ checkptycmd(Ptycmd cmd)
 static int
 ptyread(char *nam, Ptycmd cmd, char **args)
 {
-    int blen = 256, used = 0, ret;
+    int blen = 256, used = 0, ret = 1;
     char *buf = (char *) zhalloc(blen + 1);
     Patprog prog = NULL;
 
@@ -383,57 +404,113 @@ ptyread(char *nam, Ptycmd cmd, char **args)
 	char *p;
 
 	if (args[2]) {
-	    zerrnam(nam, "too many arguments", NULL, 0);
+	    zwarnnam(nam, "too many arguments", NULL, 0);
 	    return 1;
 	}
 	p = dupstring(args[1]);
 	tokenize(p);
 	remnulargs(p);
 	if (!(prog = patcompile(p, PAT_STATIC, NULL))) {
-	    zerrnam(nam, "bad pattern: %s", args[1], 0);
+	    zwarnnam(nam, "bad pattern: %s", args[1], 0);
 	    return 1;
 	}
     }
     do {
-	while ((ret = read(cmd->fd, buf + used, 1)) == 1) {
+	if (!ret) {
+	    checkptycmd(cmd);
+	    if (cmd->fin)
+		break;
+	}
+	if ((ret = read(cmd->fd, buf + used, 1)) == 1) {
 	    if (++used == blen) {
 		buf = hrealloc(buf, blen, blen << 1);
 		blen <<= 1;
 	    }
 	}
 	buf[used] = '\0';
-    } while (prog && !pattry(prog, buf));
 
-    if (*args)
-	setsparam(*args, ztrdup(buf));
-    else
-	printf("%s", buf);
+	/**** Hm. If we leave the loop when ret < 0 the user would have
+	 *    to make sure that `zpty -r' is tried more than once if
+	 *    there will be some output and we only got the ret == -1
+	 *    because the output is not yet available.
+	 *    The same for the `write' below. */
+
+	if (ret < 0 && (cmd->block
+#ifdef EWOULDBLOCK
+			|| errno != EWOULDBLOCK
+#else
+#ifdef EAGAIN
+			|| errno != EAGAIN
+#endif
+#endif
+			))
+	    break;
+
+	if (!prog && !ret)
+	    break;
+    } while (!errflag &&
+	     (prog ? (used < READ_MAX && (!ret || !pattry(prog, buf))) :
+	      (used < READ_LEN)));
 
+    if (*args)
+	setsparam(*args, ztrdup(metafy(buf, used, META_HREALLOC)));
+    else {
+	fflush(stdout);
+	write(1, buf, used);
+    }
     return !used;
 }
 
 static int
+ptywritestr(Ptycmd cmd, char *s, int len)
+{
+    int written;
+
+    for (; len; len -= written, s += written) {
+	if ((written = write(cmd->fd, s, len)) < 0 &&
+	    (cmd->block
+#ifdef EWOULDBLOCK
+			|| errno != EWOULDBLOCK
+#else
+#ifdef EAGAIN
+			|| errno != EAGAIN
+#endif
+#endif
+	     ))
+	    return 1;
+	if (written < 0) {
+	    checkptycmd(cmd);
+	    if (cmd->fin)
+		break;
+	    written = 0;
+	}
+    }
+    return 0;
+}
+
+static int
 ptywrite(Ptycmd cmd, char **args, int nonl)
 {
     if (*args) {
 	char sp = ' ';
 
-	while (*args) {
-	    write(cmd->fd, *args, strlen(*args));
+	while (*args)
+	    if (ptywritestr(cmd, *args, strlen(*args)) ||
+		(*++args && ptywritestr(cmd, &sp, 1)))
+		return 1;
 
-	    if (*++args)
-		write(cmd->fd, &sp, 1);
-	}
 	if (!nonl) {
 	    sp = '\n';
-	    write(cmd->fd, &sp, 1);
+	    if (ptywritestr(cmd, &sp, 1))
+		return 1;
 	}
     } else {
 	int n;
 	char buf[BUFSIZ];
 
 	while ((n = read(0, buf, BUFSIZ)) > 0)
-	    write(cmd->fd, buf, n);
+	    if (ptywritestr(cmd, buf, n))
+		return 1;
     }
     return 0;
 }
@@ -449,17 +526,17 @@ bin_zpty(char *nam, char **args, char *ops, int func)
 		      ops['d'] || ops['L'])) ||
 	(ops['d'] && (ops['b'] || ops['e'] || ops['L'])) ||
 	(ops['L'] && (ops['b'] || ops['e']))) {
-	zerrnam(nam, "illegal option combination", NULL, 0);
+	zwarnnam(nam, "illegal option combination", NULL, 0);
 	return 1;
     }
     if (ops['r'] || ops['w']) {
 	Ptycmd p;
 
 	if (!*args) {
-	    zerrnam(nam, "missing pty command name", NULL, 0);
+	    zwarnnam(nam, "missing pty command name", NULL, 0);
 	    return 1;
 	} else if (!(p = getptycmd(*args))) {
-	    zerrnam(nam, "no such pty command: %s", *args, 0);
+	    zwarnnam(nam, "no such pty command: %s", *args, 0);
 	    return 1;
 	}
 	checkptycmd(p);
@@ -486,11 +563,11 @@ bin_zpty(char *nam, char **args, char *ops, int func)
 	return ret;
     } else if (*args) {
 	if (!args[1]) {
-	    zerrnam(nam, "missing command", NULL, 0);
+	    zwarnnam(nam, "missing command", NULL, 0);
 	    return 1;
 	}
 	if (getptycmd(*args)) {
-	    zerrnam(nam, "pty command name already used: %s", *args, 0);
+	    zwarnnam(nam, "pty command name already used: %s", *args, 0);
 	    return 1;
 	}
 	return newptycmd(nam, *args, args + 1, ops['e'], ops['b']);