about summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/example.c39
-rw-r--r--Src/Modules/example.mdd1
-rw-r--r--Src/Modules/zftp.c3
-rw-r--r--Src/Zle/comp.h30
-rw-r--r--Src/Zle/comp1.c8
-rw-r--r--Src/Zle/comp1.export1
-rw-r--r--Src/Zle/compctl.c86
-rw-r--r--Src/Zle/compctl.mdd2
-rw-r--r--Src/Zle/zle_main.c14
-rw-r--r--Src/Zle/zle_misc.c10
-rw-r--r--Src/Zle/zle_refresh.c17
-rw-r--r--Src/Zle/zle_tricky.c306
-rw-r--r--Src/builtin.c14
-rw-r--r--Src/glob.c8
-rw-r--r--Src/mkbltnmlst.sh5
-rw-r--r--Src/mkmakemod.sh3
-rw-r--r--Src/module.c160
-rw-r--r--Src/params.c42
-rw-r--r--Src/prompt.c19
-rw-r--r--Src/zsh.export2
-rw-r--r--Src/zsh.h24
21 files changed, 603 insertions, 191 deletions
diff --git a/Src/Modules/example.c b/Src/Modules/example.c
index 95545172f..50b8c1626 100644
--- a/Src/Modules/example.c
+++ b/Src/Modules/example.c
@@ -30,22 +30,45 @@
 #include "example.mdh"
 #include "example.pro"
 
+/* parameters */
+
+static long intparam;
+static char *strparam;
+static char **arrparam;
+
+
 /**/
 static int
 bin_example(char *nam, char **args, char *ops, int func)
 {
     unsigned char c;
+    char **oargs = args, **p = arrparam;
+    long i = 0;
 
     printf("Options: ");
     for (c = 32; ++c < 128;)
 	if (ops[c])
 	    putchar(c);
     printf("\nArguments:");
-    for (; *args; args++) {
+    for (; *args; i++, args++) {
 	putchar(' ');
 	fputs(*args, stdout);
     }
     printf("\nName: %s\n", nam);
+    printf("\nInteger Parameter: %ld\n", intparam);
+    printf("String Parameter: %s\n", strparam ? strparam : "");
+    printf("Array Parameter:");
+    if (p)
+	while (*p) printf(" %s", *p++);
+    printf("\n");
+
+    intparam = i;
+    zsfree(strparam);
+    strparam = ztrdup(*oargs ? *oargs : "");
+    freearray(arrparam);
+    PERMALLOC {
+	arrparam = arrdup(oargs);
+    } LASTALLOC;
     return 0;
 }
 
@@ -103,6 +126,12 @@ static struct conddef cotab[] = {
     CONDDEF("ex", CONDF_INFIX, cond_i_ex, 0, 0, 0),
 };
 
+static struct paramdef patab[] = {
+    INTPARAMDEF("exint", &intparam),
+    STRPARAMDEF("exstr", &strparam),
+    ARRPARAMDEF("exarr", &arrparam),
+};
+
 static struct funcwrap wrapper[] = {
     WRAPDEF(ex_wrapper),
 };
@@ -120,8 +149,15 @@ setup_example(Module m)
 int
 boot_example(Module m)
 {
+    intparam = 42;
+    strparam = ztrdup("example");
+    arrparam = (char **) zalloc(3 * sizeof(char *));
+    arrparam[0] = ztrdup("example");
+    arrparam[1] = ztrdup("array");
+    arrparam[2] = NULL;
     return !(addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)) |
 	     addconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab)) |
+	     addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab)) |
 	     !addwrapper(m, wrapper));
 }
 
@@ -133,6 +169,7 @@ cleanup_example(Module m)
 {
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     deleteconddefs(m->nam, cotab, sizeof(cotab)/sizeof(*cotab));
+    deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
     deletewrapper(m, wrapper);
     return 0;
 }
diff --git a/Src/Modules/example.mdd b/Src/Modules/example.mdd
index f2cd50693..5ed55e6f1 100644
--- a/Src/Modules/example.mdd
+++ b/Src/Modules/example.mdd
@@ -2,5 +2,6 @@ autobins="example"
 
 autoinfixconds="ex"
 autoprefixconds="len"
+autoparams="exint exstr exarr"
 
 objects="example.o"
diff --git a/Src/Modules/zftp.c b/Src/Modules/zftp.c
index 126aa061e..651a5c952 100644
--- a/Src/Modules/zftp.c
+++ b/Src/Modules/zftp.c
@@ -71,6 +71,9 @@
 #ifdef HAVE_POLL_H
 # include <poll.h>
 #endif
