about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:10:10 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-04-15 18:10:10 +0000
commit2a5a899a55fd2bce10efd01c75a4bec5285aa46c (patch)
tree4744bc2f1a6b86fc1b12870be94edf96fdab4879 /Src
parent9003d99d16c46b5679da7fcf1f2a41adef495ff9 (diff)
downloadzsh-2a5a899a55fd2bce10efd01c75a4bec5285aa46c.tar.gz
zsh-2a5a899a55fd2bce10efd01c75a4bec5285aa46c.tar.xz
zsh-2a5a899a55fd2bce10efd01c75a4bec5285aa46c.zip
zsh-3.1.5-pws-4 zsh-3.1.5-pws-4
Diffstat (limited to 'Src')
-rw-r--r--Src/Builtins/rlimits.c15
-rw-r--r--Src/Builtins/sched.c14
-rw-r--r--Src/Modules/cap.c15
-rw-r--r--Src/Modules/clone.c15
-rw-r--r--Src/Modules/example.c47
-rw-r--r--Src/Modules/files.c15
-rw-r--r--Src/Modules/stat.c14
-rw-r--r--Src/Modules/zftp.c48
-rw-r--r--Src/Zle/comp.h5
-rw-r--r--Src/Zle/comp1.c16
-rw-r--r--Src/Zle/compctl.c23
-rw-r--r--Src/Zle/deltochar.c15
-rw-r--r--Src/Zle/zle_main.c35
-rw-r--r--Src/Zle/zle_tricky.c18
-rw-r--r--Src/builtin.c6
-rw-r--r--Src/cond.c58
-rw-r--r--Src/exec.c22
-rw-r--r--Src/glob.c2
-rw-r--r--Src/init.c5
-rw-r--r--Src/makepro.awk2
-rw-r--r--Src/mkbltnmlst.sh2
-rw-r--r--Src/modentry.c24
-rw-r--r--Src/module.c257
-rw-r--r--Src/params.c78
-rw-r--r--Src/parse.c6
-rw-r--r--Src/signals.c4
-rw-r--r--Src/subst.c28
-rw-r--r--Src/utils.c22
-rw-r--r--Src/zsh.export3
-rw-r--r--Src/zsh.h65
30 files changed, 677 insertions, 202 deletions
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 20b8d663d..31dcb71b1 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -576,6 +576,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_rlimits(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_rlimits(Module m)
 {
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
@@ -590,4 +597,12 @@ cleanup_rlimits(Module m)
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
+
+/**/
+int
+finish_rlimits(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c
index b4914899e..94661ccef 100644
--- a/Src/Builtins/sched.c
+++ b/Src/Builtins/sched.c
@@ -185,6 +185,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_sched(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_sched(Module m)
 {
     if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
@@ -211,4 +218,11 @@ cleanup_sched(Module m)
     return 0;
 }
 
+/**/
+int
+finish_sched(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/cap.c b/Src/Modules/cap.c
index 008b6932d..dfeca86ad 100644
--- a/Src/Modules/cap.c
+++ b/Src/Modules/cap.c
@@ -124,6 +124,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_cap(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_cap(Module m)
 {
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
@@ -138,4 +145,12 @@ cleanup_cap(Module m)
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
+
+/**/
+int
+finish_cap(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/clone.c b/Src/Modules/clone.c
index 11387fc90..e2cfea8d9 100644
--- a/Src/Modules/clone.c
+++ b/Src/Modules/clone.c
@@ -98,6 +98,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_clone(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_clone(Module m)
 {
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
@@ -112,4 +119,12 @@ cleanup_clone(Module m)
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
+
+/**/
+int
+finish_clone(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index a71806c3a..95545172f 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -51,16 +51,14 @@ bin_example(char *nam, char **args, char *ops, int func)
 
 /**/
 static int
-cond_p_len(Conddef c, char **a)
+cond_p_len(char **a, int id)
 {
-    char *s1 = a[0], *s2 = a[1];
-
-    singsub(&s1);
-    untokenize(s1);
-    if (s2) {
-	singsub(&s2);
-	untokenize(s2);
-	return strlen(s1) == matheval(s2);
+    char *s1 = cond_str(a, 0);
+
+    if (a[1]) {
+	long v = cond_val(a, 1);
+
+	return strlen(s1) == v;
     } else {
 	return !s1[0];
     }
@@ -68,14 +66,10 @@ cond_p_len(Conddef c, char **a)
 
 /**/
 static int
-cond_i_ex(Conddef c, char **a)
+cond_i_ex(char **a, int id)
 {
-    char *s1 = a[0], *s2 = a[1];
+    char *s1 = cond_str(a, 0), *s2 = cond_str(a, 1);
 
-    singsub(&s1);
-    untokenize(s1);
-    singsub(&s2);
-    untokenize(s2);
     return !strcmp("example", dyncat(s1, s2));
 }
 
@@ -105,8 +99,8 @@ static struct builtin bintab[] = {
 };
 
 static struct conddef cotab[] = {
-    CONDDEF("len", 0, 1, 2, cond_p_len),
-    CONDDEF("ex", CONDF_INFIX, 0, 0, cond_i_ex),
+    CONDDEF("len", 0, cond_p_len, 1, 2, 0),
+    CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0),
 };
 
 static struct funcwrap wrapper[] = {
@@ -115,6 +109,15 @@ static struct funcwrap wrapper[] = {
 
 /**/
 int
+setup_example(Module m)
+{
+    printf("The example module has now been set up.\n");
+    fflush(stdout);
+    return 0;
+}
+
+/**/
+int
 boot_example(Module m)
 {
     return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
@@ -133,4 +136,14 @@ cleanup_example(Module m)
     deletewrapper(m, wrapper);
     return 0;
 }
+
+/**/
+int
+finish_example(Module m)
+{
+    printf("Thank you for using the example module.  Have a nice day.\n");
+    fflush(stdout);
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/files.c b/Src/Modules/files.c
index 6127c5524..f52c54338 100644
--- a/Src/Modules/files.c
+++ b/Src/Modules/files.c
@@ -511,6 +511,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_files(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_files(Module m)
 {
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
@@ -525,4 +532,12 @@ cleanup_files(Module m)
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
+
+/**/
+int
+finish_files(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 769b42b1a..5c56be5c6 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -571,6 +571,13 @@ static struct builtin bintab[] = {
 
 /**/
 int
+setup_stat(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_stat(Module m)
 {
     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
@@ -586,4 +593,11 @@ cleanup_stat(Module m)
     return 0;
 }
 
+/**/
+int
+finish_stat(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index ca0843419..4bcd80c7f 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -62,9 +62,9 @@
 /* it's a TELNET based protocol, but don't think I like doing this */
 #include <arpa/telnet.h>
 
-/* bet there are machines which have neither INADDR_NONE nor in_addr_t. */
+/* pinch the definition from <netinet/in.h> for deficient headers */
 #ifndef INADDR_NONE
-#define INADDR_NONE (in_addr_t)-1
+#define INADDR_NONE 0xffffffff
 #endif
 
 /*
@@ -1354,7 +1354,11 @@ zfsenddata(char *name, int recv, int progress, long startat)
 	 * We do this here in case we needed to wait for a RETR
 	 * command to tell us how many bytes are coming.
 	 */
+	int osc = sfcontext;
+
+	sfcontext = SFC_HOOK;
 	doshfunc("zftp_progress", l, NULL, 0, 1);
+	sfcontext = osc;
 	/* Now add in the bit of the file we've got/sent already */
 	sofar = last_sofar = startat;
     }
@@ -1482,8 +1486,12 @@ zfsenddata(char *name, int recv, int progress, long startat)
 	    break;
 	if (!ret && sofar != last_sofar && progress &&
 	    (l = getshfunc("zftp_progress")) != &dummy_list) {
+	    int osc = sfcontext;
+
 	    zfsetparam("ZFTP_COUNT", &sofar, ZFPM_READONLY|ZFPM_INTEGER);
+	    sfcontext = SFC_HOOK;
 	    doshfunc("zftp_progress", l, NULL, 0, 1);
+	    sfcontext = osc;
 	    last_sofar = sofar;
 	}
     }
@@ -1650,7 +1658,7 @@ zftp_open(char *name, char **args, int flags)
 	zfsetparam("ZFTP_HOST", ztrdup(zhostp->h_name), ZFPM_READONLY);
     }
 
-    zsock.sin_port = ntohs(zservp->s_port);
+    zsock.sin_port = zservp->s_port;
     zcfd = zfmovefd(socket(zsock.sin_family, SOCK_STREAM, 0));
     if (zcfd < 0) {
 	zwarnnam(name, "socket failed: %e", NULL, errno);
@@ -2102,9 +2110,13 @@ zfgetcwd(void)
      * front end.  By putting it here, and in close when ZFTP_PWD is unset,
      * we at least cover the bases.
      */
-    if ((l = getshfunc("zftp_chpwd")) != &dummy_list)
-	doshfunc("zftp_chpwd", l, NULL, 0, 1);
+    if ((l = getshfunc("zftp_chpwd")) != &dummy_list) {
+	int osc = sfcontext;
 
+	sfcontext = SFC_HOOK;
+	doshfunc("zftp_chpwd", l, NULL, 0, 1);
+	sfcontext = osc;
+    }
     return 0;
 }
 
@@ -2303,9 +2315,13 @@ zftp_getput(char *name, char **args, int flags)
 	zsfree(ln);
 	if (progress && (l = getshfunc("zftp_progress")) != &dummy_list) {
 	    /* progress to finish: ZFTP_TRANSFER set to GF or PF */
+	    int osc = sfcontext;
+
 	    zfsetparam("ZFTP_TRANSFER", ztrdup(recv ? "GF" : "PF"),
 		       ZFPM_READONLY);
+	    sfcontext = SFC_HOOK;
 	    doshfunc("zftp_progress", l, NULL, 0, 1);
+	    sfcontext = osc;
 	}
 	if (rest) {
 	    zsfree(rest);
@@ -2428,9 +2444,13 @@ zftp_close(char *name, char **args, int flags)
 	zfunsetparam(*aptr);
 
     /* Now ZFTP_PWD is unset.  It's up to zftp_chpwd to notice. */
-    if ((l = getshfunc("zftp_chpwd")) != &dummy_list)
-	doshfunc("zftp_chpwd", l, NULL, 0, 1);
+    if ((l = getshfunc("zftp_chpwd")) != &dummy_list) {
+	int osc = sfcontext;
 
+	sfcontext = SFC_HOOK;
+	doshfunc("zftp_chpwd", l, NULL, 0, 1);
+	sfcontext = osc;
+    }
     /* tidy up status variables, because mess is bad */
     zfclosing = zfdrrrring = 0;
 
@@ -2558,6 +2578,13 @@ bin_zftp(char *name, char **args, char *ops, int func)
 
 /**/
 int
+setup_zftp(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_zftp(Module m)
 {
     int ret;
@@ -2593,4 +2620,11 @@ cleanup_zftp(Module m)
     return 0;
 }
 
+/**/
+int
+finish_zftp(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 84f8c3c98..afd55b7f1 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -98,7 +98,7 @@ struct compcond {
 struct compctl {
     int refc;			/* reference count                         */
     Compctl next;		/* next compctl for -x                     */
-    unsigned long mask, mask2;		/* mask of things to complete (CC_*)       */
+    unsigned long mask, mask2;	/* masks of things to complete (CC_*)      */
     char *keyvar;		/* for -k (variable)                       */
     char *glob;			/* for -g (globbing)                       */
     char *str;			/* for -s (expansion)                      */
@@ -110,7 +110,7 @@ struct compctl {
     char *withd;		/* for -w (with directory                  */
     char *hpat;			/* for -H (history pattern)                */
     int hnum;			/* for -H (number of events to search)     */
-    char *gname;
+    char *gname;		/* for -J and -V (group name)              */
     Compctl ext;		/* for -x (first of the compctls after -x) */
     Compcond cond;		/* for -x (condition for this compctl)     */
     Compctl xor;		/* for + (next of the xor'ed compctls)     */
@@ -169,7 +169,6 @@ struct cexpl {
     char *str;			/* the string */
     int count;			/* the number of matches */
     int fcount;			/* number of matches with fignore ignored */
-
 };
 
 /* This describes a group of matches. */
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index 5ffce0da2..a0c013901 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -430,7 +430,7 @@ quotename(const char *s, char **e, char *te, int *pl)
 
 /**/
 int
-boot_comp1(Module m)
+setup_comp1(Module m)
 {
     compctlreadptr = compctlread;
     clwords = (char **) zcalloc((clwsize = 16) * sizeof(char *));
@@ -446,12 +446,26 @@ boot_comp1(Module m)
     return 0;
 }
 
+/**/
+int
+boot_comp1(Module m)
+{
+    return 0;
+}
+
 #ifdef MODULE
 
 /**/
 int
 cleanup_comp1(Module m)
 {
+    return 0;
+}
+
+/**/
+int
+finish_comp1(Module m)
+{
     deletehashtable(compctltab);
     zfree(clwords, clwsize * sizeof(char *));
     compctlreadptr = fallback_compctlread;
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 7104bfc6e..4d192fef8 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1638,26 +1638,41 @@ static struct builtin bintab[] = {
 
 /**/
 int
-boot_compctl(Module m)
+setup_compctl(Module m)
 {
-    if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
-	return 1;
     compctltab->printnode = printcompctlp;
     printcompctlptr = printcompctl;
     compctl_widgetptr = compctl_widget;
     return 0;
 }
 
+/**/
+int
+boot_compctl(Module m)
+{
+    if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
+	return 1;
+    return 0;
+}
+
 #ifdef MODULE
 
 /**/
 int
 cleanup_compctl(Module m)
 {
-    compctltab->printnode = NULL;
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    return 0;
+}
+
+/**/
+int
+finish_compctl(Module m)
+{
+    compctltab->printnode = NULL;
     printcompctlptr = NULL;
     compctl_widgetptr = NULL;
     return 0;
 }
+
 #endif
diff --git a/Src/Zle/deltochar.c b/Src/Zle/deltochar.c
index 8869eb147..66a301119 100644
--- a/Src/Zle/deltochar.c
+++ b/Src/Zle/deltochar.c
@@ -73,6 +73,13 @@ deltochar(void)
 
 /**/
 int
+setup_deltochar(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_deltochar(Module m)
 {
     w_deletetochar = addzlefunction("delete-to-char", deltochar,
@@ -93,4 +100,12 @@ cleanup_deltochar(Module m)
     deletezlefunction(w_deletetochar);
     return 0;
 }
+
+/**/
+int
+finish_deltochar(Module m)
+{
+    return 0;
+}
+
 #endif
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 57b75cd39..515405a0d 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -603,11 +603,15 @@ execzlefunc(Thingy func)
 	    zsfree(msg);
 	    feep();
 	} else {
-	  startparamscope();
-	  makezleparams();
-	  doshfunc(w->u.fnnam, l, NULL, 0, 1);
-	  endparamscope();
-	  lastcmd = 0;
+	    int osc = sfcontext;
+
+	    startparamscope();
+	    makezleparams();
+	    sfcontext = SFC_WIDGET;
+	    doshfunc(w->u.fnnam, l, NULL, 0, 1);
+	    sfcontext = osc;
+	    endparamscope();
+	    lastcmd = 0;
 	}
     }
 }
@@ -856,7 +860,7 @@ static struct builtin bintab[] = {
 
 /**/
 int
-boot_zle(Module m)
+setup_zle(Module m)
 {
     /* Set up editor entry points */
     trashzleptr = trashzle;
@@ -875,6 +879,13 @@ boot_zle(Module m)
     /* initialise the keymap system */
     init_keymaps();
 
+    return 0;
+}
+
+/**/
+int
+boot_zle(Module m)
+{
     addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
@@ -885,15 +896,21 @@ boot_zle(Module m)
 int
 cleanup_zle(Module m)
 {
-    int i;
-
     if(zleactive) {
 	zerrnam(m->nam, "can't unload the zle module while zle is active",
 	    NULL, 0);
 	return 1;
     }
-
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    return 0;
+}
+
+/**/
+int
+finish_zle(Module m)
+{
+    int i;
+
     cleanup_keymaps();
     deletehashtable(thingytab);
 
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index cbc744601..8c976449e 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -3801,15 +3801,23 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 	/* Completion after `~', maketildelist adds the usernames *
 	 * and named directories.                                 */
-	if (ic == Tilde)
+	if (ic == Tilde) {
+	    char *oi = ipre;
+
+	    ipre = (ipre ? dyncat("~", ipre) : "~");
 	    maketildelist();
-	else if (ic == Equals) {
+	    ipre = oi;
+	} else if (ic == Equals) {
 	    /* Completion after `=', get the command names from *
 	     * the cmdnamtab and aliases from aliastab.         */
+	    char *oi = ipre;
+
+	    ipre = (ipre ? dyncat("=", ipre) : "=");
 	    if (isset(HASHLISTALL))
 		cmdnamtab->filltable(cmdnamtab);
 	    dumphashtable(cmdnamtab, -7);
 	    dumphashtable(aliastab, -2);
+	    ipre = oi;
 	} else {
 	    /* Normal file completion... */
 	    if (ispattern & 1) {
@@ -4082,6 +4090,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	if ((list = getshfunc(cc->func)) != &dummy_list) {
 	    /* We have it, so build a argument list. */
 	    LinkList args = newlinklist();
+	    int osc = sfcontext;
 
 	    addlinknode(args, cc->func);
 
@@ -4099,8 +4108,10 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 	    /* This flag allows us to use read -l and -c. */
 	    incompctlfunc = 1;
+	    sfcontext = SFC_COMPLETE;
 	    /* Call the function. */
 	    doshfunc(cc->func, list, args, 0, 1);
+	    sfcontext = osc;
 	    incompctlfunc = 0;
 	    /* And get the result from the reply parameter. */
 	    if ((r = get_user_var("reply")))
@@ -4246,6 +4257,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 	    LinkList args = newlinklist();
 	    LinkNode ln;
 	    Cmatch m;
+	    int osc = sfcontext;
 
 	    addlinknode(args, cc->ylist);
 	    for (ln = firstnode(matches); ln; ln = nextnode(ln)) {
@@ -4263,7 +4275,9 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd)
 
 	    /* No harm in allowing read -l and -c here, too */
 	    incompctlfunc = 1;
+	    sfcontext = SFC_COMPLETE;
 	    doshfunc(cc->ylist, list, args, 0, 1);
+	    sfcontext = osc;
 	    incompctlfunc = 0;
 	    uv = "reply";
 	}
diff --git a/Src/builtin.c b/Src/builtin.c
index 7e77bc190..6c41ce2fd 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -992,9 +992,13 @@ cd_new_pwd(int func, LinkNode dir, int chaselinks)
 
     /* execute the chpwd function */
     if ((l = getshfunc("chpwd")) != &dummy_list) {
+	int osc = sfcontext;
+
 	fflush(stdout);
 	fflush(stderr);
+	sfcontext = SFC_HOOK;
 	doshfunc("chpwd", l, NULL, 0, 1);
+	sfcontext = osc;
     }
 
     dirstacksize = getiparam("DIRSTACKSIZE");
@@ -1469,7 +1473,7 @@ bin_typeset(char *name, char **argv, char *ops, int func)
     Param pm;
     Asgment asg;
     Comp com;
-    char *optstr = "aiLRZlurtxU----A";
+    char *optstr = "aiALRZlurtxU";
     int on = 0, off = 0, roff, bit = PM_ARRAY;
     int initon, initoff, of, i;
     int returnval = 0, printflags = 0;
diff --git a/Src/cond.c b/Src/cond.c
index ed91f72f3..906e81938 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -48,7 +48,8 @@ evalcond(Cond c)
 	{
 	    Conddef cd;
 
-	    if ((cd = getconddef((c->type == COND_MODI), (char *) c->left, 1))) {
+	    if ((cd = getconddef((c->type == COND_MODI),
+				 ((char *) c->left) + 1, 1))) {
 		if (c->type == COND_MOD) {
 		    int l = arrlen((char **) c->right);
 
@@ -57,10 +58,24 @@ evalcond(Cond c)
 			return 0;
 		    }
 		}
-		return cd->handler(cd, (char **) c->right);
+		return cd->handler((char **) c->right, cd->condid);
+	    }
+	    else {
+		char **a = (char **) c->right, *s = a[0];
+
+		if (s && s[0] == '-' &&
+		    (cd = getconddef(0, s + 1, 1))) {
+		    int l = arrlen(a);
+
+		    if (l < cd->min || (cd->max >= 0 && l > cd->max)) {
+			zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
+			return 0;
+		    }
+		    a[0] = (char *) c->left;
+		    return cd->handler(a, cd->condid);
+		} else
+		    zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
 	    }
-	    else
-		zerr("unrecognized condition: `-%s'", (char *) c->left, 0);
 	    return 0;
 	}
     }
@@ -244,3 +259,38 @@ optison(char *s)
     else
 	return isset(i);
 }
+
+/**/
+char *
+cond_str(char **args, int num)
+{
+    char *s = args[num];
+
+    singsub(&s);
+    untokenize(s);
+
+    return s;
+}
+
+/**/
+long
+cond_val(char **args, int num)
+{
+    char *s = args[num];
+
+    singsub(&s);
+    untokenize(s);
+
+    return matheval(s);
+}
+
+/**/
+int
+cond_match(char **args, int num, char *str)
+{
+    char *s = args[num];
+
+    singsub(&s);
+
+    return matchpat(str, s);
+}
diff --git a/Src/exec.c b/Src/exec.c
index a2d74a9f4..911559a02 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -113,7 +113,12 @@ pid_t cmdoutpid;
  
 /**/
 int cmdoutval;
- 
+
+/* The context in which a shell function is called, see SFC_* in zsh.h. */ 
+
+/**/
+int sfcontext;
+
 /* Stack to save some variables before executing a signal handler function */
 
 /**/
@@ -2771,19 +2776,14 @@ runshfunc(List list, FuncWrap wrap, char *name)
     char *ou;
 
     while (wrap) {
-	wrap->module->flags |= MOD_WRAPPER;
-	wrap->count++;
+	wrap->module->wrapper++;
 	cont = wrap->handler(list, wrap->next, name);
-	wrap->count--;
-	if (!wrap->count) {
-	    wrap->module->flags &= ~MOD_WRAPPER;
+	wrap->module->wrapper--;
 #ifdef DYNAMIC
-	    if (wrap->module->flags & MOD_UNLOAD) {
-		wrap->module->flags &= ~MOD_UNLOAD;
-		unload_module(wrap->module, NULL);
-	    }
+	if (!wrap->module->wrapper &&
+	    (wrap->module->flags & MOD_UNLOAD))
+	    unload_module(wrap->module, NULL);
 #endif
-	}
 	if (!cont)
 	    return;
 	wrap = wrap->next;
diff --git a/Src/glob.c b/Src/glob.c
index 194d535a4..9c1d08aa4 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -1947,7 +1947,7 @@ getmatch(char **sp, char *pat, int fl, int n, char *replstr)
 {
     Comp c;
     char *s = *sp, *t, *start, sav;
-    int i, j, l = strlen(*sp), matched;
+    int i, l = strlen(*sp), matched;
 
     MUSTUSEHEAP("getmatch");	/* presumably covered by prefork() test */
     repllist = NULL;
diff --git a/Src/init.c b/Src/init.c
index decc7617e..0c874eead 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -111,13 +111,17 @@ loop(int toplevel, int justonce)
 	    if (toplevel && (prelist = getshfunc("preexec")) != &dummy_list) {
 		Histent he = gethistent(curhist);
 		LinkList args;
+		int osc = sfcontext;
+
 		PERMALLOC {
 		    args = newlinklist();
 		    addlinknode(args, "preexec");
 		    if (he && he->text)
 			addlinknode(args, he->text);
 		} LASTALLOC;
+		sfcontext = SFC_HOOK;
 		doshfunc("preexec", prelist, args, 0, 1);
+		sfcontext = osc;
 		freelinklist(args, (FreeFunc) NULL);
 		errflag = 0;
 	    }
@@ -613,6 +617,7 @@ setupvals(void)
     breaks = loops = 0;
     lastmailcheck = time(NULL);
     locallevel = sourcelevel = 0;
+    sfcontext = SFC_DIRECT;
     trapreturn = 0;
     noerrexit = -1;
     nohistsave = 1;
diff --git a/Src/makepro.awk b/Src/makepro.awk
index b5d2f3dc4..86117fcc1 100644
--- a/Src/makepro.awk
+++ b/Src/makepro.awk
@@ -104,7 +104,7 @@ BEGIN {
 	gsub(/@!/, ",", dcltor)
 
 	# If this is a module boot/cleanup function, conditionally rename it.
-	if(" " dtype " " ~ / int / && dcltor ~ / *@\+(boot|cleanup)_[_0-9A-Za-z]+@- *_\(\( *Module +[_0-9A-Za-z]+ *\)\) */) {
+	if(" " dtype " " ~ / int / && dcltor ~ / *@\+(boot|cleanup|setup|finish)_[_0-9A-Za-z]+@- *_\(\( *Module +[_0-9A-Za-z]+ *\)\) */) {
 	    modtype = dnam
 	    sub(/_.*$/, "", modtype)
 	    output = output "# if defined(DYNAMIC_NAME_CLASH_OK) && defined(MODULE)\n"
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index 4a90ecd20..2f988ec8f 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -55,6 +55,6 @@ for bin_mod in $bin_mods; do
 		exit 1 ;;
 	esac
     done
-    echo "    mod.nam = \"$bin_mod\"; boot_$bin_mod(&mod);"
+    echo "    mod.nam = \"$bin_mod\"; setup_$bin_mod(&mod); boot_$bin_mod(&mod);"
     done_mods="$done_mods$bin_mod "
 done
diff --git a/Src/modentry.c b/Src/modentry.c
index 63c4b825d..f177e0a6a 100644
--- a/Src/modentry.c
+++ b/Src/modentry.c
@@ -1,15 +1,35 @@
 #include "zsh.mdh"
 
+int setup_ _((Module));
 int boot_ _((Module));
 int cleanup_ _((Module));
+int finish_ _((Module));
 int modentry _((int boot, Module m));
 
 /**/
 int
 modentry(int boot, Module m)
 {
-    if (boot)
+    switch (boot) {
+    case 0:
+	return setup_(m);
+	break;
+
+    case 1:
 	return boot_(m);
-    else
+	break;
+
+    case 2:
 	return cleanup_(m);
+	break;
+
+    case 3:
+	return finish_(m);
+	break;
+
+    default:
+	zerr("bad call to modentry", NULL, 0);
+	return 1;
+	break;
+    }
 }
diff --git a/Src/module.c b/Src/module.c
index 8ed4f1d3b..5780eb134 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -36,6 +36,13 @@
 
 /**/
 int
+setup_zsh(Module m)
+{
+    return 0;
+}
+
+/**/
+int
 boot_zsh(Module m)
 {
     return 0;
@@ -114,7 +121,6 @@ addwrapper(Module m, FuncWrap w)
     w->next = NULL;
     w->flags |= WRAPF_ADDED;
     w->module = m;
-    w->count = 0;
 
     return 0;
 }
@@ -256,24 +262,58 @@ load_and_bind(const char *fn)
 #ifdef HAVE_DLFCN_H
 # include <dlfcn.h>
 #else
-# include <sys/types.h>
-# include <nlist.h>
-# include <link.h>
+# ifdef HAVE_DL_H
+#  include <dl.h>
+#  define RTLD_LAZY BIND_DEFERRED
+#  define RTLD_GLOBAL DYNAMIC_PATH
+# else
+#  include <sys/types.h>
+#  include <nlist.h>
+#  include <link.h>
+# endif
 #endif
-#ifndef HAVE_DLCLOSE
-# define dlclose(X) ((X), 0)
+
+#ifdef HPUXDYNAMIC
+# define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
+# define dlclose(handle) shl_unload((shl_t)(handle))
+
+/**/
+static
+void *
+hpux_dlsym(void *handle, char *name)
+{
+    void *sym_addr;
+    if (!shl_findsym((shl_t *)&handle, name, TYPE_UNDEFINED, &sym_addr))
+	return sym_addr;
+    return NULL;
+}
+
+# define dlsym(handle,name) hpux_dlsym(handle,name)
+# define dlerror() 0
+#else
+# ifndef HAVE_DLCLOSE
+#  define dlclose(X) ((X), 0)
+# endif
 #endif
 
 #ifdef DLSYM_NEEDS_UNDERSCORE
+# define STR_SETUP     "_setup_"
+# define STR_SETUP_S   "_setup_%s"
 # define STR_BOOT      "_boot_"
 # define STR_BOOT_S    "_boot_%s"
 # define STR_CLEANUP   "_cleanup_"
 # define STR_CLEANUP_S "_cleanup_%s"
+# define STR_FINISH    "_finish_"
+# define STR_FINISH_S  "_finish_%s"
 #else /* !DLSYM_NEEDS_UNDERSCORE */
+# define STR_SETUP     "setup_"
+# define STR_SETUP_S   "setup_%s"
 # define STR_BOOT      "boot_"
 # define STR_BOOT_S    "boot_%s"
 # define STR_CLEANUP   "cleanup_"
 # define STR_CLEANUP_S "cleanup_%s"
+# define STR_FINISH    "finish_"
+# define STR_FINISH_S  "finish_%s"
 #endif /* !DLSYM_NEEDS_UNDERSCORE */
 
 #endif /* !AIXDYNAMIC */
@@ -357,6 +397,13 @@ find_module(const char *name)
 
 /**/
 static int
+setup_module(Module m)
+{
+    return ((int (*)_((int,Module))) m->handle)(0, m);
+}
+
+/**/
+static int
 init_module(Module m)
 {
     return ((int (*)_((int,Module))) m->handle)(1, m);
@@ -366,14 +413,20 @@ init_module(Module m)
 static int
 cleanup_module(Module m)
 {
-    return ((int (*)_((int,Module))) m->handle)(0, m);
+    return ((int (*)_((int,Module))) m->handle)(2, m);
 }
 
-#else
-
 /**/
 static int
-init_module(Module m)
+finish_module(Module m)
+{
+    return ((int (*)_((int,Module))) m->handle)(3, m);
+}
+
+#else
+
+static Module_func
+module_func(Module m, char *name, char *name_s)
 {
     char *s, *t;
 #ifndef DYNAMIC_NAME_CLASH_OK
@@ -389,13 +442,34 @@ init_module(Module m)
     if ((t = strrchr(s, '.')))
 	*t = '\0';
 #ifdef DYNAMIC_NAME_CLASH_OK
-    fn = (Module_func) dlsym(m->handle, STR_BOOT);
+    fn = (Module_func) dlsym(m->handle, name);
 #else /* !DYNAMIC_NAME_CLASH_OK */
     if (strlen(s) + 6 > PATH_MAX)
-	return 1;
-    sprintf(buf, STR_BOOT_S, s);
+	return NULL;
+    sprintf(buf, name_s, s);
     fn = (Module_func) dlsym(m->handle, buf);
 #endif /* !DYNAMIC_NAME_CLASH_OK */
+    return fn;
+}
+
+/**/
+static int
+setup_module(Module m)
+{
+    Module_func fn = module_func(m, STR_SETUP, STR_SETUP_S);
+
+    if (fn)
+	return fn(m);
+    zwarnnam(m->nam, "no setup function", NULL, 0);
+    return 1;
+}
+
+/**/
+static int
+init_module(Module m)
+{
+    Module_func fn = module_func(m, STR_BOOT, STR_BOOT_S);
+
     if(fn)
 	return fn(m);
     zwarnnam(m->nam, "no boot function", NULL, 0);
@@ -406,33 +480,34 @@ init_module(Module m)
 static int
 cleanup_module(Module m)
 {
-    char *s, *t;
-#ifndef DYNAMIC_NAME_CLASH_OK
-    char buf[PATH_MAX + 1];
-#endif
-    Module_func fn;
+    Module_func fn = module_func(m, STR_CLEANUP, STR_CLEANUP_S);
 
-    s = strrchr(m->nam, '/');
-    if (s)
-	s = dupstring(++s);
-    else
-	s = m->nam;
-    if ((t = strrchr(s, '.')))
-	*t = '\0';
-#ifdef DYNAMIC_NAME_CLASH_OK
-    fn = (Module_func) dlsym(m->handle, STR_CLEANUP);
-#else /* !DYNAMIC_NAME_CLASH_OK */
-    if (strlen(s) + 9 > PATH_MAX)
-	return 1;
-    sprintf(buf, STR_CLEANUP_S, s);
-    fn = (Module_func) dlsym(m->handle, buf);
-#endif /* !DYNAMIC_NAME_CLASH_OK */
     if(fn)
 	return fn(m);
     zwarnnam(m->nam, "no cleanup function", NULL, 0);
     return 1;
 }
 
+/* Note that this function does more than just calling finish_foo(), *
+ * it really unloads the module. */
+
+/**/
+static int
+finish_module(Module m)
+{
+    Module_func fn = module_func(m, STR_FINISH, STR_FINISH_S);
+    int r;
+
+    if (fn)
+	r = fn(m);
+    else {
+	zwarnnam(m->nam, "no finish function", NULL, 0);
+	r = 1;
+    }
+    dlclose(m->handle);
+    return r;
+}
+
 #endif /* !AIXDYNAMIC */
 
 /**/
@@ -449,8 +524,8 @@ load_module(char const *name)
 	m = zcalloc(sizeof(*m));
 	m->nam = ztrdup(name);
 	m->handle = handle;
-	if (init_module(m)) {
-	    dlclose(handle);
+	if (setup_module(m) || init_module(m)) {
+	    finish_module(m);
 	    zsfree(m->nam);
 	    zfree(m, sizeof(*m));
 	    return NULL;
@@ -459,25 +534,35 @@ load_module(char const *name)
 	    addlinknode(modules, m);
 	} LASTALLOC;
 	return m;
-    }
+    } 
     m = (Module) getdata(node);
-    if (m->handle)
+    if (m->flags & MOD_UNLOAD)
+	m->flags &= ~MOD_UNLOAD;
+    else if (m->handle)
 	return m;
     if (m->flags & MOD_BUSY) {
 	zerr("circular dependencies for module %s", name, 0);
 	return NULL;
     }
     m->flags |= MOD_BUSY;
-    for (n = firstnode(m->deps); n; incnode(n))
-	if (!load_module((char *) getdata(n))) {
-	    m->flags &= ~MOD_BUSY;
+    if (m->deps)
+	for (n = firstnode(m->deps); n; incnode(n))
+	    if (!load_module((char *) getdata(n))) {
+		m->flags &= ~MOD_BUSY;
+		return NULL;
+	    }
+    m->flags &= ~MOD_BUSY;
+    if (!m->handle) {
+	if (!(m->handle = do_load_module(name)))
+	    return NULL;
+	if (setup_module(m)) {
+	    finish_module(m->handle);
+	    m->handle = NULL;
 	    return NULL;
 	}
-    m->flags &= ~MOD_BUSY;
-    if (!(m->handle = do_load_module(name)))
-	return NULL;
+    }
     if (init_module(m)) {
-	dlclose(m->handle);
+	finish_module(m->handle);
 	m->handle = NULL;
 	return NULL;
     }
@@ -756,12 +841,53 @@ bin_zmodload_cond(char *nam, char **args, char *ops)
 int
 unload_module(Module m, LinkNode node)
 {
-    if (m->handle && cleanup_module(m))
+    if (m->handle && !(m->flags & MOD_UNLOAD) && cleanup_module(m))
 	return 1;
     else {
+	int del = (m->flags & MOD_UNLOAD);
+
+	if (m->wrapper) {
+	    m->flags |= MOD_UNLOAD;
+	    return 0;
+	}
+	m->flags &= ~MOD_UNLOAD;
 	if (m->handle)
-	    dlclose(m->handle);
+	    finish_module(m);
 	m->handle = NULL;
+	if (del && m->deps) {
+	    /* The module was unloaded delayed, unload all modules *
+	     * on which it depended. */
+	    LinkNode n;
+
+	    for (n = firstnode(m->deps); n; incnode(n)) {
+		LinkNode dn = find_module((char *) getdata(n));
+		Module dm;
+
+		if (dn && (dm = (Module) getdata(dn)) &&
+		    (dm->flags & MOD_UNLOAD)) {
+		    /* See if this is the only module depending on it. */
+
+		    LinkNode an;
+		    Module am;
+		    int du = 1;
+
+		    for (an = firstnode(modules); du && an; incnode(an)) {
+			am = (Module) getdata(an);
+			if (am != m && am->handle && am->deps) {
+			    LinkNode sn;
+
+			    for (sn = firstnode(am->deps); du && sn;
+				 incnode(sn)) {
+				if (!strcmp((char *) getdata(sn), dm->nam))
+				    du = 0;
+			    }
+			}
+		    }
+		    if (du)
+			unload_module(dm, NULL);
+		}
+	    }
+	}
 	if(!m->deps) {
 	    if (!node) {
 		for (node = firstnode(modules); node; incnode(node))
@@ -791,24 +917,29 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 	    node = find_module(*args);
 	    if (node) {
 		LinkNode mn, dn;
+		int del = 0;
 
 		for (mn = firstnode(modules); mn; incnode(mn)) {
 		    m = (Module) getdata(mn);
 		    if (m->deps && m->handle)
 			for (dn = firstnode(m->deps); dn; incnode(dn))
 			    if (!strcmp((char *) getdata(dn), *args)) {
-				zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", *args, 0);
-				ret = 1;
-				goto cont;
+				if (m->flags & MOD_UNLOAD)
+				    del = 1;
+				else {
+				    zwarnnam(nam, "module %s is in use by another module and cannot be unloaded", *args, 0);
+				    ret = 1;
+				    goto cont;
+				}
 			    }
 		}
 		m = (Module) getdata(node);
-		if (!(m->flags & MOD_WRAPPER)) {
-		    if (unload_module(m, node))
-			ret = 1;
-		}
-		else
-		    m->flags |= MOD_UNLOAD;
+		if (del)
+		    m->wrapper++;
+		if (unload_module(m, node))
+		    ret = 1;
+		if (del)
+		    m->wrapper--;
 	    } else if (!ops['i']) {
 		zwarnnam(nam, "no such module %s", *args, 0);
 		ret = 1;
@@ -820,7 +951,7 @@ bin_zmodload_load(char *nam, char **args, char *ops)
 	/* list modules */
 	for (node = firstnode(modules); node; incnode(node)) {
 	    m = (Module) getdata(node);
-	    if (m->handle) {
+	    if (m->handle && !(m->flags & MOD_UNLOAD)) {
 		if(ops['L']) {
 		    printf("zmodload ");
 		    if(m->nam[0] == '-')
@@ -835,8 +966,11 @@ bin_zmodload_load(char *nam, char **args, char *ops)
     } else {
 	/* load modules */
 	for (; *args; args++) {
+	    Module m;
+
 	    node = find_module(*args);
-	    if (node && ((Module) getdata(node))->handle) {
+	    if (node && (m = ((Module) getdata(node)))->handle &&
+		!(m->flags & MOD_UNLOAD)) {
 		if (!ops['i']) {
 		    zwarnnam(nam, "module %s already loaded.", *args, 0);
 		    ret = 1;
@@ -894,8 +1028,6 @@ getconddef(int inf, char *name, int autol)
     return p;
 }
 
-#ifdef DYNAMIC
-
 /* This adds the given condition definition. The return value is zero on *
  * success and 1 on failure. If there is a matching definition for an    *
  * autoloaded condition, it is removed. */
@@ -909,10 +1041,11 @@ addconddef(Conddef c)
     if (p) {
 	if (!p->module || (p->flags & CONDF_ADDED))
 	    return 1;
-
+#ifdef DYNAMIC
 	/* There is an autoload definition. */
 
 	deleteconddef(p);
+#endif
     }
     c->next = condtab;
     condtab = c;
@@ -942,6 +1075,8 @@ addconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
+#ifdef DYNAMIC
+
 /* This adds a definition for autoloading a module for a condition. */
 
 /**/
@@ -1014,4 +1149,4 @@ deleteconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
-#endif /* DYNAMIC */
+#endif
diff --git a/Src/params.c b/Src/params.c
index 54699476c..89a1ed6a1 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -301,14 +301,6 @@ copyparamtable(HashTable ht, char *name)
     return nht;
 }
 
-#define SCANPM_WANTVALS   (1<<0)
-#define SCANPM_WANTKEYS   (1<<1)
-#define SCANPM_WANTINDEX  (1<<2)	/* Useful only if nested arrays */
-#define SCANPM_MATCHKEY   (1<<3)
-#define SCANPM_MATCHVAL   (1<<4)
-#define SCANPM_MATCHMANY  (1<<5)
-#define SCANPM_ISVAR_AT   ((-1)<<15)	/* Only sign bit is significant */
-
 static unsigned numparamvals;
 
 /**/
@@ -641,6 +633,7 @@ isident(char *s)
 	if (!iident(*ss))
 	    break;
 
+#if 0
     /* If this exhaust `s' or the next two characters *
      * are [(, then it is a valid identifier.         */
     if (!*ss || (*ss == '[' && ss[1] == '('))
@@ -650,6 +643,7 @@ isident(char *s)
      * definitely not a valid identifier.              */
     if (*ss != '[')
 	return 0;
+
     noeval = 1;
     (void)mathevalarg(++ss, &ss);
     if (*ss == ',')
@@ -658,6 +652,19 @@ isident(char *s)
     if (*ss != ']' || ss[1])
 	return 0;
     return 1;
+#else
+    /* If the next character is not [, then it is *
+     * definitely not a valid identifier.              */
+    if (!*ss)
+	return 1;
+    if (*ss != '[')
+	return 0;
+
+    /* Require balanced [ ] pairs */
+    if (skipparens('[', ']', &ss))
+	return 0;
+    return !*ss;
+#endif
 }
 
 static char **garr;
@@ -755,6 +762,8 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 	if (ind) {
 	    v->isarr |= SCANPM_WANTKEYS;
 	    v->isarr &= ~SCANPM_WANTVALS;
+	} else if (rev) {
+	    v->isarr |= SCANPM_WANTVALS;
 	}
 	if (!down)
 	    v->isarr &= ~SCANPM_MATCHMANY;
@@ -788,8 +797,9 @@ getarg(char **str, int *inv, Value v, int a2, long *w)
 		v->pm = createparam(s, PM_SCALAR|PM_UNSET);
 		paramtab = tht;
 	    }
-	    v->isarr = 0;
+	    v->isarr = (*inv ? SCANPM_WANTINDEX : 0);
 	    v->a = 0;
+	    *inv = 0;	/* We've already obtained the "index" (key) */
 	    *w = v->b = -1;
 	    r = isset(KSHARRAYS) ? 1 : 0;
 	} else
@@ -979,9 +989,11 @@ getindex(char **pptr, Value v)
 	    }
 	    if (a > 0 && (isset(KSHARRAYS) || (v->pm->flags & PM_HASHED)))
 		a--;
-	    v->inv = 1;
-	    v->isarr = 0;
-	    v->a = v->b = a;
+	    if (v->isarr != SCANPM_WANTINDEX) {
+		v->inv = 1;
+		v->isarr = 0;
+		v->a = v->b = a;
+	    }
 	    if (*s == ',') {
 		zerr("invalid subscript", NULL, 0);
 		while (*s != ']' && *s != Outbrack)
@@ -1546,35 +1558,37 @@ setaparam(char *s, char **val)
 
 /**/
 Param
-sethparam(char *s, char **kvarr)
+sethparam(char *s, char **val)
 {
     Value v;
-    Param pm;
-    char *t;
+    char *t = s;
 
     if (!isident(s)) {
 	zerr("not an identifier: %s", s, 0);
-	freearray(kvarr);
+	freearray(val);
+	errflag = 1;
+	return NULL;
+    }
+    if (strchr(s, '[')) {
+	freearray(val);
+	zerr("attempt to set slice of associative array", NULL, 0);
 	errflag = 1;
 	return NULL;
+    } else {
+	if (!(v = getvalue(&s, 1)))
+	    createparam(t, PM_HASHED);
+	else if (!(PM_TYPE(v->pm->flags) & (PM_ARRAY|PM_HASHED)) &&
+		 !(v->pm->flags & PM_SPECIAL)) {
+	    unsetparam(t);
+	    createparam(t, PM_HASHED);
+	    v = NULL;
+	}
     }
-    t=ztrdup(s); /* Is this a memory leak? */
-    /* Why does getvalue(s, 1) set s to empty string? */
-    if ((v = getvalue(&t, 1)))
-	if (v->pm->flags & PM_SPECIAL) {
-	    zerr("not overriding a special: %s", s, 0);
-	    freearray(kvarr);
-	    errflag = 1;
+    if (!v)
+	if (!(v = getvalue(&t, 1)))
 	    return NULL;
-	} else
-	    unsetparam(s);
-
-    pm = createparam(s, PM_HASHED);
-    DPUTS(!pm, "BUG: parameter not created");
-
-    arrhashsetfn(pm, kvarr);
-
-    return pm;
+    setarrvalue(v, val);
+    return v->pm;
 }
 
 /**/
diff --git a/Src/parse.c b/Src/parse.c
index 9024a834e..eb8398b1a 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -1339,7 +1339,7 @@ par_cond_double(char *a, char *b)
 
 	n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
 	n->type = COND_MOD;
-	n->left = (void *) (a + 1);
+	n->left = (void *) a;
 	d[0] = b;
 	d[1] = NULL;
 	n->right = (void *) arrdup(d);
@@ -1386,7 +1386,7 @@ par_cond_triple(char *a, char *b, char *c)
 
 	    n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
 	    n->type = COND_MODI;
-	    n->left = (void *) (b + 1);
+	    n->left = (void *) b;
 	    d[0] = a;
 	    d[1] = c;
 	    d[2] = NULL;
@@ -1397,7 +1397,7 @@ par_cond_triple(char *a, char *b, char *c)
 
 	n->ntype = NT_SET(N_COND, NT_STR, NT_STR | NT_ARR, 0, 0);
 	n->type = COND_MOD;
-	n->left = (void *) (a + 1);
+	n->left = (void *) a;
 	d[0] = b;
 	d[1] = c;
 	d[2] = NULL;
diff --git a/Src/signals.c b/Src/signals.c
index e637a8ca9..65bac0f52 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -703,6 +703,8 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
     execsave();
     breaks = 0;
     if (*sigtr & ZSIG_FUNC) {
+	int osc = sfcontext;
+
 	PERMALLOC {
 	    args = newlinklist();
 	    name = (char *) zalloc(5 + strlen(sigs[sig]));
@@ -712,7 +714,9 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
 	    addlinknode(args, num);
 	} LASTALLOC;
 	trapreturn = -1;
+	sfcontext = SFC_SIGNAL;
 	doshfunc(name, sigfn, args, 0, 1);
+	sfcontext = osc;
 	freelinklist(args, (FreeFunc) NULL);
 	zsfree(name);
     } else HEAPALLOC {
diff --git a/Src/subst.c b/Src/subst.c
index 77f0249e2..cc7e87d3d 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -720,8 +720,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
     int eval = 0;
     int nojoin = 0;
     char inbrace = 0;		/* != 0 means ${...}, otherwise $... */
-    char hkeys = 0;		/* 1 means get keys from associative array */
-    char hvals = 0;		/* > hkeys get values of associative array */
+    char hkeys = 0;
+    char hvals = 0;
 
     *s++ = '\0';
     if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' &&
@@ -739,7 +739,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	inbrace = 1;
 	s++;
 	if (*s == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) {
-	    hkeys = 1;
+	    hkeys = SCANPM_WANTKEYS;
 	    s++;
 	} else if (*s == '(' || *s == Inpar) {
 	    char *t, sav;
@@ -762,7 +762,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		case Outpar:
 		    break;
 		case 'A':
-		    arrasg = 1;
+		    ++arrasg;
 		    break;
 		case '@':
 		    nojoin = 1;
@@ -897,10 +897,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 		    break;
 
 		case 'k':
-		    hkeys = 1;
+		    hkeys = SCANPM_WANTKEYS;
 		    break;
 		case 'v':
-		    hvals = 2;
+		    hvals = SCANPM_WANTVALS;
 		    break;
 
 		default:
@@ -979,9 +979,8 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	*s = sav;
 	v = (Value) NULL;
     } else {
-	/* 2 == SCANPM_WANTKEYS, 1 == SCANPM_WANTVALS, see params.c */
 	if (!(v = fetchvalue(&s, (unset(KSHARRAYS) || inbrace) ? 1 : -1,
-			     (hkeys ? 2 : 0) + ((hvals > hkeys) ? 1 : 0))))
+			     hkeys|hvals)))
 	    vunset = 1;
     }
     while (v || ((inbrace || (unset(KSHARRAYS) && vunset)) && isbrack(*s))) {
@@ -1010,7 +1009,11 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 	if ((isarr = v->isarr)) {
 	    /* No way to get here with v->inv != 0, so getvaluearr() *
 	     * is called by getarrvalue(); needn't test PM_HASHED.   */
-	    aval = getarrvalue(v);
+	    if (v->isarr == SCANPM_WANTINDEX) {
+		isarr = v->isarr = 0;
+		val = dupstring(v->pm->nam);
+	    } else
+		aval = getarrvalue(v);
 	} else {
 	    if (v->pm->flags & PM_ARRAY) {
 		int tmplen = arrlen(v->pm->gets.afn(v->pm));
@@ -1260,7 +1263,12 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub)
 			*p++ = ztrdup(*t++);
 		    }
 		    *p++ = NULL;
-		    setaparam(idbeg, a);
+		    if (arrasg > 1) {
+			Param pm = sethparam(idbeg, a);
+			if (pm)
+			    aval = paramvalarr(pm->gets.hfn(pm), hkeys|hvals);
+		    } else
+			setaparam(idbeg, a);
 		} else {
 		    untokenize(val);
 		    setsparam(idbeg, ztrdup(val));
diff --git a/Src/utils.c b/Src/utils.c
index af0247ebf..90da15368 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -427,7 +427,7 @@ get_username(void)
 	    cached_username = ztrdup("");
     }
 #else /* !HAVE_GETPWUID */
-    cached_uid = current_uid;
+    cached_uid = getuid();
 #endif /* !HAVE_GETPWUID */
     return cached_username;
 }
@@ -510,16 +510,13 @@ adduserdir(char *s, char *t, int flags, int always)
     if ((flags & ND_USERNAME) && nameddirtab->getnode2(nameddirtab, s))
 	return;
 
-    /* Never hash PWD unless it was explicitly requested */
-    if (!always && !strcmp(s, "PWD"))
-	return;
-
     /* Normal parameter assignments generate calls to this function, *
      * with always==0.  Unless the AUTO_NAME_DIRS option is set, we  *
      * don't let such assignments actually create directory names.   *
      * Instead, a reference to the parameter as a directory name can *
-     * cause the actual creation of the hash table entry.            */
-    if (!always && unset(AUTONAMEDIRS) &&
+     * cause the actual creation of the hash table entry. Never hash *
+     * PWD unless it was explicitly requested (or already hashed).   */
+    if (!always && (unset(AUTONAMEDIRS) || !strcmp(s, "PWD")) &&
 	    !nameddirtab->getnode2(nameddirtab, s))
 	return;
 
@@ -633,8 +630,13 @@ preprompt(void)
 
     /* If a shell function named "precmd" exists, *
      * then execute it.                           */
-    if ((list = getshfunc("precmd")) != &dummy_list)
+    if ((list = getshfunc("precmd")) != &dummy_list) {
+	int osc = sfcontext;
+
+	sfcontext = SFC_HOOK;
 	doshfunc("precmd", list, NULL, 0, 1);
+	sfcontext = osc;
+    }
     if (errflag)
 	return;
 
@@ -643,7 +645,11 @@ preprompt(void)
      * executed "periodic", then execute it now.                    */
     if (period && (time(NULL) > lastperiodic + period) &&
 	(list = getshfunc("periodic")) != &dummy_list) {
+	int osc = sfcontext;
+
+	sfcontext = SFC_HOOK;
 	doshfunc("periodic", list, NULL, 0, 1);
+	sfcontext = osc;
 	lastperiodic = time(NULL);
     }
     if (errflag)
diff --git a/Src/zsh.export b/Src/zsh.export
index c51699269..d8b0ddf19 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -23,6 +23,8 @@ closem
 cmdnamtab
 columns
 compctlreadptr
+cond_str
+cond_val
 coprocin
 coprocout
 countlinknodes
@@ -173,6 +175,7 @@ sethparam
 setlimits
 setsparam
 settyinfo
+sfcontext
 shfunctab
 shingetline
 shout
diff --git a/Src/zsh.h b/Src/zsh.h
index 6a962d8bf..a31a7469b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -460,23 +460,24 @@ struct cond {
 #define COND_MOD   16
 #define COND_MODI  17
 
-typedef int (*CondHandler) _((Conddef, char **));
+typedef int (*CondHandler) _((char **, int));
 
 struct conddef {
     Conddef next;		/* next in list                       */
     char *name;			/* the condition name                 */
     int flags;			/* see CONDF_* below                  */
+    CondHandler handler;	/* handler function                   */
     int min;			/* minimum number of strings          */
     int max;			/* maximum number of strings          */
-    CondHandler handler;	/* handler function                   */
+    int condid;			/* for overloading handler functions  */
     char *module;		/* module to autoload                 */
 };
 
 #define CONDF_INFIX  1
 #define CONDF_ADDED  2
 
-#define CONDDEF(name, flags, min, max, handler) \
-    { NULL, name, flags, min, max, handler, NULL }
+#define CONDDEF(name, flags, handler, min, max, condid) \
+    { NULL, name, flags, handler, min, max, condid, NULL }
 
 struct forcmd {			/* for/select */
 /* Cmd->args contains list of words to loop thru */
@@ -772,6 +773,14 @@ struct shfunc {
     List funcdef;		/* function definition    */
 };
 
+/* Shell function context types. */
+
+#define SFC_DIRECT   0		/* called directly from the user */
+#define SFC_SIGNAL   1		/* signal handler */
+#define SFC_HOOK     2		/* one of the special functions */
+#define SFC_WIDGET   3		/* user defined widget */
+#define SFC_COMPLETE 4		/* called from completion code */
+
 /* node in list of function call wrappers */
 
 typedef int (*WrapFunc) _((List, FuncWrap, char *));
@@ -781,13 +790,12 @@ struct funcwrap {
     int flags;
     WrapFunc handler;
     Module module;
-    int count;
 };
 
 #define WRAPF_ADDED 1
 
 #define WRAPDEF(func) \
-    { NULL, 0, func, NULL, 0 }
+    { NULL, 0, func, NULL }
 
 /* node in builtin command hash table (builtintab) */
 
@@ -836,11 +844,11 @@ struct module {
     int flags;
     void *handle;
     LinkList deps;
+    int wrapper;
 };
 
 #define MOD_BUSY    (1<<0)
-#define MOD_WRAPPER (1<<1)
-#define MOD_UNLOAD  (1<<2)
+#define MOD_UNLOAD  (1<<1)
 
 /* node used in parameter hash table (paramtab) */
 
@@ -890,28 +898,37 @@ struct param {
 #define PM_SCALAR	0	/* scalar                                     */
 #define PM_ARRAY	(1<<0)	/* array                                      */
 #define PM_INTEGER	(1<<1)	/* integer                                    */
-#define PM_HASHED	(1<<15)	/* association                                */
+#define PM_HASHED	(1<<2)	/* association                                */
 
 #define PM_TYPE(X) (X & (PM_SCALAR|PM_INTEGER|PM_ARRAY|PM_HASHED))
 
-#define PM_LEFT		(1<<2)	/* left justify and remove leading blanks     */
-#define PM_RIGHT_B	(1<<3)	/* right justify and fill with leading blanks */
-#define PM_RIGHT_Z	(1<<4)	/* right justify and fill with leading zeros  */
-#define PM_LOWER	(1<<5)	/* all lower case                             */
+#define PM_LEFT		(1<<3)	/* left justify and remove leading blanks     */
+#define PM_RIGHT_B	(1<<4)	/* right justify and fill with leading blanks */
+#define PM_RIGHT_Z	(1<<5)	/* right justify and fill with leading zeros  */
+#define PM_LOWER	(1<<6)	/* all lower case                             */
 
 /* The following are the same since they *
  * both represent -u option to typeset   */
-#define PM_UPPER	(1<<6)	/* all upper case                             */
-#define PM_UNDEFINED	(1<<6)	/* undefined (autoloaded) shell function      */
-
-#define PM_READONLY	(1<<7)	/* readonly                                   */
-#define PM_TAGGED	(1<<8)	/* tagged                                     */
-#define PM_EXPORTED	(1<<9)	/* exported                                   */
-#define PM_UNIQUE	(1<<10)	/* remove duplicates                          */
-#define PM_SPECIAL	(1<<11) /* special builtin parameter                  */
-#define PM_DONTIMPORT	(1<<12)	/* do not import this variable                */
-#define PM_RESTRICTED	(1<<13) /* cannot be changed in restricted mode       */
-#define PM_UNSET	(1<<14)	/* has null value                             */
+#define PM_UPPER	(1<<7)	/* all upper case                             */
+#define PM_UNDEFINED	(1<<7)	/* undefined (autoloaded) shell function      */
+
+#define PM_READONLY	(1<<8)	/* readonly                                   */
+#define PM_TAGGED	(1<<9)	/* tagged                                     */
+#define PM_EXPORTED	(1<<10)	/* exported                                   */
+#define PM_UNIQUE	(1<<11)	/* remove duplicates                          */
+#define PM_SPECIAL	(1<<12) /* special builtin parameter                  */
+#define PM_DONTIMPORT	(1<<13)	/* do not import this variable                */
+#define PM_RESTRICTED	(1<<14) /* cannot be changed in restricted mode       */
+#define PM_UNSET	(1<<15)	/* has null value                             */
+
+/* Flags for extracting elements of arrays and associative arrays */
+#define SCANPM_WANTVALS   (1<<0)
+#define SCANPM_WANTKEYS   (1<<1)
+#define SCANPM_WANTINDEX  (1<<2)
+#define SCANPM_MATCHKEY   (1<<3)
+#define SCANPM_MATCHVAL   (1<<4)
+#define SCANPM_MATCHMANY  (1<<5)
+#define SCANPM_ISVAR_AT   ((-1)<<15)	/* Only sign bit is significant */
 
 /*
  * Flags for doing matches inside parameter substitutions, i.e.