about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-08-02 16:50:25 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-08-02 16:50:25 +0000
commitafb8089dcd26da5a8c932db4abca6851996cd48d (patch)
treed8d663eaf85eeb74074398e78cdbad6b04c4bf4d
parent8f006137ed6bb25243fdc5435f04348016f34aea (diff)
downloadzsh-afb8089dcd26da5a8c932db4abca6851996cd48d.tar.gz
zsh-afb8089dcd26da5a8c932db4abca6851996cd48d.tar.xz
zsh-afb8089dcd26da5a8c932db4abca6851996cd48d.zip
zsh-workers:7344
-rw-r--r--Src/Zle/compctl.c179
-rw-r--r--Src/cond.c98
-rw-r--r--Util/zsh-development-guide259
3 files changed, 420 insertions, 116 deletions
diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c
index 337ecb771..a8a864a1a 100644
--- a/Src/Zle/compctl.c
+++ b/Src/Zle/compctl.c
@@ -688,6 +688,22 @@ get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl)
 		    *argv = "" - 1;
 		}
 		break;
+	    case 'h':
+		if (cl) {
+		    zerrnam(name, "illegal option -%c", NULL, **argv);
+		    return 1;
+		} else if ((*argv)[1]) {
+		    cct.substr = (*argv) + 1;
+		    *argv = "" - 1;
+		} else if (!argv[1]) {
+		    zwarnnam(name, "command name expected after -%c", NULL,
+			    **argv);
+		    return 1;
+		} else {
+		    cct.substr = *++argv;
+		    *argv = "" - 1;
+		}
+		break;
 	    case 'W':
 		if ((*argv)[1]) {
 		    cct.withd = (*argv) + 1;
@@ -933,6 +949,9 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef)
 		t++;
 	    /* First get the condition code */
 	    switch (*t) {
+	    case 'q':
+		c->type = CCT_QUOTE;
+		break;
 	    case 's':
 		c->type = CCT_CURSUF;
 		break;
@@ -1017,7 +1036,8 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef)
 		c->u.r.a = (int *)zcalloc(n * sizeof(int));
 		c->u.r.b = (int *)zcalloc(n * sizeof(int));
 	    } else if (c->type == CCT_CURSUF ||
-		       c->type == CCT_CURPRE)
+		       c->type == CCT_CURPRE ||
+		       c->type == CCT_QUOTE)
 		c->u.s.s = (char **)zcalloc(n * sizeof(char *));
 
 	    else if (c->type == CCT_RANGESTR ||
@@ -1059,7 +1079,8 @@ get_xcompctl(char *name, char ***av, Compctl cc, int isdef)
 			c->u.r.b[l] = atoi(tt);
 		    }
 		} else if (c->type == CCT_CURSUF ||
-			   c->type == CCT_CURPRE) {
+			   c->type == CCT_CURPRE ||
+			   c->type == CCT_QUOTE) {
 		    /* -s[..] or -S[..]:  single string expected */
 		    for (; *t && *t != '\200'; t++)
 			if (*t == '\201')
@@ -1218,6 +1239,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     zsfree(cc->prefix);
     zsfree(cc->suffix);
     zsfree(cc->subcmd);
+    zsfree(cc->substr);
     zsfree(cc->withd);
     zsfree(cc->hpat);
     zsfree(cc->gname);
@@ -1239,6 +1261,7 @@ cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass)
     cc->prefix = ztrdup(cct->prefix);
     cc->suffix = ztrdup(cct->suffix);
     cc->subcmd = ztrdup(cct->subcmd);
+    cc->substr = ztrdup(cct->substr);
     cc->withd = ztrdup(cct->withd);
     cc->gname = ztrdup(cct->gname);
     cc->hpat = ztrdup(cct->hpat);