+#if defined(HAVE_POLL) && !defined(POLLIN) && !defined(POLLNORM)
+# undef HAVE_POLL
+#endif
 
 /* pinch the definition from <netinet/in.h> for deficient headers */
 #ifndef INADDR_NONE
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index c9d6aa859..caeb4d6c3 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -270,6 +270,31 @@ struct cpattern {
 #define CAF_ALT      4
 #define CAF_MATCH    8
 
+/* Data for compadd and addmatches() */
+
+typedef struct cadata *Cadata;
+
+struct cadata {
+    char *ipre;			/* ignored prefix (-i) */
+    char *isuf;			/* ignored suffix (-I) */
+    char *ppre;			/* `path' prefix (-p) */
+    char *psuf;			/* `path' suffix (-s) */
+    char *prpre;		/* expanded `path' prefix (-W) */
+    char *pre;			/* prefix to insert (-P) */
+    char *suf;			/* suffix to insert (-S) */
+    char *group;		/* name of the group (-[JV]) */
+    char *rems;			/* remove suffix on chars... (-r) */
+    char *remf;			/* function to remove suffix (-R) */
+    char *ign;			/* ignored suffixes (-F) */
+    int flags;			/* CMF_* flags (-[fqn]) */
+    int aflags;			/* CAF_* flags (-[QUa]) */
+    Cmatcher match;		/* match spec (parsed from -M) */
+    char *exp;			/* explanation (-X) */
+    char *apar;			/* array to store matches in (-A) */
+    char *opar;			/* array to store originals in (-O) */
+    char *dpar;			/* array to delete non-matches in (-D) */
+};
+
 /* Flags for special parameters. */
 
 #define CP_WORDS      (1 <<  0)
@@ -306,7 +331,8 @@ struct cpattern {
 #define CP_TOEND      (1 << 28)
 #define CP_OLDLIST    (1 << 29)
 #define CP_OLDINS     (1 << 30)
+#define CP_VARED      (1 << 31)
 
-#define CP_NUM              31
+#define CP_NUM              32
 
-#define CP_ALLMASK    ((int) ((((unsigned int) 1) << CP_NUM) - 1))
+#define CP_ALLMASK    ((unsigned int) 0xffffffff)
diff --git a/Src/Zle/comp1.c b/Src/Zle/comp1.c
index fe21b1dfc..c51aad297 100644
--- a/Src/Zle/comp1.c
+++ b/Src/Zle/comp1.c
@@ -52,7 +52,7 @@ void (*comp_setunsetptr) _((int, int));
 /* pointers to functions required by compctl and defined by zle */
 
 /**/
-int (*addmatchesptr) _((char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, char *, int, int, Cmatcher, char *, char *, char *, char **));
+int (*addmatchesptr) _((Cadata, char **));
 
 /**/
 char *(*comp_strptr) _((int *, int *, int));
@@ -129,7 +129,8 @@ char **compwords,
      *complastprompt,
      *comptoend,
      *compoldlist,
-     *compoldins;
+     *compoldins,
+     *compvared;
 
 /**/
 Param *comppms;
@@ -445,7 +446,7 @@ setup_comp1(Module m)
 	compquoting = comprestore = complist = compinsert =
 	compexact = compexactstr = comppatmatch = comppatinsert =
 	compforcelist = complastprompt = comptoend = 
-	compoldlist = compoldins = NULL;
+	compoldlist = compoldins = compvared = NULL;
     makecompparamsptr = NULL;
     comp_setunsetptr = NULL;
     return 0;
@@ -497,6 +498,7 @@ finish_comp1(Module m)
     zsfree(comptoend);
     zsfree(compoldlist);
     zsfree(compoldins);
+    zsfree(compvared);
     return 0;
 }
 
diff --git a/Src/Zle/comp1.export b/Src/Zle/comp1.export
index 4f9fb143d..2dc285d3a 100644
--- a/Src/Zle/comp1.export
+++ b/Src/Zle/comp1.export
@@ -41,6 +41,7 @@ comp_setunsetptr
 comp_strptr
 compsuffix
 comptoend
+compvared
 compwords
 freecmatcher
 freecmlist
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 28c7cb7b7..a06d558e3 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -1691,17 +1691,22 @@ bin_compgen(char *name, char **argv, char *ops, int func)
 static int
 bin_compadd(char *name, char **argv, char *ops, int func)
 {
-    char *p, **sp, *e;
-    char *ipre = NULL, *isuf = NULL, *ppre = NULL, *psuf = NULL, *prpre = NULL;
-    char *pre = NULL, *suf = NULL, *group = NULL, *m = NULL, *rs = NULL;
-    char *ign = NULL, *rf = NULL, *expl = NULL, *apar = NULL, *opar = NULL;
-    int f = 0, a = CAF_MATCH, dm;
+    struct cadata dat;
+    char *p, **sp, *e, *m = NULL;
+    int dm;
     Cmatcher match = NULL;
 
     if (incompfunc != 1) {
 	zerrnam(name, "can only be called from completion function", NULL, 0);
 	return 1;
     }
+    dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre =
+	dat.pre = dat.suf = dat.group = dat.rems = dat.remf =
+	dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL;
+    dat.match = NULL;
+    dat.flags = 0;
+    dat.aflags = CAF_MATCH;
+
     for (; *argv && **argv ==  '-'; argv++) {
 	if (!(*argv)[1]) {
 	    argv++;
@@ -1713,64 +1718,64 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 	    dm = 0;
 	    switch (*p) {
 	    case 'q':
-		f |= CMF_REMOVE;
+		dat.flags |= CMF_REMOVE;
 		break;
 	    case 'Q':
-		a |= CAF_QUOTE;
+		dat.aflags |= CAF_QUOTE;
 		break;
 	    case 'f':
-		f |= CMF_FILE;
+		dat.flags |= CMF_FILE;
 		break;
 	    case 'F':
-		sp = &ign;
+		sp = &(dat.ign);
 		e = "string expected after -%c";
 		break;
 	    case 'n':
-		f |= CMF_NOLIST;
+		dat.flags |= CMF_NOLIST;
 		break;
 	    case 'U':
-		a &= ~CAF_MATCH;
+		dat.aflags &= ~CAF_MATCH;
 		break;
 	    case 'P':
-		sp = &pre;
+		sp = &(dat.pre);
 		e = "string expected after -%c";
 		break;
 	    case 'S':
-		sp = &suf;
+		sp = &(dat.suf);
 		e = "string expected after -%c";
 		break;
 	    case 'J':
-		sp = &group;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'V':
-		if (!group)
-		    a |= CAF_NOSORT;
-		sp = &group;
+		if (!dat.group)
+		    dat.aflags |= CAF_NOSORT;
+		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
 	    case 'i':
-		sp = &ipre;
+		sp = &(dat.ipre);
 		e = "string expected after -%c";
 		break;
 	    case 'I':
-		sp = &isuf;
+		sp = &(dat.isuf);
 		e = "string expected after -%c";
 		break;
 	    case 'p':
-		sp = &ppre;
+		sp = &(dat.ppre);
 		e = "string expected after -%c";
 		break;
 	    case 's':
-		sp = &psuf;
+		sp = &(dat.psuf);
 		e = "string expected after -%c";
 		break;
 	    case 'W':
-		sp = &prpre;
+		sp = &(dat.prpre);
 		e = "string expected after -%c";
 		break;
 	    case 'a':
-		a |= CAF_ALT;
+		dat.aflags |= CAF_ALT;
 		break;
 	    case 'M':
 		sp = &m;
@@ -1778,25 +1783,29 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		dm = 1;
 		break;
 	    case 'X':
-		sp = &expl;
+		sp = &(dat.exp);
 		e = "string expected after -%c";
 		break;
 	    case 'r':
-		f |= CMF_REMOVE;
-		sp = &rs;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.rems);
 		e = "string expected after -%c";
 		break;
 	    case 'R':
-		f |= CMF_REMOVE;
-		sp = &rf;
+		dat.flags |= CMF_REMOVE;
+		sp = &(dat.remf);
 		e = "function name expected after -%c";
 		break;
 	    case 'A':
-		sp = &apar;
+		sp = &(dat.apar);
 		e = "parameter name expected after -%c";
 		break;
 	    case 'O':
-		sp = &opar;
+		sp = &(dat.opar);
+		e = "parameter name expected after -%c";
+		break;
+	    case 'D':
+		sp = &(dat.dpar);
 		e = "parameter name expected after -%c";
 		break;
 	    case '-':
@@ -1830,12 +1839,11 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     if (!*argv)
 	return 1;
 
-    match = cpcmatcher(match);
-    a = addmatchesptr(ipre, isuf, ppre, psuf, prpre, pre, suf, group,
-		      rs, rf, ign, f, a, match, expl, apar, opar, argv);
+    dat.match = match = cpcmatcher(match);
+    dm = addmatchesptr(&dat, argv);
     freecmatcher(match);
 
-    return a;
+    return dm;
 }
 
 #define CVT_RANGENUM 0
@@ -2165,6 +2173,7 @@ static struct compparam {
     { "to_end", PM_SCALAR, VAL(comptoend), NULL, NULL },
     { "old_list", PM_SCALAR, VAL(compoldlist), NULL, NULL },
     { "old_insert", PM_SCALAR, VAL(compoldins), NULL, NULL },
+    { "vared", PM_SCALAR, VAL(compvared), NULL, NULL },
     { NULL, 0, NULL, NULL, NULL }
 };
 
@@ -2308,7 +2317,7 @@ compunsetfn(Param pm, int exp)
 
 /**/
 void
-comp_setunset(int set, int unset)
+comp_setunset(unsigned int set, unsigned int unset)
 {
     Param *p;
 
@@ -2334,11 +2343,11 @@ comp_wrapper(List list, FuncWrap w, char *name)
     else {
 	char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
 	long ocur;
-	int unset = 0, m, sm;
+	unsigned int unset = 0, m, sm;
 	Param *pp;
 
 	m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
-	    CP_IPREFIX | CP_RESTORE;
+	    CP_IPREFIX | CP_ISUFFIX | CP_RESTORE;
 	for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
 	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
 		unset |= sm;
@@ -2373,7 +2382,8 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	    } LASTALLOC;
 	    comp_setunset(CP_COMPSTATE |
 			  (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
-				     CP_SUFFIX | CP_IPREFIX | CP_RESTORE)),
+				     CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
+				     CP_RESTORE)),
 			  unset);
 	} else
 	    comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE),
diff --git a/Src/Zle/compctl.mdd b/Src/Zle/compctl.mdd
index 113eef27e..e7b2cfb68 100644
--- a/Src/Zle/compctl.mdd
+++ b/Src/Zle/compctl.mdd
@@ -1,6 +1,6 @@
 moddeps="comp1"
 
-autobins="compctl complist compadd compset"
+autobins="compctl compgen compadd compset"
 
 autoprefixconds="prefix suffix between after"
 
diff --git a/Src/Zle/zle_main.c b/Src/Zle/zle_main.c
index 4d9c99f87..a5da84b66 100644
--- a/Src/Zle/zle_main.c
+++ b/Src/Zle/zle_main.c
@@ -413,7 +413,6 @@ zleread(char *lp, char *rp, int flags)
 
     baud = getiparam("BAUD");
     costmult = (baud) ? 3840000L / baud : 0;
