about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.c6
-rw-r--r--Src/Modules/.distfiles1
-rw-r--r--Src/Modules/example.c8
-rw-r--r--Src/Modules/parameter.c662
-rw-r--r--Src/Modules/parameter.mdd3
-rw-r--r--Src/Modules/stat.c12
-rw-r--r--Src/Modules/zftp.c135
-rw-r--r--Src/Zle/comp1.c10
-rw-r--r--Src/Zle/compctl.c6
-rw-r--r--Src/Zle/zle_params.c14
-rw-r--r--Src/Zle/zle_refresh.c54
-rw-r--r--Src/Zle/zle_tricky.c5
-rw-r--r--Src/builtin.c13
-rw-r--r--Src/compat.c18
-rw-r--r--Src/cond.c2
-rw-r--r--Src/exec.c98
-rw-r--r--Src/glob.c130
-rw-r--r--Src/hashtable.c5
-rw-r--r--Src/hist.c6
-rw-r--r--Src/init.c6
-rw-r--r--Src/input.c2
-rw-r--r--Src/jobs.c57
-rw-r--r--Src/math.c54
-rw-r--r--Src/mem.c33
-rw-r--r--Src/module.c4
-rw-r--r--Src/options.c26
-rw-r--r--Src/params.c90
-rw-r--r--Src/prototypes.h2
-rw-r--r--Src/subst.c19
-rw-r--r--Src/system.h18
-rw-r--r--Src/utils.c12
-rw-r--r--Src/zsh.export16
-rw-r--r--Src/zsh.h41
33 files changed, 1260 insertions, 308 deletions
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 34344f5c1..f8167a106 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -112,9 +112,15 @@ showlimits(int hard, int lim)
             else
 		printf("%lldkB\n", val / 1024L);
 #  else
+#   ifdef RLIM_T_IS_UNSIGNED
+		printf("%luMB\n", val / (1024L * 1024L));
+            else
+		printf("%lukB\n", val / 1024L);
+#   else
 		printf("%ldMB\n", val / (1024L * 1024L));
             else
 		printf("%ldkB\n", val / 1024L);
+#   endif /* RLIM_T_IS_UNSIGNED */
 #  endif /* RLIM_T_IS_LONG_LONG */
 # endif /* RLIM_T_IS_QUAD_T */
 	}
diff --git a/Src/Modules/.distfiles b/Src/Modules/.distfiles
index 23c7eae3f..dbc152fa8 100644
--- a/Src/Modules/.distfiles
+++ b/Src/Modules/.distfiles
@@ -4,6 +4,7 @@ DISTFILES_SRC='
     clone.mdd clone.c
     example.mdd example.c
     files.mdd files.c
+    parameter.mdd parameter.c
     stat.mdd stat.c
     zftp.mdd zftp.c
 '
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index 50b8c1626..1b24f336c 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -32,7 +32,7 @@
 
 /* parameters */
 
-static long intparam;
+static zlong intparam;
 static char *strparam;
 static char **arrparam;
 
@@ -55,7 +55,11 @@ bin_example(char *nam, char **args, char *ops, int func)
 	fputs(*args, stdout);
     }
     printf("\nName: %s\n", nam);
+#ifdef ZSH_64_BIT_TYPE
+    printf("\nInteger Parameter: %s\n", output64(intparam));
+#else
     printf("\nInteger Parameter: %ld\n", intparam);
+#endif
     printf("String Parameter: %s\n", strparam ? strparam : "");
     printf("Array Parameter:");
     if (p)
@@ -79,7 +83,7 @@ cond_p_len(char **a, int id)
     char *s1 = cond_str(a, 0);
 
     if (a[1]) {
-	long v = cond_val(a, 1);
+	zlong v = cond_val(a, 1);
 
 	return strlen(s1) == v;
     } else {
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
new file mode 100644
index 000000000..2257933f5
--- /dev/null
+++ b/Src/Modules/parameter.c
@@ -0,0 +1,662 @@
+/*
+ * parameter.c - parameter interface to zsh internals
+ *
+ * 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"
+
+/* 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_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);
+
+    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)) {
+	switch (PM_TYPE(f)) {
+	case PM_SCALAR:  val = "scalar"; break;
+	case PM_ARRAY:   val = "array"; break;
+	case PM_INTEGER: val = "integer"; break;
+	case PM_HASHED:  val = "association"; break;
+	}
+	DPUTS(!val, "BUG: type not handled in parameter");
+	val = dupstring(val);
+	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");
+    } else
+	val = dupstring("");
+
+    return val;
+}
+
+/**/
+static HashNode
+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;
+
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmparameters(HashTable ht, ScanFunc func, int flags)
+{
+    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 < realparamtab->hsize; i++)
+	for (hn = realparamtab->nodes[i]; hn; hn = hn->next) {
+	    pm.nam = hn->nam;
+	    if (func != scancountparams)
+		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))
+	zwarnnam(NULL, "restricted: %s", value, 0);
+    else {
+	Cmdnam cn = zcalloc(sizeof(*cn));
+
+	cn->flags = HASHED;
+	cn->u.cmd = ztrdup(value);
+
+	cmdnamtab->addnode(cmdnamtab, ztrdup(pm->nam), (HashNode) cn);
+    }
+}
+
+/**/
+static void
+unsetpmcommand(Param pm, int exp)
+{
+    HashNode hn = cmdnamtab->removenode(cmdnamtab, pm->nam);
+
+    if (hn)
+	cmdnamtab->freenode(hn);
+}
+
+/**/
+static void
+setpmcommands(Param pm, HashTable ht)
+{
+    int i;
+    HashNode hn;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    Cmdnam cn = zcalloc(sizeof(*cn));
+	    struct value v;
+
+	    v.isarr = v.inv = v.a = 0;
+	    v.b = -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);
+	}
+}
+
+/**/
+static HashNode
+getpmcommand(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);
+    }
+    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;
+	}
+    } LASTALLOC;
+
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmcommands(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+    Cmdnam cmd;
+
+    if (isset(HASHLISTALL))
+	cmdnamtab->filltable(cmdnamtab);
+
+    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;
+
+    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) {
+		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 *value)
+{
+    char *val;
+    Shfunc shf;
+    List list;
+    int sn;
+
+    val = ztrdup(value);
+    val = metafy(val, strlen(val), META_REALLOC);
+
+    HEAPALLOC {
+	list = parse_string(val);
+    } LASTALLOC;
+
+    if (!list || list == &dummy_list) {
+	zwarnnam(NULL, "invalid function definition", val, 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;
+	}
+	shfunctab->addnode(shfunctab, ztrdup(name), shf);
+    } LASTALLOC;
+
+    zsfree(val);
+}
+
+/**/
+static void
+setpmfunction(Param pm, char *value)
+{
+    setfunction(pm->nam, value);
+}
+
+/**/
+static void
+unsetpmfunction(Param pm, int exp)
+{
+    HashNode hn = shfunctab->removenode(shfunctab, pm->nam);
+
+    if (hn)
+	shfunctab->freenode(hn);
+}
+
+/**/
+static void
+setpmfunctions(Param pm, HashTable ht)
+{
+    int i;
+    HashNode hn;
+
+    for (i = 0; i < ht->hsize; i++)
+	for (hn = ht->nodes[i]; hn; hn = hn->next) {
+	    struct value v;
+
+	    v.isarr = v.inv = v.a = 0;
+	    v.b = -1;
+	    v.arr = NULL;
+	    v.pm = (Param) hn;
+
+	    setfunction(hn->nam, getstrvalue(&v));
+	}
+}
+
+/**/
+static HashNode
+getpmfunction(HashTable ht, char *name)
+{
+    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;
+	    }
+	} else {
+	    pm->u.str = "";
+	    pm->flags |= PM_UNSET;
+	}
+    } LASTALLOC;
+
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmfunctions(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    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;
+
+    for (i = 0; i < shfunctab->hsize; i++)
+	for (hn = shfunctab->nodes[i]; hn; hn = hn->next) {
+	    if (!(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);
+			zsfree(t);
+		    }
+		}
+		func((HashNode) &pm, flags);
+	    }
+	}
+}
+
+/* Functions for the options special parameter. */
+
+/**/
+static void
+setpmoption(Param pm, char *value)
+{
+    int n;
+
+    if (!value || (strcmp(value, "on") && strcmp(value, "off")))
+	zwarnnam(NULL, "invalid value: %s", value, 0);
+    else if (!(n = optlookup(pm->nam)))
+	zwarnnam(NULL, "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);
+}
+
+/**/
+static void
+unsetpmoption(Param pm, int exp)
+{
+    int n;
+
+    if (!(n = optlookup(pm->nam)))
+	zwarnnam(NULL, "no such option: %s", pm->nam, 0);
+    else if (dosetopt(n, 0, 0))
+	zwarnnam(NULL, "can't change option: %s", pm->nam, 0);
+}
+
+/**/
+static void
+setpmoptions(Param pm, HashTable ht)
+{
+    int i;
+    HashNode hn;
+
+    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;
+
+	    val = getstrvalue(&v);
+	    if (!val || (strcmp(val, "on") && strcmp(val, "off")))
+		zwarnnam(NULL, "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);
+	}
+}
+
+/**/
+static HashNode
+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;
+
+    return (HashNode) pm;
+}
+
+/**/
+static void
+scanpmoptions(HashTable ht, ScanFunc func, int flags)
+{
+    struct param pm;
+    int i;
+    HashNode hn;
+
+    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;
+
+    for (i = 0; i < optiontab->hsize; i++)
+	for (hn = optiontab->nodes[i]; hn; hn = hn->next) {
+	    pm.nam = hn->nam;
+	    pm.u.str = opts[((Optname) hn)->optno] ? "on" : "off";
+	    func((HashNode) &pm, flags);
+	}
+}
+
+/* Names and Params for the special parameters. */
+
+#define PAR_NAM "parameters"
+#define CMD_NAM "commands"
+#define FUN_NAM "functions"
+#define OPT_NAM "options"
+
+static Param parpm, cmdpm, funpm, optpm;
+
+/**/
+int
+setup_parameter(Module m)
+{
+    return 0;
+}
+
+/**/
+int
+boot_parameter(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
+     * 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;
+
+    return 0;
+}
+
+#ifdef MODULE
+
+/**/
+int
+cleanup_parameter(Module m)
+{
+    Param pm;
+
+    /* Remove the special parameters if they are still the same. */
+
+    if ((pm = (Param) paramtab->getnode(paramtab, PAR_NAM)) && pm == parpm) {
+	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)
+{
+    return 0;
+}
+
+#endif
diff --git a/Src/Modules/parameter.mdd b/Src/Modules/parameter.mdd
new file mode 100644
index 000000000..e2820aa9c
--- /dev/null
+++ b/Src/Modules/parameter.mdd
@@ -0,0 +1,3 @@
+autoparams="parameters commands functions options"
+
+objects="parameter.o"
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 6f80e2a96..d8179143e 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -213,7 +213,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
 	break;
 
     case ST_INO:
+#ifdef INO_T_IS_64_BIT
+	convbase(optr, sbuf->st_ino, 0);
+#else
+	DPUTS(sizeof(sbuf->st_ino) > 4,
+	      "Shell compiled with wrong ino_t size");
 	statulprint((unsigned long)sbuf->st_ino, optr);
+#endif
 	break;
 
     case ST_MODE:
@@ -237,7 +243,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
 	break;
 
     case ST_SIZE:
+#ifdef OFF_T_IS_64_BIT
+	convbase(optr, sbuf->st_size, 0);
+#else
+	DPUTS(sizeof(sbuf->st_size) > 4,
+	      "Shell compiled with wrong off_t size");
 	statulprint((unsigned long)sbuf->st_size, optr);
+#endif
 	break;
 
     case ST_ATIM:
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 651a5c952..873617e95 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -117,7 +117,7 @@ enum {
     ZFHD_EORB = 128		/* block is end of file */
 };
 
-typedef int (*readwrite_t)(int, char *, size_t, int);
+typedef int (*readwrite_t)(int, char *, off_t, int);
 
 struct zftpcmd {
     const char *nam;
@@ -195,7 +195,7 @@ static char *zfparams[] = {
 enum {
     ZFPM_READONLY = 0x01,	/* make parameter readonly */
     ZFPM_IFUNSET  = 0x02,	/* only set if not already set */
-    ZFPM_INTEGER  = 0x04	/* passed pointer to long */
+    ZFPM_INTEGER  = 0x04	/* passed pointer to off_t */
 };
 
 /*
@@ -250,25 +250,26 @@ static int zfhas_size, zfhas_mdtm;
  * --- we don't try to track it because it's too complicated.
  */
 enum {
-    ZFST_ASCI = 0x00,		/* type for next transfer is ASCII */
-    ZFST_IMAG = 0x01,		/* type for next transfer is image */
+    ZFST_ASCI = 0x0000,		/* type for next transfer is ASCII */
+    ZFST_IMAG = 0x0001,		/* type for next transfer is image */
 
-    ZFST_TMSK = 0x01,		/* mask for type flags */
-    ZFST_TBIT = 0x01,		/* number of bits in type flags */
+    ZFST_TMSK = 0x0001,		/* mask for type flags */
+    ZFST_TBIT = 0x0001,		/* number of bits in type flags */
 
-    ZFST_CASC = 0x00,		/* current type is ASCII - default */
-    ZFST_CIMA = 0x02,		/* current type is image */
+    ZFST_CASC = 0x0000,		/* current type is ASCII - default */
+    ZFST_CIMA = 0x0002,		/* current type is image */
 
-    ZFST_STRE = 0x00,		/* stream mode - default */
-    ZFST_BLOC = 0x04,		/* block mode */
+    ZFST_STRE = 0x0000,		/* stream mode - default */
+    ZFST_BLOC = 0x0004,		/* block mode */
 
-    ZFST_MMSK = 0x04,		/* mask for mode flags */
+    ZFST_MMSK = 0x0004,		/* mask for mode flags */
 
-    ZFST_LOGI = 0x08,		/* user logged in */
-    ZFST_NOPS = 0x10,		/* server doesn't understand PASV */
-    ZFST_NOSZ = 0x20,		/* server doesn't send `(XXXX bytes)' reply */
-    ZFST_TRSZ = 0x40,		/* tried getting 'size' from reply */
-    ZFST_CLOS = 0x80		/* connection closed */
+    ZFST_LOGI = 0x0008,		/* user logged in */
+    ZFST_SYST = 0x0010,		/* done system type check */
+    ZFST_NOPS = 0x0020,		/* server doesn't understand PASV */
+    ZFST_NOSZ = 0x0040,		/* server doesn't send `(XXXX bytes)' reply */
+    ZFST_TRSZ = 0x0080,		/* tried getting 'size' from reply */
+    ZFST_CLOS = 0x0100		/* connection closed */
 };
 #define ZFST_TYPE(x) (x & ZFST_TMSK)
 /*
@@ -461,7 +462,7 @@ zfmovefd(int fd)
  * set a non-special parameter.
  * if ZFPM_IFUNSET, don't set if it already exists.
  * if ZFPM_READONLY, make it readonly, but only when creating it.
- * if ZFPM_INTEGER, val pointer is to long (NB not int), don't free.
+ * if ZFPM_INTEGER, val pointer is to off_t (NB not int), don't free.
  */
 /**/
 static void
@@ -488,7 +489,7 @@ zfsetparam(char *name, void *val, int flags)
 	return;
     }
     if (type == PM_INTEGER)
-	pm->sets.ifn(pm, *(long *)val);
+	pm->sets.ifn(pm, *(off_t *)val);
     else
 	pm->sets.cfn(pm, (char *)val);
 }
@@ -1009,7 +1010,7 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize)
 	    if (isdigit(STOUC(*ptr))) {
 		zfstatus &= ~ZFST_NOSZ;
 		if (getsize) {
-		    long sz = zstrtol(ptr, NULL, 10);
+		    off_t sz = zstrtol(ptr, NULL, 10);
 		    zfsetparam("ZFTP_SIZE", &sz, ZFPM_READONLY|ZFPM_INTEGER);
 		}
 	    }
