From 6f93994a5aeb3a8290153ec159af35bbd96a6673 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 29 Feb 2012 09:57:40 +0000 Subject: 30299: "$*" was split with SHWORDSPLIT if IFS was empty or unset --- Src/subst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Src/subst.c') diff --git a/Src/subst.c b/Src/subst.c index b9229861b..04ef1a4fb 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1649,7 +1649,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) * This is one of the things that decides whether multsub * will produce an array, but in an extremely indirect fashion. */ - int nojoin = (pf_flags & PREFORK_SHWORDSPLIT) ? !(ifs && *ifs) : 0; + int nojoin = (pf_flags & PREFORK_SHWORDSPLIT) ? !(ifs && *ifs) && !qt : 0; /* * != 0 means ${...}, otherwise $... What works without braces * is largely a historical artefact (everything works with braces, -- cgit v1.2.3 From 4f142f279468a2d2d2500555e00649db9e74836f Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Mon, 16 Apr 2012 11:26:09 +0000 Subject: 30413: (q-) parameter flag should quote null string (q-q) etc. should be treated as errors --- ChangeLog | 8 +++++++- Src/subst.c | 4 ++++ Src/utils.c | 19 +++++++++---------- Test/D04parameter.ztst | 7 +++++++ 4 files changed, 27 insertions(+), 11 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 188a42cca..23fd23f31 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2012-04-16 Peter Stephenson + + * 30413: Src/params.c, Src/utils.c, Test/D04parameter.ztst: + (q-) parameter flag should quote the empty string and should + report an error with extra trailing q's. + 2012-04-15 Peter Stephenson * unposted: NEWS: incorporate the remainder of Bart's @@ -16202,5 +16208,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5631 $ +* $Revision: 1.5632 $ ***************************************************** diff --git a/Src/subst.c b/Src/subst.c index 04ef1a4fb..dac536f14 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -1828,6 +1828,10 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) quotemod = 1; quotetype = QT_SINGLE_OPTIONAL; } else { + if (quotetype == QT_SINGLE_OPTIONAL) { + /* extra q's after '-' not allowed */ + goto flagerr; + } quotemod++, quotetype++; } break; diff --git a/Src/utils.c b/Src/utils.c index a9b5c2c58..fb65ba815 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -4735,7 +4735,7 @@ quotestring(const char *s, char **e, int instring) char *v; int alloclen; char *buf; - int sf = 0, shownull; + int sf = 0, shownull = 0; /* * quotesub is used with QT_SINGLE_OPTIONAL. * quotesub = 0: mechanism not active @@ -4750,14 +4750,12 @@ quotestring(const char *s, char **e, int instring) const char *uend; slen = strlen(s); - if (instring == QT_BACKSLASH_SHOWNULL) { - shownull = 1; - instring = QT_BACKSLASH; - } else { - shownull = 0; - } switch (instring) { + case QT_BACKSLASH_SHOWNULL: + shownull = 1; + instring = QT_BACKSLASH; + /*FALLTHROUGH*/ case QT_BACKSLASH: /* * With QT_BACKSLASH we may need to use $'\300' stuff. @@ -4765,22 +4763,23 @@ quotestring(const char *s, char **e, int instring) * storage and using heap for correct size at end. */ alloclen = slen * 7 + 1; - if (!*s && shownull) - alloclen += 2; /* for '' */ break; case QT_SINGLE_OPTIONAL: /* * Here, we may need to add single quotes. + * Always show empty strings. */ alloclen = slen * 4 + 3; - quotesub = 1; + quotesub = shownull = 1; break; default: alloclen = slen * 4 + 1; break; } + if (!*s && shownull) + alloclen += 2; /* for '' */ quotestart = v = buf = zshcalloc(alloclen); diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index cc2d6aecd..30e4ba0ab 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -385,6 +385,13 @@ >$'playing \'stupid\' "games" \\w\\i\\t\\h $quoting.' >'playing '\'stupid\'' "games" \w\i\t\h $quoting.' + x=( a '' '\b' 'c d' '$e' ) + print -r ${(q)x} + print -r ${(q-)x} +0:Another ${(q...)...} test +>a '' \\b c\ d \$e +>a '' '\b' 'c d' '$e' + print -r -- ${(q-):-foo} print -r -- ${(q-):-foo bar} print -r -- ${(q-):-"*(.)"} -- cgit v1.2.3 From 5eb53bf88d3153510f0a5304e921b46419fe5721 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 22 Apr 2012 18:10:42 +0000 Subject: 30431 with typo in _typeset fix: add ${...:|...} and ${...:*...} operators, as documented --- ChangeLog | 10 +++++++++- Completion/Zsh/Command/_typeset | 6 ++++-- Doc/Zsh/expn.yo | 13 +++++++++++++ Src/params.c | 2 +- Src/subst.c | 43 +++++++++++++++++++++++++++++++++++++++++ Test/D04parameter.ztst | 23 ++++++++++++++++++++++ 6 files changed, 93 insertions(+), 4 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index ea0a02f06..64d199b15 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2012-04-22 Peter Stephenson + + * 30431 (typo in _typeset fixed): + Completion/Zsh/Command/_typeset, Doc/Zsh/expn.yo, ASrc/params.c, + Src/subst.c, Test/D04parameter.ztst: add ${...:|...} and + ${...:*...} operators for removal or inclusion of results + by array element. + 2012-04-21 Barton E. Schaefer * 30433: Src/hist.c: double backslash is not line continuation. @@ -16223,5 +16231,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5636 $ +* $Revision: 1.5637 $ ***************************************************** diff --git a/Completion/Zsh/Command/_typeset b/Completion/Zsh/Command/_typeset index 9c9165563..d44783d64 100644 --- a/Completion/Zsh/Command/_typeset +++ b/Completion/Zsh/Command/_typeset @@ -75,9 +75,11 @@ if [[ "$state" = vars_eq ]]; then if (( $+opt_args[-w] ));then _wanted files expl 'zwc file' _files -g '*.zwc(-.)' elif [[ $service = autoload || -n $opt_args[(i)-[uU]] ]]; then - args=(${^fpath}/*(:t)) + args=(${^fpath}/*(-.:t)) # Filter out functions already loaded or marked for autoload. - args=(${args:#(${(kj.|.)~functions})}) + local -a funckeys + funckeys=(${(k)functions}) + args=(${args:|funckeys}) _wanted functions expl 'shell function' compadd -a args else _functions diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo index 25c44f331..dbbdc5073 100644 --- a/Doc/Zsh/expn.yo +++ b/Doc/Zsh/expn.yo @@ -604,6 +604,19 @@ If var(name) is an array the matching array elements are removed (use the `tt((M))' flag to remove the non-matched elements). ) +item(tt(${)var(name)tt(:|)var(arrayname)tt(}))( +If var(arrayname) is the name (N.B., not contents) of an array +variable, then any elements contained in var(arrayname) are removed +from the substitution of var(name). If the substitution is scalar, +either because var(name) is a scalar variable or the expression is +quoted, the elements of var(arrayname) are instead tested against the +entire expression. +) +item(tt(${)var(name)tt(:*)var(arrayname)tt(}))( +Similar to the preceding subsitution, but in the opposite sense, +so that entries present in both the original substitution and as +elements of var(arrayname) are retained and others removed. +) xitem(tt(${)var(name)tt(:)var(offset)tt(})) item(tt(${)var(name)tt(:)var(offset)tt(:)var(length)tt(}))( This syntax gives effects similar to parameter subscripting diff --git a/Src/params.c b/Src/params.c index b18fb90a6..24062e03a 100644 --- a/Src/params.c +++ b/Src/params.c @@ -3493,7 +3493,7 @@ arrayuniq_freenode(HashNode hn) } /**/ -static HashTable +HashTable newuniqtable(zlong size) { HashTable ht = newhashtable((int)size, "arrayuniq", NULL); diff --git a/Src/subst.c b/Src/subst.c index dac536f14..82645ccfa 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2876,6 +2876,49 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } break; } + } else if (inbrace && (*s == '|' || *s == Bar || + *s == '*' || *s == Star)) { + int intersect = (*s == '*' || *s == Star); + char **compare = getaparam(++s), **ap, **apsrc; + if (compare) { + HashTable ht = newuniqtable(arrlen(compare)+1); + int present; + for (ap = compare; *ap; ap++) + (void)addhashnode2(ht, *ap, (HashNode) + zhalloc(sizeof(struct hashnode))); + if (!vunset && isarr) { + if (!copied) { + aval = arrdup(aval); + copied = 1; + } + for (ap = apsrc = aval; *apsrc; apsrc++) { + untokenize(*apsrc); + present = (gethashnode2(ht, *apsrc) != NULL); + if (intersect ? present : !present) { + if (ap != apsrc) { + *ap = *apsrc; + } + ap++; + } + } + *ap = NULL; + } else { + if (vunset) { + if (unset(UNSET)) { + *idend = '\0'; + zerr("%s: parameter not set", idbeg); + deletehashtable(ht); + return NULL; + } + val = dupstring(""); + } else { + present = (gethashnode2(ht, val) != NULL); + if (intersect ? !present : present) + val = dupstring(""); + } + } + deletehashtable(ht); + } } else { /* no ${...=...} or anything, but possible modifiers. */ /* * Handler ${+...}. TODO: strange, why do we handle this only diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index 30e4ba0ab..d5a6a403e 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -169,6 +169,29 @@ >a-string-with-slashes >a-string-with-slashes + args=('one' '#foo' '(bar' "'three'" two) + mod=('#foo' '(bar' "'three'" sir_not_appearing_in_this_film) + print ${args:|mod} + print ${args:*mod} + print "${(@)args:|mod}" + print "${(@)args:*mod}" + args=(two words) + mod=('one word' 'two words') + print "${args:|mod}" + print "${args:*mod}" + scalar='two words' + print ${scalar:|mod} + print ${scalar:*mod} +0:"|" array exclusion and "*" array intersection +>one two +>#foo (bar 'three' +>one two +>#foo (bar 'three' +> +>two words +> +>two words + str1='twocubed' array=(the number of protons in an oxygen nucleus) print $#str1 ${#str1} "$#str1 ${#str1}" $#array ${#array} "$#array ${#array}" -- cgit v1.2.3 From cb4ff5e9703d6641b10ca053f1caad2a8b19d2f9 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 22 Apr 2012 18:39:53 +0000 Subject: 30439: ${...:*...} with nonexistent or non-array after * should return no results --- ChangeLog | 8 ++++++-- Src/subst.c | 13 +++++++++++++ Test/D04parameter.ztst | 5 +++++ 3 files changed, 24 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 64d199b15..5c3b37fba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,11 @@ 2012-04-22 Peter Stephenson + * Test/D04parameter.ztst: 30439: Src/subst.c, + Test/D04parameter.ztst: ${...:*...} with nonexistent or + non-array variable second should return no results. + * 30431 (typo in _typeset fixed): - Completion/Zsh/Command/_typeset, Doc/Zsh/expn.yo, ASrc/params.c, + Completion/Zsh/Command/_typeset, Doc/Zsh/expn.yo, Src/params.c, Src/subst.c, Test/D04parameter.ztst: add ${...:|...} and ${...:*...} operators for removal or inclusion of results by array element. @@ -16231,5 +16235,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5637 $ +* $Revision: 1.5638 $ ***************************************************** diff --git a/Src/subst.c b/Src/subst.c index 82645ccfa..079d9efde 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2918,6 +2918,19 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } } deletehashtable(ht); + } else if (intersect) { + /* + * The intersection with nothing is nothing... + * Seems a bit pointless complaining that the first + * expression is unset here if the second is, too. + */ + if (!vunset) { + if (isarr) { + aval = mkarray(NULL); + } else { + val = dupstring(""); + } + } } } else { /* no ${...=...} or anything, but possible modifiers. */ /* diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst index d5a6a403e..cdeb15bfd 100644 --- a/Test/D04parameter.ztst +++ b/Test/D04parameter.ztst @@ -182,6 +182,9 @@ scalar='two words' print ${scalar:|mod} print ${scalar:*mod} + print ${args:*nonexistent} + empty= + print ${args:*empty} 0:"|" array exclusion and "*" array intersection >one two >#foo (bar 'three' @@ -191,6 +194,8 @@ >two words > >two words +> +> str1='twocubed' array=(the number of protons in an oxygen nucleus) -- cgit v1.2.3 From e49e41725abbd851e501855c4139b4826093ba0d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Sun, 22 Apr 2012 20:49:39 +0000 Subject: unposted: add test for valid identifier to 30431 --- ChangeLog | 4 +++- Src/subst.c | 9 ++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) (limited to 'Src/subst.c') diff --git a/ChangeLog b/ChangeLog index 5c3b37fba..c23237baa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2012-04-22 Peter Stephenson + * unposted: Src/subst.c: add test for valid identifier to 30431. + * Test/D04parameter.ztst: 30439: Src/subst.c, Test/D04parameter.ztst: ${...:*...} with nonexistent or non-array variable second should return no results. @@ -16235,5 +16237,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5638 $ +* $Revision: 1.5639 $ ***************************************************** diff --git a/Src/subst.c b/Src/subst.c index 079d9efde..932f41287 100644 --- a/Src/subst.c +++ b/Src/subst.c @@ -2879,7 +2879,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags) } else if (inbrace && (*s == '|' || *s == Bar || *s == '*' || *s == Star)) { int intersect = (*s == '*' || *s == Star); - char **compare = getaparam(++s), **ap, **apsrc; + char **compare, **ap, **apsrc; + ++s; + if (*itype_end(s, IIDENT, 0)) { + untokenize(s); + zerr("not an identifier: %s", s); + return NULL; + } + compare = getaparam(s); if (compare) { HashTable ht = newuniqtable(arrlen(compare)+1); int present; -- cgit v1.2.3