-    tv.tv_sec = 0;
 #endif
 
     /* ZLE doesn't currently work recursively.  This is needed in case a *
@@ -523,6 +522,7 @@ zleread(char *lp, char *rp, int flags)
 #ifdef HAVE_SELECT
 	    if (baud && !(lastcmd & ZLE_MENUCMP)) {
 		FD_SET(SHTTY, &foofd);
+		tv.tv_sec = 0;
 		if ((tv.tv_usec = cost * costmult) > 500000)
 		    tv.tv_usec = 500000;
 		if (!kungetct && select(SHTTY+1, (SELECT_ARG_2_T) & foofd,
@@ -656,14 +656,18 @@ handleprefixes(void)
 	initmodifier(&zmod);
 }
 
+/* this exports the argument we are currently vared'iting if != NULL */
+
+/**/
+char *varedarg;
+
 /* vared: edit (literally) a parameter value */
 
 /**/
 static int
 bin_vared(char *name, char **args, char *ops, int func)
 {
-    char *s;
-    char *t;
+    char *s, *t, *ova = varedarg;
     Value v;
     Param pm = 0;
     int create = 0;
@@ -753,7 +757,9 @@ bin_vared(char *name, char **args, char *ops, int func)
     PERMALLOC {
 	pushnode(bufstack, ztrdup(s));
     } LASTALLOC;
+    varedarg = *args;
     t = (char *) zleread(p1, p2, ops['h'] ? ZLRF_HISTORY : 0);
+    varedarg = ova;
     if (!t || errflag) {
 	/* error in editing */
 	errflag = 0;
@@ -927,6 +933,8 @@ setup_zle(Module m)
     /* initialise the keymap system */
     init_keymaps();
 
+    varedarg = NULL;
+
     return 0;
 }
 
diff --git a/Src/Zle/zle_misc.c b/Src/Zle/zle_misc.c
index e7f1744d5..30c31c358 100644
--- a/Src/Zle/zle_misc.c
+++ b/Src/Zle/zle_misc.c
@@ -611,7 +611,7 @@ Thingy
 executenamedcommand(char *prmt)
 {
     Thingy cmd;
-    int len, l = strlen(prmt);
+    int len, l = strlen(prmt), ols = listshown;
     char *ptr;
     char *okeymap = curkeymapname;
 
@@ -629,6 +629,10 @@ executenamedcommand(char *prmt)
 	if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) {
 	    statusline = NULL;
 	    selectkeymap(okeymap, 1);
+	    if ((listshown = ols))
+		showinglist = -2;
+	    else
+		clearlist = 1;
 	    return NULL;
 	}
 	if(cmd == Th(z_clearscreen)) {
@@ -669,6 +673,10 @@ executenamedcommand(char *prmt)
 		    unrefthingy(r);
 		    statusline = NULL;
 		    selectkeymap(okeymap, 1);
+		    if ((listshown = ols))
+			showinglist = -2;
+		    else
+			clearlist = 1;
 		    return r;
 		}
 		unrefthingy(r);
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 6b0239961..2377b70fa 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -96,6 +96,7 @@ static int more_start,		/* more text before start of screen?	    */
     olnct,			/* previous number of lines		    */
     ovln,			/* previous video cursor position line	    */
     lpromptw, rpromptw,		/* prompt widths on screen                  */
+    lpromptwof,			/* left prompt width with real end position */
     lprompth,			/* lines taken up by the prompt		    */
     rprompth,			/* right prompt height                      */
     vcs, vln,			/* video cursor position column & line	    */
@@ -141,8 +142,14 @@ resetvideo(void)
 	    *obuf[ln] = '\0';
     }
 
-    countprompt(lpromptbuf, &lpromptw, &lprompth);
-    countprompt(rpromptbuf, &rpromptw, &rprompth);
+    countprompt(lpromptbuf, &lpromptwof, &lprompth, 1);
+    countprompt(rpromptbuf, &rpromptw, &rprompth, 0);
+    if (lpromptwof != winw)
+	lpromptw = lpromptwof;
+    else {
+	lpromptw = 0;
+	lprompth++;
+    }
 
     if (lpromptw) {
     	memset(nbuf[0], ' ', lpromptw);
@@ -271,7 +278,7 @@ zrefresh(void)
 	    clearflag = 0;
 	    resetneeded = 1;
 	}
-	listshown = 0;
+	listshown = showinglist = 0;
     }
     clearlist = 0;
 
@@ -327,7 +334,7 @@ zrefresh(void)
             vcs = 0;
         else if (!clearflag && lpromptbuf[0]) {
             zputs(lpromptbuf, shout);
-	    if (lpromptw == 0 && lprompth == 1)
+	    if (lpromptwof == winw)
 		zputs("\n", shout);	/* works with both hasam and !hasam */
 	}
 	if (clearflag) {
@@ -947,7 +954,7 @@ tc_rightcurs(int cl)
 		zputc('\r', shout);
 	    tc_upcurs(lprompth - 1);
 	    zputs(lpromptbuf, shout);
-	    if (lpromptw == 0 && lprompth == 1)
+	    if (lpromptwof == winw)
 		zputs("\n", shout);	/* works with both hasam and !hasam */
 	}
 	i = lpromptw;
diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c
index 92b167cfe..8db571d0b 100644
--- a/Src/Zle/zle_tricky.c
+++ b/Src/Zle/zle_tricky.c
@@ -87,6 +87,10 @@ static int usemenu, useglob, useexact, useline, uselist;
 
 static int oldlist, oldins;
 
+/* Non-zero if we have to redisplay the list of matches. */
+
+static int showagain = 0;
+
 /* The match and group number to insert when starting menucompletion.   */
 
 static int insmnum, insgnum, insgroup;
@@ -555,7 +559,7 @@ acceptandmenucomplete(void)
 /* These are flags saying if we are completing in the command *
  * position, in a redirection, or in a parameter expansion.   */
 
-static int lincmd, linredir, ispar, linwhat;
+static int lincmd, linredir, ispar, linwhat, linarr;
 
 /* The string for the redirection operator. */
 
@@ -758,10 +762,14 @@ docomplete(int lst)
     char *s, *ol;
     int olst = lst, chl = 0, ne = noerrs, ocs;
 
+    if (showagain && validlist)
+	showinglist = -2;
+    showagain = 0;
+
     /* If we are doing a menu-completion... */
 