@@ -1366,7 +1389,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
 {
     Compctl cc2;
     char *css = "fcqovbAIFpEjrzBRGudeNOZUnQmw/";
-    char *mss = " pcCwWsSnNmrR";
+    char *mss = " pcCwWsSnNmrRq";
     unsigned long t = 0x7fffffff;
     unsigned long flags = cc->mask, flags2 = cc->mask2;
     unsigned long oldshowmask;
@@ -1448,6 +1471,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
     printif(cc->glob, 'g');
     printif(cc->str, 's');
     printif(cc->subcmd, 'l');
+    printif(cc->substr, 'h');
     printif(cc->withd, 'W');
     if (cc->hpat) {
 	printf(" -H %d ", cc->hnum);
@@ -1484,6 +1508,7 @@ printcompctl(char *s, Compctl cc, int printflags, int ispat)
 			    break;
 			case CCT_CURSUF:
 			case CCT_CURPRE:
+			case CCT_QUOTE:
 			    printqt(c->u.s.s[i]);
 			    break;
 			case CCT_RANGESTR:
@@ -1702,7 +1727,7 @@ bin_compadd(char *name, char **argv, char *ops, int func)
     }
     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.ign = dat.exp = dat.apar = dat.opar = dat.dpar = dat.ylist = NULL;
     dat.match = NULL;
     dat.flags = 0;
     dat.aflags = CAF_MATCH;
@@ -1754,6 +1779,10 @@ bin_compadd(char *name, char **argv, char *ops, int func)
 		sp = &(dat.group);
 		e = "group name expected after -%c";
 		break;
+	    case 'y':
+		sp = &(dat.ylist);
+		e = "string expected after -%c";
+		break;
 	    case 'i':
 		sp = &(dat.ipre);
 		e = "string expected after -%c";
@@ -1859,7 +1888,7 @@ ignore_prefix(int l)
     char *tmp, sav = compprefix[l];
 
     compprefix[l] = '\0';
-    tmp = tricat(compiprefix, compprefix, "");
+    tmp = tricat(compiprefix, rembslash(compprefix), "");
     zsfree(compiprefix);
     compiprefix = tmp;
     compprefix[l] = sav;
@@ -1874,7 +1903,7 @@ ignore_suffix(int l)
     char *tmp, sav;
 
     l = strlen(compsuffix) - l;
-    tmp = tricat(compsuffix + l, compisuffix, "");
+    tmp = tricat(rembslash(compsuffix + l), compisuffix, "");
     zsfree(compisuffix);
     compisuffix = tmp;
     sav = compsuffix[l];
@@ -1918,8 +1947,8 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 
 	    if (compcurrent - 1 < na || compcurrent - 1 > nb)
 		return 0;
-
-	    restrict_range(na, nb);
+	    if (mod)
+		restrict_range(na, nb);
 	    return 1;
 	}
     case CVT_RANGEPAT:
@@ -1960,7 +1989,7 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 	    }
 	    if (e < b)
 		t = 0;
-	    if (t)
+	    if (t && mod)
 		restrict_range(b, e);
 	    return t;
 	}
@@ -2014,8 +2043,8 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 		}
 		if (!l)
 		    return 0;
-
-		ignore_prefix(p - compprefix);
+		if (mod)
+		    ignore_prefix(p - compprefix);
 	    } else {
 		int l, ol, add;
 		char *p;
@@ -2036,8 +2065,8 @@ do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod)
 
 		if (!l)
 		    return 0;
-
-		ignore_suffix(ol - (p - compsuffix));
+		if (mod)
+		    ignore_suffix(ol - (p - compsuffix));
 	    }
 	    return 1;
 	}
@@ -2067,6 +2096,7 @@ bin_compset(char *name, char **argv, char *ops, int func)
     case 'P': test = CVT_PREPAT; break;
     case 's': test = CVT_SUFNUM; break;
     case 'S': test = CVT_SUFPAT; break;
+    case 'q': return set_comp_sepptr();
     default:
 	zerrnam(name, "bad option -%c", NULL, argv[0][1]);
 	return 1;
@@ -2135,19 +2165,25 @@ bin_compcall(char *name, char **argv, char *ops, int func)
  * order of the CP_* bits in comp.h */
 
 #define VAL(X) ((void *) (&(X)))
