diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | Doc/Zsh/builtins.yo | 34 | ||||
-rw-r--r-- | Src/builtin.c | 41 | ||||
-rw-r--r-- | Src/params.c | 79 | ||||
-rw-r--r-- | Src/utils.c | 22 | ||||
-rw-r--r-- | Src/zsh.h | 26 |
6 files changed, 160 insertions, 46 deletions
diff --git a/ChangeLog b/ChangeLog index 25c4157b6..e24c905b9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2003-09-24 Peter Stephenson <pws@csr.com> + * 19129: Doc/Zsh/builtins.yo, Src/builtin.c, Src/params.c, + Src/utils.c, Src/zsh.h: extra tie arguemnt in + "typeset -T PAGER pager ' '" used for joining and splitting. + * unposted: Completion/Unix/Command/_perforce: improve handling of label completion: now faster and uses filename to narrow range if after `@'. diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo index b5217abaf..3f6f3c450 100644 --- a/Doc/Zsh/builtins.yo +++ b/Doc/Zsh/builtins.yo @@ -1160,7 +1160,7 @@ cindex(parameters, declaring) xitem(tt(typeset) [ {tt(PLUS())|tt(-)}tt(AEFHLRUZafghilprtuxm) [var(n)]] [ \ var(name)[tt(=)var(value)] ... ]) item(tt(typeset) -T [ {tt(PLUS()|tt(-))}tt(LRUZrux) ] \ - var(SCALAR)[tt(=)var(value)] var(array))( + var(SCALAR)[tt(=)var(value)] var(array) tt([) var(sep) tt(]))( Set or display attributes and values for shell parameters. A parameter is created for each var(name) that does not already refer @@ -1189,20 +1189,24 @@ separately for arrays and associative arrays), regardless of other flags and options. Note that the tt(-h) flag on parameters is respected; no value will be shown for these parameters. -If the tt(-T) option is given, exactly two (or zero) var(name) -arguments must be present. They represent a scalar and an array (in -that order) that will be tied together in the manner of tt($PATH) and -tt($path). In other words, an array present in the latter variable -appears as a scalar with the elements of the array joined by colons in -the former. Only the scalar may have an initial value. Both the -scalar and the array may otherwise be manipulated as normal. If one -is unset, the other will automatically be unset too. There is no way -of untying the variables without unsetting them, or converting the -type of one of them with another tt(typeset) command; tt(+T) does not -work, assigning an array to var(SCALAR) is an error, and assigning a -scalar to var(array) sets it to be a single-element array. Note that -both `tt(typeset -xT ...)' and `tt(export -T ...)' work, but only the -scalar will be marked for export. +If the tt(-T) option is given, two or three arguments must be present (an +exception is that zero arguments are allowed to show the list of parameters +created in this fashion). The first two are the name of a scalar and an +array parameter (in that order) that will be tied together in the manner of +tt($PATH) and tt($path). The optional third argument is a single-character +separator which will be used to join the elements of the array to form the +scalar; if absent, a colon is used, as with tt($PATH). Only the first +character of the separator is significant; any remaining characters are +ignored. Only the scalar parameter may be assigned an initial value. Both +the scalar and the array may otherwise be manipulated as normal. If one is +unset, the other will automatically be unset too. There is no way of +untying the variables without unsetting them, or converting the type of one +of them with another tt(typeset) command; tt(+T) does not work, assigning +an array to var(SCALAR) is an error, and assigning a scalar to var(array) +sets it to be a single-element array. Note that both `tt(typeset -xT ...)' +and `tt(export -T ...)' work, but only the scalar will be marked for +export. Setting the value using the scalar version causes a split on all +separators (which cannot be quoted). The tt(-g) (global) flag is treated specially: it means that any resulting parameter will not be restricted to local scope. Note that this diff --git a/Src/builtin.c b/Src/builtin.c index 62426facb..988a342fd 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -1677,7 +1677,7 @@ enum { static Param typeset_single(char *cname, char *pname, Param pm, int func, int on, int off, int roff, char *value, Param altpm, - Options ops, int auxlen) + Options ops, int auxlen, int joinchar) { int usepm, tc, keeplocal = 0, newspecial = NS_NONE, readonly; char *subscript; @@ -1997,9 +1997,17 @@ typeset_single(char *cname, char *pname, Param pm, int func, * to make sure we only ever use the colonarr functions * when u.data is correctly set. */ - pm->sets.cfn = colonarrsetfn; - pm->gets.cfn = colonarrgetfn; - pm->u.data = &altpm->u.arr; + struct tieddata *tdp = (struct tieddata *) + zalloc(sizeof(struct tieddata)); + if (!tdp) + return NULL; + tdp->joinchar = joinchar; + tdp->arrptr = &altpm->u.arr; + + pm->sets.cfn = tiedarrsetfn; + pm->gets.cfn = tiedarrgetfn; + pm->unsetfn = tiedarrunsetfn; + pm->u.data = tdp; } if (keeplocal) @@ -2155,6 +2163,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) Param apm; struct asgment asg0; char *oldval = NULL; + int joinchar; if (OPT_ISSET(ops,'m')) { zwarnnam(name, "incompatible options for -T", NULL, 0); @@ -2162,12 +2171,25 @@ bin_typeset(char *name, char **argv, Options ops, int func) return 1; } on &= ~off; - if (!argv[1] || argv[2]) { + if (!argv[1] || argv[3]) { zwarnnam(name, "-T requires names of scalar and array", NULL, 0); unqueue_signals(); return 1; } + /* + * Third argument, if given, is character used to join + * the elements of the array in the scalar. + */ + if (!argv[2]) + joinchar = ':'; + else if (!*argv[2]) + joinchar = 0; + else if (*argv[2] == Meta) + joinchar = argv[2][1] ^ 32; + else + joinchar = *argv[2]; + if (!(asg = getasg(argv[0]))) { unqueue_signals(); return 1; @@ -2212,7 +2234,8 @@ bin_typeset(char *name, char **argv, Options ops, int func) (Param)paramtab->getnode(paramtab, asg->name), func, (on | PM_ARRAY) & ~PM_EXPORTED, - off, roff, asg->value, NULL, ops, auxlen))) { + off, roff, asg->value, NULL, ops, auxlen, + 0))) { unqueue_signals(); return 1; } @@ -2224,7 +2247,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) (Param)paramtab->getnode(paramtab, asg0.name), func, on, off, roff, asg0.value, apm, - ops, auxlen))) { + ops, auxlen, joinchar))) { if (oldval) zsfree(oldval); unsetparam_pm(apm, 1, 1); @@ -2291,7 +2314,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) for (pmnode = firstnode(pmlist); pmnode; incnode(pmnode)) { pm = (Param) getdata(pmnode); if (!typeset_single(name, pm->nam, pm, func, on, off, roff, - asg->value, NULL, ops, auxlen)) + asg->value, NULL, ops, auxlen, 0)) returnval = 1; } } @@ -2306,7 +2329,7 @@ bin_typeset(char *name, char **argv, Options ops, int func) gethashnode2(paramtab, asg->name) : paramtab->getnode(paramtab, asg->name)), func, on, off, roff, asg->value, NULL, - ops, auxlen)) + ops, auxlen, 0)) returnval = 1; } unqueue_signals(); diff --git a/Src/params.c b/Src/params.c index a4890bcb0..079378180 100644 --- a/Src/params.c +++ b/Src/params.c @@ -2595,22 +2595,77 @@ void colonarrsetfn(Param pm, char *x) { char ***dptr = (char ***)pm->u.data; - /* - * If this is tied to a parameter (rather than internal) array, - * the array itself may be NULL. Otherwise, we have to make - * sure it doesn't ever get null. + * We have to make sure this is never NULL, since that + * can cause problems. */ if (*dptr) freearray(*dptr); - *dptr = x ? colonsplit(x, pm->flags & PM_UNIQUE) : - (pm->flags & PM_TIED) ? NULL : mkarray(NULL); + if (x) + *dptr = colonsplit(x, pm->flags & PM_UNIQUE); + else + *dptr = mkarray(NULL); if (pm->ename) arrfixenv(pm->nam, *dptr); zsfree(x); } /**/ +char * +tiedarrgetfn(Param pm) +{ + struct tieddata *dptr = (struct tieddata *)pm->u.data; + return *dptr->arrptr ? zjoin(*dptr->arrptr, dptr->joinchar, 1) : ""; +} + +/**/ +void +tiedarrsetfn(Param pm, char *x) +{ + struct tieddata *dptr = (struct tieddata *)pm->u.data; + + if (*dptr->arrptr) + freearray(*dptr->arrptr); + if (x) { + char sepbuf[3]; + if (imeta(dptr->joinchar)) + { + sepbuf[0] = Meta; + sepbuf[1] = dptr->joinchar; + sepbuf[2] = '\0'; + } + else + { + sepbuf[0] = dptr->joinchar; + sepbuf[1] = '\0'; + } + *dptr->arrptr = sepsplit(x, sepbuf, 0, 0); + if (pm->flags & PM_UNIQUE) + uniqarray(*dptr->arrptr); + } else + *dptr->arrptr = NULL; + if (pm->ename) + arrfixenv(pm->nam, *dptr->arrptr); + zsfree(x); +} + +/**/ +void +tiedarrunsetfn(Param pm, int exp) +{ + /* + * Special unset function because we allocated a struct tieddata + * in typeset_single to hold the special data which we now + * need to delete. + */ + pm->sets.cfn(pm, NULL); + zfree(pm->u.data, sizeof(struct tieddata)); + /* paranoia -- shouldn't need these, but in case we reuse the struct... */ + pm->u.data = NULL; + pm->flags &= ~PM_TIED; +} + +/**/ void uniqarray(char **x) { @@ -3187,6 +3242,7 @@ void arrfixenv(char *s, char **t) { Param pm; + int joinchar; if (t == path) cmdnamtab->emptytable(cmdnamtab); @@ -3208,8 +3264,15 @@ arrfixenv(char *s, char **t) * Do not "fix" parameters that were not exported */ - if (pm->flags & PM_EXPORTED) - pm->env = addenv(s, t ? zjoin(t, ':', 1) : "", pm->flags); + if (!(pm->flags & PM_EXPORTED)) + return; + + if (pm->flags & PM_TIED) + joinchar = ((struct tieddata *)pm->u.data)->joinchar; + else + joinchar = ':'; + + pm->env = addenv(s, t ? zjoin(t, joinchar, 1) : "", pm->flags); } diff --git a/Src/utils.c b/Src/utils.c index 0d9f9f9c3..56230fddb 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -1793,14 +1793,20 @@ zjoin(char **arr, int delim, int heap) char **s, *ret, *ptr; for (s = arr; *s; s++) - len += strlen(*s) + 1; + len += strlen(*s) + 1 + (imeta(delim) ? 1 : 0); if (!len) return heap? "" : ztrdup(""); ptr = ret = (heap ? (char *) hcalloc(len) : (char *) zcalloc(len)); for (s = arr; *s; s++) { strucpy(&ptr, *s); - if (delim) - *ptr++ = delim; + if (delim) { + if (imeta(delim)) { + *ptr++ = Meta; + *ptr++ = delim ^ 32; + } + else + *ptr++ = delim; + } } ptr[-1] = '\0'; return ret; @@ -1856,7 +1862,15 @@ skipwsep(char **s) return i; } -/* see findsep() below for handling of `quote' argument */ +/* + * haven't worked out what allownull does; it's passed down from + * sepsplit but all the cases it's used are either 0 or 1 without + * a comment. it seems to be something to do with the `nulstring' + * which i think is some kind of a metafication thing, so probably + * allownull's value is associated with whether we are using + * metafied strings. + * see findsep() below for handling of `quote' argument + */ /**/ mod_export char ** diff --git a/Src/zsh.h b/Src/zsh.h index 2dca01722..158717dea 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1156,6 +1156,12 @@ struct param { int level; /* if (old != NULL), level of localness */ }; +/* structure stored in struct param's u.data by tied arrays */ +struct tieddata { + char ***arrptr; /* pointer to corresponding array */ + int joinchar; /* character used to join arrays */ +}; + /* flags for parameters */ /* parameter types */ @@ -1193,16 +1199,16 @@ struct param { #define PM_TIED (1<<16) /* array tied to colon-path or v.v. */ /* Remaining flags do not correspond directly to command line arguments */ -#define PM_LOCAL (1<<17) /* this parameter will be made local */ -#define PM_SPECIAL (1<<18) /* special builtin parameter */ -#define PM_DONTIMPORT (1<<19) /* do not import this variable */ -#define PM_RESTRICTED (1<<20) /* cannot be changed in restricted mode */ -#define PM_UNSET (1<<21) /* has null value */ -#define PM_REMOVABLE (1<<22) /* special can be removed from paramtab */ -#define PM_AUTOLOAD (1<<23) /* autoloaded from module */ -#define PM_NORESTORE (1<<24) /* do not restore value of local special */ -#define PM_HASHELEM (1<<25) /* is a hash-element */ -#define PM_NAMEDDIR (1<<26) /* has a corresponding nameddirtab entry */ +#define PM_LOCAL (1<<21) /* this parameter will be made local */ +#define PM_SPECIAL (1<<22) /* special builtin parameter */ +#define PM_DONTIMPORT (1<<23) /* do not import this variable */ +#define PM_RESTRICTED (1<<24) /* cannot be changed in restricted mode */ +#define PM_UNSET (1<<25) /* has null value */ +#define PM_REMOVABLE (1<<26) /* special can be removed from paramtab */ +#define PM_AUTOLOAD (1<<27) /* autoloaded from module */ +#define PM_NORESTORE (1<<28) /* do not restore value of local special */ +#define PM_HASHELEM (1<<29) /* is a hash-element */ +#define PM_NAMEDDIR (1<<30) /* has a corresponding nameddirtab entry */ /* The option string corresponds to the first of the variables above */ #define TYPESET_OPTSTR "aiEFALRZlurtxUhHT" |