-    if (menucmp && lst != COMP_LIST_EXPAND && compwidget &&
-	compwidget == lastcompwidget) {
+    if (menucmp && lst != COMP_LIST_EXPAND && 
+	(!compwidget || compwidget == lastcompwidget)) {
 	do_menucmp(lst);
 	return;
     }
@@ -872,7 +880,7 @@ docomplete(int lst)
 	    }
 	    if (lst == COMP_EXPAND_COMPLETE)
 		do {
-		    /* check if there is a parameter expresiion. */
+		    /* Check if there is a parameter expression. */
 		    for (; *q && *q != String; q++);
 		    if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
 			if (*++q == Inbrace) {
@@ -1128,7 +1136,7 @@ unmetafy_line(void)
 static char *
 get_comp_string(void)
 {
-    int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, inarr, ia, parct;
+    int t0, tt0, i, j, k, cp, rd, sl, ocs, ins, oins, ia, parct;
     char *s = NULL, *linptr, *tmp, *p, *tt = NULL;
 
     zsfree(brbeg);
@@ -1192,7 +1200,7 @@ get_comp_string(void)
 	inpush(dupstrspace((char *) linptr), 0, NULL);
 	strinbeg();
 	stophist = 2;
-	i = tt0 = cp = rd = ins = oins = inarr = parct = ia = 0;
+	i = tt0 = cp = rd = ins = oins = linarr = parct = ia = 0;
 
 	/* This loop is possibly the wrong way to do this.  It goes through *
 	 * the previously massaged command line using the lexer.  It stores *
@@ -1211,11 +1219,11 @@ get_comp_string(void)
 	    linredir = (inredir && !ins);
 	    oins = ins;
 	    /* Get the next token. */
-	    if (inarr)
+	    if (linarr)
 		incmdpos = 0;
 	    ctxtlex();
 	    if (tok == ENVARRAY) {
-		inarr = 1;
+		linarr = 1;
 		zsfree(varname);
 		varname = ztrdup(tokstr);
 	    } else if (tok == INPAR)
@@ -1224,7 +1232,7 @@ get_comp_string(void)
 		if (parct)
 		    parct--;
 		else
-		    inarr = 0;
+		    linarr = 0;
 	    }
 	    if (inredir)
 		rdstr = tokstrings[tok];
@@ -1267,7 +1275,7 @@ get_comp_string(void)
 		clwpos = i;
 		cp = lincmd;
 		rd = linredir;
-		ia = inarr;
+		ia = linarr;
 		if (inwhat == IN_NOTHING && incond)
 		    inwhat = IN_COND;
 	    } else if (linredir)
@@ -1515,12 +1523,53 @@ get_comp_string(void)
 	     */
 	    for (i = 0, p = s; *p; p++, i++) {
 		/* careful, ${... is not a brace expansion...
-		 * in fact, if it's got a substitution in it's too
-		 * hard for us anyway.  sorry.
+		 * we try to get braces after a parameter expansion right,
+		 * but this may fail sometimes. sorry.
 		 */
 		if (*p == String || *p == Qstring) {
-		    tt = NULL;
-		    break;
+		    if (p[1] == Inbrace || p[1] == Inpar || p[1] == Inbrack) {
+			char *tp = p + 1;
+			if (skipparens(*tp, (*tp == Inbrace ? Outbrace :
+					     (*tp == Inpar ? Outpar : Outbrack)),
+				       &tp)) {
+			    tt = NULL;
+			    break;
+			}
+			i += tp - p;
+			p = tp;
+		    } else {
+			char *tp = p + 1;
+
+			for (; *tp == '^' || *tp == Hat ||
+				 *tp == '=' || *tp == Equals ||
+				 *tp == '~' || *tp == Tilde ||
+				 *tp == '#' || *tp == Pound || *tp == '+';
+			     tp++);
+			if (*tp == Quest || *tp == Star || *tp == String ||
+			    *tp == Qstring || *tp == '?' || *tp == '*' ||
+			    *tp == '$' || *tp == '-' || *tp == '!' ||
+			    *tp == '@')
+			    p++, i++;
+			else {
+			    if (idigit(*tp))
+				while (idigit(*tp))
+				    tp++;
+			    else if (iident(*tp))
+				while (iident(*tp))
+				    tp++;
+			    else {
+				tt = NULL;
+				break;
+			    }
+			    if (*tp == Inbrace) {
+				tt = NULL;
+				break;
+			    }
+			    tp--;
+			    i += tp - p;
+			    p = tp;
+			}
+		    }
 		} else if (*p == Inbrace) {
 		    if (tt) {
 			/* too many inbraces */
@@ -3472,14 +3521,10 @@ set_param(char *name, LinkList l)
 
 /**/
 int
-addmatches(char *ipre, char *isuf,
-	   char *ppre, char *psuf, char *prpre, char *pre,
-	   char *suf, char *group, char *rems, char *remf, char *ign,
-	   int flags, int aflags, Cmatcher match, char *exp, 
-	   char *apar, char *opar, char **argv)
+addmatches(Cadata dat, char **argv)
 {
     char *s, *ms, *lipre = NULL, *lisuf = NULL, *lpre = NULL, *lsuf = NULL;
-    char **aign = NULL;
+    char **aign = NULL, **dparr;
     int lpl, lsl, pl, sl, bpl, bsl, llpl = 0, llsl = 0, nm = mnum;
     int oisalt = 0, isalt, isexact, doadd;
     Cline lc = NULL;
@@ -3487,45 +3532,52 @@ addmatches(char *ipre, char *isuf,
     struct cmlist mst;
     Cmlist oms = mstack;
     Comp cp = NULL;
-    LinkList aparl = NULL, oparl = NULL;
+    LinkList aparl = NULL, oparl = NULL, dparl = NULL;
 
     /* Switch back to the heap that was used when the completion widget
      * was invoked. */
     SWITCHHEAPS(compheap) {
 	HEAPALLOC {
-	    doadd = (!apar && !opar);
-	    if (apar)
+	    doadd = (!dat->apar && !dat->opar && !dat->dpar);
+	    if (dat->apar)
 		aparl = newlinklist();
-	    if (opar)
+	    if (dat->opar)
 		oparl = newlinklist();
-	    if (exp) {
+	    if (dat->dpar) {
+		if (*(dat->dpar) == '(')
+		    dparr = NULL;
+		else if ((dparr = get_user_var(dat->dpar)) && !*dparr)
+		    dparr = NULL;
+		dparl = newlinklist();
+	    }
+	    if (dat->exp) {
 		expl = (Cexpl) zhalloc(sizeof(struct cexpl));
 		expl->count = expl->fcount = 0;
-		expl->str = dupstring(exp);
+		expl->str = dupstring(dat->exp);
 	    } else
 		expl = NULL;
 
 	    /* Store the matcher in our stack of matchers. */
-	    if (match) {
+	    if (dat->match) {
 		mst.next = mstack;
-		mst.matcher = match;
+		mst.matcher = dat->match;
 		mstack = &mst;
 
 		if (!mnum)
-		    add_bmatchers(match);
+		    add_bmatchers(dat->match);
 
-		addlinknode(matchers, match);
-		match->refc++;
+		addlinknode(matchers, dat->match);
+		dat->match->refc++;
 	    }
 	    if (mnum && (mstack || bmatchers))
 		update_bmatchers();
 
 	    /* Get the suffixes to ignore. */
-	    if (ign)
-		aign = get_user_var(ign);
+	    if (dat->ign)
+		aign = get_user_var(dat->ign);
 	    /* Get the contents of the completion variables if we have
 	     * to perform matching. */
-	    if (aflags & CAF_MATCH) {
+	    if (dat->aflags & CAF_MATCH) {
 		lipre = dupstring(compiprefix);
 		lisuf = dupstring(compisuffix);
 		lpre = dupstring(compprefix);
@@ -3533,8 +3585,8 @@ addmatches(char *ipre, char *isuf,
 		llpl = strlen(lpre);
 		llsl = strlen(lsuf);
 		/* Test if there is an existing -P prefix. */
-		if (pre && *pre) {
-		    pl = pfxlen(pre, lpre);
+		if (dat->pre && *dat->pre) {
+		    pl = pfxlen(dat->pre, lpre);
 		    llpl -= pl;
 		    lpre += pl;
 		}
@@ -3557,79 +3609,76 @@ addmatches(char *ipre, char *isuf,
 		}
 	    }
 	    /* Now duplicate the strings we have from the command line. */
-	    if (ipre)
-		ipre = (lipre ? dyncat(lipre, ipre) : dupstring(ipre));
+	    if (dat->ipre)
+		dat->ipre = (lipre ? dyncat(lipre, dat->ipre) :
+			     dupstring(dat->ipre));
 	    else if (lipre)
-		ipre = lipre;
-	    if (isuf)
-		isuf = (lisuf ? dyncat(lisuf, isuf) : dupstring(isuf));
+		dat->ipre = lipre;
+	    if (dat->isuf)
+		dat->isuf = (lisuf ? dyncat(lisuf, dat->isuf) :
+			     dupstring(dat->isuf));
 	    else if (lisuf)
-		isuf = lisuf;
-	    if (ppre) {
-		ppre = dupstring(ppre);
-		lpl = strlen(ppre);
+		dat->isuf = lisuf;
+	    if (dat->ppre) {
+		dat->ppre = dupstring(dat->ppre);
+		lpl = strlen(dat->ppre);
 	    } else
 		lpl = 0;
-	    if (psuf) {
-		psuf = dupstring(psuf);
-		lsl = strlen(psuf);
+	    if (dat->psuf) {
+		dat->psuf = dupstring(dat->psuf);
+		lsl = strlen(dat->psuf);
 	    } else
 		lsl = 0;
-	    if (aflags & CAF_MATCH) {
-		s = ppre ? ppre : "";
-		if (llpl <= lpl && strpfx(lpre, s)) {
-		    llpl = 0;
+	    if (dat->aflags & CAF_MATCH) {
+		s = dat->ppre ? dat->ppre : "";
+		if (llpl <= lpl && strpfx(lpre, s))
 		    lpre = "";
-		} else if (llpl > lpl && strpfx(s, lpre)) {
-		    llpl -= lpl;
+		else if (llpl > lpl && strpfx(s, lpre))
 		    lpre += lpl;
-		} else
+		else
 		    *argv = NULL;
-		s = psuf ? psuf : "";
-		if (llsl <= lsl && strsfx(lsuf, s)) {
-		    llsl = 0;
+		s = dat->psuf ? dat->psuf : "";
+		if (llsl <= lsl && strsfx(lsuf, s))
 		    lsuf = "";
-		} else if (llsl > lsl && strsfx(s, lsuf)) {
+		else if (llsl > lsl && strsfx(s, lsuf))
 		    lsuf[llsl - lsl] = '\0';
-		    llsl -= lsl;
-		} else
+		else
 		    *argv = NULL;
 	    }
 	    if (*argv) {
-		if (pre)
-		    pre = dupstring(pre);
-		if (suf)
-		    suf = dupstring(suf);
-		if (!prpre && (prpre = ppre)) {
-		    singsub(&prpre);
-		    untokenize(prpre);
+		if (dat->pre)
+		    dat->pre = dupstring(dat->pre);
+		if (dat->suf)
+		    dat->suf = dupstring(dat->suf);
+		if (!dat->prpre && (dat->prpre = dat->ppre)) {
+		    singsub(&(dat->prpre));
+		    untokenize(dat->prpre);
 		} else
-		    prpre = dupstring(prpre);
+		    dat->prpre = dupstring(dat->prpre);
 		/* Select the group in which to store the matches. */
-		if (group) {
+		if (dat->group) {
 		    endcmgroup(NULL);
-		    begcmgroup(group, (aflags & CAF_NOSORT));
-		    if (aflags & CAF_NOSORT)
+		    begcmgroup(dat->group, (dat->aflags & CAF_NOSORT));
+		    if (dat->aflags & CAF_NOSORT)
 			mgroup->flags |= CGF_NOSORT;
 		} else {
 		    endcmgroup(NULL);
 		    begcmgroup("default", 0);
 		}
 		/* Select the set of matches. */
-		oisalt = (aflags & CAF_ALT);
+		oisalt = (dat->aflags & CAF_ALT);
 
-		if (remf) {
-		    remf = dupstring(remf);
-		    rems = NULL;
-		} else if (rems)
-		    rems = dupstring(rems);
+		if (dat->remf) {
+		    dat->remf = dupstring(dat->remf);
+		    dat->rems = NULL;
+		} else if (dat->rems)
+		    dat->rems = dupstring(dat->rems);
 
 		/* Probably quote the prefix and suffix for testing. */
-		if (!cp && (aflags & CAF_MATCH) && !(aflags & CAF_QUOTE)) {
+		if (!cp && (dat->aflags & CAF_MATCH) &&
+		    !(dat->aflags & CAF_QUOTE)) {
 		    lpre = quotename(lpre, NULL);
 		    lsuf = quotename(lsuf, NULL);
-		    llpl = strlen(lpre);
-		    llsl = strlen(lsuf);
 		}
 	    }
 	    /* Walk through the matches given. */
@@ -3638,7 +3687,7 @@ addmatches(char *ipre, char *isuf,
 		bpl = brpl;
 		bsl = brsl;
 		isalt = oisalt;
-		if ((!psuf || !*psuf) && aign) {
+		if ((!dat->psuf || !*(dat->psuf)) && aign) {
 		    /* Do the suffix-test. If the match has one of the
 		     * suffixes from ign, we put it in the alternate set. */
 		    char **pt = aign;
@@ -3649,39 +3698,52 @@ addmatches(char *ipre, char *isuf,
 			    && !strcmp(*pt, s + sl - filell))
 			    isalt = 1;
 
-		    if (isalt && !doadd)
+		    if (isalt && !doadd) {
+			if (dparr && !*++dparr)
+			    dparr = NULL;
 			continue;
+		    }
 		}
-		if (!(aflags & CAF_MATCH)) {
+		if (!(dat->aflags & CAF_MATCH)) {
 		    ms = dupstring(s);
 		    lc = bld_parts(ms, sl, -1, NULL);
 		    isexact = 0;
 		} else if (!(ms = comp_match(lpre, lsuf, s, cp, &lc,
-					     !(aflags & CAF_QUOTE),
-					     &bpl, &bsl, &isexact)))
+					     !(dat->aflags & CAF_QUOTE),
+					     &bpl, &bsl, &isexact))) {
+		    if (dparr && !*++dparr)
+			dparr = NULL;
 		    continue;
-
+		}
 		if (doadd) {
-		    cm = add_match_data(isalt, ms, lc, ipre, ipre, isuf, pre, 
-					prpre, ppre, psuf, suf, bpl, bsl,
-					flags, isexact);
-		    cm->rems = rems;
-		    cm->remf = remf;
+		    cm = add_match_data(isalt, ms, lc, dat->ipre, dat->ipre,
+					dat->isuf, dat->pre, dat->prpre,
+					dat->ppre, dat->psuf, dat->suf,
+					bpl, bsl, dat->flags, isexact);
+		    cm->rems = dat->rems;
+		    cm->remf = dat->remf;
 		} else {
-		    if (apar)
+		    if (dat->apar)
 			addlinknode(aparl, ms);
-		    if (opar)
+		    if (dat->opar)
 			addlinknode(oparl, s);
+		    if (dat->dpar && dparr) {
+			addlinknode(dparl, *dparr);
+			if (!*++dparr)
+			    dparr = NULL;
+		    }
 		    free_cline(lc);
 		}
 	    }
 	    compnmatches = mnum;
-	    if (exp)
+	    if (dat->exp)
 		addexpl();
-	    if (apar)
-		set_param(apar, aparl);
-	    if (opar)
-		set_param(opar, oparl);
+	    if (dat->apar)
+		set_param(dat->apar, aparl);
+	    if (dat->opar)
+		set_param(dat->opar, oparl);
+	    if (dat->dpar)
+		set_param(dat->dpar, dparl);
 	} LASTALLOC;
     } SWITCHBACKHEAPS;
 
@@ -4128,6 +4190,7 @@ docompletion(char *s, int lst, int incmd)
 				(unset(ALWAYSLASTPROMPT) && zmult != 1)) ?
 				"yes" : "");
 	movetoend = ((cs == we || isset(ALWAYSTOEND)) ? 2 : 1);
+	showinglist = 0;
 
 	/* Make sure we have the completion list and compctl. */
 	if (makecomplist(s, incmd, lst)) {
@@ -4217,14 +4280,22 @@ callcompfunc(char *s, char *fn)
 
     if ((list = getshfunc(fn)) != &dummy_list) {
 	char **p, *tmp;
-	int set, aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	int aadd = 0, usea = 1, icf = incompfunc, osc = sfcontext;
+	unsigned int set;
 	Param *ocpms = comppms;
 
 	comppms = (Param *) zalloc(CP_NUM * sizeof(Param));
 
-	set = -1 & ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
-		     CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
-		     (useglob ? 0 : CP_PATMATCH));
+	set = CP_ALLMASK &
+	    ~(CP_PARAMETER | CP_REDIRECT | CP_QUOTE | CP_QUOTING |
+	      CP_EXACTSTR | CP_FORCELIST | CP_OLDLIST | CP_OLDINS |
+	      (useglob ? 0 : CP_PATMATCH));
+	zsfree(compvared);
+	if (varedarg) {
+	    compvared = ztrdup(varedarg);
+	    set |= CP_VARED;
+	} else
+	    compvared = ztrdup("");
 	if (!*complastprompt)
 	    set &= ~CP_LASTPROMPT;
 	zsfree(compcontext);
@@ -4257,7 +4328,7 @@ callcompfunc(char *s, char *fn)
 	} else
 	    switch (linwhat) {
 	    case IN_ENV:
-		compcontext = "array_value";
+		compcontext = (linarr ? "array_value" : "value");
 		compparameter = varname;
 		set |= CP_PARAMETER;
 		if (!clwpos) {
@@ -4551,6 +4622,7 @@ makecomplist(char *s, int incmd, int lst)
 	insmnum = insgnum = 1;
 	insgroup = oldlist = oldins = 0;
 	begcmgroup("default", 0);
+	menucmp = 0;
 
 	ccused = newlinklist();
 	ccstack = newlinklist();
@@ -6717,11 +6789,13 @@ unambig_data(int *cp)
     return scache;
 }
 
-/* Insert the given match. This returns the number of characters inserted.*/
+/* Insert the given match. This returns the number of characters inserted.
+ * scs is used to return the position where a automatically created suffix
+ * has to be inserted. */
 
 /**/
 static int
-instmatch(Cmatch m)
+instmatch(Cmatch m, int *scs)
 {
     int l, r = 0, ocs, a = cs;
 
@@ -6771,6 +6845,7 @@ instmatch(Cmatch m)
     } else
 	brscs = -1;
     /* -S suffix */
+    *scs = cs;
     if (m->suf) {
 	inststrlen(m->suf, 1, (l = strlen(m->suf)));
 	r += l;
@@ -6842,13 +6917,13 @@ do_ambiguous(void)
 
 	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an  *
 	 * exact match, we want menu completion the next time round       *
-	 * so we set fromcomp,to ensure that the word on the line is not  *
+	 * so we set fromcomp, to ensure that the word on the line is not *
 	 * taken as an exact match. Also we remember if we just moved the *
 	 * cursor into the word.                                          */
 	fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
 		    ((atend && cs != lastend) ? FC_INWORD : 0));
 
-	/* Probably move the cursor to then end. */
+	/* Probably move the cursor to the end. */
 	if (movetoend == 3)
 	    cs = lastend;
 
@@ -6907,7 +6982,7 @@ ztat(char *nam, struct stat *buf, int ls)
 static void
 do_single(Cmatch m)
 {
-    int l, sr = 0;
+    int l, sr = 0, scs;
     int havesuff = 0;
     char *str = m->str, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre;
 
@@ -6937,7 +7012,7 @@ do_single(Cmatch m)
     foredel(l);
 
     /* And then we insert the new string. */
-    menulen = instmatch(m);
+    menulen = instmatch(m, &scs);
     menuend = cs;
     cs = menupos + menulen;
 
@@ -6956,6 +7031,7 @@ do_single(Cmatch m)
     } else {
 	/* There is no user-specified suffix, *
 	 * so generate one automagically.     */
+	cs = scs;
 	if (m->ripre && (m->flags & CMF_PARBR)) {
 	    /*{{*/
 	    /* Completing a parameter in braces.  Add a removable `}' suffix. */
@@ -7006,6 +7082,8 @@ do_single(Cmatch m)
 		}
 	    }
 	}
+	if (!menuinsc)
+	    cs = menupos + menulen;
     }
     /* If completing in a brace expansion... */
     if (brbeg) {
@@ -7018,7 +7096,7 @@ do_single(Cmatch m)
 	} else if (!menucmp) {
 	    /*{{*/
 	    /* Otherwise, add a `,' suffix, and let `}' remove it. */
-	    cs = menuend;
+	    cs = scs;
 	    havesuff = 1;
 	    inststrlen(",", 1, 1);
 	    menuinsc++;
@@ -7492,7 +7570,12 @@ listlist(LinkList l)
     struct cmgroup dg;
     Cmgroup am = amatches;
     int vl = validlist, sm = smatches;
+    char *oclp = complastprompt;
+
+    if (listshown)
+	showagain = 1;
 
+    complastprompt = ((zmult == 1) == !!isset(ALWAYSLASTPROMPT) ? "yes" : NULL);
     smatches = 1;
     validlist = 1;
     amatches = &dg;
@@ -7503,6 +7586,7 @@ listlist(LinkList l)
     amatches = am;
     validlist = vl;
     smatches = sm;
+    complastprompt = oclp;
 }
 
 /* Expand the history references. */
diff --git a/Src/builtin.c b/Src/builtin.c
index c042537f4..9ffcad1b3 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -120,7 +120,7 @@ static struct builtin builtins[] =
     BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
 
 #ifdef DYNAMIC
-    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicI", NULL),
+    BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "LaudicIp", NULL),
 #endif
 };
 
@@ -1485,7 +1485,7 @@ typeset_single(char *cname, char *pname, Param pm, int func,
     int usepm, tc, keeplocal = 0;
 
     /* use the existing pm? */
-    usepm = pm && !(pm->flags & PM_UNSET);
+    usepm = pm && !(pm->flags & (PM_UNSET | PM_AUTOLOAD));
 
     /* Always use an existing pm if special at current locallevel */
     if (pm && (pm->flags & PM_SPECIAL) && pm->level == locallevel)
@@ -1793,7 +1793,9 @@ bin_typeset(char *name, char **argv, char *ops, int func)
 	    continue;
 	}
 	if (!typeset_single(name, asg->name,
-			    (Param)paramtab->getnode(paramtab, asg->name),
+			    (Param) (paramtab == realparamtab ?
+				     gethashnode2(paramtab, asg->name) :
+				     paramtab->getnode(paramtab, asg->name)),
 			    func, on, off, roff, asg->value, NULL))
 	    returnval = 1;
     }
@@ -1945,7 +1947,7 @@ bin_unset(char *name, char **argv, char *ops, int func)
 			next = (Param) pm->next;
 			if ((!(pm->flags & PM_RESTRICTED) ||
 			    unset(RESTRICTED)) && domatch(pm->nam, com, 0)) {
-			    unsetparam(pm->nam);
+			    unsetparam_pm(pm, 0, 1);
 			    match++;
 			}
 		    }
@@ -1974,7 +1976,9 @@ bin_unset(char *name, char **argv, char *ops, int func)
 	    }
 	    *ss = 0;
 	}
-	pm = (Param) paramtab->getnode(paramtab, s);
+	pm = (Param) (paramtab == realparamtab ?
+		      gethashnode2(paramtab, s) :
+		      paramtab->getnode(paramtab, s));
 	if (!pm)
 	    returnval = 1;
 	else if ((pm->flags & PM_RESTRICTED) && isset(RESTRICTED)) {
diff --git a/Src/glob.c b/Src/glob.c
index 47ca1d659..79a86bbef 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -3379,16 +3379,14 @@ tokenize(char *s)
 	    *t = Inang;
 	    *s = Outang;
 	    break;
-	case '^':
-	case '#':
-	case '~':
-	    if (unset(EXTENDEDGLOB))
-		break;
 	case '(':
 	case '|':
 	case ')':
 	    if (isset(SHGLOB))
 		break;
+	case '^':
+	case '#':
+	case '~':
 	case '[':
 	case ']':
 	case '*':
diff --git a/Src/mkbltnmlst.sh b/Src/mkbltnmlst.sh
index b58d1e1dd..c174cbac6 100644
--- a/Src/mkbltnmlst.sh
+++ b/Src/mkbltnmlst.sh
@@ -24,7 +24,7 @@ for x_mod in $x_mods; do
 	*" $x_mod "*) ;;
 	*)  echo "/* non-linked-in known module \`$x_mod' */"
 	    eval "loc=\$loc_$x_mod"
-	    unset moddeps autobins autoinfixconds autoprefixconds
+	    unset moddeps autobins autoinfixconds autoprefixconds autoparams
 	    . $srcdir/../$loc/${x_mod}.mdd
 	    for bin in $autobins; do
 		echo "    add_autobin(\"$bin\", \"$x_mod\");"
@@ -35,6 +35,9 @@ for x_mod in $x_mods; do
 	    for cond in $autoprefixconds; do
 		echo "    add_autocond(\"$cond\", 0, \"$x_mod\");"
 	    done
+	    for param in $autoparams; do
+		echo "    add_autoparam(\"$param\", \"$x_mod\");"
+	    done
 	    for dep in $moddeps; do
 		case $bin_mods in
 		    *" $dep "*)
diff --git a/Src/mkmakemod.sh b/Src/mkmakemod.sh
index 2f79acbc3..cd92c7f07 100644
--- a/Src/mkmakemod.sh
+++ b/Src/mkmakemod.sh
@@ -24,6 +24,7 @@
 #   autoinfixconds  infix condition codes defined by the module, for
 #                   autoloading (without the leading `-')
 #   autoprefixconds like autoinfixconds, but for prefix condition codes
+#   autoparams      parameters defined by the module, for autoloading
 #   objects         .o files making up this module (*must* be defined)
 #   proto           .pro files for this module (default generated from $objects)
 #   headers         extra headers for this module (default none)
@@ -170,7 +171,7 @@ if $first_stage; then
     for module in $here_modules; do
 
 	unset moddeps nozshdep alwayslink hasexport
-	unset autobins autoinfixconds autoprefixconds
+	unset autobins autoinfixconds autoprefixconds autoparams
 	unset objects proto headers hdrdeps otherincs
 	. $top_srcdir/$the_subdir/${module}.mdd
 	test -n "${moddeps+set}" || moddeps=
diff --git a/Src/module.c b/Src/module.c
index ff386c630..09f1fd5db 100644
--- a/Src/module.c
+++ b/Src/module.c
@@ -539,18 +539,24 @@ load_module(char const *name)
 	m = zcalloc(sizeof(*m));
 	m->nam = ztrdup(name);
 	m->handle = handle;
+	m->flags |= MOD_SETUP;
+	PERMALLOC {
+	    node = addlinknode(modules, m);
+	} LASTALLOC;
 	if (setup_module(m) || init_module(m)) {
 	    finish_module(m);
+	    remnode(modules, node);
 	    zsfree(m->nam);
 	    zfree(m, sizeof(*m));
+	    m->flags &= ~MOD_SETUP;
 	    return NULL;
 	}
-	PERMALLOC {
-	    addlinknode(modules, m);
-	} LASTALLOC;
+	m->flags &= ~MOD_SETUP;
 	return m;
     } 
     m = (Module) getdata(node);
+    if (m->flags & MOD_SETUP)
+	return m;
     if (m->flags & MOD_UNLOAD)
 	m->flags &= ~MOD_UNLOAD;
     else if (m->handle)
@@ -570,17 +576,22 @@ load_module(char const *name)
     if (!m->handle) {
 	if (!(m->handle = do_load_module(name)))
 	    return NULL;
+	m->flags |= MOD_SETUP;
 	if (setup_module(m)) {
 	    finish_module(m->handle);
 	    m->handle = NULL;
+	    m->flags &= ~MOD_SETUP;
 	    return NULL;
 	}
     }
+    m->flags |= MOD_SETUP;
     if (init_module(m)) {
 	finish_module(m->handle);
 	m->handle = NULL;
+	m->flags &= ~MOD_SETUP;
 	return NULL;
     }
+    m->flags &= ~MOD_SETUP;
     return m;
 }
 
@@ -690,6 +701,8 @@ bin_zmodload(char *nam, char **args, char *ops, int func)
 	return bin_zmodload_auto(nam, args, ops);
     else if (ops['c'] || ops['C'])
 	return bin_zmodload_cond(nam, args, ops);
+    else if (ops['p'])
+	return bin_zmodload_param(nam, args, ops);
     else
 	return bin_zmodload_load(nam, args, ops);
 }
@@ -888,6 +901,66 @@ bin_zmodload_cond(char *nam, char **args, char *ops)
     }
 }
 