-static struct compparam {
+struct compparam {
     char *name;
     int type;
     void *var, *set, *get;
-} compparams[] = {
+};
+
+static struct compparam comprparams[] = {
     { "words", PM_ARRAY, VAL(compwords), NULL, NULL },
     { "CURRENT", PM_INTEGER, VAL(compcurrent), NULL, NULL },
     { "PREFIX", PM_SCALAR, VAL(compprefix), NULL, NULL },
     { "SUFFIX", PM_SCALAR, VAL(compsuffix), NULL, NULL },
     { "IPREFIX", PM_SCALAR, VAL(compiprefix), NULL, NULL },
     { "ISUFFIX", PM_SCALAR, VAL(compisuffix), NULL, NULL },
-    { NULL, 0, NULL, NULL, NULL },
+    { "QIPREFIX", PM_SCALAR | PM_READONLY, VAL(compqiprefix), NULL, NULL },
+    { "QISUFFIX", PM_SCALAR | PM_READONLY, VAL(compqisuffix), NULL, NULL },
+    { NULL, 0, NULL, NULL, NULL }
+};
 
+static struct compparam compkparams[] = {
     { "nmatches", PM_INTEGER, VAL(compnmatches), NULL, NULL },
     { "matcher", PM_INTEGER, VAL(compmatcher), NULL, NULL },
     { "matcher_string", PM_SCALAR, VAL(compmatcherstr), NULL, NULL },
@@ -2155,8 +2191,8 @@ static struct compparam {
     { "context", PM_SCALAR, VAL(compcontext), NULL, NULL },
     { "parameter", PM_SCALAR, VAL(compparameter), NULL, NULL },
     { "redirect", PM_SCALAR, VAL(compredirect), NULL, NULL },
-    { "quote", PM_SCALAR, VAL(compquote), NULL, NULL },
-    { "quoting", PM_SCALAR, VAL(compquoting), NULL, NULL },
+    { "quote", PM_SCALAR | PM_READONLY, VAL(compquote), NULL, NULL },
+    { "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL, NULL },
     { "restore", PM_SCALAR, VAL(comprestore), NULL, NULL },
     { "list", PM_SCALAR, VAL(complist), NULL, NULL },
     { "force_list", PM_SCALAR, VAL(compforcelist), NULL, NULL },
@@ -2173,24 +2209,25 @@ 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 },
+    { "normal_nmatches", PM_INTEGER, VAL(compnnmatches), NULL, NULL },
     { NULL, 0, NULL, NULL, NULL }
 };
 
 #define COMPSTATENAME "compstate"
 
-static struct compparam *
-addcompparams(struct compparam *cp)
+static void
+addcompparams(struct compparam *cp, Param *pp)
 {
-    Param *pp = comppms + (cp - compparams);
-
     for (; cp->name; cp++, pp++) {
-	Param pm = createparam(cp->name, cp->type | PM_SPECIAL | PM_REMOVABLE);
+	Param pm = createparam(cp->name,
+			       cp->type |PM_SPECIAL|PM_REMOVABLE|PM_LOCAL);
 	if (!pm)
 	    pm = (Param) paramtab->getnode(paramtab, cp->name);
 	DPUTS(!pm, "param not set in addcompparams");
 
 	*pp = pm;
-	pm->level = locallevel;
+	pm->level = locallevel + 1;
 	if ((pm->u.data = cp->var)) {
 	    switch(PM_TYPE(cp->type)) {
 	    case PM_SCALAR:
@@ -2213,31 +2250,30 @@ addcompparams(struct compparam *cp)
 	}
 	pm->unsetfn = compunsetfn;
     }
-    return cp;
 }
 
 /**/
 void
 makecompparams(void)
 {
-    struct compparam *cp;
     Param cpm;
     HashTable tht;
 
-    cp = addcompparams(compparams);
+    addcompparams(comprparams, comprpms);
 
-    if (!(cpm = createparam(COMPSTATENAME, PM_SPECIAL|PM_REMOVABLE|PM_HASHED)))
+    if (!(cpm = createparam(COMPSTATENAME,
+			    PM_SPECIAL|PM_REMOVABLE|PM_LOCAL|PM_HASHED)))
 	cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME);
     DPUTS(!cpm, "param not set in makecompparams");
 
-    comppms[cp - compparams] = cpm;
+    comprpms[CPN_COMPSTATE] = cpm;
     tht = paramtab;
     cpm->level = locallevel;
     cpm->gets.hfn = get_compstate;
     cpm->sets.hfn = set_compstate;
     cpm->unsetfn = compunsetfn;
-    cpm->u.hash = paramtab = newparamtable(17, COMPSTATENAME);
-    addcompparams(cp + 1);
+    cpm->u.hash = paramtab = newparamtable(31, COMPSTATENAME);
+    addcompparams(compkparams, compkpms);
     paramtab = tht;
 }
 
@@ -2261,15 +2297,15 @@ set_compstate(Param pm, HashTable ht)
 
     for (i = 0; i < ht->hsize; i++)
 	for (hn = ht->nodes[i]; hn; hn = hn->next)
-	    for (cp = compparams + CP_REALPARAMS,
-		 pp = comppms + CP_REALPARAMS; cp->name; cp++, pp++)
+	    for (cp = compkparams,
+		 pp = compkpms; cp->name; cp++, pp++)
 		if (!strcmp(hn->nam, cp->name)) {
 		    v.isarr = v.inv = v.a = 0;
 		    v.b = -1;
 		    v.arr = NULL;
 		    v.pm = (Param) hn;
 		    if (cp->type == PM_INTEGER)
-			*((long *) cp->var) = getintvalue(&v);
+			*((zlong *) cp->var) = getintvalue(&v);
 		    else if ((str = getstrvalue(&v))) {
 			zsfree(*((char **) cp->var));
 			*((char **) cp->var) = ztrdup(str);
@@ -2278,6 +2314,7 @@ set_compstate(Param pm, HashTable ht)
 
 		    break;
 		}
+    deleteparamtable(ht);
 }
 
 /**/
@@ -2288,7 +2325,7 @@ get_unambig(Param pm)
 }
 
 /**/
-static long
+static zlong
 get_unambig_curs(Param pm)
 {
     int c;
@@ -2316,20 +2353,25 @@ compunsetfn(Param pm, int exp)
 
 /**/
 void
-comp_setunset(int set, int unset)
+comp_setunset(int rset, int runset, int kset, int kunset)
 {
     Param *p;
 
-    if (!comppms)
-	return;
-
-    set &= CP_ALLMASK;
-    unset &= CP_ALLMASK;
-    for (p = comppms; set || unset; set >>= 1, unset >>= 1, p++) {
-	if (set & 1)
-	    (*p)->flags &= ~PM_UNSET;
-	if (unset & 1)
-	    (*p)->flags |= PM_UNSET;
+    if (comprpms && (rset >= 0 || runset >= 0)) {
+	for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) {
+	    if (rset & 1)
+		(*p)->flags &= ~PM_UNSET;
+	    if (runset & 1)
+		(*p)->flags |= PM_UNSET;
+	}
+    }
+    if (comprpms && (kset >= 0 || kunset >= 0)) {
+	for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) {
+	    if (kset & 1)
+		(*p)->flags &= ~PM_UNSET;
+	    if (kunset & 1)
+		(*p)->flags |= PM_UNSET;
+	}
     }
 }
 
@@ -2341,16 +2383,19 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	return 1;
     else {
 	char *orest, *opre, *osuf, *oipre, *oisuf, **owords;
-	long ocur;
-	int unset = 0, m, sm;
+	char *oqipre, *oqisuf, *oq, *oqi;
+	zlong ocur;
+	unsigned int runset = 0, kunset = 0, m, sm;
 	Param *pp;
 
 	m = CP_WORDS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 
-	    CP_IPREFIX | CP_RESTORE;
-	for (pp = comppms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
+	    CP_IPREFIX | CP_ISUFFIX | CP_QIPREFIX | CP_QISUFFIX;
+	for (pp = comprpms, sm = 1; m; pp++, m >>= 1, sm <<= 1) {
 	    if ((m & 1) && ((*pp)->flags & PM_UNSET))
-		unset |= sm;
+		runset |= sm;
 	}
+	if (compkpms[CPN_RESTORE]->flags & PM_UNSET)
+	    kunset = CP_RESTORE;
 	orest = comprestore;
 	comprestore = ztrdup("auto");
 	ocur = compcurrent;
@@ -2358,6 +2403,10 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	osuf = dupstring(compsuffix);
 	oipre = dupstring(compiprefix);
 	oisuf = dupstring(compisuffix);
+	oqipre = dupstring(compqiprefix);
+	oqisuf = dupstring(compqisuffix);
+	oq = dupstring(compquote);
+	oqi = dupstring(compquoting);
 
 	HEAPALLOC {
 	    owords = arrdup(compwords);
@@ -2375,17 +2424,27 @@ comp_wrapper(List list, FuncWrap w, char *name)
 	    compiprefix = ztrdup(oipre);
 	    zsfree(compisuffix);
 	    compisuffix = ztrdup(oisuf);
+	    zsfree(compqiprefix);
+	    compqiprefix = ztrdup(oqipre);
+	    zsfree(compqisuffix);
+	    compqisuffix = ztrdup(oqisuf);
+	    zsfree(compquote);
+	    compquote = ztrdup(oq);
+	    zsfree(compquoting);
+	    compquoting = ztrdup(oqi);
 	    freearray(compwords);
 	    PERMALLOC {
 		compwords = arrdup(owords);
 	    } LASTALLOC;
 	    comp_setunset(CP_COMPSTATE |
-			  (~unset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
-				     CP_SUFFIX | CP_IPREFIX | CP_RESTORE)),
-			  unset);
+			  (~runset & (CP_WORDS | CP_CURRENT | CP_PREFIX |
+				     CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX |
+				     CP_QIPREFIX | CP_QISUFFIX)),
+			  (runset & CP_ALLREALS),
+			  (~kunset & CP_RESTORE), (kunset & CP_ALLKEYS));
 	} else
-	    comp_setunset(CP_COMPSTATE | (~unset & CP_RESTORE),
-			  (unset & CP_RESTORE));
+	    comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE),
+			  (kunset & CP_RESTORE));
 	zsfree(comprestore);
 	comprestore = orest;
 