@@ -1090,9 +1091,9 @@ zfgetdata(char *name, char *rest, char *cmd, int getsize)
 
 /**/
 static int
-zfstats(char *fnam, int remote, long *retsize, char **retmdtm, int fd)
+zfstats(char *fnam, int remote, off_t *retsize, char **retmdtm, int fd)
 {
-    long sz = -1;
+    off_t sz = -1;
     char *mt = NULL;
     int ret;
 
@@ -1151,7 +1152,7 @@ zfstats(char *fnam, int remote, long *retsize, char **retmdtm, int fd)
 
 	if ((fd == -1 ? stat(fnam, &statbuf) : fstat(fd, &statbuf)) < 0)
 	    return 1;
-	/* make sure it's long, since this has to be a pointer */
+	/* make sure it's off_t, since this has to be a pointer */
 	sz = statbuf.st_size;
 
 	if (retmdtm) {
@@ -1179,9 +1180,9 @@ zfstats(char *fnam, int remote, long *retsize, char **retmdtm, int fd)
 
 /**/
 static void
-zfstarttrans(char *nam, int recv, long sz)
+zfstarttrans(char *nam, int recv, off_t sz)
 {
-    long cnt = 0;
+    off_t cnt = 0;
     /*
      * sz = -1 signifies error getting size.  don't set ZFTP_SIZE if sz is
      * zero, either: it probably came from an fstat() on a pipe, so it
@@ -1210,7 +1211,7 @@ zfendtrans()
 
 /**/
 static int
-zfread(int fd, char *bf, size_t sz, int tmout)
+zfread(int fd, char *bf, off_t sz, int tmout)
 {
     int ret;
 
@@ -1235,7 +1236,7 @@ zfread(int fd, char *bf, size_t sz, int tmout)
 
 /**/
 static int
-zfwrite(int fd, char *bf, size_t sz, int tmout)
+zfwrite(int fd, char *bf, off_t sz, int tmout)
 {
     int ret;
 
@@ -1262,11 +1263,11 @@ static int zfread_eof;
 
 /**/
 static int
-zfread_block(int fd, char *bf, size_t sz, int tmout)
+zfread_block(int fd, char *bf, off_t sz, int tmout)
 {
     int n;
     struct zfheader hdr;
-    size_t blksz, cnt;
+    off_t blksz, cnt;
     char *bfptr;
     do {
 	/* we need the header */
@@ -1314,11 +1315,11 @@ zfread_block(int fd, char *bf, size_t sz, int tmout)
 
 /**/
 static int
-zfwrite_block(int fd, char *bf, size_t sz, int tmout)
+zfwrite_block(int fd, char *bf, off_t sz, int tmout)
 {
     int n;
     struct zfheader hdr;
-    size_t cnt;
+    off_t cnt;
     char *bfptr;
     /* we need the header */
     do {
@@ -1359,7 +1360,7 @@ zfwrite_block(int fd, char *bf, size_t sz, int tmout)
 
 /**/
 static int
-zfsenddata(char *name, int recv, int progress, long startat)
+zfsenddata(char *name, int recv, int progress, off_t startat)
 {
 #define ZF_BUFSIZE 32768
 #define ZF_ASCSIZE (ZF_BUFSIZE/2)
@@ -1367,7 +1368,7 @@ zfsenddata(char *name, int recv, int progress, long startat)
     int n, ret = 0, gotack = 0, fdin, fdout, fromasc = 0, toasc = 0;
     int rtmout = 0, wtmout = 0;
     char lsbuf[ZF_BUFSIZE], *ascbuf = NULL, *optr;
-    long sofar = 0, last_sofar = 0;
+    off_t sofar = 0, last_sofar = 0;
     readwrite_t read_ptr = zfread, write_ptr = zfwrite;
     List l;
 
@@ -1598,7 +1599,7 @@ zftp_open(char *name, char **args, int flags)
     struct protoent *zprotop;
     struct servent *zservp;
     struct hostent *zhostp = NULL;
-    char **addrp, tbuf[2] = "X", *fname;
+    char **addrp, *fname;
     int err, len, tmout;
 
     if (!*args) {
@@ -1802,32 +1803,11 @@ zftp_open(char *name, char **args, int flags)
 #endif
     unlink(fname);
 
-    /* now find out what system we're connected to */
-    if (!(zfprefs & ZFPF_DUMB) && zfsendcmd("SYST\r\n") == 2) {
-	char *ptr = lastmsg, *eptr, *systype;
-	for (eptr = ptr; *eptr; eptr++)
-	    ;
-	systype = ztrduppfx(ptr, eptr-ptr);
-	if (!strncmp(systype, "UNIX Type: L8", 13)) {
-	    /*
-	     * Use binary for transfers.  This simple test saves much
-	     * hassle for all concerned, particularly me.
-	     */
-	    zfstatus |= ZFST_IMAG;
-	    zfis_unix = 1;
-	}
-	/*
-	 * we could set zfis_unix based just on the UNIX part,
-	 * but I don't really know the consequences of that.
-	 */
-	zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
-    } else if (zcfd == -1) {
+    if (zcfd == -1) {
 	/* final paranoid check */
 	return 1;
     }
 	
-    tbuf[0] = (ZFST_TYPE(zfstatus) == ZFST_ASCI) ? 'A' : 'I';
-    zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY);
     zfsetparam("ZFTP_MODE", ztrdup("S"), ZFPM_READONLY);
     /* if remaining arguments, use them to log in. */
     if (zcfd > -1 && *++args)
@@ -1964,7 +1944,7 @@ static int
 zftp_login(char *name, char **args, int flags)
 {
     char *ucmd, *passwd = NULL, *acct = NULL;
-    char *user;
+    char *user, tbuf[2] = "X";
     int stopit;
 
     if ((zfstatus & ZFST_LOGI) && zfsendcmd("REIN\r\n") >= 4)
@@ -2045,6 +2025,36 @@ zftp_login(char *name, char **args, int flags)
 	zfsetparam("ZFTP_ACCOUNT", ztrdup(acct), ZFPM_READONLY);
 
     /*
+     * Now find out what system we're connected to. Some systems
+     * won't let us do this until we're logged in; it's fairly safe
+     * to delay it here for all systems.
+     */
+    if (!(zfprefs & ZFPF_DUMB) && !(zfstatus & ZFST_SYST)) {
+	if (zfsendcmd("SYST\r\n") == 2) {
+	    char *ptr = lastmsg, *eptr, *systype;
+	    for (eptr = ptr; *eptr; eptr++)
+		;
+	    systype = ztrduppfx(ptr, eptr-ptr);
+	    if (!strncmp(systype, "UNIX Type: L8", 13)) {
+		/*
+		 * Use binary for transfers.  This simple test saves much
+		 * hassle for all concerned, particularly me.
+		 */
+		zfstatus |= ZFST_IMAG;
+		zfis_unix = 1;
+	    }
+	    /*
+	     * we could set zfis_unix based just on the UNIX part,
+	     * but I don't really know the consequences of that.
+	     */
+	    zfsetparam("ZFTP_SYSTEM", systype, ZFPM_READONLY);
+	}
+	zfstatus |= ZFST_SYST;
+    }
+    tbuf[0] = (ZFST_TYPE(zfstatus) == ZFST_ASCI) ? 'A' : 'I';
+    zfsetparam("ZFTP_TYPE", ztrdup(tbuf), ZFPM_READONLY);
+
+    /*
      * Get the directory.  This is possibly an unnecessary overhead, of
      * course, but when you're being driven by shell functions there's
      * just no way of telling.
@@ -2307,7 +2317,7 @@ zftp_local(char *name, char **args, int flags)
 {
     int more = !!args[1], ret = 0, dofd = !*args;
     while (*args || dofd) {
-	long sz;
+	off_t sz;
 	char *mt;
 	int newret = zfstats(*args, !(flags & ZFTP_HERE), &sz, &mt,
 			     dofd ? 0 : -1);
@@ -2324,7 +2334,12 @@ zftp_local(char *name, char **args, int flags)
 	    fputs(*args, stdout);
 	    fputc(' ', stdout);
 	}
+#ifdef OFF_T_IS_64_BIT
+	printf("%s %s\n", output64(sz), mt);
+#else
+	DPUTS(sizeof(sz) > 4, "Shell compiled with wrong off_t size");
 	printf("%ld %s\n", sz, mt);
+#endif
 	zsfree(mt);
 	if (dofd)
 	    break;
@@ -2371,9 +2386,9 @@ zftp_getput(char *name, char **args, int flags)
 	fflush(stdout);		/* since we may be using fd 1 */
     for (; *args; args++) {
 	char *ln, *rest = NULL;
-	long startat = 0;
+	off_t startat = 0;
 	if (progress && (l = getshfunc("zftp_progress")) != &dummy_list) {
-	    long sz;
+	    off_t sz;
 	    /*
 	     * This calls the SIZE command to get the size for remote
 	     * files.  Some servers send the size with the reply to
@@ -2701,7 +2716,7 @@ boot_zftp(Module m)
     if ((ret = addbuiltins(m->nam, bintab,
 			   sizeof(bintab)/sizeof(*bintab))) == 1) {
 	/* if successful, set some default parameters */
-	long tmout_def = 60;
+	off_t tmout_def = 60;
 	zfsetparam("ZFTP_VERBOSE", ztrdup("450"), ZFPM_IFUNSET);
 	zfsetparam("ZFTP_TMOUT", &tmout_def, ZFPM_IFUNSET|ZFPM_INTEGER);
 	zfsetparam("ZFTP_PREFS", ztrdup("PS"), ZFPM_IFUNSET);
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index f32e5f5c0..071a8e64a 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -100,11 +100,11 @@ int incompfunc;
 /* global variables for shell parameters in new style completion */
 
 /**/
-long compcurrent,
-     compnmatches,
-     compmatcher,
-     compmatchertot,
-     complistmax;
+zlong compcurrent,
+      compnmatches,
+      compmatcher,
+      compmatchertot,
+      complistmax;
 
 /**/
 char **compwords,
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index a06d558e3..217678c00 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -2270,7 +2270,7 @@ set_compstate(Param pm, HashTable ht)
 		    v.arr = NULL;
 		    v.pm = (Param) hn;
 		    if (cp->type == PM_INTEGER)
-			*((long *) cp->var) = getintvalue(&v);
+			*((zlong *) cp->var) = getintvalue(&v);
 		    else if ((str = getstrvalue(&v))) {
 			zsfree(*((char **) cp->var));
 			*((char **) cp->var) = ztrdup(str);
@@ -2289,7 +2289,7 @@ get_unambig(Param pm)
 }
 
 /**/
-static long
+static zlong
 get_unambig_curs(Param pm)
 {
     int c;
@@ -2342,7 +2342,7 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	return 1;
     else {
 	char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
-	long ocur;
+	zlong ocur;
 	unsigned int unset = 0, m, sm;
 	Param *pp;
 
diff --git a/Src/Zle/zle_params.c b/Src/Zle/zle_params.c
index d9fefe659..5c4feef50 100644
--- a/Src/Zle/zle_params.c
+++ b/Src/Zle/zle_params.c
@@ -101,8 +101,8 @@ makezleparams(int ro)
 		pm->gets.afn = (char **(*) _((Param))) zp->getfn;
 		break;
 	    case PM_INTEGER:
-		pm->sets.ifn = (void (*) _((Param, long))) zp->setfn;
-		pm->gets.ifn = (long (*) _((Param))) zp->getfn;
+		pm->sets.ifn = (void (*) _((Param, zlong))) zp->setfn;
+		pm->gets.ifn = (zlong (*) _((Param))) zp->getfn;
 		pm->ct = 10;
 		break;
 	}
@@ -146,7 +146,7 @@ get_buffer(Param pm)
 
 /**/
 static void
-set_cursor(Param pm, long x)
+set_cursor(Param pm, zlong x)
 {
     if(x < 0)
 	cs = 0;
@@ -157,7 +157,7 @@ set_cursor(Param pm, long x)
 }
 
 /**/
-static long
+static zlong
 get_cursor(Param pm)
 {
     return cs;
@@ -264,20 +264,20 @@ get_keys(Param pm)
 
 /**/
 static void
-set_numeric(Param pm, long x)
+set_numeric(Param pm, zlong x)
 {
     zmult = x;
 }
 
 /**/
-static long
+static zlong
 get_numeric(Param pm)
 {
     return zmult;
 }
 
 /**/
-static long
+static zlong
 get_histno(Param pm)
 {
     return histline;
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 2377b70fa..9742ba501 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -881,20 +881,8 @@ moveto(int ln, int cl)
 	}
     }
 
-    if (cl == vcs)
-	return;
-
-/* choose cheapest movements for ttys without multiple movement capabilities -
-   do this now because it's easier (to code) */
-    if (cl <= vcs / 2) {
-	zputc('\r', shout);
-	vcs = 0;
-    }
-    if (vcs < cl)
-	tc_rightcurs(cl);
-    else if (vcs > cl)
-	tc_leftcurs(vcs - cl);
-    vcs = cl;
+    if (cl != vcs)
+        singmoveto(cl);
 }
 
 /**/
@@ -912,16 +900,17 @@ tcmultout(int cap, int multcap, int ct)
     return 0;
 }
 
+/* ct: number of characters to move across */
 /**/
 static void
-tc_rightcurs(int cl)
+tc_rightcurs(int ct)
 {
-    int ct,			/* number of characters to move across	    */
+    int cl,			/* ``desired'' absolute horizontal position */
 	i = vcs,		/* cursor position after initial movements  */
 	j;
     char *t;
 
-    ct = cl - vcs;
+    cl = ct + vcs;
 
 /* do a multright if we can - it's the most reliable */
     if (tccan(TCMULTRIGHT)) {
@@ -929,6 +918,13 @@ tc_rightcurs(int cl)
 	return;
     }
 
+/* do an absolute horizontal position if we can */
+    if (tccan(TCHORIZPOS)) {
+	tcoutarg(TCHORIZPOS, cl);
+	return;
+    }
+
+/* XXX: should really check "it" in termcap and use / and % */
 /* try tabs if tabs are non destructive and multright is not possible */
     if (!oxtabs && tccan(TCNEXTTAB) && ((vcs | 7) < cl)) {
 	i = (vcs | 7) + 1;
@@ -1137,21 +1133,19 @@ singmoveto(int pos)
 {
     if (pos == vcs)
 	return;
-    if (pos <= vcs / 2) {
+
+/* choose cheapest movements for ttys without multiple movement capabilities -
+   do this now because it's easier (to code) */
+
+    if ((!tccan(TCMULTLEFT) || pos == 0) && (pos <= vcs / 2)) {
 	zputc('\r', shout);
 	vcs = 0;
     }
-    if (pos < vcs) {
+
+    if (pos < vcs)
 	tc_leftcurs(vcs - pos);
-	vcs = pos;
-    }
-    if (pos > vcs) {
-	if (tcmultout(TCRIGHT, TCMULTRIGHT, pos - vcs))
-	    vcs = pos;
-	else
-	    while (pos > vcs) {
-		zputc(nbuf[0][vcs], shout);
-		vcs++;
-	    }
-    }
+    else if (pos > vcs)
+	tc_rightcurs(pos - vcs);
+
+    vcs = pos;
 }
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index bc6cff8b6..aadbaec6c 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -3723,7 +3723,8 @@ addmatches(Cadata dat, char **argv)
 		    }
 		}
 		if (!(dat->aflags & CAF_MATCH)) {
-		    ms = dupstring(s);
+		    ms = ((dat->aflags & CAF_QUOTE) ? dupstring(s) :
+			  quotename(s, NULL));
 		    lc = bld_parts(ms, sl, -1, NULL);
 		    isexact = 0;
 		} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
@@ -3734,7 +3735,7 @@ addmatches(Cadata dat, char **argv)
 		    continue;
 		}
 		if (doadd) {
-		    cm = add_match_data(isalt, ms, lc, dat->ipre, dat->ipre,
+		    cm = add_match_data(isalt, ms, lc, dat->ipre, NULL,
 					dat->isuf, dat->pre, dat->prpre,
 					dat->ppre, dat->psuf, dat->suf,
 					bpl, bsl, dat->flags, isexact);
diff --git a/Src/builtin.c b/Src/builtin.c
index 8436cde33..a90d59cae 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1521,9 +1521,14 @@ typeset_single(char *cname, char *pname, Param pm, int func,
 	    zerrnam(cname, "%s: restricted", pname, 0);
 	    return pm;
 	}
-	if (PM_TYPE(pm->flags) == PM_ARRAY && (on & PM_UNIQUE) &&
-	    !(pm->flags & PM_READONLY & ~off))
-	    uniqarray((*pm->gets.afn) (pm));
+	if ((on & PM_UNIQUE) && !(pm->flags & PM_READONLY & ~off)) {
+	    Param apm;
+	    if (PM_TYPE(pm->flags) == PM_ARRAY)
+		uniqarray((*pm->gets.afn) (pm));
+	    else if (PM_TYPE(pm->flags) == PM_SCALAR && pm->ename &&
+		     (apm = (Param) paramtab->getnode(paramtab, pm->ename)))
+		uniqarray((*apm->gets.afn) (apm));
+	}
 	pm->flags = (pm->flags | on) & ~off;
 	/* This auxlen/pm->ct stuff is a nasty hack. */
 	if ((on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z | PM_INTEGER)) &&
@@ -3647,7 +3652,7 @@ bin_ttyctl(char *name, char **argv, char *ops, int func)
 int
 bin_let(char *name, char **argv, char *ops, int func)
 {
-    long val = 0;
+    zlong val = 0;
 
     while (*argv)
 	val = matheval(*argv++);
diff --git a/Src/compat.c b/Src/compat.c
index 53ab6b7a3..7af984799 100644
--- a/Src/compat.c
+++ b/Src/compat.c
@@ -304,3 +304,21 @@ zchdir(char *dir)
     return currdir == -2 ? -1 : -2;
 #endif
 }
+
+/*
+ * How to print out a 64 bit integer.  This isn't needed (1) if longs
+ * are 64 bit, since ordinary %ld will work (2) if we couldn't find a
+ * 64 bit type anyway.
+ */
+/**/
+#ifdef ZSH_64_BIT_TYPE
+/**/
+char *
+output64(zlong val)
+{
+    static char llbuf[DIGBUFSIZE];
+    convbase(llbuf, val, 0);
+    return llbuf;
+}
+/**/
+#endif /* ZSH_64_BIT_TYPE */
diff --git a/Src/cond.c b/Src/cond.c
index 00beb8e65..a8387a454 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -311,7 +311,7 @@ cond_str(char **args, int num)
 }
 
 /**/
-long
+zlong
 cond_val(char **args, int num)
 {
     char *s = args[num];
diff --git a/Src/exec.c b/Src/exec.c
index da2bf9fe2..7d15facfd 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -213,6 +213,78 @@ zfork(void)
     return pid;
 }
 
+/*
+ *   Allen Edeln gebiet ich Andacht,
+ *   Hohen und Niedern von Heimdalls Geschlecht;
+ *   Ich will list_pipe's Wirken kuenden
+ *   Die aeltesten Sagen, der ich mich entsinne...
+ *
+ * In most shells, if you do something like:
+ *
+ *   cat foo | while read a; do grep $a bar; done
+ *
+ * the shell forks and executes the loop in the sub-shell thus created.
+ * In zsh this traditionally executes the loop in the current shell, which
+ * is nice to have if the loop does something to change the shell, like
+ * setting parameters or calling builtins.
+ * Putting the loop in a sub-shell makes live easy, because the shell only
+ * has to put it into the job-structure and then treats it as a normal
+ * process. Suspending and interrupting is no problem then.
+ * Some years ago, zsh either couldn't suspend such things at all, or
+ * it got really messed up when users tried to do it. As a solution, we
+ * implemented the list_pipe-stuff, which has since then become a reason
+ * for many nightmares.
+ * Pipelines like the one above are executed by the functions in this file
+ * which call each other (and sometimes recursively). The one above, for
+ * example would lead to a function call stack roughly like:
+ *
+ *  execlist->execpline->execcmd->execwhile->execlist->execpline
+ *
+ * (when waiting for the grep, ignoring execpline2 for now). At this time,
+ * zsh has build two job-table entries for it: one for the cat and one for
+ * the grep. If the user hits ^Z at this point (and jobbing is used), the 
+ * shell is notified that the grep was suspended. The list_pipe flag is
+ * used to tell the execpline where it was waiting that it was in a pipeline
+ * with a shell construct at the end (which may also be a shell function or
+ * several other things). When zsh sees the suspended grep, it forks to let
+ * the sub-shell execute the rest of the while loop. The parent shell walks
+ * up in the function call stack to the first execpline. There it has to find
+ * out that it has just forked and then has to add information about the sub-
+ * shell (its pid and the text for it) in the job entry of the cat. The pid
+ * is passed down in the list_pipe_pid variable.
+ * But there is a problem: the suspended grep is a child of the parent shell
+ * and can't be adopted by the sub-shell. So the parent shell also has to 
+ * keep the information about this process (more precisely: this pipeline)
+ * by keeping the job table entry it created for it. The fact that there
+ * are two jobs which have to be treated together is remembered by setting
+ * the STAT_SUPERJOB flag in the entry for the cat-job (which now also
+ * contains a process-entry for the whole loop -- the sub-shell) and by
+ * setting STAT_SUBJOB in the job of the grep-job. With that we can keep
+ * sub-jobs from being displayed and we can handle an fg/bg on the super-
+ * job correctly. When the super-job is continued, the shell also wakes up
+ * the sub-job. But then, the grep will exit sometime. Now the parent shell
+ * has to remember not to try to wake it up again (in case of another ^Z).
+ * It also has to wake up the sub-shell (which suspended itself immediately
+ * after creation), so that the rest of the loop is executed by it.
+ * But there is more: when the sub-shell is created, the cat may already
+ * have exited, so we can't put the sub-shell in the process group of it.
+ * In this case, we put the sub-shell in the process group of the parent
+ * shell and in any case, the sub-shell has to put all commands executed
+ * by it into its own process group, because only this way the parent
+ * shell can control them since it only knows the process group of the sub-
+ * shell. Of course, this information is also important when putting a job
+ * in the foreground, where we have to attach its process group to the
+ * controlling tty.
+ * All this is made more difficult because we have to handle return values
+ * correctly. If the grep is signaled, its exit status has to be propagated
+ * back to the parent shell which needs it to set the exit status of the
+ * super-job. And of course, when the grep is signaled (including ^C), the
+ * loop has to be stopped, etc.
+ * The code for all this is distributed over three files (exec.c, jobs.c,
+ * and signals.c) and none of them is a simple one. So, all in all, there
+ * may still be bugs, but considering the complexity (with race conditions,
+ * signal handling, and all that), this should probably be expected.
+ */
 
 /**/
 int list_pipe = 0, simple_pline = 0;
@@ -625,6 +697,13 @@ execlist(List list, int dont_change_job, int exiting)
     static int donetrap;
     int ret, cj;
     int old_pline_level, old_list_pipe;
+    /*
+     * ERREXIT only forces the shell to exit if the last command in a &&
+     * or || fails.  This is the case even if an earlier command is a
+     * shell function or other current shell structure, so we have to set
+     * noerrexit here if the sublist is not of type END.
+     */
+    int oldnoerrexit = noerrexit;
 
     cj = thisjob;
     old_pline_level = pline_level;
@@ -644,6 +723,8 @@ execlist(List list, int dont_change_job, int exiting)
 
 	/* Loop through code followed by &&, ||, or end of sublist. */
 	while (slist) {
+	    if (!oldnoerrexit)
+		noerrexit = (slist->type != END);
 	    switch (slist->type) {
 	    case END:
 		/* End of sublist; just execute, ignoring status. */
@@ -687,6 +768,8 @@ execlist(List list, int dont_change_job, int exiting)
 	}
 sublist_done:
 
+	noerrexit = oldnoerrexit;
+
 	if (sigtrapped[SIGDEBUG])
 	    dotrap(SIGDEBUG);
 
@@ -761,13 +844,17 @@ execpline(Sublist l, int how, int last1)
 	coprocout = opipe[1];
 	fdtable[coprocin] = fdtable[coprocout] = 0;
     }
+    /* This used to set list_pipe_pid=0 unconditionally, but in things
+     * like `ls|if true; then sleep 20; cat; fi' where the sleep was
+     * stopped, the top-level execpline() didn't get the pid for the
+     * sub-shell because it was overwritten. */
     if (!pline_level++) {
 	list_pipe_job = newjob;
+        list_pipe_pid = 0;
 	nowait = 0;
-    }
-    list_pipe_pid = lastwj = 0;
-    if (pline_level == 1)
 	simple_pline = (l->left->type == END);
+    }
+    lastwj = 0;
     execpline2(l->left, how, opipe[0], ipipe[1], last1);
     pline_level--;
     if (how & Z_ASYNC) {
@@ -800,6 +887,7 @@ execpline(Sublist l, int how, int last1)
 		    struct process *pn, *qn;
 
 		    curjob = newjob;
+		    DPUTS(!list_pipe_pid, "invalid list_pipe_pid");
 		    addproc(list_pipe_pid, list_pipe_text);
 
 		    for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
@@ -1588,7 +1676,7 @@ execcmd(Cmd cmd, int input, int output, int how, int last1)
 	    closem(2);
 #endif
 	    if (how & Z_ASYNC) {
-		lastpid = (long) pid;
+		lastpid = (zlong) pid;
 	    } else if (!jobtab[thisjob].stty_in_env && nonempty(cmd->vars)) {
 		/* search for STTY=... */
 		while (nonempty(cmd->vars))
@@ -2548,7 +2636,7 @@ static int
 execarith(Cmd cmd)
 {
     char *e;
-    long val = 0;
+    zlong val = 0;
 
     if (isset(XTRACE))
 	fprintf(stderr, "%s((", prompt4 ? prompt4 : "");
diff --git a/Src/glob.c b/Src/glob.c
index 79a86bbef..596a05ebf 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -30,18 +30,24 @@
 #include "zsh.mdh"
 #include "glob.pro"
 
+#if defined(OFF_T_IS_64_BIT) && defined(__GNUC__)
+# define ALIGN64 __attribute__((aligned(8)))
+#else
+# define ALIGN64
+#endif
+
 /* flag for CSHNULLGLOB */
 
 typedef struct gmatch *Gmatch; 
 
 struct gmatch {
     char *name;
-    long size;
+    off_t size ALIGN64;
     long atime;
     long mtime;
     long ctime;
     long links;
-    long _size;
+    off_t _size ALIGN64;
     long _atime;
     long _mtime;
     long _ctime;
@@ -97,13 +103,13 @@ typedef struct stat *Statptr;	 /* This makes the Ultrix compiler happy.  Go figu
 #define TT_KILOBYTES 2
 #define TT_MEGABYTES 3
 
-typedef int (*TestMatchFunc) _((struct stat *, long));
+typedef int (*TestMatchFunc) _((struct stat *, off_t));
 
 struct qual {
     struct qual *next;		/* Next qualifier, must match                */
     struct qual *or;		/* Alternative set of qualifiers to match    */
     TestMatchFunc func;		/* Function to call to test match            */
-    long data;			/* Argument passed to function               */
+    off_t data ALIGN64;		/* Argument passed to function               */
     int sense;			/* Whether asserting or negating             */
     int amc;			/* Flag for which time to test (a, m, c)     */
     int range;			/* Whether to test <, > or = (as per signum) */
@@ -244,7 +250,7 @@ insert(char *s, int checked)
 	if (gf_follow) {
 	    if (!S_ISLNK(mode) || statfullpath(s, &buf2, 0))
 		memcpy(&buf2, &buf, sizeof(buf));
-	    statted = 2;
+	    statted |= 2;
 	    mode = buf2.st_mode;
 	}
 	if (gf_listtypes || S_ISDIR(mode)) {
@@ -268,11 +274,11 @@ insert(char *s, int checked)
 	    range = qn->range;
 	    amc = qn->amc;
 	    units = qn->units;
-	    if ((qn->sense & 2) && statted != 2) {
+	    if ((qn->sense & 2) && !(statted & 2)) {
 		/* If (sense & 2), we're following links */
 		if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
 		    memcpy(&buf2, &buf, sizeof(buf));
-		statted = 2;
+		statted |= 2;
 	    }
 	    bp = (qn->sense & 2) ? &buf2 : &buf;
 	    /* Reject the file if the function returned zero *
@@ -302,24 +308,29 @@ insert(char *s, int checked)
 	statfullpath(s, &buf, 1);
 	statted = 1;
     }
-    if (statted != 2 && (gf_sorts & GS_LINKED)) {
+    if (!(statted & 2) && (gf_sorts & GS_LINKED)) {
 	if (statted) {
 	    if (!S_ISLNK(buf.st_mode) || statfullpath(s, &buf2, 0))
 		memcpy(&buf2, &buf, sizeof(buf));
 	} else if (statfullpath(s, &buf2, 0))
 	    statfullpath(s, &buf2, 1);
+	statted |= 2;
     }
     matchptr->name = news;
-    matchptr->size = buf.st_size;
-    matchptr->atime = buf.st_atime;
-    matchptr->mtime = buf.st_mtime;
-    matchptr->ctime = buf.st_ctime;
-    matchptr->links = buf.st_nlink;
-    matchptr->_size = buf2.st_size;
-    matchptr->_atime = buf2.st_atime;
-    matchptr->_mtime = buf2.st_mtime;
-    matchptr->_ctime = buf2.st_ctime;
-    matchptr->_links = buf2.st_nlink;
+    if (statted & 1) {
+	matchptr->size = buf.st_size;
+	matchptr->atime = buf.st_atime;
+	matchptr->mtime = buf.st_mtime;
+	matchptr->ctime = buf.st_ctime;
+	matchptr->links = buf.st_nlink;
+    }
+    if (statted & 2) {
+	matchptr->_size = buf2.st_size;
+	matchptr->_atime = buf2.st_atime;
+	matchptr->_mtime = buf2.st_mtime;
+	matchptr->_ctime = buf2.st_ctime;
+	matchptr->_links = buf2.st_nlink;
+    }
     matchptr++;
 
     if (++matchct == matchsz) {
@@ -1102,10 +1113,10 @@ parsepat(char *str)
 /* get number after qualifier */
 
 /**/
-static long
+static off_t
 qgetnum(char **s)
 {
-    long v = 0;
+    off_t v = 0;
 
     if (!idigit(**s)) {
 	zerr("number expected", NULL, 0);
@@ -1119,10 +1130,10 @@ qgetnum(char **s)
 /* get mode spec after qualifier */
 
 /**/
-static long
+static zlong
 qgetmodespec(char **s)
 {
-    long yes = 0, no = 0, val, mask, t;
+    zlong yes = 0, no = 0, val, mask, t;
     char *p = *s, c, how, end;
 
     if ((c = *p) == '=' || c == Equals || c == '+' || c == '-' ||
@@ -1163,7 +1174,7 @@ qgetmodespec(char **s)
 		case 't': val |= 01000; break;
 		case '0': case '1': case '2': case '3':
 		case '4': case '5': case '6': case '7':
-		    t = ((long) c - '0');
+		    t = ((zlong) c - '0');
 		    val |= t | (t << 3) | (t << 6);
 		    break;
 		default:
@@ -1186,7 +1197,7 @@ qgetmodespec(char **s)
 		    val <<= 3;
 		} else {
 		    t <<= 3;
-		    val = (val << 3) | ((long) c - '0');
+		    val = (val << 3) | ((zlong) c - '0');
 		}
 		p++;
 	    }
@@ -1212,7 +1223,7 @@ static int
 gmatchcmp(Gmatch a, Gmatch b)
 {
     int i, *s;
-    long r = 0L;
+    off_t r = 0L;
 
     for (i = gf_nsorts, s = gf_sortlist; i; i--, s++) {
 	switch (*s & ~GS_DESC) {
@@ -1306,13 +1317,13 @@ glob(LinkList list, LinkNode np)
 	    /* Real qualifiers found. */
 	    int sense = 0;	/* bit 0 for match (0)/don't match (1)   */
 				/* bit 1 for follow links (2), don't (0) */
-	    long data = 0;	/* Any numerical argument required       */
-	    int (*func) _((Statptr, long));
+	    off_t data = 0;	/* Any numerical argument required       */
+	    int (*func) _((Statptr, off_t));
 
 	    str[sl-1] = 0;
 	    *s++ = 0;
 	    while (*s && !colonmod) {
-		func = (int (*) _((Statptr, long)))0;
+		func = (int (*) _((Statptr, off_t)))0;
 		if (idigit(*s)) {
 		    /* Store numeric argument for qualifier */
 		    func = qualflags;
@@ -3142,7 +3153,14 @@ matchonce(Comp c)
 	}
 	if (*pat == Inang) {
 	    /* Numeric globbing. */
+#ifdef ZSH_64_BIT_TYPE
+/* zstrtol returns zlong anyway */
+# define RANGE_CAST()
+	    zlong t1, t2, t3;
+#else
+# define RANGE_CAST() (unsigned long)
 	    unsigned long t1, t2, t3;
+#endif
 	    char *ptr, *saves = pptr, *savep = pat;
 
 	    if (!idigit(*pptr))
@@ -3161,18 +3179,18 @@ matchonce(Comp c)
 		 * t1 = number supplied:  must be positive, so use
 		 * unsigned arithmetic.
 		 */
-		t1 = (unsigned long)zstrtol(pptr, &ptr, 10);
+		t1 = RANGE_CAST() zstrtol(pptr, &ptr, 10);
 		pptr = ptr;
 		/* t2 = lower limit */
 		if (idigit(*pat))
-		    t2 = (unsigned long)zstrtol(pat, &ptr, 10);
+		    t2 = RANGE_CAST() zstrtol(pat, &ptr, 10);
 		else
 		    t2 = 0, ptr = pat;
 		if (*ptr != '-' || (not3 = (ptr[1] == Outang)))
 				/* exact match or no upper limit */
 		    t3 = t2, pat = ptr + not3;
 		else		/* t3 = upper limit */
-		    t3 = (unsigned long)zstrtol(ptr + 1, &pat, 10);
+		    t3 = RANGE_CAST() zstrtol(ptr + 1, &pat, 10);
 		DPUTS(*pat != Outang, "BUG: wrong internal range pattern");
 		pat++;
 		/*
@@ -3191,6 +3209,7 @@ matchonce(Comp c)
 		}
 	    }
 	    continue;
+#undef RANGE_CAST
 	}
 	/* itok(Meta) is zero */
 	DPUTS(itok(*pat), "BUG: matching tokenized character");
@@ -3430,7 +3449,7 @@ remnulargs(char *s)
 
 /**/
 static int
-qualdev(struct stat *buf, long dv)
+qualdev(struct stat *buf, off_t dv)
 {
     return buf->st_dev == dv;
 }
@@ -3439,7 +3458,7 @@ qualdev(struct stat *buf, long dv)
 
 /**/
 static int
-qualnlink(struct stat *buf, long ct)
+qualnlink(struct stat *buf, off_t ct)
 {
     return (range < 0 ? buf->st_nlink < ct :
 	    range > 0 ? buf->st_nlink > ct :
@@ -3450,7 +3469,7 @@ qualnlink(struct stat *buf, long ct)
 
 /**/
 static int
-qualuid(struct stat *buf, long uid)
+qualuid(struct stat *buf, off_t uid)
 {
     return buf->st_uid == uid;
 }
@@ -3459,7 +3478,7 @@ qualuid(struct stat *buf, long uid)
 
 /**/
 static int
-qualgid(struct stat *buf, long gid)
+qualgid(struct stat *buf, off_t gid)
 {
     return buf->st_gid == gid;
 }
@@ -3468,7 +3487,7 @@ qualgid(struct stat *buf, long gid)
 
 /**/
 static int
-qualisdev(struct stat *buf, long junk)
+qualisdev(struct stat *buf, off_t junk)
 {
     return S_ISBLK(buf->st_mode) || S_ISCHR(buf->st_mode);
 }
@@ -3477,7 +3496,7 @@ qualisdev(struct stat *buf, long junk)
 
 /**/
 static int
-qualisblk(struct stat *buf, long junk)
+qualisblk(struct stat *buf, off_t junk)
 {
     return S_ISBLK(buf->st_mode);
 }
@@ -3486,7 +3505,7 @@ qualisblk(struct stat *buf, long junk)
 
 /**/
 static int
-qualischr(struct stat *buf, long junk)
+qualischr(struct stat *buf, off_t junk)
 {
     return S_ISCHR(buf->st_mode);
 }
@@ -3495,7 +3514,7 @@ qualischr(struct stat *buf, long junk)
 
 /**/
 static int
-qualisdir(struct stat *buf, long junk)
+qualisdir(struct stat *buf, off_t junk)
 {
     return S_ISDIR(buf->st_mode);
 }
@@ -3504,7 +3523,7 @@ qualisdir(struct stat *buf, long junk)
 
 /**/
 static int
-qualisfifo(struct stat *buf, long junk)
+qualisfifo(struct stat *buf, off_t junk)
 {
     return S_ISFIFO(buf->st_mode);
 }
@@ -3513,7 +3532,7 @@ qualisfifo(struct stat *buf, long junk)
 
 /**/
 static int
-qualislnk(struct stat *buf, long junk)
+qualislnk(struct stat *buf, off_t junk)
 {
     return S_ISLNK(buf->st_mode);
 }
@@ -3522,7 +3541,7 @@ qualislnk(struct stat *buf, long junk)
 
 /**/
 static int
-qualisreg(struct stat *buf, long junk)
+qualisreg(struct stat *buf, off_t junk)
 {
     return S_ISREG(buf->st_mode);
 }
@@ -3531,7 +3550,7 @@ qualisreg(struct stat *buf, long junk)
 
 /**/
 static int
-qualissock(struct stat *buf, long junk)
+qualissock(struct stat *buf, off_t junk)
 {
     return S_ISSOCK(buf->st_mode);
 }
@@ -3540,7 +3559,7 @@ qualissock(struct stat *buf, long junk)
 
 /**/
 static int
-qualflags(struct stat *buf, long mod)
+qualflags(struct stat *buf, off_t mod)
 {
     return mode_to_octal(buf->st_mode) & mod;
 }
@@ -3549,7 +3568,7 @@ qualflags(struct stat *buf, long mod)
 
 /**/
 static int
-qualmodeflags(struct stat *buf, long mod)
+qualmodeflags(struct stat *buf, off_t mod)
 {
     long v = mode_to_octal(buf->st_mode), y = mod & 07777, n = mod >> 12;
 
@@ -3560,7 +3579,7 @@ qualmodeflags(struct stat *buf, long mod)
 
 /**/
 static int
-qualiscom(struct stat *buf, long mod)
+qualiscom(struct stat *buf, off_t mod)
 {
     return S_ISREG(buf->st_mode) && (buf->st_mode & S_IXUGO);
 }
@@ -3569,9 +3588,15 @@ qualiscom(struct stat *buf, long mod)
 
 /**/
 static int
-qualsize(struct stat *buf, long size)
+qualsize(struct stat *buf, off_t size)
 {
-    unsigned long scaled = buf->st_size;
+#if defined(LONG_IS_64_BIT) || defined(OFF_T_IS_64_BIT)
+# define QS_CAST_SIZE()
+    off_t scaled = buf->st_size;
+#else
+# define QS_CAST_SIZE() (unsigned long)
+    unsigned long scaled = (unsigned long)buf->st_size;
+#endif
 
     switch (units) {
     case TT_POSIX_BLOCKS:
@@ -3588,16 +3613,17 @@ qualsize(struct stat *buf, long size)
 	break;
     }
 
-    return (range < 0 ? scaled < (unsigned long) size :
-	    range > 0 ? scaled > (unsigned long) size :
-	    scaled == (unsigned long) size);
+    return (range < 0 ? scaled < QS_CAST_SIZE() size :
+	    range > 0 ? scaled > QS_CAST_SIZE() size :
+	    scaled == QS_CAST_SIZE() size);
+#undef QS_CAST_SIZE
 }
 
 /* time in required range? */
 
 /**/
 static int
-qualtime(struct stat *buf, long days)
+qualtime(struct stat *buf, off_t days)
 {
     time_t now, diff;
 
diff --git a/Src/hashtable.c b/Src/hashtable.c
index 0a640349b..b534d8ac1 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -112,6 +112,7 @@ newhashtable(int size, char const *name, PrintTableStats printinfo)
     ht->hsize = size;
     ht->ct = 0;
     ht->scan = NULL;
+    ht->scantab = NULL;
     return ht;
 }
 
@@ -361,6 +362,10 @@ scanhashtable(HashTable ht, int sorted, int flags1, int flags2, ScanFunc scanfun
 {
     struct scanstatus st;
 
+    if (ht->scantab) {
+	ht->scantab(ht, scanfunc, scanflags);
+	return;
+    }
     if (sorted) {
 	int i, ct = ht->ct;
 	VARARR(HashNode, hnsorttab, ct);
diff --git a/Src/hist.c b/Src/hist.c
index 55209a1c0..6b2c2a653 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -972,7 +972,7 @@ hend(void)
     zfree(chwords, chwordlen*sizeof(short));
     chline = NULL;
     histactive = 0;
-    if (isset(SHAREHISTORY) || isset(INCREMENTALAPPENDHISTORY))
+    if (isset(SHAREHISTORY) || isset(INCAPPENDHISTORY))
 	savehistfile(hf, 1, HFILE_USE_OPTIONS | HFILE_FAST);
     unlockhistfile(hf); /* It's OK to call this even if we aren't locked */
     return !(flag & HISTFLAG_NOEXEC || errflag);
@@ -1778,7 +1778,7 @@ savehistfile(char *fn, int err, int writeflags)
 	he = hist_ring->down;
     }
     if (writeflags & HFILE_USE_OPTIONS) {
-	if (isset(APPENDHISTORY) || isset(INCREMENTALAPPENDHISTORY)
+	if (isset(APPENDHISTORY) || isset(INCAPPENDHISTORY)
 	 || isset(SHAREHISTORY))
 	    writeflags |= HFILE_APPEND | HFILE_SKIPOLD;
 	else
@@ -1883,7 +1883,7 @@ lockhistfile(char *fn, int keep_trying)
 	char *tmpfile, *lockfile;
 
 	tmpfile = zalloc(len + 10 + 1);
-	sprintf(tmpfile, "%s.%ld", fn, mypid);
+	sprintf(tmpfile, "%s.%ld", fn, (long)mypid);
 	if ((fd = open(tmpfile, O_RDWR|O_CREAT|O_EXCL, 0644)) >= 0) {
 	    write(fd, "0\n", 2);
 	    close(fd);
diff --git a/Src/init.c b/Src/init.c
index e92a5000f..86d5aa505 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -414,7 +414,7 @@ init_shout(void)
 static char *tccapnams[TC_COUNT] = {
     "cl", "le", "LE", "nd", "RI", "up", "UP", "do",
     "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta",
-    "md", "so", "us", "me", "se", "ue"
+    "md", "so", "us", "me", "se", "ue", "ch"
 };
 
 /* Initialise termcap */
@@ -583,8 +583,8 @@ setupvals(void)
     zoptarg = ztrdup("");
     zoptind = 1;
 
-    ppid  = (long) getppid();
-    mypid = (long) getpid();
+    ppid  = (zlong) getppid();
+    mypid = (zlong) getpid();
     term  = ztrdup("");
 
     /* The following variable assignments cause zsh to behave more *
diff --git a/Src/input.c b/Src/input.c
index 6e62ce2c7..b4a6fe22d 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -406,7 +406,7 @@ stuff(char *fn)
 {
     FILE *in;
     char *buf;
-    int len;
+    off_t len;
 
     if (!(in = fopen(unmeta(fn), "r"))) {
 	zerr("can't open %s", fn, 0);
diff --git a/Src/jobs.c b/Src/jobs.c
index 6ddef0f70..7b0eca6b6 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -175,8 +175,23 @@ update_job(Job jn)
 	    jn->ty = (struct ttyinfo *) zalloc(sizeof(struct ttyinfo));
 	    gettyinfo(jn->ty);
 	}
-	if (jn->stat & STAT_STOPPED)
+	if (jn->stat & STAT_STOPPED) {
+	    if (jn->stat & STAT_SUBJOB) {
+		/* If we have `cat foo|while read a; grep $a bar;done'
+		 * and have hit ^Z, the sub-job is stopped, but the
+		 * super-job may still be running, waiting to be stopped
+		 * or to exit. So we have to send it a SIGSTOP. */
+		int i;
+
+		for (i = 1; i < MAXJOB; i++)
+		    if ((jobtab[i].stat & STAT_SUPERJOB) &&
+			jobtab[i].other == job) {
+			killpg(jobtab[i].gleader, SIGSTOP);
+			break;
+		    }
+	    }
 	    return;
+	}
     } else {                   /* job is done, so remember return value */
 	lastval2 = val;
 	/* If last process was run in the current shell, keep old status
@@ -202,14 +217,27 @@ update_job(Job jn)
 	if (mypgrp != pgrp && inforeground &&
 	    (jn->gleader == pgrp || (pgrp > 1 && kill(-pgrp, 0) == -1))) {
 	    if (list_pipe) {
-		/*
-		 * Oh, dear, we're right in the middle of some confusion
-		 * of shell jobs on the righthand side of a pipeline, so
-		 * it's death to call attachtty() just yet.  Mark the
-		 * fact in the job, so that the attachtty() will be called
-		 * when the job is finally deleted.
-		 */
-		jn->stat |= STAT_ATTACH;
+		if (pgrp > 1 && kill(-pgrp, 0) == -1) {
+		    attachtty(mypgrp);
+		    /* check window size and adjust if necessary */
+		    adjustwinsize(0);
+		} else {
+		    /*
+		     * Oh, dear, we're right in the middle of some confusion
+		     * of shell jobs on the righthand side of a pipeline, so
+		     * it's death to call attachtty() just yet.  Mark the
+		     * fact in the job, so that the attachtty() will be called
+		     * when the job is finally deleted.
+		     */
+		    jn->stat |= STAT_ATTACH;
+		}
+		/* If we have `foo|while true; (( x++ )); done', and hit
+		 * ^C, we have to stop the loop, too. */
+		if ((val & 0200) && inforeground == 1) {
+		    breaks = loops;
+		    errflag = 1;
+		    inerrflush();
+		}
 	    } else {
 		attachtty(mypgrp);
 		/* check window size and adjust if necessary */
@@ -765,8 +793,17 @@ waitjob(int job, int sig)
 			}
 		    if (!p) {
 			jn->stat &= ~STAT_SUPERJOB;
+			if (WIFEXITED(jn->procs->status))
+			    jn->gleader = mypgrp;
+			/* This deleted the job too early if the parent
+			   shell waited for a command in a list that will
+			   be executed by the sub-shell (e.g.: if we have
+			   `ls|if true;then sleep 20;cat;fi' and ^Z the
+			   sleep, the rest will be executed by a sub-shell,
+			   but the parent shell gets notified for the
+			   sleep.
+			   deletejob(sj); */
 			kill(sj->other, SIGCONT);
-			deletejob(sj);
 		    }
 		    curjob = jn - jobtab;
 		}
diff --git a/Src/math.c b/Src/math.c
index 7a0a1f9bd..efbf22e44 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -42,7 +42,7 @@ int lastbase;
  
 static char *ptr;
 
-static long yyval;
+static zlong yyval;
 static LV yylval;
 
 static int mlevel = 0;
@@ -409,14 +409,14 @@ static int sp = -1;			/* stack pointer */
 
 struct mathvalue {
     LV lval;
-    long val;
+    zlong val;
 };
 
 static struct mathvalue *stack;
 
 /**/
 static void
-push(long val, LV lval)
+push(zlong val, LV lval)
 {
     if (sp == STACKSZ - 1)
 	zerr("stack overflow", NULL, 0);
@@ -428,7 +428,7 @@ push(long val, LV lval)
 
 
 /**/
-static long
+static zlong
 getcvar(LV s)
 {
     char *t;
@@ -440,8 +440,8 @@ getcvar(LV s)
 
 
 /**/
-static long
-setvar(LV s, long v)
+static zlong
+setvar(LV s, zlong v)
 {
     if (s == -1 || s >= lvc) {
 	zerr("lvalue required", NULL, 0);
@@ -456,7 +456,7 @@ setvar(LV s, long v)
 
 /**/
 static int
-notzero(long a)
+notzero(zlong a)
 {
     if (a == 0) {
 	zerr("division by zero", NULL, 0);
@@ -496,7 +496,7 @@ notzero(long a)
 void
 op(int what)
 {
-    long a, b, c;
+    zlong a, b, c;
     LV lv;
 
     if (sp < 0) {
@@ -569,39 +569,39 @@ op(int what)
 	break;
     case LES:
 	pop2();
-	pushv((long)(a < b));
+	pushv((zlong)(a < b));
 	break;
     case LEQ:
 	pop2();
-	pushv((long)(a <= b));
+	pushv((zlong)(a <= b));
 	break;
     case GRE:
 	pop2();
-	pushv((long)(a > b));
+	pushv((zlong)(a > b));
 	break;
     case GEQ:
 	pop2();
-	pushv((long)(a >= b));
+	pushv((zlong)(a >= b));
 	break;
     case DEQ:
 	pop2();
-	pushv((long)(a == b));
+	pushv((zlong)(a == b));
 	break;
     case NEQ:
 	pop2();
-	pushv((long)(a != b));
+	pushv((zlong)(a != b));
 	break;
     case DAND:
 	pop2();
-	pushv((long)(a && b));
+	pushv((zlong)(a && b));
 	break;
     case DOR:
 	pop2();
-	pushv((long)(a || b));
+	pushv((zlong)(a || b));
 	break;
     case DXOR:
 	pop2();
-	pushv((long)((a && !b) || (!a && b)));
+	pushv((zlong)((a && !b) || (!a && b)));
 	break;
     case QUEST:
 	pop3();
@@ -658,15 +658,15 @@ op(int what)
 	break;
     case DANDEQ:
 	pop2lv();
-	set((long)(a && b));
+	set((zlong)(a && b));
 	break;
     case DOREQ:
 	pop2lv();
-	set((long)(a || b));
+	set((zlong)(a || b));
 	break;
     case DXOREQ:
 	pop2lv();
-	set((long)((a && !b) || (!a && b)));
+	set((zlong)((a && !b) || (!a && b)));
 	break;
     case COMMA:
 	pop2();
@@ -725,18 +725,18 @@ bop(int tk)
 
 
 /**/
-static long
+static zlong
 mathevall(char *s, int prek, char **ep)
 {
     int t0;
     int xlastbase, xnoeval, xunary, xlvc;
     char *xptr;
-    long xyyval;
+    zlong xyyval;
     LV xyylval;
     char **xlvals = 0;
     int xsp;
     struct mathvalue *xstack = 0;
-    long ret;
+    zlong ret;
 
     xlastbase = xnoeval = xunary = xlvc = xyyval = xyylval = xsp = 0;
     xptr = NULL;
@@ -789,11 +789,11 @@ mathevall(char *s, int prek, char **ep)
 
 
 /**/
-long
+zlong
 matheval(char *s)
 {
     char *junk;
-    long x;
+    zlong x;
     int xmtok = mtok;
 
     if (!*s)
@@ -807,10 +807,10 @@ matheval(char *s)
 
 
 /**/
-long
+zlong
 mathevalarg(char *s, char **ss)
 {
-    long x;
+    zlong x;
     int xmtok = mtok;
 
     x = mathevall(s, ARGPREC, ss);
diff --git a/Src/mem.c b/Src/mem.c
index ee0f5635f..97ff7fdc2 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -96,7 +96,7 @@ static int h_m[1025], h_push, h_pop, h_free;
 
 #endif
 
-#define H_ISIZE  sizeof(long)
+#define H_ISIZE  sizeof(zlong)
 #define HEAPSIZE (8192 - H_ISIZE)
 #define HEAP_ARENA_SIZE (HEAPSIZE - sizeof(struct heap))
 #define HEAPFREE (16384 - H_ISIZE)
@@ -500,8 +500,9 @@ ztrdup(const char *s)
 /*
    Below is a simple segment oriented memory allocator for systems on
    which it is better than the system's one. Memory is given in blocks
-   aligned to an integer multiple of sizeof(long) (4 bytes on most machines,
-   but 8 bytes on e.g. a dec alpha). Each block is preceded by a header
+   aligned to an integer multiple of sizeof(zlong) (4 bytes on most machines,
+   but 8 bytes on e.g. a dec alpha; it will be 8 bytes if we are using
+   long long's or equivalent). Each block is preceded by a header
    which contains the length of the data part (in bytes). In allocated
    blocks only this field of the structure m_hdr is senseful. In free
    blocks the second field (next) is a pointer to the next free segment
@@ -561,22 +562,26 @@ ztrdup(const char *s)
 
 struct m_shdr {
     struct m_shdr *next;	/* next one on free list */
+#ifdef ZSH_64_BIT_TYPE
+    /* dummy to make this 64-bit aligned */
+    struct m_shdr *dummy;
+#endif
 };
 
 struct m_hdr {
-    long len;			/* length of memory block */
+    zlong len;			/* length of memory block */
     struct m_hdr *next;		/* if free: next on free list
 				   if block of small blocks: next one with
 				                 small blocks of same size*/
     struct m_shdr *free;	/* if block of small blocks: free list */
-    long used;			/* if block of small blocks: number of used
+    zlong used;			/* if block of small blocks: number of used
 				                                     blocks */
 };
 
 
 /* alignment for memory blocks */
 
-#define M_ALIGN (sizeof(long))
+#define M_ALIGN (sizeof(zlong))
 
 /* length of memory header, length of first field of memory header and
    minimal size of a block left free (if we allocate memory and take a
@@ -585,7 +590,7 @@ struct m_hdr {
    the free list) */
 
 #define M_HSIZE (sizeof(struct m_hdr))
-#define M_ISIZE (sizeof(long))
+#define M_ISIZE (sizeof(zlong))
 #define M_MIN   (2 * M_ISIZE)
 
 /* a pointer to the last free block, a pointer to the free list (the blocks
@@ -621,9 +626,9 @@ static char *m_high, *m_low;
 #define M_SNUM     50
 #define M_SLEN(M)  ((M)->len / M_SNUM)
 #define M_SBLEN(S) ((S) * M_SNUM + sizeof(struct m_shdr *) +  \
-		    sizeof(long) + sizeof(struct m_hdr *))
+		    sizeof(zlong) + sizeof(struct m_hdr *))
 #define M_BSLEN(S) (((S) - sizeof(struct m_shdr *) -  \
-		     sizeof(long) - sizeof(struct m_hdr *)) / M_SNUM)
+		     sizeof(zlong) - sizeof(struct m_hdr *)) / M_SNUM)
 #define M_NSMALL 8
 
 static struct m_hdr *m_small[M_NSMALL];
@@ -1198,8 +1203,9 @@ bin_mem(char *name, char **argv, char *ops, int func)
 	if (m == mf)
 	    buf[0] = '\0';
 	else if (m == ms)
-	    sprintf(buf, "%ld %ld %ld", M_SNUM - ms->used, ms->used,
-		    (m->len - sizeof(struct m_hdr)) / M_SNUM + 1);
+	    sprintf(buf, "%ld %ld %ld", (long)(M_SNUM - ms->used),
+		    (long)ms->used,
+		    (long)(m->len - sizeof(struct m_hdr)) / M_SNUM + 1);
 
 	else {
 	    for (i = 0, b = buf, c = (char *)&m->next; i < 20 && i < m->len;
@@ -1210,7 +1216,7 @@ bin_mem(char *name, char **argv, char *ops, int func)
 
 	printf("%d\t%d\t%ld\t%ld\t%s\t%ld\t%s\n", ii,
 	       (m == mf) ? fi++ : ui++,
-	       (long)m, m->len,
+	       (long)m, (long)m->len,
 	       (m == mf) ? "free" : ((m == ms) ? "small" : "used"),
 	       (m == mf) ? (f += m->len) : (u += m->len),
 	       buf);
@@ -1231,7 +1237,8 @@ bin_mem(char *name, char **argv, char *ops, int func)
 	    printf("%ld\t", (long)i * M_ISIZE);
 
 	    for (ii = 0, m = m_small[i]; m; m = m->next) {
-		printf("(%ld/%ld) ", M_SNUM - m->used, m->used);
+		printf("(%ld/%ld) ", (long)(M_SNUM - m->used),
+		       (long)m->used);
 		if (!((++ii) & 7))
 		    printf("\n\t");
 	    }
diff --git a/Src/module.c b/Src/module.c
index c966d4497..fa7dd2774 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -1224,8 +1224,8 @@ addparamdef(Paramdef d)
 
     pm->level = 0;
     pm->u.data = d->var;
-    pm->sets.ifn = (void (*)(Param, long)) d->set;
-    pm->gets.ifn = (long (*)(Param)) d->get;
+    pm->sets.ifn = (void (*)(Param, zlong)) d->set;
+    pm->gets.ifn = (zlong (*)(Param)) d->get;
     pm->unsetfn = (void (*)(Param, int)) d->unset;
 
     return 0;
diff --git a/Src/options.c b/Src/options.c
index c0042a662..36030f516 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -45,15 +45,6 @@ char opts[OPT_SIZE];
 /**/
 HashTable optiontab;
  
-typedef struct optname *Optname;
-
-struct optname {
-    HashNode next;		/* next in hash chain */
-    char *nam;			/* hash data */
-    int flags;
-    int optno;			/* option number */
-};
-
 /* The canonical option name table */
 
 #define OPT_CSH		EMULATE_CSH
@@ -73,6 +64,10 @@ struct optname {
 
 #define defset(X) (!!((X)->flags & emulation))
 
+/*
+ * Note that option names should usually be fewer than 20 characters long
+ * to avoid formatting problems.
+ */
 static struct optname optns[] = {
 {NULL, "allexport",	      0,			 ALLEXPORT},
 {NULL, "alwayslastprompt",    OPT_ALL,			 ALWAYSLASTPROMPT},
@@ -137,7 +132,7 @@ static struct optname optns[] = {
 {NULL, "hup",		      OPT_EMULATE|OPT_ZSH,	 HUP},
 {NULL, "ignorebraces",	      OPT_EMULATE|OPT_SH,	 IGNOREBRACES},
 {NULL, "ignoreeof",	      0,			 IGNOREEOF},
-{NULL, "incrementalappendhistory",0,			 INCREMENTALAPPENDHISTORY},
+{NULL, "incappendhistory",    0,			 INCAPPENDHISTORY},
 {NULL, "interactive",	      OPT_SPECIAL,		 INTERACTIVE},
 {NULL, "interactivecomments", OPT_EMULATE|OPT_BOURNE,	 INTERACTIVECOMMENTS},
 {NULL, "ksharrays",	      OPT_EMULATE|OPT_BOURNE,	 KSHARRAYS},
@@ -443,6 +438,17 @@ emulate(const char *zsh_name, int fully)
 {
     char ch = *zsh_name;
 
+    if (!strcmp("su", zsh_name)) {
+	/* We haven't set up the paramtable yet, so just use zgetenv */
+	char *ptr = zgetenv("SHELL");
+	if (ptr && *ptr) {
+	    zsh_name = ptr;
+	    if ((ptr = strrchr(zsh_name, '/')))
+		zsh_name = ptr+1;
+	    ch = *zsh_name;
+	} else
+	    ch = 'z';
+    }
     if (ch == 'r')
 	ch = zsh_name[1];
 
diff --git a/Src/params.c b/Src/params.c
index a8b027988..e10fbda93 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -74,7 +74,7 @@ char *argzero,		/* $0           */
      *zsh_name;		/* $ZSH_NAME    */
 
 /**/
-long lastval,		/* $?           */
+zlong lastval,		/* $?           */
      mypid,		/* $$           */
      lastpid,		/* $!           */
      columns,		/* $COLUMNS     */
@@ -334,7 +334,7 @@ copyparamtable(HashTable ht, char *name)
 static unsigned numparamvals;
 
 /**/
-static void
+void
 scancountparams(HashNode hn, int flags)
 {
     ++numparamvals;
@@ -346,7 +346,7 @@ static Comp scancomp;
 static char **paramvals;
 
 /**/
-static void
+void
 scanparamvals(HashNode hn, int flags)
 {
     struct value v;
@@ -572,6 +572,8 @@ createparam(char *name, int flags)
 			 gethashnode2(paramtab, name) :
 			 paramtab->getnode(paramtab, name));
 
+	DPUTS(oldpm && oldpm->level > locallevel,
+	      "BUG:  old local parameter not deleteed");
 	if (oldpm && oldpm->level == locallevel) {
 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
 		oldpm->flags &= ~PM_UNSET;
@@ -704,13 +706,13 @@ isident(char *s)
 static char **garr;
 
 /**/
-static long
-getarg(char **str, int *inv, Value v, int a2, long *w)
+static zlong
+getarg(char **str, int *inv, Value v, int a2, zlong *w)
 {
     int num = 1, word = 0, rev = 0, ind = 0, down = 0, l, i, ishash;
     int beg = 0, hasbeg = 0;
     char *s = *str, *sep = NULL, *t, sav, *d, **ta, **p, *tt;
-    long r = 0;
+    zlong r = 0;
     Comp c;
 
     ishash = (v->pm && PM_TYPE(v->pm->flags) == PM_HASHED);
@@ -872,7 +874,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		return 0;
 
 	    if (!a2 && *tt != ',')
-		*w = (long)(s - t) - 1;
+		*w = (zlong)(s - t) - 1;
 
 	    return (a2 ? s : d + 1) - t;
 	} else if (!v->isarr && !word) {
@@ -973,7 +975,7 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		    r++;
 		for (i = 0; (t = findword(&d, sep)) && *t; i++)
 		    if (!--r) {
-			r = (long)(t - s + (a2 ? -1 : 1));
+			r = (zlong)(t - s + (a2 ? -1 : 1));
 			if (!a2 && *tt != ',')
 			    *w = r + strlen(ta[i]) - 2;
 			return r;
@@ -1051,7 +1053,7 @@ getindex(char **pptr, Value v)
 	v->b = -1;
 	s += 2;
     } else {
-	long we = 0, dummy;
+	zlong we = 0, dummy;
 
 	a = getarg(&s, &inv, v, 0, &we);
 
@@ -1216,7 +1218,7 @@ char *
 getstrvalue(Value v)
 {
     char *s, **ss;
-    static char buf[(sizeof(long) * 8) + 4];
+    static char buf[(sizeof(zlong) * 8) + 4];
 
     if (!v)
 	return hcalloc(1);
@@ -1314,7 +1316,7 @@ getarrvalue(Value v)
 }
 
 /**/
-long
+zlong
 getintvalue(Value v)
 {
     if (!v || v->isarr)
@@ -1330,7 +1332,7 @@ getintvalue(Value v)
 static void
 setstrvalue(Value v, char *val)
 {
-    char buf[(sizeof(long) * 8) + 4];
+    char buf[(sizeof(zlong) * 8) + 4];
 
     if (v->pm->flags & PM_READONLY) {
 	zerr("read-only variable: %s", v->pm->nam, 0);
@@ -1414,7 +1416,7 @@ setstrvalue(Value v, char *val)
 
 /**/
 static void
-setintvalue(Value v, long val)
+setintvalue(Value v, zlong val)
 {
     char buf[DIGBUFSIZE];
 
@@ -1429,7 +1431,7 @@ setintvalue(Value v, long val)
     switch (PM_TYPE(v->pm->flags)) {
     case PM_SCALAR:
     case PM_ARRAY:
-	sprintf(buf, "%ld", val);
+	convbase(buf, val, 0);
 	setstrvalue(v, ztrdup(buf));
 	break;
     case PM_INTEGER:
@@ -1508,7 +1510,7 @@ setarrvalue(Value v, char **val)
 /* Retrieve an integer parameter */
 
 /**/
-long
+zlong
 getiparam(char *s)
 {
     Value v;
@@ -1681,7 +1683,7 @@ sethparam(char *s, char **val)
 
 /**/
 Param
-setiparam(char *s, long val)
+setiparam(char *s, zlong val)
 {
     Value v;
     char *t = s;
@@ -1794,7 +1796,7 @@ stdunsetfn(Param pm, int exp)
 /* Function to get value of an integer parameter */
 
 /**/
-static long
+static zlong
 intgetfn(Param pm)
 {
     return pm->u.val;
@@ -1804,7 +1806,7 @@ intgetfn(Param pm)
 
 /**/
 static void
-intsetfn(Param pm, long x)
+intsetfn(Param pm, zlong x)
 {
     pm->u.val = x;
 }
@@ -1859,7 +1861,7 @@ arrsetfn(Param pm, char **x)
 /* Function to get value of an association parameter */
 
 /**/
-static HashTable
+HashTable
 hashgetfn(Param pm)
 {
     return pm->u.hash;
@@ -1872,7 +1874,7 @@ static int delunset;
 /* Function to set value of an association parameter */
 
 /**/
-static void
+void
 hashsetfn(Param pm, HashTable x)
 {
     if (pm->u.hash && pm->u.hash != x) {
@@ -1941,10 +1943,10 @@ nullsetfn(Param pm, char *x)
  * containing the integer value.                    */
 
 /**/
-long
+zlong
 intvargetfn(Param pm)
 {
-    return *((long *)pm->u.data);
+    return *((zlong *)pm->u.data);
 }
 
 /* Function to set value of generic special integer *
@@ -1953,9 +1955,9 @@ intvargetfn(Param pm)
 
 /**/
 void
-intvarsetfn(Param pm, long x)
+intvarsetfn(Param pm, zlong x)
 {
-    *((long *)pm->u.data) = x;
+    *((zlong *)pm->u.data) = x;
 }
 
 /* Function to set value of any ZLE-related integer *
@@ -1964,9 +1966,9 @@ intvarsetfn(Param pm, long x)
 
 /**/
 void
-zlevarsetfn(Param pm, long x)
+zlevarsetfn(Param pm, zlong x)
 {
-    long *p = (long *)pm->u.data;
+    zlong *p = (zlong *)pm->u.data;
 
     *p = x;
     if (p == &lines || p == &columns)
@@ -2086,7 +2088,7 @@ uniqarray(char **x)
 /* Function to get value of special parameter `#' and `ARGC' */
 
 /**/
-long
+zlong
 poundgetfn(Param pm)
 {
     return arrlen(pparams);
@@ -2095,7 +2097,7 @@ poundgetfn(Param pm)
 /* Function to get value for special parameter `RANDOM' */
 
 /**/
-long
+zlong
 randomgetfn(Param pm)
 {
     return rand() & 0x7fff;
@@ -2105,7 +2107,7 @@ randomgetfn(Param pm)
 
 /**/
 void
-randomsetfn(Param pm, long v)
+randomsetfn(Param pm, zlong v)
 {
     srand((unsigned int)v);
 }
@@ -2113,7 +2115,7 @@ randomsetfn(Param pm, long v)
 /* Function to get value for special parameter `SECONDS' */
 
 /**/
-long
+zlong
 secondsgetfn(Param pm)
 {
     return time(NULL) - shtimer.tv_sec;
@@ -2123,7 +2125,7 @@ secondsgetfn(Param pm)
 
 /**/
 void
-secondssetfn(Param pm, long x)
+secondssetfn(Param pm, zlong x)
 {
     shtimer.tv_sec = time(NULL) - x;
     shtimer.tv_usec = 0;
@@ -2163,7 +2165,7 @@ usernamesetfn(Param pm, char *x)
 /* Function to get value for special parameter `UID' */
 
 /**/
-long
+zlong
 uidgetfn(Param pm)
 {
     return getuid();
@@ -2183,7 +2185,7 @@ uidsetfn(Param pm, uid_t x)
 /* Function to get value for special parameter `EUID' */
 
 /**/
-long
+zlong
 euidgetfn(Param pm)
 {
     return geteuid();
@@ -2203,7 +2205,7 @@ euidsetfn(Param pm, uid_t x)
 /* Function to get value for special parameter `GID' */
 
 /**/
-long
+zlong
 gidgetfn(Param pm)
 {
     return getgid();
@@ -2223,7 +2225,7 @@ gidsetfn(Param pm, gid_t x)
 /* Function to get value for special parameter `EGID' */
 
 /**/
-long
+zlong
 egidgetfn(Param pm)
 {
     return getegid();
@@ -2241,7 +2243,7 @@ egidsetfn(Param pm, gid_t x)
 }
 
 /**/
-long
+zlong
 ttyidlegetfn(Param pm)
 {
     struct stat ttystat;
@@ -2345,7 +2347,7 @@ lcsetfn(Param pm, char *x)
 /* Function to get value for special parameter `HISTSIZE' */
 
 /**/
-long
+zlong
 histsizegetfn(Param pm)
 {
     return histsiz;
@@ -2355,7 +2357,7 @@ histsizegetfn(Param pm)
 
 /**/
 void
-histsizesetfn(Param pm, long v)
+histsizesetfn(Param pm, zlong v)
 {
     if ((histsiz = v) <= 2)
 	histsiz = 2;
@@ -2365,7 +2367,7 @@ histsizesetfn(Param pm, long v)
 /* Function to get value for special parameter `ERRNO' */
 
 /**/
-long
+zlong
 errnogetfn(Param pm)
 {
     return errno;
@@ -2626,11 +2628,11 @@ delenv(char *x)
 }
 
 /**/
-static void
-convbase(char *s, long v, int base)
+void
+convbase(char *s, zlong v, int base)
 {
     int digs = 0;
-    unsigned long x;
+    zulong x;
 
     if (v < 0)
 	*s++ = '-', v = -v;
@@ -2774,7 +2776,11 @@ printparamnode(HashNode hn, int printflags)
 	break;
     case PM_INTEGER:
 	/* integer */
+#ifdef ZSH_64_BIT_TYPE
+	fputs(output64(p->gets.ifn(p)), stdout);
+#else
 	printf("%ld", p->gets.ifn(p));
+#endif
 	break;
     case PM_ARRAY:
 	/* array */
diff --git a/Src/prototypes.h b/Src/prototypes.h
index f7f560111..1754c9b96 100644
--- a/Src/prototypes.h
+++ b/Src/prototypes.h
@@ -51,7 +51,7 @@ extern int tputs _((char *cp, int affcnt, int (*outc) (int)));
 # define WRITE_ARG_2_T char *
 #endif
 
-#if defined(__hpux) && defined(_HPUX_SOURCE)
+#if defined(__hpux) && defined(_HPUX_SOURCE) && !defined(_XPG4_EXTENDED)
 # define SELECT_ARG_2_T int *
 #else
 # define SELECT_ARG_2_T fd_set *
diff --git a/Src/subst.c b/Src/subst.c
index 4b60de120..3030218d6 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -99,6 +99,8 @@ stringsubst(LinkList list, LinkNode node, int ssub)
     while (!errflag && *str) {
 	if ((qt = *str == Qstring) || *str == String) {
 	    if (str[1] == Inpar) {
+		if (!qt)
+		    mult_isarr = 1;
 		str++;
 		goto comsub;
 	    } else if (str[1] == Inbrack) {
@@ -249,6 +251,7 @@ singsub(char **s)
  * The mult_isarr variable is used by paramsubst() to tell if it yields *
  * an array.                                                            */
 
+/**/
 static int mult_isarr;
 
 /**/
@@ -282,6 +285,8 @@ multsub(char **s, char ***a, int *isarr, char *sep)
 	}
 	*s = sepjoin(r, NULL);
 	mult_isarr = omi;
+	if (isarr)
+	    *isarr = 0;
 	return 0;
     }
     if (l)
@@ -666,7 +671,7 @@ get_intarg(char **s)
 {
     char *t = get_strarg(*s + 1);
     char *p, sav;
-    long ret;
+    zlong ret;
 
     if (!*t)
 	return -1;
@@ -719,7 +724,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
     char *sep = NULL, *spsep = NULL;
     char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL;
     char *replstr = NULL;	/* replacement string for /orig/repl */
-    long prenum = 0, postnum = 0;
+    zlong prenum = 0, postnum = 0;
     int copied = 0;
     int arrasg = 0;
     int eval = 0;
@@ -751,7 +756,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	} else if (*s == '(' || *s == Inpar) {
 	    char *t, sav;
 	    int tt = 0;
-	    long num;
+	    zlong num;
 	    int escapes = 0;
 	    int klen;
 #define UNTOK(C)  (itok(C) ? ztokens[(C) - Pound] : (C))
@@ -1678,13 +1683,13 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 static char *
 arithsubst(char *a, char **bptr, char *rest)
 {
-    char *s = *bptr, *t, buf[DIGBUFSIZE];
-    char *b = buf;
-    long v;
+    char *s = *bptr, *t;
+    char buf[DIGBUFSIZE], *b = buf;
+    zlong v;
 
     singsub(&a);
     v = matheval(a);
-    sprintf(buf, "%ld", v);
+    convbase(buf, v, 0);
     t = *bptr = (char *)ncalloc(strlen(*bptr) + strlen(buf) + strlen(rest) + 1);
     t--;
     while ((*++t = *s++));
diff --git a/Src/system.h b/Src/system.h
index 2babafa7a..e95e2c4cc 100644
--- a/Src/system.h
+++ b/Src/system.h
@@ -27,12 +27,6 @@
  *
  */
 
-#ifdef __hpux
-# define _INCLUDE_POSIX_SOURCE 1
-# define _INCLUDE_XOPEN_SOURCE 1
-# define _INCLUDE_HPUX_SOURCE 1
-#endif
-
 #ifdef sinix
 # define _XPG_IV 1
 #endif
@@ -401,9 +395,10 @@ struct timezone {
 #endif
 
 /* DIGBUFSIZ is the length of a buffer which can hold the -LONG_MAX-1 *
+ * (or with ZSH_64_BIT_TYPE maybe -LONG_LONG_MAX-1)                   *
  * converted to printable decimal form including the sign and the     *
  * terminating null character. Below 0.30103 > lg 2.                  */
-#define DIGBUFSIZE ((int)(((sizeof(long) * 8) - 1) * 0.30103) + 3)
+#define DIGBUFSIZE ((int)(((sizeof(zlong) * 8) - 1) * 0.30103) + 3)
 
 /* If your stat macros are broken, we will *
  * just undefine them.                     */
@@ -609,3 +604,12 @@ extern short ospeed;
 #ifndef O_NOCTTY
 # define O_NOCTTY 0
 #endif
+
+#ifdef _LARGEFILE_SOURCE
+#ifdef HAVE_FSEEKO
+#define fseek fseeko
+#endif
+#ifdef HAVE_FTELLO
+#define ftell ftello
+#endif
+#endif
diff --git a/Src/utils.c b/Src/utils.c
index faeeb0c58..32588b4c3 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -134,7 +134,7 @@ zerrnam(const char *cmd, const char *fmt, const char *str, int num)
 	    fmt++;
 	}
     if (unset(SHINSTDIN) && lineno)
-	fprintf(stderr, " [%ld]\n", lineno);
+	fprintf(stderr, " [%ld]\n", (long)lineno);
     else
 	putc('\n', stderr);
     fflush(stderr);
@@ -1096,15 +1096,15 @@ skipparens(char inpar, char outpar, char **s)
    return level;
 }
 
-/* Convert string to long.  This function (without the z) *
- * is contained in the ANSI standard C library, but a lot *
- * of them seem to be broken.                             */
+/* Convert string to zlong (see zsh.h).  This function (without the z) *
+ * is contained in the ANSI standard C library, but a lot of them seem *
+ * to be broken.                                                       */
 
 /**/
-long
+zlong
 zstrtol(const char *s, char **t, int base)
 {
-    long ret = 0;
+    zlong ret = 0;
     int neg;
 
     while (inblank(*s))
diff --git a/Src/zsh.export b/Src/zsh.export
index b62621e0f..65626e2f6 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -31,6 +31,7 @@ compctlreadptr
 cond_match
 cond_str
 cond_val
+convbase
 coprocin
 coprocout
 countlinknodes
@@ -45,6 +46,7 @@ deletehashtable
 deleteparamdefs
 deletewrapper
 domatch
+dosetopt
 doshfunc
 down_histent
 dputs
@@ -52,6 +54,7 @@ dquotedztrdup
 dummy_list
 dupstring
 dupstrpfx
+dupstruct
 dyncat
 emptyhashtable
 endparamscope
@@ -71,6 +74,7 @@ findcmd
 firsthist
 freearray
 freeheap
+freestruct
 getaparam
 gethashnode
 gethashnode2
@@ -79,7 +83,9 @@ getintvalue
 getiparam
 getkeystring
 getlinknode
+getpermtext
 getshfunc
+getsignum
 getsparam
 getstrvalue
 gettempname
@@ -92,6 +98,8 @@ gotwordptr
 hasam
 hashcmd
 hasher
+hashgetfn
+hashsetfn
 hasspecial
 haswilds
 hcalloc
@@ -156,10 +164,13 @@ noop_function
 noop_function_int
 old_heaps
 optiontab
+optlookup
 opts
+output64
 paramtab
 parbegin
 parend
+parse_string
 parsereg
 parsestr
 path
@@ -171,6 +182,7 @@ ppid
 prefork
 prepromptfns
 printif
+printparamnode
 printqt
 promptexpand
 pushheap
@@ -179,6 +191,7 @@ pwd
 quietgetevent
 quietgethist
 quotedzputs
+realparamtab
 refreshptr
 remlpaths
 remnulargs
@@ -189,11 +202,13 @@ restoredir
 reswdtab
 retflag
 runshfunc
+scancountparams
 scanhashtable
 setaparam
 sethparam
 setlimits
 setsparam
+settrap
 settyinfo
 sfcontext
 shfunctab
@@ -211,6 +226,7 @@ startparamscope
 stdunsetfn
 stophist
 stopmsg
+strgetfn
 strinbeg
 strinend
 strpfx
diff --git a/Src/zsh.h b/Src/zsh.h
index 1d635afdc..ae4513491 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -38,6 +38,21 @@
 /* A few typical macros */
 #define minimum(a,b)  ((a) < (b) ? (a) : (b))
 
+/*
+ * Our longest integer type:  will be a 64 bit either if long already is,
+ * or if we found some alternative such as long long.
+ * Currently we only define this to be longer than a long if --enable-lfs
+ * was given.  That enables internal use of 64-bit types even if
+ * no actual large file support is present.
+ */
+#ifdef ZSH_64_BIT_TYPE
+typedef ZSH_64_BIT_TYPE zlong;
+typedef unsigned ZSH_64_BIT_TYPE zulong;
+#else
+typedef long zlong;
+typedef unsigned long zulong;
+#endif
+
 /* math.c */
 typedef int LV;
 
@@ -228,6 +243,7 @@ typedef struct linklist  *LinkList;
 typedef struct hashnode  *HashNode;
 typedef struct hashtable *HashTable;
 
+typedef struct optname   *Optname;
 typedef struct reswd     *Reswd;
 typedef struct alias     *Alias;
 typedef struct param     *Param;
@@ -685,6 +701,7 @@ typedef int      (*CompareFunc)    _((const char *, const char *));
 /* type of function that is passed to *
  * scanhashtable or scanmatchtable    */
 typedef void     (*ScanFunc)       _((HashNode, int));
+typedef void     (*ScanTabFunc)    _((HashTable, ScanFunc, int));
 
 typedef void (*PrintTableStats) _((HashTable));
 
@@ -710,6 +727,7 @@ struct hashtable {
     ScanFunc enablenode;	/* pointer to function to enable a node       */
     FreeNodeFunc freenode;	/* pointer to function to free a node         */
     ScanFunc printnode;		/* pointer to function to print a node        */
+    ScanTabFunc scantab;	/* pointer to function to scan table          */
 
 #ifdef HASHTABLE_INTERNAL_MEMBERS
     HASHTABLE_INTERNAL_MEMBERS	/* internal use in hashtable.c                */
@@ -729,6 +747,15 @@ struct hashnode {
  * reserved words.                                        */
 #define DISABLED	(1<<0)
 
+/* node in shell option table */
+
+struct optname {
+    HashNode next;		/* next in hash chain */
+    char *nam;			/* hash data */
+    int flags;
+    int optno;			/* option number */
+};
+
 /* node in shell reserved word hash table (reswdtab) */
 
 struct reswd {
@@ -868,14 +895,14 @@ struct param {
 	void *data;		/* used by special parameter functions    */
 	char **arr;		/* value if declared array   (PM_ARRAY)   */
 	char *str;		/* value if declared string  (PM_SCALAR)  */
-	long val;		/* value if declared integer (PM_INTEGER) */
+	zlong val;		/* value if declared integer (PM_INTEGER) */
         HashTable hash;		/* value if declared assoc   (PM_HASHED)  */
     } u;
 
     /* pointer to function to set value of this parameter */
     union {
 	void (*cfn) _((Param, char *));
-	void (*ifn) _((Param, long));
+	void (*ifn) _((Param, zlong));
 	void (*afn) _((Param, char **));
         void (*hfn) _((Param, HashTable));
     } sets;
@@ -883,7 +910,7 @@ struct param {
     /* pointer to function to get value of this parameter */
     union {
 	char *(*cfn) _((Param));
-	long (*ifn) _((Param));
+	zlong (*ifn) _((Param));
 	char **(*afn) _((Param));
         HashTable (*hfn) _((Param));
     } gets;
@@ -1155,7 +1182,7 @@ enum {
     HUP,
     IGNOREBRACES,
     IGNOREEOF,
-    INCREMENTALAPPENDHISTORY,
+    INCAPPENDHISTORY,
     INTERACTIVE,
     INTERACTIVECOMMENTS,
     KSHARRAYS,
@@ -1298,7 +1325,8 @@ struct ttyinfo {
 #define TCALLATTRSOFF  21
 #define TCSTANDOUTEND  22
 #define TCUNDERLINEEND 23
-#define TC_COUNT       24
+#define TCHORIZPOS     24
+#define TC_COUNT       25
 
 #define tccan(X) (tclen[X])
 
@@ -1381,6 +1409,9 @@ struct heap {
     struct heap *next;		/* next one                                  */
     size_t used;		/* bytes used from the heap                  */
     struct heapstack *sp;	/* used by pushheap() to save the value used */
+#ifdef ZSH_64_BIT_TYPE
+    size_t dummy;		/* Make sure sizeof(heap) is a multiple of 8 */
+#endif
 #define arena(X)	((char *) (X) + sizeof(struct heap))
 };