+static void
+printautoparams(HashNode hn, int lon)
+{
+    Param pm = (Param) hn;
+
+    if (pm->flags & PM_AUTOLOAD) {
+	if (lon)
+	    printf("zmodload -p %s %s\n", pm->u.str, pm->nam);
+	else
+	    printf("%s (%s)\n", pm->nam, pm->u.str);
+    }
+}
+
+/**/
+static int
+bin_zmodload_param(char *nam, char **args, char *ops)
+{
+    int ret = 0;
+
+    if (ops['u']) {
+	/* remove autoloaded parameters */
+	for (; *args; args++) {
+	    Param pm = (Param) gethashnode2(paramtab, *args);
+
+	    if (!pm) {
+		if (!ops['i']) {
+		    zwarnnam(nam, "%s: no such parameter", *args, 0);
+		    ret = 1;
+		}
+	    } else if (!(pm->flags & PM_AUTOLOAD)) {
+		zwarnnam(nam, "%s: parameter is already defined", *args, 0);
+		ret = 1;
+	    } else
+		unsetparam_pm(pm, 0, 1);
+	}
+	return ret;
+    } else if (!*args) {
+	scanhashtable(paramtab, 1, 0, 0, printautoparams, ops['L']);
+	return 0;
+    } else {
+	/* add autoloaded parameters */
+	char *modnam;
+
+	modnam = *args++;
+	if(isset(RESTRICTED) && strchr(modnam, '/')) {
+	    zwarnnam(nam, "%s: restricted", modnam, 0);
+	    return 1;
+	}
+	do {
+	    char *pnam = *args ? *args++ : modnam;
+	    if (strchr(pnam, '/')) {
+		zwarnnam(nam, "%s: `/' is illegal in a parameter", pnam, 0);
+		ret = 1;
+	    } else
+		add_autoparam(pnam, modnam);
+	} while(*args);
+	return ret;
+    }
+}
+
 /**/
 int
 unload_module(Module m, LinkNode node)