@@ -2410,10 +2469,10 @@ cond_psfix(char **a, int id)
 {
     if (comp_check()) {
 	if (a[1])
-	    return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1),
+	    return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1, 1),
 				0, NULL, 0);
 	else
-	    return do_comp_vars(id, -1, cond_str(a, 0), 0, NULL, 0);
+	    return do_comp_vars(id, -1, cond_str(a, 0, 1), 0, NULL, 0);
     }
     return 0;
 }
@@ -2422,8 +2481,8 @@ cond_psfix(char **a, int id)
 static int
 cond_range(char **a, int id)
 {
-    return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0), 0,
-			(id ? cond_str(a, 1) : NULL), 0);
+    return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0, 1), 0,
+			(id ? cond_str(a, 1, 1) : NULL), 0);
 }
 
 static struct builtin bintab[] = {
diff --git a/Src/cond.c b/Src/cond.c
index 00beb8e65..a4b652fee 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -42,6 +42,7 @@ int
 evalcond(Cond c)
 {
     struct stat *st;
+    char *left, *right = NULL;
 
     switch (c->type) {
     case COND_NOT:
@@ -103,107 +104,109 @@ evalcond(Cond c)
 	    return 0;
 	}
     }
-    singsub((char **)&c->left);
-    untokenize(c->left);
+    left = dupstring((char *) c->left);
+    singsub(&left);
+    untokenize(left);
     if (c->right) {
-	singsub((char **)&c->right);
+	right = dupstring((char *) c->right);
+	singsub(&right);
 	if (c->type != COND_STREQ && c->type != COND_STRNEQ)
-	    untokenize(c->right);
+	    untokenize(right);
     }
 
     if (tracingcond) {
 	if (c->type < COND_MOD) {
-	    char *rt = (char *)c->right;
+	    char *rt = (char *)right;
 	    if (c->type == COND_STREQ || c->type == COND_STRNEQ) {
 		rt = dupstring(rt);
 		untokenize(rt);
 	    }
-	    fprintf(stderr, " %s %s %s", (char *)c->left, condstr[c->type],
+	    fprintf(stderr, " %s %s %s", (char *)left, condstr[c->type],
 		    rt);
 	} else
-	    fprintf(stderr, " -%c %s", c->type, (char *)c->left);
+	    fprintf(stderr, " -%c %s", c->type, (char *)left);
     }
 
     switch (c->type) {
     case COND_STREQ:
-	return matchpat(c->left, c->right);
+	return matchpat(left, right);
     case COND_STRNEQ:
-	return !matchpat(c->left, c->right);
+	return !matchpat(left, right);
     case COND_STRLT:
-	return strcmp(c->left, c->right) < 0;
+	return strcmp(left, right) < 0;
     case COND_STRGTR:
-	return strcmp(c->left, c->right) > 0;
+	return strcmp(left, right) > 0;
     case 'e':
     case 'a':
-	return (doaccess(c->left, F_OK));
+	return (doaccess(left, F_OK));
     case 'b':
-	return (S_ISBLK(dostat(c->left)));
+	return (S_ISBLK(dostat(left)));
     case 'c':
-	return (S_ISCHR(dostat(c->left)));
+	return (S_ISCHR(dostat(left)));
     case 'd':
-	return (S_ISDIR(dostat(c->left)));
+	return (S_ISDIR(dostat(left)));
     case 'f':
-	return (S_ISREG(dostat(c->left)));
+	return (S_ISREG(dostat(left)));
     case 'g':
-	return (!!(dostat(c->left) & S_ISGID));
+	return (!!(dostat(left) & S_ISGID));
     case 'k':
-	return (!!(dostat(c->left) & S_ISVTX));
+	return (!!(dostat(left) & S_ISVTX));
     case 'n':
-	return (!!strlen(c->left));
+	return (!!strlen(left));
     case 'o':
-	return (optison(c->left));
+	return (optison(left));
     case 'p':
-	return (S_ISFIFO(dostat(c->left)));
+	return (S_ISFIFO(dostat(left)));
     case 'r':
-	return (doaccess(c->left, R_OK));
+	return (doaccess(left, R_OK));
     case 's':
-	return ((st = getstat(c->left)) && !!(st->st_size));
+	return ((st = getstat(left)) && !!(st->st_size));
     case 'S':
-	return (S_ISSOCK(dostat(c->left)));
+	return (S_ISSOCK(dostat(left)));
     case 'u':
-	return (!!(dostat(c->left) & S_ISUID));
+	return (!!(dostat(left) & S_ISUID));
     case 'w':
-	return (doaccess(c->left, W_OK));
+	return (doaccess(left, W_OK));
     case 'x':
 	if (privasserted()) {
-	    mode_t mode = dostat(c->left);
+	    mode_t mode = dostat(left);
 	    return (mode & S_IXUGO) || S_ISDIR(mode);
 	}
-	return doaccess(c->left, X_OK);
+	return doaccess(left, X_OK);
     case 'z':
-	return (!strlen(c->left));
+	return (!strlen(left));
     case 'h':
     case 'L':
-	return (S_ISLNK(dolstat(c->left)));
+	return (S_ISLNK(dolstat(left)));
     case 'O':
-	return ((st = getstat(c->left)) && st->st_uid == geteuid());
+	return ((st = getstat(left)) && st->st_uid == geteuid());
     case 'G':
-	return ((st = getstat(c->left)) && st->st_gid == getegid());
+	return ((st = getstat(left)) && st->st_gid == getegid());
     case 'N':
-	return ((st = getstat(c->left)) && st->st_atime <= st->st_mtime);
+	return ((st = getstat(left)) && st->st_atime <= st->st_mtime);
     case 't':
-	return isatty(matheval(c->left));
+	return isatty(matheval(left));
     case COND_EQ:
-	return matheval(c->left) == matheval(c->right);
+	return matheval(left) == matheval(right);
     case COND_NE:
-	return matheval(c->left) != matheval(c->right);
+	return matheval(left) != matheval(right);
     case COND_LT:
-	return matheval(c->left) < matheval(c->right);
+	return matheval(left) < matheval(right);
     case COND_GT:
-	return matheval(c->left) > matheval(c->right);
+	return matheval(left) > matheval(right);
     case COND_LE:
-	return matheval(c->left) <= matheval(c->right);
+	return matheval(left) <= matheval(right);
     case COND_GE:
-	return matheval(c->left) >= matheval(c->right);
+	return matheval(left) >= matheval(right);
     case COND_NT:
     case COND_OT:
 	{
 	    time_t a;
 
-	    if (!(st = getstat(c->left)))
+	    if (!(st = getstat(left)))
 		return 0;
 	    a = st->st_mtime;
-	    if (!(st = getstat(c->right)))
+	    if (!(st = getstat(right)))
 		return 0;
 	    return (c->type == COND_NT) ? a > st->st_mtime : a < st->st_mtime;
 	}
@@ -212,11 +215,11 @@ evalcond(Cond c)
 	    dev_t d;
 	    ino_t i;
 
-	    if (!(st = getstat(c->left)))
+	    if (!(st = getstat(left)))
 		return 0;
 	    d = st->st_dev;
 	    i = st->st_ino;
-	    if (!(st = getstat(c->right)))
+	    if (!(st = getstat(right)))
 		return 0;
 	    return d == st->st_dev && i == st->st_ino;
 	}
@@ -300,18 +303,19 @@ optison(char *s)
 
 /**/
 char *
-cond_str(char **args, int num)
+cond_str(char **args, int num, int raw)
 {
     char *s = args[num];
 
     singsub(&s);
-    untokenize(s);
+    if (!raw)
+	untokenize(s);
 
     return s;
 }
 
 /**/
-long
+zlong
 cond_val(char **args, int num)
 {
     char *s = args[num];
diff --git a/Util/zsh-development-guide b/Util/zsh-development-guide
index f779b17b3..4ec4ff079 100644
--- a/Util/zsh-development-guide
+++ b/Util/zsh-development-guide
@@ -17,12 +17,13 @@ Patches
 
 * Send all patches to the mailing list rather than directly to me.
 
-* Send only context diffs "diff -c oldfile newfile".  They are much
-  easier to read and understand while also allowing the patch program
-  to patch more intelligently.  Please make sure the filenames in
-  the diff header are relative to the top-level directory of the zsh
-  distribution; for example, it should say "Src/init.c" rather than
-  "init.c" or "zsh/Src/init.c".
+* Send only context diffs "diff -c oldfile newfile" or unified diffs
+  "diff -u oldfile newfile".  They are much easier to read and
+  understand while also allowing the patch program to patch more
+  intelligently.  Please make sure the filenames in the diff header
+  are relative to the top-level directory of the zsh distribution; for
+  example, it should say "Src/init.c" rather than "init.c" or
+  "zsh/Src/init.c".
 
 * Please put only one bug fix or feature enhancement in a single patch and
   only one patch per mail message.  This helps me to multiplex the many
@@ -127,6 +128,7 @@ variables:
   - 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)
@@ -137,7 +139,7 @@ Be sure to put the values in quotes. For further enlightenment have a
 look at the `mkmakemod.sh' script in the Src directory of the
 distribution.
 
-Modules have to define four functions which will automatically called
+Modules have to define four functions which will be called automatically
 by the zsh core. The first one, named `setup_foo' for a module named
 `foo', should set up any data needed in the module, at least any data
 other modules may be interested in. The second one, named `boot_foo',
@@ -283,11 +285,12 @@ Note that no preprocessing is done on the strings. This means that
 no substitutions are performed on them and that they will be
 tokenized. There are three helper functions available:
 
-  - char *cond_str(args, num)
+  - char *cond_str(args, num, raw)
     The first argument is the array of strings the handler function
     got as an argument and the second one is an index into this array.
     The return value is the num'th string from the array with
-    substitutions performed and untokenized.
+    substitutions performed. If the last argument is zero, the string
+    will also be untokenized.
   - long cond_val(args, num)
     The arguments are the same as for cond_str(). The return value is
     the result of the mathematical evaluation of the num'th string
@@ -323,6 +326,226 @@ almost exactly the same as for builtins, using the functions
 Arguments and return values are the same as for the functions for
 builtins.
 
+For defining parameters, a module can call `createparam()' directly or 
+use a table to describe them, e.g.:
+
+  static struct paramdef patab[] = {
+    PARAMDEF("foo", PM_INTEGER, NULL, get_foo, set_foo, unset_foo),
+    INTPARAMDEF("exint", &intparam),
+    STRPARAMDEF("exstr", &strparam),
+    ARRPARAMDEF("exarr", &arrparam),
+  };
+
+There are four macros used:
+
+  - PARAMDEF() gets as arguments:
+    - the name of the parameter
+    - the parameter flags to set for it (from the PM_* flags defined
+      in zsh.h)
+    - optionally a pointer to a variable holding the value of the
+      parameter
+    - three functions that will be used to get the value of the
+      parameter, store a value in the parameter, and unset the
+      parameter
+  - the other macros provide simple ways to define the most common
+    types of parameters; they get the name of the parameter and a
+    pointer to a variable holding the value as arguments; they are
+    used to define integer-, scalar-, and array-parameters, so the
+    variables whose addresses are given should be of type `long',
+    `char *', and `char **', respectively
+
+For a description of how to write functions for getting or setting the 
+value of parameters, or how to write a function to unset a parameter,
+see the description of the following functions in the `params.c' file:
+
+  - `intvargetfn()' and `intvarsetfn()' for integer parameters
+  - `strvargetfn()' and `strvarsetfn()' for scalar parameters
+  - `arrvargetfn()' and `arrvarsetfn()' for array parameters
+  - `stdunsetfn()' for unsetting parameters
+
+Note that if one defines parameters using the last two macros (for
+scalars and arrays), the variable holding the value should be
+initialized to either `NULL' or to a a piece of memory created with
+`zalloc()'. But this memory should *not* be freed in the
+finish-function of the module because that will be taken care of by
+the `deleteparamdefs()' function described below.
+
+To register the parameters in the zsh core, the function
+`addparamdefs()' is called as in:
+
+  /**/
+  int
+  boot_example(Module m)
+  {
+    int ret;
+
+    ret = addparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab))
+    ...
+  }
+
+The arguments and the return value are as for the functions used to
+add builtins and condition codes and like these, it should be called
+in the boot-function of the module. To remove the parameters defined,
+the function `deleteparamdefs()' should be called, again with the same 
+arguments and the same return value as for the functions to remove
+builtins and condition codes:
+
+  /**/
+  int
+  cleanup_example(Module m)
+  {
+    deleteparamdefs(m->nam, patab, sizeof(patab)/sizeof(*patab));
+    ...
+  }
+
+Modules can also define function hooks. Other modules can then add
+functions to these hooks to make the first module call these functions
+instead of the default.
+
+Again, an array is used to define hooks:
+
+  static struct hookdef foohooks[] = {
+    HOOKDEF("foo", foofunc, 0),
+  };
+
+The first argument of the macro is the name of the hook. This name
+is used whenever the hook is used. The second argument is the default
+function for the hook or NULL if no default function exists. The
+last argument is used to define flags for the hook. Currently only one
+such flag is defined: `HOOKF_ALL'. If this flag is given and more than
+one function was added to the hook, all functions will be called
+(including the default function). Otherwise only the last function
+added will be called.
+
+The functions that can be used as default functions or that can be
+added to a hook have to be defined like:
+
+  /**/
+  static int
+  foofunc(Hookdef h, void *data)
+  {
+    ...
+  }
+
+The first argument is a pointer to the struct defining the hook. The
+second argument is an arbitrary pointer that is given to the function
+used to invoke hooks (see below).
+
+The functions to register and de-register hooks look like those for
+the other things that can be defined by modules:
+
+  /**/
+  int
+  boot_foo(Module m)
+  {
+    int ret;
+
+    ret = addhookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks))
+    ...
+  }
+  ...
+  /**/
+  int
+  cleanup_foo(Module m)
+  {
+    deletehookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks));
+    ...
+  }
+
+Modules that define hooks can invoke the function(s) registered for
+them by calling the function `runhook(name, data)'. The first argument 
+is the name of the hook and the second one is the pointer given to the 
+hook functions as their second argument. Hooks that have the `HOOKF_ALL' 
+flag call all function defined for them until one returns non-zero.
+The return value of `runhook()' is the return value of the last hook
+function called or zero if none was called.
+
+To add a function to a hook, the function `addhookfunc(name, func)' is 
+called with the name of the hook and a hook function as arguments.
+Deleting them is done by calling `deletehookfunc(name, func)' with the 
+same arguments as for the corresponding call to `addhookfunc()'.
+
+Alternative forms of the last three function are provided for hooks
+that are changed or called very often. These functions,
+`runhookdef(def, data)', `addhookdeffunc(def, func)', and
+`deletehookdeffunc(def, func)' get a pointer to the `hookdef'
+structure defining the hook instead of the name and otherwise behave
+like their counterparts.
+
+Modules can also define function hooks. Other modules can then add
+functions to these hooks to make the first module call these functions
+instead of the default.
+
+Again, an array is used to define hooks:
+
+  static struct hookdef foohooks[] = {
+    HOOKDEF("foo", foofunc, 0),
+  };
+
+The first argument of the macro is the name of the hook. This name
+is used whenever the hook is used. The second argument is the default
+function for the hook or NULL if no default function exists. The
+last argument is used to define flags for the hook. Currently only one
+such flag is defined: `HOOKF_ALL'. If this flag is given and more than
+one function was added to the hook, all functions will be called
+(including the default function). Otherwise only the last function
+added will be called.
+
+The functions that can be used as default functions or that can be
+added to a hook have to be defined like:
+
+  /**/
+  static int
+  foofunc(Hookdef h, void *data)
+  {
+    ...
+  }
+
+The first argument is a pointer to the struct defining the hook. The
+second argument is an arbitrary pointer that is given to the function
+used to invoke hooks (see below).
+
+The functions to register and de-register hooks look like those for
+the other things that can be defined by modules:
+
+  /**/
+  int
+  boot_foo(Module m)
+  {
+    int ret;
+
+    ret = addhookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks))
+    ...
+  }
+  ...
+  /**/
+  int
+  cleanup_foo(Module m)
+  {
+    deletehookdefs(m->nam, foohooks, sizeof(foohooks)/sizeof(*foohooks));
+    ...
+  }
+
+Modules that define hooks can invoke the function(s) registered for
+them by calling the function `runhook(name, data)'. The first argument 
+is the name of the hook and the second one is the pointer given to the 
+hook functions as their second argument. Hooks that have the `HOOKF_ALL' 
+flag call all function defined for them until one returns non-zero.
+The return value of `runhook()' is the return value of the last hook
+function called or zero if none was called.
+
+To add a function to a hook, the function `addhookfunc(name, func)' is 
+called with the name of the hook and a hook function as arguments.
+Deleting them is done by calling `deletehookfunc(name, func)' with the 
+same arguments as for the corresponding call to `addhookfunc()'.
+
+Alternative forms of the last three function are provided for hooks
+that are changed or called very often. These functions,
+`runhookdef(def, data)', `addhookdeffunc(def, func)', and
+`deletehookdeffunc(def, func)' get a pointer to the `hookdef'
+structure defining the hook instead of the name and otherwise behave
+like their counterparts.
+
 Finally, modules can define wrapper functions. These functions are
 called whenever a shell function is to be executed.
 
@@ -430,3 +653,21 @@ Documentation
   ocurring in the main text, "plugh" is a normal word that is being quoted
   (it's the user that says `plugh', not the documentation), and "xyzzy"
   is some text to be typed literally that is being quoted.
+
+* For multiple-line pieces of text that should not be filled, there are
+  various models.
+  - If the text is pure example, i.e. with no metasyntactic variables etc.,
+    it should be included within `example(...)'.  The text will be
+    indented, will not be filled and will be put into a fixed width font.
+  - If the text includes mixed fonts, it should be included within
+    `indent(...)'.  The text is now filled unless `nofill(...)' is also
+    used, and explicit font-changing commands are required inside.
+  - If the text appears inside some other format, such as for example the
+    `item()' list structure, then the instruction `nofill(...)', which
+    simply turns off filling should be used; as with `indent(...)',
+    explicit font changing commands are required.  This can be used
+    without `indent()' when no identation is required, e.g. if the
+    accumulated indentation would otherwise be too long.
+  All the above should appear on their own, separated by newlines from the
+  surrounding text.  No extra newlines after the opening or before the
+  closing parenthesis are required.