@@ -1114,6 +1187,71 @@ addconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
+/* This adds the given parameter definition. The return value is zero on *
+ * success and 1 on failure. */
+
+/**/
+int
+addparamdef(Paramdef d)
+{
+    Param pm;
+
+    if ((pm = (Param) gethashnode2(paramtab, d->name)))
+	unsetparam_pm(pm, 0, 1);
+
+    if (!(pm = createparam(d->name, d->flags)) &&
+	!(pm = (Param) paramtab->getnode(paramtab, d->name)))
+	return 1;
+
+    pm->level = 0;
+    pm->u.data = d->var;
+    pm->sets.ifn = (void (*)(Param, long)) d->set;
+    pm->gets.ifn = (long (*)(Param)) d->get;
+    pm->unsetfn = (void (*)(Param, int)) d->unset;
+
+    return 0;
+}
+
+/* This adds multiple parameter definitions. This is like addbuiltins(). */
+
+/**/
+int
+addparamdefs(char const *nam, Paramdef d, int size)
+{
+    int hads = 0, hadf = 0;
+
+    while (size--) {
+	if (addparamdef(d)) {
+	    zwarnnam(nam, "error when adding parameter `%s'", d->name, 0);
+	    hadf = 1;
+	} else
+	    hads = 2;
+	d++;
+    }
+    return hadf ? hads : 1;
+}
+
+/* Delete parameters defined. No error checking yet. */
+
+/**/
+int
+deleteparamdef(Paramdef d)
+{
+    unsetparam(d->name);
+    return 0;
+}
+
+/**/
+int
+deleteparamdefs(char const *nam, Paramdef d, int size)
+{
+    while (size--) {
+	deleteparamdef(d);
+	d++;
+    }
+    return 1;
+}
+
 #ifdef DYNAMIC
 
 /* This adds a definition for autoloading a module for a condition. */
@@ -1188,4 +1326,20 @@ deleteconddefs(char const *nam, Conddef c, int size)
     return hadf ? hads : 1;
 }
 
+/* This adds a definition for autoloading a module for a parameter. */
+
+/**/
+void
+add_autoparam(char *nam, char *module)
+{
+    Param pm;
+
+    if ((pm = (Param) gethashnode2(paramtab, nam)))
+	unsetparam_pm(pm, 0, 1);
+
+    pm = setsparam(ztrdup(nam), ztrdup(module));
+
+    pm->flags |= PM_AUTOLOAD;
+}
+
 #endif
diff --git a/Src/params.c b/Src/params.c
index dbc6ce8d8..d60f91990 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -255,7 +255,11 @@ static Param argvparam;
 /* hash table containing the parameters */
  
 /**/
-HashTable paramtab;
+HashTable paramtab, realparamtab;
+
+#ifndef DYNAMIC
+#define getparamnode gethashnode2
+#endif /* DYNAMIC */
 
 /**/
 HashTable
@@ -267,8 +271,8 @@ newparamtable(int size, char const *name)
     ht->emptytable  = emptyhashtable;
     ht->filltable   = NULL;
     ht->addnode     = addhashnode;
-    ht->getnode     = gethashnode2;
-    ht->getnode2    = gethashnode2;
+    ht->getnode     = getparamnode;
+    ht->getnode2    = getparamnode;
     ht->removenode  = removehashnode;
     ht->disablenode = NULL;
     ht->enablenode  = NULL;
@@ -278,6 +282,25 @@ newparamtable(int size, char const *name)
     return ht;
 }
 
+#ifdef DYNAMIC
+/**/
+static HashNode
+getparamnode(HashTable ht, char *nam)
+{
+    HashNode hn = gethashnode2(ht, nam);
+    Param pm = (Param) hn;
+
+    if (pm && pm->u.str && (pm->flags & PM_AUTOLOAD)) {
+	char *mn = dupstring(pm->u.str);
+
+	if (!load_module(mn))
+	    return NULL;
+	hn = gethashnode2(ht, nam);
+    }
+    return hn;
+}
+#endif /* DYNAMIC */
+
 /* Copy a parameter hash table */
 
 static HashTable outtable;
@@ -402,7 +425,7 @@ createparamtable(void)
     char buf[50], *str, *iname;
     int num_env;
 
-    paramtab = newparamtable(151, "paramtab");
+    paramtab = realparamtab = newparamtable(151, "paramtab");
 
     /* Add the special parameters to the hash table */
     for (ip = special_params; ip->nam; ip++)
@@ -542,7 +565,9 @@ createparam(char *name, int flags)
     Param pm, oldpm;
 
     if (name != nulstring) {
-	oldpm = (Param) paramtab->getnode(paramtab, name);
+	oldpm = (Param) (paramtab == realparamtab ?
+			 gethashnode2(paramtab, name) :
+			 paramtab->getnode(paramtab, name));
 
 	if (oldpm && oldpm->level == locallevel) {
 	    if (!(oldpm->flags & PM_UNSET) || (oldpm->flags & PM_SPECIAL)) {
@@ -2703,6 +2728,8 @@ printparamnode(HashNode hn, int printflags)
 
     /* Print the attributes of the parameter */
     if (printflags & PRINT_TYPE) {
+	if (p->flags & PM_AUTOLOAD)
+	    printf("undefined ");
 	if (p->flags & PM_INTEGER)
 	    printf("integer ");
 	else if (p->flags & PM_ARRAY)
@@ -2736,6 +2763,11 @@ printparamnode(HashNode hn, int printflags)
     }
 
     quotedzputs(p->nam, stdout);
+
+    if (p->flags & PM_AUTOLOAD) {
+	putchar('\n');
+	return;
+    }
     if (printflags & PRINT_KV_PAIR)
 	putchar(' ');
     else
diff --git a/Src/prompt.c b/Src/prompt.c
index 69823a5e3..ad7cdbc31 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -232,7 +232,7 @@ putpromptchar(int doprint, int endchar)
 		    break;
 		case 'l':
 		    *bp = '\0';
-		    countprompt(bufline, &t0, 0);
+		    countprompt(bufline, &t0, 0, 0);
 		    if (t0 >= arg)
 			test = 1;
 		    break;
@@ -678,11 +678,15 @@ putstr(int d)
 
 /**/
 void
-countprompt(char *str, int *wp, int *hp)
+countprompt(char *str, int *wp, int *hp, int overf)
 {
     int w = 0, h = 1;
     int s = 1;
     for(; *str; str++) {
+	if(w >= columns) {
+	    w = 0;
+	    h++;
+	}
 	if(*str == Meta)
 	    str++;
 	if(*str == Inpar)
@@ -694,12 +698,15 @@ countprompt(char *str, int *wp, int *hp)
 	else if(s) {
 	    if(*str == '\t')
 		w = (w | 7) + 1;
-	    else if(*str == '\n')
-		w = columns;
-	    else
+	    else if(*str == '\n') {
+		w = 0;
+		h++;
+	    } else
 		w++;
 	}
-	if(w >= columns) {
+    }
+    if(w >= columns) {
+	if (!overf || w > columns) {
 	    w = 0;
 	    h++;
 	}
diff --git a/Src/zsh.export b/Src/zsh.export
index dcee683f6..7f994bf29 100644
--- a/Src/zsh.export
+++ b/Src/zsh.export
@@ -4,6 +4,7 @@ addbuiltins
 addconddefs
 addedx
 addhashnode
+addparamdefs
 addwrapper
 arrvargetfn
 arrvarsetfn
@@ -40,6 +41,7 @@ current_limits
 deletebuiltins
 deleteconddefs
 deletehashtable
+deleteparamdefs
 deletewrapper
 domatch
 doshfunc
diff --git a/Src/zsh.h b/Src/zsh.h
index c3c853dfd..1eefc51c1 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -231,6 +231,7 @@ typedef struct hashtable *HashTable;
 typedef struct reswd     *Reswd;
 typedef struct alias     *Alias;
 typedef struct param     *Param;
+typedef struct paramdef  *Paramdef;
 typedef struct cmdnam    *Cmdnam;
 typedef struct shfunc    *Shfunc;
 typedef struct funcwrap  *FuncWrap;
@@ -850,6 +851,7 @@ struct module {
 
 #define MOD_BUSY    (1<<0)
 #define MOD_UNLOAD  (1<<1)
+#define MOD_SETUP   (1<<2)
 
 /* node used in parameter hash table (paramtab) */
 
@@ -923,6 +925,7 @@ struct param {
 #define PM_RESTRICTED	(1<<15) /* cannot be changed in restricted mode       */
 #define PM_UNSET	(1<<16)	/* has null value                             */
 #define PM_REMOVABLE	(1<<17)	/* special can be removed from paramtab */
+#define PM_AUTOLOAD     (1<<18) /* autoloaded from module */
 
 /* Flags for extracting elements of arrays and associative arrays */
 #define SCANPM_WANTVALS   (1<<0)
@@ -955,6 +958,27 @@ struct param {
 #define PF_ASSIGN	0x02	/* argument handled like the RHS of foo=bar */
 #define PF_SINGLE	0x04	/* single word substitution */
 
+struct paramdef {
+    char *name;
+    int flags;
+    void *var;
+    void *set;
+    void *get;
+    void *unset;
+};
+
+#define PARAMDEF(name, flags, var, set, get, unset) \
+    { name, flags, (void *) var, (void *) set, (void *) get, (void *) unset }
+#define INTPARAMDEF(name, var) \
+    { name, PM_INTEGER, (void *) var, (void *) intvarsetfn, \
+      (void *) intvargetfn, (void *) stdunsetfn }
+#define STRPARAMDEF(name, var) \
+    { name, PM_SCALAR, (void *) var, (void *) strvarsetfn, \
+      (void *) strvargetfn, (void *) stdunsetfn }
+#define ARRPARAMDEF(name, var) \
+    { name, PM_ARRAY, (void *) var, (void *) arrvarsetfn, \
+      (void *) arrvargetfn, (void *) stdunsetfn }
+
 /* node for named directory hash table (nameddirtab) */
 
 struct nameddir {