zsh-workers
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* Re: behavior of test true -a \( ! -a \)
  2024-03-25 17:36  3%         ` Bart Schaefer
@ 2024-04-03 13:59  5%           ` Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2024-04-03 13:59 UTC (permalink / raw)
  To: zsh-workers

On 2024-03-25 10:36:13 -0700, Bart Schaefer wrote:
> So in other words you're intentionally breaking this:
> 
> % test \( ! -a \) \)
> test: too many arguments

I suppose that with zsh 5.9, zsh sees that -a is a binary primary
(so, no contradictions with POSIX[*] since for the decision of the
matching parenthesis, at least 5 arguments need to be considered,
and this is where the results are unspecified).

[*] https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html

> In the name of "fixing" this:
> 
> % test \) -a \( ! -a \)
> 
> If we're arguing here based on spec, POSIX says the below should
> return 1 because $2 is a "binary primary" which takes precedence over
> parens, but it's broken with or without this patch:
> 
> % test \( -a \(
> test: parse error
> 
> To be fair, /bin/test on MacOS and /usr/bin/test on Ubuntu both choke
> (or not) in exactly those same cases.

In Debian:

With dash 0.5.12-6:

$ test \( -a \( ; echo $?
sh: 1: test: closing paren expected
2

With ksh93u+m 1.0.8-1:

$ test \( -a \( ; echo $?                                                      
ksh93: test: argument expected
2

With mksh 59c-35:

$ test \( -a \( ; echo $?
0

With bash 5.2.21-2:

vinc17@qaa:~$ test \( -a \( ; echo $?
0

With coreutils 9.4-3.1:

$ /usr/bin/test \( -a \( ; echo $?
/usr/bin/test: ‘-a’: unary operator expected
2

Note that POSIX says that the results are unspecified if
$1 is '(' and $3 is ')', but here both $1 and $3 are '('.
So the rule is:
  If $2 is a binary primary, perform the binary test of $1 and $3.

so that 0 is expected (only mksh and bash are correct).

IMHO, once you have reached a subsequence with at most 4 arguments
(like here), you should apply the POSIX rules. Doing otherwise is
surprising.

Said otherwise, I suppose that the following should work:
  * If there are at most 4 arguments, apply the POSIX rules.
  * If the first argument is an opening parenthesis, choose a rule
    to determine the matching closing parenthesis (say, arg n), or
    possibly regard this first argument as a string.
  * In the case of a real opening parenthesis, arg n needs to be the
    last argument or be followed by -a or -o. Apply the test algorithm
    on arg 2 to n-1, and in case of -a or -o, also on arg n+2 to the
    last arg (possibly with early termination in the parsing).
  * Otherwise:
    Choose a rule to determine the operator. Note that the obtained
    expression associated with this operator is necessarily followed
    by a -a or -o binary primary (say, arg n). Evaluate the expression
    and apply the test algorithm on arg n+1 to the last arg (possibly
    with early termination in the parsing).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 5%]

* Re: Aliases that ignore "noaliases"
  @ 2024-04-01 20:18  3% ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-04-01 20:18 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2024-04-01 12:59:09 -0700, Bart Schaefer:
> There are some cases where it would be nice to be able to declare an
> alias that "always works".  The most obvious recent example would be
>   alias nameref='typeset -n'

For the record, ksh used to have a number of builtin aliases,
but they were causing all sort of problems including breaking
POSIX compliance as things like

suspend() { ...; }

for instance would fail (as suspend used to be defined as a
suspend='kill -s STOP $$' (yes, with the missing quotes around
$$ (!), see https://github.com/att/ast/issues/10)

So they were eventually changed to being separate builtins (on
my request IIRC, though I can't find the bug report any
longer).

TLDR, I think zsh should avoid having builtin aliases.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-25 16:38  0%       ` Peter Stephenson
@ 2024-03-25 17:36  3%         ` Bart Schaefer
  2024-04-03 13:59  5%           ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2024-03-25 17:36 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Mon, Mar 25, 2024 at 9:38 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> > I suppose as long as we only look for ")" when we know there's one to
> > match we can probably get away with it without being too clever.  If
> > there's a ")" that logically needs to be treated as a string following a
> > "(" we're stuck but I think that's fair game.

So in other words you're intentionally breaking this:

% test \( ! -a \) \)
test: too many arguments

In the name of "fixing" this:

% test \) -a \( ! -a \)

If we're arguing here based on spec, POSIX says the below should
return 1 because $2 is a "binary primary" which takes precedence over
parens, but it's broken with or without this patch:

% test \( -a \(
test: parse error

To be fair, /bin/test on MacOS and /usr/bin/test on Ubuntu both choke
(or not) in exactly those same cases.

> Feel free to argue that the current behaviour of simply parsing
> parentheses in order and blindly trusting the result is actually a
> better bet

That's not how I'd describe the current behavior, but I'm arguing that
it's no worse and anything with more than 4 arguments is unspecified
anyway.


^ permalink raw reply	[relevance 3%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-21 11:29  0%     ` Peter Stephenson
  2024-03-21 12:18  3%       ` Vincent Lefevre
@ 2024-03-25 16:38  0%       ` Peter Stephenson
  2024-03-25 17:36  3%         ` Bart Schaefer
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2024-03-25 16:38 UTC (permalink / raw)
  To: zsh-workers

> On 21/03/2024 11:29 GMT Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> > On 21/03/2024 11:04 GMT Vincent Lefevre <vincent@vinc17.net> wrote:
> > On 2024-03-21 10:28:16 +0000, Peter Stephenson wrote:
> > > I haven't had time to go through this completely but I think somewhere
> > > near the root of the issue is this chunk in par_cond_2(), encountered at
> > > the opint we get to the "!":
> > > 
> > >     if (tok == BANG) {
> > > 	/*
> > > 	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
> > > 	 * are treated as "[string] [and] ..." and "[string] [or] ...".
> > > 	 */
> > > 	if (!(n_testargs > 2 && (check_cond(*testargs, "a") ||
> > > 				 check_cond(*testargs, "o"))))
> > > 	{
> > > 	    condlex();
> > > 	    ecadd(WCB_COND(COND_NOT, 0));
> > > 	    return par_cond_2();
> > > 	}
> > >     }
> > > 
> > > in which case it needs yet more logic to decide why we shouldn't treat !
> > > -a as a string followed by a logical "and" in this case.  To be clear,
> > > obviously *I* can see why you want that, the question is teaching the
> > > code without confusing it further.
> > 
> > Perhaps follow the coreutils logic. What matters is that if there is
> > a "(" argument, it tries to look at a matching ")" argument among the
> > following 3 arguments. So, for instance, if it can see
> > 
> >   ( arg2 arg3 )
> > 
> > (possibly with other arguments after the closing parenthesis[*]), it
> > will apply the POSIX test on 4 arguments.
> > 
> > [*] which can make sense if the 5th argument is -a or -o.
> 
> I suppose as long as we only look for ")" when we know there's one to
> match we can probably get away with it without being too clever.  If
> there's a ")" that logically needs to be treated as a string following a
> "(" we're stuck but I think that's fair game.
> 
> Something simple like: if we find a (, look for a matching ), so blindly
> count intervening ('s and )'s regardless of where they occur, and then
> NULL out the matching ) temporarily until we've parsed the expression
> inside.  If we don't find a matching one treat the ( as as a string.

This implements the above.  I don't think any of the subsequent
discussion has any impact on the effectiveness of this.  Because this is
only done when we've already identified a "(" as starting grouping,
looking for a ")" is benign --- failing to find it would mean the pattern
was invalid.  As Vincent already pointed out, assuming the pattern is
valid is a sensible strategy.  The remaining question is which ")" to
match if there are multiple.

I've added a check that "test \( = \)" returns 1.  This isn't affected
because as I said before three arguments are treated specially.
Possibly some more tests for non-pathological cases where parentheses do
grouping in test compatibility mode would be sensible.

There is inevitably a trade off: "test \( \) = \) \)" used to "work"
(test that the two inner closing parentheses were the same string) but
now doesn't (the first closing parenthesis ends the group started by the
first opening parenthesis).  That strikes me as OK as we're making the
less pathological case (the one where parentheses mean just one thing)
work.  However, it is a sign we're right on the edge of sanity, so I'm
not proposing to "fix" this any further.

Feel free to argue that the current behaviour of simply parsing
parentheses in order and blindly trusting the result is actually a
better bet, though I can't frankly see how, myself.  There is an
alternative strategy which is to assume the rightmost closing parenthesis
ends the outermost group.

Also feel free to come up with other pathologies.

pws

diff --git a/Src/parse.c b/Src/parse.c
index 3343656..1505b49 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2528,10 +2528,39 @@ par_cond_2(void)
     if (tok == INPAR) {
 	int r;
 
+	/*
+	 * Owing to ambiguuities in "test" compatibility mode, it's
+	 * safest to assume the INPAR has a corresponding OUTPAR
+	 * before trying to guess what intervening strings mean.
+	 */
+	char **endargptr = NULL, *endarg = NULL;
+	if (condlex == testlex) {
+	    char **argptr;
+	    int n_inpar = 1;
+
+	    for (argptr = testargs; *argptr; argptr++) {
+		if (!strcmp(*argptr, ")")) {
+		    if (!--n_inpar) {
+			endargptr = argptr;
+			endarg = *argptr;
+			*argptr = NULL;
+			break;
+		    }
+		} else if (!strcmp(*argptr, "(")) {
+		    ++n_inpar;
+		}
+	    }
+	}
+
 	condlex();
 	while (COND_SEP())
 	    condlex();
 	r = par_cond();
+	if (endargptr) {
+	    *endargptr = endarg;
+	    if (testargs == endargptr)
+		condlex();
+	}
 	while (COND_SEP())
 	    condlex();
 	if (tok != OUTPAR)
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index daea5b4..453fa1c 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -442,6 +442,14 @@ F:scenario if you encounter it.
 >in conjunction: 3
 ?(eval):6: no such option: invalidoption
 
+  test \( = \)
+1: test compatility mode doesn't do grouping with three arguments
+
+# This becomes [[ -n true && ( -n -a ) ]]
+# The test is to ensure the ! -a is analysed as two arguments.
+  test true -a \( ! -a \)
+1: test compatilibty mode is based on arguments inside parentheses
+
 %clean
   # This works around a bug in rm -f in some versions of Cygwin
   chmod 644 unmodish


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-25 10:23  0%         ` Vincent Lefevre
@ 2024-03-25 15:21  0%           ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2024-03-25 15:21 UTC (permalink / raw)
  To: zsh-workers

On Mon, Mar 25, 2024 at 3:24 AM Vincent Lefevre <vincent@vinc17.net> wrote:
>
> On 2024-03-23 15:41:33 -0700, Bart Schaefer wrote:
> > On Sat, Mar 23, 2024 at 3:20 PM Vincent Lefevre <vincent@vinc17.net> wrote:
> > >
> > > On 2024-03-23 14:48:36 -0700, Bart Schaefer wrote:
> > > > I'd therefore argue that it's actually
> > > >
> > > > % test \( ! -a \)
> > > >
> > > > that is wrong
> > >
> > > POSIX specifies what happens with up to 4 arguments.
> >
> > Ok, but
> >
> > % test \( ! -a \) \)
> >
> > has five [...]
>
> I meant that
>
>   test \( ! -a \)
>
> has four, thus fully specified and not wrong.

And I meant (in the follow-up, being unaware of the exact spec at
first) that I think it was wrong to specify it that way in the first
place.

I suspect that we're re-hashing an argument that's already been had on
austin-group and led to these constructs being first declared obsolete
and soon dropped.

> Concerning
>
>   test true -a \( ! -a \)
>
> I would say that if you decide that the first "-a" is an "and",
> then after this "-a", there remain exactly 4 arguments, so that
> for *consistency*, I think that the remaining 4 arguments should
> be interpreted exactly as in
>
>   test \( ! -a \)

So what about
  test true -a \( ! -a \) \)
??

Counting arguments just doesn't work.


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-23 22:41  0%       ` Bart Schaefer
  2024-03-23 23:33  4%         ` Lawrence Velázquez
@ 2024-03-25 10:23  0%         ` Vincent Lefevre
  2024-03-25 15:21  0%           ` Bart Schaefer
  1 sibling, 1 reply; 200+ results
From: Vincent Lefevre @ 2024-03-25 10:23 UTC (permalink / raw)
  To: zsh-workers

On 2024-03-23 15:41:33 -0700, Bart Schaefer wrote:
> On Sat, Mar 23, 2024 at 3:20 PM Vincent Lefevre <vincent@vinc17.net> wrote:
> >
> > On 2024-03-23 14:48:36 -0700, Bart Schaefer wrote:
> > > I'd therefore argue that it's actually
> > >
> > > % test \( ! -a \)
> > >
> > > that is wrong
> >
> > POSIX specifies what happens with up to 4 arguments.
> 
> Ok, but
> 
> % test \( ! -a \) \)
> 
> has five and
> 
> % test \( ! -a \) -a true
> 
> has six, and in neither case are the "first four" interpreted as you
> would have the "last four" interpreted in
> 
> % test true -a \( ! -a \)

I meant that

  test \( ! -a \)

has four, thus fully specified and not wrong.

Concerning

  test true -a \( ! -a \)

I would say that if you decide that the first "-a" is an "and",
then after this "-a", there remain exactly 4 arguments, so that
for *consistency*, I think that the remaining 4 arguments should
be interpreted exactly as in

  test \( ! -a \)

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-24  0:14  0%           ` Bart Schaefer
@ 2024-03-24  2:52  0%             ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2024-03-24  2:52 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

On Sat, Mar 23, 2024, at 8:14 PM, Bart Schaefer wrote:
> On Sat, Mar 23, 2024 at 4:33 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>>
>> The next version of POSIX will only specify what happens with four
>> arguments if the very first one is "!".  The "-a" and "-o" primaries
>> and the "(" and ")" operators have been removed.
>
> So, no "and"/"or" at all, and no grouping?  Or are they just demoted
> from "primary" and "operator" in some way?

The former -- everything marked "OB" in the current "test" spec [1]
has been completely excised from the upcoming one (although shells
can retain them as extensions to the standard, to avoid breaking
scripts).  The current "Application Usage" section [2] already
recommends that portable scripts stick to simpler "test" commands
connected with general shell syntax, like so:

	test -f "$foo" || { test ! "$bar" && test -d "$baz"; }

[1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
[2]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_16

-- 
vq


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-23 23:33  4%         ` Lawrence Velázquez
@ 2024-03-24  0:14  0%           ` Bart Schaefer
  2024-03-24  2:52  0%             ` Lawrence Velázquez
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2024-03-24  0:14 UTC (permalink / raw)
  To: Lawrence Velázquez; +Cc: zsh-workers

On Sat, Mar 23, 2024 at 4:33 PM Lawrence Velázquez <larryv@zsh.org> wrote:
>
> The next version of POSIX will only specify what happens with four
> arguments if the very first one is "!".  The "-a" and "-o" primaries
> and the "(" and ")" operators have been removed.

So, no "and"/"or" at all, and no grouping?  Or are they just demoted
from "primary" and "operator" in some way?


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-23 22:41  0%       ` Bart Schaefer
@ 2024-03-23 23:33  4%         ` Lawrence Velázquez
  2024-03-24  0:14  0%           ` Bart Schaefer
  2024-03-25 10:23  0%         ` Vincent Lefevre
  1 sibling, 1 reply; 200+ results
From: Lawrence Velázquez @ 2024-03-23 23:33 UTC (permalink / raw)
  To: zsh-workers

On Sat, Mar 23, 2024, at 6:41 PM, Bart Schaefer wrote:
> On Sat, Mar 23, 2024 at 3:20 PM Vincent Lefevre <vincent@vinc17.net> wrote:
>>
>> On 2024-03-23 14:48:36 -0700, Bart Schaefer wrote:
>> > I'd therefore argue that it's actually
>> >
>> > % test \( ! -a \)
>> >
>> > that is wrong
>>
>> POSIX specifies what happens with up to 4 arguments.

The next version of POSIX will only specify what happens with four
arguments if the very first one is "!".  The "-a" and "-o" primaries
and the "(" and ")" operators have been removed.

> Ok, but
>
> % test \( ! -a \) \)
>
> has five and
>
> % test \( ! -a \) -a true
>
> has six, and in neither case are the "first four" interpreted as you
> would have the "last four" interpreted in
>
> % test true -a \( ! -a \)
>
>> The idea is to
>> interpret the operators in a way so that the expression is meaningful
>
> The only way to do that is to (in effect) start counting arguments
> again when \( is encountered.  That changes the meaning of everything
> with an open paren and more than four words.  At what point do we
> stop?

The current version of POSIX leaves test(1) behavior with more than
4 arguments unspecified but says that:

	On XSI-conformant systems, combinations of primaries and
	operators shall be evaluated using the precedence and
	associativity rules described previously.  In addition, the
	string comparison binary primaries '=' and "!=" shall have
	a higher precedence than any unary primary.

I suspect that the Austin Group gave up on the whole thing once
they realized its general intractability.

-- 
vq


^ permalink raw reply	[relevance 4%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-23 22:20  3%     ` Vincent Lefevre
@ 2024-03-23 22:41  0%       ` Bart Schaefer
  2024-03-23 23:33  4%         ` Lawrence Velázquez
  2024-03-25 10:23  0%         ` Vincent Lefevre
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2024-03-23 22:41 UTC (permalink / raw)
  To: zsh-workers

On Sat, Mar 23, 2024 at 3:20 PM Vincent Lefevre <vincent@vinc17.net> wrote:
>
> On 2024-03-23 14:48:36 -0700, Bart Schaefer wrote:
> > I'd therefore argue that it's actually
> >
> > % test \( ! -a \)
> >
> > that is wrong
>
> POSIX specifies what happens with up to 4 arguments.

Ok, but

% test \( ! -a \) \)

has five and

% test \( ! -a \) -a true

has six, and in neither case are the "first four" interpreted as you
would have the "last four" interpreted in

% test true -a \( ! -a \)

> The idea is to
> interpret the operators in a way so that the expression is meaningful

The only way to do that is to (in effect) start counting arguments
again when \( is encountered.  That changes the meaning of everything
with an open paren and more than four words.  At what point do we
stop?


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  @ 2024-03-23 22:20  3%     ` Vincent Lefevre
  2024-03-23 22:41  0%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2024-03-23 22:20 UTC (permalink / raw)
  To: zsh-workers

On 2024-03-23 14:48:36 -0700, Bart Schaefer wrote:
> I'd therefore argue that it's actually
> 
> % test \( ! -a \)
> 
> that is wrong: It should be complaining of a missing close paren,
> rather than magically reverting to treating "!" as "not" (and also
> "-a" as a plain string).  It's entirely dependent on the count of
> arguments rather than on treating parens as tokens.

POSIX specifies what happens with up to 4 arguments. The idea is to
interpret the operators in a way so that the expression is meaningful
rather than having an incorrect syntax.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-21 11:29  0%     ` Peter Stephenson
@ 2024-03-21 12:18  3%       ` Vincent Lefevre
  2024-03-25 16:38  0%       ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Vincent Lefevre @ 2024-03-21 12:18 UTC (permalink / raw)
  To: zsh-workers

On 2024-03-21 11:29:39 +0000, Peter Stephenson wrote:
> I suppose as long as we only look for ")" when we know there's one to
> match we can probably get away with it without being too clever.  If
> there's a ")" that logically needs to be treated as a string following a
> "(" we're stuck but I think that's fair game.
> 
> Something simple like: if we find a (, look for a matching ), so blindly
> count intervening ('s and )'s regardless of where they occur, and then
> NULL out the matching ) temporarily until we've parsed the expression
> inside.  If we don't find a matching one treat the ( as as a string.

But be careful with the simple

  test \( = \)

which you may not want to change. This is currently the equality test,
thus returning false (1).

In POSIX, this special case is unspecified, but if the obsolescent
XSI option is supported, this should be the unary test of "=", thus
true (0) instead of false (1).

In practice, all implementations (including zsh) does

$ test \( = \) ; echo $?
1

i.e. seeing it as an equality test. This is rather surprising (but
perhaps more useful), as the goal of the XSI option was to support
parentheses, which implementations do; thus one could expect 0.

However, zsh differs for

  test true -a \( = \) ; echo $?

zsh still sees \( = \) as an equality test (it outputs 1), while
the other implementations output 0, probably because they perform
the unary test on "=" (which returns true, i.e. 0).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-21 11:04  3%   ` Vincent Lefevre
@ 2024-03-21 11:29  0%     ` Peter Stephenson
  2024-03-21 12:18  3%       ` Vincent Lefevre
  2024-03-25 16:38  0%       ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Peter Stephenson @ 2024-03-21 11:29 UTC (permalink / raw)
  To: zsh-workers

> On 21/03/2024 11:04 GMT Vincent Lefevre <vincent@vinc17.net> wrote:
> On 2024-03-21 10:28:16 +0000, Peter Stephenson wrote:
> > I haven't had time to go through this completely but I think somewhere
> > near the root of the issue is this chunk in par_cond_2(), encountered at
> > the opint we get to the "!":
> > 
> >     if (tok == BANG) {
> > 	/*
> > 	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
> > 	 * are treated as "[string] [and] ..." and "[string] [or] ...".
> > 	 */
> > 	if (!(n_testargs > 2 && (check_cond(*testargs, "a") ||
> > 				 check_cond(*testargs, "o"))))
> > 	{
> > 	    condlex();
> > 	    ecadd(WCB_COND(COND_NOT, 0));
> > 	    return par_cond_2();
> > 	}
> >     }
> > 
> > in which case it needs yet more logic to decide why we shouldn't treat !
> > -a as a string followed by a logical "and" in this case.  To be clear,
> > obviously *I* can see why you want that, the question is teaching the
> > code without confusing it further.
> 
> Perhaps follow the coreutils logic. What matters is that if there is
> a "(" argument, it tries to look at a matching ")" argument among the
> following 3 arguments. So, for instance, if it can see
> 
>   ( arg2 arg3 )
> 
> (possibly with other arguments after the closing parenthesis[*]), it
> will apply the POSIX test on 4 arguments.
> 
> [*] which can make sense if the 5th argument is -a or -o.

I suppose as long as we only look for ")" when we know there's one to
match we can probably get away with it without being too clever.  If
there's a ")" that logically needs to be treated as a string following a
"(" we're stuck but I think that's fair game.

Something simple like: if we find a (, look for a matching ), so blindly
count intervening ('s and )'s regardless of where they occur, and then
NULL out the matching ) temporarily until we've parsed the expression
inside.  If we don't find a matching one treat the ( as as a string.

pws


^ permalink raw reply	[relevance 0%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-21 10:28  0% ` Peter Stephenson
@ 2024-03-21 11:04  3%   ` Vincent Lefevre
  2024-03-21 11:29  0%     ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2024-03-21 11:04 UTC (permalink / raw)
  To: zsh-workers

On 2024-03-21 10:28:16 +0000, Peter Stephenson wrote:
> I haven't had time to go through this completely but I think somewhere
> near the root of the issue is this chunk in par_cond_2(), encountered at
> the opint we get to the "!":
> 
>     if (tok == BANG) {
> 	/*
> 	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
> 	 * are treated as "[string] [and] ..." and "[string] [or] ...".
> 	 */
> 	if (!(n_testargs > 2 && (check_cond(*testargs, "a") ||
> 				 check_cond(*testargs, "o"))))
> 	{
> 	    condlex();
> 	    ecadd(WCB_COND(COND_NOT, 0));
> 	    return par_cond_2();
> 	}
>     }
> 
> in which case it needs yet more logic to decide why we shouldn't treat !
> -a as a string followed by a logical "and" in this case.  To be clear,
> obviously *I* can see why you want that, the question is teaching the
> code without confusing it further.

Perhaps follow the coreutils logic. What matters is that if there is
a "(" argument, it tries to look at a matching ")" argument among the
following 3 arguments. So, for instance, if it can see

  ( arg2 arg3 )

(possibly with other arguments after the closing parenthesis[*]), it
will apply the POSIX test on 4 arguments.

[*] which can make sense if the 5th argument is -a or -o.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* Re: behavior of test true -a \( ! -a \)
  2024-03-21 10:07  3% behavior of test true -a \( ! -a \) Vincent Lefevre
@ 2024-03-21 10:28  0% ` Peter Stephenson
  2024-03-21 11:04  3%   ` Vincent Lefevre
    1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2024-03-21 10:28 UTC (permalink / raw)
  To: zsh-workers

> On 21/03/2024 10:07 GMT Vincent Lefevre <vincent@vinc17.net> wrote:
> I know that the "test" utility (builtin in zsh) is ambiguous,
> is not completely specified by POSIX and should not be used,
> but IMHO, it should behave in a sensible and consistent way.
> 
> The following with zsh 5.9 is inconsistent:
> 
> qaa% test \( ! -a \) ; echo $?
> 1
> qaa% test true -a \( ! -a \) ; echo $?
> test: argument expected
> 2

As you can imagine, trying to put some order on the ill-defined mess
here tends to mean moving the problems around rather than fixing them.

I haven't had time to go through this completely but I think somewhere
near the root of the issue is this chunk in par_cond_2(), encountered at
the opint we get to the "!":

    if (tok == BANG) {
	/*
	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
	 * are treated as "[string] [and] ..." and "[string] [or] ...".
	 */
	if (!(n_testargs > 2 && (check_cond(*testargs, "a") ||
				 check_cond(*testargs, "o"))))
	{
	    condlex();
	    ecadd(WCB_COND(COND_NOT, 0));
	    return par_cond_2();
	}
    }

in which case it needs yet more logic to decide why we shouldn't treat !
-a as a string followed by a logical "and" in this case.  To be clear,
obviously *I* can see why you want that, the question is teaching the
code without confusing it further.

pws


^ permalink raw reply	[relevance 0%]

* behavior of test true -a \( ! -a \)
@ 2024-03-21 10:07  3% Vincent Lefevre
  2024-03-21 10:28  0% ` Peter Stephenson
    0 siblings, 2 replies; 200+ results
From: Vincent Lefevre @ 2024-03-21 10:07 UTC (permalink / raw)
  To: zsh-workers

I know that the "test" utility (builtin in zsh) is ambiguous,
is not completely specified by POSIX and should not be used,
but IMHO, it should behave in a sensible and consistent way.

The following with zsh 5.9 is inconsistent:

qaa% test \( ! -a \) ; echo $?
1
qaa% test true -a \( ! -a \) ; echo $?
test: argument expected
2

In the second case, one should just get 1, like in the first case.

In 2008, I had noted at

  https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=421591#25

that zsh was returning 1 as expected. So it seems that this has
changed. This bug is about bash giving an error (like zsh now),
but note that with ash (BusyBox v1.36.1 sh), dash 0.5.12 and the
"test" command from the GNU coreutils 9.4, one gets 1 in these
two cases.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* [PATCH] More "typeset -p" and GLOBAL_EXPORT
  @ 2024-03-14  2:11  8%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2024-03-14  2:11 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 2205 bytes --]

On Tue, Mar 12, 2024 at 1:38 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> On Tue, Mar 12, 2024 at 1:26 PM Stephane Chazelas <stephane@chazelas.org> wrote:
> >
> > $ zsh -c 'a() { export a; a=3; typeset -p a; }; b() { local a=2; a; typeset -p a; }; a=1; b; typeset -p a'
> > export -x a=3
> > typeset -x a=3
> > typeset a=1
> >
> > That export -x seems bogus BTW as export doesn't accept the -x
> > option.
>
> Indeed, that's a bug in the printparamnode() routine.

That's not the only bug.  As demonstrated by B02typeset.ztst in the test
  no array/hash in POSIX export/readonly -p
with a declaration in a function of
   local -rx zsh_exported_readonly_scalar=1
the output of "export -p" is
  typeset -rx zsh_exported_readonly_scalar=1

However, "local" is supposed to supersede the GLOBAL_EXPORT option, so
that should have output one of
  typeset +g -rx zsh_exported_readonly_scalar=1
or
  local -rx zsh_exported_readonly_scalar=1

The attached patch changes this (using "local").  The POSIX mode output --
  export zsh_exported_readonly_scalar=1
-- is explained by a comment:
         * The zsh variants of export -p/readonly -p also report other
         * flags to indicate other attributes or scope. The POSIX variants
         * don't.

There is also an AFAICT insurmountable problem:
  innie() { typeset -p $1 }
  outie() { local -x $1; innie $1 }
  outie var
displays
  export var=''

That is "correct" in that var is not local to outie, but that
statement cannot be evaluated to restore the state of $var anywhere
other than from functions called by innie.  Conversely:
  innie() { print ${(tP)1} }
  outie var
displays
  scalar-local-export

Which is also "correct" but fibs about $var being local to innie.
Finally we have
  innie() { typeset +m $1 }
  outie var
which agrees with the (t) flag by reporting
  local exported var

And
  innie() { typeset -m $1 }
  outie var
yielding
  var=''

No mention of export at all.

These are all long-standing behaviors and haven't caused anyone a
problem yet that I know of, so I'm not suggesting anything change,
just pointing out that this patch doesn't address them.

[-- Attachment #2: printparamflags.txt --]
[-- Type: text/plain, Size: 2733 bytes --]

diff --git a/Src/params.c b/Src/params.c
index 973df3fe5..f65aa1e80 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6044,6 +6044,7 @@ printparamnode(HashNode hn, int printflags)
 {
     Param p = (Param) hn;
     Param peer = NULL;
+    int altname = 0;
 
     if (!(p->node.flags & PM_HASHELEM) &&
 	!(printflags & PRINT_WITH_NAMESPACE) && *(p->node.nam) == '.')
@@ -6089,16 +6090,26 @@ printparamnode(HashNode hn, int printflags)
 	if (printflags & PRINT_POSIX_EXPORT) {
 	    if (!(p->node.flags & PM_EXPORTED))
 		return;
+	    altname = 'x';
 	    printf("export ");
 	} else if (printflags & PRINT_POSIX_READONLY) {
 	    if (!(p->node.flags & PM_READONLY))
 		return;
+	    altname = 'r';
 	    printf("readonly ");
-	} else if (locallevel && p->level >= locallevel) {
-	    printf("typeset ");	    /* printf("local "); */
 	} else if ((p->node.flags & PM_EXPORTED) &&
 		   !(p->node.flags & (PM_ARRAY|PM_HASHED))) {
-	    printf("export ");
+	  if (p->level && p->level >= locallevel)
+		printf("local ");
+	    else {
+		altname = 'x';
+		printf("export ");
+	    }
+	} else if (locallevel && p->level >= locallevel) {
+	    if (p->node.flags & PM_EXPORTED)
+		printf("local ");
+	    else
+		printf("typeset ");	    /* printf("local "); */
 	} else if (locallevel) {
 	    printf("typeset -g ");
 	} else
@@ -6112,6 +6123,10 @@ printparamnode(HashNode hn, int printflags)
 
 	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
 	    int doprint = 0;
+
+	    if (altname && altname == pmptr->typeflag)
+		continue;
+
 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
 		if (p->level) {
 		    /*
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index d90f17d13..914eea92b 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -311,7 +311,7 @@
  print $OUTER
 0:Export of tied parameters
 >i:n:n:e:r
->typeset -xT OUTER outer=( i n n e r )
+>local -xT OUTER outer=( i n n e r )
 >typeset -aT OUTER outer=( i n n e r )
 >OUTER=i:n:n:e:r
 >outer=( i n n e r )
@@ -1099,12 +1099,12 @@
  }
 0: no array/hash in POSIX export/readonly -p
 >zsh:
->typeset -arx zsh_exported_readonly_array=( 2 )
->typeset -Arx zsh_exported_readonly_hash=( [3]=3 )
->typeset -rx zsh_exported_readonly_scalar=1
->typeset -arx zsh_exported_readonly_array=( 2 )
->typeset -Arx zsh_exported_readonly_hash=( [3]=3 )
->typeset -rx zsh_exported_readonly_scalar=1
+>local -arx zsh_exported_readonly_array=( 2 )
+>local -Arx zsh_exported_readonly_hash=( [3]=3 )
+>local -rx zsh_exported_readonly_scalar=1
+>local -arx zsh_exported_readonly_array=( 2 )
+>local -Arx zsh_exported_readonly_hash=( [3]=3 )
+>local -rx zsh_exported_readonly_scalar=1
 >sh:
 >export zsh_exported_readonly_scalar=1
 >readonly zsh_exported_readonly_scalar=1

^ permalink raw reply	[relevance 8%]

* Re: "typeset -p" and no_GLOBAL_EXPORT, other misc.
  @ 2024-03-12 20:06  4%     ` Stephane Chazelas
    1 sibling, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-03-12 20:06 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2024-03-12 11:32:41 -0700, Bart Schaefer:
[...]
> > bash-5.3$ f() { local i; integer i=2+2; echo "$i"; }
> > bash-5.3$ f
> >
> > bash-5.3$ echo $i
> > 4
> >
> > That "integer" changed the type of the global (outer-most) i
> > variable instead of that of its caller.
> 
> Looks like "integer" et al. in bash actually search for the parameter
> using the type (which corresponds to what zsh attempts to do when
> using -p), rather searching for the parameter name and then altering
> the type (which zsh without my patch sometimes does by accident).
> 
> Does it always use outermost scope or does it just use the "nearest"
> integer (in this example) that it finds?

Sorry, you're missing my point. bash doesn't have an "integer"
builtin. I was defining a:

integer() { typeset -gi "$@"; }

*function* to demonstrate the undesired behaviour of bash's
typeset -g.

[...]
> > ksh93 does static scoping
> 
> As someone else pointed out elsewhere, this depends on whether you do
>   foo() { ...; }
> or
>   function foo { ...; }
> but really, I don't care, as we don't emulate this bit anyway.

Yes, Bourne-style functions in ksh93 do no scoping at all
whether static or dynamic.

If you use "typeset" in a Bourne-style function in ksh93, that
will affect or instantiate the variable in the inner-most
Korn-style function in the call stack, or the global scope if
there are only Bourne-style functions in the call stack.

Calling a Bourne-style function in ksh in effect is like dumping
the body of that function on the spot when it comes to scoping.

That has its uses to work around the strictness of the
Korn-style statically scoped functions. You could do for
instance:

int() typeset -i "$@"

there.

> Aside:  Shouldn't IGNORE_CLOSE_BRACES be set in ksh emulation?  It
> currently is not.

I'd say

$ zsh --emulate ksh -c 'echo go}'
zsh:1: parse error near `}'
$ zsh --emulate ksh -o ignoreclosebraces  -c 'echo go}'
go }

Are both wrong for ksh compatibility.

$ zsh --emulate sh -c 'echo go}'
go}

~$ zsh --emulate sh -c 'set -o' | grep brace
braceccl              off
noignorebraces        off
ignoreclosebraces     off
~$ zsh --emulate ksh -c 'set -o' | grep brace
braceccl              off
ignorebraces          off
ignoreclosebraces     off

$ zsh --emulate ksh -o ignorebraces -c 'echo go}'
go}

But that disables braceexpansion (which is or is not enabled by
default on ksh depending on the implementation, version, how it
was compiled and the setting of the braceexpand (and posix in
ksh93u+m) options).

Newer versions of the POSIX spec allow (but don't require nor
specify) brace expansion, so it doesn't need to be disabled
in sh emulation any longer (but doesn't need to be enabled
either). Same for {fd}> ...

See https://www.austingroupbugs.net/view.php?id=1193

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: [PATCH v3] regexp-replace and ^, word boundary or look-behind operators (and more).
  @ 2024-03-08 15:30  2%                 ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-03-08 15:30 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

2021-05-05 12:45:21 +0100, Stephane Chazelas:
> 2021-04-30 16:13:34 -0700, Bart Schaefer:
> [...]
> > I went back and looked at the patch again.
> 
> Thanks. Here's a third version with further improvements
> addressing some of the comments here.
[...]

That v3 patch had (at least) a couple of bugs:
- in ERE mode, replacement was not inserted properly when
  pattern matched an empty string not at the start of the
  subject (like in regexp-replace var '\>' new)

- it would run in an infinite loop when there's no match in ERE
  mode.

I see Bart ended up committing the v2 version of my patch (from
48747) a few months later in:

commit bb61da36aaeeaa70413cdf5bc66d7a71194f93e5
Author:     Stephane Chazelas <stephane.chazelas@gmail.com>
AuthorDate: Mon Sep 6 14:43:01 2021 -0700
Commit:     Bart Schaefer <schaefer@ipost.com>
CommitDate: Mon Sep 6 14:43:01 2021 -0700

    45180: clarify doc for POSIX EREs, fix an issue with PCRE when the replacement was empty or generated more than one element

That one didn't have the second problem but had the first and
also failed to add the replacement in:

regexp-replace var '^' replacement

for instance when $var is initially empty.

So here's a v4 that should address that, some of the objections
to v2 and uses namerefs to replace that illegible usage
of positional parameters for local variables (that's diff
against current HEAD, not pre-v2).

I went for the:

typeset -g -- "$1"
typeset -nu -- var=$1

suggested by Bart to avoid possible clashes with local variable
names. That might have side effects if called as regexp-replace
'a[2]' re?

diff --git a/Functions/Misc/regexp-replace b/Functions/Misc/regexp-replace
index d4408f0f7..0e3deed4f 100644
--- a/Functions/Misc/regexp-replace
+++ b/Functions/Misc/regexp-replace
@@ -1,91 +1,95 @@
-# Replace all occurrences of a regular expression in a variable.  The
-# variable is modified directly.  Respects the setting of the
-# option RE_MATCH_PCRE.
+# Replace all occurrences of a regular expression in a scalar variable.
+# The variable is modified directly.  Respects the setting of the option
+# RE_MATCH_PCRE, but otherwise sets the zsh emulation mode.
 #
-# First argument: *name* (not contents) of variable.
-# Second argument: regular expression
-# Third argument: replacement string.  This can contain all forms of
-# $ and backtick substitutions; in particular, $MATCH will be replaced
-# by the portion of the string matched by the regular expression.
-
-# we use positional parameters instead of variables to avoid
-# clashing with the user's variable. Make sure we start with 3 and only
-# 3 elements:
-argv=("$1" "$2" "$3")
-
-# $4 records whether pcre is enabled as that information would otherwise
-# be lost after emulate -L zsh
-4=0
-[[ -o re_match_pcre ]] && 4=1
+# Arguments:
+#
+# 1. *name* (not contents) of variable or more generally any lvalue;
+#    expected to be scalar.
+#
+# 2. regular expression
+#
+# 3. replacement string.  This can contain all forms of
+#    $ and backtick substitutions; in particular, $MATCH will be
+#    replaced by the portion of the string matched by the regular
+#    expression. Parsing errors are fatal to the shell process.
+
+if (( $# < 2 || $# > 3 )); then
+  setopt localoptions functionargzero
+  print -ru2 "Usage: $0 <varname> <regexp> [<replacement>]"
+  return 2
+fi
 
-emulate -L zsh
+# ensure variable exists in the caller's scope before referencing it
+# to make sure we don't end up referencing one of our own.
+typeset -g -- "$1" || return 2
+typeset -nu -- var=$1 || return 2
 
+local -i use_pcre=0
+[[ -o re_match_pcre ]] && use_pcre=1
 
-local MATCH MBEGIN MEND
+emulate -L zsh
+
+local regexp=$2 replacement=$3 result MATCH MBEGIN MEND
 local -a match mbegin mend
 
-if (( $4 )); then
+if (( use_pcre )); then
   # if using pcre, we're using pcre_match and a running offset
   # That's needed for ^, \A, \b, and look-behind operators to work
   # properly.
 
   zmodload zsh/pcre || return 2
-  pcre_compile -- "$2" && pcre_study || return 2
+  pcre_compile -- "$regexp" && pcre_study || return 2
+
+  local -i offset=0 start stop
+  local new ZPCRE_OP
+  local -a finds
 
-  # $4 is the current *byte* offset, $5, $6 reserved for later use
-  4=0 6=
+  while pcre_match -b -n $offset -- "$var"; do
+    # we need to perform the evaluation in a scalar assignment so that
+    # if it generates an array, the elements are converted to string (by
+    # joining with the first chararacter of $IFS as usual)
+    new=${(Xe)replacement}
 
-  local ZPCRE_OP
-  while pcre_match -b -n $4 -- "${(P)1}"; do
-    # append offsets and computed replacement to the array
-    # we need to perform the evaluation in a scalar assignment so that if
-    # it generates an array, the elements are converted to string (by
-    # joining with the first character of $IFS as usual)
-    5=${(e)3}
-    argv+=(${(s: :)ZPCRE_OP} "$5")
+    finds+=( ${(s[ ])ZPCRE_OP} "$new" )
 
     # for 0-width matches, increase offset by 1 to avoid
     # infinite loop
-    4=$((argv[-2] + (argv[-3] == argv[-2])))
+    (( offset = finds[-2] + (finds[-3] == finds[-2]) ))
   done
 
-  (($# > 6)) || return # no match
+  (( $#finds )) || return # no match
 
-  set +o multibyte
+  unsetopt multibyte
 
-  # $5 contains the result, $6 the current offset
-  5= 6=1
-  for 2 3 4 in "$@[7,-1]"; do
-    5+=${(P)1[$6,$2]}$4
-    6=$(($3 + 1))
+  offset=1
+  for start stop new in "$finds[@]"; do
+    result+=${var[offset,start]}$new
+    (( offset = stop + 1 ))
   done
-  5+=${(P)1[$6,-1]}
-else
+  result+=${var[offset,-1]}
+
+else # no PCRE
+
   # in ERE, we can't use an offset so ^, (and \<, \b, \B, [[:<:]] where
   # available) won't work properly.
-
-  # $4 is the string to be matched
-  4=${(P)1}
-
-  while [[ -n $4 ]]; do
-    if [[ $4 =~ $2 ]]; then
-      # append initial part and substituted match
-      5+=${4[1,MBEGIN-1]}${(e)3}
-      # truncate remaining string
-      if ((MEND < MBEGIN)); then
-        # zero-width match, skip one character for the next match
-        ((MEND++))
-	5+=${4[1]}
-      fi
-      4=${4[MEND+1,-1]}
-      # indicate we did something
-      6=1
-    else
-      break
+  local subject=$var
+  local -i ok
+  while [[ $subject =~ $regexp ]]; do
+    # append initial part and substituted match
+    result+=$subject[1,MBEGIN-1]${(Xe)replacement}
+    # truncate remaining string
+    if (( MEND < MBEGIN )); then
+      # zero-width match, skip one character for the next match
+      (( MEND++ ))
+      result+=$subject[MBEGIN]
     fi
+    subject=$subject[MEND+1,-1]
+    ok=1
+    [[ -n $subject ]] && break
   done
-  [[ -n $6 ]] || return # no match
-  5+=$4
+  (( ok )) || return
+  result+=$subject
 fi
 
-eval $1=\$5
+var=$result


^ permalink raw reply	[relevance 2%]

* Re: [PATCH?] Nofork and removing newlines
  @ 2024-03-07  7:10  3%             ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-03-07  7:10 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Mikael Magnusson, Zsh hackers list

2024-03-06 20:53:28 -0800, Bart Schaefer:
[...]
> > "${ foo}" and ${ foo} having the same wordsplitting behavior but only
> > differing in stripping newlines feels a bit magical and weird.
> 
> One question (and sort of the point) is whether anyone would really
> notice.  If you put it in quotes you're expecting a literal result,
> and if you (for example) assign it unquoted to a scalar you're
> expecting it to "just work" the way assigning $(foo) would.  It's a
> bit unusual but it seems to preserve the principle of least surprise,
> and it uses the least amount of extra syntax.
> 
> On the other hand I'm not highly invested in this.  In the absence of
> this (no)quoting behavior, I've found I nearly always want ${=${ foo
> }} or ${(f)${ foo }}, each of which gives exactly the same result with
> or without trimming.
[...]

For ${=${ foo }} that depends on whether $IFS contains a
(non-doubled) newline or not.

Without trimming:

$ IFS=:
$ printf '<%s>\n' ${=${ getconf PATH }}
</bin>
</usr/bin
>

$ IFS=$'\n\n'
$ printf '<%s>\n' ${=${ seq 3 }}
<1>
<2>
<3>
<>

For (f), see also:

$ printf '<%s>\n' "${(f@)${ print -l 'a b' '' 'c d' }}"
<a b>
<>
<c d>
<>

Like with IFS=$'\n\n', those are typically the cases where you
do want to preserve empty lines.

In both cases, trimming one (and only one) newline character
would lead to a better behaviour. One exception would be in:

lines=( "${(f@)${ print -l '' }}" )

Where you'd get no line instead of one empty line. Though at the moment, you get:

$ lines=( "${(f@)${ print -l '' }}" )
$ typeset -p lines
typeset -a lines=( '' '' )

(2 empty lines) which is not better.

We'd need to have a way to treat the separator as *delimiter*
instead (as POSIX requires for IFS splitting despite the S in
IFS; both "delimiting" and "separating" have their use).

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH?] Nofork and removing newlines
    @ 2024-03-06 19:43  3%     ` Stephane Chazelas
  1 sibling, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-03-06 19:43 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2024-03-05 14:48:00 -0800, Bart Schaefer:
[...]
> The suggested change would provide
> $(...)-like behavior for the usual case and a simple way to keep the
> newline(s) in the less-usual cases.
[...]

For reference, some other shells that can keep trailing newline
in command subtitution:

rc:

  whole_output = ``(){cmd and its args}

fish:

  set whole_output (cmd and its args | string collect -aN)

  (-aN short for --allow-empty --no-trim-newlines).

  fish's command substitution ( (...) and also $(...) including
  inside "..." in recent versions) doesn't fork so is closer to
  ksh93's ${ cmd; } than ksh86's $(...)

POSIX/Korn-like shells:

  I'm sure everyone will have their own variant, but

  get_whole_output() {
    eval "
      $1"'=$(shift; "$@"; ret=$?; echo .; exit "$ret")
      set -- "$1" "$?"
      '"$1"'=${'"$1"'%.}
      return "$2"'
  }
  get_whole_output whole_output cmd and its args

  (bearing in mind that there aren't many characters beside .
  that you can use safely there as it's important its encoding
  can't be found in the encoding of other characters.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* unset, POSIX and the export attribute (Was: [PATCH] Fix crash on unset-through-nameref)
  2024-03-05 18:42  0%           ` Bart Schaefer
@ 2024-03-05 19:48  9%             ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-03-05 19:48 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2024-03-05 10:42:18 -0800, Bart Schaefer:
> On Tue, Mar 5, 2024 at 12:19 AM Stephane Chazelas <stephane@chazelas.org> wrote:
> >
> > 2024-03-04 15:18:06 -0800, Bart Schaefer:
> > > On Mon, Mar 4, 2024 at 11:34 AM Stephane Chazelas <stephane@chazelas.org> wrote:
> > > >
> > > > It still retained its export attribute.
> > >
> > > This gets messy because POSIX says that's exactly what's supposed to
> > > happen when unsetting an export, even though in native zsh it normally
> > > doesn't work that way.
> >
> > No, I think you're confusing with:
> >
> > export foo
> 
> I'm referring to comments in the C code, e.g.:
> 
>      * POSIXBUILTINS horror: we need to retain the 'readonly' or 'export'
>      * flags of an unset parameter.
> [...]
>     if (isset(POSIXBUILTINS)) {
> [...]
>         /* This is handled by createparam():
>         if (usepm && (pm->node.flags & PM_EXPORTED) && !(off & PM_EXPORTED))
>             on |= PM_EXPORTED;
>         */
[...]

But AFAICT, that's about the "export var" when var is not
previously set. You can't unset a readonly variable anyway.

zsh retaining the export attribute of a variable upon unset
would make it non-compliant.

POSIX is not ambiguous on that. See
https//pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#unset

"unset - unset values and attributes of variables and functions"
"Read-only variables cannot be unset."

-- 
Stephane


^ permalink raw reply	[relevance 9%]

* Re: [PATCH] Fix crash on unset-through-nameref
  2024-03-05  8:18  4%         ` Stephane Chazelas
@ 2024-03-05 18:42  0%           ` Bart Schaefer
  2024-03-05 19:48  9%             ` unset, POSIX and the export attribute (Was: [PATCH] Fix crash on unset-through-nameref) Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2024-03-05 18:42 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

On Tue, Mar 5, 2024 at 12:19 AM Stephane Chazelas <stephane@chazelas.org> wrote:
>
> 2024-03-04 15:18:06 -0800, Bart Schaefer:
> > On Mon, Mar 4, 2024 at 11:34 AM Stephane Chazelas <stephane@chazelas.org> wrote:
> > >
> > > It still retained its export attribute.
> >
> > This gets messy because POSIX says that's exactly what's supposed to
> > happen when unsetting an export, even though in native zsh it normally
> > doesn't work that way.
>
> No, I think you're confusing with:
>
> export foo

I'm referring to comments in the C code, e.g.:

     * POSIXBUILTINS horror: we need to retain the 'readonly' or 'export'
     * flags of an unset parameter.
[...]
    if (isset(POSIXBUILTINS)) {
[...]
        /* This is handled by createparam():
        if (usepm && (pm->node.flags & PM_EXPORTED) && !(off & PM_EXPORTED))
            on |= PM_EXPORTED;
        */

> I hate to say this but it seems to me that if this kind of issue
> is not fixable, then it would likely be preferable (from a
> consistency PoV at least) to go for bash/mksh dumber approaches
> where namerefs are just plain scalar variables containing the
> name of another variable (or other lvalue) and having the target
> variable resolved any time the nameref is assigned/referenced

That is in fact exactly how it works, with the addition now that -u
makes it skip upward one scope before resolving.

> (see also
> https://unix.stackexchange.com/questions/640687/prevent-command-substitution-from-running-when-declaring-a-variable/640695#640695
> where namerefs are abused to have a variable with a dynamic
> value).

Although I wasn't aware of that discussion, I had already thought of that:

  When RNAME includes an array subscript, the subscript expression is
  interpreted at the time ${PNAME} is expanded.  Any form of subscript is
  allowed, including those that select individual elements, substrings of
  scalar strings, or multiple elements as with array slices or the '(i)',
  '(I)', '(r)', '(R)' and '(w)' subscript flags.  However, the subscript
  is evaluated with the NO_EXEC option in effect, so command substitution
  and other similar constructs produce no output, although are not
  syntactically excluded.


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Fix crash on unset-through-nameref
  2024-03-04 23:18  3%       ` Bart Schaefer
@ 2024-03-05  8:18  4%         ` Stephane Chazelas
  2024-03-05 18:42  0%           ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2024-03-05  8:18 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2024-03-04 15:18:06 -0800, Bart Schaefer:
> On Mon, Mar 4, 2024 at 11:34 AM Stephane Chazelas <stephane@chazelas.org> wrote:
> >
> > 2024-03-04 00:39:30 -0800, Bart Schaefer:
> > >
> > > Try removing this line from the patch:
> > >
> > > +    pm->node.flags |= PM_DECLARED;
> >
> > $ ./Src/zsh -c 'myunset() { typeset -n v=$1; unset v; }; export x=1; myunset x; typeset -p x; x=2; typeset -p x'
> > export x=2
> >
> > It still retained its export attribute.
> 
> This gets messy because POSIX says that's exactly what's supposed to
> happen when unsetting an export, even though in native zsh it normally
> doesn't work that way.

No, I think you're confusing with:

export foo

Which is meant to give the export attribute to foo without
giving it a value (so the variable will end up in the
environment of executed command if ever its assigned in the
future but not until then).

unset foo (or better unset -v foo as POSIX allows bash's
behaviour where that could unset a function instead) is required
to clear the value and export attribute.

unset is the only way to unexport a variable in POSIX shells.


> You'll note it also didn't say
>   typeset: no such variable: x
> 
> ... because there is no provision in the parameter implementation for
> a global to occupy a table slot and yet to appear not to exist.
> 
> This is one of the reasons your desire for "create it an as unset at
> the time a nameref mentions it" has inherent problems.

I was suggesting a "unset (and undeclared then) but named ref"
(and refcount if needed for garbage collection) flag for that in
a separate message, but I have no idea whether that'd be
sufficient or feasible.

I hate to say this but it seems to me that if this kind of issue
is not fixable, then it would likely be preferable (from a
consistency PoV at least) to go for bash/mksh dumber approaches
where namerefs are just plain scalar variables containing the
name of another variable (or other lvalue) and having the target
variable resolved any time the nameref is assigned/referenced
(in whatever scope that happens to be).

You'd still need to namespace your variables in functions using
namerefs, even more so, but at least it would be more consistent
and we wouldn't have to list all the special cases that work or
don't work in the documentation

BTW, speaking of "other lvalue", see also:

$ ksh -c 'typeset -n a="b[n++]"; typeset -p n; b=(); a=a a=b a=c; typeset -p b n'
n=2
typeset -a b=([1]=c)
n=2
$ mksh -c 'typeset -n a="b[n++]"; typeset -p n; b=(); a=a a=b a=c; typeset -p b n'
set -A b
typeset b[0]=a
typeset b[2]=b
typeset b[4]=c
typeset n=6
$ bash -c 'typeset -n a="b[n++]"; typeset -p n; b=(); a=a a=b a=c; typeset -p b n'
bash: line 1: typeset: n: not found
declare -a b=([0]="a" [1]="b" [2]="c")
declare -- n="3"
$ ./Src/zsh -c 'typeset -n a="b[n++]"; typeset -p n; b=(); a=a a=b a=c; typeset -p b n'
zsh:typeset:1: no such variable: n
typeset -a b=( a '' b '' c )
typeset -i n=6

Which suggests the lvalue is still evaluated by zsh at every assignment at
least.

(see also
https://unix.stackexchange.com/questions/640687/prevent-command-substitution-from-running-when-declaring-a-variable/640695#640695
where namerefs are abused to have a variable with a dynamic
value).

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: [PATCH] Fix crash on unset-through-nameref
  @ 2024-03-04 23:18  3%       ` Bart Schaefer
  2024-03-05  8:18  4%         ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2024-03-04 23:18 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

On Mon, Mar 4, 2024 at 11:34 AM Stephane Chazelas <stephane@chazelas.org> wrote:
>
> 2024-03-04 00:39:30 -0800, Bart Schaefer:
> >
> > Try removing this line from the patch:
> >
> > +    pm->node.flags |= PM_DECLARED;
>
> $ ./Src/zsh -c 'myunset() { typeset -n v=$1; unset v; }; export x=1; myunset x; typeset -p x; x=2; typeset -p x'
> export x=2
>
> It still retained its export attribute.

This gets messy because POSIX says that's exactly what's supposed to
happen when unsetting an export, even though in native zsh it normally
doesn't work that way.

You'll note it also didn't say
  typeset: no such variable: x

... because there is no provision in the parameter implementation for
a global to occupy a table slot and yet to appear not to exist.

This is one of the reasons your desire for "create it an as unset at
the time a nameref mentions it" has inherent problems.


^ permalink raw reply	[relevance 3%]

* PATCH: real-time signals support
@ 2024-02-24 22:01  3% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2024-02-24 22:01 UTC (permalink / raw)
  To: Zsh workers

This adds support for POSIX real-time signals, covering kill, trap,
$signals and TRAP...() functions.

For consistency with ksh and bash, the naming is RTMIN, RTMIN+1 ...
RTMAX-1, RTMAX. This means that each signal has an alternate name
so on my system, RTMIN+31 is an alternate name for RTMAX-30. NetBSD's
sh uses RT0, RT1...

The patch also adds a -L option to kill similar to bash and ksh which
prints signals with their numbers as a table. On many systems, the
real-time signals are not numbered contiguously with the earlier
signals. Where they are (NetBSD and Solaris), zsh was already including
RTMIN.

Prior to this patch, kill -l uses the WIFSIGNALED and WTERMSIG
macros to convert a return status to the corresponding signal. But
zsh simply ORs the status with 0200 (128). So surely we need to
look for that instead? This alteration makes the behaviour more
consistent with bash. To test, try kill -l {0..260}

In the POSIX spec, SIGRTMIN/MAX are permitted to not be fixed constants, and
this is indeed the case on Linux. As far as I can tell this is because glibc
steals a couple of them for threading support. They don't appear to be
dynamically configurable. However, this does prevent the sigtrapped and
siglists arrays from having their size determined at compile-time. Where
numbers are not contiguous, I've not left a gap so some of the patch is
renaming to make the distinction between signal numbers and trap table indices
clear.

Oliver

diff --git a/Completion/Zsh/Command/_kill b/Completion/Zsh/Command/_kill
index 084cf42c8..3b5c02151 100644
--- a/Completion/Zsh/Command/_kill
+++ b/Completion/Zsh/Command/_kill
@@ -4,10 +4,11 @@ local curcontext="$curcontext" line state ret=1
 typeset -A opt_args
 
 _arguments -C \
-  '(-s -l 1)-n[specify signal number]:signal number' \
-  '(-l)-q[send the specified integer with the signal using sigqueue]:value' \
-  '(-n -l 1)-s[specify signal name]:signal:_signals -s' \
-  '(-n -s)-l[list signal names or numbers of specified signals]:*:signal:_signals' \
+  '(-s -l -L 1)-n[specify signal number]:signal number' \
+  '(-l -L)-q[send the specified integer with the signal using sigqueue]:value' \
+  '(-n -l -L 1)-s[specify signal name]:signal:_signals -s' \
+  '-l[list signal names or numbers of specified signals]:*:signal:_signals' \
+  '(- *)-L[list each signal and corresponding number]' \
   '(-n -s -l)1::signal:_signals -p -s' \
   '*:processes:->processes' && ret=0
   
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 784089594..6318053d8 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1144,7 +1144,8 @@ cindex(killing jobs)
 cindex(jobs, killing)
 xitem(tt(kill) [ tt(-s) var(signal_name) | tt(-n) var(signal_number) | \
 tt(-)var(sig) ] [ tt(-q) var(value) ] var(job) ...)
-item(tt(kill) tt(-l) [ var(sig) ... ])(
+xitem(tt(kill) tt(-l) [ var(sig) ... ])
+item(tt(kill) tt(-L))(
 Sends either tt(SIGTERM) or the specified signal to the given
 jobs or processes.
 Signals are given by number or by names, with or without the `tt(SIG)'
@@ -1158,7 +1159,8 @@ specified the signal names are listed.  Otherwise, for each
 var(sig) that is a name, the corresponding signal number is
 listed.  For each var(sig) that is a signal number or a number
 representing the exit status of a process which was terminated or
-stopped by a signal the name of the signal is printed.
+stopped by a signal the name of the signal is printed.  The final
+form with tt(-L) lists each signal name with its corresponding number.
 
 On some systems, alternative signal names are allowed for a few signals.
 Typical examples are tt(SIGCHLD) and tt(SIGCLD) or tt(SIGPOLL) and
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index a6fbe6723..8c5e67e70 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -953,7 +953,10 @@ has index 1, the signals are offset by 1 from the signal number
 used by the operating system.  For example, on typical Unix-like systems
 tt(HUP) is signal number 1, but is referred to as tt($signals[2]).  This
 is because of tt(EXIT) at position 1 in the array, which is used
-internally by zsh but is not known to the operating system.
+internally by zsh but is not known to the operating system. On many systems
+there is a block of reserved or unused signal numbers before the POSIX
+real-time signals so the array index can't be used as an accurate indicator
+of their signal number. Use, for example, tt(kill -l SIGRTMIN) instead.
 )
 vindex(TRY_BLOCK_ERROR)
 item(tt(TRY_BLOCK_ERROR) <S>)(
diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c
index a05ea2fe4..7441c30b8 100644
--- a/Src/Modules/parameter.c
+++ b/Src/Modules/parameter.c
@@ -309,7 +309,7 @@ setfunction(char *name, char *val, int dis)
     shfunc_set_sticky(shf);
 
     if (!strncmp(name, "TRAP", 4) &&
-	(sn = getsignum(name + 4)) != -1) {
+	(sn = getsigidx(name + 4)) != -1) {
 	if (settrap(sn, NULL, ZSIG_FUNC)) {
 	    freeeprog(shf->funcdef);
 	    zfree(shf, sizeof(*shf));
diff --git a/Src/builtin.c b/Src/builtin.c
index dd352c146..7a851936c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3425,16 +3425,16 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    newsh->sticky = sticky_emulation_dup(shf->sticky, 0);
 	/* is newsh a signal trap? (adapted from exec.c) */
 	if (!strncmp(s, "TRAP", 4)) {
-	    int signum = getsignum(s + 4);
-	    if (signum != -1) {
-		if (settrap(signum, NULL, ZSIG_FUNC)) {
+	    int sigidx = getsigidx(s + 4);
+	    if (sigidx != -1) {
+		if (settrap(sigidx, NULL, ZSIG_FUNC)) {
 		    freeeprog(newsh->funcdef);
 		    dircache_set(&newsh->filename, NULL);
 		    zfree(newsh, sizeof(*newsh));
 		    return 1;
 		}
 		/* Remove any old node explicitly */
-		removetrapnode(signum);
+		removetrapnode(sigidx);
 	    }
 	}
 	shfunctab->addnode(shfunctab, ztrdup(s), &newsh->node);
@@ -3713,15 +3713,15 @@ bin_functions(char *name, char **argv, Options ops, int func)
 		/* no flags, so just print */
 		printshfuncexpand(&shf->node, pflags, expand);
 	} else if (on & PM_UNDEFINED) {
-	    int signum = -1, ok = 1;
+	    int sigidx = -1, ok = 1;
 
 	    if (!strncmp(*argv, "TRAP", 4) &&
-		(signum = getsignum(*argv + 4)) != -1) {
+		(sigidx = getsigidx(*argv + 4)) != -1) {
 		/*
 		 * Because of the possibility of alternative names,
 		 * we must remove the trap explicitly.
 		 */
-		removetrapnode(signum);
+		removetrapnode(sigidx);
 	    }
 
 	    if (**argv == '/') {
@@ -3757,8 +3757,8 @@ bin_functions(char *name, char **argv, Options ops, int func)
 	    shfunc_set_sticky(shf);
 	    add_autoload_function(shf, *argv);
 
-	    if (signum != -1) {
-		if (settrap(signum, NULL, ZSIG_FUNC)) {
+	    if (sigidx != -1) {
+		if (settrap(sigidx, NULL, ZSIG_FUNC)) {
 		    shfunctab->removenode(shfunctab, *argv);
 		    shfunctab->freenode(&shf->node);
 		    returnval = 1;
@@ -7344,7 +7344,7 @@ bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
     /* If given no arguments, list all currently-set traps */
     if (!*argv) {
 	queue_signals();
-	for (sig = 0; sig < VSIGCOUNT; sig++) {
+	for (sig = 0; sig < TRAPCOUNT; sig++) {
 	    if (sigtrapped[sig] & ZSIG_FUNC) {
 		HashNode hn;
 
@@ -7370,13 +7370,13 @@ bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 
     /* If we have a signal number, unset the specified *
      * signals.  With only -, remove all traps.        */
-    if ((getsignum(*argv) != -1) || (!strcmp(*argv, "-") && argv++)) {
+    if ((getsigidx(*argv) != -1) || (!strcmp(*argv, "-") && argv++)) {
 	if (!*argv) {
-	    for (sig = 0; sig < VSIGCOUNT; sig++)
+	    for (sig = 0; sig < TRAPCOUNT; sig++)
 		unsettrap(sig);
 	} else {
 	    for (; *argv; argv++) {
-		sig = getsignum(*argv);
+		sig = getsigidx(*argv);
 		if (sig == -1) {
 		    zwarnnam(name, "undefined signal: %s", *argv);
 		    break;
@@ -7401,12 +7401,12 @@ bin_trap(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 	Eprog t;
 	int flags;
 
-	sig = getsignum(*argv);
+	sig = getsigidx(*argv);
 	if (sig == -1) {
 	    zwarnnam(name, "undefined signal: %s", *argv);
 	    break;
 	}
-	if (idigit(**argv) ||
+	if (idigit(**argv) || (sig >= VSIGCOUNT) ||
 	    !strcmp(sigs[sig], *argv) ||
 	    (!strncmp("SIG", *argv, 3) && !strcmp(sigs[sig], *argv+3))) {
 	    /* The signal was specified by number or by canonical name (with
diff --git a/Src/exec.c b/Src/exec.c
index 1565cb13e..f6ccbefe5 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5427,7 +5427,7 @@ execfuncdef(Estate state, Eprog redir_prog)
 	} else {
 	    /* is this shell function a signal trap? */
 	    if (!strncmp(s, "TRAP", 4) &&
-		(signum = getsignum(s + 4)) != -1) {
+		(signum = getsigidx(s + 4)) != -1) {
 		if (settrap(signum, NULL, ZSIG_FUNC)) {
 		    freeeprog(shf->funcdef);
 		    dircache_set(&shf->filename, NULL);
diff --git a/Src/hashtable.c b/Src/hashtable.c
index bb165505e..75b06c4ad 100644
--- a/Src/hashtable.c
+++ b/Src/hashtable.c
@@ -836,10 +836,10 @@ static HashNode
 removeshfuncnode(UNUSED(HashTable ht), const char *nam)
 {
     HashNode hn;
-    int signum;
+    int sigidx;
 
-    if (!strncmp(nam, "TRAP", 4) && (signum = getsignum(nam + 4)) != -1)
-	hn = removetrap(signum);
+    if (!strncmp(nam, "TRAP", 4) && (sigidx = getsigidx(nam + 4)) != -1)
+	hn = removetrap(sigidx);
     else
 	hn = removehashnode(shfunctab, nam);
 
@@ -856,10 +856,10 @@ disableshfuncnode(HashNode hn, UNUSED(int flags))
 {
     hn->flags |= DISABLED;
     if (!strncmp(hn->nam, "TRAP", 4)) {
-	int signum = getsignum(hn->nam + 4);
-	if (signum != -1) {
-	    sigtrapped[signum] &= ~ZSIG_FUNC;
-	    unsettrap(signum);
+	int sigidx = getsigidx(hn->nam + 4);
+	if (sigidx != -1) {
+	    sigtrapped[sigidx] &= ~ZSIG_FUNC;
+	    unsettrap(sigidx);
 	}
     }
 }
@@ -876,9 +876,9 @@ enableshfuncnode(HashNode hn, UNUSED(int flags))
 
     shf->node.flags &= ~DISABLED;
     if (!strncmp(shf->node.nam, "TRAP", 4)) {
-	int signum = getsignum(shf->node.nam + 4);
-	if (signum != -1) {
-	    settrap(signum, NULL, ZSIG_FUNC);
+	int sigidx = getsigidx(shf->node.nam + 4);
+	if (sigidx != -1) {
+	    settrap(sigidx, NULL, ZSIG_FUNC);
 	}
     }
 }
diff --git a/Src/init.c b/Src/init.c
index 83b79d3d4..ec21521b1 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1382,6 +1382,9 @@ setupshin(char *runscript)
 void
 init_signals(void)
 {
+    sigtrapped = (int *) hcalloc(TRAPCOUNT * sizeof(int));
+    siglists = (Eprog *) hcalloc(TRAPCOUNT * sizeof(Eprog));
+
     if (interact) {
 	int i;
 	signal_setmask(signal_mask(0));
diff --git a/Src/jobs.c b/Src/jobs.c
index 118c5e61b..49decc661 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1073,6 +1073,21 @@ should_report_time(Job j)
     return 0;
 }
 
+/**/
+char *
+sigmsg(int sig)
+{
+    static char *unknown = "unknown signal";
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    static char rtmsg[] = "real-time event XXX";
+    if (sig >= SIGRTMIN && sig <= SIGRTMAX) {
+	sprintf(rtmsg + sizeof(rtmsg) - 4, "%u", sig - SIGRTMIN + 1);
+	return rtmsg;
+    }
+#endif
+    return sig <= SIGCOUNT ? sig_msg[sig] : unknown;
+}
+
 /* !(lng & 3) means jobs    *
  *  (lng & 1) means jobs -l *
  *  (lng & 2) means jobs -p
@@ -2694,7 +2709,7 @@ static const struct {
 int
 bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 {
-    int sig = SIGTERM;
+    int status, sig = SIGTERM;
     int returnval = 0;
 #ifdef HAVE_SIGQUEUE
     union sigval sigqueue_info;
@@ -2740,23 +2755,29 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 	    if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
 		if (argv[1]) {
 		    while (*++argv) {
-			sig = zstrtol(*argv, &signame, 10);
+			status = zstrtol(*argv, &signame, 10);
 			if (signame == *argv) {
+			    signame = casemodify(signame, CASMOD_UPPER);
 			    if (!strncmp(signame, "SIG", 3))
 				signame += 3;
 			    for (sig = 1; sig <= SIGCOUNT; sig++)
-				if (!strcasecmp(sigs[sig], signame))
+				if (!strcmp(sigs[sig], signame))
 				    break;
 			    if (sig > SIGCOUNT) {
 				int i;
 
 				for (i = 0; alt_sigs[i].name; i++)
-				    if (!strcasecmp(alt_sigs[i].name, signame))
+				    if (!strcmp(alt_sigs[i].name, signame))
 				    {
 					sig = alt_sigs[i].num;
 					break;
 				    }
 			    }
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+			    if (sig > SIGCOUNT && (sig = rtsigno(signame))) {
+				printf("%d\n", sig);
+			    } else
+#endif
 			    if (sig > SIGCOUNT) {
 				zwarnnam(nam, "unknown signal: SIG%s",
 					 signame);
@@ -2769,14 +2790,15 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 					 signame);
 				returnval++;
 			    } else {
-				if (WIFSIGNALED(sig))
-				    sig = WTERMSIG(sig);
-				else if (WIFSTOPPED(sig))
-				    sig = WSTOPSIG(sig);
+				sig = status & ~0200;
 				if (1 <= sig && sig <= SIGCOUNT)
 				    printf("%s\n", sigs[sig]);
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+				else if ((signame = rtsigname(sig, 0)))
+				    printf("%s\n", signame);
+#endif
 				else
-				    printf("%d\n", sig);
+				    printf("%d\n", status);
 			    }
 			}
 		    }
@@ -2785,10 +2807,42 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 		printf("%s", sigs[1]);
 		for (sig = 2; sig <= SIGCOUNT; sig++)
 		    printf(" %s", sigs[sig]);
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+		for (sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
+		    printf(" %s", rtsigname(sig, 0));
+#endif
 		putchar('\n');
 		return 0;
 	    }
 
+	    /* with argument "-L" list signals with their numbers in a table */
+	    if ((*argv)[1] == 'L' && (*argv)[2] == '\0') {
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+		const int width = SIGRTMAX >= 100 ? 3 : 2;
+#else
+		const int width = SIGCOUNT >= 100 ? 3 : 2;
+#endif
+		for (sig = 1; sig < SIGCOUNT
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+			+ 1
+#endif
+			; sig++)
+		{
+		    printf("%*d) %-10s%c", width, sig, sigs[sig],
+			    sig % 5 ? ' ' : '\n');
+		}
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+		for (sig = SIGRTMIN; sig < SIGRTMAX; sig++) {
+		    printf("%*d) %-10s%c", width, sig, rtsigname(sig, 0),
+			    (sig - SIGRTMIN + SIGCOUNT + 1) % 5 ? ' ' : '\n');
+		}
+		printf("%*d) RTMAX\n", width, sig);
+#else
+		printf("%*d) %s\n", width, sig, sigs[sig]);
+#endif
+		return 0;
+	    }
+
     	    if ((*argv)[1] == 'n' && (*argv)[2] == '\0') {
 	    	char *endp;
 
@@ -2833,9 +2887,13 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 			    break;
 			}
 		}
-		if (sig > SIGCOUNT) {
+		if (sig > SIGCOUNT
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+			&& !(sig = rtsigno(signame))
+#endif
+			) {
 		    zwarnnam(nam, "unknown signal: SIG%s", signame);
-		    zwarnnam(nam, "type kill -l for a list of signals");
+		    zwarnnam(nam, "type kill -L for a list of signals");
 		    return 1;
 		}
 	    }
@@ -2916,18 +2974,19 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 
     return returnval < 126 ? returnval : 1;
 }
-/* Get a signal number from a string */
+
+/* Get index into table of traps from a string describing a signal */
 
 /**/
 mod_export int
-getsignum(const char *s)
+getsigidx(const char *s)
 {
     int x, i;
 
     /* check for a signal specified by number */
     x = atoi(s);
-    if (idigit(*s) && x >= 0 && x < VSIGCOUNT)
-	return x;
+    if (idigit(*s) && x >= 0)
+	return SIGIDX(x);
 
     /* search for signal by name */
     if (!strncmp(s, "SIG", 3))
@@ -2943,11 +3002,16 @@ getsignum(const char *s)
 	    return alt_sigs[i].num;
     }
 
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    if ((x = rtsigno(s)))
+	return SIGIDX(x);
+#endif
+
     /* no matching signal */
     return -1;
 }
 
-/* Get the name for a signal. */
+/* Get the name for a signal given the index into the traps table. */
 
 /**/
 mod_export const char *
@@ -2961,6 +3025,11 @@ getsigname(int sig)
 		return alt_sigs[i].name;
     }
     else
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    if (sig >= VSIGCOUNT)
+	return rtsigname(SIGNUM(sig), 0);
+    else
+#endif
 	return sigs[sig];
 
     /* shouldn't reach here */
@@ -2985,10 +3054,22 @@ gettrapnode(int sig, int ignoredisable)
     else
 	getptr = shfunctab->getnode;
 
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    if (sig >= VSIGCOUNT)
+	sprintf(fname, "TRAP%s", rtsigname(SIGNUM(sig), 0));
+    else
+#endif
     sprintf(fname, "TRAP%s", sigs[sig]);
     if ((hn = getptr(shfunctab, fname)))
 	return hn;
 
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    if (sig >= VSIGCOUNT) {
+	sprintf(fname, "TRAP%s", rtsigname(SIGNUM(sig), 1));
+	return getptr(shfunctab, fname);
+    }
+#endif
+
     for (i = 0; alt_sigs[i].name; i++) {
 	if (alt_sigs[i].num == sig) {
 	    sprintf(fname, "TRAP%s", alt_sigs[i].name);
diff --git a/Src/params.c b/Src/params.c
index 225acb8a1..7c5e9d8ff 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -946,8 +946,18 @@ createparamtable(void)
     setsparam("ZSH_ARGZERO", ztrdup(posixzero));
     setsparam("ZSH_VERSION", ztrdup_metafy(ZSH_VERSION));
     setsparam("ZSH_PATCHLEVEL", ztrdup_metafy(ZSH_PATCHLEVEL));
-    setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));
-    for (t = sigs; (*sigptr++ = ztrdup_metafy(*t++)); );
+    setaparam("signals", sigptr = zalloc((TRAPCOUNT + 1) * sizeof(char *)));
+    t = sigs;
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    while (t - sigs <= SIGCOUNT)
+	*sigptr++ = ztrdup_metafy(*t++);
+    {
+	int sig;
+	for (sig = SIGRTMIN; sig <= SIGRTMAX; sig++)
+	    *sigptr++ = ztrdup_metafy(rtsigname(sig, 0));
+    }
+#endif
+    while ((*sigptr++ = ztrdup_metafy(*t++))) /* empty */ ;
 
     noerrs = 0;
 }
diff --git a/Src/signals.c b/Src/signals.c
index b1a843e2c..d28853ea6 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -31,10 +31,12 @@
 #include "signals.pro"
  
 /* Array describing the state of each signal: an element contains *
- * 0 for the default action or some ZSIG_* flags ored together.   */
+ * 0 for the default action or some ZSIG_* flags ored together.   *
+ * Contains TRAPCOUNT elements but can't be allocated statically  *
+ * because that's a dynamic value on Linux                        */
 
 /**/
-mod_export int sigtrapped[VSIGCOUNT];
+mod_export int *sigtrapped;
 
 /*
  * Trap programme lists for each signal.
@@ -48,7 +50,7 @@ mod_export int sigtrapped[VSIGCOUNT];
  */
 
 /**/
-mod_export Eprog siglists[VSIGCOUNT];
+mod_export Eprog *siglists;
 
 /* Total count of trapped signals */
 
@@ -892,7 +894,7 @@ dosavetrap(int sig, int level)
  * Set a trap:  note this does not handle manipulation of
  * the function table for TRAPNAL functions.
  *
- * sig is the signal number.
+ * sig is index into the table of trapped signals.
  *
  * l is the list to be eval'd for a trap defined with the "trap"
  * builtin and should be NULL for a function trap.
@@ -931,6 +933,10 @@ settrap(int sig, Eprog l, int flags)
 #endif
             sig != SIGCHLD)
             signal_ignore(sig);
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+	else if (sig >= VSIGCOUNT && sig < TRAPCOUNT)
+	    signal_ignore(SIGNUM(sig));
+#endif
     } else {
 	nsigtrapped++;
         sigtrapped[sig] = ZSIG_TRAPPED;
@@ -940,6 +946,10 @@ settrap(int sig, Eprog l, int flags)
 #endif
             sig != SIGCHLD)
             install_handler(sig);
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+	if (sig >= VSIGCOUNT && sig < TRAPCOUNT)
+	    install_handler(SIGNUM(sig));
+#endif
     }
     sigtrapped[sig] |= flags;
     /*
@@ -1019,6 +1029,11 @@ removetrap(int sig)
 #endif
              sig != SIGCHLD)
         signal_default(sig);
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+    else if (sig >= VSIGCOUNT && sig < TRAPCOUNT)
+	    signal_default(SIGNUM(sig));
+#endif
+
     if (sig == SIGEXIT)
 	exit_trap_posix = 0;
 
@@ -1172,7 +1187,7 @@ endtrapscope(void)
 static int
 handletrap(int sig)
 {
-    if (!sigtrapped[sig])
+    if (!sigtrapped[SIGIDX(sig)])
 	return 0;
 
     if (trap_queueing_enabled)
@@ -1189,7 +1204,7 @@ handletrap(int sig)
 	return 1;
     }
 
-    dotrap(sig);
+    dotrap(SIGIDX(sig));
 
     if (sig == SIGALRM)
     {
@@ -1481,3 +1496,60 @@ dotrap(int sig)
 
     restore_queue_signals(q);
 }
+
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+
+/* Realtime signals, these are a contiguous block that can
+ * be separated from the other signals with an unused gap. */
+
+/**/
+int
+rtsigno(const char* signame)
+{
+    const int maxofs = SIGRTMAX - SIGRTMIN;
+    const char *end = signame + 5;
+    int offset;
+    struct rtdir { int sig; int dir; char op; } x = { 0, 0, 0 };
+    if (!strncmp(signame, "RTMIN", 5)) {
+	x = (struct rtdir) { SIGRTMIN, 1, '+' };
+    } else if (!strncmp(signame, "RTMAX", 5)) {
+	x = (struct rtdir) { SIGRTMAX, -1, '-' };
+    } else
+	return 0;
+
+    if (signame[5] == x.op) {
+	if ((offset = strtol(signame + 6, (char **) &end, 10)) > maxofs)
+	    return 0;
+	x.sig += offset * x.dir;
+    }
+    if (*end)
+	return 0;
+
+    return x.sig;
+}
+
+/**/
+char *
+rtsigname(int signo, int alt)
+{
+    char* buf = (char *) zhalloc(10);
+    int minofs = signo - SIGRTMIN;
+    int maxofs = SIGRTMAX - signo;
+    int offset;
+    int form = alt ^ (maxofs < minofs);
+
+    if (signo < SIGRTMIN || signo > SIGRTMAX)
+	return NULL;
+
+    strcpy(buf, "RT");
+    strcpy(buf+2, form ? "MAX-" : "MIN+");
+    offset = form ? maxofs : minofs;
+    if (offset) {
+	snprintf(buf + 6, 4, "%d", offset);
+    } else {
+	buf[5] = '\0';
+    }
+    return buf;
+}
+
+#endif
diff --git a/Src/signals.h b/Src/signals.h
index 41ac88cce..391f11fed 100644
--- a/Src/signals.h
+++ b/Src/signals.h
@@ -36,6 +36,15 @@
 #define SIGZERR   (SIGCOUNT+1)
 #define SIGDEBUG  (SIGCOUNT+2)
 #define VSIGCOUNT (SIGCOUNT+3)
+#if defined(SIGRTMIN) && defined(SIGRTMAX)
+# define TRAPCOUNT (VSIGCOUNT + SIGRTMAX - SIGRTMIN + 1)
+# define SIGNUM(x) ((x) >= VSIGCOUNT ? (x) - VSIGCOUNT + SIGRTMIN : (x))
+# define SIGIDX(x) ((x) >= SIGRTMIN && (x) <= SIGRTMAX ? (x) - SIGRTMIN + VSIGCOUNT : (x))
+#else
+# define TRAPCOUNT VSIGCOUNT
+# define SIGNUM(x) (x)
+# define SIGIDX(x) (x)
+#endif
 #define SIGEXIT    0
 
 #ifdef SV_BSDSIG
diff --git a/Src/signames2.awk b/Src/signames2.awk
index 4d1557cd8..5738030c6 100644
--- a/Src/signames2.awk
+++ b/Src/signames2.awk
@@ -15,7 +15,7 @@
     if (signam == "CHLD" && sig[signum] == "CLD")  sig[signum] = ""
     if (signam == "POLL" && sig[signum] == "IO")   sig[signum] = ""
     if (signam == "ABRT" && sig[signum] == "IOT")  sig[signum] = ""
-    if (sig[signum] == "") {
+    if (signam !~ /RTM(IN|AX)/ && sig[signum] == "") {
 	sig[signum] = signam
 	if (0 + max < 0 + signum && signum < 60)
 	    max = signum
@@ -66,10 +66,6 @@ END {
     printf "#include %czsh.mdh%c\n", 34, 34
     printf "\n"
     printf "/**/\n"
-    printf "#define sigmsg(sig) ((sig) <= SIGCOUNT ? sig_msg[sig]"
-    printf " : %c%s%c)", 34, "unknown signal", 34
-    printf "\n"
-    printf "/**/\n"
     printf "mod_export char *sig_msg[SIGCOUNT+2] = {\n"
     printf "\t%c%s%c,\n", 34, "done", 34
 


^ permalink raw reply	[relevance 3%]

* [PATCH] (take 2) Local specials and Re: Regression of typeset output with "private"
  2024-02-18 19:35  5%   ` Bart Schaefer
@ 2024-02-20  4:54  3%     ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2024-02-20  4:54 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1604 bytes --]

On Sun, Feb 18, 2024 at 11:35 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> How about this?  It skips PM_RO_BY_DESIGN for any parameter not
> declared in the same scope where "typeset -p" is being run.  This
> means that in addition to displaying parameters declared private,
> it'll show cases where "local +h" has been used to shadow a special.

The more I think through this, the more I think it's the right thing
to do.  A couple of related observations:
1) It isn't necessary to use +h unless removing the -h attribute, the
default is to retain specialness even when local.  I usually include
it just for clarity, so in case we want to add it later I've left a
comment in the patch.
2) On the other hand, it is necessary to use -h for hiding, and
typeset -p did not preserve that flag on output before.

Consequently I've revised the patch to add the -h option for
parameters that have it.  This is also consistent with the output of
${(t)var} which shows the substring "hide".  The side-effect of this
is that private parameters are shown as having the -h property, which
is a bit closer to correct.

> [...] we should probably mention
> somewhere that "typeset -p" no longer displays values for the special
> parameters $!, $#, $-, $*, $@, $$, $?, $ARGC, etc.

Doc change added for this.  Also disabled "private -p" (it had already
been removed from the documentation) and update the doc to reflect
this.

> This is actually a change in 5.9 vs. 5.8 that was not
> included in the NEWS file.

I did not edit NEWS, yet.

This replaces workers/52557.

[-- Attachment #2: private-p2.txt --]
[-- Type: text/plain, Size: 7417 bytes --]

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 7a8654f27..784089594 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -2136,6 +2136,14 @@ tt(-p) may be followed by an optional integer argument.  Currently
 only the value tt(1) is supported.  In this case arrays and associative
 arrays are printed with newlines between indented elements for
 readability.
+
+The names and values of readonly special parameters
+(most of the parameters marked `<S>' in
+ifzman(zmanref(zshparam))ifnzman(noderef(Parameters Set By The Shell)),
+except those documented as settable)
+are not printed with `tt(-)tt(p)' because to execute those typeset commands
+would cause errors.  However, these parameters are printed when they
+have been made local to the scope where `tt(typeset -p)' is run.
 )
 item(tt(-T) [ var(scalar)[tt(=)var(value)] var(array)[tt(=LPAR())var(value) ...tt(RPAR())] [ var(sep) ] ])(
 This flag has a different meaning when used with tt(-f); see below.
diff --git a/Doc/Zsh/mod_private.yo b/Doc/Zsh/mod_private.yo
index 08ac4cafe..24c099f38 100644
--- a/Doc/Zsh/mod_private.yo
+++ b/Doc/Zsh/mod_private.yo
@@ -16,9 +16,10 @@ The tt(private) builtin accepts all the same options and arguments as tt(local)
 (ifzman(zmanref(zshbuiltins))ifnzman(noderef(Shell Builtin Commands))) except
 for the `tt(-)tt(T)' option.  Tied parameters may not be made private.
 
-The `tt(-)tt(p)' option is presently a no-op because the state of
-private parameters cannot reliably be reloaded.  This also applies
-to printing private parameters with `tt(typeset -p)'.
+The `tt(-)tt(p)' option is presently disabled because the state of
+private parameters cannot reliably be reloaded.  When `tt(typeset -)tt(p)'
+outputs a private parameter, it is treated as a local with the
+`tt(-)tt(h)' (hide) option enabled.
 
 If used at the top level (outside a function scope), tt(private) creates a
 normal parameter in the same manner as tt(declare) or tt(typeset).  A
diff --git a/Src/Modules/param_private.c b/Src/Modules/param_private.c
index 5003d4627..044617190 100644
--- a/Src/Modules/param_private.c
+++ b/Src/Modules/param_private.c
@@ -646,7 +646,7 @@ printprivatenode(HashNode hn, int printflags)
 
 static struct builtin bintab[] = {
     /* Copied from BUILTIN("local"), "P" added */
-    BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmprtux", "P")
+    BUILTIN("private", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_private, 0, -1, 0, "AE:%F:%HL:%PR:%TUZ:%ahi:%lnmrtux", "P")
 };
 
 static struct features module_features = {
diff --git a/Src/params.c b/Src/params.c
index fce3af940..b329d2079 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5896,6 +5896,7 @@ static const struct paramtypes pmtypes[] = {
     { PM_ARRAY, "array", 'a', 0},
     { PM_HASHED, "association", 'A', 0},
     { 0, "local", 0, PMTF_TEST_LEVEL},
+    { PM_HIDE, "hide", 'h', 0 },
     { PM_LEFT, "left justified", 'L', PMTF_USE_WIDTH},
     { PM_RIGHT_B, "right justified", 'R', PMTF_USE_WIDTH},
     { PM_RIGHT_Z, "zero filled", 'Z', PMTF_USE_WIDTH},
@@ -6025,13 +6026,21 @@ printparamnode(HashNode hn, int printflags)
 	printflags |= PRINT_NAMEONLY;
 
     if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
-	if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
+	if (p->node.flags & PM_AUTOLOAD) {
 	    /*
 	     * It's not possible to restore the state of
 	     * these, so don't output.
 	     */
 	    return;
 	}
+	if (p->node.flags & PM_RO_BY_DESIGN) {
+	    /*
+	     * Compromise: cannot be restored out of context,
+	     * but show anyway if printed in scope of declaration
+	     */
+	    if (p->level != locallevel || p->level == 0)
+		return;
+	}
 	/*
 	 * The zsh variants of export -p/readonly -p also report other
 	 * flags to indicate other attributes or scope. The POSIX variants
@@ -6064,8 +6073,19 @@ printparamnode(HashNode hn, int printflags)
 	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
 	    int doprint = 0;
 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
-		if (p->level)
+		if (p->level) {
+		    /*
+		    if ((p->node.flags & PM_SPECIAL) &&
+			(p->node.flags & PM_LOCAL) &&
+			!(p->node.flags & PM_HIDE)) {
+			if (doneminus)
+			    putchar(' ');
+			printf("+h ");
+			doneminus = 0;
+		    }
+		    */
 		    doprint = 1;
+		}
 	    } else if ((pmptr->binflag != PM_EXPORTED || p->level ||
 			(p->node.flags & (PM_LOCAL|PM_ARRAY|PM_HASHED))) &&
 		       (p->node.flags & pmptr->binflag))
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 8b3988151..d90f17d13 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -959,6 +959,20 @@
 >  [three]=''
 >)
 
+ () {
+  local -h status
+  typeset -p status
+ }
+0:parameter hiding preserved by "typeset -p"
+>typeset -h status=''
+
+ () {
+  local status
+  typeset -p status
+ }
+0:read-only special params are output when localized
+>typeset -i10 -r status=0
+
  (export PATH MANPATH
  path=(/bin)
  MANPATH=/
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index ebb70dd92..ff48e2289 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -464,7 +464,7 @@ F:unexpected side-effects of previous tests
  }
 0:up-reference part 3, hidden global
 >outside
->typeset var
+>typeset -h var
 
  () {
    typeset notdef
@@ -541,7 +541,7 @@ F:Same test, should part 5 output look like this?
  fi
 0:up-reference part 3, autoloading with hidden special
 >nameref-local-nameref-local
->typeset parameters
+>typeset -h parameters
 
  if [[ $options[typesettounset] != on ]]; then
    ZTST_skip='Ignoring zmodload bug that resets TYPESET_TO_UNSET'
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 9eeda0f47..4140d4e96 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -28,7 +28,7 @@
  print $scalar_test
 0:basic scope hiding
 >toplevel
->local scalar_test
+>local hide scalar_test
 >0
 >toplevel
 
@@ -54,7 +54,7 @@
  print $+unset_test
 0:variable defined only in scope
 >0
->local unset_test
+>local hide unset_test
 >setme
 >0
 
@@ -70,7 +70,7 @@
  }
  print $array_test
 0:nested scope with different type, correctly restored
->local array_test
+>local hide array_test
 >in function
 >top level
 
@@ -113,7 +113,7 @@
  typeset -a hash_test=(top level)
  typeset -p hash_test
  inner () {
-  private -p hash_test
+  typeset -p hash_test
   print ${(t)hash_test} ${(kv)hash_test}
  }
  outer () {
@@ -328,6 +328,7 @@ F:future revision will create a global with this assignment
 F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 *?*read-only variable: ptr2
 
  () {
@@ -348,10 +349,12 @@ F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 F:Assignment silently fails, is that correct?
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2=''
 >ptr1=ptr2
 >ptr1=
 >ptr2=
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2=''
 *?*no such variable: ptr2
 
  typeset ptr2
@@ -372,11 +375,13 @@ F:Assignment silently fails, is that correct?
 F:See K01typeset.ztst up-reference part 5
 F:Here ptr1 points to global ptr2 so assignment succeeds
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 >ptr1=ptr2
 >ptr2=val
 >ptr1=val
 >ptr2=val
 >typeset -n ptr1=ptr2
+>typeset -hn ptr2
 >typeset ptr2=val
 
  () {

^ permalink raw reply	[relevance 3%]

* Re: Regression of typeset output with "private"
  @ 2024-02-18 19:35  5%   ` Bart Schaefer
  2024-02-20  4:54  3%     ` [PATCH] (take 2) Local specials and " Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2024-02-18 19:35 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1050 bytes --]

On Fri, Feb 16, 2024 at 10:29 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> Traced this to here:
>
> >> commit f99f7dca7552d21782354f675c0741896c9785f1
> >> Author: Peter Stephenson <p.stephenson@samsung.com>
> >> Date:   Mon Oct 8 10:10:42 2018 +0100
> >>
> >>     43616: Various parameter setting and display fixes.
>
> in the context of explicitly asking for "typeset -p foo" it surely
> ought to print ... something?

How about this?  It skips PM_RO_BY_DESIGN for any parameter not
declared in the same scope where "typeset -p" is being run.  This
means that in addition to displaying parameters declared private,
it'll show cases where "local +h" has been used to shadow a special.

No doc included in this patch, but we should probably mention
somewhere that "typeset -p" no longer displays values for the special
parameters $!, $#, $-, $*, $@, $$, $?, $ARGC, etc. (unless "local +h"
per above)  This is actually a change in 5.9 vs. 5.8 that was not
included in the NEWS file.  Should it also be in the Doc?

[-- Attachment #2: private-p.txt --]
[-- Type: text/plain, Size: 1932 bytes --]

diff --git a/Src/params.c b/Src/params.c
index a722a20f6..ee5733af4 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -6025,13 +6025,21 @@ printparamnode(HashNode hn, int printflags)
 	printflags |= PRINT_NAMEONLY;
 
     if (printflags & (PRINT_TYPESET|PRINT_POSIX_READONLY|PRINT_POSIX_EXPORT)) {
-	if (p->node.flags & (PM_RO_BY_DESIGN|PM_AUTOLOAD)) {
+	if (p->node.flags & PM_AUTOLOAD) {
 	    /*
 	     * It's not possible to restore the state of
 	     * these, so don't output.
 	     */
 	    return;
 	}
+	if (p->node.flags & PM_RO_BY_DESIGN) {
+	    /*
+	     * Compromise: cannot be restored out of context,
+	     * but show anyway if printed in scope of declaration
+	     */
+	    if (p->level != locallevel || p->level == 0)
+		return;
+	}
 	/*
 	 * The zsh variants of export -p/readonly -p also report other
 	 * flags to indicate other attributes or scope. The POSIX variants
diff --git a/Test/V10private.ztst b/Test/V10private.ztst
index 9eeda0f47..11ac92f03 100644
--- a/Test/V10private.ztst
+++ b/Test/V10private.ztst
@@ -328,6 +328,7 @@ F:future revision will create a global with this assignment
 F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 *?*read-only variable: ptr2
 
  () {
@@ -348,10 +349,12 @@ F:See K01nameref.ztst up-reference part 5
 F:Here ptr1 finds private ptr2 by scope mismatch
 F:Assignment silently fails, is that correct?
 >typeset -n ptr1=ptr2
+>typeset -n ptr2=''
 >ptr1=ptr2
 >ptr1=
 >ptr2=
 >typeset -n ptr1=ptr2
+>typeset -n ptr2=''
 *?*no such variable: ptr2
 
  typeset ptr2
@@ -372,11 +375,13 @@ F:Assignment silently fails, is that correct?
 F:See K01typeset.ztst up-reference part 5
 F:Here ptr1 points to global ptr2 so assignment succeeds
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 >ptr1=ptr2
 >ptr2=val
 >ptr1=val
 >ptr2=val
 >typeset -n ptr1=ptr2
+>typeset -n ptr2
 >typeset ptr2=val
 
  () {

^ permalink raw reply	[relevance 5%]

* Re: [PATCH][nitpick-BUG] shebang less scripts and paths starting with -/+
  2024-02-04  9:06  6% [PATCH][nitpick-BUG] shebang less scripts and paths starting with -/+ Stephane Chazelas
@ 2024-02-10 16:32  6% ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2024-02-10 16:32 UTC (permalink / raw)
  To: Zsh hackers list

2024-02-04 09:06:27 +0000, Stephane Chazelas:
[...]
> $ echo echo ++ > ++
> $ chmod +x ++
> $ strace -qqfe /exec zsh -c 'PATH=; ++'
> execve("/usr/bin/zsh", ["zsh", "-c", "PATH=; ++"], 0x7fffadb8e870 /* 55 vars */) = 0
> execve("++", ["++"], 0x7ffc57750de8 /* 55 vars */) = -1 ENOEXEC (Exec format error)
> execve("/bin/sh", ["sh", "++"], 0x7ffc57750de8 /* 55 vars */) = 0
> sh: 0: Illegal option -+
> 
> The path of the script was passed as an option to sh rather than
> an operand.
> 
> The patch below changes it to:
> 
> $ strace -qqfe /exec Src/zsh -c 'PATH=; ++'
> execve("Src/zsh", ["Src/zsh", "-c", "PATH=; ++"], 0x7ffd2a923100 /* 55 vars */) = 0
> execve("++", ["++"], 0x7ffd8d292448 /* 55 vars */) = -1 ENOEXEC (Exec format error)
> execve("/bin/sh", ["sh", "-", "++"], 0x7ffd8d292448 /* 55 vars */) = 0
> ++
[...]

Sorry, forgot to add a test case:

diff --git a/Src/exec.c b/Src/exec.c
index 7d8135266..9c8bbb458 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -612,9 +612,22 @@ zexecve(char *pth, char **argv, char **newenvp)
                         }
                     }
 		    if (!isbinary) {
-			argv[-1] = "sh";
+		        char** args = argv;
+			if (argv[0][0] == '-' || argv[0][0] == '+') {
+			    /*
+			     * guard against +foo or -bar script paths being
+			     * taken as options. POSIX says the script path
+			     * must be passed as an *operand*. "--" would also
+			     * make sure the next argument is treated as an
+			     * operand with POSIX compliant sh implementations
+			     * but "-" is more portable (to the Bourne shell in
+			     * particular) and shorter.
+			     */
+			    *--args = "-";
+			}
+			*--args = "sh";
 			winch_unblock();
-			execve("/bin/sh", argv - 1, newenvp);
+			execve("/bin/sh", args, newenvp);
 		    }
 		}
 	    } else
diff --git a/Test/A05execution.ztst b/Test/A05execution.ztst
index bcadc6d56..07a24f9c8 100644
--- a/Test/A05execution.ztst
+++ b/Test/A05execution.ztst
@@ -2,7 +2,7 @@
 
   storepath=($path)
 
-  mkdir command.tmp command.tmp/dir1 command.tmp/dir2
+  mkdir command.tmp command.tmp/dir{1,2} command.tmp/{+,-}dir
 
   cd command.tmp
 
@@ -21,7 +21,10 @@
   print '#!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxnyyy' >tstcmd-interp-too-long
   print "#!${sh}\necho should not execute; exit 1" >xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn
 
-  chmod 755 tstcmd dir1/tstcmd dir2/tstcmd
+  print 'echo no shebang in -dir' > -dir/tstcmd
+  print 'echo no shebang in +dir' > +dir/tstcmd
+
+  chmod 755 tstcmd dir{1,2}/tstcmd ./{-,+}dir/tstcmd
   chmod 755 tstcmd-slashless tstcmd-arg tstcmd-interp-too-long
   chmod 755 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxn
 
@@ -422,3 +425,12 @@ F:anonymous function, and a descriptor leak when backgrounding a pipeline
  (exit 4); repeat 0 do done
 0:'repeat 0' resets lastval
 
+ -dir/tstcmd
+ +dir/tstcmd
+ PATH=-dir tstcmd
+ PATH=+dir tstcmd
+0:shebang-less scripts are to be run by sh even when their file paths start with - or + (workers/52515)
+>no shebang in -dir
+>no shebang in +dir
+>no shebang in -dir
+>no shebang in +dir


^ permalink raw reply	[relevance 6%]

* [PATCH][nitpick-BUG] shebang less scripts and paths starting with -/+
@ 2024-02-04  9:06  6% Stephane Chazelas
  2024-02-10 16:32  6% ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2024-02-04  9:06 UTC (permalink / raw)
  To: Zsh hackers list

Hello,

$ echo echo ++ > ++
$ chmod +x ++
$ strace -qqfe /exec zsh -c 'PATH=; ++'
execve("/usr/bin/zsh", ["zsh", "-c", "PATH=; ++"], 0x7fffadb8e870 /* 55 vars */) = 0
execve("++", ["++"], 0x7ffc57750de8 /* 55 vars */) = -1 ENOEXEC (Exec format error)
execve("/bin/sh", ["sh", "++"], 0x7ffc57750de8 /* 55 vars */) = 0
sh: 0: Illegal option -+

The path of the script was passed as an option to sh rather than
an operand.

The patch below changes it to:

$ strace -qqfe /exec Src/zsh -c 'PATH=; ++'
execve("Src/zsh", ["Src/zsh", "-c", "PATH=; ++"], 0x7ffd2a923100 /* 55 vars */) = 0
execve("++", ["++"], 0x7ffd8d292448 /* 55 vars */) = -1 ENOEXEC (Exec format error)
execve("/bin/sh", ["sh", "-", "++"], 0x7ffd8d292448 /* 55 vars */) = 0
++

yash is the only other shell I've found so far that guards
against it. It does add the "-" unconditionally. Here I add it
only if the path starts with - or + which would be extremely
rare to avoid getting closer to the E2BIG limit in the normal
case.

Also note (related though this patch doesn't do anything about
it other than adding the "-"):

$ strace -qqfe /exec zsh -c 'PATH=.; ++'
execve("/usr/bin/zsh", ["zsh", "-c", "PATH=.; ++"], 0x7ffcf4504b50 /* 55 vars */) = 0
execve("++", ["++"], 0x7ffc2a099678 /* 55 vars */) = -1 ENOEXEC (Exec format error)
execve("/bin/sh", ["sh", "++"], 0x7ffc2a099678 /* 55 vars */) = 0
sh: 0: Illegal option -+

Is that intentional? I'd have expected execve("./++", ["++"]...)
as $path contains the "." relative path there.

$ strace -qqfe /exec zsh -c 'PATH=./.; ++'
execve("/usr/bin/zsh", ["zsh", "-c", "PATH=./.; ++"],
0x7ffddeba1840 /* 55 vars */) = 0
execve("././++", ["++"], 0x7ffc4dfe9ae8 /* 55 vars */) = -1
ENOEXEC (Exec format error)
execve("/bin/sh", ["sh", "././++"], 0x7ffc4dfe9ae8 /* 55 vars
*/) = 0
++

There are a number of scripts in the source distribution whose
shebang is missing the "-", and which this patch doesn't
address. See also
https://unix.stackexchange.com/questions/351729/why-the-in-the-bin-sh-shebang


diff --git a/Src/exec.c b/Src/exec.c
index 7d8135266..294587802 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -612,9 +612,22 @@ zexecve(char *pth, char **argv, char **newenvp)
                         }
                     }
 		    if (!isbinary) {
-			argv[-1] = "sh";
+		        char** args = argv;
+			if (argv[0][0] == '-' || argv[0][0] == '+') {
+			    /*
+			     * guard against +foo or -bar script paths being
+			     * taken as options.  POSIX says the script path
+			     * must be passed as an *operand*. "--" would also
+			     * make sure the next argument is treated as an
+			     * operand with POSIX compliant sh implementations
+			     * but "-" is more portable (to the Bourne shell in
+			     * particular) and shorter.
+			     */
+			    *--args = "-"; 
+			}
+			*--args = "sh";
 			winch_unblock();
-			execve("/bin/sh", argv - 1, newenvp);
+			execve("/bin/sh", args, newenvp);
 		    }
 		}
 	    } else


^ permalink raw reply	[relevance 6%]

* Re: [PATCH v2] string.c: remove use of strcat() after strlen()
  2023-12-31  5:10  3%   ` James
  2023-12-31  5:20  0%     ` Bart Schaefer
@ 2024-01-28  0:57  0%     ` Oliver Kiddle
  1 sibling, 0 replies; 200+ results
From: Oliver Kiddle @ 2024-01-28  0:57 UTC (permalink / raw)
  To: James; +Cc: Bart Schaefer, zsh-workers

On 31 Dec, James wrote:
> Since we are already calling strlen() beforehand to know the size of
> allocation, we can just memcpy() from BASE + BASE_LEN and avoid another strlen
> () call in strcat(). We should prefer memcpy() because we always know the
> length and most libc implementations provide an assembly implementation of
> memcpy but maybe not strcpy(). Even if it is implemented in assembly, memcpy()
> is likely to be faster than strcpy() since as the loop condition strcpy() needs
> to check for zeros in SRC, whereas memcpy() can just decrement the size.
>
> I'm using a MEMPCPY macro because I don't know how zsh handles using GNU/POSIX
> extensions.

Many OS-specific extensions are used. We'd normally add a test in
configure.ac and then check for that so the macro could be wrapped in
#ifndef HAVE_MEMPCPY
And such macros may preserve the original lowercase which can be less
ugly. Calling the actual system mempcpy may be more efficient than the
macro because it probably already has a pointer to the end. FreeBSD
also has mempcpy().

If it is meant as an optimisation it could be worth verifying that it
has an effect. I don't especially find the modified code any easier to
read. I find it quicker and easier to scan when simple nested calls like
strlen() are not first taken out and assigned to a variable. If it does
make things faster, there may be other places in the code where appstr()
could have been used but strcat/realloc were used directly.

Oliver


^ permalink raw reply	[relevance 0%]

* Re: [PATCH v2] Fix jobs -p to be POSIX compliant
  2024-01-20 12:30  7% ` [PATCH v2] " Wesley Schwengle
@ 2024-01-20 21:14  9%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2024-01-20 21:14 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: zsh-workers

On Sat, Jan 20, 2024 at 4:31 AM Wesley Schwengle
<wesleys@opperschaap.net> wrote:
>
> POSIX says that with "jobs -p", only the PID is output, whereas zsh
> outputs full information.
>
> There is discussion in the bug regarding POSIX_BUILTINS and refers to
> workers/21366. The latter is interesting because it refers to setopt
> long_list_jobs. I would want to argue that jobs -p should only show the
> PID regardless of that setting and POSIX_BUILTINS. jobs has the -l
> option, where the full line is displayed. From that point it doesn't
> make a whole lot of sense to have jobs -p do the same thing.

This is not correct.  As you noted later, "jobs -p" lists information
about process group leaders only, whereas "jobs -l" lists all jobs.
This differs mainly when there's a pipeline:

% sleep 30 | sleep 20 | sleep 10 &
[1] 67157 67158 67159
% jobs -p
[1]  + 67157 running    sleep 30 |
             running    sleep 20 | sleep 10
% jobs -l
[1]  + 67157 running    sleep 30 |
       67158 running    sleep 20 |
       67159 running    sleep 10
%

> Than there is the issue where its argued that zsh shows the group pid
> and not the actual pid of the process that is running. I looked at the
> output of bash and with this patch zsh and bash act similar.

More relevant is how they compare without the patch.

If we really wanted to make this POSIX compliant, we should arrange
that "jobs -lp" shows "more information" only about process group
leaders (currently -l simply overrides -p) and add "jobs -n" to
produce the notifications that are suppressed by "setopt no_notify"
(setopt long_list_jobs would apply here).

However, I'm generally not in favor of changing longstanding zsh
behavior for POSIX compliance without some kind of additional
conditions, such as [[ -o POSIX_JOBS ]] in this case.


^ permalink raw reply	[relevance 9%]

* [PATCH v2] Fix jobs -p to be POSIX compliant
  2024-01-19 23:22  9% [PATCH] Fix jobs -p to be POSIX compliant Wesley Schwengle
@ 2024-01-20 12:30  7% ` Wesley Schwengle
  2024-01-20 21:14  9%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Wesley Schwengle @ 2024-01-20 12:30 UTC (permalink / raw)
  To: zsh-workers

In Debian the following bug was reported a couple of year ago and
someone re-raised it:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=346162

POSIX says that with "jobs -p", only the PID is output, whereas zsh
outputs full information.

There is discussion in the bug regarding POSIX_BUILTINS and refers to
workers/21366. The latter is interesting because it refers to setopt
long_list_jobs. I would want to argue that jobs -p should only show the
PID regardless of that setting and POSIX_BUILTINS. jobs has the -l
option, where the full line is displayed. From that point it doesn't
make a whole lot of sense to have jobs -p do the same thing. From a UI
standpoint I think it is more logical to let jobs -l do a long listing
and jobs -p only show the pid.

Than there is the issue where its argued that zsh shows the group pid
and not the actual pid of the process that is running. I looked at the
output of bash and with this patch zsh and bash act similar. They both
show the pid of the command group:

On bash:

$ ( sleep 20 && echo foo) & sleep 5 &
$ jobs -p && jobs -l
255028
255029
[1]- 255028 Running                 ( sleep 20 && echo foo ) &
[2]+ 255029 Done                    sleep 5

On zsh with this patch:

$ ( sleep 20 && echo foo) & sleep 5 &
$ jobs -l && jobs -p
[1] 255065
[2] 255066
[1]  - 255065 running    ( sleep 20 && echo foo; )
[2]  + 255066 running    sleep 5
255065
255066

Signed-off-by: Wesley Schwengle <wesleys@opperschaap.net>
---
 Src/jobs.c        | 16 ++++++----------
 Test/W02jobs.ztst |  2 +-
 2 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/Src/jobs.c b/Src/jobs.c
index 118c5e61b..14f1be831 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1209,6 +1209,11 @@ printjob(Job jn, int lng, int synch)
 	    putc('\n', fout);
 	}
 	for (pn = jn->procs; pn;) {
+	    if (lng & 2) {
+		fprintf(fout, "%ld\n", (long) jn->gleader);
+		doneprint = 1;
+		break;
+	    }
 	    len2 = (thisfmt ? 5 : 10) + len;	/* 2 spaces */
 	    if (lng & 3)
 		qn = pn->next;
@@ -1235,16 +1240,7 @@ printjob(Job jn, int lng, int synch)
 		    fprintf(fout, "zsh: ");
 		if (lng & 1)
 		    fprintf(fout, "%ld ", (long) pn->pid);
-		else if (lng & 2) {
-		    pid_t x = jn->gleader;
-
-		    fprintf(fout, "%ld ", (long) x);
-		    do
-			skip++;
-		    while ((x /= 10));
-		    skip++;
-		    lng &= ~3;
-		} else
+		else
 		    fprintf(fout, "%*s", skip, "");
 		if (pn->status == SP_RUNNING) {
 		    if (!conted)
diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index d52888dd9..11bbdbf43 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -128,7 +128,7 @@
 0:`jobs -l` and `jobs -p` with running job
 *>\[1] [0-9]##
 *>\[1]  + [0-9]## running*sleep*
-*>\[1]  + [0-9]## running*sleep*
+*>[0-9]##
 *>zsh:*SIGHUPed*
 
   zpty_start
-- 
2.42.0.1140.gf01f4dc781



^ permalink raw reply	[relevance 7%]

* [PATCH] Fix jobs -p to be POSIX compliant
@ 2024-01-19 23:22  9% Wesley Schwengle
  2024-01-20 12:30  7% ` [PATCH v2] " Wesley Schwengle
  0 siblings, 1 reply; 200+ results
From: Wesley Schwengle @ 2024-01-19 23:22 UTC (permalink / raw)
  To: zsh-workers

In Debian the following bug was reported:
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=346162

POSIX says that with "jobs -p", only the PID is output, whereas zsh
outputs full information.

There is discussion in the bug regarding POSIX_BUILTINS and refers to
workers/21366. The latter is interesting because it refers to setopt long_list_jobs.
I would want to argue that jobs -p should only show the PID regardless
of that setting and POSIX_BUILTINS. jobs has the -l option, where the
full line is displayed.

These patch makes the jobs -p POSIX compliant

Signed-off-by: Wesley Schwengle <wesleys@opperschaap.net>
---
 Src/jobs.c        | 18 ++++++++----------
 Test/W02jobs.ztst |  2 +-
 2 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/Src/jobs.c b/Src/jobs.c
index 118c5e61b..50f4fa3cf 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1209,6 +1209,13 @@ printjob(Job jn, int lng, int synch)
 	    putc('\n', fout);
 	}
 	for (pn = jn->procs; pn;) {
+	    if (lng & 2) {
+		pid_t x = jn->gleader;
+		fprintf(fout, "%ld", (long) x);
+		putc('\n', fout);
+		doneprint = 1;
+		break;
+	    }
 	    len2 = (thisfmt ? 5 : 10) + len;	/* 2 spaces */
 	    if (lng & 3)
 		qn = pn->next;
@@ -1235,16 +1242,7 @@ printjob(Job jn, int lng, int synch)
 		    fprintf(fout, "zsh: ");
 		if (lng & 1)
 		    fprintf(fout, "%ld ", (long) pn->pid);
-		else if (lng & 2) {
-		    pid_t x = jn->gleader;
-
-		    fprintf(fout, "%ld ", (long) x);
-		    do
-			skip++;
-		    while ((x /= 10));
-		    skip++;
-		    lng &= ~3;
-		} else
+		else
 		    fprintf(fout, "%*s", skip, "");
 		if (pn->status == SP_RUNNING) {
 		    if (!conted)
diff --git a/Test/W02jobs.ztst b/Test/W02jobs.ztst
index d52888dd9..11bbdbf43 100644
--- a/Test/W02jobs.ztst
+++ b/Test/W02jobs.ztst
@@ -128,7 +128,7 @@
 0:`jobs -l` and `jobs -p` with running job
 *>\[1] [0-9]##
 *>\[1]  + [0-9]## running*sleep*
-*>\[1]  + [0-9]## running*sleep*
+*>[0-9]##
 *>zsh:*SIGHUPed*
 
   zpty_start
-- 
2.42.0.1140.gf01f4dc781



^ permalink raw reply	[relevance 9%]

* Re: [PATCH v2] string.c: remove use of strcat() after strlen()
  2023-12-31  5:10  3%   ` James
@ 2023-12-31  5:20  0%     ` Bart Schaefer
  2024-01-28  0:57  0%     ` Oliver Kiddle
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2023-12-31  5:20 UTC (permalink / raw)
  To: James; +Cc: zsh-workers

On Sat, Dec 30, 2023 at 9:10 PM James <tirtajames45@gmail.com> wrote:
>
> Since we are already calling strlen() beforehand to know the size of allocation, we can just memcpy()

Fair enough, but the function you've optimized is called so seldom
that this is not going to have a meaningful effect on performance.

> I'm using a MEMPCPY macro because I don't know how zsh handles using GNU/POSIX extensions.

Please explain why that matters?  The macro is used exactly once after
being declared and there are no preprocesor conditionals around it.


^ permalink raw reply	[relevance 0%]

* Re: [PATCH v2] string.c: remove use of strcat() after strlen()
  @ 2023-12-31  5:10  3%   ` James
  2023-12-31  5:20  0%     ` Bart Schaefer
  2024-01-28  0:57  0%     ` Oliver Kiddle
  0 siblings, 2 replies; 200+ results
From: James @ 2023-12-31  5:10 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 862 bytes --]

Since we are already calling strlen() beforehand to know the size of
allocation, we can just memcpy() from BASE + BASE_LEN and avoid another
strlen() call in strcat(). We should prefer memcpy() because we always know
the length and most libc implementations provide an assembly implementation
of memcpy but maybe not strcpy(). Even if it is implemented in assembly,
memcpy() is likely to be faster than strcpy() since as the loop condition
strcpy() needs to check for zeros in SRC, whereas memcpy() can just
decrement the size.

I'm using a MEMPCPY macro because I don't know how zsh handles using
GNU/POSIX extensions.

On Sun, Dec 31, 2023 at 11:22 AM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> I take it this is intended to be an optimization?
>
> Please do provide some background / rationale when sending a patch.
> Thanks.
>

[-- Attachment #2: Type: text/html, Size: 1150 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: set temporary environment variables for builtins
       [not found]           ` <CAH+w=7YrzKuBygXeDt+BkmScJTvqqSwWm-6Y_oFgW1tuFdtk+g@mail.gmail.com>
@ 2023-12-16 20:33  3%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2023-12-16 20:33 UTC (permalink / raw)
  To: Zsh hackers list

On Sat, Dec 16, 2023 at 12:27 PM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> It works for parameters that zsh separately
> considers to be "special", which includes all the LC_*

Theoretically, I suppose, this means that for POSIX compatibility all
parameters that appear in assignments prefixing a simple command
should have their PM_HIDE bit set, so they cease to be special.


^ permalink raw reply	[relevance 3%]

* PATCH: add -q option to kill for sigqueue
@ 2023-11-24 23:46  2% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2023-11-24 23:46 UTC (permalink / raw)
  To: Zsh workers

The following adds support for a -q option to kill which takes a numeric
argument. It then uses sigqueue(2) to send the signal with the provided
number which a signal handler can pick up as si_value.sival_int in the
siginfo_t parameter. The util-linux kill also supports a similar option.
sigqueue and a range of "realtime" signals are specified in POSIX and
well supported. As far as I can tell, the RT signals are intended for
user-defined purposes like SIGUSR1 and USR2. The value can be an int or
a pointer but in practice, sending a pointer is fairly useless given
that signals are usually sent to a different process.

We could potentially make the signal value and other details such as
si_pid available to trap handlers. Perhaps using namespaced variables -
e.g. .signal.pid and .signal.value? However, I don't really understand
enough about how trap is implemented to know how (or whether) that can
be done safely.

It also ought to be possible to make SIGRTMIN through to SIGRTMAX
available. util-linux's kill allows those to be specified as RT<n>,
RTMIN+<n> or RTMAX-<n>. Would that need us to muck around with
signames2.awk or is leaving them out of $signals / kill -l and using
#ifdef RTMIN sufficient?

Oliver

diff --git a/Src/jobs.c b/Src/jobs.c
index a3b9f667a..4e9767ee4 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -2677,9 +2677,35 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 {
     int sig = SIGTERM;
     int returnval = 0;
+#ifdef HAVE_SIGQUEUE
+    union sigval sigqueue_info;
+#endif
+    int use_sigqueue = 0, got_sig = 0;
+
+    while (*argv && **argv == '-') {
+	if (!use_sigqueue && (*argv)[1] == 'q' && (*argv)[2] == '\0') {
+	    char *endp;
+
+	    if (!*++argv) {
+		zwarnnam(nam, "-q: argument expected");
+		return 1;
+	    }
+#ifdef HAVE_SIGQUEUE
+	    sigqueue_info.sival_int =
+#endif
+		    zstrtol(*argv, &endp, 10);
+	    if (*endp) {
+		zwarnnam(nam, "invalid number: %s", *argv);
+		return 1;
+	    }
+	    use_sigqueue = 1;
+	    argv++;
+	    continue;
+	}
+	if (got_sig)
+	    break;
 
     /* check for, and interpret, a signal specifier */
-    if (*argv && **argv == '-') {
 	if (idigit((*argv)[1])) {
 	    char *endp;
 	    /* signal specified by number */
@@ -2796,6 +2822,7 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 	    }
 	}
 	argv++;
+	got_sig = 1;
     }
 
     /* Discard the standard "-" and "--" option breaks */
@@ -2844,7 +2871,12 @@ bin_kill(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
 	    returnval++;
 	} else {
 	    int pid = atoi(*argv);
-	    if (kill(pid, sig) == -1) {
+	    if (
+#ifdef HAVE_SIGQUEUE
+		use_sigqueue ? sigqueue(pid, sig, sigqueue_info) :
+#endif
+		kill(pid, sig) == -1)
+	    {
 		zwarnnam("kill", "kill %s failed: %e", *argv, errno);
 		returnval++;
 	    } 
diff --git a/configure.ac b/configure.ac
index c5263035e..9cb6e032b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1299,6 +1299,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       mkfifo _mktemp mkstemp \
 	       waitpid wait3 \
 	       sigaction sigblock sighold sigrelse sigsetmask sigprocmask \
+	       sigqueue \
 	       killpg setpgid setpgrp tcsetpgrp tcgetattr nice \
 	       gethostname gethostbyname2 getipnodebyname \
 	       inet_aton inet_pton inet_ntop \


^ permalink raw reply	[relevance 2%]

* PATCH: completion options update
@ 2023-11-20  0:11  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2023-11-20  0:11 UTC (permalink / raw)
  To: Zsh workers

This is an update based on the usual help output diffs. Quite a few
files changed, mostly fairly minor.

For iptables, I've only bothered with the options that are always
accepted and not handled the many new extended match options that need a
-m option to be enabled. This adds arptables and entables to the compdef
line without making much attempt to handle the specifics of those.

xdvi updates are also incomplete.

_strip changes are mainly adding support for elftoolchain (FreeBSD)

enscript is a minor fix rather than new options.

Latest versions I have checked are as follows:

binutils 2.40.0 / elfutils 0.189 / elftoolchain 3769
btrfs 6.5.1
coreutils 9.4
dbus-send 1.14.10
dig 9.18.19
dmidecode 3.5
ethtool 6.5
evince 45.0
flac 1.4.2
gawk 5.2.2
gnupg 2.4.3
gnutls 3.8.1
iptables 1.8.8
less 643
libtiff 4.4.0
lsof 4.98.0
lua 5.4.6
mpc 0.34
pandoc 3.1.8
perl 5.38.0
ping 20221126
procps 4.0.3
pv 1.6.20
qiv 2.3.2
rsync 3.2.7
samba 4.19.2
shadow-utils 4.14.0
sqlite 3.43.1
sysstat 12.6.2
trace 6.6
util-linux 2.39.2
valgrind 3.19.0
wget 1.21.4
xsltproc 10138
xxd 2023-09-04
cat - macOS 13
chflags - various recent BSDs
truss and pkg5 - a fairly old snapshot of Solaris 11.4

Oliver

diff --git a/Completion/BSD/Command/_chflags b/Completion/BSD/Command/_chflags
index 924b09acd..905aa0645 100644
--- a/Completion/BSD/Command/_chflags
+++ b/Completion/BSD/Command/_chflags
@@ -1,22 +1,31 @@
 #compdef chflags
 
-local args own='-g *(-u$EUID)'
+local own='-g *(-u$EUID)'
+local -a args recurse
 
 (( ! EUID || $+_comp_priv_prefix )) && own=
 
-if [[ $OSTYPE = (darwin|dragonfly|freebsd)* ]]; then
-  args=(
-    "-f[don't display diagnostic messages]"
-    '-v[verbose output]'
-  )
-fi
+case $OSTYPE in
+  (darwin|dragonfly|freebsd)*)
+    args=(
+      "-f[don't display diagnostic messages]"
+      '-v[verbose output]'
+    )
+  ;|
+  darwin*|freebsd*)
+    recurse=( "-x[don't cross mount points]" )
+  ;|
+  netbsd*)
+    args=( '-d[if the change requested would not alter the flags, attempt no change]' )
+  ;|
+esac
 
 _arguments -s -A "-*" : $args \
   ': :_file_flags' \
   '*:file:_files "$own"' \
   - opth \
   '-h[act on symlinks]' \
-  - optR \
+  - optR $recurse \
   '-R[recurse directories]' \
   '(-L -P)-H[follow symlinks on the command line (specify with -R)]' \
   '(-H -P)-L[follow all symlinks (specify with -R)]' \
diff --git a/Completion/Linux/Command/_btrfs b/Completion/Linux/Command/_btrfs
index 1d87fd83a..d8b97a200 100644
--- a/Completion/Linux/Command/_btrfs
+++ b/Completion/Linux/Command/_btrfs
@@ -8,16 +8,16 @@ groups=( subvolume filesystem device scrub balance inspect-internal property
          quota qgroup replace rescue check restore send receive
          help version )
 cmds_1=( create delete list snapshot get-default set-default find-new show sync help )
-cmds_2=( df du show sync defragment resize label usage help )
+cmds_2=( df du show sync defragment resize label mkswapfile usage help )
 cmds_3=( add delete remove ready scan stats usage help )
 cmds_4=( start cancel resume status help )
 cmds_5=( start pause cancel resume status )
-cmds_6=( dump-{super,tree} {inode,logical,subvolid}-resolve min-dev-size rootid tree-stats help )
+cmds_6=( dump-{super,tree} {inode,logical,subvolid}-resolve map-swapfile min-dev-size rootid tree-stats help )
 cmds_7=( get set list )
 cmds_8=( enable disable rescan help )
-cmds_9=( assign remove create destroy show limit help )
+cmds_9=( assign remove create clear-stale destroy show limit help )
 cmds_10=( start status cancel help )
-cmds_11=( chunk-recover fix-device-size super-recover zero-log create-control-device )
+cmds_11=( chunk-recover clear-uuid-tree fix-device-size super-recover zero-log create-control-device )
 
 _arguments -C -A "-*" "$args[@]" \
   '(- *)--help[print help information]' \
@@ -25,6 +25,7 @@ _arguments -C -A "-*" "$args[@]" \
   '(-v --verbose -q --quiet --help --version)'{-v,--verbose}'[verbose output of operation]' \
   '(-v --verbose -q --quiet --help --version)'{-q,--quiet}'[suppress all messages except errors]' \
   '(--help --version)--format=[specify output format]:format:(text json)' \
+  '(--help --version)--log=[set log level]:level:(default info verbose debug quiet)' \
   '(--version)1: :->groups' \
   '2: :->cmds' \
   '*:: :->args' && ret=0
@@ -151,7 +152,7 @@ while (( $#state )); do
         filesystem:defragment)
           args+=( '!-v'
             '-r[defragment files recursively]'
-            '-c+[compress files while defragmenting]::compression algorithm:(zlib lzo zstd)'
+            '-c-[compress files while defragmenting]::compression algorithm:(zlib lzo zstd)'
             '-r[defragment files recursively]'
             '-f[flush after defragmenting]'
             '-s[start position]: :_numbers -u bytes -d "beginning of file" offset K M G T P E'
@@ -171,6 +172,13 @@ while (( $#state )); do
             '1: :_guard "^-*" uuid or label'
           )
         ;;
+        filesystem:mkswapfile)
+          args+=(
+            '-s[size]: :_numbers -d "2GiB" size K M G T P E'
+            '(-u --uuid)'{-u,--uuid}'[specify a uuid to use]:uuid:(clear random time)'
+            ':file:_files'
+          )
+        ;;
         filesystem:usage) args+=( '-T[show data in tabular format]' );;
         device:(add|delete|ready|remove))
           args+=(
@@ -194,6 +202,7 @@ while (( $#state )); do
           args+=(
             '(-c --check)'{-c,--check}'[return non-zero if any stat counter is not zero]'
             '(-z --reset)'{-z,--reset}'[reset stats when done]'
+            '-T[show current stats in tabular format]'
             "1:device or mountpoint:_files -g '*(-%,/)'"
           )
         ;;
@@ -233,7 +242,7 @@ while (( $#state )); do
         ;;
         balance:status) args+=( '!-v' '!--verbose' '1:path:_files -/' );;
         balance:(pause|cancel|resume)) args+=( '1:path:_files -/' );;
-        property:set) args+=( '3:value' );&
+        property:set) args+=( '-f[force the change]' '3:value' );&
         property:get) args+=( '2:property:(ro label compression)' );&
         property:list)
           args+=(
@@ -244,8 +253,9 @@ while (( $#state )); do
         quota:(enable|disable)) args+=( '1:path:_files -/' );;
         quota:rescan)
           args+=(
-            '-s[show status of currently running rescan]'
-            '-w[wait for rescan to finish]'
+            '(-s --status)'{-s,--status}'[show status of currently running rescan]'
+            '(-w --wait -W --wait-norescan)'{-w,--wait}'[wait for rescan to finish]'
+            '(-w --wait -W --wait-norescan)'{-w,--wait-norescan}'[wait for rescan to finish without starting it]'
             '1:path:_files -/'
           )
         ;;
@@ -268,11 +278,14 @@ while (( $#state )); do
             '-F[list impacted qgroups \(include ancestral qgroups\)]'
             '-f[list impacted qgroups \(exclude ancestral qgroups\)]'
             '--sort=-[sort qgroups]:sort:_values -s , sort \
-              qgroupid rfer excl max_rfer max_excl'
+              qgroupid rfer excl max_rfer max_excl path'
             '--sync[do filesystem sync before getting information]'
             '1:path:_files -/'
           )
         ;;
+        qgroup:clear-stale)
+          args+=( '(-q --quiet)'{-q,--quiet}'[print only errors]' '1:path:_files -/' )
+        ;;
         qgroup:limit)
           args+=(
             '-c[limit amount of data after compression]'
@@ -287,6 +300,7 @@ while (( $#state )); do
             '-r[read from specified source device only]:srcdev:_files'
             '-f[force overwriting of target]'
             "-B[don't background]"
+            '(-K --nodiscard)'{-K,--nodiscard}"[don't perform whole device TRIM]"
             ':srcdev or devid:_files'
             ':target:_files'
             ':path:->mounts'
@@ -332,6 +346,12 @@ while (( $#state )); do
             '2:filesystem path:_files -/'
           )
         ;;
+        inspect*:map-swapfile)
+          args+=(
+            '(-r --resume-offset)'{-r,--resume-offset}'[print only the value suitable as resume offset for file /sys/power/resume_offset]'
+            ':file:_files'
+          )
+        ;;
         inspect*:min*) args+=( '--id[specify the device id to query]:device id [1]' );;
         inspect*:rootid) args+=( '1:path:_files -/' );;
         inspect*:tree*) args+=( '-b[print raw numbers in bytes]' );;
@@ -395,6 +415,8 @@ while (( $#state )); do
             '*-c[use snapshot as clone source]:clone:_files -/'
             '-f[specify output file]:file:_files'
             '--no-data[send in NO_FILE_DATA mode]'
+            '--proto[specify protocol version]:version'
+            '--compressed-data[send data that is compressed on the filesystem directly without decompressing it]'
             '1:subvolume:_files -/'
           )
         ;;
@@ -405,6 +427,7 @@ while (( $#state )); do
             '(-C --chroot)'{-C,--chroot}'[confine the process to destination path using chroot(1)]'
             '(-E --max-errors)'{-E,--max-errors}'[terminate as soon as specified number of errors occur]:errors [1]'
             '(--dump)-m[specify root mount point of the destination filesystem]:mount point:_directories'
+            '--force-decompress[if the stream contains compressed data, always decompress it]'
             '(-m)--dump[dump stream metadata, one line per operation]'
             '1:mount:->mounts'
           )
diff --git a/Completion/Linux/Command/_ethtool b/Completion/Linux/Command/_ethtool
index 95a8bbfb6..3e3fc0b1d 100644
--- a/Completion/Linux/Command/_ethtool
+++ b/Completion/Linux/Command/_ethtool
@@ -4,7 +4,7 @@ local curcontext="$curcontext"
 local -a state line expl cmds
 local -A opt_args
 
-_arguments -C \
+_arguments -C -A "-*" \
   '--debug[turn on debugging messages]:mask:((1\:parser\ information))' \
   '--json[output results in JSON]' \
   '(-I --include-statistics)'{-I,--include-statistics}'[include command-related statistics in the output]' \
@@ -59,12 +59,21 @@ _arguments -C \
   '--cable-test[perform cable test and report the results]' \
   '--cable-test-tdr[perform cable test and report Time Domain Reflectometer data]' \
   '--show-tunnels[show tunnel-related device capabilities and state]' \
+  '--show-module[show transceiver module settings]' \
+  '--set-module[set transceiver module settings]' \
+  '--get-plca-cfg[get PLCA configuration]' \
+  '--set-plca-cfg[set PLCA configuration]' \
+  '--get-plca-status[get PLCA status information]' \
+  '--show-mm[show MAC merge layer state]' \
+  '--set-mm[set MAC merge layer parameters]' \
+  '--show-pse[show settings for power sourcing equipment]' \
+  '--set-pse[set power sourcing equipment settings]' \
   '--monitor[listen to netlink notifications and displays them]::command:(
     --all -s --change -k --show-features --show-offload -K
     --features --offload  --show-priv-flags --set-priv-flags -g --show-ring
     -G --set-ring -l --show-channels -L --set-channels -c --show-coalesce
     -C --coalesce -a --show-pause -A --pause --show-eee --set-eee
-    --cable-test --cable-test-tdr
+    --cable-test --cable-test-tdr --show-module --set-module
   )' && return
 
 if [[ -n $state ]]; then
@@ -79,22 +88,30 @@ if [[ -n $state ]]; then
     fi
   ;;
   autoneg|adaptive-[rt]x|raw|hex|sg|tso|ufo|gso|lro|eee|tx-lpi|downshift) ;&
-  fast-link-down|energy-detect-power-down|mode)
+  cqe-mode-[rt]x|fast-link-down|energy-detect-power-down|mode) ;&
+  [tr]x-push|enable|*-enabled)
     _wanted onoff expl 'enabled' compadd off on
   ;;
   rx-usecs|rx-frames|rx-usecs-irq|rx-frames-irq|tx-usecs|tx-frames) ;&
   tx-usecs-irq|tx-frames-irq|stats-block-usecs|pkt-rate-low|rx-usecs-low) ;&
   rx-frames-low|tx-usecs-low|tx-frames-low|pkt-rate-high|rx-usecs-high) ;&
-  rx-frames-high|tx-usecs-high|tx-frames-high|sample-interval|dmac|rx-mini) ;&
-  rx-jumbo|offset|length|magic|value|phyad|proto|tos|tclass|l4proto|src-port) ;&
+  rx-frames-high|tx-usecs-high|tx-frames-high|sample-interval|dmac) ;&
+  tx-aggr-max-bytes|tx-aggr-max-frame|tx-aggr-time-usec) ;&
+  rx-mini|rx-jumbo|rx-buf-len|cqe-size|tx-push-buf-len) ;&
+  offset|length|magic|value|phyad|proto|tos|tclass|l4proto|src-port) ;&
   dst-port|spi|l4data|vlan-etype|vlan|user-def|action|vf|queue|loc) ;&
   page|bank|i2c|first|last|step|pair|lanes) ;&
-  rx-copybreak|tx-copybreak|pfc-prevention-tout) ;&
-  other|combined|tx-timer|count|msecs)
+  rx-copybreak|tx-copybreak|tx-buf-size|pfc-prevention-tout) ;&
+  other|combined|tx-timer|count|msecs) ;&
+  node-id|node-cnt|to-tmr|burst-cnt|burst-tmr) ;&
+  tx-min-frag-size)
     _message -e numbers 'number'
   ;;
+  podl-pse-admin-control)
+    _wanted values expl 'value' compadd enable disable
+  ;;
   speed)
-        _wanted -x speed expl 'speed' compadd 10 100 1000
+    _wanted -x speed expl 'speed' compadd 10 100 1000
   ;;
   duplex)
     _wanted duplex expl 'duplex mode' compadd half full
@@ -166,8 +183,14 @@ if [[ -n $state ]]; then
   context)
     _message -e contexts 'RSS context'
   ;;
+  power-mode-policy)
+    _wanted policies expl 'policy' compadd high auto
+  ;;
   *)
     case ${${(Mk)opt_args:#cmd?*}[1]#cmd?-} in
+    -a|--show-pause)
+      _arguments '--src=-:source:(aggregate emac pmac)'
+    ;;
     -A|--pause)
       _values -S ' ' -w 'pause parameter' \
         'autoneg[specify if pause autonegotiation is enabled]' \
@@ -177,14 +200,16 @@ if [[ -n $state ]]; then
     -C|--coalesce)
       _wanted settings expl 'coalescing setting' compadd -F line -M 'r:|-=* r:|=*' - \
         adaptive-{r,t}x {r,t}x-{usecs,frames}{,-irq,-high,-low} \
-        stats-block-usecs pkt-rate-{low,high} sample-interval
+        stats-block-usecs pkt-rate-{low,high} sample-interval cqe-mode-{r,t}x \
+        tx-aggr-{max-bytes,max-frames,time-usecs}
     ;;
     -G|--set-ring)
       _values -S ' ' -w 'ring parameter' \
         'rx[change number of ring entries for the RX ring]' \
         'rx-mini[change number of ring entries for the RX Mini ring]' \
         'rx-jumbo[change number of ring entries for the RX Jumbo ring]' \
-        'tx[change number of ring entries for the TX ring]'
+        'tx[change number of ring entries for the TX ring]' \
+        rx-buf-len cqe-size tx-push rx-push tx-push-buf-len
     ;;
     -d|--register-dump)
       _values -S ' ' -w 'option' \
@@ -216,7 +241,9 @@ if [[ -n $state ]]; then
       (( CURRENT = 4 )) && _message -e length 'duration (seconds)'
     ;;
     -S|--statistics)
-      _arguments '(-)--all-groups' '(-)--groups:eth-phy: :eth-mac: :eth-ctrl: :rmon'
+      _arguments '(-)--all-groups' \
+        '(-)--groups:eth-phy: :eth-mac: :eth-ctrl: :rmon' \
+        '--src=-:source:(aggregate emac pmac)' \
     ;;
     -t|--test)
       _values -S ' ' -w 'test mode' \
@@ -318,7 +345,7 @@ if [[ -n $state ]]; then
     ;;
     --[gs]et-tunable)
       _wanted options expl tunable compadd rx-copybreak tx-copybreak \
-          pfc-prevention-tout
+          tx-buf-size pfc-prevention-tout
     ;;
     --reset)
       _wanted components expl component compadd flags dedicated all \
@@ -341,6 +368,13 @@ if [[ -n $state ]]; then
     --cable-test-tdr)
       _wanted options expl 'distance options' compadd first last step pair
     ;;
+    --set-module)
+      _wanted options expl tunable compadd power-mode-policy
+    ;;
+    --set-plca-cfg)
+      _wanted options expl tunable compadd enable node-id node-cnt \
+          to-tmr burst-cnt burst-tmr
+    ;;
     esac
   ;;
   esac
diff --git a/Completion/Linux/Command/_gpasswd b/Completion/Linux/Command/_gpasswd
index 24fe361b0..d5d16ebba 100644
--- a/Completion/Linux/Command/_gpasswd
+++ b/Completion/Linux/Command/_gpasswd
@@ -5,7 +5,7 @@ _arguments -s \
   '(-d --delete -a --add)'{-d,--delete}'[remove user from group]: : _users' \
   '(-)'{-h,--help}'[display help]' \
   '(-Q --root)'{-Q,--root}'[specify directory to chroot into]: : _files -/' \
-  '(-r --remove-password)'{-r,--remove-password}'[remove the group password]' \
+  '(-r --delete-password)'{-r,--delete-password}'[remove the group password]' \
   '(-R --restrict)'{-R,--restrict}'[restrict access to GROUP to its members]' \
   '(-M --members -A --administrators)'{-M,--members}'[set the list of members of GROUP]: :_sequence _users' \
   '(-A --administrators -M --members)'{-A,--administrators}'[set the list of admins for GROUP]: :_sequence _users' \
diff --git a/Completion/Linux/Command/_iptables b/Completion/Linux/Command/_iptables
index 27c801da1..892c48710 100644
--- a/Completion/Linux/Command/_iptables
+++ b/Completion/Linux/Command/_iptables
@@ -1,7 +1,7 @@
-#compdef iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore
+#compdef iptables iptables-save iptables-restore ip6tables ip6tables-save ip6tables-restore arptables ebtables
 
-local curcontext="$curcontext" state line expl i ret=1
-local -a cmds rcmds ropts rules states prev args
+local curcontext="$curcontext" i ret=1
+local -a state line expl cmds rcmds ropts rules states prev args
 
 case $service in
   iptables-save | ip6tables-save)
@@ -24,12 +24,12 @@ cmds=(
   -P --policy -E --rename-chain -h --help -V --version
 )
 ropts=(
-  -p --protocol -s --src --source -d --dst --destination -j --jump -i
+  -p --proto --protocol -s --src --source -d --dst --destination -j --jump -i
   --in-interface -o --out-interface -f --fragment -c --set-counters
 )
 
 prev=( ${words[1,CURRENT-1]} )
-case ${prev[${prev[(I)-p|--protocol]}+1]}; in
+case ${prev[${prev[(I)-p|--proto|--protocol]}+1]}; in
   tcp)
     args=(
       '--tcp-flags[match based on TCP flags in a packet]: :->tcp-flags: :->tcp-flags'
@@ -92,7 +92,42 @@ while
   (( i=words[(ib.i.)-m|--match]+1 ))
 (( i<CURRENT )); do
   case ${words[i]}; in
-    ah) args+=( '--ahspi[match SPIs in AH header]:*^!:spi' ) ;;
+    addrtype)
+      args+=(
+        '--src-type[match if the source address is of given type]:type:->address-types'
+        '--dst-type[match if the destination address is of given type]:type:->address-types'
+        '(--limit-iface-out)--limit-iface-in[limit to interface the packet is coming in]'
+        '(--limit-iface-in)--limit-iface-out[limit to interface the packet is going out]'
+      )
+    ;;
+    ah)
+      args+=( '--ahspi[match SPIs in AH header]:*^!:spi' )
+      [[ $service = ip6* ]] && args+=(
+        '--ahlen[total length of this header]:length (octets)'
+        '--ahres[match if the reserved field is filled with zero]'
+      )
+    ;;
+    bpf)
+      args+=(
+        '--object-pinned[pass a path to a pinned eBPF object]:path:_files'
+        '--bytecode[pass BPF byte code as generated by nfbpf_compile]:code'
+      )
+    ;;
+    cgroup)
+      args+=(
+        '--path[match cgroup2 membership]:path:_files -W /sys/fs/cgroup'
+        '--cgroup[match cgroup net_cls classid]:classid'
+      )
+    ;;
+    cluster)
+      args+=(
+        '--cluster-total-nodes[set number of total nodes in cluster]:number'
+        '--cluster-local-node[set the local node number ID]:number'
+        '--cluster-local-nodemask[set the local node number ID mask]:mask'
+        '--cluster-hash-seed[set seed value of the Jenkins hash]:value'
+      )
+    ;;
+    comment) args+=( '--comment[add comment to rule]:comment' ) ;;
     conntrack)
       args+=(
         '--ctstate[match packet state]:state:->cfstates'
@@ -160,30 +195,34 @@ _arguments -C -s \
   '(-)'{-V,--version}'[print version information]' \
   '(-h --help -V --version)'{-t,--table}'[specify table]:table:(filter nat mangle raw security)' \
   "($rcmds $cmds)"{-A,--append}'[append rules to end of specified chain]:chain:->chains' \
+  {-C,--check}'[check for the existence of a rule]' \
   "($rcmds $cmds -c --set-counters)"{-D,--delete}'[delete rules from specified chain]:chain:->chains::rule number:->rulenums' \
   "($rcmds $cmds)"{-I,--insert}'[insert rules before specified rule number]:chain:->chains::rule number:->rulenums' \
   "($rcmds $cmds)"{-R,--replace}'[replace a rule]:chain:->chains::rule number:->rulenums' \
-  "($rcmds "${(j. .)cmds:#(-Z|--zero)}" $ropts)"{-L,--list}'[list rules in selected chain]::chain:->chains' \
+  "($rcmds "${(j. .)cmds:#(-Z|--zero)}" $ropts)"{-L,--list}'[list rules in selected chain]::chain:->chains:rule number:->rulenums' \
+  '(-L --list -S --list-rules)'{-S,--list-rules}'[list rules in the form of options to iptables]::chain:->chains::rule number:->rulenums' \
   "($rcmds $cmds $ropts)"{-F,--flush}'[flush specified chain (delete all rules)]::chain:->chains' \
   "($rcmds "${(j. .)cmds:#(-L|--list)}" $ropts)"{-Z,--zero}'[zero the packet and byte counters]::chain:->chains' \
   "($rcmds $cmds)"{-N,--new,--new-chain}'[create a new user-defined chain]:chain name' \
   "($rcmds $cmds)"{-X,--delete-chain}'[delete a user-defined chain]:: :->user-chains' \
   "($rcmds $cmds)"{-P,--policy}'[set the policy for a chain to given target]:chain:->chains:target:->targets' \
   "($rcmds $cmds)"{-E,--rename-chain}'[rename a user-defined chain]:old chain:->user-chains:new chain name' \
-  "($cmds -p --protocol)"{-p,--protocol}'[specify protocol of rule]:*^!:protocol:(! tcp udp icmp all)' \
-  "($cmds -s --src --source)"{-s,--src,--source}'[specify source]:*^!:network:_hosts' \
-  "($cmds -d --dst --destination)"{-d,--dst,--destination}'[specify destination]:*^!:network:_hosts' \
+  "($cmds -p --proto --protocol)"{-p,--proto,--protocol}'[specify protocol of rule]:*^!:protocol:(! tcp udp icmp all)' \
+  "($cmds -s --src --source)"{-s,--src,--source}'[specify source]:*^!:network:_sequence _hosts' \
+  "($cmds -d --dst --destination)"{-d,--dst,--destination}'[specify destination]:*^!:network:_sequence _hosts' \
   "($cmds -j --jump)"{-j,--jump}'[specify rule target]:target:->targets' \
   "($cmds -i --in-interface)"{-i,--in-interface}'[specify interface via which packet is received]:*^!:interface:_net_interfaces' \
   "($cmds -o --out-interface)"{-o,--out-interface}'[specify interface via which packet is to be sent]:*^!:interface:_net_interfaces' \
   "($cmds -f --fragment)"{-f,--fragment}'[match second or further fragments only]' \
   "($cmds -D --delete -c --set-counters)"{-c,--set-counters}'[initialise packet and byte counters]:packets: :bytes' \
   '(-v --verbose)'{-v,--verbose}'[enable verbose output]' \
+  '(-w --wait)'{-w,--wait}'[specify maximum wait to acquire xtables lock before giving up]: :_numbers -u seconds -d 1 wait' \
+  '(-W --wait-interval)'{-W,--wait-interval}'[specify wait time to try to acquire xtables lock]: :_numbers -u usecs -d "1 second" wait' \
   '(-n --numeric)'{-n,--numeric}'[print IP addresses and port numbers in numeric format]' \
   '(-x --exact)'{-x,--exact}'[expand numbers (display exact values)]' \
   '--line-numbers[print line numbers when listing]' \
   '--modprobe=[specify command to load modules with]:command:_command_names -e' \
-  "($cmds)*"{-m,--match}'[extended match (may load extension)]:extension:(ah conntrack dscp esp helper icmp length limit mac mark multiport owner physdev pkttype state tcp tos ttl udp unclean)' \
+  "($cmds)*"{-m,--match}'[extended match (may load extension)]:extension:(addrtype ah bpf cgroup cluster comment connbytes connlabel connlimit connmark conntrack cpu dccp devgroup dscp dsr ecn esp eui64 frag hashlimit hbh helper hl icmp icmp6 iprange ipv6header ipvs length limit mac mark mh multiport nfacct osf owner physdev pkttype policy quota rateest realm recent rpfilter rt sctp set socket state statistic string tcp tcpmss time tos ttl u32 udp unclean)' \
   "$args[@]" && ret=0
 
 case "$state" in
@@ -230,6 +269,11 @@ case "$state" in
     [[ "$state" = cf* ]] && states+=( SNAT DNAT )
     _values -s , 'state' $states && return
   ;;
+  address-types)
+    _wanted address-types expl 'address type' compadd \
+        UNSPEC UNICAST LOCAL BROADCAST ANYCAST MULTICAST \
+        BLACKHOLE UNREACHABLE PROHIBIT THROW NAT XRESOLVE && ret=0
+  ;;
   port-list)
     compset -P '*,'
     if compset -S ',*'; then
diff --git a/Completion/Linux/Command/_strace b/Completion/Linux/Command/_strace
index b1c7e1c8f..37e14b6d6 100644
--- a/Completion/Linux/Command/_strace
+++ b/Completion/Linux/Command/_strace
@@ -17,6 +17,7 @@ _arguments -C -s \
   '(-D)--daemonize=-[specify how to run tracer process]::method:(grandchild pgroup session)' \
   '(-f --follow-forks)'{-f,--follow-forks}'[trace child processes as they are created by currently traced processes]' \
   '(-I --interruptible)'{-I+,--interruptible=}'[specify when strace can be interrupted by signals]:interruptible:((1\:"no signals are blocked" 2\:"fatal signals are blocked while decoding syscall (default)" 3\:"fatal signals are always blocked (default with -o)" 4\:"fatal signals and SIGTSTP are always blocked"))' \
+  '--kill-on-exit[kill all tracees if strace is killed]' \
   \*{-e+,--trace=}'[select events to trace or how to trace]:system call:->expressions' \
   \*{-P+,--path=}'[trace only system calls accessing given path]:path:_files' \
   '(-z -Z --successful-only --failed-only)'{-z,--successful-only}'[trace only system calls that return success]' \
diff --git a/Completion/Linux/Command/_sysstat b/Completion/Linux/Command/_sysstat
index 0baae0764..59a2f5da9 100644
--- a/Completion/Linux/Command/_sysstat
+++ b/Completion/Linux/Command/_sysstat
@@ -56,6 +56,7 @@ _sadf() {
       '--dev=-[specify block devices for which statistics are to be displayed]:block device:_files -g "*(-%)"' \
       '--fs=-[specify filesystems for which statistics are to be displayed]:file system:_dir_list -s ,' \
       '--iface=-[specify network interfaces for which statistics are to be displayed]:network interface:_sequence _net_interfaces' \
+      '--int=-[specify interrupts for which statistics are to be displayed]: : _values -s "," interrupt 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15' \
       '-s[set starting time of report]:starting time (HH\:MM\:SS)"' \
       '(-t -U)-T[display timestamp in local time]' \
       '(-T -U)-t[display timestamp in file\''s original localtime]' \
@@ -99,9 +100,10 @@ _sar() {
     '(--human -p)-h[make output easier to read: implies --human and -p]' \
     '(- 1 2)--help[display usage information]' \
     '--human[print sizes in human readable format]' \
-    '*-I[report statistics for interrupts]: : _values -s "," interrupt 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 SUM ALL XALL' \
+    '-I[report statistics for interrupts]:interrupt:(SUM ALL)' \
     '-i[select records as close as possible to interval]:interval' \
     '--iface=-[specify network interfaces for which statistics are to be displayed]:network interface:_sequence _net_interfaces' \
+    '--int=-[specify interrupts for which statistics are to be displayed]: : _values -s "," interrupt 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15' \
     '-j[display persistent device names]:type:(ID LABEL PATH UUID)' \
     '-m[report power management statistics]:keyword:_sequence compadd - CPU FAN FREQ IN TEMP USB ALL' \
     '-n[report network statistics]:keyword:_sequence compadd - DEV EDEV NFS NFSD SOCK IP EIP ICMP EICMP TCP ETCP UDP SOCK6 IP6 EIP6 ICMP6 EICMP6 UDP6 FC SOFT ALL' \
diff --git a/Completion/Linux/Command/_valgrind b/Completion/Linux/Command/_valgrind
index b4bb3248e..e1498be6d 100644
--- a/Completion/Linux/Command/_valgrind
+++ b/Completion/Linux/Command/_valgrind
@@ -216,7 +216,7 @@ _arguments -C ${(P)args} $cmd \
   '--vgdb=-[activate gdbserver]:enable [yes]:(yes no full)' \
   '--vgdb-error=-[invoke gdbserver after specified number of errors]:errors [999999999]:errors' \
   '--vgdb-stop-at=-[invoke gdbserver for given events]:event:_sequence compadd - startup exit valgrindabexit all none' \
-  '--track-fds=-[track open file descriptors]:enable:(yes no)' \
+  '--track-fds=-[track open file descriptors]:enable [no]:(yes no all)' \
   '--time-stamp=-[add timestamps to log messages]:enable:(yes no)' \
   '--log-fd=-[log messages to specified file descriptor]:file descriptor:_file_descriptors' \
   '--log-file=-[log messages to specified file with pid appended]:file:_files' \
diff --git a/Completion/Redhat/Command/_rpm b/Completion/Redhat/Command/_rpm
index d00f88429..97f65cd6c 100644
--- a/Completion/Redhat/Command/_rpm
+++ b/Completion/Redhat/Command/_rpm
@@ -74,6 +74,7 @@ _rpm () {
   selectopts=(
     {-a,--all}'[query all packages]'
     {-f,--file}'[query packages that own specified files]'
+    '--path[query packages that own specified files, installed or not]'
     {-p,--package}'[query uninstalled packages]'
     {-g,--group}'[query packages in one of specified groups]'
     --pkgid --hdrid --tid --querybynumber
@@ -165,9 +166,7 @@ _rpm () {
         {-F+,--freshen}'[freshen mode]:*:upgrade:->upgrade'
         {-e+,--erase}'[uninstall mode]:*:uninstall:->uninstall'
         '--reinstall[reinstall mode]:*:install:->install'
-        '--setperms[set file permissions]:*:package:->setattrs'
-        '--setugids[set file owner/group]:*:package:->setattrs'
-        '--setcaps[set capabilities of files in the given package]:*:package:->setattrs'
+        '!--set'{perms,ugids,caps}':*:package:->setattrs'
         '--restore[restore owner, group, permissions and capabilities of files in the given package]:*:package:->setattrs'
       )
     ;;
@@ -261,13 +260,15 @@ _rpm () {
     install)
       _arguments -s -C \!{-i,--install,-U,--upgrade,-F,--freshen} $tmp \
         $commonopts $pathopts \
+        '(--nodb)--justdb[update the database but not the filesystem]' \
+        '(--justdb)--nodb[update the filesystem but not the database]' \
         '--excludepath=:file to exclude:_files -/' \
 	'--relocate:relocate:->relocate' \
         '--prefix=[relocate the package]:package prefix directory:_files -/' \
         '(-h --hash)'{-h,--hash}'[print hash marks as package installs]' \
 	'(--replacepkgs --replacefiles --oldpackage)--force' \
 	'(--force)--'{replacefiles,replacepkgs} \
-        --{aid,allfiles,badreloc,excludedocs,ignorearch,ignoreos,ignoresize,includedocs,justdb,percent,test} \
+        --{aid,allfiles,badreloc,excludedocs,ignorearch,ignoreos,ignoresize,includedocs,percent,test} \
         --no{deps,filedigest,contexts,caps,order,suggest,pre,post,preun,postun,trigger{s,in,un,postun}} \
 	'(--nopre --nopost --nopreun --nopostun)--noscripts' \
         '*:pkg file:->package_file'
@@ -275,7 +276,9 @@ _rpm () {
     uninstall)
       _arguments -s -C \!{-e,--erase} \
 	"${commonopts[@]}" "${pathopts[@]}" \
-	--{allmatches,justdb,repackage,test} \
+        '(--nodb)--justdb[update the database but not the filesystem]' \
+        '(--justdb)--nodb[update the filesystem but not the database]' \
+	--{allmatches,repackage,test} \
 	--no{deps,scripts,preun,postun,trigger{s,un,postun}} \
         '*:package:->package'
       ;;
diff --git a/Completion/Solaris/Command/_pkg5 b/Completion/Solaris/Command/_pkg5
index bcd4e3daf..5524e4eda 100644
--- a/Completion/Solaris/Command/_pkg5
+++ b/Completion/Solaris/Command/_pkg5
@@ -378,6 +378,7 @@ _pkg5() {
 			'--non-sticky[Make this publisher non-sticky]' \
 			'--search-after[Set publisher search-order]:publisher:_pkg5_pubs' \
 			'--search-before[Set publisher search-order]:publisher:_pkg5_pubs' \
+			'--search-first[set the specified publisher first in the search order]' \
 			'--approve-ca-cert[Add trusted CA certificate]:CA cert path:_path_files' \
 			'--revoke-ca-cert[Revoke CA certificate]:CA cert hash:(${${certs#/etc/openssl/certs/}%.0})' \
 			'--unset-ca-cert[Remove trusted CA certificate]:CA cert hash:' \
diff --git a/Completion/Unix/Command/_awk b/Completion/Unix/Command/_awk
index e8f4a2530..b69cc5cf8 100644
--- a/Completion/Unix/Command/_awk
+++ b/Completion/Unix/Command/_awk
@@ -50,6 +50,7 @@ case $variant in
       {-D-,--debug=-}'[enable debugging]::debugger command file:_files'
       {-g,--gen-pot}'[scan awk program and generate .po file on stdout]'
       '*'{-i+,--include}'[load source library]:library file:->script'
+      {-I,--trace}'[print internal byte code names as they are executed]'
       '*'{-l+,--load}'[load dynamic extension]:extension:->extension'
       {-M,--bignum}'[select arbitrary-precision arithmetic on numbers]'
       {-o-,--pretty-print=-}'[pretty-print awk program]::output file:_files'
diff --git a/Completion/Unix/Command/_cat b/Completion/Unix/Command/_cat
index 74d7278b8..526c49e31 100644
--- a/Completion/Unix/Command/_cat
+++ b/Completion/Unix/Command/_cat
@@ -38,6 +38,9 @@ elif [[ "$OSTYPE" == (*bsd|dragonfly|darwin)* ]]; then
     '-B+[read with buffer of specified size]:size (bytes)'
     '-f[only attempt to display regular files]'
   )
+  [[ $OSTYPE = darwin* ]] && args+=(
+    '-l[set an exclusive advisory lock on standard output]'
+  )
 elif [[ $OSTYPE = solaris* ]]; then
   args=(
     -A "-*"
diff --git a/Completion/Unix/Command/_dbus b/Completion/Unix/Command/_dbus
index 37b5458d7..d2a93152c 100644
--- a/Completion/Unix/Command/_dbus
+++ b/Completion/Unix/Command/_dbus
@@ -8,11 +8,13 @@ case $service in
   dbus-send)
     _arguments -A "--*" -C \
       '(--session)--system' '(--system)--session' \
-      '--address=-:bus address:->addresses' \
+      '--bus=-:bus address:->addresses' \
+      '--peer=-:bus address:->addresses' \
       '--dest=-:connection:->connections' \
       '--print-reply=-::format:(literal)' \
       '--reply-timeout=-:timeout (ms)' \
-      '--type=-:type:(method_call signal)' \
+      '--sender=-:name' \
+      '--type=-:type [signal]:(method_call signal)' \
       '(* -)--help' \
       ':object path:->objectpaths' \
       ':message name:->methods' \
diff --git a/Completion/Unix/Command/_dd b/Completion/Unix/Command/_dd
index 10682bc8e..c55efb68c 100644
--- a/Completion/Unix/Command/_dd
+++ b/Completion/Unix/Command/_dd
@@ -74,7 +74,7 @@ case $variant in
     vals+=(
       'status[specify level of information to print to stderr]:level:(none noxfer progress)'
     )
-    flags+=( fullblock noatime nocache count_bytes skip_bytes seek_bytes )
+    flags+=( fullblock noatime nocache )
     conv+=( excl nocreat fdatasync fsync )
     units=( c:1 w:2 b:512 kB:1000 K:1024 MB:1000^2 M:1024\^2 GB G TB T PB P EB E ZB Z YB Y )
   ;;
diff --git a/Completion/Unix/Command/_dig b/Completion/Unix/Command/_dig
index 3081e2cfd..c09bebbe5 100644
--- a/Completion/Unix/Command/_dig
+++ b/Completion/Unix/Command/_dig
@@ -6,8 +6,9 @@ local -a alts args
   '*+'{no,}'tcp[use TCP instead of UDP for queries]'
   '*+'{no,}'ignore[ignore truncation in UDP responses]'
   '*+domain=[set search list to single domain]:domain:_hosts'
-  '*+dscp=[set DSCP code point for query]:code point (0..63)'
+  '!*+dscp=:code point (0..63)'
   '*+'{no,}'search[use search list defined in resolv.conf]'
+  '!*+'{no,}defname
   '*+'{no,}'showsearch[show intermediate results in domain search]'
   '*+split[split hex/base64 fields into chunks]:width (characters) [56]'
   '*+'{no,}'aaonly[set aa flag in the query]'
@@ -18,6 +19,7 @@ local -a alts args
   '*+'{no,}'class[display the CLASS whening printing the record]'
   '*+'{no,}'cookie[add a COOKIE option to the request]'
   '*+'{no,}'crypto[display cryptographic fields in DNSSEC records]'
+  '*+'{no,}'dns64prefix[get the DNS64 prefixes from ipv4only.arpa]'
   '*+edns=[specify EDNS version for query]:version (0-255)'
   '*+noedns[clear EDNS version to be sent]'
   '*+ednsflags=[set EDNS flags bits]:flags'
@@ -27,11 +29,15 @@ local -a alts args
   '*+'{no,}'expandaaaa[expand AAAA records]'
   '*+'{no,}'expire[send an EDNS Expire option]'
   '*+'{no,}'header-only[send query without a question section]'
+  '*+'{no,}'https=[DNS-over-HTTPS POST mode]::endpoint [/dns-query]'
+  '!*+'{no,}'https-post=::endpoint [/dns-query]'
+  '*+'{no,}'https-get=[DNS-over-HTTPS GET mode]::endpoint [/dns-query]'
+  '*+'{no,}'http-plain=[DNS-over-HTTP POST mode]::endpoint [/dns-query]'
+  '*+'{no,}'http-plain-get=[DNS-over-HTTP GET mode]::endpoint [/dns-query]'
   '*+'{no,}'idnin[set processing of IDN domain names on input]'
   '*+'{no,}'idnout[set conversion of IDN puny code on output]'
   '*+'{no,}'keepalive[request EDNS TCP keepalive]'
   '*+'{no,}'keepopen[keep TCP socket open between queries]'
-  '*+'{no,}'mapped[allow mapped IPv4 over IPv6 to be used]'
   '*+'{no,}'recurse[set the RD (recursion desired) bit in the query]'
   '*+'{no,}'nssearch[search all authoritative nameservers]'
   '*+opcode[set DNS message opcode of the request]:opcode [QUERY]:(QUERY IQUERY STATUS NOTIFY UPDATE)'
@@ -39,10 +45,12 @@ local -a alts args
   '*+'{no,}'trace[trace delegation down from root]'
   '*+'{no,}'cmd[print initial comment in output]'
   '*+'{no,}'short[print terse output]'
+  '*+'{no,}'showbadcookie[show BADCOOKIE message]'
   '*+'{no,}'identify[print IP and port of responder]'
   '*+'{no,}'comments[print comment lines in output]'
   '*+'{no,}'stats[print statistics]'
   '*+padding[set padding block size]:size [0]'
+  '*+qid=[specify query ID]:query ID'
   '*+'{no,}'qr[print query as it was sent]'
   '*+'{no,}'question[print question section of a query]'
   '*+'{no,}'raflag[set RA flag in the query]'
@@ -52,6 +60,11 @@ local -a alts args
   '*+'{no,}'subnet[send EDNS client subnet option]:addr/prefix-length'
   '*+'{no,}'tcflag[set TC flag in the query]'
   '*+timeout=[set query timeout]:timeout (seconds) [5]'
+  '*+'{no,}'tls[DNS-over-TLS mode]'
+  '*+'{no,}"tls-ca=[enable remote server's TLS certificate validation]:file:_files"
+  '*+'{no,}"tls-hostname=[explicitly set the expected TLS hostname]:hostname"
+  '*+'{no,}'tls-certfile=[load client TLS certificate chain from file]:file:_files'
+  '*+'{no,}'tls-keyfile=[load client TLS private key from file]:file:_files'
   '*+tries=[specify number of UDP query attempts]:tries'
   '*+retry=[specify number of UDP query retries]:retries'
   '*+'{no,}'rrcomments[set display of per-record comments]'
@@ -65,7 +78,6 @@ local -a alts args
   '*+'{no,}'nsid[include EDNS name server ID request in query]'
   '*+'{no,}'ttlid[display the TTL whening printing the record]'
   '*+'{no,}'ttlunits[display the TTL in human-readable units]'
-  '*+'{no,}'unexpected[print replies from unexpected sources]'
   '*+'{no,}'unknownformat[print RDATA in RFC 3597 "unknown" format]'
   '*+'{no,}'yaml[present the results as YAML]'
   '*+'{no,}'zflag[set Z flag in query]'
diff --git a/Completion/Unix/Command/_dmidecode b/Completion/Unix/Command/_dmidecode
index 047b74f6d..e2c511313 100644
--- a/Completion/Unix/Command/_dmidecode
+++ b/Completion/Unix/Command/_dmidecode
@@ -4,6 +4,7 @@ _arguments -s \
   '(-d --dev-mem --from-dump)'{-d+,--dev-mem=}'[read memory from specified file]:memory device [/dev/mem]:_files' \
   '(-)'{-h,--help}'[display usage information]' \
   '(-q --quiet -u --dump)'{-q,--quiet}'[be less verbose]' \
+  '--no-quirks[decode everything without quirks]' \
   '(-t --type -H --handle -u --dump --dump-bin -s --string)'{-s+,--string=}'[only display value of specified DMI string]:DMI string:(bios-vendor bios-version bios-release-date system-manufacturer system-product-name system-version system-serial-number system-uuid baseboard-manufacturer baseboard-product-name baseboard-version baseboard-serial-number baseboard-asset-tag chassis-manufacturer chassis-type chassis-version chassis-serial-number chassis-asset-tag processor-family processor-manufacturer processor-version processor-frequency)' \
   '(-s --string -H --handle --dump-bin)*'{-t+,--type=}'[only display entries of specified type]:entry type:(bios system baseboard chassis processor memory cache connector slot)' \
   '(-s --string -t --type -H --handle --dump-bin)'{-H,--handle=}'[only display the entry of specified handle]:handle' \
diff --git a/Completion/Unix/Command/_enscript b/Completion/Unix/Command/_enscript
index 3e09da5a4..4658ae4bc 100644
--- a/Completion/Unix/Command/_enscript
+++ b/Completion/Unix/Command/_enscript
@@ -128,7 +128,7 @@ case "$state" in
     local suf='{'
     compquote suf
     if [[ ${PREFIX} = *[%$]D${suf}[^}]# ]]; then
-      _strftime
+      _date_formats
     elif [[ ${(Q)PREFIX} = *\$\([^\)]# ]]; then
       compset -P '*\('
       _parameters -g '*export*' -S '\)'
diff --git a/Completion/Unix/Command/_flac b/Completion/Unix/Command/_flac
index 82b6f0160..1773061ee 100644
--- a/Completion/Unix/Command/_flac
+++ b/Completion/Unix/Command/_flac
@@ -85,6 +85,7 @@ case $service in
       '(-p --qlp-coeff-precision-search -q --qlp-coeff-precision)'{-p,--qlp-coeff-precision-search}'[exhaustively search LP coeff quantization]' \
       '(-p --qlp-coeff-precision-search -q --qlp-coeff-precision)'{-q,--qlp-coeff-precision=}'[specify precision]:precision (bits)' \
       '(-r --rice-partition-order)'{-r,--rice-partition-order=}'[set min/max residual partition order]:order' \
+      "--limit-min-bitrate[don't allow frames consisting of only constant subframes]" \
       '--endian=:byte order:(big little)' \
       '--channels=:channels' \
       '--bps=:bits per sample' \
diff --git a/Completion/Unix/Command/_getent b/Completion/Unix/Command/_getent
index b96852db3..5604e526e 100644
--- a/Completion/Unix/Command/_getent
+++ b/Completion/Unix/Command/_getent
@@ -8,6 +8,7 @@ typeset -A opt_args
 if _pick_variant -r is_gnu gnu='(Free Soft|GNU|GLIBC|Gentoo)' unix --version; then
   args+=(
     '(- 1 *)'{-\?,--help}'[display help information]'
+    '(-A --no-addrconfig)'{-A,--no-addrconfig}"[don't filter out unsupported IPv4/IPv6 addresses (with ahosts*)]"
     '(- 1 *)--usage[display a short usage message]'
     '(- 1 *)'{-V,--version}'[display version information]'
     '*'{-s+,--service=}'[specify service configuration to use]: :->services'
@@ -23,7 +24,7 @@ case $state in
   services)
     # @todo GNU getent supports both `-s svc` and `-s db:svc`; we only complete
     # the former here
-    services=( {,/usr}/lib/{,*-linux-gnu/}libnss_*(N-.:fr:t:s/libnss_//) )
+    services=( {,/usr}/lib{,64}/{,*-linux-gnu/}libnss_*(N-.:fr:t:s/libnss_//) )
     _wanted services expl 'service or database:service' \
       compadd ${(u)services%-*} \
     && ret=0
diff --git a/Completion/Unix/Command/_gnutls b/Completion/Unix/Command/_gnutls
index b9f91264d..9b8bcf6ea 100644
--- a/Completion/Unix/Command/_gnutls
+++ b/Completion/Unix/Command/_gnutls
@@ -4,8 +4,7 @@ local -a args
 
 args=(
   '(- :)'{-h,--help}'[display help information]'
-  '(- :)--version=[display version information]:information:((v\:simple c\:copyright n\:full))'
-  '(- :)-v[display version information]'
+  '(- :)'{-v+,--version=-}'[display version information]:information:((v\:simple c\:copyright n\:full))'
   '(- :)'{-\!,--more-help}'[display help information through a pager]'
   '(-d --debug)'{-d,--debug}'[enable debugging]:debug level'
   \*{-V,--verbose}'[more verbose output]'
@@ -17,6 +16,11 @@ case "$service" in
       '(-p --port)'{-p,--port}'[specify port or service to connect to]:port:_ports'
     )
   ;|
+  gnutls-*|certtool)
+    args+=(
+      '--attime=[perform validation at the timestamp instead of the system time]:timestamp'
+    )
+  ;|
   gnutls-cli*)
     args+=(
       '(--app-proto --starttls-proto)'{--app-proto,--starttls-proto}"=[specify application protocol to use to obtain the server's certificate]:protocol:(https ftp smtp imap ldap xmpp lmtp pop3 nntp sieve postgres)"
@@ -30,6 +34,7 @@ case "$service" in
       '(-u --udp)'{-u,--udp}'[use DTLS (datagram TLS) over UDP]'
       '--mtu=[set MTU for datagram TLS]:mtu'
       '--srtp-profiles=[offer SRTP profiles]:string'
+      '*--compress-cert=[compress certificate]:compression method'
       '(-b --heartbeat)'{-b,--heartbeat}'[activate heartbeat support]'
       '--x509fmtder[use DER format for certificates to read from]'
       '--priority=[specify TLS algorithms and protocols to enable]:(NORMAL PFS SECURE128 SECURE192 SUITEB128 SUITEB192 LEGACY PERFORMANCE NONE)'
@@ -94,7 +99,8 @@ case "$service" in
       '--post-handshake-auth[enable post-handshake authentication under TLS1.3]'
       '--inline-commands[inline commands of the form ^<cmd>^]'
       '--inline-commands-prefix=[change delimiter used for inline commands]:delimiter [^]'
-      '--fips140-mode[report status of FIPS140-2 mode in gnutls library]'
+      '--fips140-mode[report status of FIPS140-3 mode in gnutls library]'
+      '--list-config[report configuration of the library]'
       '--logfile=[redirect informational messages to a specific file]:file:_files'
       '--waitresumption[block waiting for the resumption data under TLS1.3]'
       '--ca-auto-retrieve[enable automatic retrieval of missing CA certificates]'
@@ -127,6 +133,7 @@ case "$service" in
       '--ignore-ocsp-response-errors[ignore any errors when setting the OCSP response]'
       '--recordsize=[specify maximum record size to advertise]:record size (0-16384)'
       '--httpdata=[specify data to use as HTTP response]:file:_files'
+      '--timeout=[specify he timeout period for server]:timeout'
     )
   ;;
 
diff --git a/Completion/Unix/Command/_gpg b/Completion/Unix/Command/_gpg
index 5d54865d5..2161d2d24 100644
--- a/Completion/Unix/Command/_gpg
+++ b/Completion/Unix/Command/_gpg
@@ -93,6 +93,7 @@ fi
   '--no-default-recipient[reset default recipient]'
   '*--encrypt-to[specify recipient]:key:->public-keys'
   '(--encrypt-to)--no-encrypt-to[disable the use of all --encrypt-to keys]'
+  '--group[set up email aliases]:spec'
   '-z[specify compression level]:compression level:((0\:no\ compression 1\:minimum 2 3 4 5 6\:default 7 8 9\:maximum))'
   '(-t --textmode)'{-t,--textmode}'[use canonical text mode]'
   '(-n --dry-run)'{-n,--dry-run}"[don't make any changes]"
@@ -117,6 +118,7 @@ fi
   '--utf8-strings' '--no-utf8-strings[arguments are not in UTF8]'
   '(--no-options)--options[specify file to read options from]:options file:_files'
   "(--options)--no-options[don't read options file]"
+  '--log-file[write server mode logs to file]:file:_files'
   '--'{attribute,passphrase,command}'-fd:file descriptor:_file_descriptors'
   '--sk-comments[include secret key comments when exporting keys]'
   '(--emit-version)--no-emit-version[omit version string in clear text signatures]'
@@ -170,6 +172,9 @@ fi
   '--ctapi-driver[file to use to access smartcard reader]:file:_files'
   '--pcsc-driver[file to use to access smartcard reader]:file:_files'
   '--auto-key-locate:parameters'
+  '--auto-key-import[import missing key from a signature]'
+  '--include-key-block[include the public key in signatures]'
+  '--disable-dirmngr[disable all access to the dirmngr]'
   '--dump-options[show all options]'
 )
 
diff --git a/Completion/Unix/Command/_gprof b/Completion/Unix/Command/_gprof
index a7e602fd5..6b97506a6 100644
--- a/Completion/Unix/Command/_gprof
+++ b/Completion/Unix/Command/_gprof
@@ -4,7 +4,7 @@ local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
 _arguments -C -s -{a,b,c,D,h,i,l,L,r,s,T,v,w,x,y,z} \
-           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,R,S,t,Z}:'function name:->funcs' \
+           -{A,B,C,e,E,f,F,J,n,N,O,p,P,q,Q,R,S,t,Z}:'function name:->funcs' \
 	   '-I:directory:_dir_list' \
 	   '-d-:debug level:' '-k:function names:->pair' \
 	   '-m:minimum execution count:' \
diff --git a/Completion/Unix/Command/_install b/Completion/Unix/Command/_install
index 238b8b5bc..881c99620 100644
--- a/Completion/Unix/Command/_install
+++ b/Completion/Unix/Command/_install
@@ -27,6 +27,7 @@ if _pick_variant gnu='Free Soft' unix --version; then
     '(-b --backup)--backup=[create backup; optionally specify method]:: :->controls'
     "${lx}--context=-[like -Z, or specify SELinux security context to set]::SELinux security context:_selinux_contexts -a file_type"
     '-D[create all leading destination path components]'
+    '--debug[explain how a file is copied. Implies -v]'
     '(: -)--help[display help information]'
     "${lx}--preserve-context[preserve SELinux security context]"
     '--strip-program=[specify program used to strip binaries]:strip program:_files'
diff --git a/Completion/Unix/Command/_less b/Completion/Unix/Command/_less
index 69f75fd0e..8772f5771 100644
--- a/Completion/Unix/Command/_less
+++ b/Completion/Unix/Command/_less
@@ -56,7 +56,7 @@ _arguments -S -s -A "[-+]*"  \
   '(-L --no-lessopen)'{-L,--no-lessopen}'[ignore the LESSOPEN environment variable]' \
   '(-M --LONG-PROMPT -m --long-prompt)'{-m,--long-prompt}'[prompt verbosely]' \
   '(-m --long-prompt -M --LONG-PROMPT)'{-M,--LONG-PROMPT}'[prompt very verbosely]' \
-  '(-N --LINE-NUMBERS -n --line-numbers)'{-n,--line-numbers}"[don't keep track of line numbers]" \
+  '(-N --LINE-NUMBERS -n --line-numbers)'{-n,--line-numbers}'[suppress line numbers in prompts and messages]' \
   '(-n --line-numbers -N --LINE-NUMBERS)'{-N,--LINE-NUMBERS}'[show line numbers]' \
   '(* -O --LOG-FILE -o --log-file)'{-o+,--log-file=}'[copy input to file]:file:_files' \
   '(* -o --log-file -O --LOG-FILE)'{-O+,--LOG-FILE=}'[copy input to file, overwriting if necessary]:file:_files' \
@@ -83,18 +83,39 @@ _arguments -S -s -A "[-+]*"  \
   '(-\" --quotes)'{'-\"+',--quotes=}'[change quoting character]:quoting characters' \
   '(-~ --tilde)'{-~,--tilde}"[don't display tildes after end of file]" \
   '(-\# --shift)'{'-\#+',--shift=}"[specify amount to move when scrolling horizontally]:number" \
+  '--exit-follow-on-close[exit F command on a pipe when writer closes pipe]' \
   '--file-size[automatically determine the size of the input file]' \
+  '--header=[set header size]:lines,columns' \
   '--incsearch[search file as each pattern character is typed in]' \
+  '--intr=[specify interrupt character instead of ^X]:char [^X]' \
   '--line-num-width=[set the width of line number field]:width [7]' \
+  '--modelines=[look for vim modelines]:lines to search' \
   '--follow-name[the F command changes file if the input file is renamed]' \
   '--mouse[enable mouse input]' \
   '--no-histdups[remove duplicates from command history]' \
+  "--no-number-headers[don't give line numbers to header lines]" \
+  "--no-search-headers[don't search in header lines or columns]" \
+  "--no-vbell[disable the terminal's visual bell]" \
+  '--redraw-on-quit[redraw final screen when quitting]' \
   '--rscroll=[set the character used to mark truncated lines]:character [>]' \
   '--save-marks[retain marks across invocations of less]' \
+  '--search-options=[set default options for every search]: : _values -s ""
+    "search option"
+    "E[multi-file]" "F[from first line]" "K[highlight]"
+    "N[non-matching]" "R[literal]" "W[wrap]" -' \
+  '--show-preproc-errors[display a message if preprocessor exits with an error status]' \
+  '--proc-backspace[process backspaces for bold/underline]' \
+  '--SPECIAL-BACKSPACE[treat backspaces as control characters]' \
+  '--proc-return[delete carriage returns before newline]' \
+  '--SPECIAL-RETURN[treat carriage returns as control characters]' \
+  '--proc-tab[expand tabs to spaces]' \
+  '--SPECIAL-TAB[treat tabs as control characters]' \
   '--status-col-width=[set the width of the -J status column]:width [2]' \
+  '--status-line[highlight or color the entire line containing a mark]' \
   '--use-backslash[subsequent options use backslash as escape char]' \
   '--use-color[enable colored text]' \
   '--wheel-lines=[specify lines to move for each click of the mouse wheel]:lines' \
+  '--wordwrap[wrap lines at spaces]' \
   "$files[@]" && ret=0
 
 
diff --git a/Completion/Unix/Command/_lsof b/Completion/Unix/Command/_lsof
index 8afb55e1d..60f59a589 100644
--- a/Completion/Unix/Command/_lsof
+++ b/Completion/Unix/Command/_lsof
@@ -9,6 +9,7 @@ case $OSTYPE in
       '-E[display endpoint info for pipes, sockets and pseudoterminal files but not files of the endpoints]'
       '+E[display endpoint info for pipes, sockets and pseudoterminal files including files of the endpoints]'
       '-X[skip reporting of info on network connections]'
+      '*-Z[display or filter by SELinux security context]::context pattern:_selinux_contexts -a domain'
     )
   ;;
   solaris*)
@@ -23,7 +24,6 @@ _arguments -C -s -S $args \
   '(-)'{-\?,-h}'[list help]' \
   '-a[AND selections]' \
   '-b[avoid kernel blocks]' \
-  '-C[disable reporting of path name components]' \
   '+c[truncate command name to specified characters]:characters' \
   '-c[list files with specified command name beginning]:command name' \
   '+d[search for open instances for contents of specified dir]:search directory:_files -/' \
@@ -31,16 +31,19 @@ _arguments -C -s -S $args \
   '+D[recursively search from specified dir]:search directory:_files -/' \
   '-D[direct use of device cache file]:function:((\?\:report\ device\ cache\ file\ paths b\:build\ the\ device\ cache\ file i\:ignore\ the\ device\ cache\ file r\:read\ the\ device\ cache\ file u\:read\ and\ update\ the\ device\ cache\ file))' \
   '*-+e[exempt filesystem from blocking kernel calls]:file system:_directories' \
+  '-+E[show endpoint information for pipes, sockets, ptys, mqueues and eventfds; with -E, omit endpoint files]' \
   '-f[inhibit listing of kernel file structure info]::info type:->file-structures' \
   '+f[enable listing of kernel file structure info]::info type:->file-structures' \
   '-F[select output fields]:fields:->fields' \
   '-g[select by process group id]::process group id:_sequence -s , _pgids' \
+  '-H[print human readable sizes]' \
   '(*)*-i[select internet files]::address:->addresses' \
   '-K+[select listing of tasks of processes]::value:((i\:ignore\ tasks))' \
   '-k[specify kernel name list file]:kernel file:_files' \
   '-l[inhibit conversion of UIDs to user names]' \
   '-L[list no link counts]' \
   '+L[list all link counts]::max link count for listed files' \
+  '+m[specify or write a mount supplement file]::mount supplement file:_files' \
   '-m[specify kernel memory file]:kernel memory file:_files' \
   '-M[disable reporting of portmapper registrations]' \
   '+M[enable reporting of portmapper registrations]' \
@@ -49,6 +52,7 @@ _arguments -C -s -S $args \
   '(-s)-o[list file offset]::digits for file offset' \
   '-O[avoid overheads of bypassing potential blocking]' \
   '-P[inhibit conversion of port numbers to port names]' \
+  '-Q[ignore failed search terms]' \
   '-p[list files for specified processes]:process ID:_sequence -s , _pids' \
   '-r[repeat listing endlessly]::delay (seconds)' \
   '+r[repeat listing until no files listed]::delay (seconds)' \
diff --git a/Completion/Unix/Command/_lua b/Completion/Unix/Command/_lua
index 7254d3819..3a1ef4fd7 100644
--- a/Completion/Unix/Command/_lua
+++ b/Completion/Unix/Command/_lua
@@ -41,6 +41,7 @@ _lua() {
   _arguments -S -A '-*' : \
     '*-e+[execute specified command string]:command string' \
     '-E[ignore environment variables]' \
+    '-W[turn warnings on]' \
     '-i[enter interactive mode]' \
     '*-l+[specify library or module to require]: :_lua_libraries' \
     '-v[display version information]' \
diff --git a/Completion/Unix/Command/_mpc b/Completion/Unix/Command/_mpc
index 7f7adc7b4..c3f93878c 100644
--- a/Completion/Unix/Command/_mpc
+++ b/Completion/Unix/Command/_mpc
@@ -26,6 +26,7 @@ _mpc_command() {
 
   mpc_cmds=(
     add:"append a song to the end of the current playlist"
+    albumart:"download album art for the given song and write to stdout"
     cdprev:"compact disk player-like previous command"
     channels:"list the channels that other clients have subscribed to"
     clear:"clear the current playlist"
@@ -57,6 +58,7 @@ _mpc_command() {
     prio:"change song priorities in the queue"
     queued:"show the next queued song"
     random:"toggle random mode, or specify state"
+    readpicture:"download a picture from the given song and write to stdout"
     repeat:"toggle repeat mode, or specify state"
     single:"toggle single mode, or specify state"
     consume:"toggle consume mode, or specify state"
@@ -205,6 +207,10 @@ _mpc_add() {
   _mpc_helper_files
 }
 
+_mpc_albumart() {
+  _mpc_helper_files
+}
+
 _mpc_del() {
   _mpc_helper_songnumbers
 }
@@ -304,8 +310,14 @@ _mpc_random() {
   _mpc_helper_bool
 }
 
+_mpc_readpicture() {
+  _mpc_helper_files
+}
+
 _mpc_single() {
-  _mpc_helper_bool
+  local state
+  _description states expl state
+  compadd "$@" "$expl[@]" on once off
 }
 
 _mpc_consume() {
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index b142c1d54..a78eb7068 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -18,7 +18,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
     '(-f --format -P --portability)-B[same as --format=bsd]'
     '(-u --undefined-only)--defined-only[display only defined symbols]'
     '(-n --numeric-sort -p --no-sort --size-sort -v)'{-n,--numeric-sort}'[sort symbols numerically by address]'
-    '(-p --no-sort -n -v --numeric-sort -r --reverse-sort --size-sort)'{-p,--no-sort}'[do not sort symbols]'
+    '(-p --no-sort -n -v --numeric-sort -r --reverse-sort --size-sort)'{-p,--no-sort}"[don't sort symbols]"
     '(-P --portability -B -f --format)'{-P,--portability}'[same as --format=posix]'
     '(-r --reverse-sort -p --no-sort)'{-r,--reverse-sort}'[reverse sort order]'
     '(-u --undefined-only --defined-only)'{-u,--undefined-only}'[display only undefined symbols]'
@@ -60,10 +60,10 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
       args+=(
         '!(--no-recurse-limit)--recurse-limit'
         '--no-recurse-limit[disable demangling recursion limit]'
-	'(-f --format -P -j)'{-f,--format}'[specify output format]:format:(bsd sysv posix just-symbols)'
-	'(-C --no-demangle)--demangle=-[decode symbol names]::style [auto]:(auto gnu lucid arm hp edg gnu-v3 java gnat rust dlang)'
+        '(-f --format -P -j --just-symbols)'{-f+,--format=}'[specify output format]:format [bsd]:(bsd sysv posix just-symbols)'
+        '(-C --no-demangle)--demangle=-[decode symbol names]::style [auto]:(none auto gnu-v3 java gnat dlang rust)'
         '--ifunc-chars=[specify characters to use for indirect function symbols]:characters for global/local indirect function symbols [ii]'
-	'(-B -f --format -P --portability -j --just-symbols)'{-j,--just-symbols}'[Same as --format=just-symbols]'
+        '(-B -f --format -P --portability -j --just-symbols)'{-j,--just-symbols}'[same as --format=just-symbols]'
 	'--plugin[load specified plugin]:plugin'
 	'--quiet[suppress no "no symbols" diagnostic]'
 	'--special-syms[include special symbols in the output]'
diff --git a/Completion/Unix/Command/_objdump b/Completion/Unix/Command/_objdump
index e2dde7e4c..94c01eb83 100644
--- a/Completion/Unix/Command/_objdump
+++ b/Completion/Unix/Command/_objdump
@@ -38,8 +38,10 @@ case $variant in
 
       '*-W-[display DWARF info in the file]::dwarf section:->short-dwarf-names'
       '*--dwarf=-[display DWARF info in the file]::dwarf section:->dwarf-names'
+      '(-L --process-links)'{-L,--process-links}'[display the contents of non-debug sections in separate debuginfo files]'
 
-      '--ctf=[display compact C type format info for section]:section'
+      '--ctf=-[display compact C type format info for section]::section'
+      '--sframe=-[display SFrame info from section]::section name [.sframe]'
       '(-t --syms)'{-t,--syms}'[display the contents of the symbol table(s)]'
       '(-T --dynamic-syms)'{-T,--dynamic-syms}'[display the contents of the dynamic symbol table]'
       '(-R --dynamic-reloc)'{-R,--dynamic-reloc}'[display the dynamic relocation entries in the file]'
@@ -59,11 +61,13 @@ case $variant in
       \*{-I+,--include=}'[add directory to search list for source files]:directory:_files -/'
       '(-l --line-numbers)'{-l,--line-numbers}'[include line numbers and filenames in output]'
       '(-F --file-offsets)'{-F,--file-offsets}'[include file offsets when displaying information]'
-      '(-C --demangle)-C[decode mangled/processed symbol names]'
-      '(-C --demangle)--demangle=-[decode mangled/processed symbol names]::style:(auto gnu lucid arm hp edg gnu-v3 java gnat rust dlang)'
+      '(--demangle)-C[decode symbol names]'
+      '(-C)--demangle=-[decode symbol names]::style [auto]:(none auto gnu-v3 java gnat dlang rust)'
       '!(--no-recurse-limit)--recurse-limit'
       '--no-recurse-limit[disable demangling recursion limit]'
       '(-w --wide)'{-w,--wide}'[format output for more than 80 columns]'
+      '-U+[specify how to display unicode characters]:method:(d l e x h i)'
+      '--unicode=[specify how to display unicode characters]:method:(default locale escape hex highlight invalid)'
       '(-z --disassemble-zeroes)'{-z,--disassemble-zeroes}"[don't skip blocks of zeroes when disassembling]"
 
       '--start-address=[only process data whose address is >= ADDR]:address'
@@ -73,15 +77,17 @@ case $variant in
       '(--show-raw-insn --no-show-raw-insn)'--{,no-}show-raw-insn'[display hex alongside symbolic disassembly]'
       '--insn-width=[display specified number of bytes on a single line with -d]:width (bytes)'
       '--adjust-vma=[add offset to all displayed section addresses]:offset'
+      '--show-all-symbols[when disassembling, display all symbols at a given address]'
       '--special-syms[include special symbols in symbol dumps]'
       '--inlines[print all inlines for source line (with -l)]'
       '--prefix=[add prefix to absolute paths for -S]:prefix'
       '--prefix-strip=[strip initial directory names for -S]:level'
       "--dwarf-depth=[don't display DIEs at specified or greater depth]:depth"
       '--dwarf-start=[display DIEs at specified or deeper depth]:depth'
-      '--dwarf-check[perform additional dwarf internal consistency checks]'
+      '--dwarf-check[perform additional dwarf consistency checks]'
       '--ctf-parent=[use specified section as the CTF parent]:section'
       '--visualize-jumps=-[visualize jumps by drawing ASCII art lines]::color:(color extended-color off)'
+      '--disassembler-color=[control use of colored syntax highlighting in disassembly output]:color use [on]:(off terminal on extended)'
     )
   ;;
   elfutils)
diff --git a/Completion/Unix/Command/_pandoc b/Completion/Unix/Command/_pandoc
index b0fff80d6..797e73eaa 100644
--- a/Completion/Unix/Command/_pandoc
+++ b/Completion/Unix/Command/_pandoc
@@ -113,7 +113,7 @@ _pandoc_defaults_file() {
 
 # choose reference location
 (( $+functions[_pandoc_reference_location] )) ||
-_pandoc_reference_location(){
+_pandoc_reference_location() {
   local -a policies
   policies=(
     'block:place references at the end of the current (top-level) block'
@@ -123,22 +123,16 @@ _pandoc_reference_location(){
   _describe 'location' policies
 }
 
-# choose top level division
-(( $+functions[_pandoc_top_level_division] )) ||
-_pandoc_top_level_division(){
-  _values 'top level division' default section chapter part
-}
-
 # choose email obfusication
 (( $+functions[_pandoc_email_obfusication] )) ||
 _pandoc_email_obfusication(){
   local -a policies
   policies=(
-    'none:leave mailto: links as they are'
-    'javascript:obfuscates them using JavaScript'
-    'references:obfuscates them by printing their letters as decimal or hexadecimal character references'
+    'none:leave mailto: links as-is'
+    'javascript:obfuscate using JavaScript'
+    'references:obfuscate by printing letters as decimal or hexadecimal character references'
   )
-  _describe 'obfuscation policy [none]' policies
+  _describe 'e-mail obfuscation policy [none]' policies
 }
 
 # choose wrapping policy
@@ -181,26 +175,26 @@ _pandoc_track_changes() {
 _arguments -s \
   {-f+,-r+,--from=,--read=}'[specify input format]: :_pandoc_format -T input' \
   {-t+,-w+,--to=,--write=}'[specify output format]: :_pandoc_format -T output' \
-  {-o+,--output=}'[write output to FILE instead of stdout]:file:_files' \
+  {-o+,--output=}'[write output to specified file instead of stdout]:file:_files' \
   '--data-dir=[specify the user data directory to search for pandoc data files]:data directory:_files -/' \
   {-d+,--defaults=}'[read default from YAML file]: :_pandoc_defaults_file' \
   '--shift-heading-level-by=[shift heading levels by specified number]:positive or negative integer: ' \
   '!--base-header-level=:number [1]:(1 2 3 4 5)' \
-  '!--strip-empty-paragraphs[deprecated. Use the +empty_paragraphs extension instead]' \
-  '--indented-code-classes=[classes to use for indented code blocks]:class list (comma-separated)' \
+  '--indented-code-classes=[specify classes to use for indented code blocks]:class list (comma-separated)' \
   '--default-image-extension=[specify a default extension to use when image paths/URLs have no extension]:extension: ' \
   '--file-scope[parse each file individually before combining for multifile documents]' \
+  '--sandbox=-[run in a sandbox, limiting IO operations]::enable:(true false)' \
   {\*-F+,\*--filter=}'[specify an executable to be used as a filter transforming the pandoc AST after the input is parsed and before the output is written]: :_pandoc_filter' \
   {\*-L+,\*--lua-filter=}"[transform the document by using pandoc's built-in lua filtering system]: :_pandoc_lua_filter" \
   {\*-M+,\*--metadata=}'[set the metadata field KEY to the value VALUE]:key\:value: ' \
   '*--metadata-file=[read metadata from file]:YAML or JSON file:_files' \
   {-p,--preserve-tabs}'[preserve tabs instead of converting them to spaces]' \
   '--tab-stop=[specify the number of spaces per tab]:spaces [4]' \
-  '--track-changes=[specifies what to do with insertions, deletions, and comments produced by the MS Word "Track Changes" feature]: :_pandoc_track_changes' \
+  '--track-changes=[specify what to do with insertions, deletions, and comments produced by the MS Word "Track Changes" feature]: :_pandoc_track_changes' \
   '--extract-media=[extract media in source document to specified directory]:directory:_files -/' \
-  '--abbreviations=[specifies a custom abbreviations file]:file:_files ' \
+  '--abbreviations=[specify a custom abbreviations file]:file:_files ' \
   {-s,--standalone}'[produce output with an appropriate header and footer]' \
-  '--template=[use FILE as a custom template for the generated document. Implies --standalone]: :_pandoc_template' \
+  '--template=[use specified file as a custom template for the generated document. Implies --standalone]: :_pandoc_template' \
   {\*-V+,\*--variable=}'[set the variable KEY to the value VALUE]:key\:value: ' \
   '(- :)'{-D+,--print-default-template=}'[print the system default template for an output]:format:( $(pandoc --list-output-formats) )' \
   '(- :)--print-default-data-file=[print a system default data file]:file: ' \
@@ -211,43 +205,48 @@ _arguments -s \
   {--toc,--table-of-contents}'[include an automatically generated table of contents]' \
   '--toc-depth=[specify the number of section levels to include in the table of contents]:number' \
   '--strip-comments[strip out HTML comments in the Markdown or Textile source]' \
-  '--no-highlight[disables syntax highlighting for code blocks and inlines]' \
-  '--highlight-style=[specifies the coloring style to be used in highlighted source code]:style|file:_pandoc_highlight_style' \
+  '--no-highlight[disable syntax highlighting for code blocks and inlines]' \
+  '--highlight-style=[specify coloring style to be used in highlighted source code]: :_pandoc_highlight_style' \
   '(- :)--print-highlight-style=[prints a JSON version of a highlighting style]: :_pandoc_highlight_style' \
   '--syntax-definition=[load a KDE XML syntax definition file]:file:_files -g "*.xml(-.)"' \
-  {\*-H+,\*--include-in-header=}'[include contents of FILE, verbatim, at the end of the header, implies --standalone]:file:_files' \
-  {\*-B+,\*--include-before-body=}'[include contents of FILE, verbatim, at the beginning of the document body, implies --standalone]:file:_files' \
-  {\*-A+,\*--include-end-body=}'[include contents of FILE, verbatim, at the end of the document body, implies --standalone]:file:_files' \
+  \*{-H+,--include-in-header=}'[include contents of file, verbatim, at the end of the header, implies --standalone]:file:_files' \
+  \*{-B+,--include-before-body=}'[include contents of file, verbatim, at the beginning of the document body, implies --standalone]:file:_files' \
+  \*{-A+,--include-end-body=}'[include contents of file, verbatim, at the end of the document body, implies --standalone]:file:_files' \
   '--resource-path=[list of paths to search for images and other resources]:searchpath:_dir_list' \
   '--request-header=[set the request header NAME to the value VAL when making HTTP requests]:name\:val: ' \
   '--no-check-certificate[disable the certificate verification]' \
   '--self-contained[produce a standalone HTML file with no external dependencies, using data: URIs to incorporate the contents of linked scripts, stylesheets, images, and videos. Implies --standalone]' \
+  '--embed-resources=-[produce a standalone HTML document with no external dependencies]::enable:(true false)' \
   '--html-q-tags[use <q> tags for quotes in HTML]' \
   '--ascii[use only ASCII characters in output, supported only for HTML and DocBook output]' \
   '--reference-links[use reference-style links, rather than inline links]' \
   '--reference-location=[specify where footnotes (and references, if reference-links is set) are placed (block|section|document)]: :_pandoc_reference_location' \
   '--markdown-headings[specify style for level1 and 2 headings in markdown output]:style [atx]:(setext atx)' \
-  '!--atx-headers[use ATX-style headers in Markdown and AsciiDoc output]' \
-  '--top-level-division=[treat top-level headers as the given division type in LaTeX, ConTeXt, DocBook, and TEI output]: :_pandoc_top_level_division' \
+  '--list-tables=-[render tables as list tables in RST output]::enable(true false)' \
+  '--top-level-division=[treat top-level headers as given division type in LaTeX, ConTeXt, DocBook and TEI output]:top level division:(default section chapter part)' \
   {-N,--number-sections}'[number section headings in LaTeX, ConTeXt, HTML, or EPUB output]' \
-  '--number-offset=[offset for section headings in HTML output (ignored in other output formats)]:number[number,...] [0]' \
+  '--number-offset=[specify offset for section headings in HTML output (ignored in other output formats)]:number[number,...] [0]' \
   '--listings[use the listings package for LaTeX code blocks]' \
   {-i,--incremental}'[make list items in slide shows display incrementally (one by one)]' \
-  '--slide-level=[specifies that headers with the specified level create slides (for beamer, s5, slidy, slideous, dzslides)]:slide level:(1 2 3 4 5 6)' \
-  '--section-divs[wrap sections in <section> tags (or <div> tags for html4)Use the section-divs package for LaTeX code blocks]' \
-  '--email-obfusication=[treat top-level headers as the given division type in LaTeX, ConTeXt, DocBook, and TEI output (none|javascript|references)]: :_pandoc_email_obfusication' \
+  '--slide-level=[divide into slides for headers above the specified level (for beamer, s5, slidy, slideous, dzslides)]: :_pandoc_header_levels' \
+  '--section-divs[wrap sections in <section> tags (or <div> tags for html4)]' \
+  '--email-obfusication=[specify method for obfusicating mailto: links in HTML documents]: :_pandoc_email_obfusication' \
   '--id-prefix=[specify a prefix to be added to all identifiers and internal links in HTML and DocBook output]:string: ' \
   {-T+,--title-prefix=}'[specify STRING as a prefix at the beginning of the title that appears in the HTML header]:string: ' \
   {\*-c+,\*--css=}'[link to a CSS style sheet]: :_urls' \
-  '--reference-doc=[use the specified file as a style reference in producing a docx or ODT file]:file: ' \
+  '--reference-doc=[use specified file as a style reference in producing a docx or ODT file]:file:_files' \
   '--epub-subdirectory=[specify the subdirectory in the OCF container that is to hold the EPUB-specific contents]:directory:_files -/' \
   '--epub-cover-image=[use the specified image as the EPUB cover]:file:_files' \
+  '--epub-title-page=-[determine whether title page is included in EPUB]::enable [true]:(true false)' \
   '--epub-metadata=[look in the specified XML file for metadata for the EPUB]:file:_files -g "*.xml(-.)"' \
   '*--epub-embed-font=[embed the specified font in the EPUB]:file:_files ' \
+  '--split-level=[specify heading level at which to split an EPUB or chunked HTML into separate files]:heading level' \
+  '--chunk-template=[specify filename template for a chunked html document]:template' \
   '--epub-chapter-level=[specify the header level at which to split the EPUB into separate "chapter" files]:number:(1 2 3 4 5 6)' \
   '--ipynb-output=[specify how to tread ipynb output cells]:method:(all none best)' \
-  '--pdf-engine=[use the specified engine when producing PDF output]:program:_pandoc_pdf_engine' \
-  '*--pdf-engine-opt=[use the given string as a command-line argument to the pdf-engine]:string:_pandoc_pdf_engine_opts' \
+  '--pdf-engine=[use specified engine when producing PDF output]:program:_pandoc_pdf_engine' \
+  '*--pdf-engine-opt=[use given string as a command-line argument to the pdf-engine]:string:_pandoc_pdf_engine_opts' \
+  '(-C --citeproc)'{-C,--citeproc}'[process citations]' \
   "*--bibliography=[set the bibliography field in the document's metadata to specified file]:file:_files -g '*.(bib|bibtex|copac|json|yaml|enl|xml|wos|medline|mods|ris)(-.)'" \
   "--csl=[set the csl field in the document's metadata to specified file]:file:_files -g '*.csl(-.)'" \
   '--citation-abbreviations=[set the citation-abbreviations field in the document'"'"'s metadata to FILE]:file:_files' \
@@ -257,10 +256,10 @@ _arguments -s \
   '--webtex=[convert TeX formulas to <img> tags that link to an external script that converts formulas to images]:: :_urls' \
   '--mathjax=[use MathJax to display embedded TeX math in HTML output]:: :_urls' \
   '--katex=[use KaTeX to display embedded TeX math in HTML output]:: :_urls' \
-  '--gladtex[Enclose TeX math in <eq> tags in HTML output]' \
+  '--gladtex[enclose TeX math in <eq> tags in HTML output]' \
   '--trace[enable tracing]' \
-  '--dump-args[print information about command-line arguments to stdout, then exit]' \
-  '--ignore-args[ignore command-line arguments (for use in wrapper scripts)]' \
+  '!--dump-args' \
+  '!--ignore-args' \
   '--verbose[give verbose debugging output]' \
   '--quiet[suppress warning messages]' \
   '--fail-if-warnings[exit with error status if there are any warnings]' \
@@ -271,6 +270,7 @@ _arguments -s \
   '(- :)--list-extensions=[list supported extensions, one per line, preceded by a + or - indicating whether it is enabled by default in FORMAT]:format:_pandoc_all_formats' \
   '(- :)--list-highlight-languages[list supported languages for syntax highlighting, one per line]' \
   '(- :)--list-highlight-styles[list supported styles for syntax highlighting, one per line]' \
+  '(- :)--print-highlight-style=[print JSON version of a highlighting style]: :_pandoc_highlight_style' \
   '(- :)'{-v,--version}'[print version]' \
   '(- :)'{-h,--help}'[print help]' \
   '*:file:_files'
diff --git a/Completion/Unix/Command/_perl b/Completion/Unix/Command/_perl
index d7e8f1b51..1631560ce 100644
--- a/Completion/Unix/Command/_perl
+++ b/Completion/Unix/Command/_perl
@@ -17,6 +17,7 @@ _perl () {
     '(1 -e)*-E+[like -e but enable all optional features]:one line of program' \
     '-f[disable executing $Config{sitelib}/sitecustomize.pl at startup]' \
     '-F-[split() pattern for autosplit (-a)]:split() pattern, // is optional' \
+    '-g[read all input in one go (slurp), rather than line-by-line (alias for -0777)]' \
     '-h[list help summary]' \
     '-i-[edit <> files in place (make backup if extension supplied)]:backup file extension: ' \
     '*-I-[specify @INC/#include directory (may be used more than once)]:include path:_files -/' \
diff --git a/Completion/Unix/Command/_pgrep b/Completion/Unix/Command/_pgrep
index 9c3ddf039..94c1dae1a 100644
--- a/Completion/Unix/Command/_pgrep
+++ b/Completion/Unix/Command/_pgrep
@@ -34,6 +34,7 @@ arguments=(
   '(-P --parent)'{-P+,--parent=}'[match only on specified parent process IDs]: :->ppid'
   '(-l)-q[suppress normal output]'
   '(-r --runstates)'{-r+,--runstates}'[match runstates]:run state:compadd -S "" D I R S T t W X Z'
+  '(-A --ignore-ancestors)'{-A,--ignore-ancestors}'[exclude our ancestors from results]'
   '-S[search also in system processes (kernel threads)]'
   '(-s --session)'{-s+,--session=}'[match only on specified process session IDs]: :->sid'
   # _signals is OK here - we do it differently below
@@ -44,6 +45,7 @@ arguments=(
   '(-u --euid)'{-u+,--euid=}'[match only on specified effective user IDs]: :_sequence _users'
   '(-v --inverse)'{-v,--inverse}'[negate matching]'
   '(-x --exact)'{-x,--exact}'[match process name or command line (with -f) exactly]'
+  '--cgroup=[match by cgroup v2 names]:cgroup'
   '--ns=[match only on same namespaces as specified PID]: :_pids'
   '--nslist=[match only on specified namespaces (with --ns)]:namespace:(ipc mnt net pid user uts)'
   '(: * -)'{-V,--version}'[display version information]'
@@ -55,6 +57,8 @@ arguments=(
   '(-w --lightweight)'{-w,--lightweight}'[show all thread IDs instead of PID]'
 )
 [[ $service == pkill ]] && arguments+=(
+  '(-H --require-handler)'{-H,--require-handler}'[match only if signal handler is present]'
+  '(-q --queue)'{-q+,--queue=}'[specify value to be sent with the signal]:value'
   '(-e --echo)'{-e,--echo}'[display signalled process]'
   '-l[display kill command]'
 )
@@ -62,8 +66,8 @@ arguments=(
 case $OSTYPE in
   linux*)
     # Note: We deliberately exclude -v but not --inverse from pkill
-    pgopts=acdFfGghLlnoOPrstUuVvwx-
-    pkopts=ceFfGghLnoOPstUuVx-
+    pgopts=AacdFfGghLlnoOPrstUuVvwx-
+    pkopts=AceFfGgHhLnoOPstUuVx-
     arguments=(
       ${arguments:#((#s)|*\))(\*|)-[acl]*}
       '(-c --count)'{-c,--count}'[display count of matching processes]'
diff --git a/Completion/Unix/Command/_ping b/Completion/Unix/Command/_ping
index d36a0f3a9..84bd76b82 100644
--- a/Completion/Unix/Command/_ping
+++ b/Completion/Unix/Command/_ping
@@ -199,7 +199,9 @@ case ${variant}:${${service#ping}:-4} in
       '-A[adaptive]'
       '-b[allow pinging a broadcast address]'
       "-B[don't allow ping to change source address]"
+      '-C[call connect() syscall on socket creation]'
       '-D[print timestamp before each line]'
+      '-e+[define identifier for ping session]:identifier'
       '(-4)-F+[allocate and set 20-bit flow label]:flow label (hex)'
       '(-)-h[show usage information]'
       '-I+[specify source interface]:interface:_net_interfaces'
diff --git a/Completion/Unix/Command/_ps b/Completion/Unix/Command/_ps
index 905309a12..c3dfae47d 100644
--- a/Completion/Unix/Command/_ps
+++ b/Completion/Unix/Command/_ps
@@ -163,10 +163,12 @@ case $OSTYPE in
       '(-N --deselect)'{-N,--deselect}'[negate selection: all processes except those selected]'
       '*-C[select processes by command name]:command:_sequence -s , _command_names -e'
       '*--ppid[select processes by parent process ID]:parent process:_sequence -S , _pids'
+      '(-D --date-format)'{-D,--date-format=}'[set the date format of the lstart field to format]:format:_strftime'
       '(-f)-F[extra full format listing]'
       '--context[show SELinux security context format]'
       '-M[show security data]'
       '(--forest -H)'{--forest,-H}'[show process hierarchy]'
+      '-P[add psr column]'
       '--headers[repeat header lines, one per page of output]'
       '(--cols --columns --width)'{--cols,--columns,--width}'[set screen width]:width'
       '(--lines --rows)'{--lines,--rows}'[set screen height]'
diff --git a/Completion/Unix/Command/_pv b/Completion/Unix/Command/_pv
index d02d3a35d..b21625650 100644
--- a/Completion/Unix/Command/_pv
+++ b/Completion/Unix/Command/_pv
@@ -17,7 +17,9 @@ _arguments -s -S $args \
   '(-I --fineta -F --format)'{-I,--fineta}'[show absolute estimated time of arrival]' \
   '(-r --rate -F --format)'{-r,--rate}'[show data transfer rate counter]' \
   '(-a --average-rate -F --format)'{-a,--average-rate}'[show data transfer average rate counter]' \
-  '(-b --bytes -F --format)'{-b,--bytes}'[show number of bytes transferred]' \
+  '(-m --average-rate-window)'{-m+,--average-rate-window=}'[compute average rate over period]:duration (seconds) [30]' \
+  '(-b --bytes -8 --bits -F --format)'{-b,--bytes}'[show number of bytes transferred]' \
+  '(-8 --bits -b --bytes -F --format)'{-8,--bits}'[show number of bits transferred]' \
   '(-T --buffer-percent -F --format)'{-T,--buffer-percent}'[show percentage of transfer buffer in use]' \
   '(-A --last-written -F --format)'{-A+,--last-written=}'[show number of bytes last written]:number (bytes)' \
   '(-F --format -p --progress -t --timer -e --eta -I --fineta -r --rate -a --average-rate -b --bytes -T --buffer-percent -A --last-written -F --format)'{-F+,--format=}'[set output format]:format:->formats' \
diff --git a/Completion/Unix/Command/_readelf b/Completion/Unix/Command/_readelf
index fc0fb7ce1..b3abdf0a5 100644
--- a/Completion/Unix/Command/_readelf
+++ b/Completion/Unix/Command/_readelf
@@ -16,10 +16,12 @@ args=(
   '(-V --version-info)'{-V,--version-info}'[show version sections (if present)]'
   '(-A --arch-specific)'{-A,--arch-specific}'[show architecture specific information (if any)]'
   '(-c --archive-index)'{-c,--archive-index}'[show symbol/file index in an archive]'
+  '(-D --use-dynamic)'{-D,--use-dynamic}'[use dynamic section info when showing symbols]'
   \*{-x,--hex-dump=}"[dump contents of specified section as bytes]:section:($sections)"
   \*{-p,--string-dump=}"[dump contents of specified section as strings]:section:($sections)"
-  '-w+[show the contents of DWARF2 debug sections]::debug section:(l L i a p r m f F s o O R t U u T g A c k K)'
-  '--debug-dump=[show the contents of DWARF2 debug sections]::section:(rawline decodedline info abbrev pubnames aranges macro frames frames-interp str loc Ranges pubtypes gdb_index trace_info trace_abbrev trace_aranges addr cu_index links follow-links)'
+  '-w+[show the contents of DWARF2 debug sections]::debug section:(a A r c L f F g i o m p t R l s O u T U k K N)'
+  '--debug-dump=[show the contents of DWARF2 debug sections]::section:(abbrev addr aranges cu_index decodedline frames frames-interp gdb_index info loc macro pubnames pubtypes Ranges rawline str str-offsets trace_abbrev trace_aranges trace_info links follow-links no-follow-links)'
+  '(-P --process-links)'{-P,--process-links}'[display the contents of non-debug sections in separate debuginfo files]'
   '(-I --histogram)'{-I,--histogram}'[show histogram of bucket list lengths]'
   '(-W --wide)'{-W,--wide}'[allow output width to exceed 80 characters]'
   '(- *)'{-H,--help}'[display help information]'
@@ -35,7 +37,6 @@ case $variant in
       '(-s --syms --symbols)'{-s,--syms,--symbols}'[show symbol table]'
       '(-n --notes)'{-n,--notes}'[show core notes (if present)]'
       '(-u --unwind)'{-u,--unwind}'[show unwind info (if present)]'
-      '(-D --use-dynamic)'{-D,--use-dynamic}'[use dynamic section info when showing symbols]'
     )
   ;|
   elfutils|binutils)
@@ -50,11 +51,14 @@ case $variant in
   ;|
   binutils)
     args+=(
+      '--sym-base=[force base for symbol sizes]:base:(0 8 10 16)'
       '!(-C --demangle)--no-demangle'
       '(--demangle)-C[decode symbol names]'
-      '(-C)--demangle=-[decode symbol names]::style [auto]:(auto gnu lucid arm hp edg gnu-v3 java gnat)'
+      '(-C)--demangle=-[decode symbol names]::style [auto]:(none auto gnu-v3 java gnat dlang rust)'
       '!(--no-recurse-limit)--recurse-limit'
       '--no-recurse-limit[disable demangling recursion limit]'
+      '-U+[specify how to display unicode characters]:method:(d l e x h i)'
+      '--unicode=[specify how to display unicode characters]:method:(default locale escape hex highlight invalid)'
       '(-L --lint --enable-checks)'{-L,--lint,--enable-checks}'[display warning messages for possible problems]'
       \*{-R,--relocated-dump=}"[dump contents of specified section as relocated bytes]:section:($sections)"
       "--dwarf-depth=[don't show DIEs at greater than specified depth]:depth"
@@ -63,6 +67,7 @@ case $variant in
       '--ctf-parent=[use specified section as the CTF parent]:section'
       '--ctf-symbols=[use specified section as the CTF external symbol table]:section'
       '--ctf-strings=[use specified section as the CTF external string table]:section'
+      '--sframe=-[display SFrame info from section]::section name [.sframe]'
       '(-T --silent-truncation)'{-T,--silent-truncation}"[if a symbol name is truncated, don't add ... suffix]"
     )
   ;;
diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync
index eb906e974..c65266dbd 100644
--- a/Completion/Unix/Command/_rsync
+++ b/Completion/Unix/Command/_rsync
@@ -141,8 +141,9 @@ _rsync() {
     '(-X --xattrs)'{-X,--xattrs}'[preserve extended attributes]' \
     '--fake-super[use xattrs to save all file attributes]' \
     '(-d --dirs)'{-d,--dirs}'[transfer directories without recursing]' \
-    {--no-d,--no-dirs}'[turn off --dirs]' \
-    "--mkpath[create the destination's path component]" \
+    '(--no-d --no-dirs)'{--no-d,--no-dirs}'[turn off --dirs]' \
+    '(--old-dirs --old-d)'{--old-dirs,--old-d}'[work like --dirs when talking to old rsync]' \
+    "--mkpath[create destination's missing path components]" \
     '(-l --links)'{-l,--links}'[copy symlinks as symlinks]' \
     {--no-l,--no-links}'[turn off --links]' \
     '(-L --copy-links)'{-L,--copy-links}'[transform symlinks into referent file/dir]' \
@@ -161,8 +162,10 @@ _rsync() {
     '(-g --group)'{-g,--group}'[preserve group]' \
     {--no-g,--no-group}'[turn off --group]' \
     '(--devices --specials)-D[same as --devices --specials]' \
-    '(-D)--devices[preserve devices]' \
+    '(-D --copy-devices --write-devices)--devices[preserve devices]' \
     '--no-devices[turn off --devices]' \
+    '(-D --devices)--copy-devices[copy device contents as a regular file]' \
+    '(-D --devices)--write-devices[write to devices as files (implies --inplace)]' \
     '(-D)--specials[preserve special files]' \
     '--no-specials[turn off --specials]' \
     '--no-D[turn off --devices and --specials]' \
@@ -179,7 +182,7 @@ _rsync() {
     '(-n --dry-run)'{-n,--dry-run}'[show what would have been transferred]' \
     '(-W --whole-file)'{-W,--whole-file}'[copy files whole (without delta-transfer algorithm)]' \
     {--no-W,--no-whole-file}'[turn off --whole-file]' \
-    '(--cc --checksum-choice)'{--cc,--checksum-choice}'=[choose the checksum algorithms]:algorithm:_sequence -n 2 compadd - auto md4 md5 none' \
+    '(--cc --checksum-choice)'{--cc,--checksum-choice}'=[choose the checksum algorithms]:algorithm:_sequence -n 2 compadd - auto xxh128 xxh3 xxh64 xxhash md4 md5 sha1 none' \
     '(-x --one-file-system)'{-x,--one-file-system}"[don't cross filesystem boundaries]" \
     '(-B --block-size)'{-B+,--block-size=}'[force a fixed checksum block-size]: :_numbers -f -u bytes -d 1g "block size" B K M G T P' \
     '(-e --rsh)'{-e+,--rsh=}'[specify the remote shell to use]:remote-shell command:(rsh ssh)' \
@@ -233,7 +236,8 @@ _rsync() {
     '*--include=[do not exclude files matching pattern]:pattern' \
     '--files-from=[read list of source-file names from specified file]:file:_files' \
     '(-0 --from0)'{-0,--from0}'[all *-from file lists are delimited by nulls]' \
-    '(-s --protect-args)'{-s,--protect-args}'[no space-splitting; only wildcard special-chars]' \
+    '(-s --secluded-args)'{-s,--secluded-args}'[use the protocol to safely send arguments]' \
+    "--trust-sender[trust the remote sender's file list]" \
     '--copy-as=[specify user & optional group for the copy]:user:_rsync_users_groups' \
     '--version[print version number]' \
     '*'{-h,--human-readable}'[output numbers in a human-readable format]' \
@@ -251,6 +255,7 @@ _rsync() {
     '--list-only[list the files instead of copying them]' \
     '--stop-after=[stop copying after specified time has elapsed]:time (minutes)' \
     '--stop-at=[stop copying when specified point in time is reached]:date/time (YYYY-MM-DDTHH\:MM):_dates -F -S "T"' \
+    '--fsync[fsync every written file]' \
     '(--only-write-batch)--write-batch=[write a batched update to the specified file]:file:_files' \
     '(--write-batch)--only-write-batch=[like --write-batch but w/o updating destination]:file:_files' \
     '--protocol=[force an older protocol version to be used]:number' \
diff --git a/Completion/Unix/Command/_samba b/Completion/Unix/Command/_samba
index 6c7a64e18..a36130cf9 100644
--- a/Completion/Unix/Command/_samba
+++ b/Completion/Unix/Command/_samba
@@ -5,16 +5,29 @@ local -a state line expl msgs args ign
 
 (( CURRENT == 2 )) || ign='!'
 args=(
+  '--debug-stdout[send debug output to stdout]'
   '(-d --debuglevel)'{-d+,--debuglevel=}'[set debug level]:debug level (1..10) [1]'
   '(-s --configfile)'{-s+,--configfile=}'[specify alternate smb.conf file]:config file:_files'
   '(-l --log-basename)'{-l+,--log-basename=}'[specify base name for log files]:base name:_files'
   '*--option=[set smb.conf option from command line]:option=value'
+  '--leak-report[enable talloc leak reporting on exit]'
+  '--leak-report-full[enable full talloc leak reporting on exit]'
   "${ign}(1 2 3 -)"{-\?,--help}'[display usage information]'
   "${ign}(1 2 3 -)--usage[display brief usage information]"
   "${ign}(1 2 3 - *)"{-V,--version}'[display version information]'
 )
 
 case $service in
+  smbclient|nmblookup)
+    args+=(
+      '(2 -R --name-resolve)'{-R+,--name-resolve=}'[specify name resolution order]:name resolution order:_values -s " " "name resolution order" lmhosts host wins bcast'
+      '(-m --max-protocol)'{-m+,--max-protocol=}'[set the max protocol level]:level'
+      '(2 -O --socket-options)'{-O+,--socket-options=}'[specify socket options]:socket options'
+      '(2)--netbios-scope=[specify NetBIOS scope]:scope'
+      '(2 -W --workgroup)'{-W+,--workgroup=}'[specify workgroup name]:workgroup name'
+      '--realm=[set the realm name]:realm'
+    )
+  ;|
   smbcontrol)
     _arguments -C -S $args \
       '(-t --timeout)'{-t+,--timeout=}'[set timeout]:timeout (seconds)' \
@@ -42,12 +55,10 @@ case $service in
   smbclient)
     args+=(
       '(-N -A)2: :_guard "^-*" password'
-      '(2 -R --name-resolve)'{-R+,--name-resolve=}'[specify name resolution order]:name resolution order:_values -s " " "name resolution order" lmhosts host wins bcast'
       '(2 -M --message -L --list -D --directory -T --tar)'{-M+,--message=}'[send message]:host:_hosts'
       '(2 -I --ip-address)'{-I+,--ip-address=}'[specify IP address of server]:IP address'
       '(2 -E --stderr)'{-E,--stderr}'[output messages to stderr]'
       '(2 -M --message -D --directory -T --tar)'{-L+,--list=}'[list services on server]:host:_hosts'
-      '(-m --max-protocol)'{-m+,--max-protocol=}'[set the max protocol level]:level'
       '(2 -T --tar -M --message -L --list)'{-T+,--tar=}'[specify tar options]:tar options'
       '(2 -D --directory -M --message -L --list)'{-D+,--directory=}'[specify initial directory]:initial directory'
       '(2 -c --command)'{-c,--command=}'[specify commands]:command string'
@@ -58,19 +69,18 @@ case $service in
       '(-q --quiet)'{-q,--quiet}'[suppress help message]'
       '(-B --browse)'{-B,--browse}'[browse SMB servers using DNS]'
       '(2 -d --debuglevel)'{-d+,--debuglevel=}'[specify debug level]:debug level:(0 1 2 3 4 5 6 7 8 9 10)'
-      '(2 -O --socket-options)'{-O+,--socket-options=}'[specify socket options]:socket options'
       '(2 -n --netbiosname)'{-n+,--netbiosname=}'[specify local NetBIOS name]:local machine name'
-      '(2 -W --workgroup)'{-W+,--workgroup=}'[specify workgroup]:workgroup'
-      '(2 -i --scope)'{-i+,--scope=}'[specify NetBIOS scope]:scope'
       '(2 -U --user)'{-U+,--user=}'[specify username]:username:_users'
       '(2 -N --no-pass)'{-N,--no-pass}'[suppress password prompt]'
-      '(-k --kerberos)'{-k,--kerberos}'[use kerberos (active directory) authentication]'
-      '(2 -A --authentication-file)'{-A+,--authentication-file=}'[specify file containing username/password]:file:_files'
-      '(-S --signing)'{-S+,--signing=}'[set the client signing state]:state:(on off required)'
-      '(-P --machine-pass)'{-P,--machine-pass}'[use stored machine account password]'
-      '(-e --encrypt)'{-e,--encrypt}'[encrypt SMB transport]'
-      '(-C --use-ccache)'{-C,--use-ccache}'[use the winbind ccache for authentication]'
       '--pw-nt-hash[the supplied password is the NT hash]'
+      '(2 -A --authentication-file)'{-A+,--authentication-file=}'[specify file containing username/password]:file:_files'
+      '(-P --machine-pass)'{-P,--machine-pass}'[use stored machine account password]'
+      '--simple-bind-dn=[specify DN to use for a simple bind]:DN'
+      '--use-kerberos=[use Kerberos authentication]:state:(desired required off)'
+      '--use-krb5-ccache=[specify credentials cache location for Kerberos]:file:_files'
+      '--use-winbind-ccache[use the winbind ccache for authentication]'
+      '--client-protection=[configure protection used for client connections]:protection:(sign encrypt off)'
+      '!(--use-kerberos)'{-k,--kerberos}
     )
     (( CURRENT == 2 )) && args+=( '1:service name:_hosts -P // -S /' )
     _arguments -s -S $args
@@ -81,16 +91,13 @@ case $service in
       '(-f --flags)'{-f,--flags}'[list NMB flags returned]' \
       '(-U --unicast)'{-U+,--unicast=}'[specify unicast address]:unicast address' \
       '(-M --master-browser)'{-M,--master-browser}'[search for a master browser]' \
-      '(-R --recursion)'{-R,--recursion}'[set recursion desired in packet]' \
+      '--recursion[set recursion desired in packet]' \
       '(-S --status)'{-S,--status}'[lookup node status as well]' \
       '(-T --translate)'{-T,--translate}'[perform reverse DNS on IP addresses]' \
       '(-r --root-port)'{-r,--root-port}'[use root port 137]' \
       '(-A --lookup-by-ip)'{-A,--lookup-by-ip}'[query node status on IP address]' \
       '(-d --debuglevel)'{-d+,--debuglevel=}'[specify debug level]:debug level:(0 1 2 3 4 5 6 7 8 9 10)' \
-      '(-O --socket-options)'{-O+,--socket-options=}'[specify socket options to use]:socket option' \
       '(-n --netbiosname)'{-n+,--netbiosname=}'[specify primary netbios name]:netbios name' \
-      '(-W --workgroup)'{-W+,--workgroup=}'[specify workgroup name]:workgroup name' \
-      '(-i --scope)'{-i+,--scope=}'[specify NetBIOS scope]:scope' \
       '(h)*:NetBIOS name:_hosts'
   ;;
   smbstatus)
diff --git a/Completion/Unix/Command/_sqlite b/Completion/Unix/Command/_sqlite
index 6425732f1..6f0b1de94 100644
--- a/Completion/Unix/Command/_sqlite
+++ b/Completion/Unix/Command/_sqlite
@@ -12,7 +12,7 @@ dashes=( '' )
 
 options=(
   '(-init --init)'$^dashes'-init[startup file]:file containing SQLite commands:_files'
-  $^dashes'-echo[echo commands]'
+  $^dashes'-echo[print inputs before execution]'
 )
 
 exclusive=( {,-}-{no,}header )
@@ -72,12 +72,14 @@ if [[ -n $words[(r)-A*] ]]; then
     '(1 -a --append -f --file)'{-f+,--file=}'[specify archive file]:archive file:_files'
     '(1 -a --append -f --file)'{-a,--append=}'[operate on specified file opened using the apndvfs VFS]:archive file:_files'
     '(-C --directory)'{-C+,--directory=}'[change to specified directory to read/extract files]:directory:_directories'
+    '(-g --glob)'{-g,--glob}'[use glob matching for names in archive]'
     '(-n --dryrun)'{-n,--dryrun}'[show the SQL that would have occurred]'
     '*:file:_files'
     + '(commands)' \
     '(-c --create)'{-c,--create}'[create a new archive]'
     '(-u --update)'{-u,--update}'[update or add files to an existing archive]'
     '(-i --insert)'{-i,--insert}'[like -u but always add even if mtime unchanged]'
+    '(-r --remove)'{-r,--remove}'[remove files from archive]'
     '(-t --list)'{-t,--list}'[list contents of archive]'
     '(-x --extract)'{-x,--extract}'[extract files from archive]'
   )
diff --git a/Completion/Unix/Command/_strip b/Completion/Unix/Command/_strip
index 3e1a6b698..cc67ae49a 100644
--- a/Completion/Unix/Command/_strip
+++ b/Completion/Unix/Command/_strip
@@ -1,55 +1,68 @@
 #compdef strip
 
-local curcontext=$curcontext state line ret=1
+local curcontext=$curcontext state line variant ret=1
 declare -A opt_args
 declare -a args
 
-if _pick_variant gnu=GNU solaris --version; then
-  if [[ -prefix @* ]]; then
-    compset -P '@'
+if _pick_variant -r variant gnu=GNU elftoolchain=elftoolchain $OSTYPE --version; then
+  case $variant in
+    gnu|elftoolchain)
+      args=(
+        '(-g -S -d --strip-debug)'{-g,-S,-d,--strip-debug}'[remove debugging symbols]'
+        '(-I --input-target)'{-I+,--input-target=}'[object code format of input]:bfd name:->bfdnames'
+        '*'{-K+,--keep-symbol=}'[keep given symbol]:symbol name'
+        '*'{-N+,--strip-symbol=}'[strip given symbol]:symbol name'
+        '(-O --output-target)'{-O+,--output-target=}'[object code format of output]:bfd name:->bfdnames'
+        '(-p --preserve-dates)'{-p,--preserve-dates}'[preserve access and modification dates]'
+        '*'{-R+,--remove-section=}'[remove given sections]:section name'
+        '(-s --strip-all)'{-s,--strip-all}'[remove all symbols]'
+        '(-w --wildcard)'{-w,--wildcard}'[permit wildcards in symbol names]'
+        '(-X --discard-locals)'{-X,--discard-locals}'[remove compiler-generated local symbols]'
+        '(-x --discard-all)'{-x,--discard-all}'[remove non-global symbols]'
+        '--only-keep-debug[remove everything except debugging information]'
+        '--strip-unneeded[remove symbols not needed for relocation processing]'
+        '(- 1 *)'{-V,--version}'[display version information and exit]'
+      )
+    ;|
+    gnu)
+      if [[ -prefix @* ]]; then
+        compset -P '@'
 
-    local expl
+        local expl
 
-    _description files expl 'command-line-options file'
-    _files "$expl[@]"
-    return
-  fi
-  args=(
-    '(-F --target)'{-F+,--target=}'[object code format to use]:bfd name:->bfdnames'
-    '(-)--help[display usage information]'
-    '(-)--info[display list of architectures and object formats]'
-    '(-I --input-target)'{-I+,--input-target=}'[object code format of input]:bfd name:->bfdnames'
-    '(-O --output-target)'{-O+,--output-target=}'[object code format of output]:bfd name:->bfdnames'
-    '(-D --enable-deterministic-archives -U --disable-deterministic-archives)'{-U,--disable-deterministic-archives}'[disable -D behavior]'
-    '(-D --enable-deterministic-archives -U --disable-deterministic-archives)'{-D,--enable-deterministic-archives}'[produce deterministic output when stripping archives (zero file metadata)]'
-    '*'{-R+,--remove-section=}'[remove given sections]:section name'
-    '--remove-relocations=[remove relocations from specified section]:section'
-    '(-s --strip-all)'{-s,--strip-all}'[remove all symbols]'
-    '(-g -S -d --strip-debug)'{-g,-S,-d,--strip-debug}'[remove debugging symbols]'
-    '--strip-dwo[remove all DWARF .dwo sections]'
-    '--strip-unneeded[remove symbols not needed for relocation processing]'
-    '!(--no-merge-notes)'{-M,--merge-notes}
-    "--no-merge-notes[don't attempt to remove redundant notes]"
-    '*'{-K+,--keep-symbol=}'[keep given symbol]:symbol name'
-    '*'{-N+,--strip-symbol=}'[strip given symbol]:symbol name'
-    "*--keep-section=[don't strip given section]:section"
-    '(*)-o+[output file]:output file:_files'
-    '(-p --preserve-dates)'{-p,--preserve-dates}'[preserve access and modification dates]'
-    '(-w --wildcard)'{-w,--wildcard}'[permit wildcards in symbol names]'
-    '(-x --discard-all)'{-x,--discard-all}'[remove non-global symbols]'
-    '(-X --discard-locals)'{-X,--discard-locals}'[remove compiler-generated local symbols]'
-    '--keep-file-symbols[retain symbols specifying source file names]'
-    '--only-keep-debug[remove everything except debugging information]'
-    '(-)'{-V,--version}'[display version information and exit]'
-    '(-v --verbose)'{-v,--verbose}'[list all object files modified or members of archives]')
-else
-  case $OSTYPE in
+        _description files expl 'command-line-options file'
+        _files "$expl[@]"
+        return
+      fi
+      args+=(
+        '(-F --target)'{-F+,--target=}'[object code format to use]:bfd name:->bfdnames'
+        '(-)--help[display usage information]'
+        '(-)--info[display list of architectures and object formats]'
+        '(-D --enable-deterministic-archives -U --disable-deterministic-archives)'{-U,--disable-deterministic-archives}'[disable -D behavior]'
+        '(-D --enable-deterministic-archives -U --disable-deterministic-archives)'{-D,--enable-deterministic-archives}'[produce deterministic output when stripping archives (zero file metadata)]'
+        '--remove-relocations=[remove relocations from specified section]:section'
+        '--strip-dwo[remove all DWARF .dwo sections]'
+        '!(--no-merge-notes)'{-M,--merge-notes}
+        "--no-merge-notes[don't attempt to remove redundant notes]"
+        "*--keep-section=[don't strip given section]:section"
+        '(*)-o+[output file]:output file:_files'
+        '--keep-section-symbols[retain section symbols]'
+        '--keep-file-symbols[retain symbols specifying source file names]'
+        '(-v --verbose)'{-v,--verbose}'[list all object files modified or members of archives]')
+    ;;
+    elftoolchain)
+      args+=(
+        '(- 1 *)'{-h,--help}'[display usage information]'
+        '(*)'{-o+,--output-file=}'[specify output file]:output file:_files'
+      )
+    ;;
     solaris*)
       args=(
 	'-l[strip line information only]'
 	'-V[display version information on stderr and exit]'
-	'-x[do not strip the symbol table]')
-      ;;
+	'-x[do not strip the symbol table]'
+      )
+    ;;
     darwin*)
       local -a arch
       arch=( ${(z)${${"$(_call_program architectures
@@ -73,12 +86,13 @@ else
 	'-no_uuid[remove only LC_UUID load command]'
 	'-no_split_info[remove LC_SEGMENT_SPLIT_INFO load command]'
 	'-no_code_signature_warning[not warn when code signature would be invalid in the output]'
-	'-arch[specify the architecture]:architecture:( $arch )' )
-      ;;
+	'-arch[specify the architecture]:architecture:( $arch )'
+      )
+    ;;
   esac
 fi
 
-_arguments \
+_arguments -C \
   $args \
   '1:executable:_files -g "*(-*)"' \
   '*::executable:_files -g "*(-*)"' && ret=0
diff --git a/Completion/Unix/Command/_tiff b/Completion/Unix/Command/_tiff
index ef12777de..1aeff3ff7 100644
--- a/Completion/Unix/Command/_tiff
+++ b/Completion/Unix/Command/_tiff
@@ -159,6 +159,7 @@ tiffinfo)
     '-f+[force fill order]:fill order:(lsb2msb msb2lsb)' \
     '-w[display raw data in words]' \
     '-z[enable strip chopping]' \
+    '-M+[set the memory allocation limit]:limit (MiB), 0 for unlimited' \
     '*:input TIFF file:_files -g "*.(#i)tif(|f)(-.)"' && ret=0
   ;;
 tiffmedian)
@@ -172,6 +173,7 @@ tiffmedian)
   ;;
 tiffsplit)
   _arguments \
+    '-M+[set the memory allocation limit]:limit (MiB), 0 for unlimited' \
     ':input file:_files -g "*.(#i)tif(|f)(-.)"' \
     ':output file prefix' && ret=0
   ;;
diff --git a/Completion/Unix/Command/_truss b/Completion/Unix/Command/_truss
index b798f03cb..b69e174e6 100644
--- a/Completion/Unix/Command/_truss
+++ b/Completion/Unix/Command/_truss
@@ -16,7 +16,11 @@ args=(
 
 case $OSTYPE in
   solaris2.<11->)
-    args+=( '(-c)-A[include absolute timestamps in output]' )
+    args+=(
+      '(-c)-A[include absolute timestamps in output]'
+      '-I[interpret system calls to well-known rather than underlying names]'
+      '-N[report only system calls that returned an error]'
+    )
   ;|
   aix*|solaris*)
     args+=(
diff --git a/Completion/Unix/Command/_user_admin b/Completion/Unix/Command/_user_admin
index db1c977ad..d5a53af7c 100644
--- a/Completion/Unix/Command/_user_admin
+++ b/Completion/Unix/Command/_user_admin
@@ -12,7 +12,7 @@ case ${service%???}:${(M)service%???}:$OSTYPE in
       shells=( ${(M)commands:#*/(|[abckz]|tc|ba)sh} )
     fi
     args+=(
-      '(-D -c --commend)'{-c+,--comment=}'[comment]:comment'
+      '(-D -c --comment)'{-c+,--comment=}'[comment]:comment'
       '(-D -d --home -b --base-dir)'{-d+,--home=}"[specify home directory]:home directory:_directories -W /"
       '(-D -e --expiredate)'{-e+,--expiredate}'[specify expiration date]:expiration date (YYYY-MM-DD)'
       '(-D -f --inactive)'{-f+,--inactive=}'[specify inactive days]:inactive days'
@@ -41,6 +41,8 @@ case ${service%???}:${(M)service%???}:$OSTYPE in
       SYS_GID_MIN SYS_UID_MAX SYS_UID_MIN UID_MAX UID_MIN UMASK
     )
     args+=(
+      '--btrfs-subvolume-home[use BTRFS subvolume for home directory]'
+      '(-F --add-subids-for-system)'{-F,--add-subids-for-system}'[add entries to sub[ud]id even when adding a system user]'
       '(-l --no-log-init)'{-l,--no-log-init}"[don't add user to lastlog and faillog databases]"
       '(-m --create-home -M --no-create-home)'{-M,--no-create-home}"[don't create user's home directory, regardless of /etc/login.defs]"
       '(-N --no-user-group -U --user-group)'{-N,--no-user-group}"[don't create a group with the same name as the user]"
@@ -103,6 +105,7 @@ case ${service%???}:${(M)service%???}:$OSTYPE in
   user:mod:linux*)
     args+=(
       '(-a --append)'{-a,--append}'[add user to supplementary groups without removing from other groups]'
+      '(-r --remove)'{-r,--remove}'[remove user from supplementary groups without removing from other groups]'
       \*{-v,--add-subuids}'[add a range of subordinate uids]:uids (first-last)'
       \*{-V,--del-subuids}'[remove a range of subordinate uids]:uids (first-last)'
       \*{-w,--add-subgids}'[add a range of subordinate gids]:gids (first-last)'
@@ -118,9 +121,16 @@ case ${service%???}:${(M)service%???}:$OSTYPE in
   ;|
   user:*:linux*)
     args+=(
+      '(-b --badname)'{-b,--badname}"[don't check for bad names]"
       '(-U --unlock --lock -L -p)'{-L,--lock}"[lock user's password]"
       '(-U --unlock --lock -L -p)'{-U,--unlock}"[unlock user's password]"
-      '(-Z --selinux-user)'{-Z,--selinux-user}"[specify SELinux user for the user's login]:user"
+      '(-Z --selinux-user)'{-Z,--selinux-user}"[specify SELinux user for the user's login]:user:_selinux_users"
+      "--selinux-range[specify SELinux MLS range for the user's login]:range"
+    )
+  ;|
+  group:*:linux*)
+    args+=(
+      '(-U --users)'{-U+,--users=}'[specify users to add as members of the group]:user:_sequence _users'
     )
   ;|
   group:*)
@@ -164,6 +174,9 @@ case ${service%???}:${(M)service%???}:$OSTYPE in
       ':group:_groups'
     )
   ;|
+  group:mod:linux*)
+    args+=( '(-a --append)'{-a,--append}'[append the users mentioned by -U without removing existing members]' )
+  ;|
   ^*:linux*)
     args=( ${(R)args:#(|\*)(|\(*\))--*} )    # remove long options
   ;|
diff --git a/Completion/Unix/Command/_vmstat b/Completion/Unix/Command/_vmstat
index e05bc88bc..6db776e62 100644
--- a/Completion/Unix/Command/_vmstat
+++ b/Completion/Unix/Command/_vmstat
@@ -8,7 +8,7 @@ case $OSTYPE in
       '(-t --timestamp)'{-t,--timestamp}'[show timestamp]'
       '(-n --one-header)'{-n,--one-header}'[do not redisplay header]'
       '(-S --unit)'{-S+,--unit=}'[specify unit for displayed sizes]:unit prefix [K]:((k\:1000 K\:1024 m\:1000000 M\:1048576))'
-      '(-C --full-cache)'{-C,--full-cache}'[add further cache lines to main cache]'
+      '(-y --no-first)'{-y,--no-first}'[skip first line of output]'
       '1: :_guard "[0-9]#" "interval (seconds)"' '2:count'
       + '(action)' \
       '(- :)'{-h,--help}'[display help information]'
diff --git a/Completion/Unix/Command/_vorbis b/Completion/Unix/Command/_vorbis
index 6c94469f9..fca218a51 100644
--- a/Completion/Unix/Command/_vorbis
+++ b/Completion/Unix/Command/_vorbis
@@ -32,7 +32,6 @@ case $service in
       '(-q --quality)'{-q+,--quality=}'[set encoding quality]:quality:(0 1 2 3 4 5 6 7 8 9 10)' \
       '--resample=[resample input to the given sample rate before encoding]:sample rate (Hz)' \
       '--downmix[down mix input from stereo to mono]' \
-      '--scale=[set input scaling factor]:scaling factor' \
       '(-s --serial)'{-s+,--serial=}'[force a specific serial number in the output stream]:serial number' \
       "--discard-comments[don't copy comments from FLAC file to output Ogg Vorbis file]" \
       '--ignorelength[ignore the datalength in Wave headers]' \
@@ -74,10 +73,6 @@ case $service in
       '(-q --quiet -v --verbose)'{--quiet,-q}'[quiet mode]' \
       '(-q --quiet)*'{-v,--verbose}'[increase verbosity]' \
       '(- *)'{-V,--version}'[display version information]' \
-      \*{-c-,--config=-}'[specify config options]: :_values option
-        "default_device\:device"
-        "shuffle\:value\:(0 1)"
-        "repeat\:value\:(0 1)"' \
       '*:sound file or directory:->urls-or-files' && ret=0
   ;;
   ogginfo)
diff --git a/Completion/Unix/Command/_w b/Completion/Unix/Command/_w
index 69751c5e5..e82c84f57 100644
--- a/Completion/Unix/Command/_w
+++ b/Completion/Unix/Command/_w
@@ -1,6 +1,6 @@
 #compdef w
 
-local args
+local -a args
 
 case $OSTYPE in
   linux*)
@@ -11,7 +11,7 @@ case $OSTYPE in
       '(H -o --old-style -s --short)'{-o,--old-style}'[old style output format]'
       '(H -s --short -o --old-style)'{-s,--short}'[use short output format]'
       '(H -u --no-current)'{-u,--no-current}'[ignore the username while figuring out the current process and cpu times]'
-      '(H -n --no-truncat)'{-n,--no-truncat}'[non-truncated listing (large)]'
+      '(H -p --pids)'{-p,--pids}'[show process IDs]'
       + H
       '(-)--help[display help information]'
       '(-)'{-V,--version}'[display version information]'
diff --git a/Completion/Unix/Command/_wget b/Completion/Unix/Command/_wget
index 50fd7791a..acc8d5c6e 100644
--- a/Completion/Unix/Command/_wget
+++ b/Completion/Unix/Command/_wget
@@ -23,6 +23,7 @@ _arguments -C -s \
   '(--config)--no-config' '--rejected-log=:file:_files' \
   '(--tries -t)'{--tries=,-t+}'[set number of retries]:number of retries' \
   '--retry-connrefused[retry even if connection is refused]' \
+  '--retry-on-host-error[consider host errors as non-fatal, transient errors]' \
   '--retry-on-http-error=[specify list of HTTP errors to retry]:http error' \
   '(--output-document -O)'{--output-document=,-O+}'[specify file to write documents to]:output file:_files' \
   '(--continue -c)'{--continue,-c}'[continue getting an existing file]'  \
@@ -98,7 +99,7 @@ _arguments -C -s \
   '--content-disposition[honor the Content-Disposition header when choosing local file names]'  \
   '--content-on-error[output received content on server errors]' \
   "--auth-no-challenge[send basic HTTP authentication without first waiting for server's challenge]" \
-  '--secure-protocol=[choose secure protocol]:protocol:(SSLv2 SSLv3 TLSv1 TLSv1_1 TLSv1_2 PFS)' \
+  '--secure-protocol=[choose secure protocol]:protocol:(SSLv2 SSLv3 TLSv1 TLSv1_1 TLSv1_2 TLSv1_3 PFS)' \
   --https-only \
   "--no-check-certificate[don't check the server certificate]" \
   '--certificate=[specify client certificate]:client certificate file:_files' \
diff --git a/Completion/Unix/Command/_xmlsoft b/Completion/Unix/Command/_xmlsoft
index 08b123e54..b8cf92700 100644
--- a/Completion/Unix/Command/_xmlsoft
+++ b/Completion/Unix/Command/_xmlsoft
@@ -40,6 +40,7 @@ case $service in
       '--maxdepth[increase the maximum depth]:depth' \
       '--maxvars[increase the maximum variables]:variables' \
       '--maxparserdepth[increase the maximum parser depth]:depth' \
+      '--huge[relax hardcoded limits of the parser]' \
       '--seed-rand[initialise random number generator]:seed' \
       '--html[input document is an HTML file]' \
       '--encoding[the input document character encoding]:encoding:(${encoding[@]})' \
diff --git a/Completion/Unix/Command/_xxd b/Completion/Unix/Command/_xxd
index 31d26ab64..e9015a081 100644
--- a/Completion/Unix/Command/_xxd
+++ b/Completion/Unix/Command/_xxd
@@ -24,7 +24,7 @@ arguments=(
   # output options
   '(-b -bits            -i -include -p -postscript -plain -ps -r -revert -u -uppercase)'{-b,-bits}'[output in binary digits, rather than hex]'
   '(         -E -EBCDIC -i -include -p -postscript -plain -ps -r -revert              )'{-E,-EBCDIC}'[print human-readable part in EBCDIC rather than ASCII]'
-  '(-i -include -p -postscript -plain -ps -r -revert)'{-e,-endian}'[little-endian dump]'
+  '(-i -include -p -postscript -plain -ps -r -revert)-e[little-endian dump]'
   '(-b -bits -E -EBCDIC -i -include -p -postscript -plain -ps -r -revert              )'{-i,-include}'[output in C include file style]'
   '(-b -bits -E -EBCDIC -i -include -p -postscript -plain -ps -C -capitalize          )'{-p,-postscript,-plain,-ps}'[read or write a plain hexdump (no line numbers or ASCII rendering)]'
 
@@ -35,12 +35,14 @@ arguments=(
   '(- :)'{-v,-version}'[show program version]'
   '*'{-a,-autoskip}"[a single '*' replaces runs of NUL (toggleable)]"
   '(-C -capitalize)'{-C,-capitalize}'[capitalize variable names in C include file style]'
-  {-c+,-cols}'[specify number of octets per line]: :_guard "[0-9a-fA-Fx]#" "number of octets per line"'
-  {-g+,-groupsize}'[specify the number of octets per group]: :_guard "[0-9]#" "number of octets per group"'
-  {-l+,-len}'[specify number of octets to output]: :_guard "[0-9]#" "number of octets to output"'
-  {-o+,-offset}'[add specified offset to displayed file position]:offset'
+  '(-c -cols)'{-c+,-cols}'[specify number of octets per line]: :_guard "(0x|)[0-9a-fA-Fx]#" "number of octets per line"'
+  '(-g -groupsize)'{-g+,-groupsize}'[specify the number of octets per group]: :_guard "(0x|)[0-9a-fA-F]#" "number of octets per group"'
+  '(-l -len)'{-l+,-len}'[specify number of octets to output]: :_guard "(0x|)[0-9a-fA-F]#" "number of octets to output"'
+  '(-n -name)'{-n+,-name}'[override the variable name output when -i is used]:variable name'
+  '(-o -offset)'{-o+,-offset}'[add specified offset to displayed file position]:offset'
   '-d[show offset in decimal instead of hex]'
-  {-s,-skip,-seek}'[specify file offset to dump from]: :_guard "[0-9]#" "file offset to dump from (absolute or relative)"'
+  '-R+[colorize the output]:when:(always auto never)'
+  '(-s -skip -seek)'{-s+,-skip,-seek}'[specify file offset to dump from]: :_guard "(0x|)[0-9a-fA-F]#" "file offset to dump from (absolute or relative)"'
 
   ': :_files'
 )
diff --git a/Completion/X/Command/_evince b/Completion/X/Command/_evince
index 21b493360..49f11f341 100644
--- a/Completion/X/Command/_evince
+++ b/Completion/X/Command/_evince
@@ -15,6 +15,7 @@ _arguments -s -S \
   '--g-fatal-warnings[make all warnings fatal]' \
   '--gtk-debug=[specify GTK+ debugging flags to set]:flag' \
   '--gtk-no-debug=[specify GTK+ debugging flags to unset]:flag' \
+  '(-o --new-window)'{-o,--new-window}'[open a new window]' \
   '(-p --page-label -i --page-index -n --named-dest)'{-p,--page-label=}'[specify page label of the document to display]' \
   '(-p --page-label -i --page-index -n --named-dest)'{-i,--page-index=}'[specify page number of the document to display]' \
   '(-p --page-label -i --page-index -n --named-dest)'{-n,--named-dest=}'[specify named destination to display]' \
diff --git a/Completion/X/Command/_qiv b/Completion/X/Command/_qiv
index 35ceec09a..5d0aa8faf 100644
--- a/Completion/X/Command/_qiv
+++ b/Completion/X/Command/_qiv
@@ -10,6 +10,7 @@ _arguments -s \
   '(-C --cycle)'{-C,--cycle}"[don't cycle after last image]" \
   '(-w --fixed_width -W --fixed_zoom)'{-w,--fixed_width}'[use window with specified width]:width' \
   '(-w --fixed_width -W --fixed_zoom)'{-W,--fixed_zoom}'[use window with specified zoom factor]:zoom (percentage)' \
+  '--highDPIfactor[specify resize factor to compensate for high (or also low) DPI screens]:factor' \
   '(-x -y -z --root --root_t --root_s -f --file *)'{-x,--root}'[use image as the current desktop background, centered]:image file:_files' \
   '(-x -y -z --root --root_t --root_s -f --file *)'{-y,--root_t}'[use image on the current desktop background, tiled]:image file:_files' \
   '(-x -y -z --root --root_t --root_s -f --file *)'{-z,--root_s}'[use image as the current desktop background, stretched]:image file:_files' \
@@ -22,6 +23,9 @@ _arguments -s \
   '(-n --no_filter)'{-n,--no_filter}'[disable filtering of images by extension]' \
   '(-i --no_statusbar -I --statusbar)'{-i,--no_statusbar}'[disable statusbar]' \
   '(-i --no_statusbar -I --statusbar)'{-I,--statusbar}'[enable statusbar]' \
+  '(-J --showJPEGcomments)'{-J,--showJPEGcomments}'[enable display of JPEG comments]' \
+  '(-E --showArtistName)'{-E,--showArtistName}'[enable display of artist (author) name]' \
+  "--artist_ignore[don't show specified artist name]:artist" \
   '(-p --transparency)'{-p,--transparency}'[enable transparency]' \
   '(-a --do_grab)'{-a,--do_grab}'[grab the pointer in windowed mode]' \
   '(-G --disable_grab)'{-G,--disable_grab}'[disable pointer grabbing in fullscreen mode]' \
@@ -47,4 +51,4 @@ _arguments -s \
   '(-Y --source_profile)'{-Y,--source_profile}'[specify colour profile file as source profile]:colour profile file:_files' \
   '(-Z --display_profile)'{-Z,--display_profile}'[specify colour profile file as display profile]:colour profile file:_files' \
   '--vikeys[enable movement with h/j/k/l]' \
-  '*:image file:_files -g "*.(#i)(bmp|eim|gif|ico|jp([eg]|eg)|pcx|png|p[pngb]m|pjpeg|svg|tif(|f)|wmf|x[pb]m)(-.)"'
+  '*:image file:_files -g "*.(#i)(bmp|eim|gif|hei[cf]|ico|jp([eg]|eg)|pcx|png|p[pngb]m|pjpeg|svg|tif(|f)|webp|wmf|x[pb]m)(-.)"'
diff --git a/Completion/X/Command/_xdvi b/Completion/X/Command/_xdvi
index c33e67bcc..ed5982bcc 100644
--- a/Completion/X/Command/_xdvi
+++ b/Completion/X/Command/_xdvi
@@ -2,15 +2,22 @@
 
 _xt_arguments \
   -+{allowshell,copy,expert,hush{,chars,checksums,specials},keep,l,no{ghostscript,grey,gssafer,makepk,postscript,scan},safer,thorough,underlink,version} \
-  +{altfont,base,browser,cr,debug,density,gamma,gspalette,hl,icongeometry,interpreter,margin,mfmode,offsets,p,paper,shrink,S,sidemargin,topmargin,xoffset,yoffset,grid{1,2,3},mgs{,1,2,3,4,5}} \
+  +{altfont,background,bg,browser,cr,debug,density,dvispath,editor,gamma,gspalette,hl,icongeometry,interpreter,margin,mfmode,offsets,p,paper,shrink,S,sidemargin,topmargin,xoffset,yoffset,grid{1,2,3},mgs{,1,2,3,4,5}} \
   '-altfont:default font' \
-  '-base:base URL' \
+  -{bg,background}':color:_x_color' \
   '-browser:WWW browser:_command_names -e' \
   '-cr:cursor color:_x_color' \
-  '-debug:debugging bitmask:((1\:bitmaps 2\:dvi\ translation 4\:pk\ reading 8\:batch\ operation 16\:events 32\:file\ opening 64\:PostScript\ communication 128\:Kpathsea\ statistics 256\:Kpathsea\ hash\ table\ lookups 512\:Kpathsea\ path\ definitions 1024\:Kpathsea\ path\ expansion 2048\:Kpathsea\ searches))' \
+  '-debug:debugging bitmask:((1\:bitmaps 2\:dvi\ translation 4\:pk\ reading 8\:batch\ operation 16\:events 32\:file\ opening 64\:PostScript\ communication 128\:Kpathsea\ statistics 256\:Kpathsea\ hash\ table\ lookups 512\:Kpathsea\ path\ definitions 1024\:Kpathsea\ path\ expansion 2048\:Kpathsea\ searches ))' \
   '-density:font shrink density' \
+  '-dvispath:dvips program:_command_names -e' \
+  '-editor:text editor:_cmdstring' \
+  '-expertmode:display bitmask:((1\:statusline 2\:scrollbars 4\:pagelist 8\:toolbar 16\:menubar))' \
+  -{fg,foreground}':color:_x_color' \
+  '-findstring:string' \
+  '-font:font:_x_font' \
+  '-fullscreen' \
   '-gamma:anti-aliasing factor [1.0]' \
-  -grid{1,2,3}':grid color:_x_color' \
+  '-gsalpha' \
   '-gspalette:Ghostscript palette:(Color Greyscale Monochrome)' \
   '-hl:page highlight color:_x_color' \
   '-icongeometry:icon geometry:_x_geometry' \
@@ -21,6 +28,9 @@ _xt_arguments \
   '-offsets:offset size' \
   '-p:font size (pixel per inch)' \
   '-paper:paper size (<width>x<height> or ...):(us usr legal foolscap a1 a2 a3 a4 a5 a6 a7 b1 b2 b3 b4 b5 b6 b7 c1 c2 c3 c4 c5 c6 c7 a1r a2r a3r a4r a5r a6r a7r)' \
+  '-ps2pdfpath:ps2pdf program:_command_names -e' \
+  '-rulecolor:color' \
+  '-rv' \
   '-shrink:shrink factor' \
   '-S:font shrink density' \
   '-sidemargin:side margin' \


^ permalink raw reply	[relevance 1%]

* Re: Suggested changes to Etc/FAQ
  @ 2023-11-16  2:32  3%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2023-11-16  2:32 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 433 bytes --]

New patch attached, incorporating suggestions/corrections.

On Mon, Nov 13, 2023 at 6:18 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> As the FAQ can get around it might be worthwhile adding release numbers
> to new features

Oblique references to already appeared in the list in section 2.1, but
i've added them to 2.9 - 2.11 as well.

Stephane, see what you think about the rewrite of "cmd1 && cmd2 &"

[-- Attachment #2: EtcFAQ.txt --]
[-- Type: text/plain, Size: 8627 bytes --]

diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 8c795685a..270a04608 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -445,7 +445,14 @@ label(21)
      invoked with the appropriate name.  Including the command
      `emulate sh; setopt localoptions' in a shell function will
      turn on sh emulation for that function only.  In version 4 (and in
-     3.0.6 through 8), this can be abbreviated as `emulate -L sh'.
+     3.0.6 through 8), this can be abbreviated as `emulate -L sh';
+  myeit() in versions after 5.9, the myem(namespace) syntax and
+     myem(named references) (ksh mytt(nameref)) are available, but
+     differ in some details from the ksh93+ semantics;
+  myeit() also after 5.9, myem(non-forking command substitutions) are
+     available.  These are described by ksh as myem(a brace group preceded
+     by a dollar sign) (mytt(${ list;})), but zsh has both some added
+     features adopted from mksh, and some limitations, see link(2.11)(211)
    )
 
   The classic difference is word splitting, discussed in question \
@@ -496,9 +503,9 @@ tt(RM_STAR_SILENT),
 	those are a completely different type of object.)
     it()  Coprocesses are established by mytt(coproc); mytt(|&) behaves like
         csh.  Handling of coprocess file descriptors is also different.
-    it()  In mytt(cmd1 && cmd2 &), only mytt(cmd2) instead of the whole
-        expression is run in the background in zsh.  The manual implies
-        this is a bug.  Use mytt({ cmd1 && cmd2 } &) as a workaround.
+    it()  In mytt(cmd1 && cmd2 &), instead of backgrounding the whole
+        expression, only mytt(cmd2) is run in the background in zsh.
+        Use mytt(( cmd1 && cmd2 ) &) as a workaround.
   )
   it() Command line substitutions, globbing etc.:
   itemization(
@@ -960,6 +967,106 @@ label(28)
   languages and adjusting it accordingly, just like you would
   when translating a book from American English to British English.
 
+sect(What is a mytt(namespace) anyway?)
+label(29)
+
+  As of this writing, namespaces in zsh are little more than syntactic
+  sugar for grouping related parameters.  For example, as of the update
+  to PCRE2, the parameters ${.pcre.match} and ${.pcre.subject} are used
+  for regular expression substring capture.  The mytt(.pcre.) part is
+  the namespace, and when you refer to a parameter that has one, you
+  mybf(must) use the mytt(${...}) braces around the name.  Assignments
+  are not special, they have the form mytt(.nspace.var=value) as usual.
+
+  Parameters using a namespace have the additional property that, like
+  file names beginning with a dot for globbing, they're hidden from
+  mytt(typeset) output unless explicitly asked for.
+
+  Namespaces appear in releases after but not including zsh 5.9.
+
+sect(What about named references?)
+label(210)
+
+  Named references are a bit like aliases, but for parameters.  A named
+  reference would typically be usable in the same cases as ${(P)name}
+  (see link(3.22)(322)).  The value of a named reference is the name
+  of another parameter, and when you expand or assign to the named
+  reference, that other parameter is expanded or assigned instead.
+  Thus a trivial example is
+  verb(
+    % target=RING
+    % typeset -n ref=target
+    % print $ref
+    RING
+    % ref=BULLSEYE
+    % print $target
+    BULLSEYE
+  )
+
+  One exception to this behavior is when a named reference is used as
+  the loop variable in a mytt(for) loop.  In that case the reference is
+  unset and reset on each iteration of the loop.
+  verb(
+    % target=RING bullseye=SPOT other=MISS
+    % typeset -n ref=other
+    % for ref in target bullseye; do
+    > print $ref
+    > ref=HIT:$ref
+    > done
+    RING
+    SPOT
+    % print $other
+    MISS
+    % print $ref
+    HIT:SPOT
+  )
+
+  Named references may be used in zsh versions later than 5.9.
+
+sect(What is zsh's support for non-forking command substitution?)
+label(211)
+
+  This is for cases where you'd write mytt($(command)) but you don't want
+  the overhead or other issues associated with forking a subshell.
+  There are 3 variations:
+  enumeration(
+  myeit() Borrowed from mksh
+   verb(
+     ${| code }
+   )
+   Runs code in the current shell context and then substitutes mytt(${REPLY}).
+
+  myeit() An extension to #1
+   verb(
+     ${|var| code }
+   )
+   Runs code in the current shell and then substitutes mytt(${var}).
+
+  myeit() The traditional ksh form, except that the closing mytt(;)
+   may usually be omitted:
+   verb(
+     ${ code }
+   )
+   Runs code in the current shell and substitutes its standard output.
+   (this is done with a temporary file ala mytt($(<=( code ))) but
+   without the fork implied by mytt(=(...))).
+  )
+
+  In all three forms mytt(code) behaves myem(similarly) to an anonymous
+  function invoked like:
+  verb(
+    () { local REPLY; code } "$@"
+  )
+  Thus, mytt($REPLY) is implicitly local and returns to its previous
+  value after the substitution ends, all other parameters declared from
+  inside the substitution are also local by default, and positional
+  parameters mytt($1), mytt($2), etc. are those of the calling context.
+
+  The most significant limitation is that braces (mytt({) and mytt(}))
+  within the substitutions must either be in balanced pairs, or must be
+  quoted, that is, included in a quoted string or prefixed by backslash.
+  These substitutions first become usable after zsh 5.9.
+
 chapter(How to get various things to work)
 
 sect(Why does mytt($var) where mytt(var="foo bar") not do what I expect?)
@@ -1641,6 +1748,7 @@ label(321)
   manual.
 
 sect(How do I get a variable's value to be evaluated as another variable?)
+label(322)
 
   The problem is that you have a variable tt($E) containing the string
   mytt(EDITOR), and a variable tt($EDITOR) containing the string mytt(emacs),
@@ -2509,14 +2617,11 @@ sect(What's on the wish-list?)
      characters.  Initial support for this appeared in version 4.3;
      it is reasonably complete in the line editor but patchy elsewhere
      (note this may require the configuration option --enable-multibyte).
-  it() The parameter code could do with tidying up, maybe with more of the
-     features made available in ksh93.
+  it() The parameter code could do with tidying up.
   it() Configuration files to enable zsh startup files to be created
      with the Dotfile Generator.
   it() Further improvements in integrating the line editor with shell
      functions.
-  it() POSIX compatibility could be improved.
-  it() Option for glob qualifiers to follow perl syntax (a traditional item).
   )
 
 sect(Did zsh have problems in the year 2000?)
@@ -2618,11 +2723,12 @@ https://github.com/chrisbra/vim_faq/blob/de424bd8e08bcf0e6b1e0563ee49514dfed926a
 
 nsect(Acknowledgments:)
 
-Thanks to zsh-list, in particular Bart Schaefer, for suggestions
+Thanks to zsh-workers, in particular Bart Schaefer, for suggestions
 regarding this document.  Zsh has been in the hands of archivists Jim
 Mattson, Bas de Bakker, Richard Coleman, Zoltan Hidvegi and Andrew
-Main, and the mailing list has been run by Peter Gray, Rick Ohnemus,
-Richard Coleman, Karsten Thygesen and Geoff Wing, all of whom deserve
+Main, and the mailing lists have been managed or hosted by Peter Gray,
+Rick Ohnemus, Richard Coleman, Karsten Thygesen, Geoff Wing, Phil
+Pennock, Daniel Shahaf, and Oliver Kiddle, all of whom deserve
 thanks.  The world is eternally in the debt of Paul Falstad for inventing
 zsh in the first place (though the wizzo extended completion is by Sven
 Wischnowsky).
@@ -2630,15 +2736,15 @@ Wischnowsky).
 nsect(Copyright Information:)
 
 This document is copyright (C) P.W. Stephenson, 1995, 1996, 1997,
-1998, 1999, 2000, 2012, 2020. This text originates in the U.K. and the author
-asserts his moral rights under the Copyrights, Designs and Patents Act,
-1988.
+1998, 1999, 2000, 2012, 2020, 2023. This text originates in the U.K.
+and the author asserts his moral rights under the Copyrights, Designs
+and Patents Act, 1988.
 
 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 documentation for any purpose, provided that the above copyright
 notice appears in all copies of this documentation.  Remember,
-however, that this document changes monthly and it may be more useful
+however, this document changes occasionally and it may be more useful
 to provide a pointer to it rather than the entire text.  A suitable
 pointer is "information on the Z-shell can be obtained on the World
 Wide Web at URL https://zsh.sourceforge.io/".

^ permalink raw reply	[relevance 3%]

* Suggested changes to Etc/FAQ
@ 2023-11-11  5:10  3% Bart Schaefer
    0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2023-11-11  5:10 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 507 bytes --]

I wrote most of this up in response to someone's off-list question and
thought it worth throwing in.  PWS, feel free to move it out of
chapter 2 if it would go better elsewhere ... I didn't want to mess up
numbering and cross-references by attempting to add a whole new
chapter.

Also made some (but probably not all that are needed) edits to bring a
few answers and acknowledgements up to date.  I'm not sure after 28
years that I still deserve special mention for making suggestions, but
left that alone.

[-- Attachment #2: EtcFAQ.txt --]
[-- Type: text/plain, Size: 8400 bytes --]

diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 8c795685a..759bdb4a1 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -445,7 +445,14 @@ label(21)
      invoked with the appropriate name.  Including the command
      `emulate sh; setopt localoptions' in a shell function will
      turn on sh emulation for that function only.  In version 4 (and in
-     3.0.6 through 8), this can be abbreviated as `emulate -L sh'.
+     3.0.6 through 8), this can be abbreviated as `emulate -L sh';
+  myeit() in versions after 5.9, the myem(namespace) syntax and
+     myem(named references) (ksh mytt(nameref)) are available, but
+     differ in some details from the ksh93+ semantics;
+  myeit() also after 5.9, myem(non-forking command substitutions) are
+     available.  These are described by ksh as myem(a brace group preceded
+     by a dollar sign) (mytt(${ list;})), but zsh has both some added
+     features adopted from mksh, and some limitations, see link(2.11)(211)
    )
 
   The classic difference is word splitting, discussed in question \
@@ -497,8 +504,9 @@ tt(RM_STAR_SILENT),
     it()  Coprocesses are established by mytt(coproc); mytt(|&) behaves like
         csh.  Handling of coprocess file descriptors is also different.
     it()  In mytt(cmd1 && cmd2 &), only mytt(cmd2) instead of the whole
-        expression is run in the background in zsh.  The manual implies
-        this is a bug.  Use mytt({ cmd1 && cmd2 } &) as a workaround.
+        expression is run in the background in zsh.  In versions beginning
+	with 5.9, the whole expression is backgrounded during sh emulation.
+	Use mytt({ cmd1 && cmd2 } &) as a workaround in zsh native mode.
   )
   it() Command line substitutions, globbing etc.:
   itemization(
@@ -960,6 +968,101 @@ label(28)
   languages and adjusting it accordingly, just like you would
   when translating a book from American English to British English.
 
+sect(What is a mytt(namespace) anyway?)
+label(29)
+
+  As of this writing, namespaces in zsh are little more than syntactic
+  sugar for grouping related parameters.  For example, as of the update
+  to PCRE2, the parameters ${.pcre.match} and ${.pcre.subject} are used
+  for regular expression substring capture.  The mytt(.pcre.) part is
+  the namespace, and when you refer to a parameter that has one, you
+  mybf(must) use the mytt(${...}) braces around the name.  Assignments
+  are not special, they have the form mytt(.nspace.var=value) as usual.
+
+  Parameters using a namespace have the additional property that, like
+  file names beginning with a dot for globbing, they're hidden from
+  mytt(typeset) output unless explicitly asked for.
+
+sect(What about named references?)
+label(210)
+
+  Named references are a bit like aliases, but for parameters.  A named
+  reference would typically be usable in the same cases as ${(P)name}
+  (see link(3.22)(322)).  The value of a named reference is the name
+  of another parameter, and when you expand or assign to the named
+  reference, that other parameter is expanded or assigned instead.
+  Thus a trivial example is
+  verb(
+    % target=RING
+    % typeset -n ref=target
+    % print $ref
+    RING
+    % ref=BULLSEYE
+    % print $target
+    BULLSEYE
+  )
+
+  One exception to this behavior is when a named reference is used as
+  the loop variable in a mytt(for) loop.  In that case the reference is
+  unset and reset on each iteration of the loop.
+  verb(
+    % target=RING bullseye=SPOT other=MISS
+    % typeset -n ref=other
+    % for ref in target bullseye; do
+    > print $ref
+    > ref=HIT:$ref
+    > done
+    RING
+    SPOT
+    % print $other
+    MISS
+    % print $ref
+    HIT:SPOT
+  )
+
+sect(What is zsh's support for non-forking command substitution?)
+label(211)
+
+  This is for cases where you'd write mytt($(command)) but you don't want
+  the overhead or other issues associated with forking a subshell.
+  There are 3 variations:
+  enumeration(
+  myeit() Borrowed from mksh
+   verb(
+     ${| code }
+   )
+   Runs code in the current shell context and then substitutes mytt(${REPLY}).
+
+  myeit() An extension to #1
+   verb(
+     ${|var| code }
+   )
+   Runs code in the current shell and then substitutes mytt(${var}).
+
+  myeit() The traditional ksh form, except that the closing mytt(;)
+   may usually be omitted:
+   verb(
+     ${ code }
+   )
+   Runs code in the current shell and substitutes its standard output.
+   (this is done with a temporary file ala mytt($(<=( code ))) but
+   without the fork implied by mytt(=(...))).
+  )
+
+  In all three forms mytt(code) behaves myem(similarly) to an anonymous
+  function invoked like:
+  verb(
+    () { local REPLY; code } "$@"
+  )
+  Thus, mytt($REPLY) is implicitly local and returns to its previous
+  value after the substitution ends, all other parameters declared from
+  inside the substitution are also local by default, and positional
+  parameters mytt($1), mytt($2), etc. are those of the calling context.
+
+  The most significant limitation is that braces (mytt({) and mytt(}))
+  within the substitutions must either be in balanced pairs, or must be
+  quoted, that is, included in a quoted string or prefixed by backslash.
+
 chapter(How to get various things to work)
 
 sect(Why does mytt($var) where mytt(var="foo bar") not do what I expect?)
@@ -1641,6 +1744,7 @@ label(321)
   manual.
 
 sect(How do I get a variable's value to be evaluated as another variable?)
+label(322)
 
   The problem is that you have a variable tt($E) containing the string
   mytt(EDITOR), and a variable tt($EDITOR) containing the string mytt(emacs),
@@ -2509,14 +2613,11 @@ sect(What's on the wish-list?)
      characters.  Initial support for this appeared in version 4.3;
      it is reasonably complete in the line editor but patchy elsewhere
      (note this may require the configuration option --enable-multibyte).
-  it() The parameter code could do with tidying up, maybe with more of the
-     features made available in ksh93.
+  it() The parameter code could do with tidying up.
   it() Configuration files to enable zsh startup files to be created
      with the Dotfile Generator.
   it() Further improvements in integrating the line editor with shell
      functions.
-  it() POSIX compatibility could be improved.
-  it() Option for glob qualifiers to follow perl syntax (a traditional item).
   )
 
 sect(Did zsh have problems in the year 2000?)
@@ -2618,11 +2719,12 @@ https://github.com/chrisbra/vim_faq/blob/de424bd8e08bcf0e6b1e0563ee49514dfed926a
 
 nsect(Acknowledgments:)
 
-Thanks to zsh-list, in particular Bart Schaefer, for suggestions
+Thanks to zsh-workers, in particular Bart Schaefer, for suggestions
 regarding this document.  Zsh has been in the hands of archivists Jim
 Mattson, Bas de Bakker, Richard Coleman, Zoltan Hidvegi and Andrew
-Main, and the mailing list has been run by Peter Gray, Rick Ohnemus,
-Richard Coleman, Karsten Thygesen and Geoff Wing, all of whom deserve
+Main, and the mailing lists have been managed or hosted by Peter Gray,
+Rick Ohnemus, Richard Coleman, Karsten Thygesen, Geoff Wing, Phil
+Pennock, Daniel Shahaf, and Oliver Kiddle, all of whom deserve
 thanks.  The world is eternally in the debt of Paul Falstad for inventing
 zsh in the first place (though the wizzo extended completion is by Sven
 Wischnowsky).
@@ -2630,15 +2732,15 @@ Wischnowsky).
 nsect(Copyright Information:)
 
 This document is copyright (C) P.W. Stephenson, 1995, 1996, 1997,
-1998, 1999, 2000, 2012, 2020. This text originates in the U.K. and the author
-asserts his moral rights under the Copyrights, Designs and Patents Act,
-1988.
+1998, 1999, 2000, 2012, 2020, 2023. This text originates in the U.K.
+and the author asserts his moral rights under the Copyrights, Designs
+and Patents Act, 1988.
 
 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 documentation for any purpose, provided that the above copyright
 notice appears in all copies of this documentation.  Remember,
-however, that this document changes monthly and it may be more useful
+however, this document changes occasionally and it may be more useful
 to provide a pointer to it rather than the entire text.  A suitable
 pointer is "information on the Z-shell can be obtained on the World
 Wide Web at URL https://zsh.sourceforge.io/".

^ permalink raw reply	[relevance 3%]

* [PATCH] README, NEWS, BUGS updates
@ 2023-10-15 21:54  9% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2023-10-15 21:54 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 60 bytes --]

Bringing these up to date with current significant updates.

[-- Attachment #2: Etc-5_9+.txt --]
[-- Type: text/plain, Size: 3929 bytes --]

diff --git a/Etc/BUGS b/Etc/BUGS
index 1719946b1..e238c161c 100644
--- a/Etc/BUGS
+++ b/Etc/BUGS
@@ -46,12 +46,12 @@ related, probably obsolete, vared special case for $TERM set to "emacs".
 ------------------------------------------------------------------------
 47561: [PATCH v4] vcs_info: choose backend by basedir
 ------------------------------------------------------------------------
-48091: Bug in compdescribe with matcher 'b:-=+'
+48091, 49276: Bug in compdescribe with matcher 'b:-=+'
 ------------------------------------------------------------------------
 users/26071: Strange behavior about option completion of "git push --f"
 ------------------------------------------------------------------------
 50930: If a conditional expression appears in a current-shell construct
 (such as { sleep 20 && print $? }) which is then suspended with ^Z, the
-return value of the left side of the expression is always 148 (SIGSTOP)
+return value of the left side of the expression is always 148 (SIGTSTP)
 and thus the expression is likely to be incorrectly interpreted.
 ------------------------------------------------------------------------
diff --git a/NEWS b/NEWS
index 0e726699f..80b668a6d 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,15 @@ consistent and better aligned with the POSIX-2017 specification of
 `set -e`. For details on what exactly changed, see the list of
 incompatibilities in the README file.
 
+Support for named references and namespaces has been added, similar to
+those features in ksh but with some notable differences. The `nameref`
+builtin and some ksh-equivlent namespace names are available by loading
+the zsh/ksh93 module.  See the documentation of that module for more.
+
+Non-forking command substitutions with ${ ... } and ${| ... } are now
+available, and the latter extended with ${|param| ... } to return the
+result via assignment to the named param rather than always via $REPLY.
+
 Changes since 5.8.1
 -------------------
 
diff --git a/README b/README
index cb6d380aa..250b1d26e 100644
--- a/README
+++ b/README
@@ -79,6 +79,42 @@ consistent and better aligned with the POSIX-2017 specification of
       f() { { false; echo "This is printed only since 5.10." } || true }
       if f; then true; fi
 
+PCRE support is now PCRE2 by default.
+
+Parameter names may begin with a "." and follow a relaxed implementation
+of ksh namespace syntax.  Expansion of such parameters must use braces,
+that is, in ${.param.name} form.  Parameters so named are excluded from
+`typeset` and `set` output unless explicitly listed in `typeset` arguments
+or matched by a pattern with `typeset -m`.
+
+Interpretation of exclusion-patterns following alternation-patterns has
+been rationalised.  This means for example that `[[ ab = (|a*)~^(*b) ]]`
+is true where prevously it was false.
+
+Improvements to handling of terminal colors and attributes in prompts
+may change the behavior of some prompt sequences, most notably in
+cases where `esq=${(%)...}` is used to capture an escape sequence.
+
+The `which` and `functions` commands output function definitions in a
+format independent of the MULTI_FUNC_DEF option.
+
+Math context no longer interprets a leading underscore as part of a
+numeric constant.
+
+Nul and characters greater than \x77 are correctly handled by `read -d`.
+
+Return values of `sysopen` from the zsh/system module have been updated
+to be more similar to other commands in that module.
+
+The `watch' parameter and `log' command have moved to an autoloaded module.
+
+Tied parameters created with the zsh/db/gdbm module may not be re-tied
+as locals in nested function scope.  This prevents database corruption
+when a function scope ends.
+
+Many Completion/ functions have been updated to recent versions of their
+corresponding commands, so the results offered may have changed.
+
 Incompatibilities between 5.8.1 and 5.9
 ---------------------------------------
 

^ permalink raw reply	[relevance 9%]

* Re: $watch, log and Cyrillic usernames
  2023-10-07  2:05  2% ` Oliver Kiddle
@ 2023-10-07 16:49  0%   ` Максим
  0 siblings, 0 replies; 200+ results
From: Максим @ 2023-10-07 16:49 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 4633 bytes --]

Found out that there is no need in bypassing "adduser", as this command
works just fine:

% adduser --allow-all-names --home /root --shell /usr/bin/zsh Плохой

So it is actually possible to create user with unicode username in a
correct way (at least on Linux).


Now about the patch:

% watch=(all); log
    root has logged on /proc/10045/fd/2 from .
    Студент has logged on pts/29 from 127.0.0.1.

% watch=(notme); log # Broken
    root has logged on /proc/10045/fd/2 from .
    Студент has logged on pts/29 from 127.0.0.1.

% watch=(Студент); log
    Студент has logged on pts/29 from 127.0.0.1.


Also tested "too long" username:

% echo ${#USERNAME}
    33

% watch=(all); log
    root has logged on /proc/10045/fd/2 from .
    oooooooooooooooooooooooooooooooo has logged on pts/29 from 127.0.0.1.

% watch=(notme); log
    root has logged on /proc/10045/fd/2 from .

% watch=(${(l:33::o:):-}); log

% watch=(${(l:32::o:):-}); log
    oooooooooooooooooooooooooooooooo has logged on pts/29 from .


And no, Cygwin usernames are case-sensitive.

Sent via Gmail

сб, 7 окт. 2023 г., 05:05 Oliver Kiddle <opk@zsh.org>:

> Максим wrote:
> > Hello again. I found another bug with cyrillic usernames in zsh (again on
> > Cygwin, but can be reproduced on Linux)
>
> Reproducing does involve bypassing utilities like useradd which complain
> about invalid usernames. But I can imagine such rules will increasingly
> be relaxed and there's no reason for zsh to make assumptions.
>
> > % watch=(Студент); log # ("Студент" record is missing)
>
> The value from $watch is metafied and that's what patcompile() and
> pattry() need so the fix below uses metafy() on the username from
> utmp.
>
> However, in looking closer at the code I observed the existing use of
> sizeof(u->ut_name) which is 32 on my system. So I tried creating 32 and
> 33 character usernames (which, incidentally, useradd was happy with) and
> as I suspected u->ut_name is not null-terminated for these. So the patch
> uses strnlen() with the sizeof() for n to get the length to pass
> to metafy(). We have no existing uses of strnlen() but I don't foresee
> portability issues given that it is attributed to the 2008 POSIX
> standard and is supported in Solaris 10 which is from a few years prior
> to that. If needed, it'd be easy to provide an alternative
> implementation.
>
> To match the 33 character username, it does need to be truncated in
> $watch. last -w does manage to print the full username, would be good
> to know how. For the hostname, our code was using strlen() rather than
> sizeof(). I can't see why this would be needed. I would have tried
> putting UTF-8 in my hosts file to test that that but I'm only getting IP
> addresses in utmp. I guess we could do reverse lookups but it hardly
> seems worth it for the amount of use watch/log likely get these days.
>
> The example also uses an uppercase letter. Usernames on Unix are
> case-sensitive but it wouldn't surprise me if they aren't on Cygwin.
> If so, should we add #ifdefs for that?
>
> Oliver
>
> diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c
> index 0de8cbf9a..2ad962fb6 100644
> --- a/Src/Modules/watch.c
> +++ b/Src/Modules/watch.c
> @@ -423,20 +423,22 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char
> *fmt, int prnt, int fini)
>  /* See if the watch entry matches */
>
>  static int
> -watchlog_match(char *teststr, char *actual, int len)
> +watchlog_match(char *teststr, char *actual, size_t buflen)
>  {
>      int ret = 0;
>      Patprog pprog;
>      char *str = dupstring(teststr);
> +    int len = strnlen(actual, buflen);
> +    char *user = metafy(actual, len, META_USEHEAP);
>
>      tokenize(str);
>
>      if ((pprog = patcompile(str, PAT_STATIC, 0))) {
>         queue_signals();
> -       if (pattry(pprog, actual))
> +       if (pattry(pprog, user))
>             ret = 1;
>         unqueue_signals();
> -    } else if (!strncmp(actual, teststr, len))
> +    } else if (!strcmp(user, teststr))
>         ret = 1;
>      return ret;
>  }
> @@ -488,7 +490,7 @@ watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w,
> char *fmt)
>                 for (vv = ++v; *vv && *vv != '%'; vv++);
>                 sav = *vv;
>                 *vv = '\0';
> -               if (!watchlog_match(v, u->ut_host, strlen(v)))
> +               if (!watchlog_match(v, u->ut_host, sizeof(u->ut_host)))
>                     bad = 1;
>                 *vv = sav;
>                 v = vv;
>

[-- Attachment #2: Type: text/html, Size: 6666 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: $watch, log and Cyrillic usernames
  @ 2023-10-07  2:05  2% ` Oliver Kiddle
  2023-10-07 16:49  0%   ` Максим
  0 siblings, 1 reply; 200+ results
From: Oliver Kiddle @ 2023-10-07  2:05 UTC (permalink / raw)
  To: Максим; +Cc: zsh-workers

Максим wrote:
> Hello again. I found another bug with cyrillic usernames in zsh (again on
> Cygwin, but can be reproduced on Linux)

Reproducing does involve bypassing utilities like useradd which complain
about invalid usernames. But I can imagine such rules will increasingly
be relaxed and there's no reason for zsh to make assumptions.

> % watch=(Студент); log # ("Студент" record is missing)

The value from $watch is metafied and that's what patcompile() and
pattry() need so the fix below uses metafy() on the username from
utmp.

However, in looking closer at the code I observed the existing use of
sizeof(u->ut_name) which is 32 on my system. So I tried creating 32 and
33 character usernames (which, incidentally, useradd was happy with) and
as I suspected u->ut_name is not null-terminated for these. So the patch
uses strnlen() with the sizeof() for n to get the length to pass
to metafy(). We have no existing uses of strnlen() but I don't foresee
portability issues given that it is attributed to the 2008 POSIX
standard and is supported in Solaris 10 which is from a few years prior
to that. If needed, it'd be easy to provide an alternative
implementation.

To match the 33 character username, it does need to be truncated in
$watch. last -w does manage to print the full username, would be good
to know how. For the hostname, our code was using strlen() rather than
sizeof(). I can't see why this would be needed. I would have tried
putting UTF-8 in my hosts file to test that that but I'm only getting IP
addresses in utmp. I guess we could do reverse lookups but it hardly
seems worth it for the amount of use watch/log likely get these days.

The example also uses an uppercase letter. Usernames on Unix are
case-sensitive but it wouldn't surprise me if they aren't on Cygwin.
If so, should we add #ifdefs for that?

Oliver

diff --git a/Src/Modules/watch.c b/Src/Modules/watch.c
index 0de8cbf9a..2ad962fb6 100644
--- a/Src/Modules/watch.c
+++ b/Src/Modules/watch.c
@@ -423,20 +423,22 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
 /* See if the watch entry matches */
 
 static int
-watchlog_match(char *teststr, char *actual, int len)
+watchlog_match(char *teststr, char *actual, size_t buflen)
 {
     int ret = 0;
     Patprog pprog;
     char *str = dupstring(teststr);
+    int len = strnlen(actual, buflen);
+    char *user = metafy(actual, len, META_USEHEAP);
 
     tokenize(str);
 
     if ((pprog = patcompile(str, PAT_STATIC, 0))) {
 	queue_signals();
-	if (pattry(pprog, actual))
+	if (pattry(pprog, user))
 	    ret = 1;
 	unqueue_signals();
-    } else if (!strncmp(actual, teststr, len))
+    } else if (!strcmp(user, teststr))
 	ret = 1;
     return ret;
 }
@@ -488,7 +490,7 @@ watchlog(int inout, WATCH_STRUCT_UTMP *u, char **w, char *fmt)
 		for (vv = ++v; *vv && *vv != '%'; vv++);
 		sav = *vv;
 		*vv = '\0';
-		if (!watchlog_match(v, u->ut_host, strlen(v)))
+		if (!watchlog_match(v, u->ut_host, sizeof(u->ut_host)))
 		    bad = 1;
 		*vv = sav;
 		v = vv;


^ permalink raw reply	[relevance 2%]

* [PATCH] 52027: whitelist capability CAP_WAKE_ALARM in 'privasserted' function
  @ 2023-08-14 18:39  5% ` Robert Woods
  0 siblings, 0 replies; 200+ results
From: Robert Woods @ 2023-08-14 18:39 UTC (permalink / raw)
  To: zsh-workers

This patch is a follow up of this issue: https://zsh.org/workers/52027

Since the systemd update v254 from July 28, 2023, the capability
'CAP_WAKE_ALARM' is passed by default to some user process (especially
desktop managers). Since 'CAP_WAKE_ALARM' is very narrow in focus, it
is preferable that zsh does not consider it as a 'privileged'
capability.

For context, in the release note of systemd v254 the following is
written in the Section "Security Relevant Changes"[1]:
> pam_systemd will now by default pass the CAP_WAKE_ALARM ambient
> process capability to invoked session processes of regular users on
> local seats (as well as to systemd --user), unless configured
> otherwise [...]. This is useful in order allow desktop tools such as
> GNOME's Alarm Clock application to set a timer for
> LOCK_REALTIME_ALARM that wakes up the system when it elapses. [...].
> Note that this capability is relatively narrow in focus (in
> particular compared to other process capabilities such as
> CAP_SYS_ADMIN) and we already — by default — permit more impactful
> operations such as system suspend to local users.

[1] https://github.com/systemd/systemd/releases/tag/v254

Signed-off-by: Robert Woods <141646993+RobieWoods@users.noreply.github.com>

---
 Src/utils.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Src/utils.c b/Src/utils.c
index 94a33453f..7040d0954 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -7551,9 +7551,9 @@ privasserted(void)
 	    /* POSIX doesn't define a way to test whether a capability set *
 	     * is empty or not.  Typical.  I hope this is conforming...    */
 	    cap_flag_value_t val;
-	    cap_value_t n;
-	    for(n = 0; !cap_get_flag(caps, n, CAP_EFFECTIVE, &val); n++)
-		if(val) {
+	    cap_value_t cap;
+	    for(cap = 0; !cap_get_flag(caps, cap, CAP_EFFECTIVE, &val); cap++)
+		if(val && cap != CAP_WAKE_ALARM) {
 		    cap_free(caps);
 		    return 1;
 		}
-- 
2.41.0



^ permalink raw reply	[relevance 5%]

* [PATCH] Add option like tcsh's dextract
@ 2023-07-18  9:54  4% Tim Eliseo
  0 siblings, 0 replies; 200+ results
From: Tim Eliseo @ 2023-07-18  9:54 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 1491 bytes --]

Hi all!

This is my first post to the group. I’d been using tcsh as an 
interactive shell since way back when it was still cool, before zsh or 
bash even existed. Zsh is the first shell that’s a worthy successor. One 
of the small things that kept me from jumping to bash (along with 
everyone else in the Linux world) is that it doesn’t have a proper 
implementation of asynchronous notify of job completion (-b), which zsh 
does. Another thing that bugged me about bash was that there is no clean 
way to emulate tcsh’s dextract option, which rearranges the pushd stack 
differently. I eventually discovered that zsh can do the basic function 
through the cd/chdir builtin with the auto_pushd option set, but coding 
a pushd replacement function was complicated to get right for all option 
cases (see attached).

However, I found that adding this pushd mode to zsh natively was trivial 
(simply testing for the new option in one place), and I’m still baffled 
why it wasn’t included a long time ago while someone was looking for 
ways to increase compatibility with other shells. The attached patch 
(based on the current master branch) does just that, and I hope you see 
fit to merge it into the codebase. I believe I’ve done all the 
appropriate option handling, documentation, and unit test to make this 
painless. I didn’t write a ChangeLog entry since I wasn’t sure of the 
appropriate format, or how to derive the number. (Is that an SVN 
revision number?)

Tim


[-- Attachment #2: zsh-pushd_extract.patch.txt --]
[-- Type: text/plain, Size: 4905 bytes --]

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 5393cb149..47c15583b 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1459,6 +1459,7 @@ pindex(PUSHD_TO_HOME, use of)
 pindex(PUSHD_MINUS, use of)
 pindex(CDABLE_VARS, use of)
 pindex(PUSHD_SILENT, use of)
+pindex(PUSHD_EXTRACT, use of)
 xitem(tt(pushd) [ tt(-qsLP) ] [ var(arg) ])
 xitem(tt(pushd) [ tt(-qsLP) ] var(old) var(new))
 item(tt(pushd) [ tt(-qsLP) ] {tt(PLUS())|tt(-)}var(n))(
@@ -1473,8 +1474,10 @@ Otherwise, var(arg) is interpreted as it would be by tt(cd).
 The meaning of var(old) and var(new) in the second form is also
 the same as for tt(cd).
 
-The third form of tt(pushd) changes directory by rotating the
-directory list.  An argument of the form `tt(PLUS())var(n)' identifies a stack
+The third form of tt(pushd) changes directory either by rotating the
+directory list (the default), or by extracting an entry from the directory
+list and pushing it on top (when the tt(PUSHD_EXTRACT) option is set).
+An argument of the form `tt(PLUS())var(n)' identifies a stack
 entry by counting from the left of the list shown by the tt(dirs)
 command, starting with zero.  An argument of the form `tt(-)var(n)' counts
 from the right.  If the tt(PUSHD_MINUS) option is set, the meanings
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index cbd3d0f8e..3a3e4b629 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -162,6 +162,18 @@ shells); and any use of a component of tt(CDPATH), including a `tt(.)' but
 excluding an empty component that is otherwise treated as `tt(.)', causes
 the directory to be printed.
 )
+pindex(PUSHD_EXTRACT)
+pindex(NO_PUSHD_EXTRACT)
+pindex(PUSHDEXTRACT)
+pindex(NOPUSHDEXTRACT)
+cindex(directory stack, altering reordering)
+item(tt(PUSHD_EXTRACT))(
+A push using `tt(PLUS())' or `tt(-)' will reorder by moving the specified
+entry to the top, preserving the order of the remainder below (like the
+tt(dextract) option of bf(tcsh)), instead of the default which rotates the
+stack so that the specified entry is on top. This option makes tt(pushd)
+using `tt(PLUS())' or `tt(-)' behave like tt(cd) with tt(AUTO_PUSHD) set.
+)
 pindex(PUSHD_IGNORE_DUPS)
 pindex(NO_PUSHD_IGNORE_DUPS)
 pindex(PUSHDIGNOREDUPS)
diff --git a/NEWS b/NEWS
index 0e726699f..47c063b40 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,9 @@ consistent and better aligned with the POSIX-2017 specification of
 `set -e`. For details on what exactly changed, see the list of
 incompatibilities in the README file.
 
+The option PUSHD_EXTRACT was added to alter how pushd reorders the stack,
+in the same way as the dextract option of tcsh.
+
 Changes since 5.8.1
 -------------------
 
diff --git a/Src/builtin.c b/Src/builtin.c
index 669a47092..3b1705a0f 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1194,7 +1194,7 @@ cd_new_pwd(int func, LinkNode dir, int quiet)
     struct stat st1, st2;
     int dirstacksize;
 
-    if (func == BIN_PUSHD)
+    if (func == BIN_PUSHD && unset(PUSHDEXTRACT))
 	rolllist(dirstack, dir);
     new_pwd = remnode(dirstack, dir);
 
diff --git a/Src/options.c b/Src/options.c
index a994b563e..b0bee7e6d 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -231,6 +231,7 @@ static struct optname optns[] = {
 {{NULL, "promptpercent",      OPT_NONBOURNE},		 PROMPTPERCENT},
 {{NULL, "promptsp",	      OPT_ALL},			 PROMPTSP},
 {{NULL, "promptsubst",	      OPT_BOURNE},		 PROMPTSUBST},
+{{NULL, "pushdextract",       OPT_EMULATE},		 PUSHDEXTRACT},
 {{NULL, "pushdignoredups",    OPT_EMULATE},		 PUSHDIGNOREDUPS},
 {{NULL, "pushdminus",	      OPT_EMULATE},		 PUSHDMINUS},
 {{NULL, "pushdsilent",	      0},			 PUSHDSILENT},
diff --git a/Src/zsh.h b/Src/zsh.h
index a0243e98e..85bd97fba 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2508,6 +2508,7 @@ enum {
     PROMPTPERCENT,
     PROMPTSP,
     PROMPTSUBST,
+    PUSHDEXTRACT,
     PUSHDIGNOREDUPS,
     PUSHDMINUS,
     PUSHDSILENT,
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 533e08773..89860c78f 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -938,6 +938,25 @@
 >waaah
 >`echo waaah`
 
+  mkdir newpd
+  cd $mydir
+  pushd $mydir/tmpcd
+  pushd $mydir/newpd
+  dirs
+  pushd +1
+  dirs
+  setopt pushdextract
+  pushd +1
+  dirs
+  unsetopt pushdextract
+  popd >/dev/null
+  popd >/dev/null
+  cd $mydir
+0q:PUSHD_EXTRACT option
+>$mydirt/newpd $mydirt/tmpcd $mydirt
+>$mydirt/tmpcd $mydirt $mydirt/newpd
+>$mydirt $mydirt/tmpcd $mydirt/newpd
+
   dirs
   pushd $mydir/tmpcd
   dirs
@@ -1459,7 +1478,7 @@ F:If this test fails at the first unsetopt, refer to P01privileged.ztst.
   fi
   BEL=$'\a'
 0q:RM_STAR_SILENT
-*>zsh: sure you want to delete all 15 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
+*>zsh: sure you want to delete all 16 files in ${PWD:h}/options.tmp \[yn\]\? ${BEL}(|n)
 *>zsh: sure you want to delete (all <->|more than <->) files in / \[yn\]\? ${BEL}(|n)
 
   () {

[-- Attachment #3: pushd_extract.zsh --]
[-- Type: text/plain, Size: 1528 bytes --]

# In zsh, emulate the behavior of pushd with tcsh's dextract option
# Version 1.0, written by Timothy R. Eliseo

# Don't need the function def if native option exists
if ! setopt pushd_extract 2> /dev/null; then
    pushd() {
	setopt local_options extended_glob auto_pushd cd_silent
	zmodload zsh/parameter      # Need $dirstack[]

	# Gather any option flags, duplicating builtin behavior of only recognizing
	# certain options, and only before non-option arguments.
	local -a opts
	while [[ $# -gt 0 && $1 == -[qsLP]## ]]; do
	    opts+=("$1")
	    [[ $1 != *q* ]] || setopt pushd_silent
	    shift
	done

	# The chdir/cd builtin, with one argument in [+|-]n form and with
	# the auto_pushd option set, has the desired stack extract behavior,
	# instead of pushd's stack rotation. For better error output, we also
	# check if the index is in the range that would have different behavior than
	# pushd. This range check is the same regardless of +/- because pushing
	# either the first or last entry has the same result with extraction or
	# rotation.
	if [[ $# -eq 1 && ! -o posix_cd &&
	  $1 == [+-][0-9]## && $1 -ne 0 && ${1:1} -lt ${#dirstack[@]} ]]; then
	    # Use chdir to pushd with extract. cd_silent suppresses its normal
	    # output, and then we execute dirs, as pushd would, if appropriate.
	    builtin chdir "${opts[@]}" "$@" && { [[ ! -o interactive ||
	      -o pushd_silent ]] || builtin dirs; }
	else        # Otherwise just execute pushd with original args
	    builtin pushd "${opts[@]}" "$@"
	fi
    }
fi

^ permalink raw reply	[relevance 4%]

* Re: PATCH: migrate pcre module to pcre2
  @ 2023-06-19  8:20  4%   ` Jun T
  0 siblings, 0 replies; 200+ results
From: Jun T @ 2023-06-19  8:20 UTC (permalink / raw)
  To: zsh-workers


> 2023/06/13 16:35, I wrote
> 
> Or is it better to set enable_pcre=no in configure.ac
> if pcre2-config is not available?

I think this is better. Availability of pcre2-config
need not be checked in two places.
Moreover, currently, pcre2-config is called at configure.ac:956
even if it doesn't exist.

PCRECONF is renamed PCRE_CONFIG. User can override PCRE_CONFIG as
./configure --enable-pcre PCRE_CONFIG=/path/to/pcre2-conf
if pcre2-config is not in PATH.

oldcflags is removed because it is not used anywhere.


diff --git a/Src/Modules/pcre.mdd b/Src/Modules/pcre.mdd
index 6eb3c691b..3e1579117 100644
--- a/Src/Modules/pcre.mdd
+++ b/Src/Modules/pcre.mdd
@@ -1,5 +1,5 @@
 name=zsh/pcre
-link=`if test x$enable_pcre = xyes && (pcre-config --version >/dev/null 2>/dev/null); then echo dynamic; else echo no; fi`
+link=`if test x$enable_pcre = xyes; then echo dynamic; else echo no; fi`
 load=no
 
 autofeatures="b:pcre_compile b:pcre_study b:pcre_match"
diff --git a/configure.ac b/configure.ac
index ba76f9a60..c5263035e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -440,6 +440,17 @@ dnl Do you want to look for pcre support?
 AC_ARG_ENABLE(pcre,
 AS_HELP_STRING([--enable-pcre],[enable the search for the pcre2 library (may create run-time library dependencies)]))
 
+AC_ARG_VAR(PCRE_CONFIG, [pathname of pcre2-config if it is not in PATH])
+if test "x$enable_pcre" = xyes; then
+  AC_CHECK_PROG([PCRE_CONFIG], pcre2-config, pcre2-config)
+  if test "x$PCRE_CONFIG" = x; then
+    enable_pcre=no
+    AC_MSG_WARN([pcre2-config not found: pcre module is disabled.])
+    AC_MSG_NOTICE(
+      [Set PCRE_CONFIG to pathname of pcre2-config if it is not in PATH.])
+  fi
+fi
+
 dnl Do you want to look for capability support?
 AC_ARG_ENABLE(cap,
 AS_HELP_STRING([--enable-cap],[enable the search for POSIX capabilities (may require additional headers to be added by hand)]))
@@ -655,15 +666,12 @@ AC_HEADER_DIRENT
 AC_HEADER_STAT
 AC_HEADER_SYS_WAIT
 
-oldcflags="$CFLAGS"
-if test x$enable_pcre = xyes; then
-AC_CHECK_PROG([PCRECONF], pcre2-config, pcre2-config)
 dnl pcre2-config --cflags may produce a -I output which needs to go into
 dnl CPPFLAGS else configure's preprocessor tests don't pick it up,
 dnl producing a warning.
-if test "x$ac_cv_prog_PCRECONF" = xpcre2-config; then
-  CPPFLAGS="$CPPFLAGS `pcre2-config --cflags`"
-fi
+if test "x$enable_pcre" = xyes; then
+  CPPFLAGS="`$PCRE_CONFIG --cflags` $CPPFLAGS"
+  AC_CHECK_HEADERS([pcre2.h],,,[#define PCRE2_CODE_UNIT_WIDTH 8])
 fi
 
 AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
@@ -675,7 +683,6 @@ AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
 		 netinet/in_systm.h langinfo.h wchar.h stddef.h \
 		 sys/stropts.h iconv.h ncurses.h ncursesw/ncurses.h \
 		 ncurses/ncurses.h)
-AC_CHECK_HEADERS([pcre2.h],,,[#define PCRE2_CODE_UNIT_WIDTH 8])
 if test x$dynamic = xyes; then
   AC_CHECK_HEADERS(dlfcn.h)
   AC_CHECK_HEADERS(dl.h)
@@ -952,10 +959,6 @@ if test "x$ac_found_iconv" = "xyes"; then
     [Define as const if the declaration of iconv() needs const.])
 fi
 
-if test x$enable_pcre = xyes; then
-  LIBS="`$ac_cv_prog_PCRECONF --libs8` $LIBS"
-fi
-
 dnl ---------------------
 dnl CHECK TERMCAP LIBRARY
 dnl ---------------------
@@ -1316,7 +1319,6 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
 	       pathconf sysconf \
 	       tgetent tigetflag tigetnum tigetstr setupterm initscr resize_term \
 	       getcchar setcchar waddwstr wget_wch win_wch use_default_colors \
-	       pcre2_compile_8 \
 	       nl_langinfo \
 	       erand48 open_memstream \
 	       posix_openpt \
@@ -1371,6 +1373,11 @@ if test x$zsh_cv_func_realpath_accepts_null = xyes; then
   AC_DEFINE(REALPATH_ACCEPTS_NULL)
 fi
 
+if test x$enable_pcre = xyes; then
+  LIBS="`$PCRE_CONFIG --libs8` $LIBS"
+  AC_CHECK_FUNCS(pcre2_compile_8)
+fi
+
 if test x$enable_cap = xyes; then
   AC_CHECK_FUNCS(cap_get_proc)
 fi




^ permalink raw reply	[relevance 4%]

* Re: [Bug] modules zsh/tcp, zsh/zftp unloadable, probably affecting most modern Linuxes
  @ 2023-06-06 17:54  3%                   ` Mikael Magnusson
  0 siblings, 0 replies; 200+ results
From: Mikael Magnusson @ 2023-06-06 17:54 UTC (permalink / raw)
  To: Philippe Troin; +Cc: zsh-workers

On 6/6/23, Philippe Troin <phil@fifi.org> wrote:
> On Tue, 2023-06-06 at 16:01 +0100, Peter Stephenson wrote:
>> > On 06/06/2023 15:38 Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>> >
>> >
>> > > 2023/06/06 18:05, Peter Stephenson <p.w.stephenson@ntlworld.com>
>> > > wrote:
>> > >
>> > > > On 06/06/2023 07:42 Jun T <takimoto-j@kba.biglobe.ne.jp> wrote:
>> > > >
>> > > > Why '-z now' is used when building binary packages? For
>> > > > security?
>> > >
>> > > I think this is just so that failure to find symbols at all will
>> > > show up quickly in the build rather than at run time, which would
>> > > be a real pain.
>> >
>> > I think '-z now' is to mark (add the flag) zftp.so so that the
>> > dynamic linker resolves all the symbols when _loading_ it;
>> > the symbols are not resolved when _building_ zftp.so.
>>
>> Yes, it does say it gets applied at the point of dlopen(), so it's
>> explicitly counteracting RTLD_LAZY.
>>
>> Is this specific to the Fedora configuration in their own source
>> package?  I don't see an obvious sign the standard zsh build itself
>> is making this choice.  configure has some system-specific tweaks
>> for dynamic loading, but not this.
>
> "-z now" is automatically added to all builds by the hardening
> configuration on RedHat/Fedora and possibly derived distributions:
>
>    % ag -- -Wl.*now /usr/lib/rpm/
>    /usr/lib/rpm/macros.d/macros.rust
>    46:  -Clink-arg=-Wl,-z,now
>
>    /usr/lib/rpm/redhat/macros
>    302:%_hardening_ldflags	 -Wl,-z,now %[ "%{toolchain}" == "gcc" ?
> "-specs=/usr/lib/rpm/redhat/redhat-hardened-ld" : "" ]

The zftp module's setup_ function is:
int
setup_(UNUSED(Module m))
{
    return (require_module("zsh/net/tcp", NULL, 0) == 1);
}

So the module providing the "missing" symbol will always be loaded
before any functions in zftp using it will be called, and there will
not be any failed symbol resolutions at runtime, which we indicate by
the RTLD_LAZY flag to dlopen().

The glibc manpage says
       RTLD_LAZY   Perform  lazy binding.  Resolve symbols only as the
code that references them
 is executed.  If the symbol is never referenced, then it is  never  resolved.

The posix manpage does not agree with the glibc manpage and says
       RTLD_LAZY   Relocations shall be performed at an
implementation-defined time,  ranging  from  the  time of the dlopen()
call until the first reference to a given symbol occurs.

Ie, it allows the behavior in Fedora.

I guess it would probably not be very hard to make this work on both
setups. Another workaround you (or the packager) could do in the
meantime is to statically link the tcp module.

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 3%]

* Re: [Bug] modules zsh/tcp, zsh/zftp unloadable, probably affecting most modern Linuxes
  2023-06-04 13:51  4% [Bug] modules zsh/tcp, zsh/zftp unloadable, probably affecting most modern Linuxes Marcus Müller
@ 2023-06-04 20:37  0% ` Marcus Müller
    0 siblings, 1 reply; 200+ results
From: Marcus Müller @ 2023-06-04 20:37 UTC (permalink / raw)
  To: zsh-workers

Bit more debugging: Doesn't work with Fedora 30 / glibc 2.29, does work with OpenSUSE leap 
15.2 / glibc 2.26.

For that reason I must assume the regression must have appeared between release 2.26 in 
August 2017 and release 2.29 in Februrary 2019.

On 04.06.23 15:51, Marcus Müller wrote:
> Dear ZSH community,
>
> I just opened a Fedora bug[1], since I suspected this to a configuration-vs-facts 
> mistake in the build, but it turns out that this happens on debian, too, and that I can 
> see in the source code that the offending function is actually used – which should have 
> made linkage fail, but it only does so at dynamic runtime linking.
>
> Don't really know how to go from there – someone would have to rework name resolution to 
> use getaddrinfo/freeaddrinfo (which is POSIX) instead of getipnodebyname/freehostent 
> (which isn't POSIX).
>
> I see that this already happened, in 2007, in commit 
> a5187bb6ac96cc43f68367c5dc9332854c250713, "23670: use getaddrinfo() and getnameinfo() 
> instead of get*by* functions.", but was promptly reverted 30 minutes later without 
> explanation. Maybe it's time to revisit that? Maybe it's also just a sign that the code 
> hasn't been used by anyone in roughly forever, and deserves to be not built on the 
> platforms it doesn't support, or removed altogether.
>
> Bug description:
>
> when running `zmodload zsh/zftp`, it fails due to missing symbol `freehostent`. This is 
> worrisome, because a) that's a broken feature, and b) `freehostent` shouldn't be used on 
> glibc systems (far as I can tell) – `man freehostent` tells us that the function is 
> *not* present in glibc and deprecated.
>
> Steps to Reproduce:
> 1. clean F37 or F38 or debian stable installation
> 2. `sudo dnf --refresh install -y zsh`
> 3. `zsh`
> 4. in zsh: `zmodload zsh/zftp`
>
> Actual Results:
> zsh: failed to load module `zsh/zftp': /usr/lib64/zsh/5.9/zsh/zftp.so: undefined symbol: 
> freehostent
>
> Expected Results:
> loading of module
>
> Best regards,
> Marcus Müller
>
>
> [1] https://bugzilla.redhat.com/show_bug.cgi?id=2212160
>


^ permalink raw reply	[relevance 0%]

* [Bug] modules zsh/tcp, zsh/zftp unloadable, probably affecting most modern Linuxes
@ 2023-06-04 13:51  4% Marcus Müller
  2023-06-04 20:37  0% ` Marcus Müller
  0 siblings, 1 reply; 200+ results
From: Marcus Müller @ 2023-06-04 13:51 UTC (permalink / raw)
  To: zsh-workers

Dear ZSH community,

I just opened a Fedora bug[1], since I suspected this to a configuration-vs-facts mistake 
in the build, but it turns out that this happens on debian, too, and that I can see in the 
source code that the offending function is actually used – which should have made linkage 
fail, but it only does so at dynamic runtime linking.

Don't really know how to go from there – someone would have to rework name resolution to 
use getaddrinfo/freeaddrinfo (which is POSIX) instead of getipnodebyname/freehostent 
(which isn't POSIX).

I see that this already happened, in 2007, in commit 
a5187bb6ac96cc43f68367c5dc9332854c250713, "23670: use getaddrinfo() and getnameinfo() 
instead of get*by* functions.", but was promptly reverted 30 minutes later without 
explanation. Maybe it's time to revisit that? Maybe it's also just a sign that the code 
hasn't been used by anyone in roughly forever, and deserves to be not built on the 
platforms it doesn't support, or removed altogether.

Bug description:

when running `zmodload zsh/zftp`, it fails due to missing symbol `freehostent`. This is 
worrisome, because a) that's a broken feature, and b) `freehostent` shouldn't be used on 
glibc systems (far as I can tell) – `man freehostent` tells us that the function is *not* 
present in glibc and deprecated.

Steps to Reproduce:
1. clean F37 or F38 or debian stable installation
2. `sudo dnf --refresh install -y zsh`
3. `zsh`
4. in zsh: `zmodload zsh/zftp`

Actual Results:
zsh: failed to load module `zsh/zftp': /usr/lib64/zsh/5.9/zsh/zftp.so: undefined symbol: 
freehostent

Expected Results:
loading of module

Best regards,
Marcus Müller


[1] https://bugzilla.redhat.com/show_bug.cgi?id=2212160



^ permalink raw reply	[relevance 4%]

* Re: PATCH: migrate pcre module to pcre2
  2023-05-12 23:12  3% ` PATCH: migrate pcre module to pcre2 Phil Pennock
@ 2023-05-24 18:11  0%   ` Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2023-05-24 18:11 UTC (permalink / raw)
  To: Zsh workers

On 12 May, Phil Pennock wrote:
> I handed in my commit bit a while back because I used it so rarely and
> it felt better for commit to be only the people more actively involved.
> Shells and their provenance matter.  So I can't commit.

If I remember correctly, you indicated at the time that it shouldn't be
committed, at least not at that time. We probably have more of a problem
with patches getting missed than having to be backed out later. Trust
and competence don't expire if not used.

> My main motivation with RE2 was to get to something which all vendors
> will actually include when distributing.  The reason can't be licensing,
> since the PCRE lib is BSD licensed.

Do Apple include any of pcre, pcre2 and re2 already with macOS? It's
difficult to guess at their motivations. Zsh's build system linking pcre
into every ELF file by default if you enable pcre may not help. They
must have put some thought into at least their initial packaging of zsh
as they stripped out some of the shell functions.

> I'd seen RE2 pick up quite a bit of steam and wanted to explore to see
> how feasible it was.
>
> Ideally, we'd have a contact within Apple who can tell us what they
> might or might not consider, so that we can have working regexps with
> semantics younger than POSIX.2 (1992) and some more actual utility.  I'm

The one time I had a chance to speak to an actual Apple employee, and
that was someone far removed from the Unix layer, they only reinforced
my general impression that Apple really don't care about the shell and
Unix part of macOS in general. The change of default shell was likely
due to licencing alone. Did Apple at least provide 5.8.1 as a security
patch? RHEL 8 still comes with a vulnerable 5.8 so it would seem that
us doing security only releases is a waste of time.

I generally stick with zsh pattern matching out of habit. =~ seems to be
a popular feature, though, I guess people know and understand regexes.
Does bash ignore the system regex library and use the GNU one on all
systems? That's equivalent to us pulling something like TRE or PCRE into
the zsh source tree and forcing its use.

Oliver


^ permalink raw reply	[relevance 0%]

* Re: PATCH: migrate pcre module to pcre2
    2023-05-06  4:44  3% ` named capture groups with PCRE matching (Was: PATCH: migrate pcre module to pcre2) Stephane Chazelas
@ 2023-05-12 23:12  3% ` Phil Pennock
  2023-05-24 18:11  0%   ` Oliver Kiddle
    2 siblings, 1 reply; 200+ results
From: Phil Pennock @ 2023-05-12 23:12 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh workers

On 2023-05-06 at 01:35 +0200, Oliver Kiddle wrote:
> The old PCRE library that zsh uses is considered "end of life, and is no
> longer being actively maintained". The newer PCRE2 has a slighty
> different interface. It has been around since 2015 so this is not new.
> Actual version numbers are 8.x and 10.x rather than 1 and 2. Migrating
> seems to be the sensible way forward rather than, for example, adding a
> separate zsh/pcre2 module. That way, zsh users don't need to be
> concerned with the change.

Before anything else, this is great to see, thank you.

> Would it perhaps be useful to add support for PCRE2's alternative DFA
> algorithm? This might meet the needs Phil was considering with the re2
> based module he once posted but never committed. What form might that
> take?

I handed in my commit bit a while back because I used it so rarely and
it felt better for commit to be only the people more actively involved.
Shells and their provenance matter.  So I can't commit.

My main motivation with RE2 was to get to something which all vendors
will actually include when distributing.  The reason can't be licensing,
since the PCRE lib is BSD licensed.

I'd seen RE2 pick up quite a bit of steam and wanted to explore to see
how feasible it was.

Ideally, we'd have a contact within Apple who can tell us what they
might or might not consider, so that we can have working regexps with
semantics younger than POSIX.2 (1992) and some more actual utility.  I'm
tired of dealing with regexps being so sub-par 30 years later.  Trying
to write tools which work both for people using macOS and people using
Linux today pretty much means "write a client in Go".  Which is fine,
but sometimes a scripted solution is desirable.

I wrote the zsh/regex module because folks felt that we needed to match
Bash's semantics and use ERE by default when I added the  =~  syntactic
sugar.  I still see the benefit of that, but wonder if not doing so
would have led to a better net outcome, as distributors would have had
to enable a modern RE engine to get =~ working ... or would it have just
left =~ not working on random platforms.

-Phil


^ permalink raw reply	[relevance 3%]

* named capture groups with PCRE matching (Was: PATCH: migrate pcre module to pcre2)
  @ 2023-05-06  4:44  3% ` Stephane Chazelas
  2023-05-12 23:12  3% ` PATCH: migrate pcre module to pcre2 Phil Pennock
    2 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2023-05-06  4:44 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh workers

2023-05-06 01:35:46 +0200, Oliver Kiddle:
[...]
> When looking at PCRE documentation for this, other ideas for extensions
> I saw would be to support:
> 
>  * named capture groups
>    (either to an associative array or to variables directly?)
[...]

I was thinking about that when answering
https://unix.stackexchange.com/questions/742664/bash-posix-regex-optional-groups/742680#742680
recently.

Maybe we could do:

typeset -A match
if [[ aa =~ '(?<foo>.)(?<bar>)' ]]
  print -r -- $match[foo] $match[bar]

That is if $match is an associative array, store the named
capture groups there. Same for pcre_match -a array (or add a -A
assoc there)

There's the question of $mbegin / $mend. Should all three
$match, $mbegin and $mend be automatically converted to assoc if
any of them is an assoc?

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* RE: Re: ksh compatibility: initial value of $_
  2023-04-05  1:03  3%           ` Oliver Kiddle
@ 2023-04-05  8:15  0%             ` zeurkous
  0 siblings, 0 replies; 200+ results
From: zeurkous @ 2023-04-05  8:15 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh-workers, Jun. T

Haai,

On Wed, 05 Apr 2023 03:03:35 +0200, Oliver Kiddle <opk@zsh.org> wrote:
> "Jun. T" wrote:
> Given that you're ignoring the output, test -L is likely more portable
> in this case. Specifically it would work on Solaris 10 which doesn't
> have readlink (but does have /proc/self/path/a.out). test -L is covered
> by the POSIX standard while readlink isn't.

FWIW, OpenBSD test(1) says--

     -\b-L\bL _\bf_\bi_\bl_\be
             True if _\bf_\bi_\bl_\be exists and is a symbolic link.  This operator is for
             compatibility purposes.  Do not rely on its existence; use -\b-h\bh
             instead.

Note that last part. Is "-L" actually more standard? (Even on other
*cough* Unices, me's always used "-h").

There's also stat(1), but that appears to be even less standard than
readlink(1).

> Oliver

        --zeurkous.

-- 
Friggin' Machines!


^ permalink raw reply	[relevance 0%]

* Re: ksh compatibility: initial value of $_
  @ 2023-04-05  1:03  3%           ` Oliver Kiddle
  2023-04-05  8:15  0%             ` zeurkous
  0 siblings, 1 reply; 200+ results
From: Oliver Kiddle @ 2023-04-05  1:03 UTC (permalink / raw)
  To: Jun. T; +Cc: zsh-workers

"Jun. T" wrote:
> diff --git a/configure.ac b/configure.ac
> index e6ced85d9..d33ea6945 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -1,4 +1,4 @@
> -dnl
> +dnexe

Is that part of the patch intentional?

> +[for zsh_cv_proc_self_exe in /proc/self/exe /proc/curproc/exe \
> +                             /proc/curproc/file /proc/self/path/a.out no; do
> +   readlink $zsh_cv_proc_self_exe >/dev/null && break

Given that you're ignoring the output, test -L is likely more portable
in this case. Specifically it would work on Solaris 10 which doesn't
have readlink (but does have /proc/self/path/a.out). test -L is covered
by the POSIX standard while readlink isn't.

Oliver


^ permalink raw reply	[relevance 3%]

* Re: ksh compatibility: initial value of $_
  @ 2023-03-31 17:45  3%       ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2023-03-31 17:45 UTC (permalink / raw)
  To: Jun. T; +Cc: zsh-workers

On Fri, Mar 31, 2023 at 7:32 AM Jun. T <takimoto-j@kba.biglobe.ne.jp> wrote:
>
>     _    Initially,  the value of _ is an absolute pathname of the
>          shell or script being executed as passed in the environment.
>
> So zsh can just do the same thing?
> With the following patch, zsh behaves similarly with ksh?

With your patch:

% /bin/sh
$ Src/zsh -fc 'print $_'
/bin/sh
$ Src/zsh -fc 'echo $_'
print $_
$

Similar behavior from ksh, so it really is whatever happens to be in
the environment for '_' rather than an actual pathname.  This means
you only get the documented behavior when a new shell or script was
invoked via a previous shell that exports $_ appropriately (which
evidently zsh already does, though I can't immediately find the code).

% typeset -p _
typeset _=_
% printenv _
/bin/printenv
%

There's nothing in POSIX (that I can find) specifying any behavior of $_ at all.

One other notable difference (which I think has been mentioned before)
is demonstrated thus:

ksh93:
$ for _ in a b c; do echo $_; done
a
b
c
$ for _ in a b c; do echo X; echo $_; done
X
a
X
b
X
c
$

zsh (even with ARGV0=ksh):
% for _ in a b c; do echo $_; done

echo
echo
% for _ in a b c; do echo X; echo $_; done
X
X
X
X
X
X
%

So ... ksh assigns $_ only after each full complex command, and does
not otherwise treat it as special, whereas zsh assigns it after every
pipeline (and also after the "do" keyword, it seems) and cannot use it
as a normal parameter in between.  (This can be partly worked around
in a function body by using "local -h _" but then all special behavior
is lost.)

Incidentally, as far as I can tell from a quick bit of research, if
you want to compare zsh and ksh behavior it is not advisable to
install "ksh2020" (which is unfortunately the default "ksh" for Ubuntu
at least as of 20.04).  Explicitly install "ksh93" instead if you have
that option.


^ permalink raw reply	[relevance 3%]

* [PATCH 1/1] Update nm options
  @ 2023-03-20  2:16 21% ` Shohei YOSHIDA
  0 siblings, 0 replies; 200+ results
From: Shohei YOSHIDA @ 2023-03-20  2:16 UTC (permalink / raw)
  To: zsh-workers; +Cc: Shohei YOSHIDA

- Update Binutils nm 2.40.0
- Update elftoolchain nm 0.7.1

---
 Completion/Unix/Command/_nm | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 888f1ef87..b142c1d54 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -17,7 +17,6 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
     '(- *)'{-V,--version}'[display version information]'
     '(-f --format -P --portability)-B[same as --format=bsd]'
     '(-u --undefined-only)--defined-only[display only defined symbols]'
-    '(-f --format -P)--format=[specify output format]:format:(bsd sysv posix)'
     '(-n --numeric-sort -p --no-sort --size-sort -v)'{-n,--numeric-sort}'[sort symbols numerically by address]'
     '(-p --no-sort -n -v --numeric-sort -r --reverse-sort --size-sort)'{-p,--no-sort}'[do not sort symbols]'
     '(-P --portability -B -f --format)'{-P,--portability}'[same as --format=posix]'
@@ -41,7 +40,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
       args=( ${args:#*(-C|-o|--portability)\[*}
 	'(-C --demangle)'{-C,--demangle=-}'[decode symbol names]::style:(auto gnu-v2 gnu-v3 arm)'
 	'(-g --extern-only)-e[only display global and static symbols]'
-	'(--format -P)-F+[specify output format]:format:(bsd sysv posix)'
+	'(-B --format -P)'{-F,--format}'[specify output format]:format:(bsd sysv posix)'
 	'-o[with -P, same as -t o; otherwise same as -A]'
 	'(-t --radix)-x[print values in hexadecimal]'
       )
@@ -51,7 +50,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
         '--mark-special[mark special symbols]'
 	'--color=[use color in output]:color:(always auto never)'
 	'(-C)--demangle[decode symbol names]'
-	'(--format -P)-f+[specify output format]:format:(bsd sysv posix)'
+	'(-B -f --format -P --portability)'{-f,--format}'[specify output format]:format:(bsd sysv posix)'
 	'(- *)--usage[give a short usage message]'
 	'(- *)-?[display help information]'
       )
@@ -61,14 +60,19 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
       args+=(
         '!(--no-recurse-limit)--recurse-limit'
         '--no-recurse-limit[disable demangling recursion limit]'
-	'(-f --format -P)-f+[specify output format]:format:(bsd sysv posix)'
+	'(-f --format -P -j)'{-f,--format}'[specify output format]:format:(bsd sysv posix just-symbols)'
 	'(-C --no-demangle)--demangle=-[decode symbol names]::style [auto]:(auto gnu lucid arm hp edg gnu-v3 java gnat rust dlang)'
         '--ifunc-chars=[specify characters to use for indirect function symbols]:characters for global/local indirect function symbols [ii]'
+	'(-B -f --format -P --portability -j --just-symbols)'{-j,--just-symbols}'[Same as --format=just-symbols]'
 	'--plugin[load specified plugin]:plugin'
+	'--quiet[suppress no "no symbols" diagnostic]'
 	'--special-syms[include special symbols in the output]'
 	'--synthetic[display synthetic symbols as well]'
 	"--target=[target object format]:target:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
+	'--unicode=[specify how to treat UTF-8 encoded unicode characters]:how_to_treat:(default show invalid hex escape highlight)'
+	'(-W --no-weak)'{-W,--no-weak}'[ignore weak symbols]'
 	'--with-symbol-versions[display version strings after symbol names]'
+	'--without-symbol-versions[not display of symbol version information]'
       )
     ;;
   esac
-- 
2.37.2



^ permalink raw reply	[relevance 21%]

* Re: bug report : printf %.1s outputting more than 1 character
  2023-03-15  3:46  3%   ` Bart Schaefer
@ 2023-03-15  4:56  1%     ` Jason C. Kwan
  0 siblings, 0 replies; 200+ results
From: Jason C. Kwan @ 2023-03-15  4:56 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 7381 bytes --]

 quote :
============This triggers a branch of the printf code introduced by this comment:
    /*
    * Invalid/incomplete character at this
    * point.  Assume all the rest are a
    * single byte.  That's about the best we
    * can do.
    */============

does the following ( below the "====" line ) behavior look even reasonable at all, regardless of your spec ? Because what the spec ends up doing is treating the rest of the input string as 1 byte and printing everything out, even though there are valid code points further down the input string. 
The behavior is correct when LC_ALL=C is set, meaning zsh already has the codes needed to generate the correct output. My point was that instead of treating the rest of the input string, regardless of size, as 1 byte/character, why not have it behave "as if" LC_ALL=C is in effect whenever it enters this branch :
if (chars < 0) {/* * Invalid/incomplete character at this * point.  Assume all the rest are a * single byte.  That's about the best we * can do. */lchars += lleft;lbytes = (ptr - b) + lleft;break;
and continue in this mode until a locale-valid character is found, then revert back to multi-byte behavior ? wouldn't that be a more logical behavior ?
If that's too complex to implement, then perhaps treat rest of input string as a collection of individual bytes instead of just 1 byte ?
I just find printf '%.3s' outputting a 179 KB string rather odd.
=========================
 zsh --restricted --no-rcs --nologin --verbose -xtrace -f -c '___=$'\''=\343\276\255#\377\210\234\256A\301B\354\210\264_'\''; command printf "%s" "$___" | gwc -lcm; for __ in {1..16}; do builtin printf "%.${__}s" "$___" | gwc -lcm; done '___=$'=\343\276\255#\377\210\234\256A\301B\354\210\264_'; command printf "%s" "$___" | gwc -lcm; for __ in {1..16}; do builtin printf "%.${__}s" "$___" | gwc -lcm; done+zsh:1> ___=$'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> printf %s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=1+zsh:1> printf %.1s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       1       1+zsh:1> __=2+zsh:1> printf %.2s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       2       4+zsh:1> __=3+zsh:1> printf %.3s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       3       5+zsh:1> __=4+zsh:1> printf %.4s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=5+zsh:1> printf %.5s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=6+zsh:1> printf %.6s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=7+zsh:1> printf %.7s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=8+zsh:1> printf %.8s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=9+zsh:1> printf %.9s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=10+zsh:1> printf %.10s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=11+zsh:1> printf %.11s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=12+zsh:1> printf %.12s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=13+zsh:1> printf %.13s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=14+zsh:1> printf %.14s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=15+zsh:1> printf %.15s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=16+zsh:1> printf %.16s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16
+zsh:1> ___=$'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> LC_ALL=C printf %s $'=㾭#\M-\C-?\M-\C-H\M-\C-\\M-.A\M-AB숴_'+zsh:1> gwc -lcm      0       7      16+zsh:1> __=1+zsh:1> LC_ALL=C +zsh:1> printf %.1s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       1       1+zsh:1> __=2+zsh:1> LC_ALL=C +zsh:1> printf %.2s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       1       2+zsh:1> __=3+zsh:1> LC_ALL=C +zsh:1> printf %.3s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       1       3+zsh:1> __=4+zsh:1> LC_ALL=C +zsh:1> printf %.4s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       2       4+zsh:1> __=5+zsh:1> LC_ALL=C +zsh:1> printf %.5s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       3       5+zsh:1> __=6+zsh:1> LC_ALL=C +zsh:1> printf %.6s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       3       6+zsh:1> __=7+zsh:1> LC_ALL=C +zsh:1> printf %.7s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       3       7+zsh:1> __=8+zsh:1> LC_ALL=C +zsh:1> printf %.8s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       3       8+zsh:1> __=9+zsh:1> LC_ALL=C +zsh:1> printf %.9s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       3       9+zsh:1> __=10+zsh:1> LC_ALL=C +zsh:1> printf %.10s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       4      10+zsh:1> __=11+zsh:1> LC_ALL=C +zsh:1> printf %.11s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       4      11+zsh:1> __=12+zsh:1> LC_ALL=C +zsh:1> printf %.12s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       5      12+zsh:1> __=13+zsh:1> LC_ALL=C +zsh:1> printf %.13s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       5      13+zsh:1> __=14+zsh:1> LC_ALL=C +zsh:1> printf %.14s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       5      14+zsh:1> __=15+zsh:1> LC_ALL=C +zsh:1> printf %.15s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       6      15+zsh:1> __=16+zsh:1> LC_ALL=C +zsh:1> printf %.16s '=㾭#????A?B숴_'+zsh:1> gwc -lcm      0       7      16



    On Tuesday, March 14, 2023 at 11:46:14 PM EDT, Bart Schaefer <schaefer@brasslantern.com> wrote:  
 
 On Tue, Mar 14, 2023 at 7:40 PM Jason C. Kwan <jasonckwan@yahoo.com> wrote:
>
> I'm using the macOS 13.2.1 OS-provided zsh, version 5.8.1, which I understand isn't the latest and greatest of 5.9, so perhaps this bug has already been addressed.

A related case been addressed by declaring it an intentional
divergence from POSIX, see
https://www.zsh.org/mla/workers/2022/msg00240.html

However ...

> In the 4-byte sequence as seen below ( defined via explicit octal codes ), under no Unicode scenario should 4 bytes be printed out via a command of printf %.1s, by design.
>
>  - The first byte of \377 \xFF is explicitly invalid under UTF-8 (even allowing up to 7-byte in the oldest of definitions).

This triggers a branch of the printf code introduced by this comment:
    /*
    * Invalid/incomplete character at this
    * point.  Assume all the rest are a
    * single byte.  That's about the best we
    * can do.
    */

Thus, you've deliberately invoked a case where zsh's response to
invalid input is to punt.  This dates back to the original
implementation in workers/23098,
https://www.zsh.org/mla/workers/2007/msg00019.html, January 2007.
  

[-- Attachment #2: Type: text/html, Size: 26365 bytes --]

^ permalink raw reply	[relevance 1%]

* Re: bug report : printf %.1s outputting more than 1 character
  2023-03-15  2:38  2% ` bug report : printf %.1s outputting more than 1 character Jason C. Kwan
@ 2023-03-15  3:46  3%   ` Bart Schaefer
  2023-03-15  4:56  1%     ` Jason C. Kwan
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2023-03-15  3:46 UTC (permalink / raw)
  To: Jason C. Kwan; +Cc: zsh-workers

On Tue, Mar 14, 2023 at 7:40 PM Jason C. Kwan <jasonckwan@yahoo.com> wrote:
>
> I'm using the macOS 13.2.1 OS-provided zsh, version 5.8.1, which I understand isn't the latest and greatest of 5.9, so perhaps this bug has already been addressed.

A related case been addressed by declaring it an intentional
divergence from POSIX, see
https://www.zsh.org/mla/workers/2022/msg00240.html

However ...

> In the 4-byte sequence as seen below ( defined via explicit octal codes ), under no Unicode scenario should 4 bytes be printed out via a command of printf %.1s, by design.
>
>  - The first byte of \377 \xFF is explicitly invalid under UTF-8 (even allowing up to 7-byte in the oldest of definitions).

This triggers a branch of the printf code introduced by this comment:
    /*
     * Invalid/incomplete character at this
     * point.  Assume all the rest are a
     * single byte.  That's about the best we
     * can do.
     */

Thus, you've deliberately invoked a case where zsh's response to
invalid input is to punt.  This dates back to the original
implementation in workers/23098,
https://www.zsh.org/mla/workers/2007/msg00019.html, January 2007.


^ permalink raw reply	[relevance 3%]

* bug report : printf %.1s outputting more than 1 character
       [not found]     <1621619253.265114.1678847919086.ref@mail.yahoo.com>
@ 2023-03-15  2:38  2% ` Jason C. Kwan
  2023-03-15  3:46  3%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Jason C. Kwan @ 2023-03-15  2:38 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3346 bytes --]

I'm using the macOS 13.2.1 OS-provided zsh, version 5.8.1, which I understand isn't the latest and greatest of 5.9, so perhaps this bug has already been addressed.
In the 4-byte sequence as seen below ( defined via explicit octal codes ), under no Unicode scenario should 4 bytes be printed out via a command of printf %.1s, by design. 
 - The first byte of \377 \xFF is explicitly invalid under UTF-8 (even allowing up to 7-byte in the oldest of definitions).  - The 4-byte value is too large to constitute a single character under either endian of UTF-32.  - It's also not a pair of beyond-BMP UTF-16 surrogates either, regardless of endian
At best, if treated as UTF-16, of either endian, this 4-byte sequence represents 2 code points, in which case, only 2 bytes should be printed not 4.

My high-level understanding of printf %.1s is that it should output the first locale-valid character of the input string, and in its absence, output the first byte instead, if any, so setting LC_ALL=C or POSIX would defeat the purpose of this bug report.
The reproducible sample shell command below includes what the output from zsh built-in printf looks like, what the macOS built-in printf looks like, and what the gnu printf looks like, all else being equal. The testing shell was invoked via
invoked via
    zsh --restricted --no-rcs --nologin --verbose -xtrace -f -c
In all 3 test scenarios, LC_ALL is explicitly cleared, while LANG is explicitly set to a widely used one. 
The od used is the macOS one, not the gnu one.
To my best knowledge, the other printfs have produced the correct output.
Thanks for your time.
====================================================================
echo; echo "$ZSH_VERSION"; echo; uname -a; echo; LC_ALL= LANG="en_US.UTF-8" builtin printf '\n\n\t[%.1s]\n\n' $'\377\210\234\256' | od -bacx ;  echo; LC_ALL= LANG="en_US.UTF-8" command printf '\n\n\t[%.1s]\n\n' $'\377\210\234\256' | od -bacx ;  echo; LC_ALL= LANG="en_US.UTF-8" gprintf '\n\n\t[%.1s]\n\n' $'\377\210\234\256' | od -bacx ;  echo;+zsh:1> echo
+zsh:1> echo 5.8.15.8.1+zsh:1> echo
+zsh:1> uname -aDarwin m1mx4CT 22.3.0 Darwin Kernel Version 22.3.0: Mon Jan 30 20:38:37 PST 2023; root:xnu-8792.81.3~2/RELEASE_ARM64_T6000 arm64+zsh:1> echo
+zsh:1> LC_ALL='' LANG=en_US.UTF-8 +zsh:1> printf '\n\n\t[%.1s]\n\n' $'\M-\C-?\M-\C-H\M-\C-\\M-.'+zsh:1> od -bacx0000000   012 012 011 133 377 210 234 256 135 012 012          nl  nl  ht   [   ?  88  9c   ?   ]  nl  nl          \n  \n  \t   [ 377 210 234 256   ]  \n  \n             0a0a    5b09    88ff    ae9c    0a5d    000a0000013+zsh:1> echo
+zsh:1> LC_ALL='' LANG=en_US.UTF-8 printf '\n\n\t[%.1s]\n\n' $'\M-\C-?\M-\C-H\M-\C-\\M-.'+zsh:1> od -bacx0000000   012 012 011 133 377 135 012 012          nl  nl  ht   [   ?   ]  nl  nl          \n  \n  \t   [ 377   ]  \n  \n             0a0a    5b09    5dff    0a0a0000010+zsh:1> echo
+zsh:1> LC_ALL='' LANG=en_US.UTF-8 gprintf '\n\n\t[%.1s]\n\n' $'\M-\C-?\M-\C-H\M-\C-\\M-.'+zsh:1> od -bacx0000000   012 012 011 133 377 135 012 012          nl  nl  ht   [   ?   ]  nl  nl          \n  \n  \t   [ 377   ]  \n  \n             0a0a    5b09    5dff    0a0a0000010+zsh:1> echo
zsh 5.8.1 (x86_64-apple-darwin22.0)

[-- Attachment #2: Type: text/html, Size: 10769 bytes --]

^ permalink raw reply	[relevance 2%]

* Re: PATCH: move $ERRNO to the system module
  @ 2023-01-16 21:34  3%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2023-01-16 21:34 UTC (permalink / raw)
  To: zsh-workers

On Thu, Jan 12, 2023 at 9:15 AM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Does moving $ERRNO from the core to a module "reorder or add system
> calls" to the codepath that expands/evaluates uses of ERRNO?

As far as I can tell system call changes would only occur in
circumstances where the module could not be loaded at all.  On the
other hand, that circumstance also renders ERRNO useless.

> Oliver Kiddle wrote on Wed, 11 Jan 2023 23:19 +00:00:
> > ERRNO predates the system module, and loadable modules in general.

It doesn't just predate the system module, it predates the zsh source
import to git.

> > The trick with defining it as PM_UNSET doesn't
> > appear to work from a module.

Hm, that might be worthy of some further digging.

Aside, is Src/modentry.c present for any reason other than as some
kind of example?  It's been around since at least 2007 (workers/23479,
approximately) but it's not referenced anywhere, not even in
zsh-development-guide.

> Well, it's backwards incompatible and I don't understand the
> justification given, so I can't say I'm +1 on this.

On the one hand, workers/32337 already made a backwards-incompatible
change to ERRNO in the name of POSIX script compatibility, so any
really old scripts that used it will already have needed updating.
Moving it to a module is just another step in that direction, and
actually fixes the "must set before use" issue (obviously by replacing
it with "must load module before use").

On the opposing hand, the existence/use of ERRNO has been recently
discussed on the lists, the change to document the previous
incompatible change is also recent, and there have been other changes
to make the value of ERRNO more correctly reflect actual error states.
So his might not be an ideal time to introduce yet another such
change.

I'm net-zero on this.


^ permalink raw reply	[relevance 3%]

* $var not expanded in ${x?$var}
@ 2023-01-13  8:02  3% Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2023-01-13  8:02 UTC (permalink / raw)
  To: Zsh hackers list

$ zsh -c 'echo ${1?$USERNAME}'
zsh:1: 1: $USERNAME

No quote removal either:

$ zsh -c 'echo ${1?"x"}'
zsh:1: 1: "x"

Doc says:

> In any of the above expressions that test a variable and substitute an
> alternate WORD, note that you can use standard shell quoting in the WORD
> value to selectively override the splitting done by the SH_WORD_SPLIT
> option and the = flag, but not splitting by the s:STRING: flag.

POSIX:

> ${parameter:?[word]}
> Indicate Error if Null or Unset. If parameter is unset or
> null, the *expansion* of word (or a message indicating it is
> unset if word is omitted) shall be written to standard error
> and the shell exits with a non-zero exit status. Otherwise,
> the value of parameter shall be substituted. An interactive
> shell need not exit.

(also note that line number being printed twice)

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: Read a line from user without clearing screen below the prompt while allowing user to use arrow keys to make edits in middle of line
  2022-12-30  5:37  3% Read a line from user without clearing screen below the prompt while allowing user to use arrow keys to make edits in middle of line OG Code Poet
@ 2022-12-30  8:58  0% ` Mikael Magnusson
  0 siblings, 0 replies; 200+ results
From: Mikael Magnusson @ 2022-12-30  8:58 UTC (permalink / raw)
  To: OG Code Poet; +Cc: zsh-workers

On 12/30/22, OG Code Poet <ogcodepoet@gmail.com> wrote:
> Using Bash ``tput cup 0 0; read -e -p "Enter input: " userinput`` works
> well for getting a line of user input:
>
> * It does not clear screen below the prompt
> * It allows user to use arrow keys to go to middle of line and edit a
> mistake they might have made while typing
>
> How can this be achieved in zsh? I have tried two techniques; either it
> clears screen below prompt or it does not allow using arrow to go back to
> middle of line to edit it.
>
> 1. Using ``vared``:
> ```
> tput cup 0 0; userinput=""; vared -p "Enter input: " userinput
> ```
> ``vared`` seems to clear screen below the prompt, so this clears the entire
> screen before showing the prompt.
>
> 2. Using ``read``:
>
> ```
> tput cup 0 0; printf "Enter input: "; read -r userinput
> ```
> This does not clear the screen below the prompt, but does not allow using
> arrow keys to go to middle of the line and make an edit ("delete" key
> works, but is too much to ask users to delete and retype everything from
> the point of typo).
>
> Is there a way out? Perhaps it could be possible to trick vared to believe
> there are no lines below, so it clears just 1 line (the line of prompt). If
> it is not possible in zsh, I am open to an external POSIX way of getting
> user input on first line of the screen.
>
> P.S. Also posted in unix.stackexchange.com:
> https://unix.stackexchange.com/q/730022/456507

Without more context this sounds like a very weird request, surely
printing stuff at 0,0 will just overlap whatever existing text was
there, resulting in a corrupted screen output? Perhaps you will have
better luck switching to the alternate screen while prompting for the
string, and then switching back, in effect giving you the appearance
of a full screen program (more likely to direct the user's attention
to the top of the terminal). (enable with echo -n '\e[?47h' and
disable with echo -n '\e[?47l')

PS
this is probably more of a zsh-users question than zsh-workers

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* Read a line from user without clearing screen below the prompt while allowing user to use arrow keys to make edits in middle of line
@ 2022-12-30  5:37  3% OG Code Poet
  2022-12-30  8:58  0% ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: OG Code Poet @ 2022-12-30  5:37 UTC (permalink / raw)
  To: zsh-workers; +Cc: OG Code Poet

[-- Attachment #1: Type: text/plain, Size: 1323 bytes --]

Using Bash ``tput cup 0 0; read -e -p "Enter input: " userinput`` works
well for getting a line of user input:

* It does not clear screen below the prompt
* It allows user to use arrow keys to go to middle of line and edit a
mistake they might have made while typing

How can this be achieved in zsh? I have tried two techniques; either it
clears screen below prompt or it does not allow using arrow to go back to
middle of line to edit it.

1. Using ``vared``:
```
tput cup 0 0; userinput=""; vared -p "Enter input: " userinput
```
``vared`` seems to clear screen below the prompt, so this clears the entire
screen before showing the prompt.

2. Using ``read``:

```
tput cup 0 0; printf "Enter input: "; read -r userinput
```
This does not clear the screen below the prompt, but does not allow using
arrow keys to go to middle of the line and make an edit ("delete" key
works, but is too much to ask users to delete and retype everything from
the point of typo).

Is there a way out? Perhaps it could be possible to trick vared to believe
there are no lines below, so it clears just 1 line (the line of prompt). If
it is not possible in zsh, I am open to an external POSIX way of getting
user input on first line of the screen.

P.S. Also posted in unix.stackexchange.com:
https://unix.stackexchange.com/q/730022/456507

[-- Attachment #2: Type: text/html, Size: 1671 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: zsh_error_db --- hash-based database of error messages
  2022-12-17 21:33  3% ` Oliver Kiddle
@ 2022-12-19  9:19  0%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2022-12-19  9:19 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh workers

> If we want to address internationalisation, we might come to regret not
> just using the normal POSIX catgets(3) interface and catalogue files.
> What they do looks simple on the surface but there's probably hidden
> areas of complexity that we'd end up duplicating. I can see the value of
> allowing things to be done in shell code but the two are not mutually
> exclusive.

Actually, internationalization was only one possible use.  The idea
was to allow for more descriptive error messages for those who wanted
them.  But if that's not going anywhere this can be ditched.  It was
only a proposal to allow the minimum of work within the shell internals
that seemed it might get something off the ground.
 
> E and a number sounds fine.

It sounds like that, and a script to keep this in order, is the way
this would be heading, if it seems worth pursuing.  The script
should be able to list out the default messages, checked for
duplicates, and check for the next unassigned number.  If
the number appears in a macro, as noted by Daniel, that makes
it easy.  That can use ## to join strings so still doesn't
need a change to the message API.

pws


^ permalink raw reply	[relevance 0%]

* Re: read -d $'\200' doesn't work with set +o multibyte (and [PATCH])
  2022-12-18 10:51  5%             ` Jun. T
@ 2022-12-18 17:58  3%               ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2022-12-18 17:58 UTC (permalink / raw)
  To: Jun. T; +Cc: zsh-workers

2022-12-18 19:51:22 +0900, Jun. T:
[...]
> In the web page Stehane mentioned:
> https://austingroupbugs.net/view.php?id=243#c6091
> 
> "When the current locale is not the C or POSIX locale,
> pathnames can contain bytes that do not form part of a valid
> character, and therefore portable applications need to ensure
> that the current locale is the C or POSIX locale when using
> read with arbitrary pathnames as input."
> 
> But I'm not familiar with this type of documents.
[...]

In the POSIX terminology, "application" identifies users of the
API. So sh/read users/scripts, code that use the "read" utility
here while "implementation" identifies a compliant
implementation of the API supplier, so a sh implementation like
zsh in sh emulation.

Here, it says that applications (scripts) wanting to use "read"
to read a file path into a variable should use:

IFS= LC_ALL=C read -rd '' file

I argued there in comments below
(https://austingroupbugs.net/view.php?id=243#c6093,
https://austingroupbugs.net/view.php?id=243#c6095) that with
IFS= read -d '', read implementations in practice don't seem to
need LC_ALL=C to do the right thing.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: read -d $'\200' doesn't work with set +o multibyte (and [PATCH])
  @ 2022-12-18 10:51  5%             ` Jun. T
  2022-12-18 17:58  3%               ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Jun. T @ 2022-12-18 10:51 UTC (permalink / raw)
  To: zsh-workers


> 2022/12/16 17:29, Oliver Kiddle <opk@zsh.org> wrote:
> 
>>> +  read -ed $'\xc2'
>>> +0:read delimited by a single byte terminates if the byte is part of a multibyte character
>>> +<one£two
>>> +>one
>> 
>> Is this really what the standard requires (or will require)?
>> Breaking in the middle of a valid multibyte character looks
>> rather odd to me.
> 
> The proposed standard wording appears to only talk about the case of the
> delimiter consisting of "one single-byte character". $'\xc2' is not a
> valid UTF-8 character so my interpretation is that they are leaving this
> undefined.

I thought the "one single-byte character" etc. applies only when C or
POSIX locale is in use.

> Behaviour that treats the input as raw bytes for a raw byte delimiter
> is consistent. This retains compatibility with the way things
> work for a non-multibyte locale. Not all files are valid UTF-8 and it
> can be useful to force things to work at a raw byte level.

I was thinking it would be enough if we can do 'byte-by-byte' analysis by
using C/POSIX locale (or by setting MULTIBYTE option to off).

In the web page Stehane mentioned:
https://austingroupbugs.net/view.php?id=243#c6091

"When the current locale is not the C or POSIX locale, pathnames can contain bytes that do not form part of a valid character, and therefore portable applications need to ensure that the current locale is the C or POSIX locale when using read with arbitrary pathnames as input."

But I'm not familiar with this type of documents.



^ permalink raw reply	[relevance 5%]

* Re: zsh_error_db --- hash-based database of error messages
  @ 2022-12-17 21:33  3% ` Oliver Kiddle
  2022-12-19  9:19  0%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Oliver Kiddle @ 2022-12-17 21:33 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh workers

Peter Stephenson wrote:
> Following on from the retread of the discussion on error messages,
> here's a very simply proof of concept for a hash-based database of
> error messages.  Even if it's adopted I don't intend the C code
> to get much larger as the point is to allow it to be able to do
> everything in shell code.
>
> Apart from more user-friendly messages which someone with no
> access to the C code can dedicate their life to tweaking,
> this is obviously a boon for internationalization (which

If we want to address internationalisation, we might come to regret not
just using the normal POSIX catgets(3) interface and catalogue files.
What they do looks simple on the surface but there's probably hidden
areas of complexity that we'd end up duplicating. I can see the value of
allowing things to be done in shell code but the two are not mutually
exclusive.

While error messages encompass the majority of strings that zsh ever
needs to print there are some strings that aren't error messages.

> Apart from updating the error message to examine the hash, the
> only change is to prefix the error message format string with
> the code such as "E3" and a colon.  This would obviously
> be done universally.

E and a number sounds fine. I'm not keen on trying to encode file names
such as ZW for zle_word.c because we may want to move code from one file
to another in the future. If there's a need to divide things up, perhaps
do something like 1000s for history, 2000s for zle, etc like we have for
test cases. Parsing the E-number out of the string may be less flexible
than adding an extra parameter and/or having a macro to wrap it. If
duplicates are a concern scripts can be written to do checking or maybe
some clever use of X macros.

The best example for easy error messages I've come across is the Rust
compiler. This quotes your code with highlighting and colours and
finishes with a message like:
  For more information about this error, try `rustc --explain E0463`.
So there are two levels of detail about an error available.

If the only way to get friendly error explanations is to autoload
functions and enable plugins, the type of users that will benefit from
them will likely not find out about them until they're knowledgeable
enough not to want them. Perhaps prompting with the explain invocation
needs to be enabled by default with a setopt to turn that off. For
people that do turn it off, a special parameter could store the number
of the last error that was printed so that explanations can still be
accessed.

> The signatures of the format strings, i.e. where the % escapes
> live, is checked for, though if there are cases where
> we have more than a single letter code it'll fall over.
> There's no provision for reordering escapes, either, but I
> wouldn't expect to do that in an initial implementation anyway.

Reordering is quite common for internationalisation. Our printf builtin
does handle that with things like %2$s so we already have an
implementation of parsing printf formats but directed at a rather
aifferent purpose.

Oliver


^ permalink raw reply	[relevance 3%]

* Re: ERR_RETURN doc
  2022-12-11  1:24  4%                             ` Bart Schaefer
@ 2022-12-12 23:35  3%                               ` Philippe Altherr
  0 siblings, 0 replies; 200+ results
From: Philippe Altherr @ 2022-12-12 23:35 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Daniel Shahaf, Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 2316 bytes --]

>
> The zsh manual is not rigorously enough written to be treated as a
> "specification" and would become even less readable than Ray already
> accuses it of being if we tried.  I'd prefer to give a summary and
> then reference the POSIX spec for details (but not via URL-link to it;
> URLs tend to get stale).


My proposed doc update covers most points. So much so that I didn't even
feel the need to link to the POSIX doc. So no URL-link problem :-)

Shouldn't docs of ERR_EXIT explicitly mention that «! true» does not
> cause an exit?


This is implicitly covered by my proposed update.

Philippe




On Sun, Dec 11, 2022 at 2:24 AM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> On Sat, Dec 10, 2022 at 6:12 AM Philippe Altherr
> <philippe.altherr@gmail.com> wrote:
> >
> > POSIX' "set -e" specification. That specification is quite a bit longer.
> Should Zsh's specification repeat all of that? Or should it link to it?
>
> The zsh manual is not rigorously enough written to be treated as a
> "specification" and would become even less readable than Ray already
> accuses it of being if we tried.  I'd prefer to give a summary and
> then reference the POSIX spec for details (but not via URL-link to it;
> URLs tend to get stale).
>
> Aside, Martijn Dekker raised a related question back in workers/43874
> -- according to the POSIX chapter on Utilities
> (
> https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_01
> )
> there are a bunch of circumstances where a non-interactive shell is
> required to exit "as if the exit builtin were called".  With ERR_EXIT,
> interactive shells are also required to exit in those circumstances.
> I'm pretty sure, though haven't re-tested, that zsh does not in fact
> exit in some of those (such as a redirection error with a special
> builtin) and in some of the cases where it does exit, it does not run
> the SIGEXIT trap as implied by "as if the exit builtin" (that being
> the actual reason for Martijn's message).
>
> And yes, I used a URL that might become stale, in this message.
> Nobody is ever going to need or to be able to go through the archives
> and fix that, whereas documentation would be expected to be kept up to
> date, a burden I don't wish to impose.
>

[-- Attachment #2: Type: text/html, Size: 3317 bytes --]

^ permalink raw reply	[relevance 3%]

* [PATCH] NEWS and README items about ERR_EXIT and ERR_RETURN changes
@ 2022-12-12 16:06  6% Philippe Altherr
  0 siblings, 0 replies; 200+ results
From: Philippe Altherr @ 2022-12-12 16:06 UTC (permalink / raw)
  To: Zsh hackers list


[-- Attachment #1.1: Type: text/plain, Size: 84 bytes --]

Here is an updated patch to document the ERR_EXIT and ERR_RETURN changes.

Philippe

[-- Attachment #1.2: Type: text/html, Size: 146 bytes --]

[-- Attachment #2: patch-errexit-news-and-readme.txt --]
[-- Type: text/plain, Size: 3022 bytes --]

diff --git a/NEWS b/NEWS
index cdafd1ff5..e3a16a8bc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,14 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
+Changes since 5.9
+-----------------
+
+The ERR_EXIT and ERR_RETURN options were refined to be more self-
+consistent and better aligned with the POSIX-2017 specification of
+`set -e`. For details on what exactly changed, see the list of
+incompatibilities in the README file.
+
 Changes since 5.8.1
 -------------------
 
diff --git a/README b/README
index 21142e17c..cb6d380aa 100644
--- a/README
+++ b/README
@@ -31,8 +31,56 @@ Zsh is a shell with lots of features.  For a list of some of these, see the
 file FEATURES, and for the latest changes see NEWS.  For more
 details, see the documentation.
 
-Incompatibilities since 5.8.1
------------------------------
+Incompatibilities since 5.9
+---------------------------
+
+The ERR_EXIT and ERR_RETURN options were refined to be more self-
+consistent and better aligned with the POSIX-2017 specification of
+`set -e`:
+
+  - Function calls or anonymous functions prefixed with `!` now never
+    trigger exit or return. Negated function calls or anonymous
+    functions used to trigger exit or return if ERR_EXIT or ERR_RETURN
+    was set and the function call or anonymous function returned a
+    zero exit status. Example:
+
+      setopt ERR_EXIT
+      f() { true }
+      ! f
+      echo "This is printed only since 5.10."
+
+  - The `always` command now ignores ERR_EXIT and ERR_RETURN, as other
+    complex commands do, if its exit status comes from a command
+    executed while the option is ignored. Example:
+
+      setopt ERR_EXIT
+      { false && true } always { echo "This was and still is printed." }
+      echo "This is printed only since 5.10."
+
+  - Function calls, anonymous functions, and the `eval`, `.`, and
+    `source` builtins now never ignore ERR_EXIT and ERR_RETURN on
+    their own. These commands used to ignore ERR_EXIT and ERR_RETURN
+    if their result came from a complex command (if, for, ...) whose
+    result came from a command executed while the option is
+    ignored. Example:
+
+      setopt ERR_EXIT
+      f() { if true; then false && true; fi }
+      f
+      echo "This is printed only prior to 5.10."
+
+  - The `&&` and `||` operators now always ignore ERR_RETURN in their
+    left operand. Until this version, the operators failed to ignored
+    ERR_RETURN in their left operand if they were executed as part of
+    a function call or an anonymous function that was itself executed
+    in a context where ERR_RETURN is ignored. Example:
+
+      setopt ERR_RETURN
+      f() { { false; echo "This is printed only since 5.10." } || true }
+      if f; then true; fi
+
+Incompatibilities between 5.8.1 and 5.9
+---------------------------------------
 
 compinit: A "y" response to the "Ignore ... and continue?" prompt removes
 insecure elements from the set of completion functions, where previously

^ permalink raw reply	[relevance 6%]

* Re: xtrace output sets ERRNO to 9 (EBADF)
  @ 2022-12-11 20:01  3%         ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2022-12-11 20:01 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Daniel Shahaf, zsh-workers

2022-12-11 10:52:44 -0800, Bart Schaefer:
[...]
> In any case,
> fileno() doesn't set errno (it's just a data structure deref, would
> only fail by crashing)

Not that it matters much here, but POSIX does say that fileno()
shall  return -1 EBADF if "The stream is not associated with a
file." and may if "The file descriptor underlying stream is not
a valid file descriptor."

https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/fileno.html

musl libc has:

int fileno(FILE *f)
{
        FLOCK(f);
        int fd = f->fd;
        FUNLOCK(f);
        if (fd < 0) {
                errno = EBADF;
                return -1;
        }
        return fd;
}

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: Get cursor position (Was: [bug report] prompt can erase messages written on the terminal by background processes)
  @ 2022-12-11 18:00  3%               ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2022-12-11 18:00 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: zsh-workers, Bart Schaefer

2022-12-09 13:46:21 +0100, Philippe Altherr:
[...]
> assign() {
> >     print -v "$1" "$2"
> > }
[...]

Note that that "assign" function has a command injection
vulnerability.

Even more  so than for other  commands, -- (- also works) should
always be used for "print" to separate options from non-options
at least when the first non-option argument is not guaranteed
not to start with - or +.

Try for instance:

assign var '-va[1$(reboot)]'

So:

assign() print -rv "$1" -- "$2"

Or the Bourne-compatible:

assign() eval "$1=\$2"

Or POSIX:

assign() { eval "$1=\$2"; }

A bit ironic that people often go to great lengths to avoid
using "eval" but end up coming up with unsafe solutions.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] NEWS item about the ERR_EXIT fixes
  2022-12-10 13:49  3%       ` Philippe Altherr
@ 2022-12-11  3:32  3%         ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-12-11  3:32 UTC (permalink / raw)
  To: Philippe Altherr, Daniel Shahaf; +Cc: zsh-workers

On Sat, Dec 10, 2022, at 8:49 AM, Philippe Altherr wrote:

> Afaik, Zsh intends to be compatible with the POSIX "set -e" 
> specification 

On what are you basing this assertion?

> If that is indeed the case, then all the patches can be seen as bug 
> fixes.

I don't agree.  The documentation barely says anything about any
of the behaviors you modified, and zsh is not a POSIX-compatible
shell, so it's entirely reasonable for users to have accepted the
previous behavior as intentional.

> So no Zsh doc changes are required (or at least not because of 
> these patches).

This is only incidentally true.  The documentation omits many details
about ERR_EXIT's special cases, so your changes largely fall between
the lines (so to speak).

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: ERR_RETURN doc
  2022-12-10 14:06  3%                           ` Philippe Altherr
@ 2022-12-11  1:24  4%                             ` Bart Schaefer
  2022-12-12 23:35  3%                               ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-12-11  1:24 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: Daniel Shahaf, Zsh hackers list

On Sat, Dec 10, 2022 at 6:12 AM Philippe Altherr
<philippe.altherr@gmail.com> wrote:
>
> POSIX' "set -e" specification. That specification is quite a bit longer. Should Zsh's specification repeat all of that? Or should it link to it?

The zsh manual is not rigorously enough written to be treated as a
"specification" and would become even less readable than Ray already
accuses it of being if we tried.  I'd prefer to give a summary and
then reference the POSIX spec for details (but not via URL-link to it;
URLs tend to get stale).

Aside, Martijn Dekker raised a related question back in workers/43874
-- according to the POSIX chapter on Utilities
(https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_01)
there are a bunch of circumstances where a non-interactive shell is
required to exit "as if the exit builtin were called".  With ERR_EXIT,
interactive shells are also required to exit in those circumstances.
I'm pretty sure, though haven't re-tested, that zsh does not in fact
exit in some of those (such as a redirection error with a special
builtin) and in some of the cases where it does exit, it does not run
the SIGEXIT trap as implied by "as if the exit builtin" (that being
the actual reason for Martijn's message).

And yes, I used a URL that might become stale, in this message.
Nobody is ever going to need or to be able to go through the archives
and fix that, whereas documentation would be expected to be kept up to
date, a burden I don't wish to impose.


^ permalink raw reply	[relevance 4%]

* Re: ERR_RETURN doc
  2022-12-10 11:33  0%                         ` Daniel Shahaf
@ 2022-12-10 14:06  3%                           ` Philippe Altherr
  2022-12-11  1:24  4%                             ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-12-10 14:06 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 668 bytes --]

>
> Shouldn't docs of ERR_EXIT explicitly mention that «! true» does not
> cause an exit?


Arguably there is much more that is missing. Zsh's ERR_EXIT
<https://zsh.sourceforge.io/Doc/Release/Options.html#index-ERREXIT>
specification
<https://zsh.sourceforge.io/Doc/Release/Options.html#index-ERREXIT> doesn't
even state that ERR_EXIT is disabled in the condition of if/while/etc. Zsh
intends to be compatible with POSIX' "set -e" specification
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>.
That specification is quite a bit longer. Should Zsh's specification
repeat all of that? Or should it link to it?

Philippe

[-- Attachment #2: Type: text/html, Size: 974 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] NEWS item about the ERR_EXIT fixes
  2022-12-10 11:32  0%     ` Daniel Shahaf
@ 2022-12-10 13:49  3%       ` Philippe Altherr
  2022-12-11  3:32  3%         ` Lawrence Velázquez
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-12-10 13:49 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 829 bytes --]

Just a quick reply. I will prepare an updated patch that includes a short
description in NEWS (mainly an updated version of Lawrence's proposal) and
a longer one with examples in README. Once it's ready (probably only
tomorrow), I will check again here whether there are still questions not
yet answered by the updated patch.

Afaik, Zsh intends to be compatible with the POSIX "set -e" specification
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>.
If that is indeed the case, then all the patches can be seen as bug fixes.
So no Zsh doc changes are required (or at least not because of these
patches). The patches also only affect corner cases, which are quite a bit
more complicated than Daniel's examples. None of Daniel's examples are
affected; they all keep behaving the same way.

Philippe

[-- Attachment #2: Type: text/html, Size: 978 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: ERR_RETURN doc
  2022-12-01 19:30  3%                       ` Philippe Altherr
@ 2022-12-10 11:33  0%                         ` Daniel Shahaf
  2022-12-10 14:06  3%                           ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2022-12-10 11:33 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: Zsh hackers list

Philippe Altherr wrote on Thu, Dec 01, 2022 at 20:30:22 +0100:
> Yep, that remains correct. Same for ERR_EXIT.
> 
> Most(/All?) of the patches address cases where the implementation wasn't
> following the specification.
> 

Shouldn't docs of ERR_EXIT explicitly mention that «! true» does not
cause an exit?

> The patch about the always statement makes it behave like compound
> statements. Since the always statement isn't part of POSIX, this could be
> seen either as a bug fix or a spec change (but rather of the always
> statement than of ERR_EXIT).
> 
> Philippe
> 
> 
> On Thu, Dec 1, 2022 at 5:30 PM Bart Schaefer <schaefer@brasslantern.com>
> wrote:
> 
> > On Thu, Dec 1, 2022 at 6:42 AM Philippe Altherr
> > <philippe.altherr@gmail.com> wrote:
> > >
> > > https://zsh.sourceforge.io/Doc/Release/Options.html#index-ERRRETURN.
> >
> > Will that doc remain correct with respect to what it says about
> > ERR_EXIT after recent patches are considered?
> >
> > (Still on my TODO list, have been busier than I expected so far this week.)
> >


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] NEWS item about the ERR_EXIT fixes
  2022-12-09  6:44  5%   ` Lawrence Velázquez
@ 2022-12-10 11:32  0%     ` Daniel Shahaf
  2022-12-10 13:49  3%       ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2022-12-10 11:32 UTC (permalink / raw)
  To: zsh-workers; +Cc: Philippe Altherr

Lawrence Velázquez wrote on Fri, Dec 09, 2022 at 01:44:44 -0500:
> On Thu, Dec 8, 2022, at 7:24 PM, Bart Schaefer wrote:
> > On Thu, Dec 8, 2022 at 1:47 PM Philippe Altherr
> > <philippe.altherr@gmail.com> wrote:
> >>
> >> I couldn't make it shorter than what is in the patch.
> >
> > I think this is fine.  Any opposed?
> 
> I think it's overly verbose; NEWS doesn't have to explain how
> ERR_EXIT works.  Here's a possible alternative:
> 
> diff --git a/NEWS b/NEWS
> index cdafd1ff5..d8b8687c0 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -4,8 +4,27 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
>  
>  Note also the list of incompatibilities in the README file.
>  
> -Changes since 5.8.1
> --------------------
> +Changes since 5.9
> +-----------------
> +
> +The ERR_EXIT option was refined to be more self-consistent and better
> +aligned with the POSIX-2017 specification of `set -e`:
> +
> +  - Prefixing a function call or anonymous function with `!` now
> +    suppresses ERR_EXIT.

Shouldn't this define the term "suppresses"?  It's not used in
the documentation of ERR_EXIT.

Is the option suppressed for the function call or the result of the
anonymous function, or /within/ the called function or anonymous
function?

What's the behaviour of ERR_EXIT on «! foo» when foo isn't a named or
anonymous function?  I.e., does the change make function calls an
exception, or does it make them /no longer/ an exception?  I think the
text should answer this.

> +
> +  - The `always` command now propagates ERR_EXIT suppression, as other
> +    complex commands do.
> +

Shouldn't this define the term "propagates"?  It's not used in
the documentation of ERR_EXIT.

> +  - Function calls, anonymous functions, and the `eval`, `.`, and
> +    `source` commands no longer propagate ERR_EXIT suppression.

s/commands/builtins/

> +
> +The ERR_RETURN option is now suppressed when a function containing
> +a compound sublist (`&&` or `||`) is called from within another compound
> +sublist.
> +

Does suppression happen for the result of the call, or within the
callee?

What exactly are the conditions whereupon suppression happens?  As
written, the text implies that suppression happens in
.
    FWaCL() { …; if false; then : && :; fi; … }
    false || FWaCL
.
regardless of the values of the ellipses; is that the intended meaning?

As you mentioned downthread, please add examples of affected cases (and,
if needed, of unaffected cases too).  Doc/Zsh/ can be updated as well,
if needed (this is discussed on the 51089 thread).

Proposed text (possibly wrong, do not use it without checking for
correctness and omissions):

    The ERR_EXIT option no longer applies to the result of commands
    of the form '! foo' regardless of what 'foo' is.  Previously, the
    option did take effect if 'foo' were a function call or an anonymous
    function.  Example:
    .
	setopt ERR_EXIT
        f() { false }
	g() { ! f; echo This will be printed in 5.10 but was not printed in 5.9 }

    The ERR_EXIT option now applies to the result of an 'always'
    block.  This aligns 'always' with other complex commands.
    Example:
    .
	setopt ERR_EXIT
        { false } always { echo This would be printed by either 5.9 and 5.10 }
	echo This would only be printed by 5.10 and newer
    # I'm saying "complex" rather than "compound" because that's the
    # term the manual uses.

    The ERR_EXIT option now applies to the results of function calls,
    anonymous functions, and the `eval`, `.`, and `source` builtins.
    Example:
    .
        setopt ERR_EXIT
	f() { false; }
	f
	echo This was printed under 5.9 but will not be printed by 5.10

    The ERR_RETURN option now applies within a function even if the
    return code of the function itself would not trigger ERR_RETURN
    behaviour from the function's caller (e.g., because the function
    call is on the left-hand side of an "&&" or "||").  Example:
    .
        setopt ERR_RETURN
	f() { false; echo This was printed under 5.9 but will not be printed under 5.10 }
	g() { f || true }

Cheers,

Daniel

P.S. Personally, I'd have preferred it if the four commits with "51001:"
at the start of their log message had something unique there, e.g.,
"51001/{1..4}", as per precedent (e.g., zsh-5.8-433-ga23f19bfb).
Rationale: so anyone doing «git log --grep='^51001'» would know, from
the first log message they see, that several commits match the grep,
rather than just one as might be assumed.

> +Changes from 5.8.1 to 5.9
> +-------------------------
>  
>  zsh 5.9 is dedicated to the memory of Sven Guckes, who was, amongst other
>  things, a long-time zsh advocate.  For more information, see:
> -- 
> vq
> 


^ permalink raw reply	[relevance 0%]

* Re: read -d $'\200' doesn't work with set +o multibyte (and [PATCH])
  2022-12-09 20:05  2% ` Oliver Kiddle
@ 2022-12-10  9:06  2%   ` Stephane Chazelas
    0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2022-12-10  9:06 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh hackers list

2022-12-09 21:05:02 +0100, Oliver Kiddle:
> Stephane Chazelas wrote:
> > Even in a locale with a single-byte charmap, when multibyte is
> > off, I can't make read -d work when the delimiter is a byte >=
> > 0x80.
> 
> In my testing, it does work in a single-byte locale. I tested on
> multiple systems.
> 
> Looking at the multibyte implementation of read, the approach taken
> is to use a wchar_t for the delimiter and then maintain mbstate_t for
> the input. This supports a delimiter that can be any single unicode
> codepoint. In my testing this is working as intended. But note that \351
> alone is incomplete in UTF-8 terms so what wchar_t value should that be
> mapped to.

Note that here I'm talking of the case where multibyte is
*disabled* (zsh +o multibyte), and where UTF-8 (or any other
multibyte charset) is nowhere in the picture. As I said, with
multibyte on, it works for valid characters; in iso8859-15 on
GNU systems, that's 0..0x7f, 0xa0..0xff.


IIRC In other areas of the code, bytes that can't be decoded
into characters are decoded as 0xdc00 + byte.

$ grep -rnwi 0xdc00 .
./ChangeLog:12625:      invalid multibyte characters to 0xDC00 + index which is invalid
./Src/pattern.c:242:    ((wchar_t) (0xDC00 + STOUC(ch)))

See workers/36411 workers/36415

It would be great if something like that was done everywhere so
we can always deal with arbitrary arrays of bytes regardless of
the locale.

> Also interesting to consider is the range \x7f to \x9f in an ISO-8859-x
> locale. Those are duplicates of the control characters. In my testing
> with a single-byte locale \x89 as a delimiter will end input at a tab
> character but the converse (\t as a delimiter) will not terminate at
> \x89 in the input.

I can't reproduce here:

~$ LC_ALL=en_GB.iso885915 zsh +o multibyte -c "IFS= read -rd $'\x89' a <<< $'a\tb'; print -rn -- \$a" | hd
00000000  61 09 62 0a                                       |a.b.|
00000004
~$ LC_ALL=en_GB.iso885915 zsh -c "IFS= read -rd $'\x89' a <<< $'a\tb'; print -rn -- \$a" | hd
00000000  61 09 62 0a                                       |a.b.|
00000004
~$ LC_ALL=en_GB.UTF-8 zsh -c "IFS= read -rd $'\x89' a <<< $'a\tb'; print -rn -- \$a" | hd
00000000  61 09 62 0a                                       |a.b.|
00000004
~$ LC_ALL=en_GB.UTF-8 zsh +o multibyte -c "IFS= read -rd $'\x89' a <<< $'a\tb'; print -rn -- \$a" | hd
00000000  61 09 62 0a                                       |a.b.|
00000004


> My understanding of the proposed POSIX wording is that it requires
> the individual octet, regardless of any character mapping to be the
> delimiter. Does anyone track the austin list? Would be good if they can
> be persuaded to relax what they specify. The part I especially object to
> is requiring that the input does not contain null bytes. The fact that
> zsh can cope with nulls is often really useful. Why can't they leave
> that unspecified? I can understand wanting to standardise a lowest
> common denominator but that is punishing an existing richer
> implementation.

Not sure what you mean. The proposed text has:

 -d delim

    If delim consists of one single-byte character, that byte
    shall be used as the logical line delimiter. If delim is the
    null string, the logical line delimiter shall be the null
    byte. Otherwise, the behavior is unspecified.

That's added alongside xargs -0 and find's -prin0 to be able to
deal with arbitrary file names, so the point is for it to work
on input with NULs.

The:

 If the -d delim option is specified and delim consists of one
 single-byte character other than <newline>, the standard input
 shall contain zero or more characters, shall not contain any
 null bytes, and (if not empty) shall end with delim.

Is a requirement on the *application*, not the implementation.
That is, it only specifies what's meant to happen when the input
doesn't contain NULs.

So I think we're good here.

I'm susbscribed to both austin-group-l and zsh-workers but don't
follow them very closely. I try to mention things relevant to
zsh here when I spot them on austin-group-l and I try to argue
there about things that would conflict with the zsh way for no
good reason.

austin-group-l is not large volume, I would recommend at least
one zsh developer get in there. I see the maintainers of FreeBSD
sh, NetBSD sh, mksh, bash at least occasionally contributing
there. You can also get an account on their bug tracker. I've
got one and I'm not the maintainer of any software relevant to
POSIX.

Changes in the bug tracker are posted to the ML. It's often
preferable to add a comment on a ticket than post on the ML.

> One way forward would be to take the argument to -d as a literal and
> potentially multi-byte delimiter. UTF-8 has the property that a valid
> sequence can't occur within a longer sequence so for UTF-8 you would not
> need to worry about it finding a delimiter within a different
> character. This is not the case with combining characters but the
> current implementation will also stop at the uncombined character.
> There are other multi-byte encodings for which this is not true. I've
> no idea how relevant things like EUC-JP and Shift-JIS still are.

Things like Shift-JIS are unworkable. I don't expect anyone to
still be using them.

GB18030 and BIG5/BIG5-HKSCS may still be relevant. They don't
work on Shift state like Shift-JIS, but many of their characters
have bytes <= 0x7f, and zsh doesn't really work with them for
that reason.

$ echo αε | iconv -t BIG5-HKSCS | hd
00000000  a3 5c a3 60 0a                                    |.\.`.|
00000005


Simply *having* locales with those charsets opens your system up
to security vulnerabilities as you have alpha characters which
contain \ and `, special to the shell and many other things.

in practice not many things work with them, it's not just zsh;
I've noticed newer Debian/Ubuntu doesn't offer locales with them
any longer (though you can still generate some if you like).

[...]
> Should we document the fact that -d '' works like -d $'\0'? Perhaps mark
> this as being for compatibility with other shells? Fortunately, it does
> work as specified but this may only be by accident. When the -d feature
> was added, it was probably only checked that the behaviour with an empty
> delimiter was sane.

Yes, I agree it's worth documenting. AFAIK, read -d is from
ksh93. read -d '' likely works in bash (added there in 2.04) by
accident as well (first byte of a NUL-delimited string), it
didn't in ksh93.

IFS= read -rd '' is a well known coding pattern in bash.
read -d '' now works in ksh93u+m and mksh.

-d is likely used much more often with '' than with anything
else.

> > $ LC_ALL=en_GB.iso885915 ./Src/zsh +o multibyte
> > $ locale charmap
> > ISO-8859-15
> 
> What do you get with the following, I'd sooner trust this:
>   zmodload zsh/langinfo; echo $langinfo[CODESET]

Same ISO-8859-15

$ LC_ALL=en_GB.iso885915  ./Src/zsh +o multibyte -c "IFS= read -rd $'\351' a <<< a$'\351'b; print -rn -- \$a" | hd
00000000  61 e9 62 0a                                       |a.b.|
00000004

gdb under LC_ALL=en_GB.iso885915 luit

6402        if (OPT_ISSET(ops,'d')) {
(gdb)
6403            char *delimstr = OPT_ARG(ops,'d');
(gdb)
6407            if (isset(MULTIBYTE)) {
(gdb)
6412                wi = WEOF;
(gdb)
6413            if (wi != WEOF)
(gdb)
6416                delim = (wchar_t)((delimstr[0] == Meta) ?
(gdb)
6417                                  delimstr[1] ^ 32 : delimstr[0]);
(gdb)
6416                delim = (wchar_t)((delimstr[0] == Meta) ?
(gdb)
6421            if (SHTTY != -1) {
(gdb) p delim
$1 = -23 L'\xffffffe9'
(gdb) p delimstr
$2 = 0x7ffff7fa1790 "é"

(as delimstr is a signed char* instead of unsigned char I guess).

It works better after:

diff --git a/Src/builtin.c b/Src/builtin.c
index a7b7755a7..d650ca750 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -6414,9 +6414,9 @@ bin_read(char *name, char **args, Options ops, UNUSED(int func))
 	    delim = (wchar_t)wi;
 	else
 	    delim = (wchar_t)((delimstr[0] == Meta) ?
-			      delimstr[1] ^ 32 : delimstr[0]);
+			      STOUC(delimstr[1]) ^ 32 : STOUC(delimstr[0]));
 #else
-        delim = (delimstr[0] == Meta) ? delimstr[1] ^ 32 : delimstr[0];
+        delim = (delimstr[0] == Meta) ? STOUC(delimstr[1]) ^ 32 : STOUC(delimstr[0]);
 #endif
 	if (SHTTY != -1) {
 	    struct ttyinfo ti;


(I don't know if it's the proper way to cast, my C is rusty)

Including for bytes that don't map to any character in ISO8859-15:

$ LC_ALL=en_GB.iso885915 zsh -c "IFS= read -rd $'\x80' a <<< $'a\x80b'; print -rn -- \$a" | hd
00000000  61                                                |a|
00000001

So I guess that's the fix for my bug.

-- 
Stephane


^ permalink raw reply	[relevance 2%]

* Re: read -d $'\200' doesn't work with set +o multibyte
  2022-12-09 15:42  3% read -d $'\200' doesn't work with set +o multibyte Stephane Chazelas
@ 2022-12-09 20:05  2% ` Oliver Kiddle
  2022-12-10  9:06  2%   ` read -d $'\200' doesn't work with set +o multibyte (and [PATCH]) Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Oliver Kiddle @ 2022-12-09 20:05 UTC (permalink / raw)
  To: Zsh hackers list

Stephane Chazelas wrote:
> Even in a locale with a single-byte charmap, when multibyte is
> off, I can't make read -d work when the delimiter is a byte >=
> 0x80.

In my testing, it does work in a single-byte locale. I tested on
multiple systems.

Looking at the multibyte implementation of read, the approach taken
is to use a wchar_t for the delimiter and then maintain mbstate_t for
the input. This supports a delimiter that can be any single unicode
codepoint. In my testing this is working as intended. But note that \351
alone is incomplete in UTF-8 terms so what wchar_t value should that be
mapped to.

Also interesting to consider is the range \x7f to \x9f in an ISO-8859-x
locale. Those are duplicates of the control characters. In my testing
with a single-byte locale \x89 as a delimiter will end input at a tab
character but the converse (\t as a delimiter) will not terminate at
\x89 in the input.

My understanding of the proposed POSIX wording is that it requires
the individual octet, regardless of any character mapping to be the
delimiter. Does anyone track the austin list? Would be good if they can
be persuaded to relax what they specify. The part I especially object to
is requiring that the input does not contain null bytes. The fact that
zsh can cope with nulls is often really useful. Why can't they leave
that unspecified? I can understand wanting to standardise a lowest
common denominator but that is punishing an existing richer
implementation.

One way forward would be to take the argument to -d as a literal and
potentially multi-byte delimiter. UTF-8 has the property that a valid
sequence can't occur within a longer sequence so for UTF-8 you would not
need to worry about it finding a delimiter within a different
character. This is not the case with combining characters but the
current implementation will also stop at the uncombined character.
There are other multi-byte encodings for which this is not true. I've
no idea how relevant things like EUC-JP and Shift-JIS still are.

A side effect of this would be support for strings of quite distinct
characters as a multi-character delimiter.

Should we document the fact that -d '' works like -d $'\0'? Perhaps mark
this as being for compatibility with other shells? Fortunately, it does
work as specified but this may only be by accident. When the -d feature
was added, it was probably only checked that the behaviour with an empty
delimiter was sane.

> $ LC_ALL=en_GB.iso885915 ./Src/zsh +o multibyte
> $ locale charmap
> ISO-8859-15

What do you get with the following, I'd sooner trust this:
  zmodload zsh/langinfo; echo $langinfo[CODESET]

Oliver


^ permalink raw reply	[relevance 2%]

* Re: `return` does not behave properly under `!`
  2022-12-09 16:21  0%           ` Bart Schaefer
@ 2022-12-09 19:20  0%             ` Michael Greenberg
  0 siblings, 0 replies; 200+ results
From: Michael Greenberg @ 2022-12-09 19:20 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Stephane Chazelas, zsh-workers

Derp! I _did_ see it, but apparently I forgot about it. Delighted zsh is
on board! :)

Cheers,
Michael

On 2022-12-09 at 08:21:53 AM, Bart Schaefer wrote:

> On Fri, Dec 9, 2022 at 7:22 AM Michael Greenberg
> <michael@greenberg.science> wrote:
>>
>> Hopefully zsh can follow suit (and perhaps we can raise this with POSIX
>> folks). I'd be happy to try for a patch, but I'm not at all familiar
>> with zsh's code...
>
> Did you not see PWS's patch in workers/51125 ?  You were Cc'd ...


^ permalink raw reply	[relevance 0%]

* Re: `return` does not behave properly under `!`
  2022-12-09 15:22  3%         ` Michael Greenberg
@ 2022-12-09 16:21  0%           ` Bart Schaefer
  2022-12-09 19:20  0%             ` Michael Greenberg
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-12-09 16:21 UTC (permalink / raw)
  To: Michael Greenberg; +Cc: Stephane Chazelas, zsh-workers

On Fri, Dec 9, 2022 at 7:22 AM Michael Greenberg
<michael@greenberg.science> wrote:
>
> Hopefully zsh can follow suit (and perhaps we can raise this with POSIX
> folks). I'd be happy to try for a patch, but I'm not at all familiar
> with zsh's code...

Did you not see PWS's patch in workers/51125 ?  You were Cc'd ...


^ permalink raw reply	[relevance 0%]

* read -d $'\200' doesn't work with set +o multibyte
@ 2022-12-09 15:42  3% Stephane Chazelas
  2022-12-09 20:05  2% ` Oliver Kiddle
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2022-12-09 15:42 UTC (permalink / raw)
  To: Zsh hackers list

Even in a locale with a single-byte charmap, when multibyte is
off, I can't make read -d work when the delimiter is a byte >=
0x80.

$ LC_ALL=en_GB.iso885915 ./Src/zsh +o multibyte
$ locale charmap
ISO-8859-15
$ locale ctype-mb-cur-max
1
$ print 'a\351b' | read -rd $'\351'
$ print $?
1
$ print -r -- $REPLY | LC_ALL=C od -tc
0000000   a 351   b  \n
0000004

Without set +o multibyte, the above works (at treating 0351 (é
in that charset) as a delimiter), but not for \200 (undefined in
ISO-8859-1 which I guess is expected).

With LC_ALL=C, on GNU systems where mbrtowc() returns -1 EILSEQ
for any byte >= 0x80, I find read -d doesn't work for byte >=
0x80 used as delimiter with or without set +o multibyte.

(on Debian GNU/Linux amd64 with 5.9 or git HEAD).

I've raised a related issue against ksh93
(https://github.com/ksh93/ksh/issues/590)

It looks like POSIX are considering specifying  read -d. They
would leave it unspecified if the delimiter is neither the empty
string nor a single-byte character.
https://austingroupbugs.net/view.php?id=243#c6091

-- 
Stephane






^ permalink raw reply	[relevance 3%]

* Re: `return` does not behave properly under `!`
  2022-12-07 17:10  3%       ` Michael Greenberg
@ 2022-12-09 15:22  3%         ` Michael Greenberg
  2022-12-09 16:21  0%           ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Michael Greenberg @ 2022-12-09 15:22 UTC (permalink / raw)
  To: Stephane Chazelas; +Cc: Bart Schaefer, zsh-workers

A tiny update:

On 2022-12-07 at 12:10:55 PM, Michael Greenberg wrote:

> I think there's a good opportunity to have shells in alignment here (and
> maybe make POSIX more explicit): if zsh folks agree that return should
> not be affected by an enclosing !, we can align bash/dash/zsh. (I'm
> hopeful yash folks will agree, too.)

yash maintainers agreed that this is a bug, which is now fixed
<https://osdn.net/projects/yash/ticket/46224>.

Hopefully zsh can follow suit (and perhaps we can raise this with POSIX
folks). I'd be happy to try for a patch, but I'm not at all familiar
with zsh's code...

Cheers,
Michael


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] NEWS item about the ERR_EXIT fixes
  @ 2022-12-09  6:44  5%   ` Lawrence Velázquez
  2022-12-10 11:32  0%     ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Lawrence Velázquez @ 2022-12-09  6:44 UTC (permalink / raw)
  To: Bart Schaefer, Philippe Altherr; +Cc: zsh-workers

On Thu, Dec 8, 2022, at 7:24 PM, Bart Schaefer wrote:
> On Thu, Dec 8, 2022 at 1:47 PM Philippe Altherr
> <philippe.altherr@gmail.com> wrote:
>>
>> I couldn't make it shorter than what is in the patch.
>
> I think this is fine.  Any opposed?

I think it's overly verbose; NEWS doesn't have to explain how
ERR_EXIT works.  Here's a possible alternative:

diff --git a/NEWS b/NEWS
index cdafd1ff5..d8b8687c0 100644
--- a/NEWS
+++ b/NEWS
@@ -4,8 +4,27 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.8.1
--------------------
+Changes since 5.9
+-----------------
+
+The ERR_EXIT option was refined to be more self-consistent and better
+aligned with the POSIX-2017 specification of `set -e`:
+
+  - Prefixing a function call or anonymous function with `!` now
+    suppresses ERR_EXIT.
+
+  - The `always` command now propagates ERR_EXIT suppression, as other
+    complex commands do.
+
+  - Function calls, anonymous functions, and the `eval`, `.`, and
+    `source` commands no longer propagate ERR_EXIT suppression.
+
+The ERR_RETURN option is now suppressed when a function containing
+a compound sublist (`&&` or `||`) is called from within another compound
+sublist.
+
+Changes from 5.8.1 to 5.9
+-------------------------
 
 zsh 5.9 is dedicated to the memory of Sven Guckes, who was, amongst other
 things, a long-time zsh advocate.  For more information, see:
-- 
vq


^ permalink raw reply	[relevance 5%]

* Re: Get cursor position (Was: [bug report] prompt can erase messages written on the terminal by background processes)
  @ 2022-12-08 10:10  3%           ` Stephane Chazelas
    1 sibling, 0 replies; 200+ results
From: Stephane Chazelas @ 2022-12-08 10:10 UTC (permalink / raw)
  To: Roman Perepelitsa, Bart Schaefer, Millian Poquet, zsh-workers

2022-12-08 10:02:15 +0000, Stephane Chazelas:
[...]
> (bash does by exploiting some bug (calling unset -v in a
> severate function peels one layer of scoping instead of
> unsetting in the current scope)).
[...]

Not sure how "separate" became "severate" there. Sometimes it
feels like my fingers have a life of their own... Sorry.

unlocal in bash (or yash) can be written:

unlocal() { unset -v "$@"; }

(that's one of the main reasons POSIX couldn't specify "local"
btw).

It's worse in mksh where unset is always unlocal.

$ bash -c 'unlocal() { unset -v "$@"; }; f() { local a=1; g; echo "f: $a"; }; g() { local a=2; unlocal a; echo "g: $a"; a=3; }; a=0; f'
g: 1
f: 3
$ yash -c 'unlocal() { unset -v "$@"; }; f() { local a=1; g; echo "f: $a"; }; g() { local a=2; unlocal a; echo "g: $a"; a=3; }; a=0; f'
g: 1
f: 3

$ zsh -c 'unlocal() { unset -v "$@"; }; f() { local a=1; g; echo "f: $a"; }; g() { local a=2; unlocal a; echo "g: $a"; a=3; }; a=0; f'
g:
f: 1
$ dash -c 'unlocal() { unset -v "$@"; }; f() { local a=1; g; echo "f: $a"; }; g() { local a=2; unlocal a; echo "g: $a"; a=3; }; a=0; f'
g:
f: 1
$ bosh -c 'unlocal() { unset -v "$@"; }; f() { local a=1; g; echo "f: $a"; }; g() { local a=2; unlocal a; echo "g: $a"; a=3; }; a=0; f'
g:
f: 1

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: `return` does not behave properly under `!`
  2022-12-07 16:01  3%     ` Stephane Chazelas
@ 2022-12-07 17:10  3%       ` Michael Greenberg
  2022-12-09 15:22  3%         ` Michael Greenberg
  0 siblings, 1 reply; 200+ results
From: Michael Greenberg @ 2022-12-07 17:10 UTC (permalink / raw)
  To: Stephane Chazelas; +Cc: Bart Schaefer, zsh-workers

On 2022-12-07 at 04:01:13 PM, Stephane Chazelas wrote:

> 2022-12-07 10:05:34 -0500, Michael Greenberg:
>> Hi Stephane and Bart (reply inline below, as it's relevant to Stephane),
> [...]
>> So my reading is the opposite: `return` doesn't have an exit status,
>> because it causes the currently executing function (or sourced script)
>> to terminate; it does, however, set $?. So `!` shouldn't affect it.
> [...]
>
> Agreed.
>
>> But even without a close reading of the spec, it's just not how early
>> return works in any language. Having the evaluation context beyond
>> `return` affect the returned value subverts the early and immediate
>> return---and, in so doing, invites bugs.
> [...]
>
> Agreed.
>
>> So far, dash, yash, and zsh are the only shells I've found with this
>> behavior, and the dash folks seem to agree that it's an undesirable
>> bug. And also...
>
> Also bosh.
>
> I can't see why one would call ! return if not to expect that to
> have an effect on the exit status.
>
> $ zsh -c 'f() { ! { false || return; }; }; f; echo "$?"'
> 0
>
> Is more of a problem though and I agree would be an undesirable bug..

Like in your example, I think the pernicious case is when the ! and the
return are far apart. The scenario I imagine is something like:

f() {
  while ! { SOME_CONDITION_FOR_EARLY_EXIT && return 1 
            SOME_CONDITION_FOR_TERMINATION_WITH_POSTPROCESSING 
          }
  do 
    ...
  done
  ...
}

In process of running the loop's predicate, the script might realize
that it's just time to exit the function early (without
postprocessing). The outer negation in the predicate is meant to negate
the whole predicate, not the return. It would be surprising to have that
distant `!` affect the return (and having it negate the status would
make it impossible to return statuses other than 0 and 1 in this form).

>
> [...]
>> Ah---thank you! I wish there were a straightforward fulltext search of
>> the archives (though I don't know I would have found this anyway, as it
>> doesn't explicitly mention `return`). I'll try to test these patches to
>> confirm.
>
> You can download and rsync the full archive from
> rsync://rsync.zsh.org/mla/zsh-workers/

Oh---I didn't realize this rsync interface existed, thank you! Might be
good to document it on https://www.zsh.org/mla/.

>> That seems hardly relevant here: a return explicitly sets $?, unlike
>> break/continue (which both have exit statuses, unlike return).
> [...]
>
> They're still special builtins that break the flow, so I would
> still consider it relevant. I've not checked zsh recently but
> there are funny things you can do with some shells by calling
> break/continue in a function where the corresponding "enclosing"
> loop is in one of the callers. IIRC there was some POSIX
> discussion about that and the text tightened.

Yes, non-lexical break is a mess, with varying treatment in popular
shells (e.g., bash and dash disagree). Having ! affect return from a
distance amounts to a form of non-lexical return munging. As someone who
studies programming languages for a living, I would very much advise
against non-lexical control if we can avoid it. :)

I think there's a good opportunity to have shells in alignment here (and
maybe make POSIX more explicit): if zsh folks agree that return should
not be affected by an enclosing !, we can align bash/dash/zsh. (I'm
hopeful yash folks will agree, too.)

Cheers,
Michael


^ permalink raw reply	[relevance 3%]

* Re: `return` does not behave properly under `!`
  2022-12-07 15:05  3%   ` Michael Greenberg
@ 2022-12-07 16:01  3%     ` Stephane Chazelas
  2022-12-07 17:10  3%       ` Michael Greenberg
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2022-12-07 16:01 UTC (permalink / raw)
  To: Michael Greenberg; +Cc: Bart Schaefer, zsh-workers

2022-12-07 10:05:34 -0500, Michael Greenberg:
> Hi Stephane and Bart (reply inline below, as it's relevant to Stephane),
[...]
> So my reading is the opposite: `return` doesn't have an exit status,
> because it causes the currently executing function (or sourced script)
> to terminate; it does, however, set $?. So `!` shouldn't affect it.
[...]

Agreed.

> But even without a close reading of the spec, it's just not how early
> return works in any language. Having the evaluation context beyond
> `return` affect the returned value subverts the early and immediate
> return---and, in so doing, invites bugs.
[...]

Agreed.

> So far, dash, yash, and zsh are the only shells I've found with this
> behavior, and the dash folks seem to agree that it's an undesirable
> bug. And also...

Also bosh.

I can't see why one would call ! return if not to expect that to
have an effect on the exit status.

$ zsh -c 'f() { ! { false || return; }; }; f; echo "$?"'
0

Is more of a problem though and I agree would be an undesirable bug..

[...]
> Ah---thank you! I wish there were a straightforward fulltext search of
> the archives (though I don't know I would have found this anyway, as it
> doesn't explicitly mention `return`). I'll try to test these patches to
> confirm.

You can download and rsync the full archive from
rsync://rsync.zsh.org/mla/zsh-workers/

And search in there.

$ rsync rsync.zsh.org::
========================================================
ZSH FTP primary site (rsync.zsh.org)

Example usage:
rsync -av --delete rsync://rsync.zsh.org/pub /local/path/to/zsh/pub

Always do a dry run (-n) first or --delete may bite you!
========================================================
Modules:
========================================================


pub             Zsh FTP Pub directory (~280MB as of Feb 2010)
mla             Zsh Mailing List Archive directory (~333MB as of Feb 2010)


> > That's consistent with ! break causing the while/until loop it's
> > in returning with failure which I've seen code rely upon (AFAIK,
> > that's the only way to get those loops to return with failure;
> > doesn't work in pdksh and derivatives though).
> 
> That seems hardly relevant here: a return explicitly sets $?, unlike
> break/continue (which both have exit statuses, unlike return).
[...]

They're still special builtins that break the flow, so I would
still consider it relevant. I've not checked zsh recently but
there are funny things you can do with some shells by calling
break/continue in a function where the corresponding "enclosing"
loop is in one of the callers. IIRC there was some POSIX
discussion about that and the text tightened.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: `return` does not behave properly under `!`
  2022-12-07  8:42  4% ` Stephane Chazelas
@ 2022-12-07 15:05  3%   ` Michael Greenberg
  2022-12-07 16:01  3%     ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Michael Greenberg @ 2022-12-07 15:05 UTC (permalink / raw)
  To: Stephane Chazelas, Bart Schaefer; +Cc: zsh-workers

Hi Stephane and Bart (reply inline below, as it's relevant to Stephane),

On 2022-12-07 at 08:42:55 AM, Stephane Chazelas wrote:

> 2022-12-06 13:18:59 -0500, Michael Greenberg:
> [...]
>> i() {
>>   ! return 9
>>   echo fail not
>> }
>> i
>> echo $?
>> ```
> [...]
>> 0
> [...]
>
> That:
>
> ! return n
>
> Behaves like return !n (and ! return behave like return !$? (or
> return "$(( ! $? ))" in POSIX syntax) doesn't sound totally off
> to me. As written, I would say the POSIX spec may even be
> requiring it.

Here's what the POSIX spec says about `return`:

  The return utility shall cause the shell to stop executing the
  current function or dot script. If the shell is not currently
  executing a function or dot script, the results are unspecified.

  ...

  EXIT STATUS

  The value of the special parameter '?' shall be set to n, an unsigned
  decimal integer, or to the exit status of the last command executed if
  n is not specified. If n is not an unsigned decimal integer, or is
  greater than 255, the results are unspecified. When return is executed
  in a trap action, the last command is considered to be the command
  that executed immediately preceding the trap action.

And here's what it says about `!` on pipelines:

  If the pipeline does not begin with the ! reserved word, the exit
  status shall be the exit status of the last command specified in the
  pipeline. Otherwise, the exit status shall be the logical NOT of the
  exit status of the last command. That is, if the last command returns
  zero, the exit status shall be 1; if the last command returns greater
  than zero, the exit status shall be zero.

So my reading is the opposite: `return` doesn't have an exit status,
because it causes the currently executing function (or sourced script)
to terminate; it does, however, set $?. So `!` shouldn't affect it.

But even without a close reading of the spec, it's just not how early
return works in any language. Having the evaluation context beyond
`return` affect the returned value subverts the early and immediate
return---and, in so doing, invites bugs.

So far, dash, yash, and zsh are the only shells I've found with this
behavior, and the dash folks seem to agree that it's an undesirable
bug. And also...

On 2022-12-06 at 08:53:25 PM, Bart Schaefer wrote:

> On Tue, Dec 6, 2022 at 10:19 AM Michael Greenberg
> <michael@greenberg.science> wrote:
>>
>> Following up an example from Harald van Dijk on the dash mailing list, I
>> discovered that zsh does not `return` properly under a `!`.
>
> This appears to have been fixed by Philippe Altherr's series of
> patches for ERR_EXIT et al, zsh-workers 51001, 51071, 51076.

Ah---thank you! I wish there were a straightforward fulltext search of
the archives (though I don't know I would have found this anyway, as it
doesn't explicitly mention `return`). I'll try to test these patches to
confirm.

> That's consistent with ! break causing the while/until loop it's
> in returning with failure which I've seen code rely upon (AFAIK,
> that's the only way to get those loops to return with failure;
> doesn't work in pdksh and derivatives though).

That seems hardly relevant here: a return explicitly sets $?, unlike
break/continue (which both have exit statuses, unlike return).

Cheers,
Michael


^ permalink raw reply	[relevance 3%]

* Re: `return` does not behave properly under `!`
  @ 2022-12-07  8:42  4% ` Stephane Chazelas
  2022-12-07 15:05  3%   ` Michael Greenberg
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2022-12-07  8:42 UTC (permalink / raw)
  To: Michael Greenberg; +Cc: zsh-workers

2022-12-06 13:18:59 -0500, Michael Greenberg:
[...]
> i() {
>   ! return 9
>   echo fail not
> }
> i
> echo $?
> ```
[...]
> 0
[...]

That:

! return n

Behaves like return !n (and ! return behave like return !$? (or
return "$(( ! $? ))" in POSIX syntax) doesn't sound totally off
to me. As written, I would say the POSIX spec may even be
requiring it.

That's consistent with ! break causing the while/until loop it's
in returning with failure which I've seen code rely upon (AFAIK,
that's the only way to get those loops to return with failure;
doesn't work in pdksh and derivatives though).

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: ERR_RETURN doc
  @ 2022-12-01 19:30  3%                       ` Philippe Altherr
  2022-12-10 11:33  0%                         ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-12-01 19:30 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 844 bytes --]

Yep, that remains correct. Same for ERR_EXIT.

Most(/All?) of the patches address cases where the implementation wasn't
following the specification.

The patch about the always statement makes it behave like compound
statements. Since the always statement isn't part of POSIX, this could be
seen either as a bug fix or a spec change (but rather of the always
statement than of ERR_EXIT).

Philippe


On Thu, Dec 1, 2022 at 5:30 PM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> On Thu, Dec 1, 2022 at 6:42 AM Philippe Altherr
> <philippe.altherr@gmail.com> wrote:
> >
> > https://zsh.sourceforge.io/Doc/Release/Options.html#index-ERRRETURN.
>
> Will that doc remain correct with respect to what it says about
> ERR_EXIT after recent patches are considered?
>
> (Still on my TODO list, have been busier than I expected so far this week.)
>

[-- Attachment #2: Type: text/html, Size: 1441 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-23  9:43  4%           ` Philippe Altherr
@ 2022-11-24  4:28  5%             ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-11-24  4:28 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: zsh-workers

On Wed, Nov 23, 2022, at 4:43 AM, Philippe Altherr wrote:
> I think POSIX indirectly mandates the behavior. So far, there are two 
> proposals on how to specify anonymous functions:
>
> A) a function call (to a function defined on the spot and undefined 
> right after the call)
> B) a compound command

Anonymous functions are complex commands regardless; they are parsed
much like function definitions.  The question here is only about
how they should interact with ERR_EXIT.


> In my opinion, the name and the description of anonymous functions 
> strongly suggests that anonymous functions are a shorthand for defining 
> a function, calling it with the provided arguments, and undefining the 
> function. I have always assumed that "() { <body> } <args>" is 
> syntactic sugar for "anon() { <body> }; { anon <args> } always { 
> unfunction anon }". As far as I can tell, Zsh effectively implements 
> anonymous functions with function calls. If this is indeed the case and 
> one agrees with the specification described here, then everything is 
> consistent; anonymous functions look, feel, and behave like function 
> calls, including when it comes to ERR_EXIT, and this with and without 
> my patches.

This "syntactic sugar" argument is flawed in its very conception
because the POSIX specification for "set -e" is *all about syntax*.
It addresses the early-exit behavior of various *syntactic* command
forms -- pipelines, compound commands, AND-OR lists.  It does not
know or care about function calls; it does not mention them even
once.  They are just simple commands as far as POSIX "set -e" is
concerned.

To be clear, there is nothing wrong with considering anonymous
functions to be syntactic sugar for defining, calling, and removing
a function, but that does not change their syntax.  They *are*
complex commands.  It doesn't matter how they're implemented or how
you want to think about them -- you cannot reasonably use POSIX to
justify giving them the same early-exit behavior as vanilla function
calls.

Of course, that need not stop us from doing so.  POSIX compliance
is not a requirement for zsh, anonymous functions are already well
outside the POSIX spec, and carving out a (...)-like exception for
them (as Bart originally suggested) has a lot to recommend it (as
I agreed with in my response to Peter).  But at this point POSIX
is more or less out of the picture.  Which is fine.


> You propose to specify anonymous functions as a kind of compound 
> command.

No, I did not propose that.  I presented two possibilities for
anonymous functions' behavior with respect to ERR_EXIT, elaborated
on "like other complex commands" because I thought the argument for
"like regular function calls" was self-evident, and explicitly
expressed ambivalence about which was best.

Plus, they already are complex commands.


> I fear that anonymous functions as compound commands require a more 
> complicated mental model than anonymous functions as function calls.
> For example, if anonymous functions are compound commands then I would 
> expect that the "return" in the code below exits the function "foo" but 
> that's not what it does.
>
>> foo() {
>>   echo foo-start;
>>   () { echo args: $@; return } 1 2 3
>>   echo foo-end;
>> }
>> foo

Why would you expect that?  "Complex command" is a syntactic
classification that doesn't imply any particular behavior.  It
includes {...}, (...), function definitions, the various loops and
conditionals, etc., but these all behave differently.


-- 
vq


^ permalink raw reply	[relevance 5%]

* Re: [PATCH] zsh/random module [UPDATED]
  @ 2022-11-24  2:58  4%             ` Clinton Bunch
  0 siblings, 0 replies; 200+ results
From: Clinton Bunch @ 2022-11-24  2:58 UTC (permalink / raw)
  To: zsh-workers

This is a from memory reply as I'm away from my git repository/code for 
the holiday. :)  So there may be a follow up.

On 11/23/2022 1:46 PM, Daniel Shahaf wrote:
> Clinton Bunch wrote on Mon, Nov 07, 2022 at 18:18:15 -0600:
> +++ b/Doc/Zsh/mod_random.yo
>> @@ -0,0 +1,67 @@
>> +startitem()
>> +findex(getrandom)
>> +cindex(random data, printing, array)
>> +xitem(tt(getrandom) [ tt(-c) var(count) ] [ tt(-r) ] [ tt(-s) var(scalar) ] [tt(-i) ] [ tt(-a) var(array) ] [ tt(-L) var(lower_bound) ] [ tt(-U) var(upper_bound) ])
> Never use xitem() without item() after it.
I'm using existing docs as a template as I don't know YODL at all, so 
I'm not surprised I made mistakes.
>
> I don't understand this API.
>
> - Magic numbers:
>
>    + Why should -c default to 8 in the "random bytes" case?  Why
>      shouldn't it default to some other value, or even be required to be
>      specified explicitly by the user?
Not sure why 8 was the number I thought of, just that one wasn't 
particularly useful.
>
>    + Why should -c0 be an error?  It should be valid to request an array
>      of 0 random numbers, just like, say, «yes | head -n 0».
I thought nonsensical options must be an error.
>
>    + Why should -c65 be an error?  (Saw your comment elsethread that you
>      imagine that would suffice.  That's not a good reason for this limit.)
It started as a 256 byte limit from getrandom().
>
>    + Why should -L$(( 2**32 - 1)) be an error?  I should be able to request
>      a random integer in the range { x | 42 ≤ x ≤ 42 }.  It's perfectly
>      well-defined.
if the difference between lower and upper is zero, you get a divide by 
zero error unless you special case it, and it never occurred to me that 
someone would specify that case deliberately
>
> - Why should -c's default depend on anything at all?  You mentioned
>    downthread you consider making -c1 the default in all cases; that'd be
>    better.
>
> - The builtin can generate either integers or bytes.  Most of the API
>    (the type of "returned random data" that -c deals with, the default
>    number of those, validity of -L/-U, etc.) is split right along this
>    line.  Shouldn't this become two separate builtins, then?  One for
>    bytes and one for integers?
>
>    (More on this below, at the end of the implementation review.)
>
> - Interdependencies.  This can generate either bytes or unsigned ints,
>    and bytes can be emitted either in hex, raw, or in decimal, and either
>    to stdout or to a scalar or to an array… but not all of these
>    combinations are possible.  For instance, adding «-a» to «getrandom -c 1»
>    changes the output encoding from hex to decimal AND the output channel
>    from stdout to $reply.  It seems better to avoid coupling things like
>    this.
>
>> +subsect(Parameters)
>> +
>> +startitem()
>> +vindex(SRANDOM)
>> +item(tt(SRANDOM)) (
>> +A random positive 32-bit integer between 0 and 4,294,967,295.  This parameter
>> +is read-only.
>> +)
>> +enditem()
>> +
>> +subsect(Math Functions)
>> +
>> +startitem()
>> +item(tt(zrandom+LPAR()RPAR())) (
> Doesn't this need a findex()?
>
> Do other math functions have index entries?  And if not (systell()
> doesn't), shouldn't they?
>
>> +++ b/Src/Modules/random.c
>> @@ -0,0 +1,675 @@
> There's a whole bunch of orthographic issues in this file (whitespace,
> punctuation, spelling, etc.).  I won't point them out now since there
> are bigger issues.
>
>> +#include <stdbool.h>
> C99-ism.  (zsh is written in C89.)
>
>> +/* buffer to pre-load integers for SRANDOM to lessen the context switches */
>> +uint32_t rand_buff[8];
> C99-ism (the array element type).

I asked about POSIX standards as the dev guide seemed badly out of date 
in workers/50819

Got this response in workers/50847


On Tue, Oct 25, 2022 at 6:52 PM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
 >
 > My personal opinion is that development should use at least the
 > POSIX-1.2001 standard.  It's 20 years old.  That's surely old enough for
 > any system still running.  (It's  certainly old enough that any such
 > system is not supported by the vendor)

OTOH any system not supported by the vendor is exactly one where
somebody might be trying to build their own zsh binary.

That said, I thought we standardized on c99 rather than c89 quite some 
time ago.

>
> Even in C99, wouldn't this require an explicit #include?  I guess it
> works now due to transitive #include's, but I don't know that it's
> guaranteed to work everywhere.
>
>> +getrandom_buffer(void *buf, size_t len)
>> +{
> ⋮
>> +    do {
>> +#ifdef HAVE_ARC4RANDOM
>> +	/* Apparently, the creaters of arc4random didn't believe in errors */
> Leave out the /ad homines/.
>
> FWIW, I would sooner guess arc4random() was originally written on
> a platform where it /couldn't/ error.
>
>> +	arc4random_buf(buf,len);
>> +	ret = len;
>> +#elif defined(HAVE_GETRANDOM)
>> +	ret=getrandom(bufptr,(len - val),0);
>> +#else
>> +	ret=read(randfd,bufptr,(len - val));
> The premise of the module is to offer an interface to high-quality
> random numbers.  Is /dev/urandom, which is the module falls back to
> here, necessarily of sufficient quality?  If not, shouldn't there be
> a way for the module's user to determine the source of randomness?
arc4random and getrandom are just more efficient access to the pool of 
/dev/urandom.   AFAIK it's as good a pseudo-random source as any on any 
platform.
>
>> +#endif
>> +	if (ret < 0) {
>> +	    if (errno != EINTR || errflag || retflag || breaks || contflag) {
>> +		zwarn("Unable to get random data: %e.", errno);
> Need to set «errno = 0» first, surely?
>
>> +/*
>> + * Implements the getrandom builtin to return a string of random bytes of
>> + * user-specified length.  It either prints them to stdout or returns them
>> + * in a parameter passed on the command line.
>> + *
>> + */
>> +
>> +/**/
>> +static int
>> +bin_getrandom(char *name, char **argv, Options ops, int func)
>> +{
> ⋮
>> +    bool integer_out = false;	 /*  boolean */
> The target audience for comments knows C.  So, nuke this comment.
>
> You might define inline enums here (for ints/bytes, scalar/array/stdout,
> and decimal/hex/raw) to make the code more self-documenting.
>
> Incidentally, this would also immediately raise the question of why some
> combinations of these aren't valid (e.g., hex or raw bytes output to an
> array).
>
>> +    int i, j;		         /* loop counters */
>> +
>> +    /*maximum string length of a 32-bit integer + null */
>> +    char int2str[11];
> Have the comment point out that this doesn't include a sign byte?
>
> FWIW, we have a 64-bit version of this in DIGBUFSIZE.
>
>> +    /* Vailues for -U *nd -L */
>> +    zulong   upper = UINT32_MAX, lower = 0;
>> +    uint32_t diff  = UINT32_MAX;
>> +    uint32_t min   = 0, rej = 0;  /* Reject below min and count */
> «rej» is never read.
>
>> +    bool     bound = false;       /* set if upper or lower bound specified */
> Why is this variable needed?  Having it at all means that passing «-L 0
> -U $((2**32-1))» is different to not passing any -L or -U option at all,
> even though these values are ostensibly the defaults.
>
>> +    if (OPT_ISSET(ops, 'U')) {
>> +	if (!zstrtoul_underscore(OPT_ARG(ops, 'U'), &upper)) {
>> +	    zwarnnam(name, "Couldn't convert -U %s to a number.",
>> +		    OPT_ARG(ops, 'U'));
>> +	    return 1;
>> +	} else if (upper > UINT32_MAX || upper < 1) {
>> +	    zwarnnam(name,
>> +		    "Upper bound must be between 1 and %z you specified: %z.",
>> +		     (zlong) UINT32_MAX, (zlong) upper);
> If «upper > ZLONG_MAX», the downcast to zlong would result in
> a negative number.
zwarnnam has no zulong format and upper is supposed to be a 32-bit integer.
>
>> +	    return 1;
> ⋮
>> +    if (bound) {
> ⋮
>> +	if (lower > upper) {
>> +	    zwarnnam(name, "-U must be larger than -L.");
>> +	    return 1;
>> +	}
>> +
>> +	diff = upper == UINT32_MAX && lower == 0 ? UINT32_MAX :
>> +		upper - lower + 1;
> How can this possibly be right?  As written it means the meaning of
> «diff» with the default values of «upper»/«lower» is different to its
> meaning in literally every other case.
>
> Ah, I see.  Without special-casing the default values, explicitly
> passing «-L 0 -U $((2**32 - 1))» would incorrectly trigger the
> zwarnnam() just below, because «diff» is a uint32_t.  Thus, the
> special-casing is an incorrect fix to a real issue.
>
>> +	if(!diff) {
>> +	    zwarnnam(name, "Upper and Lower bounds cannot be the same.");
>> +	    return 1;
>> +	}
> This warning will never be printed.  [Why?  Because «diff» is either
> UINT32_MAX, which is true, or «(uint32_t)(zulong)(upper - lower + 1)»,
> which, taking into account the range checks on «upper» and «lower», can
> only work out to 0 if «upper == UINT32_MAX && lower == 0»… which is
> precisely the case that's special-cased in the assignment to «diff» just
> above.]
>
> I suppose it was intended to be printed for «getrandom -L 42 -U 42».  In
> practice, that incantation just prints 42.  As I mentioned in the API
> review, I think that's desired behaviour.  In either case, please add
> a test.
>
>> +    }
>> +
>> +    if(!OPT_ISSET(ops,'c'))
>> +	if ((!bound && !integer_out) || arrname)
>> +	len = 8;
> So one default value of -c is here and the other is up in the
> declaration of «len».  That's somewhat confusing.
>
>> +
>> +
>> +    if (!byte_len)
>> +	byte_len = len;
> The condition is always true.
>
> Didn't you get a compiler warning for this?
No.  Not in Developer's Studio, clang, gcc, or HP ANSI C.
>
>> +
>> +
>> +    if (bound) {
>> +	pad = len / 16 + 1;
>> +	byte_len = (len + pad) * sizeof(uint32_t);
> «pad» should be declared in this scope since it's not used elsewhere.
> Ditto «outbuff» below and others.
>
> Why «len / 16 + 1»?
I couldn't find any statistical information that would tell me how many 
numbers were likely to be rejected, so I guessed.
>> +    } else if (integer_out)
>> +	byte_len = len * sizeof(uint32_t);
>> +
>> +    if (byte_len > 256)
>> +	byte_len=256;
>> +
> Why not report an error to the user?
>
> ⋮
>> +    min = -diff % diff;
> See above about the special casing in the assignment to «diff».  I guess
> it affects this line.
>
> ⋮
>> +	sprintf(int2str, "%u", int_val);
> Hold on.  %u expects an «unsigned int» and «int_val» is a «uint32_t».
> So, this line is only correct when «unsigned int» happens to be a 32-bit
> type… while there's nothing stopping that type from being a 64-bit type,
> or even a 16-bit type, and in either case this line would read the wrong
> number of bytes off the varargs.
>
>> +	if (arrname) {
>> +	    array[i]=ztrdup(int2str);
>> +	} else if (scalar && len == 1) {
>> +	    setiparam(scalar, int_val);
>> +	} else {
>> +	    printf("%s ",int2str);
>> +	}
>> +    }
>> +    if (arrname) {
>> +	setaparam(arrname,array);
>> +    } else if (!scalar) {
>> +	printf("\n");
>> +    }
>> +
>> +
>> +    zfree(buf, byte_len);
>> +    return 0;
>> +}
>> +
> In the API docs review I proposed to split «getrandom» into two separate
> builtins.
>
> Having read this function, I reiterate that proposal.  This function,
> with all the if/then cases that try to keep track of which of the
> function's different modes of operation was requested, is difficult to
> read and to modify.
>
>> +
>> +/*
>> + * Provides for the SRANDOM parameter and returns an unsigned 32-bit random
>> + * integer.
>> + */
>> +
>> +/**/
>> +static zlong
>> +get_srandom(UNUSED(Param pm)) {
>> +
>> +    if(buf_cnt < 0) {
>> +	getrandom_buffer((void*) rand_buff,sizeof(rand_buff));
>> +	buf_cnt=7;
> Magic number.  You might want «sizeof(rand_buff) / sizeof(rand_buff[0]) - 1»…
>
> …but it'd be more idiomatic to leave that «- 1» out and then change the
> postfix decrement to a prefix decrement.  That would also be more
> consistent with the variable's name.  (As written, «buf_cnt == 0» means
> there's one more zlong in it; it's not a "count" but a "largest valid
> index".)
>
>> +    }
>> +    return rand_buff[buf_cnt--];
>> +}
>> +
>> +/*
>> + * Implements the mathfunc zrandom and returns a random floating-point
>> + * number between 0 and 1.  Does this by getting a random 32-bt integer
>> + * and dividing it by UINT32_MAX.
>> + *
> Presumably this means to guarantee a /uniformly-distributed/ random
> floating-point number in the given range.  So, why does "getting
> a random 32-bit integer and dividing it by UINT32_MAX" actually
> implement that guarantee?
>
> Oh, wait, never mind.  The comment is out of date.  Fix it.
>
>> + */
>> +
>> +/**/
>> +static mnumber
>> +math_zrandom(UNUSED(char *name), UNUSED(int argc), UNUSED(mnumber *argv),
>> +	     UNUSED(int id))
>> +{
>> +    mnumber ret;
>> +    double r;
>> +
>> +    r = random_real();
>> +    if (r < 0) {
>> +	zwarnnam(name, "Failed to get sufficient random data.");
> Say why.  (Probably via errno?)
>
> Rule of thumb: every error message should include at least one replaceable.
>
> (Further instances of this elsewhere in the file.)
>
>> +/**/
>> +int
>> +setup_(UNUSED(Module m))
>> +{
>> +#ifdef USE_URANDOM
>> +    /* Check for the existence of /dev/urandom */
>> +
>> +    struct stat st;
>> +
>> +    if (lstat("/dev/urandom",&st) < 0) {
> Why not stat()?
Is it appropriate for /dev/urandom to be a symlink?
>
>> +	zwarn("No kernel random pool found.");
>> +	return 1;
>> +    }
>> +
>> +    if (!(S_ISCHR(st.st_mode)) ) {
>> +	zwarn("No kernel random pool found.");
>> +	return 1;
>> +    }
>> +#endif /* USE_URANDOM */
>> +    return 0;
>> +}
>> +/**/
>> +int
>> +_zclz64(uint64_t x) {
> ⋮
>> +    if (!(x & 0xFFFFFFFF00000000)) {
> Don't you need ZLONG_CONST() here?
>
>> +/**/
>> +uint64_t
>> +random64(void) {
>> +    uint64_t r;
>> +
>> +    if(getrandom_buffer(&r,sizeof(r)) < 0) {
>> +	zwarn("zsh/random: Can't get sufficient random data.");
>> +	return 1; /* 0 will cause loop */
> Where is the docstring of random64() itself?  /That/ is what determines
> whether or not returning 0 would be correct.
>
> What loops and why?
>
> Also, I suspect this name will collide with a third-party function one
> day.  Recommending to rename.
>
>> +    }
>> +
>> +    return r;
>> +}
>> +
>> +/* Following code is under the below copyright, despite changes for error
>> + * handling and removing GCCisms */
>> +
> -1.  Don't say "Following code"; identify the code explicitly, or better
> yet, move it to its own *.c file.  Otherwise, any function we might
> append to this file would be taken to be covered by this copyright
> notice and license statement.
>
>> +/*
>> + * random_real: Generate a stream of bits uniformly at random and
>> + * interpret it as the fractional part of the binary expansion of a
>> + * number in [0, 1], 0.00001010011111010100...; then round it.
>> + */
>> +
>> +/**/
>> +double
> Need «static».
>
> (Further instances of this elsewhere in the file.)
>
>> +random_real(void)
>> +{
> ⋮
>> +}
>> +++ b/Test/V15random.ztst
>> @@ -0,0 +1,51 @@
>> +# Tests for the zsh/random module
>> +%test
>> +  getrandom -U 56
>> +1f:Checking if system has a kernel random source
>> +?(eval):1: No kernel random pool found.
>> +
> The test point's code has nothing to do with the test point's
> description and expected errput.
>
> The 'f' flag is why this test point's failure doesn't get reported.
The test is supposed to fail.
>
>> +  getrandom -U 64
>> +0:Checking upper Bound is observed
>> +*><0-64>
>> +
>> +  tmpmsg="failed"
>> +  getrandom -L 4 -U 5 -c 16 -a tmpa
>> +  for i in ${tmpa[@]}
>> +  do
>> +    if (( i == 5 )); then
>> +      tmpmsg="success"
>> +      break
>> +    fi
>> +  done
> Use ${tmpa[(I)5]} ?
>
>> +  echo $tmpmsg
>> +0:Checking that upper bound is inclusive
>> +F:Try running the test again: make TESTNUM=V15 check
> Baby and bathwater.  Say what the problem is first and what the
> recommended fix is second.  In this case, something along the lines
> of "This test WILL false positive once every 65536 runs on average.  To
> rule this out, run the test again."
>
> Oh, and bump that 16 to something 3 or 4 times as big, because a 1/65536
> chance isn't really enough in a world where automated builds (CI,
> distros' QA, etc.) is a thing.
>
>> +>success
>> +
>> +  echo $(( zrandom() ))
>> +0:Checking if zrandom() produces a floating-point number between 0 and 1
>> +*>0(|.)[[:digit:]]#
> Why is the period optional?  Something like "042" shouldn't be accepted.
>
>> diff --git a/configure.ac b/configure.ac
>> index 074141d38..f1fa01274 100644
>> --- a/configure.ac
>> +++ b/configure.ac
>> @@ -675,6 +675,7 @@ fi
>>   AC_CHECK_HEADERS(sys/time.h sys/times.h sys/select.h termcap.h termio.h \
>>   		 termios.h sys/param.h sys/filio.h string.h memory.h \
>>   		 limits.h fcntl.h libc.h sys/utsname.h sys/resource.h \
>> +                 sys/random.h \
> Tabs/spaces are wrong.  Also in the next hunk.
>
>>   		 locale.h errno.h stdio.h stdarg.h varargs.h stdlib.h \
>>   		 unistd.h sys/capability.h \
>>   		 utmp.h utmpx.h sys/types.h pwd.h grp.h poll.h sys/mman.h \
>> @@ -1337,6 +1338,7 @@ AC_CHECK_FUNCS(strftime strptime mktime timelocal \
>>   	       cygwin_conv_path \
>>   	       nanosleep \
>>   	       srand_deterministic \
>> +               getrandom arc4random \
>>   	       setutxent getutxent endutxent getutent)
>>   AC_FUNC_STRCOLL
>>   
> Bottom line:
>
> - Interfacing to kernel random number APIs seems reasonable enough.
>
> - The API to shell scripts feels unintuitive.
>
> - As the patch stands, it is not ready to be merged (even assuming
>    arguendo the API is perfect as-is).
>
> Thanks,
>
> Daniel
>



^ permalink raw reply	[relevance 4%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-23  6:59  3%         ` Lawrence Velázquez
@ 2022-11-23  9:43  4%           ` Philippe Altherr
  2022-11-24  4:28  5%             ` Lawrence Velázquez
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-23  9:43 UTC (permalink / raw)
  To: Lawrence Velázquez; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 5105 bytes --]

>
> POSIX does not mandate any behavior for case F unless one treats

anonymous functions as compound commands


I think POSIX indirectly mandates the behavior. So far, there are two
proposals on how to specify anonymous functions:

A) a function call (to a function defined on the spot and undefined right
after the call)
B) a compound command

POSIX mandates the behavior for both, function calls and compound commands.
Therefore, if we opt for one of these two specifications, POSIX also
indirectly mandates the behavior of anonymous functions.

In my opinion, the name and the description of anonymous functions strongly
suggests that anonymous functions are a shorthand for defining a function,
calling it with the provided arguments, and undefining the function. I have
always assumed that "() { <body> } <args>" is syntactic sugar for "anon() {
<body> }; { anon <args> } always { unfunction anon }". As far as I can
tell, Zsh effectively implements anonymous functions with function calls.
If this is indeed the case and one agrees with the specification described
here, then everything is consistent; anonymous functions look, feel, and
behave like function calls, including when it comes to ERR_EXIT, and this
with and without my patches.

You propose to specify anonymous functions as a kind of compound command.
This is of course possible but it's not how anonymous functions currently
behave. As far as I can tell, they currently behave in all aspects,
including ERR_EXIT, as function calls. For ERR_EXIT, see case E, which
behaves like the equivalent function call (case H) and not like the
equivalent compound command (case B). Note that this is true with and
without my patch. Beside the new behavior for ERR_EXIT are there other
aspects of anonymous functions that would/should change? If not, is that
change of specification really worth it? I fear that anonymous functions as
compound commands require a more complicated mental model than anonymous
functions as function calls. For example, if anonymous functions are
compound commands then I would expect that the "return" in the code below
exits the function "foo" but that's not what it does.

foo() {
>   echo foo-start;
>   () { echo args: $@; return } 1 2 3
>   echo foo-end;
> }
> foo


My feeling is that changing anonymous functions to behave like compound
commands adds complexity for little benefit. If it's all about the ERR_EXIT
behavior, does that really matter that much? Is there a use case for
anonymous functions where the compound command ERR_EXIT behavior is
significantly better than the function call ERR_EXIT behavior?

I'd also prefer to post all your patches at once because you attached
> them all to the same zsh-workers article.  Convention has been that a
> series of patches should be sent as a series of articles.


OK, then I will resend my patches in separate emails. This way I can better
document what each one is doing. It will also be easier for you (or whoever
submits patches) to sooner submit the less controversial ones while the
more controversial ones remain open for discussion.

I don't think there's any requirement that the NEWS item arrive at the
> same time as the other three patches.  We sometimes don't add NEWS
> until the time of a release, months (years) after a patch was pushed
> to sourceforge git.


I see. In that case I will start another thread with a patch for the NEWS
item where we can discuss the exact wording.

Philippe


On Wed, Nov 23, 2022 at 7:59 AM Lawrence Velázquez <larryv@zsh.org> wrote:

> On Mon, Nov 21, 2022, at 9:52 PM, Philippe Altherr wrote:
> > To help decide what to do, here is a table that lists all the different
> > cases and how they behave in the current Zsh, in a patched Zsh, and in
> > a patched Zsh where anonymous functions behave as compound commands:
> >
> >    Code                             Current Zsh     Patched Zsh
> > Compound command (and patches)
> > A)         false                    Exit            Exit            Exit
> > B)         false && true            No exit         No exit         No
> > exit
> > C)     {   false && true   }        No exit         No exit         No
> > exit
> > D)  () {   false           }        Exit            Exit            Exit
> > E)  () {   false && true   }        Exit            Exit            *No
> > exit*
> > F)  () { { false && true } }        No Exit         *Exit*
> > No exit
> > G) f() {   false           }; f     Exit            Exit            Exit
> > H) f() {   false && true   }; f     Exit            Exit
> > Exit
> > I) f() { { false && true } }; f     No Exit         *Exit*
> > *Exit*
> >
> > Currently anonymous functions behave like function calls. My patches
> > don't change that but they change/fix cases F and I to behave as
> > mandated by POSIX.
>
> POSIX does not mandate any behavior for case F unless one treats
> anonymous functions as compound commands, in which case the new
> behavior actually violates the standard.
>
> --
> vq
>

[-- Attachment #2: Type: text/html, Size: 6815 bytes --]

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-22 10:17  0%         ` Peter Stephenson
@ 2022-11-23  8:11  3%           ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-11-23  8:11 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Tue, Nov 22, 2022, at 5:17 AM, Peter Stephenson wrote:
> On the whole I think keeping anonymous functions behaving like other functions
> is probably sensible, though we could draw better attention to this unusual
> degree of consistency somewhere in the documentation.
>
> I don't think there's a killer argument for this but if you're using an
> anonymous function it's because you need some form of function behaviour and
> my own inclination would be to continue to provide essentially the whole of it,
> hopefully also limiting special cases in the source code.

There would certainly be value in permitting

    set -e
    foo() { cmd1; cmd2; cmd3 }
    foo
    unset -f foo

to be simplified to

    set -e
    () { cmd1; cmd2; cmd3 }

while maintaining the same early-exit behavior.  That consistency
might be more useful than strict adherence to the syntax-based logic
of POSIX "set -e".  Plus, as Bart noted, the (...) exception has
already set a precedent for special treatment.

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-22  2:52  2%       ` Philippe Altherr
  2022-11-22 10:17  0%         ` Peter Stephenson
@ 2022-11-23  6:59  3%         ` Lawrence Velázquez
  2022-11-23  9:43  4%           ` Philippe Altherr
  1 sibling, 1 reply; 200+ results
From: Lawrence Velázquez @ 2022-11-23  6:59 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: zsh-workers

On Mon, Nov 21, 2022, at 9:52 PM, Philippe Altherr wrote:
> To help decide what to do, here is a table that lists all the different 
> cases and how they behave in the current Zsh, in a patched Zsh, and in 
> a patched Zsh where anonymous functions behave as compound commands:
>
>    Code                             Current Zsh     Patched Zsh     
> Compound command (and patches)
> A)         false                    Exit            Exit            Exit
> B)         false && true            No exit         No exit         No 
> exit
> C)     {   false && true   }        No exit         No exit         No 
> exit
> D)  () {   false           }        Exit            Exit            Exit
> E)  () {   false && true   }        Exit            Exit            *No 
> exit*    
> F)  () { { false && true } }        No Exit         *Exit*            
> No exit
> G) f() {   false           }; f     Exit            Exit            Exit
> H) f() {   false && true   }; f     Exit            Exit            
> Exit    
> I) f() { { false && true } }; f     No Exit         *Exit*            
> *Exit*
>
> Currently anonymous functions behave like function calls. My patches 
> don't change that but they change/fix cases F and I to behave as 
> mandated by POSIX.

POSIX does not mandate any behavior for case F unless one treats
anonymous functions as compound commands, in which case the new
behavior actually violates the standard.

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-22  2:52  2%       ` Philippe Altherr
@ 2022-11-22 10:17  0%         ` Peter Stephenson
  2022-11-23  8:11  3%           ` Lawrence Velázquez
  2022-11-23  6:59  3%         ` Lawrence Velázquez
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2022-11-22 10:17 UTC (permalink / raw)
  To: Philippe Altherr, zsh-workers

On 22/11/2022 02:52 Philippe Altherr <philippe.altherr@gmail.com> wrote:
> Currently anonymous functions behave like function calls. My patches
> don't change that but they change/fix cases F and I to behave as mandated
> by POSIX. If anonymous functions are changed to behave like compound
> commands then anonymous functions behave as if the code was inlined.
> This changes the behavior of case E, which currently exits.

On the whole I think keeping anonymous functions behaving like other functions
is probably sensible, though we could draw better attention to this unusual
degree of consistency somewhere in the documentation.

I don't think there's a killer argument for this but if you're using an
anonymous function it's because you need some form of function behaviour and
my own inclination would be to continue to provide essentially the whole of it,
hopefully also limiting special cases in the source code.

(One possible comparison is Ruby, where you consistently either get "yield
semantics" or "function semantics", though comparing zsh with Ruby feels
wrong at pretty much every other level so this is a very shallow similarity
indeed.)

pws


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  @ 2022-11-22  2:52  2%       ` Philippe Altherr
  2022-11-22 10:17  0%         ` Peter Stephenson
  2022-11-23  6:59  3%         ` Lawrence Velázquez
  0 siblings, 2 replies; 200+ results
From: Philippe Altherr @ 2022-11-22  2:52 UTC (permalink / raw)
  To: Lawrence Velázquez; +Cc: Bart Schaefer, zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3912 bytes --]

>
> Each time though, you've removed the NEWS item.  Although we've
> established that the behavior it describes was not actually
> appropriate, there still has been a change in ERR_EXIT behavior that
> probably warrants a mention.  What's the best description of that?


Good point. There is indeed a behavior change but it's more complicated
than what you described. I will try to come up with something. Actually my
3 fix patches address 3 different issues. In my opinion, at least 2 of them
qualify as bugs but it still makes sense to describe what changes.

This suggests that anonymous
> functions should *not* behave like normal function calls here.


That's debatable. If, like me, you see anonymous functions as some kind of
syntactic sugar, then it makes sense that they behave like function calls
and exit. However, I can also understand that others rather see them as
another type of compound command. In that case, they should not exit.

To help decide what to do, here is a table that lists all the different
cases and how they behave in the current Zsh, in a patched Zsh, and in a
patched Zsh where anonymous functions behave as compound commands:

   Code                             Current Zsh     Patched Zsh
 Compound command (and patches)
A)         false                    Exit            Exit            Exit
B)         false && true            No exit         No exit         No exit
C)     {   false && true   }        No exit         No exit         No exit
D)  () {   false           }        Exit            Exit            Exit
E)  () {   false && true   }        Exit            Exit            *No
exit*
F)  () { { false && true } }        No Exit         *Exit*            No
exit
G) f() {   false           }; f     Exit            Exit            Exit
H) f() {   false && true   }; f     Exit            Exit            Exit
I) f() { { false && true } }; f     No Exit         *Exit*            *Exit*

Currently anonymous functions behave like function calls. My patches don't
change that but they change/fix cases F and I to behave as mandated by
POSIX. If anonymous functions are changed to behave like compound commands
then anonymous functions behave as if the code was inlined. This changes
the behavior of case E, which currently exits.

Is the compound command behavior a reasonable one? Certainly yes. Is it
desirable? I guess that's more debatable. Personally, I am leaning towards
the current behavior. I could be convinced otherwise and for sure I could
live with the alternative.

If you care about code complexity (of the Zsh implementation), then that
would be an argument against the compound command option as it requires
additional code. However, in my opinion, languages should in general NOT be
designed to simplify their implementation but rather to simplify their
usage.

Does it?  These seem to behave identically with Philippe's latest
> patches; am I overlooking something?


No, with my patch "false && true" and "{ false && true}" now always behave
the same.

Frankly I'm
> still not certain that the extra level of { } should matter in the
> function example.


With my patches, they no longer do. Note however that the behaviors of the
following examples, which are unaffected by my patches:

set -e
> { false && true } # does not exit
> () { false && true } # exits


As you can see, with my patches, an extra level of { } no longer changes
any behavior. However, already today, anonymous functions don't always
behave the same as the inlined code.

FYI: Here are my next steps
- Write NEWS for my 3 fixes.
- Better document the role and usage of noerrexit and this_noerrexit.
- Try to fix "eval", "source", and possibly a bunch of other related cases.

Unless anyone sees a reason not to, it would be nice to submit my first
pacth, which reverts Bart's changes. For the other patches, I have at the
very least to first add a NEWS item.

Philippe

[-- Attachment #2: Type: text/html, Size: 6168 bytes --]

^ permalink raw reply	[relevance 2%]

* Re: [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
  2022-11-16 14:40  2% [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements Philippe Altherr
@ 2022-11-19 13:39  0% ` Philippe Altherr
    0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-19 13:39 UTC (permalink / raw)
  To: Zsh hackers list; +Cc: Bart Schaefer, Lawrence Velázquez


[-- Attachment #1.1: Type: text/plain, Size: 1652 bytes --]

I have found that there is an error in the implementation of the negation
statement. Zsh currently fails to print "done" for the following code:

set -e
> fn() { true; }
> ! fn
> echo done $?


Fixing the negation statement allows a slightly simpler fix for function
calls. Instead of my original patch, I recommend submitting the 4 patches
attached here.

Philippe



On Wed, Nov 16, 2022 at 3:40 PM Philippe Altherr <philippe.altherr@gmail.com>
wrote:

> The attached patch fixes the ERR_EXIT behavior in function calls and
> "always" statements. The patch does the following:
>
>    - Revert the following patches, which are based on an unfortunate
>    misunderstanding of the expected behavior of ERR_EXIT:
>       -    50929: fix handling of ERR_RETURN bent by 50928.
>       <https://sourceforge.net/p/zsh/code/ci/8839e969bf8f3f129d0efd8ecd51505610a1f01b/>
>       -    50928: fix tests for 50897, mention behavior change in NEWS
>       <https://sourceforge.net/p/zsh/code/ci/1ba8714a7ac665e661c1b3a716ffe2af73d1e443/>
>          -       I kept the localoptions fix in one of the tests.
>       -    50897: nonzero status of complex commands should trigger
>       ERR_EXIT
>       <https://sourceforge.net/p/zsh/code/ci/d873ed6026d7b0c48d6e65ec06df491d015a4d59/>
>    - Add saving and restoring of local_noerrexit in doshfunc in exec.c
>       - This fixes the ERR_EXIT behavior in function calls.
>    - Add "this_noerrexit = 1;" at the very end of exectry in loop.c
>       - This makes "always" statements compliant with the exception 3 of
>       the POSIX specification of "set -e".
>    - Add new tests in C03traps.ztst
>
> Philippe
>
>

[-- Attachment #1.2: Type: text/html, Size: 2345 bytes --]

[-- Attachment #2: patch-01-revert-mistaken-errexit-patches.txt --]
[-- Type: text/plain, Size: 4234 bytes --]

diff --git a/NEWS b/NEWS
index 9c28169bb..cdafd1ff5 100644
--- a/NEWS
+++ b/NEWS
@@ -4,15 +4,6 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.9
------------------
-
-Handling of ERR_EXIT is corrected when the final status of a structured
-command (for, select, while, repeat, if, case, or a list in braces) is
-nonzero.  To be compatible with other shells, "zsh -e" now exits in
-those circumstances, whereas previous versions did not.  This does not
-affect the handling of nonzero status within conditional statements.
-
 Changes since 5.8.1
 -------------------
 
diff --git a/Src/exec.c b/Src/exec.c
index ce0c1f1ad..b0f42ae67 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -451,7 +451,7 @@ execcursh(Estate state, int do_exec)
     cmdpop();
 
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
@@ -1442,8 +1442,6 @@ execlist(Estate state, int dont_change_job, int exiting)
 		    execsimple(state);
 		else
 		    execpline(state, code, ltype, (ltype & Z_END) && exiting);
-		if (!locallevel || unset(ERRRETURN))
-		    this_noerrexit = noerrexit;
 		state->pc = next;
 		goto sublist_done;
 		break;
diff --git a/Src/loop.c b/Src/loop.c
index be5261369..db5b3e097 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -208,7 +208,7 @@ execfor(Estate state, int do_exec)
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -336,7 +336,7 @@ execselect(Estate state, UNUSED(int do_exec))
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -478,7 +478,7 @@ execwhile(Estate state, UNUSED(int do_exec))
     popheap();
     loops--;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -532,7 +532,7 @@ execrepeat(Estate state, UNUSED(int do_exec))
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -587,7 +587,7 @@ execif(Estate state, int do_exec)
 	    lastval = 0;
     }
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
@@ -701,7 +701,7 @@ execcase(Estate state, int do_exec)
 
     if (!anypatok)
 	lastval = 0;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 5cc45e2de..a7a040d70 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -726,7 +726,8 @@ F:Must be tested with a top-level script rather than source or function
   done
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of for
+0:ERR_EXIT not triggered by status 1 at end of for
+>OK
 
   (setopt err_exit
   integer x=0
@@ -735,7 +736,8 @@ F:Must be tested with a top-level script rather than source or function
   done
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of while
+0:ERR_EXIT not triggered by status 1 at end of while
+>OK
 
   (setopt err_exit
   repeat 1; do
@@ -743,7 +745,8 @@ F:Must be tested with a top-level script rather than source or function
   done
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of repeat
+0:ERR_EXIT not triggered by status 1 at end of repeat
+>OK
 
   (setopt err_exit
   if true; then
@@ -751,7 +754,8 @@ F:Must be tested with a top-level script rather than source or function
   fi
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of if
+0:ERR_EXIT not triggered by status 1 at end of if
+>OK
 
   (setopt err_exit
   {
@@ -759,7 +763,8 @@ F:Must be tested with a top-level script rather than source or function
   }
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of { }
+0:ERR_EXIT not triggered by status 1 at end of { }
+>OK
 
   unsetopt err_exit err_return
   (setopt err_exit

[-- Attachment #3: patch-02-fix-always-statement.txt --]
[-- Type: text/plain, Size: 1517 bytes --]

diff --git a/Src/loop.c b/Src/loop.c
index db5b3e097..7c3e04b8a 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -793,6 +793,7 @@ exectry(Estate state, int do_exec)
     cmdpop();
     popheap();
     state->pc = end;
+    this_noerrexit = 1;
 
     return endval;
 }
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index a7a040d70..4719dfd57 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -721,22 +721,19 @@ F:Must be tested with a top-level script rather than source or function
 >Good
 
   (setopt err_exit
-  for x in y; do
-    false && true
-  done
+  false && true
   print OK
   )
-0:ERR_EXIT not triggered by status 1 at end of for
+0:ERR_EXIT not triggered by "false && true"
 >OK
 
   (setopt err_exit
-  integer x=0
-  while (( ! x++ )); do
+  for x in y; do
     false && true
   done
   print OK
   )
-0:ERR_EXIT not triggered by status 1 at end of while
+0:ERR_EXIT not triggered by status 1 at end of for
 >OK
 
   (setopt err_exit
@@ -755,6 +752,31 @@ F:Must be tested with a top-level script rather than source or function
   print OK
   )
 0:ERR_EXIT not triggered by status 1 at end of if
+>OK
+
+  (setopt err_exit
+  loop=true
+  while print COND; $loop; do
+    loop=false
+    false && true
+  done
+  print OK
+  )
+0:ERR_EXIT not triggered by status 1 at end of while
+>COND
+>COND
+>OK
+
+  (setopt err_exit
+  {
+    false && true
+  } always {
+    print ALWAYS
+  }
+  print OK
+  )
+0:ERR_EXIT not triggered by status 1 at end of always
+>ALWAYS
 >OK
 
   (setopt err_exit

[-- Attachment #4: patch-03-fix-negation-statement.txt --]
[-- Type: text/plain, Size: 1801 bytes --]

diff --git a/Src/exec.c b/Src/exec.c
index b0f42ae67..d8501ca68 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -63,7 +63,10 @@ typedef struct funcsave *Funcsave;
 /**/
 int noerrexit;
 
-/* used to suppress ERREXIT or ERRRETURN for one occurrence: 0 or 1 */
+/*
+ * used to suppress ERREXIT and ERRRETURN for the command under evaluation.
+ * 0 or 1
+ */
 
 /**/
 int this_noerrexit;
@@ -1429,10 +1432,7 @@ execlist(Estate state, int dont_change_job, int exiting)
 	    if (!oldnoerrexit)
 		noerrexit = isend ? 0 : NOERREXIT_EXIT | NOERREXIT_RETURN;
 	    if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) {
-		/* suppress errexit for "! this_command" */
-		if (isend)
-		    this_noerrexit = 1;
-		/* suppress errexit for ! <list-of-shell-commands> */
+		/* suppress errexit for the commands in ! <list-of-commands> */
 		noerrexit = NOERREXIT_EXIT | NOERREXIT_RETURN;
 	    }
 	    switch (WC_SUBLIST_TYPE(code)) {
@@ -1443,6 +1443,9 @@ execlist(Estate state, int dont_change_job, int exiting)
 		else
 		    execpline(state, code, ltype, (ltype & Z_END) && exiting);
 		state->pc = next;
+		/* suppress errexit for the command "! ..." */
+		if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
+		  this_noerrexit = 1;
 		goto sublist_done;
 		break;
 	    case WC_SUBLIST_AND:
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 4719dfd57..08e24a32e 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -720,6 +720,21 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_RETURN in "else" branch in nested function
 >Good
 
+  (setopt err_exit
+  ! true
+  print OK
+  )
+0:ERR_EXIT not triggered by "! true"
+>OK
+
+  (setopt err_exit
+  fn() { true }
+  ! fn
+  print OK
+  )
+0:ERR_EXIT not triggered by "! fn"
+>OK
+
   (setopt err_exit
   false && true
   print OK

[-- Attachment #5: patch-04-fix-function-call.txt --]
[-- Type: text/plain, Size: 3811 bytes --]

diff --git a/Src/exec.c b/Src/exec.c
index d8501ca68..43df8211a 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5932,15 +5932,6 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	     * This function is forced to return.
 	     */
 	    retflag = 0;
-	    /*
-	     * The calling function isn't necessarily forced to return,
-	     * but it should be made sensitive to ERR_EXIT and
-	     * ERR_RETURN as the assumptions we made at the end of
-	     * constructs within this function no longer apply.  If
-	     * there are cases where this is not true, they need adding
-	     * to C03traps.ztst.
-	     */
-	    this_noerrexit = 0;
 	    breaks = funcsave->breaks;
 	}
 	freearray(pparams);
@@ -6010,6 +6001,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	    trap_return++;
 	ret = lastval;
 	noerrexit = funcsave->noerrexit;
+	this_noerrexit = 0;
 	if (noreturnval) {
 	    lastval = funcsave->lastval;
 	    numpipestats = funcsave->numpipestats;
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 08e24a32e..a8880673f 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -742,6 +742,15 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_EXIT not triggered by "false && true"
 >OK
 
+  (setopt err_exit
+  fn() {
+    false && true
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by "false && true" but by return from fn
+
   (setopt err_exit
   for x in y; do
     false && true
@@ -751,6 +760,17 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_EXIT not triggered by status 1 at end of for
 >OK
 
+  (setopt err_exit
+  fn() {
+    for x in y; do
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of for but by return from fn
+
   (setopt err_exit
   repeat 1; do
     false && true
@@ -760,6 +780,17 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_EXIT not triggered by status 1 at end of repeat
 >OK
 
+  (setopt err_exit
+  fn() {
+    repeat 1; do
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of repeat but by return from fn
+
   (setopt err_exit
   if true; then
     false && true
@@ -769,6 +800,17 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_EXIT not triggered by status 1 at end of if
 >OK
 
+  (setopt err_exit
+  fn() {
+    if true; then
+      false && true
+    fi
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of if but by return from fn
+
   (setopt err_exit
   loop=true
   while print COND; $loop; do
@@ -782,6 +824,21 @@ F:Must be tested with a top-level script rather than source or function
 >COND
 >OK
 
+  (setopt err_exit
+  fn() {
+    loop=true
+    while print COND; $loop; do
+      loop=false
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of while but by return from fn
+>COND
+>COND
+
   (setopt err_exit
   {
     false && true
@@ -794,6 +851,20 @@ F:Must be tested with a top-level script rather than source or function
 >ALWAYS
 >OK
 
+  (setopt err_exit
+  fn() {
+    {
+      false && true
+    } always {
+      print ALWAYS
+    }
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of always but by return from fn
+>ALWAYS
+
   (setopt err_exit
   {
     false && true
@@ -803,6 +874,17 @@ F:Must be tested with a top-level script rather than source or function
 0:ERR_EXIT not triggered by status 1 at end of { }
 >OK
 
+  (setopt err_exit
+  fn() {
+    {
+      false && true
+    }
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of { } but by return from fn
+
   unsetopt err_exit err_return
   (setopt err_exit
   for x in y; do

^ permalink raw reply	[relevance 0%]

* [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements
@ 2022-11-16 14:40  2% Philippe Altherr
  2022-11-19 13:39  0% ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-16 14:40 UTC (permalink / raw)
  To: Zsh hackers list; +Cc: Bart Schaefer, Lawrence Velázquez


[-- Attachment #1.1: Type: text/plain, Size: 1147 bytes --]

The attached patch fixes the ERR_EXIT behavior in function calls and
"always" statements. The patch does the following:

   - Revert the following patches, which are based on an unfortunate
   misunderstanding of the expected behavior of ERR_EXIT:
      -    50929: fix handling of ERR_RETURN bent by 50928.
      <https://sourceforge.net/p/zsh/code/ci/8839e969bf8f3f129d0efd8ecd51505610a1f01b/>
      -    50928: fix tests for 50897, mention behavior change in NEWS
      <https://sourceforge.net/p/zsh/code/ci/1ba8714a7ac665e661c1b3a716ffe2af73d1e443/>
         -       I kept the localoptions fix in one of the tests.
      -    50897: nonzero status of complex commands should trigger ERR_EXIT
      <https://sourceforge.net/p/zsh/code/ci/d873ed6026d7b0c48d6e65ec06df491d015a4d59/>
   - Add saving and restoring of local_noerrexit in doshfunc in exec.c
      - This fixes the ERR_EXIT behavior in function calls.
   - Add "this_noerrexit = 1;" at the very end of exectry in loop.c
      - This makes "always" statements compliant with the exception 3 of
      the POSIX specification of "set -e".
   - Add new tests in C03traps.ztst

Philippe

[-- Attachment #1.2: Type: text/html, Size: 1368 bytes --]

[-- Attachment #2: fix-err-exit-behavior-in-function-calls-and-always-statements.txt --]
[-- Type: text/plain, Size: 7027 bytes --]

diff --git a/NEWS b/NEWS
index 9c28169bb..cdafd1ff5 100644
--- a/NEWS
+++ b/NEWS
@@ -4,15 +4,6 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.9
------------------
-
-Handling of ERR_EXIT is corrected when the final status of a structured
-command (for, select, while, repeat, if, case, or a list in braces) is
-nonzero.  To be compatible with other shells, "zsh -e" now exits in
-those circumstances, whereas previous versions did not.  This does not
-affect the handling of nonzero status within conditional statements.
-
 Changes since 5.8.1
 -------------------
 
diff --git a/Src/exec.c b/Src/exec.c
index ce0c1f1ad..b9061e3a4 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -49,7 +49,8 @@ struct funcsave {
     int zoptind, lastval, optcind, numpipestats;
     int *pipestats;
     char *scriptname;
-    int breaks, contflag, loops, emulation, noerrexit, oflags, restore_sticky;
+    int breaks, contflag, loops, emulation, noerrexit, this_noerrexit, oflags;
+    int restore_sticky;
     Emulation_options sticky;
     struct funcstack fstack;
 };
@@ -451,7 +452,7 @@ execcursh(Estate state, int do_exec)
     cmdpop();
 
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
@@ -1442,8 +1443,6 @@ execlist(Estate state, int dont_change_job, int exiting)
 		    execsimple(state);
 		else
 		    execpline(state, code, ltype, (ltype & Z_END) && exiting);
-		if (!locallevel || unset(ERRRETURN))
-		    this_noerrexit = noerrexit;
 		state->pc = next;
 		goto sublist_done;
 		break;
@@ -5763,6 +5762,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	funcsave->pipestats = NULL;
 	funcsave->numpipestats = numpipestats;
 	funcsave->noerrexit = noerrexit;
+	funcsave->this_noerrexit = this_noerrexit;
 	if (trap_state == TRAP_STATE_PRIMED)
 	    trap_return--;
 	/*
@@ -6009,6 +6009,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	    trap_return++;
 	ret = lastval;
 	noerrexit = funcsave->noerrexit;
+	this_noerrexit = funcsave->this_noerrexit;
 	if (noreturnval) {
 	    lastval = funcsave->lastval;
 	    numpipestats = funcsave->numpipestats;
diff --git a/Src/loop.c b/Src/loop.c
index be5261369..7c3e04b8a 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -208,7 +208,7 @@ execfor(Estate state, int do_exec)
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -336,7 +336,7 @@ execselect(Estate state, UNUSED(int do_exec))
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -478,7 +478,7 @@ execwhile(Estate state, UNUSED(int do_exec))
     popheap();
     loops--;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -532,7 +532,7 @@ execrepeat(Estate state, UNUSED(int do_exec))
     loops--;
     simple_pline = old_simple_pline;
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
     return lastval;
 }
 
@@ -587,7 +587,7 @@ execif(Estate state, int do_exec)
 	    lastval = 0;
     }
     state->pc = end;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
@@ -701,7 +701,7 @@ execcase(Estate state, int do_exec)
 
     if (!anypatok)
 	lastval = 0;
-    this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);
+    this_noerrexit = 1;
 
     return lastval;
 }
@@ -793,6 +793,7 @@ exectry(Estate state, int do_exec)
     cmdpop();
     popheap();
     state->pc = end;
+    this_noerrexit = 1;
 
     return endval;
 }
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 5cc45e2de..01d8fa25b 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -721,21 +721,40 @@ F:Must be tested with a top-level script rather than source or function
 >Good
 
   (setopt err_exit
-  for x in y; do
+  false && true
+  print OK
+  )
+0:ERR_EXIT not triggered by "false && true"
+>OK
+
+  (setopt err_exit
+  fn() {
     false && true
-  done
+  }
+  fn
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of for
+1:ERR_EXIT not triggered by "false && true" but by return from fn
 
   (setopt err_exit
-  integer x=0
-  while (( ! x++ )); do
+  for x in y; do
     false && true
   done
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of while
+0:ERR_EXIT not triggered by status 1 at end of for
+>OK
+
+  (setopt err_exit
+  fn() {
+    for x in y; do
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of for but by return from fn
 
   (setopt err_exit
   repeat 1; do
@@ -743,7 +762,19 @@ F:Must be tested with a top-level script rather than source or function
   done
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of repeat
+0:ERR_EXIT not triggered by status 1 at end of repeat
+>OK
+
+  (setopt err_exit
+  fn() {
+    repeat 1; do
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of repeat but by return from fn
 
   (setopt err_exit
   if true; then
@@ -751,15 +782,93 @@ F:Must be tested with a top-level script rather than source or function
   fi
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of if
+0:ERR_EXIT not triggered by status 1 at end of if
+>OK
+
+  (setopt err_exit
+  fn() {
+    if true; then
+      false && true
+    fi
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of if but by return from fn
+
+  (setopt err_exit
+  loop=true
+  while print COND; $loop; do
+    loop=false
+    false && true
+  done
+  print OK
+  )
+0:ERR_EXIT not triggered by status 1 at end of while
+>COND
+>COND
+>OK
+
+  (setopt err_exit
+  fn() {
+    loop=true
+    while print COND; $loop; do
+      loop=false
+      false && true
+    done
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of while but by return from fn
+>COND
+>COND
 
   (setopt err_exit
   {
     false && true
+  } always {
+    print ALWAYS
   }
   print OK
   )
-1:ERR_EXIT triggered by status 1 at end of { }
+0:ERR_EXIT not triggered by status 1 at end of always
+>ALWAYS
+>OK
+
+  (setopt err_exit
+  fn() {
+    {
+      false && true
+    } always {
+      print ALWAYS
+    }
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of always but by return from fn
+>ALWAYS
+
+  (setopt err_exit
+  {
+    false && true
+  }
+  print OK
+  )
+0:ERR_EXIT not triggered by status 1 at end of { }
+>OK
+
+  (setopt err_exit
+  fn() {
+    {
+      false && true
+    }
+  }
+  fn
+  print OK
+  )
+1:ERR_EXIT not triggered by status 1 at end of { } but by return from fn
 
   unsetopt err_exit err_return
   (setopt err_exit

^ permalink raw reply	[relevance 2%]

* Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT)
  2022-11-16  7:56  4%                 ` Philippe Altherr
@ 2022-11-16 14:21  0%                   ` Philippe Altherr
  0 siblings, 0 replies; 200+ results
From: Philippe Altherr @ 2022-11-16 14:21 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 4021 bytes --]

>
> [...] That's the only instance of "errexit shouldn't exit in case Y" that
> I can remember of. Were there others?


Oh and then there was the thread about your patch where I noticed that the
ERR_EXIT was triggered too early. There I commented that in a number of
cases there should be no ERR_EXIT. Unfortunately, I didn't realize that you
had misunderstood the expected behavior. It's only later, when I prepared
my patch, that I realized that you had changed the expected exit status of
some tests.

Philippe


On Wed, Nov 16, 2022 at 8:56 AM Philippe Altherr <philippe.altherr@gmail.com>
wrote:

> [...] Just use ".txt" [...]
>
>
> Yep, I noticed that that's what you did and that this was rendered much
> better on www.zsh.org/. I will do that.
>
> Did using localoptions here break something?
>
>
> I was just about to comment on that. This was automatically reverted when
> I reverted your 3 patches. And it took me a while to figure out why my new
> tests in C03traps were failing. It's only after sending my patch that I
> realized that you too had to fix that issue. And that you did it in a nicer
> way. I will change my patch to use your fix.
>
> I started making all my changes on the premise that "bbb: 1" was
>> incorrect output.
>
>
> Ah, now I understand where the misunderstanding is coming from :-(
>
> After fix-err-exit.patch is applied, the bug.zsh
>> script outputs
>
>
>> aaa: 0
>> bbb: 1
>
>
> Which is what POSIX mandates and also what Bash does.
>
>
>> So my question is, was the whole premise of the thread that started
>> there, incorrect?
>
>
> Yes and no :-( In my original post, I noticed two things
>
> A) "false && true" at the top-level doesn't trigger an ERR_EXIT even
> though it ends in an error and isn't part of a condition.
> B) the call to fun1 doesn't trigger and ERR_EXIT while the call to fun2
> does.
>
> At that time I didn't know about POSIX, nor about its exception 3. I also
> didn't know what Bash was doing (I hadn't thought about comparing Zsh with
> Bash). It was quite clear to me that B was a bug (because in what world
> should fun1 and fun2 behave differently?!?). So it was clear that there
> should be no "ccc: 1" output. I was much less sure about A. Clearly it
> wasn't doing what I wanted but it was much less clear whether it could be
> qualified as a bug. And it turns out that POSIX mandates that there is NO
> ERR_EXIT. So "bbb: 1" is expected.
>
> Your current assertion is that those tests were correct all along,
>> because you've reverted them back to the 5.8.1/5.9 status, so ...
>> they're not a disagreement with bash?
>
>
> Yes, these tests are in agreement with Bash (and POSIX). It's only when
> you modify these tests to move the "false && true" and the surrounding
> statement into a function that you can observe a disagreement between Zsh
> 5.8 and Bash.
>
> Somewhere along the line we pivoted from "errexit isn't exiting in
>> case X" to "errexit shouldn't exit in case Y"
>
>
> Did we? All the bugs were always about cases where Zsh did NOT exit while
> it should.
>
> In the original thread, I mentioned that I would like to have an option
> such that Zsh DOES errexit in a few cases where it currently doesn't, like
> for example after the top-level "false && true" or after "false" in "if
> false; true; then true fi". You and Lawrence opposed that. That's the only
> instance of "errexit shouldn't exit in case Y" that I can remember of. Were
> there others?
>
> (given also Lawrence's remarks RE source and eval)
>
>
> That's again instances of "errexit isn't exiting in case X".
>
> I'm not sure we've yet resolved
>> that any of the approaches to Y are satisfactory for X.
>
>
> If by this you refer to your and Lawrence's opposition to some of the
> changes that I wished, then the answer is no. Neither my patch nor the
> patching of the newly discovered bugs (source and eval) will give me what I
> wish. I will have to come back to that later and try to better explain what
> I would like to get and why.
>
> Philippe
>
>
>

[-- Attachment #2: Type: text/html, Size: 6492 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT)
  @ 2022-11-16  7:56  4%                 ` Philippe Altherr
  2022-11-16 14:21  0%                   ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-16  7:56 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 3276 bytes --]

>
> [...] Just use ".txt" [...]


Yep, I noticed that that's what you did and that this was rendered much
better on www.zsh.org/. I will do that.

Did using localoptions here break something?


I was just about to comment on that. This was automatically reverted when I
reverted your 3 patches. And it took me a while to figure out why my new
tests in C03traps were failing. It's only after sending my patch that I
realized that you too had to fix that issue. And that you did it in a nicer
way. I will change my patch to use your fix.

I started making all my changes on the premise that "bbb: 1" was
> incorrect output.


Ah, now I understand where the misunderstanding is coming from :-(

After fix-err-exit.patch is applied, the bug.zsh
> script outputs


> aaa: 0
> bbb: 1


Which is what POSIX mandates and also what Bash does.


> So my question is, was the whole premise of the thread that started
> there, incorrect?


Yes and no :-( In my original post, I noticed two things

A) "false && true" at the top-level doesn't trigger an ERR_EXIT even though
it ends in an error and isn't part of a condition.
B) the call to fun1 doesn't trigger and ERR_EXIT while the call to fun2
does.

At that time I didn't know about POSIX, nor about its exception 3. I also
didn't know what Bash was doing (I hadn't thought about comparing Zsh with
Bash). It was quite clear to me that B was a bug (because in what world
should fun1 and fun2 behave differently?!?). So it was clear that there
should be no "ccc: 1" output. I was much less sure about A. Clearly it
wasn't doing what I wanted but it was much less clear whether it could be
qualified as a bug. And it turns out that POSIX mandates that there is NO
ERR_EXIT. So "bbb: 1" is expected.

Your current assertion is that those tests were correct all along,
> because you've reverted them back to the 5.8.1/5.9 status, so ...
> they're not a disagreement with bash?


Yes, these tests are in agreement with Bash (and POSIX). It's only when you
modify these tests to move the "false && true" and the surrounding
statement into a function that you can observe a disagreement between Zsh
5.8 and Bash.

Somewhere along the line we pivoted from "errexit isn't exiting in
> case X" to "errexit shouldn't exit in case Y"


Did we? All the bugs were always about cases where Zsh did NOT exit while
it should.

In the original thread, I mentioned that I would like to have an option
such that Zsh DOES errexit in a few cases where it currently doesn't, like
for example after the top-level "false && true" or after "false" in "if
false; true; then true fi". You and Lawrence opposed that. That's the only
instance of "errexit shouldn't exit in case Y" that I can remember of. Were
there others?

(given also Lawrence's remarks RE source and eval)


That's again instances of "errexit isn't exiting in case X".

I'm not sure we've yet resolved
> that any of the approaches to Y are satisfactory for X.


If by this you refer to your and Lawrence's opposition to some of the
changes that I wished, then the answer is no. Neither my patch nor the
patching of the newly discovered bugs (source and eval) will give me what I
wish. I will have to come back to that later and try to better explain what
I would like to get and why.

Philippe

[-- Attachment #2: Type: text/html, Size: 5372 bytes --]

^ permalink raw reply	[relevance 4%]

* Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT)
  @ 2022-11-16  2:41  3%               ` Lawrence Velázquez
    1 sibling, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-11-16  2:41 UTC (permalink / raw)
  To: Philippe Altherr, Bart Schaefer; +Cc: zsh-workers

On Tue, Nov 15, 2022, at 2:18 PM, Philippe Altherr wrote:
> Here is a patch with which all tests pass (the Zsh ones, including the 
> new ones that the patch adds, and my tests mentioned in this thread). 

Here are two additional cases that your patch does not cover.  They
are not regressions, as stable zsh 5.9 is also affected.

As you've mentioned several times, POSIX states:

	If the exit status of a compound command other than a
	subshell command was the result of a failure while -e was
	being ignored, then -e shall not apply to this command.

This implies that ignored non-zero exit statuses may "bubble up"
until reaching a (...) command or a simple command.  You've already
mentioned function calls, but *any* simple command that derives its
exit status from "the last command executed" should be able to
trigger early exit.  At a minimum, this includes the dot/source and
eval commands, neither of which currently behaves correctly.

-----

	% cat /tmp/dotting.sh; echo
	. /tmp/dotted.sh
	echo done

	% cat /tmp/dotted.sh; echo
	if true; then
	    false && true
	fi

	% bash -e /tmp/dotting.sh; echo $?
	1
	% ksh -e /tmp/dotting.sh; echo $?
	1
	% dash -e /tmp/dotting.sh; echo $?
	1
	% yash -e /tmp/dotting.sh; echo $?
	1
	% zsh -e /tmp/dotting.sh; echo $?
	done
	0
	% Src/zsh -e /tmp/dotting.sh; echo $?
	done
	0

-----

	% cat /tmp/eval.sh; echo
	eval 'if true; then false && true; fi'
	echo done

	% bash -e /tmp/eval.sh; echo $?
	1
	% ksh -e /tmp/eval.sh; echo $?
	1
	% dash -e /tmp/eval.sh; echo $?
	1
	% yash -e /tmp/eval.sh; echo $?
	1
	% zsh -e /tmp/eval.sh; echo $?
	done
	0
	% Src/zsh -e /tmp/eval.sh; echo $?
	done
	0

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Even more ERR_EXIT (was Re: More ERR_EXIT Re: Tests RE behavior of ERR_EXIT)
  @ 2022-11-15 19:50  3%               ` Philippe Altherr
  0 siblings, 0 replies; 200+ results
From: Philippe Altherr @ 2022-11-15 19:50 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 2321 bytes --]

As commented in the other thread, code like the following should NOT
trigger an ERR_EXIT (because of exception 3 in the POSIX specification of
"set -e"
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>
).

setopt err_exit
> if true; then
>   false && true
> fi
> print OK


The non-zero status of the "if" statement only triggers an ERR_EXIT if it
becomes the result of a function call. Then the return of the function
triggers the ERR_EXIT, like in the following code:

setopt err_exit
> fn() {
>   if true; then
>     false && true
>   fi
> }
> fn
> print OK


The test exit status changes in 50928: fix tests for 50897, mention
behavior change in NEWS
<https://sourceforge.net/p/zsh/code/ci/1ba8714a7ac665e661c1b3a716ffe2af73d1e443/>
are
incorrect and several tests in the new patch are incorrect.

Philippe


On Tue, Nov 15, 2022 at 8:30 AM Philippe Altherr <philippe.altherr@gmail.com>
wrote:

> Oops, I see this only now, just after sending my other reply. I will have
> a look later. I first need some sleep.
>
> Philippe
>
>
> On Tue, Nov 15, 2022 at 8:01 AM Bart Schaefer <schaefer@brasslantern.com>
> wrote:
>
>> On Mon, Nov 14, 2022 at 5:11 PM Bart Schaefer <schaefer@brasslantern.com>
>> wrote:
>> >
>> > [if workers/50929 makes 50897 redundant then] there's no point in
>> > bashing through if/case/for/while/repeat/select individually -- the
>> > only case we have to fix is this one:
>>
>> I was half right.  Fixing that case revealed that it was necessary to
>> go through the others, because the "redundant" fix is one level too
>> far up the stack.
>>
>> Attached patch removes 50929 again, and amends this_noerrexit from
>> 50897 in each of the complex command exec* functions.  Finally it adds
>> tests to E01options for each of the cases that Philippe previously
>> outlined, with the exception of "select" which is interactive.
>>
>> The tests from 50928 still pass with this patch.  I spent a ridiculous
>> amount of time with every change I made flopping back and forth
>> between C03 working and the new E01 failing and vice-versa, before
>> noticing what happened when I nested a brace expression inside another
>> one.
>>
>> Also a minor fix for TRAPDEBUG that caused me some confusion earlier
>> in the process.
>>
>> Are there more cases that need testing?
>>
>

[-- Attachment #2: Type: text/html, Size: 3555 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT)
  2022-11-12 22:16  3% [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT) Philippe Altherr
@ 2022-11-13  3:59  3% ` Philippe Altherr
    0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-13  3:59 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

[-- Attachment #1: Type: text/plain, Size: 4773 bytes --]

>
> My high-level understanding of exception 3 is that if an error was
> produced by a condition (note that the last command in a sub-list is NOT a
> condition but a regular command), then that error should bubble up the
> evaluation stack, without triggering any ERR_EXIT, until it gets ignored
> (for example on the left of a ";" in a sequence) or it becomes the result
> of an enclosing function or subshell.


In other words, an error produced by a condition should never trigger an
ERR_EXIT unless it becomes the result of a function or of a subshell, in
which case an ERR_EXIT should be triggered at the calling point of the
function or subshell.

I assume that command substitutions play the same role as subshells and may
turn errors from conditions into ERR_EXITs. However, I assume that they
only ever do so if their result isn't ignored. So "v=$(...)" may trigger an
ERR_EXIT but never ": $(...)". I added new tests for that and Bash does
indeed behave like that.

Below is the new set of tests .I dropped the one for always blocks and for
sequences, i.e., all the "foo?3" and "foo?4" tests because they don't
differ from the "foo?2" tests. I also reordered the tests to better group
together the ones that behave correctly.

function foo1AX() {           init;               false
>       ; }
> function foo1AY() { init; v=$(init;               false
>        ); }
> function foo1AZ() { init; : $(init;               false
>        ); }



function foo1BX() {           init;               false && true
>       ; }
> function foo1BY() { init; v=$(init;               false && true
>        ); }
> function foo1BZ() { init; : $(init;               false && true
>        ); }



function foo1CX() {           init;               false && true    ; echo
> foo >&2;  }
> function foo1CY() { init; v=$(init;               false && true    ; echo
> foo >&2); }
> function foo1CZ() { init; : $(init;               false && true    ; echo
> foo >&2); }



function foo2AX() {           init; if true; then false        ; fi
>       ; }
> function foo2AY() { init; v=$(init; if true; then false        ; fi
>        ); }
> function foo2AZ() { init; : $(init; if true; then false        ; fi
>        ); }



function foo2BX() {           init; if true; then false && true; fi
>       ; }
> function foo2BY() { init; v=$(init; if true; then false && true; fi
>        ); }
> function foo2BZ() { init; : $(init; if true; then false && true; fi
>        ); }



function foo2CX() {           init; if true; then false && true; fi; echo
> foo >&2;  }
> function foo2CY() { init; v=$(init; if true; then false && true; fi; echo
> foo >&2); }
> function foo2CZ() { init; : $(init; if true; then false && true; fi; echo
> foo >&2); }


And here are the updated results:


         Zsh 5.8.1              Zsh 5.9.0.1-dev        Bash
> 5.1.16(1)-release



foo1AX   Exit in foo*           Exit in foo*           Exit in foo*
> foo1AY   Exit in $() and foo*   Exit in $() and foo*   Exit in $() and foo*
> foo1AZ   Exit in $()            Exit in $()            Exit in $()



foo1BX   Exit in bar            Exit in bar            Exit in bar
> foo1BY   Exit in foo*           Exit in foo*           Exit in foo*
> foo1BZ   No exit                No exit                No exit



foo1CX   No exit                No exit                No exit
> foo1CY   No exit                No exit                No exit
> foo1CZ   No exit                No exit                No exit



foo2AX   Exit in foo*           Exit in foo*           Exit in foo*
> foo2AY   Exit in $() and foo*   Exit in $() and foo*   Exit in $() and foo*
> foo2AZ   Exit in $()            Exit in $()            Exit in $()



foo2BX   No exit                Exit in foo*           Exit in bar
> foo2BY   Exit in foo*           Exit in $() and foo*   Exit in foo*
> foo2BZ   No exit                Exit in $()            No exit



foo2CX   No exit                Exit in foo*           No exit
> foo2CY   No exit                Exit in $() and foo*   No exit
> foo2CZ   No exit                Exit in $()            No exit


- Bash behaves correctly for all tests (from my understanding of the POSIX
spec).
- Zsh 5.8 and 5.9 behave correctly for all "foo1??" and "foo2A?" tests.
- For all "foo2B?" and "foo2C?" tests, either Zsh 5.8 and/or Zsh 5.9 behave
incorrectly.
- Command substitutions don't seem to have any problem (of their own).
   - In other words, only test foo2BX and foo2CX matter. If they get fixed,
I expect the other ones to be fixed too.
- The problem seems to be related to how "false && true" interacts with
other constructs.
   - In Zsh 5.9 the problem seems to be that compound commands now
incorrectly trigger ERR_EXIT.
   - In Zsh 5.8 I can't pinpoint the problem, for now.

Philippe

[-- Attachment #2: Type: text/html, Size: 9673 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT)
@ 2022-11-12 22:16  3% Philippe Altherr
  2022-11-13  3:59  3% ` Philippe Altherr
  0 siblings, 1 reply; 200+ results
From: Philippe Altherr @ 2022-11-12 22:16 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

[-- Attachment #1: Type: text/plain, Size: 5634 bytes --]

Hi Bart,

I just noticed the following change:

+Changes since 5.9
> +-----------------
> +
> +Handling of ERR_EXIT is corrected
> *when the final status of a structured+command* (for, select, while,
> repeat, if, case, or a list in braces)
> *is+nonzero*.  To be compatible with other shells, *"zsh -e" now exits* in
> +those circumstances, whereas previous versions did not.  This does not
> +affect the handling of nonzero status within conditional statements.


This looks wrong to me. It's not compatible with the third exception of POSiX
"set -e"
<https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#set>
:

When this option is on, when any command fails (for any of the reasons
> listed in Consequences of Shell Errors or by returning an exit status
> greater than zero), the shell immediately shall exit, as if by executing
> the exit special built-in utility with no arguments, with the following
> exceptions:
>
>    1. The failure of any individual command in a multi-command pipeline
>    shall not cause the shell to exit. Only the failure of the pipeline itself
>    shall be considered.
>    2. The -e setting shall be ignored when executing the compound list
>    following the while, until, if, or elif reserved word, a pipeline beginning
>    with the ! reserved word, or any command of an AND-OR list other than the
>    last.
>    3. *If the exit status of a compound command other than a subshell
>    command was the result of a failure while -e was being ignored, then -e
>    shall not apply to this command.*
>
> My high-level understanding of exception 3 is that if an error was
produced by a condition (note that the last command in a sub-list is NOT a
condition but a regular command), then that error should bubble up the
evaluation stack, without triggering any ERR_EXIT, until it gets ignored
(for example on the left of a ";" in a sequence) or it becomes the result
of an enclosing function or subshell.

Let's consider the following example:

function foo() { if true; then false && true; fi }
> function bar() { foo }
> bar


Exception 2 tells us that "false && true" shouldn't trigger an ERR_EXIT. By
exception 3, the resulting exit status becomes the result, first of the
enclosing if, and then of the enclosing {}, without triggering an ERR_EXIT.
It's only in function "bar" that an "ERR_EXIT" should be triggered because
the call to "foo" returns 1 and function calls aren't compound commands.

Zsh 5.8.1, doesn't trigger any ERR_EXIT for this example. Zsh 5.9.*, with
your latest changes, triggers an ERR_EXIT in "foo". Bash 5.1.16 triggers an
ERR_EXIT in "bar". My understanding is that Bash is right.

Here is the script that I used to test this behavior with Zsh and Bash (for
bash you have to comment out the "foo?3" tests):

# test.zsh
> # Usage: test.zsh A1|...|A4|B1|...|B4|C1|...|C4
> #
> # Example: "test.zsh A1" runs the test for "fooA1".


> set -e


> function err-exit() {
>     local error=$?;
>     # Print where ERR_EXIT was called from.
>     if [[ -n $ZSH_VERSION ]]; then
>         local file=${funcfiletrace[1]%:*}
>         local line=${funcfiletrace[1]#*:}
>     elif [[ -n $BASH_VERSION ]]; then
>         local caller=$(caller 0);
>         local file=${caller##* }
>         local line=${caller%% *}
>     fi
>     echo "Caught error $error at $file:$line: $(cat $file | head -$line |
> tail -1)" >&2
>     return $error;
> }


> trap err-exit ERR
> if [[ -n $ZSH_VERSION ]]; then
>     alias init=''
> elif [[ -n $BASH_VERSION ]]; then
>     # It looks like in Bash the ERR trap must be set in every function
>     shopt -s expand_aliases
>     alias init='trap err-exit ERR'
> fi


> function fooA1() { init;               false        ;
>           }
> function fooA2() { init; if true; then false        ; fi
>          }
> function fooA3() { init;             { false        ; } always { true; }
>          }
> function fooA4() { init;             { false        ; }
>           }


> function fooB1() { init;               false && true;
>           }
> function fooB2() { init; if true; then false && true; fi
>          }
> function fooB3() { init;             { false && true; } always { true; }
>          }
> function fooB4() { init;             { false && true; }
>           }


> function fooC1() { init;               false && true                    ;
> echo foo; }
> function fooC2() { init; if true; then false && true; fi                ;
> echo foo; }
> function fooC3() { init;             { false && true; } always { true; };
> echo foo; }
> function fooC4() { init;             { false && true; }                 ;
> echo foo; }


> function bar() {
>     init
>     echo Start
>     foo$1
>     echo End
> }


> bar "$@"


I included the "foo?3" tests because all the compound commands in loop.c
seem to behave the same except for "exectry", which lacks the following
line:

  this_noerrexit = (WC_SUBLIST_TYPE(*end) != WC_SUBLIST_END);


 I included the "foo?4" tests because sequences are not handled by one of
the functions in loop.c but by some function in exec.c. However, all
"foo?3" and "foo?4" tests nevertheless behave the same as the matching
"foo?2" tests.

Here are the results:

        Zsh 5.8.1      Zsh 5.9.*      Bash 5.1.16



fooA1   Exit in foo*   Exit in foo*   Exit in foo*
> fooA2   Exit in foo*   Exit in foo*   Exit in foo*



fooB1   Exit in bar    Exit in bar    Exit in bar
> fooB2   No exit        Exit in foo*   Exit in bar



fooC1   No exit        No exit        No exit
> fooC2   No exit        Exit in foo*   No exit


My understanding is that Bash's behavior is the correct one.

Philippe

[-- Attachment #2: Type: text/html, Size: 12162 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: Inconsistent behavior of ERR_EXIT with conditionals
  2022-11-08 23:28  4%             ` Bart Schaefer
@ 2022-11-09  4:11  4%               ` Philippe Altherr
  0 siblings, 0 replies; 200+ results
From: Philippe Altherr @ 2022-11-09  4:11 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Lawrence Velázquez, zsh-workers

[-- Attachment #1: Type: text/plain, Size: 4100 bytes --]

>
> All of 1,3,4 are fixed by my patch in workers/50897


That's great! It's a small win but I actually (re-)stumbled on the problem
of conditional expressions because of one of these cases. So it's good to
see that they can be fixed.


My ultimate goal is to be able to run Zsh scripts with the guarantee that
if any command unexpectedly fails (i.e., if any command whose result is not
otherwise checked returns a non-zero exit status), then the whole *script* (not
just some subshells) stops immediately. Wouldn't you agree that this would
be a useful feature?

The question is how can this be achieved. On the surface, it looks like
enabling ERR_EXIT does the trick. However there are several cases where
ERR_EXIT fails to do the job. These cases are of two categories:

   1. *Non-triggering:* In some contexts, commands whose result is not
   otherwise checked don't trigger a shell exit when they return a non-zero
   exit status even when ERR_EXIT is enabled, e.g., the "false" command in
   "{false; true} && true" doesn't trigger a shell exit.
   2. *Non-propagation:* In some contexts, errors in subshells don't
   propagate to the parent shell, e.g., the "false" in "local var=$(false)"
   triggers an exit in the subshell of the command substitution but the
   assignment ignores the result of the command substitution and thus the
   parent shell fails to exit in turn.

I hoped that some of these cases could be "fixed" but I have now checked
the POSIX specification and as you both pointed out, for most of them POSIX
specifies that they have to work as they currently do (this doesn't include
Lawrence's example 1,3,4, which should indeed be fixed).

The first developer is wrong.  That's not what -e is for.  A script
> should be correct WITHOUT the use of -e ... the purpose of -e is to
> uncover cases where the developer made a mistake, not to be an
> integral part of the script function.


I can agree with that but consider that the developer's mistake was to use
a ";" instead of an "&&" in the "backup" function. My broader point was
that the same error (or developer mistake) in a function "foo" triggers an
exit if "foo" is called from a plain statement but not if it's called from
within a condition. Wouldn't you agree that it's unfortunate that the same
error/mistake may or may not trigger an exit depending on whether it's
executed outside or inside a condition?

Again, wrong.  "{ false; true }" is a single statement because of the
> braces.  When that statement is followed by || the result of the
> ENTIRE statement is considered to have been "checked".
> Similarly, in "if false; true; then" the conditional part is
> considered as a single statement whose result is "checked".


Indeed, POSIX states "The -e setting shall be ignored when executing the
compound list following the while, until, if, or elif reserved word, a
pipeline beginning with the ! reserved word, or any command of an AND-OR
list other than the last.", so there is unfortunately no way this can be
changed, at least in the context of ERR_EXIT.


Is all hope lost? Not necessarily. The non-propagation issues can be worked
around. That's what my zabort
<https://github.com/paltherr/zabort/blob/main/src/bin/zabort.zsh> does by
configuring a ZERR trap that forcibly kills all parent shells from within
the subshell where the error occurred. Unfortunately, I don't see how the
non-triggering issues could be worked around. For these some change is
needed in Zsh but I agree that changing the behavior of ERR_EXIT isn't the
way to go as it should remain POSIX compliant. What could work is to
implement a new shell option ERR_EXIT_STRICT, which triggers an exit on any
command that returns a non-zero exit status and whose result isn't checked
otherwise. Only one of ERR_EXIT and ERR_EXIT_STRICT could be enabled at any
given time.

*Would you agree to add a new shell option if it allows to run Zsh scripts
such that if any command unexpectedly fails the script immediately stops
(and its implementation doesn't require too complex changes)?* If yes, I
may look into implementing it.

Philippe

[-- Attachment #2: Type: text/html, Size: 5132 bytes --]

^ permalink raw reply	[relevance 4%]

* [PATCH] diff for test harness (was: There seems to be a problem with the test harness on Solaris 11.4)
  2022-11-07 19:39  0%           ` Clinton Bunch
@ 2022-11-09  3:29  0%             ` Clinton Bunch
  0 siblings, 0 replies; 200+ results
From: Clinton Bunch @ 2022-11-09  3:29 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 838 bytes --]

On 11/7/2022 1:39 PM, Clinton Bunch wrote:
> On 11/6/2022 1:32 PM, Clinton Bunch wrote:
>> On 11/6/2022 1:09 PM, Bart Schaefer wrote:
>>> On Sun, Nov 6, 2022 at 10:35 AM Clinton Bunch <cdb_zsh@zentaur.org> 
>>> wrote:
>>>> Solaris 11.4 at least also has GNU diff as gdiff.
>>> Use of "diff -a" hasn't changed since at least 2017.  Is it possible
>>> that there's been a default (or your own) PATH change causing the
>>> POSIX diff to be found in preference?
>>>
>>
>>
>>
> I'm working on a patch to check if diff supports -a, check if gdiff is 
> in the path.  If both of those fail, do we want to run without -a or 
> abort and kindly suggest they install GNU diff?
>
Here's a patch that has configure check for an appropriate diff in the 
path and if it fails to find one runs diff without -a in the test harness


[-- Attachment #2: zsh-diff-a.patch --]
[-- Type: text/plain, Size: 2064 bytes --]

diff --git a/Config/defs.mk.in b/Config/defs.mk.in
index 2bc17482a..c979307f7 100644
--- a/Config/defs.mk.in
+++ b/Config/defs.mk.in
@@ -75,6 +75,7 @@ IMPOPT          = @IMPOPT@
 
 # utilities
 AWK             = @AWK@
+DIFF            = @DIFF@
 ANSI2KNR        = @ANSI2KNR@
 YODL            = @YODL@ @YODL_OPTIONS@
 YODL2TXT        = @YODL@2txt
diff --git a/Test/Makefile.in b/Test/Makefile.in
index 09f37bf53..636746a45 100644
--- a/Test/Makefile.in
+++ b/Test/Makefile.in
@@ -53,6 +53,7 @@ check test:
 	if ZTST_testlist="`for f in $(sdir)/$(TESTNUM)*.ztst; \
            do echo $$f; done`" \
 	 ZTST_srcdir="$(sdir)" \
+	 ZTST_diff_pg="$(DIFF)" \
 	 ZTST_exe=$(dir_top)/Src/zsh@EXEEXT@ \
 	 $(dir_top)/Src/zsh@EXEEXT@ +Z -f $(sdir)/$$ZTST_handler; then \
 	 stat=0; \
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index ea1b016d5..96a138483 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -382,7 +382,7 @@ ZTST_diff() {
       diff_ret=1
     fi
   else
-    diff_out=$(diff -a "$@")
+    diff_out=$(${=ZTST_diff_pg}  "$@")
     diff_ret="$?"
     if [[ "$diff_ret" != "0" ]]; then
       print -r -- "$diff_out"
diff --git a/configure.ac b/configure.ac
index 074141d38..7e9426148 100644
--- a/configure.ac
+++ b/configure.ac
@@ -611,6 +611,19 @@ AC_PROG_AWK                 dnl Check for mawk,gawk,nawk, then awk.
 AC_PROG_LN                  dnl Check for working ln, for "make install"
 AC_PROG_LN_S                dnl Use ln -s/ln/cp for "make install.runhelp"
 AC_PROG_EGREP               dnl sets $EGREP to grep -E or egrep
+
+dnl check for diff that supports -a
+AC_CACHE_CHECK([for diff that supports -a],[ac_cv_path_DIFF],
+    [AC_PATH_PROGS_FEATURE_CHECK([DIFF],[diff gdiff],
+       [[
+	    echo "abcdef" > conftest.$$
+	    echo "abcdef" > conftest2.$$
+	    $ac_path_DIFF -a conftest.$$ conftest2.$$ > /dev/null 2>&1
+	    test "x$?" = x0 \
+            && ac_cv_path_DIFF="$ac_path_DIFF -a" ac_path_DIFF_found=:]],
+	[ac_cv_path_DIFF="diff"])])
+AC_SUBST([DIFF],[$ac_cv_path_DIFF])
+
 AC_CHECK_PROGS([YODL], [yodl], [: yodl])
 
 YODL_OPTIONS=''

^ permalink raw reply	[relevance 0%]

* Re: Inconsistent behavior of ERR_EXIT with conditionals
    2022-11-08 19:20  4%             ` Lawrence Velázquez
@ 2022-11-08 23:28  4%             ` Bart Schaefer
  2022-11-09  4:11  4%               ` Philippe Altherr
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2022-11-08 23:28 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: Lawrence Velázquez, zsh-workers

On Tue, Nov 8, 2022 at 10:51 AM Philippe Altherr
<philippe.altherr@gmail.com> wrote:
>
> Let me try to illustrate with a more concrete example why I think Zsh's behavior could/should be improved. Consider that a first developer wrote the following code:
>
>> #!/bin/zsh -e

The first developer is wrong.  That's not what -e is for.  A script
should be correct WITHOUT the use of -e ... the purpose of -e is to
uncover cases where the developer made a mistake, not to be an
integral part of the script function.

> On Tue, Nov 8, 2022, at 12:36 AM, Bart Schaefer wrote:
>>
>> ERR_EXIT kicks in only when the result is not otherwise checked.
>
> Unfortunately there are several cases where Zsh doesn't behave like that. For example, consider the following commands:
>
>> { false; true } || true; echo $?
>> if false; true; then echo 0; else echo 1; fi

Again, wrong.  "{ false; true }" is a single statement because of the
braces.  When that statement is followed by || the result of the
ENTIRE statement is considered to have been "checked".
Similarly, in "if false; true; then" the conditional part is
considered as a single statement whose result is "checked".

As Lawrence has said, you're discarding the POSIX definition of how
"set -e" is intended to work.

> There are other cases where ERR_EXIT is triggered but fails to propagate. A major offender in that regard is the following code:
>
>> local var=$(false); echo $?
>
> In this case "false" triggers an ERR_EXIT but it only exits the sub-shell of the command substitution.

This is explicitly called out in the documentation:

     Unlike parameter assignment statements, typeset's exit status on an
     assignment that involves a command substitution does not reflect
     the exit status of the command substitution.  Therefore, to test
     for an error in a command substitution, separate the declaration of
     the parameter from its initialization:

          # WRONG
          typeset var1=$(exit 1) || echo "Trouble with var1"

          # RIGHT
          typeset var1 && var1=$(exit 1) || echo "Trouble with var1"

> However, having to systematically use this style is rather cumbersome. Furthermore it's not even foolproof. Indeed, if there are multiple command substitutions, the assignment returns the exit status of the last one. Thus, the following command does NOT exit and prints "0":
>
>> local var; var=$(false)$(true); echo $?

This also follows bash and presumably POSIX behavior.

> Is there any chance that Zsh could be changed to more closely follow the specification above?

No.


^ permalink raw reply	[relevance 4%]

* Re: Inconsistent behavior of ERR_EXIT with conditionals
  @ 2022-11-08 19:20  4%             ` Lawrence Velázquez
  2022-11-08 23:28  4%             ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-11-08 19:20 UTC (permalink / raw)
  To: Philippe Altherr; +Cc: Bart Schaefer, zsh-workers

On Tue, Nov 8, 2022, at 1:51 PM, Philippe Altherr wrote:
> *Is there any chance that Zsh could be changed to more closely follow 
> the specification above? *

I don't have time right now to provide more tests or otherwise
elaborate, but I am pretty sure that no shell exhibits the behavior
you want, and I am *very* sure that said behavior would violate
POSIX in one way or another.  I know that zsh does not aim for POSIX
compliance, but that doesn't mean it ought to take a feature which
is currently highly compatible with other shells and change it to
be completely incompatible.

I strongly object to any of these proposed changes, except ones
that bring zsh into closer alignment with other shells.  (These are
arguably bugfixes.)

-- 
vq


^ permalink raw reply	[relevance 4%]

* Re: Inconsistent behavior of ERR_EXIT with conditionals
  @ 2022-11-08  8:04  3%         ` Lawrence Velázquez
    0 siblings, 1 reply; 200+ results
From: Lawrence Velázquez @ 2022-11-08  8:04 UTC (permalink / raw)
  To: Bart Schaefer, Philippe Altherr; +Cc: zsh-workers

On Tue, Nov 8, 2022, at 12:36 AM, Bart Schaefer wrote:
> So you can see that zsh agrees with bash on your "Failure" cases.  The
> output of dash (as /bin/sh on ubuntu) is the same as zsh with the
> exception of Failure-b, which can't be tested because there is no
> equivalent of "declare" (or "local").

Here is a set of tests incorporating most of Philippe's examples
(some slightly modified).  In the output, "no" and "yes" are intended
to indicate whether the shell exited due to "set -e" / ERR_EXIT.
The tl;dr is that zsh agrees with other shells, except on three
constructs from Philippe's original email.

The shells I tested are zsh 5.9, bash 5.1.16(1)-release, ksh AJM
93u+ 2012-08-01, dash 0.5.11.5, and yash 2.52.  For more fun, see
<https://www.in-ulm.de/~mascheck/various/set-e/>.

	% head -n 100 *.sh(n) driver.zsh
	==> 1.sh <==
	f() {
	    { false && true; }
	}
	f
	printf '    no'

	==> 2.sh <==
	f() {
	    false && true
	}
	f
	printf '    no'

	==> 3.sh <==
	f() {
	    if true; then
	        false && true
	    fi
	}
	f
	printf '    no'

	==> 4.sh <==
	f() {
	    case foo in
	        *) false && true ;;
	    esac
	}
	f
	printf '    no'

	==> 5.sh <==
	f() {
	    (false && true)
	}
	f
	printf '    no'

	==> 6.sh <==
	: $(false)
	printf '    no'

	==> 7.sh <==
	if [ "$KSH_VERSION" ]; then
	    f() { typeset v=$(false); }
	else
	    f() { local v=$(false); }
	fi
	f
	printf '    no'

	==> 8.sh <==
	if
	    false
	    printf '    no'
	    true
	then
	    true
	fi

	==> 9.sh <==
	{
	    false
	    printf '    no'
	    true
	} && true

	==> 10.sh <==
	false && true
	printf '    no'

	==> 11.sh <==
	! true
	printf '    no'

	==> driver.zsh <==
	set -- *.sh(n)

	printf '     '
	printf ' %5s' $@
	echo

	for sh in zsh bash ksh dash yash; do
	    printf %4s: $sh
	    for arg; do
	        $sh -e $arg || printf '   yes'
	    done
	    echo
	done
	% zsh driver.zsh
	       1.sh  2.sh  3.sh  4.sh  5.sh  6.sh  7.sh  8.sh  9.sh 10.sh 11.sh
	 zsh:    no   yes    no    no   yes    no    no    no    no    no    no
	bash:   yes   yes   yes   yes   yes    no    no    no    no    no    no
	 ksh:   yes   yes   yes   yes   yes    no    no    no    no    no    no
	dash:   yes   yes   yes   yes   yes    no    no    no    no    no    no
	yash:   yes   yes   yes   yes   yes    no    no    no    no    no    no


> Bash disagrees with dash and
> zsh on your "Success" cases, at least at that version.

Bash disables "set -e" in command substitutions and has done so
since at least 1.14 (the oldest version I can test).  Bash 4.4 added
an option that causes command substitutions to inherit "set -e",
but it remains disabled by default (except in POSIX mode).


-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: There seems to be a problem with the test harness on Solaris 11.4
  2022-11-06 19:32  0%         ` Clinton Bunch
@ 2022-11-07 19:39  0%           ` Clinton Bunch
  2022-11-09  3:29  0%             ` [PATCH] diff for test harness (was: There seems to be a problem with the test harness on Solaris 11.4) Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-11-07 19:39 UTC (permalink / raw)
  To: zsh-workers

On 11/6/2022 1:32 PM, Clinton Bunch wrote:
> On 11/6/2022 1:09 PM, Bart Schaefer wrote:
>> On Sun, Nov 6, 2022 at 10:35 AM Clinton Bunch <cdb_zsh@zentaur.org> 
>> wrote:
>>> Solaris 11.4 at least also has GNU diff as gdiff.
>> Use of "diff -a" hasn't changed since at least 2017.  Is it possible
>> that there's been a default (or your own) PATH change causing the
>> POSIX diff to be found in preference?
>>
>
>
>
I'm working on a patch to check if diff supports -a, check if gdiff is 
in the path.  If both of those fail, do we want to run without -a or 
abort and kindly suggest they install GNU diff?



^ permalink raw reply	[relevance 0%]

* Re: There seems to be a problem with the test harness on Solaris 11.4
  2022-11-06 19:09  3%       ` Bart Schaefer
@ 2022-11-06 19:32  0%         ` Clinton Bunch
  2022-11-07 19:39  0%           ` Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-11-06 19:32 UTC (permalink / raw)
  To: zsh-workers

On 11/6/2022 1:09 PM, Bart Schaefer wrote:
> On Sun, Nov 6, 2022 at 10:35 AM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>> Solaris 11.4 at least also has GNU diff as gdiff.
> Use of "diff -a" hasn't changed since at least 2017.  Is it possible
> that there's been a default (or your own) PATH change causing the
> POSIX diff to be found in preference?
>
I haven't changed the default path on this system yet.  To get GNU diff 
as diff you'd have to add /usr/gnu/bin to the path, and I doubt that's 
been in the standard path.  I'm not positive it wasn't pulled in as a 
prereq when I installed autoconf from the standard package repository.

I think it's possible that only a few people have run the tests on 
Solaris in the last 5 years and either had /usr/gnu/bin in their path 
(not exactly unexpected from someone who'd try to build their own shell) 
or they just didn't report the failure.

Especially since it ships with a version of zsh (5.3.1), a lot of people 
wouldn't feel the need to build their own.



^ permalink raw reply	[relevance 0%]

* Re: There seems to be a problem with the test harness on Solaris 11.4
  @ 2022-11-06 19:09  3%       ` Bart Schaefer
  2022-11-06 19:32  0%         ` Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-11-06 19:09 UTC (permalink / raw)
  To: Clinton Bunch; +Cc: zsh-workers

On Sun, Nov 6, 2022 at 10:35 AM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>
> Solaris 11.4 at least also has GNU diff as gdiff.

Use of "diff -a" hasn't changed since at least 2017.  Is it possible
that there's been a default (or your own) PATH change causing the
POSIX diff to be found in preference?


^ permalink raw reply	[relevance 3%]

* Re: Minimum POSIX standard
  2022-10-26 20:48  5%           ` Clinton Bunch
@ 2022-10-27  7:40  5%             ` Štěpán Němec
  0 siblings, 0 replies; 200+ results
From: Štěpán Němec @ 2022-10-27  7:40 UTC (permalink / raw)
  To: Clinton Bunch; +Cc: zsh-workers

On Wed, 26 Oct 2022 15:48:14 -0500
Clinton Bunch wrote:

> I swear though, I did try to search the ML archives for an answer
> before posting the question, but the search feature leaves much to be
> desired.

There's a public-inbox instance on https://inbox.vuxu.org which
includes the Zsh mailing lists. E.g.:

  https://inbox.vuxu.org/zsh-workers/?q=POSIX&o=-1

(See https://inbox.vuxu.org/zsh-workers/_/text/help/ for explanation of
the search syntax and other things.)

-- 
Štěpán


^ permalink raw reply	[relevance 5%]

* Re: Minimum POSIX standard
  2022-10-26 20:44  5%         ` Bart Schaefer
@ 2022-10-26 20:48  5%           ` Clinton Bunch
  2022-10-27  7:40  5%             ` Štěpán Němec
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-10-26 20:48 UTC (permalink / raw)
  To: zsh-workers


On 10/26/2022 3:44 PM, Bart Schaefer wrote:
> On Wed, Oct 26, 2022 at 1:41 PM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>> Maybe I missed it, but the development guide kept talking about C89 and
>> not confusing K&R compilers from what I read.
> Hm.  I would suspect that just means the development guide is sorely
> lacking attention.

I wouldn't be surprised after reading the git log.

I swear though, I did try to search the ML archives for an answer before 
posting the question, but the search feature leaves much to be desired.



^ permalink raw reply	[relevance 5%]

* Re: Minimum POSIX standard
  2022-10-26 20:39  5%       ` Clinton Bunch
@ 2022-10-26 20:44  5%         ` Bart Schaefer
  2022-10-26 20:48  5%           ` Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-10-26 20:44 UTC (permalink / raw)
  To: Clinton Bunch; +Cc: zsh-workers

On Wed, Oct 26, 2022 at 1:41 PM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>
> Maybe I missed it, but the development guide kept talking about C89 and
> not confusing K&R compilers from what I read.

Hm.  I would suspect that just means the development guide is sorely
lacking attention.


^ permalink raw reply	[relevance 5%]

* Re: Minimum POSIX standard
  2022-10-26 20:18  5%     ` Bart Schaefer
@ 2022-10-26 20:39  5%       ` Clinton Bunch
  2022-10-26 20:44  5%         ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-10-26 20:39 UTC (permalink / raw)
  To: zsh-workers


On 10/26/2022 3:18 PM, Bart Schaefer wrote:
> On Tue, Oct 25, 2022 at 6:52 PM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>> My personal opinion is that development should use at least the
>> POSIX-1.2001 standard.  It's 20 years old.  That's surely old enough for
>> any system still running.  (It's  certainly old enough that any such
>> system is not supported by the vendor)
> OTOH any system not supported by the vendor is exactly one where
> somebody might be trying to build their own zsh binary.
Trust me, they're used to the frustration and having to settle for older 
versions.  I never could get a gcc version more recent that 4.9 to build 
on HP-UX. And that's still technically supported. (Practically OTOH) :)
>
> That said, I thought we standardized on c99 rather than c89 quite some time ago.
Maybe I missed it, but the development guide kept talking about C89 and 
not confusing K&R compilers from what I read.


^ permalink raw reply	[relevance 5%]

* Re: Minimum POSIX standard
  2022-10-26  1:51  9%   ` Clinton Bunch
@ 2022-10-26 20:18  5%     ` Bart Schaefer
  2022-10-26 20:39  5%       ` Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-10-26 20:18 UTC (permalink / raw)
  To: Clinton Bunch; +Cc: zsh-workers

On Tue, Oct 25, 2022 at 6:52 PM Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>
> My personal opinion is that development should use at least the
> POSIX-1.2001 standard.  It's 20 years old.  That's surely old enough for
> any system still running.  (It's  certainly old enough that any such
> system is not supported by the vendor)

OTOH any system not supported by the vendor is exactly one where
somebody might be trying to build their own zsh binary.

That said, I thought we standardized on c99 rather than c89 quite some time ago.


^ permalink raw reply	[relevance 5%]

* Re: Minimum POSIX standard
  2022-10-23 21:57  5% ` Mikael Magnusson
@ 2022-10-26  1:51  9%   ` Clinton Bunch
  2022-10-26 20:18  5%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-10-26  1:51 UTC (permalink / raw)
  To: zsh-workers

On 10/23/2022 4:57 PM, Mikael Magnusson wrote:
> On 10/23/22, Clinton Bunch <cdb_zsh@zentaur.org> wrote:
>> What is the minimum POSIX standard modern Zsh code is intended to
>> conform to?
> As far as I'm aware, none.
>
Don't you think there should be?  The guidelines in the Development 
guide are somewhat vague and were apparently written more than 20 years 
ago.  (git log puts the first revision at 1999 and the updates seem to 
address git usage, typos, and module documentation)

Someone writing new code should have a baseline for what functions and 
types can be used without #ifdefs, autoconf tests and roll-your-own 
backup functions.  Something more recent than the C89 standard library 
with all it's flaws.  Are people still trying to get zsh 5.9 to run on 
SunOS 4 or AIX 3.25?

My personal opinion is that development should use at least the 
POSIX-1.2001 standard.  It's 20 years old.  That's surely old enough for 
any system still running.  (It's  certainly old enough that any such 
system is not supported by the vendor)



^ permalink raw reply	[relevance 9%]

* Re: Minimum POSIX standard
  2022-10-23 20:19 10% Minimum POSIX standard Clinton Bunch
@ 2022-10-23 21:57  5% ` Mikael Magnusson
  2022-10-26  1:51  9%   ` Clinton Bunch
  0 siblings, 1 reply; 200+ results
From: Mikael Magnusson @ 2022-10-23 21:57 UTC (permalink / raw)
  To: Clinton Bunch; +Cc: zsh-workers

On 10/23/22, Clinton Bunch <cdb_zsh@zentaur.org> wrote:
> What is the minimum POSIX standard modern Zsh code is intended to
> conform to?

As far as I'm aware, none.

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 5%]

* Minimum POSIX standard
@ 2022-10-23 20:19 10% Clinton Bunch
  2022-10-23 21:57  5% ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Clinton Bunch @ 2022-10-23 20:19 UTC (permalink / raw)
  To: zsh-workers

What is the minimum POSIX standard modern Zsh code is intended to 
conform to?  Is development still trying to support systems that don't 
conform at least to POSIX.1-2001?

I didn't really find an answer in the Development Guide

  I find it hard to believe that modern versions of Zsh are expected to 
run on 20 year old systems.  Especially since there are un-ifdef uses of 
snprintf which wasn't standardized in the C library until the C99 spec.


P.S.  The mailing list archives need a better search feature.  I 
couldn't determine if this question had been asked before:)



^ permalink raw reply	[relevance 10%]

* Re: Deprecation of egrep
  @ 2022-09-10 17:26  3% ` Ellenor Bjornsdottir
  0 siblings, 0 replies; 200+ results
From: Ellenor Bjornsdottir @ 2022-09-10 17:26 UTC (permalink / raw)
  To: Zsh Hackers' List

[-- Attachment #1: Type: text/plain, Size: 1065 bytes --]

grep from which system? GNU? `egrep` would appear to be a GNU extension, mimicked by some other UNIXes like FreeBSD. "Releases of grep" as a thing separate from the OS is a concept foreign to me, other than GNU.

I am not from zsh-land (though I do use it as my login shell), so I doubt I've a say here, but I'd suggest this looks right. I looked at the SUSv2 grep manpage and this will perform as expected if one's grep complies with SUSv2. (For the count, that's a very old version of POSIX.)

On 10 September 2022 16:04:49 UTC, Vin Shelton <acs@alumni.princeton.edu> wrote:
>Greetings!
>
>The latest release of grep officially deprecates egrep in favor of "grep
>-E".  In the build process, we have handled this in our autoconf script,
>but egrep persists in our test scripts, causing failures.  Changing all
>occurrences of "egrep" to "grep -E" in our test scripts will fix this.  How
>do we want to handle this?
>
>Regards,
>  Vin Shelton
>
>-- 
>
>*Never for money, always for love*

-- 
Ellenor Bjornsdottir (she)
sysadmin umbrellix.net

[-- Attachment #2: Type: text/html, Size: 1960 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: ${EDITOR} with spaces (was: Re: [PATCH] initialization of main keymap)
  2022-09-05  9:15  5%                   ` Vincent Lefevre
@ 2022-09-05 21:17  3%                     ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2022-09-05 21:17 UTC (permalink / raw)
  To: Vincent Lefevre; +Cc: zsh-workers

On Mon, Sep 5, 2022, at 5:15 AM, Vincent Lefevre wrote:
> Indeed, for EDITOR, under "mailx", POSIX says "name of a utility"
> and not "command". This is a bit unclear about the possibility of
> full pathnames, but under "more", POSIX says "If the last pathname
> component in EDITOR is either vi or ex, [...]" so it is now clear
> that EDITOR may contain a full pathname (there wasn't any practical
> reason for a restriction).
>
> For VISUAL, POSIX says "pathname of a utility".
>
> So, in both cases, options should not be accepted, i.e. spaces
> should be regarded as part of the name (though I wonder whether
> this is portable in practice).

It isn't.  As far as I'm aware, POSIX only addresses EDITOR and
VISUAL as used by a handful of specific utilities (mailx, more, and
so on).  Even you assume that these discrete descriptions imply a
global specification, nonstandardized tools can do whatever they
please.  For instance, Git shell-evaluates the contents of EDITOR
and VISUAL.

https://git-scm.com/docs/git-var#Documentation/git-var.txt-GITEDITOR

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: ${EDITOR} with spaces (was: Re: [PATCH] initialization of main keymap)
  @ 2022-09-05  9:15  5%                   ` Vincent Lefevre
  2022-09-05 21:17  3%                     ` Lawrence Velázquez
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2022-09-05  9:15 UTC (permalink / raw)
  To: zsh-workers

On 2022-09-04 12:48:20 +0200, Mikael Magnusson wrote:
> On 9/4/22, Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> > Vincent Lefevre wrote on Fri, Sep 02, 2022 at 15:15:33 +0200:
> >> Yes, the current behavior (with or without the patch) is definitely
> >> incorrect. For instance, https://unix.stackexchange.com/a/4861/74516
> >> suggests to set VISUAL to the full-screen editor, and either leave
> >> EDITOR unset or set it to "vi -e" (just in case a special line mode
> >> would be needed in some context). So a user who would use VISUAL=emacs
> >> and EDITOR="vi -e" would probably be annoyed by the current behavior.
> >
> > Is $EDITOR meant to be used in a system(3) manner, as «system("${EDITOR}
> > ${(q-)filename}")»,
> > or in an execve(2) manner, as «execl($EDITOR, $EDITOR, $filename)»?
> > (plus or minus a «--» guard in both cases)
> 
> In practice, if you want $EDITOR to contain options to your editor,
> you have to make a wrapper script and put it in a path without spaces,
> because programs all assume different answers to your question.

Indeed, for EDITOR, under "mailx", POSIX says "name of a utility"
and not "command". This is a bit unclear about the possibility of
full pathnames, but under "more", POSIX says "If the last pathname
component in EDITOR is either vi or ex, [...]" so it is now clear
that EDITOR may contain a full pathname (there wasn't any practical
reason for a restriction).

For VISUAL, POSIX says "pathname of a utility".

So, in both cases, options should not be accepted, i.e. spaces
should be regarded as part of the name (though I wonder whether
this is portable in practice).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 5%]

* Re: An incompatible behavior from bash?
  2022-08-22 21:44  5%     ` Bart Schaefer
@ 2022-08-23  5:42  0%       ` Liu Xin
  0 siblings, 0 replies; 200+ results
From: Liu Xin @ 2022-08-23  5:42 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 771 bytes --]

Ok, thanks for the clarification.

On Mon, Aug 22, 2022 at 2:44 PM Bart Schaefer <schaefer@brasslantern.com>
wrote:

> On Mon, Aug 22, 2022 at 1:00 AM Liu Xin <navy.xliu@gmail.com> wrote:
> >
> > I hold the wrong impression that zsh is compatible with bash. I just
> assume it because I see both Ubuntu and MacOS have replaced bash with it.
>
> Zsh is mostly compatible with POSIX shell provided that it is invoked
> via the name "sh" (e.g., when linked to /bin/sh).  Bash is similarly
> compatible with POSIX when run this way.  When run under their own
> names, zsh and bash differ from POSIX in different ways.
>
> Apple and Ubuntu appear to have concluded that zsh's POSIX
> compatibility is sufficient to use it as "sh".  I won't speculate on
> other motivations.
>

[-- Attachment #2: Type: text/html, Size: 1195 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: An incompatible behavior from bash?
  @ 2022-08-22 21:44  5%     ` Bart Schaefer
  2022-08-23  5:42  0%       ` Liu Xin
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-08-22 21:44 UTC (permalink / raw)
  To: Liu Xin; +Cc: zsh-workers

On Mon, Aug 22, 2022 at 1:00 AM Liu Xin <navy.xliu@gmail.com> wrote:
>
> I hold the wrong impression that zsh is compatible with bash. I just assume it because I see both Ubuntu and MacOS have replaced bash with it.

Zsh is mostly compatible with POSIX shell provided that it is invoked
via the name "sh" (e.g., when linked to /bin/sh).  Bash is similarly
compatible with POSIX when run this way.  When run under their own
names, zsh and bash differ from POSIX in different ways.

Apple and Ubuntu appear to have concluded that zsh's POSIX
compatibility is sufficient to use it as "sh".  I won't speculate on
other motivations.


^ permalink raw reply	[relevance 5%]

* zargs error with some combinations of arguments
@ 2022-08-19  2:06  3% Alan Wagner-Krankel
  0 siblings, 0 replies; 200+ results
From: Alan Wagner-Krankel @ 2022-08-19  2:06 UTC (permalink / raw)
  To: zsh-workers

I've run across some conditions that apparently trip up calls to
zargs. A simplified example:

zsh -f <<\eof
  vals=(${(l:79::x:):-{001..256}})
  print count:${#vals} length:${(c)#vals}
  autoload -Uz zargs
  zargs -- $vals -- print -l
eof

The output:
count:256 length:20479
zargs: cannot fit single argument within size limit

This error occurs when:
- the combined length of the arguments that are going to be used in a
  call is less than the max argument size (-s, default is 20480), and
- the length of the command string plus the arguments is greater than
  the -s size value.



It looks like zargs was set up this way to emulate the behavior of
gxargs from GNU findutils. With the right options, you can get a
similar error:

gxargs -L 256 -s 20480 -x echo <<<${(f)${(l:79::x:):-{001..256}}}

On my system this returns:
gxargs: argument list too long

I wasn't able to find an input that gave this result when using
the (large) defaults for gxargs.



On the other hand, POSIX seems to want the constructed command to fit
within all of the various size arguments, if I'm reading this snippet
in the spec correctly:
-s size
  Invoke utility using as many standard input arguments as possible
  yielding a command line length less than size (a positive decimal
  integer) bytes. Fewer arguments shall be used if:
  - The total number of arguments exceeds that specified by the -n
    option.
  - The total number of lines exceeds that specified by the -L option.



I've run into the zargs error a couple of times recently with
real-world data, so my system is now using a version that is hopefully
a bit closer to the POSIX behavior.  The diff listing is below.

Another option would have been to use a large value for -s, and
significantly reduce the likelihood of hitting a set of inputs that
result in an error.  That seems to be the gxargs approach.



Any thoughts? Is there something else I missed, or is a change like
I've described something that you want to consider for a future
version of zargs?

Thank you for reading this far. Hope I didn't make too many mistakes
in my first post to the list :).

Thanks,
Awk



diff --context=1 zsh.5.9/Functions/Misc/zargs ~/.zfunctions/zargs
*** zsh.5.9/Functions/Misc/zargs
--- ~/.zfunctions/zargs
***************
*** 178,180 ****

! local -i end c=0
  if [[ $eof == -(e|-eof) ]]; then ((end=ARGC+1))
--- 178,180 ----

! local -i end a c=0
  if [[ $eof == -(e|-eof) ]]; then ((end=ARGC+1))
***************
*** 249,250 ****
--- 249,257 ----

+ (( a = s - ${#:-"$command "} ))
+ if (( a <= 0 ))
+ then
+     print -u2 'zargs: value for max-chars must be >= command length'
+     return 1
+ fi
+
  l=${${${l##*-(l|L|-max-lines(=|))}[-1]}:-${${l[1]:+1}:-$ARGC}}
***************
*** 291,293 ****
    ((ARGC)) || break
!   for (( end=l; end && ${(c)#argv[1,end]} > s; end/=2 )) { }
    (( end > n && ( end = n ) ))
--- 298,300 ----
    ((ARGC)) || break
!   for (( end=l; end && ${(c)#argv[1,end]} > a; end/=2 )) { }
    (( end > n && ( end = n ) ))


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] FAQ update for aliasing
  @ 2022-06-12 13:10  1% ` Jun. T
  0 siblings, 0 replies; 200+ results
From: Jun. T @ 2022-06-12 13:10 UTC (permalink / raw)
  To: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 1682 bytes --]

I've found that the text version of FAQ has some format problems,
and then found that it was already reported one-and-half year ago:

> 2021/01/30 4:35, Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
> However, when I do "cd Etc; make FAQ" on Ubuntu 20.04.1 LTS, I get
> some strange formatting.
(snip)
> That is, most paragraphs get a hanging left indent (outdent?),

It seems yodl removes any indent of the 1st line of a paragraph in
text mode by default (a paragraph is started by a blank line).

But at line 152 of the FAQ:
 (As a method of reading the following in Emacs, you can type \M-2   
  \C-x $ to make all the indented text vanish, ...

I have _NO_ experience with emacs, but I guess the lack of indent
would break this feature?

With some trial and error, I found the indent can be preserved by the
following patch.
But with this patch two or more consecutive blank lines in FAQ.yo
are copied to the text output as is. I guess the symbol XXparagraph
contains all the preceding blank lines. Using ifnewparagraph() didn't
work. So I removed many blank lines. These trivial changes are only
included in the attached file.


diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 8a6895454..ebe86c202 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -57,6 +57,11 @@ def(emdash)(0)(\
     whentxt(--))\
 SUBST(_LPAR_)(CHAR(40))\
 SUBST(_RPAR_)(CHAR(41))
+COMMENT(-- preserve the indent of the 1st line of paragraph --)\
+IFDEF(txt)(\
+  DEFINESYMBOL(XXparagraph)()\
+  PUSHMACRO(PARAGRAPH)(0)(SYMBOLVALUE(XXparagraph))\
+)()
 myreport(Z-Shell Frequently-Asked Questions)(Peter Stephenson)(2010/02/15)
 COMMENT(-- the following are for Usenet and must appear first)\
 description(\





[-- Attachment #2: FAQ-indent.patch --]
[-- Type: application/octet-stream, Size: 17955 bytes --]

diff --git a/Etc/FAQ.yo b/Etc/FAQ.yo
index 8a6895454..ebe86c202 100644
--- a/Etc/FAQ.yo
+++ b/Etc/FAQ.yo
@@ -57,6 +57,11 @@ def(emdash)(0)(\
     whentxt(--))\
 SUBST(_LPAR_)(CHAR(40))\
 SUBST(_RPAR_)(CHAR(41))
+COMMENT(-- preserve the indent of the 1st line of paragraph --)\
+IFDEF(txt)(\
+  DEFINESYMBOL(XXparagraph)()\
+  PUSHMACRO(PARAGRAPH)(0)(SYMBOLVALUE(XXparagraph))\
+)()
 myreport(Z-Shell Frequently-Asked Questions)(Peter Stephenson)(2010/02/15)
 COMMENT(-- the following are for Usenet and must appear first)\
 description(\
@@ -163,7 +168,7 @@ Acknowledgments
 
 Copyright
 --- End of Contents ---
-)
+)\
 
 chapter(Introducing zsh and how to install it)
 
@@ -222,7 +227,6 @@ email(mail-server@rtfm.mit.edu)
   For any more eclectic information, you should contact the mailing
   list:  see question link(6.2)(62).
 
-
 sect(What is it?)
 
   Zsh is a UNIX command interpreter (shell) which of the standard
@@ -242,7 +246,6 @@ sect(What is it?)
   included with the source distribution are highly recommended.  A list
   of features is given in FEATURES, also with the source.
 
-
 sect(What is it good at?)
 
   Here are some things that zsh is particularly good at.  No claim of
@@ -284,7 +287,6 @@ sect(What is it good at?)
   it() Spelling correction.
   )
 
-
 sect(On what machines will it run?)
 
   From version 3.0, zsh uses GNU autoconf as the installation
@@ -313,7 +315,6 @@ sect(On what machines will it run?)
   signames.h file. This makes the signals code unusable. This often happens
   on Ultrix, HP-UX, IRIX (?). Install gawk if you experience such problems.
 
-
 sect(What's the latest version?)
 
   Zsh 5.9 is the latest production version.  For details of all the
@@ -335,7 +336,6 @@ sect(What's the latest version?)
   users), or to enhance compatibility with other Bourne shell
   derivatives, or (mostly in the 3.0 series) to provide POSIX compliance.
 
-
 sect(Where do I get it?)
 label(16)
 
@@ -435,7 +435,6 @@ sect(I don't have root access: how do I make zsh my login shell?)
   /etc/shells on all appropriate machines, including NIS clients, or you
   may have problems with FTP to that machine.
 
-
 chapter(How does zsh differ from...?)
 
 As has already been mentioned, zsh is most similar to ksh, while many
@@ -639,7 +638,6 @@ link(2.3)(23).
   )
   )
 
-
 sect(Similarities with csh)
 
   Although certain features aim to ease the withdrawal symptoms of csh
@@ -673,7 +671,6 @@ sect(Similarities with csh)
   it()  Arrays have csh-like features (see under link(2.1)(21)).
   )
 
-
 sect(Why do my csh aliases not work?  (Plus other alias pitfalls.))
 label(23)
 
@@ -863,7 +860,6 @@ mytt(compctl)
   )
   and can now bind tt(run-fg-editor) just like any other editor function.
 
-
 sect(Similarities with bash)
 label(25)
 
@@ -889,7 +885,6 @@ label(25)
   and `tt((#e))' to match the end.  These require the option
   tt(EXTENDED_GLOB) to be set.
 
-
 sect(Shouldn't zsh be more/less like ksh/(t)csh?)
 
   People often ask why zsh has all these `unnecessary' csh-like features,
@@ -916,7 +911,6 @@ sect(Shouldn't zsh be more/less like ksh/(t)csh?)
   want.  The introduction of loadable in modules in version 3.1 should
   help.
 
-
 sect(What is zsh's support for Unicode/UTF-8?)
 
   `Unicode', or UCS for Universal Character Set, is the modern way
@@ -935,7 +929,6 @@ sect(What is zsh's support for Unicode/UTF-8?)
   this becomes a production release.)  This is discussed more
   fully below, see `Multibyte input and output'.
 
-
 sect(Why does my bash script report an error when I run it under zsh?)
 label(28)
 
@@ -996,7 +989,6 @@ label(28)
   languages and adjusting it accordingly, just like you would
   when translating a book from American English to British English.
 
-
 chapter(How to get various things to work)
 
 sect(Why does mytt($var) where mytt(var="foo bar") not do what I expect?)
@@ -1166,7 +1158,6 @@ sect(In which startup file do I put...?)
   put in tt(.zshrc)
   to save your history.
 
-
 sect(What is the difference between `export' and the tt(ALL_EXPORT) option?)
 
   Normally, you would put a variable into the environment by using
@@ -1192,7 +1183,6 @@ sect(What is the difference between `export' and the tt(ALL_EXPORT) option?)
   it immediately afterwards.  Only those variables will be automatically
   exported.
 
-
 sect(How do I turn off spelling correction/globbing for a single command?)
 
   In the first case, you presumably have mytt(setopt correctall) in an
@@ -1217,7 +1207,6 @@ sect(How do I turn off spelling correction/globbing for a single command?)
   Note also that a shell function won't work: the no... directives must
   be expanded before the rest of the command line is parsed.
 
-
 sect(How do I get the Meta key to work on my xterm?)
 label(35)
 
@@ -1255,7 +1244,6 @@ label(35)
   each byte is used to indicate a part of a multibyte character.  See
   link(chapter 5)(c5).
 
-
 sect(How do I automatically display the directory in my xterm title bar?)
 
   You should use the special function mytt(chpwd), which is called when
@@ -1283,7 +1271,6 @@ sect(How do I automatically display the directory in my xterm title bar?)
   directly: just put mytt(chpwd) in tt(.zshrc) after it is defined or \
   autoloaded.
 
-
 sect(How do I make the completion list use eight bit characters?)
 
   If you are sure your terminal handles this, the easiest way from versions
@@ -1297,7 +1284,6 @@ sect(How do I make the completion list use eight bit characters?)
   possibility may be to set tt(LC_ALL=en_US).  For older versions of the
   shell, there is no easy way out.
 
-
 sect(Why do the cursor (arrow) keys not work?  (And other terminal oddities.))
 
   The cursor keys send different codes depending on the terminal; zsh
@@ -1365,7 +1351,6 @@ sect(Why do the cursor (arrow) keys not work?  (And other terminal oddities.))
   what we used to get the cursor keys above), replace mytt(echoti smkx)
   with mytt(echotc ks) and replace mytt(echoti rmkx) with mytt(echotc ke).
 
-
 sect(Why does my terminal act funny in some way?)
 
   If you are using an OpenWindows cmdtool as your terminal, any
@@ -1408,7 +1393,6 @@ sect(Why does my terminal act funny in some way?)
   afterwards: just the modes it uses itself and a number of special
   processing characters (see the tt(stty(1)) manual page).
 
-
 sect(Why does zsh not work in an Emacs shell mode any more?)
 
   (This information comes from Bart Schaefer and other zsh-workers.)
@@ -1438,7 +1422,6 @@ sect(Why does zsh not work in an Emacs shell mode any more?)
   )
   to ~/.emacs.
 
-
 sect(Why do my autoloaded functions not autoload [the first time]?)
 
   The problem is that there are two possible ways of autoloading a
@@ -1484,7 +1467,6 @@ sect(Why do my autoloaded functions not autoload [the first time]?)
   parentheses removes the directory part of the filenames, leaving
   just the function names.)
 
-
 sect(How does base arithmetic work?)
 
   The ksh syntax is now understood, i.e.
@@ -1528,7 +1510,6 @@ sect(How does base arithmetic work?)
     print $(( [#16] 255 ))
   )
 
-
 sect(How do I get a newline in my prompt?)
 label(313)
 
@@ -1551,7 +1532,6 @@ label(313)
   is a neat way of doing what you want.  Note that it is the quotes, not
   the prompt expansion, which turns the `tt(\n)' into a newline.
 
-
 sect(Why does mytt(bindkey ^a command-name) or mytt(stty intr ^-) do something funny?)
 
   You probably have the extendedglob option set in which case tt(^) and tt(#)
@@ -1561,7 +1541,6 @@ sect(Why does mytt(bindkey ^a command-name) or mytt(stty intr ^-) do something f
   See link(3.27)(327) if you want to know more about the pattern
   character mytt(^).
 
-
 sect(Why can't I bind tt(\C-s) and tt(\C-q) any more?)
 
   The control-s and control-q keys now do flow control by default,
@@ -1575,7 +1554,6 @@ sect(Why can't I bind tt(\C-s) and tt(\C-q) any more?)
   control and hence restoring the use of the keys: put mytt(setopt
   noflowcontrol) in your tt(.zshrc) file.
 
-
 sect(How do I execute command mytt(foo) within function mytt(foo)?)
 
   The command mytt(command foo) does just that.  You don't need this with
@@ -1587,7 +1565,6 @@ sect(How do I execute command mytt(foo) within function mytt(foo)?)
   using `command'.  If mytt(foo) is a builtin rather than an external
   command, use mytt(builtin foo) instead.
 
-
 sect(Why do history substitutions with single bangs do something funny?)
 
   If you have a command like "tt(echo !-2:$ !$)", the first history
@@ -1596,7 +1573,6 @@ sect(Why do history substitutions with single bangs do something funny?)
   tt(!-2:$).  The option tt(CSH_JUNKIE_HISTORY) makes all single bangs refer
   to the last command.
 
-
 sect(Why does zsh kill off all my background jobs when I logout?)
 
   Simple answer: you haven't asked it not to.  Zsh (unlike [t]csh) gives
@@ -1614,13 +1590,11 @@ sect(Why does zsh kill off all my background jobs when I logout?)
   Likewise, you can start a background job with mytt(&!) instead of just
   mytt(&) at the end, which will automatically disown the job.
 
-
 sect(How do I list all my history entries?)
 
   Tell zsh to start from entry 1: mytt(history 1).  Those entries at the
   start which are no longer in memory will be silently omitted.
 
-
 sect(How does the alternative loop syntax, e.g. mytt(while {...} {...}) \
 work?)
 
@@ -1678,7 +1652,6 @@ work?)
   manual), which you are in any case encouraged even more strongly not
   to use in programs as it can be very confusing.
 
-
 sect(Why is my history not being saved?)
 label(321)
 
@@ -1696,7 +1669,6 @@ label(321)
   above.  There are also various options affecting history; see the
   manual.
 
-
 sect(How do I get a variable's value to be evaluated as another variable?)
 
   The problem is that you have a variable tt($E) containing the string
@@ -1733,7 +1705,6 @@ sect(How do I get a variable's value to be evaluated as another variable?)
   it, this works).  So in mytt(${${E}}), the internal mytt(${...})
   actually does nothing.
 
-
 sect(How do I prevent the prompt overwriting output when there is no newline?)
 
   The problem is normally limited to zsh versions prior to 4.3.0 due to the
@@ -1776,7 +1747,6 @@ sect(How do I prevent the prompt overwriting output when there is no newline?)
   One final alternative is to put a newline in your prompt -- see question
   link(3.13)(313) for that.
 
-
 sect(What's wrong with cut and paste on my xterm?)
 
   On the majority of modern UNIX systems, cutting text from one window and
@@ -1815,7 +1785,6 @@ sect(What's wrong with cut and paste on my xterm?)
      in the tt(zshparam) manual page for details.
   )
 
-
 sect(How do I get coloured prompts on my colour xterm?)
 
   (Or `color xterm', if you're reading this in black and white.)
@@ -1859,7 +1828,6 @@ sect(How do I get coloured prompts on my colour xterm?)
   `mytt(<ESC>[0m)' puts printing back to normal so that the rest of the line
   is unchanged.
 
-
 sect(Why is my output duplicated with `tt(foo 2>&1 >foo.out | bar)'?)
 
   This is a slightly unexpected effect of the option tt(MULTIOS), which is
@@ -1903,7 +1871,6 @@ sect(Why is my output duplicated with `tt(foo 2>&1 >foo.out | bar)'?)
   (to the pipe) and start anew with tt(>foo.out) instead of adding it as a
   redirection target to stdout.
 
-
 sect(What are these `^' and `~' pattern characters, anyway?)
 label(327)
 
@@ -2030,7 +1997,6 @@ label(327)
      in the current directory or any parent.)
   )
 
-
 sect(How do I edit the input buffer in $EDITOR?)
 label(328)
 
@@ -2046,7 +2012,6 @@ label(328)
   command-line for editing.  The command will not be automatically executed;
   quitting the editor will only return to zsh's command-line editing mode.
 
-
 sect(Why does `which' output for missing commands go to stdout?)
 
   The issue is that if you run:
@@ -2076,7 +2041,6 @@ sect(Why does `which' output for missing commands go to stdout?)
   other Bourne-style shells it is in fact self-consistent.  Note that
   the exit status does reflect the fact the command can't be found.
 
-
 sect(Why doesn't the expansion mytt(*.{tex,aux,pdf}) do what I expect?)
 
   Based on the behaviour of some other shells, you might guess that the
@@ -2114,10 +2078,8 @@ sect(Why doesn't the expansion mytt(*.{tex,aux,pdf}) do what I expect?)
   This is harder for the user to remember but easier for the shell to
   parse!
 
-
 chapter(The mysteries of completion)
 
-
 sect(What is completion?)
 
   `Completion' is where you hit a particular command key (TAB is the
@@ -2147,7 +2109,6 @@ sect(What is completion?)
   compinit; compinit)' in your tt(.zshrc) should be enough if the system is
   installed properly.
 
-
 sect(What sorts of things can be completed?)
 label(42)
 
@@ -2171,7 +2132,6 @@ label(42)
   `anything where an automated guess is possible'.  Just hit TAB
   and see if the shell manages to guess correctly.
 
-
 sect(How does zsh deal with ambiguous completions?)
 
   Often there will be more than one possible completion: two files
@@ -2209,7 +2169,6 @@ sect(How does zsh deal with ambiguous completions?)
   from version 3.1 tt(LIST_AMBIGUOUS) is set by default; if you use
   autolist, you may well want to `unsetopt listambiguous'.
 
-
 sect(How do I complete in the middle of words / just what's before the cursor?)
 
   Sometimes you have a word on the command-line which is incomplete in the
@@ -2238,7 +2197,6 @@ sect(How do I complete in the middle of words / just what's before the cursor?)
   can expand to tt(/usr/local/bin) or anything else that matches.  This
   saves you having to expand the middle part of the path separately.
 
-
 sect(How do I get started with programmable completion?)
 label(45)
 
@@ -2251,7 +2209,6 @@ label(45)
   tells you how to configure the completion system and chapter 15 how
   to write your own completion functions.
 
-
 sect(Suppose I want to complete all files during a special completion?)
 
   If you're using the completion system the shell will decide what
@@ -2283,7 +2240,6 @@ sect(Suppose I want to complete all files during a special completion?)
   completion.  Your actual completer style may include other actions,
   such as expansion or approximate completion.
 
-
 chapter(Multibyte input and output)
 label(c5)
 
@@ -2334,7 +2290,6 @@ sect(What is multibyte input?)
   way, for example on Windows, but the shell can't deal directly with text
   in those formats.)
 
-
 sect(How does zsh handle multibyte input and output?)
 
   Until version 4.3, zsh didn't handle multibyte input properly at all.
@@ -2379,7 +2334,6 @@ sect(How does zsh handle multibyte input and output?)
   in inverse video.  Highlighting of such special characters can
   be modified using the new array parameter tt(zle_highlight).
 
-
 sect(How do I ensure multibyte input and output work on my system?)
 
   Once you have a version of zsh with multibyte support, you need to
@@ -2451,7 +2405,6 @@ sect(How do I ensure multibyte input and output work on my system?)
   to compile with the tt(MULTIBYTE) option enabled, but the system
   didn't provide full support for it.
 
-
 sect(How can I input characters that aren't on my keyboard?)
 
   Two functions are provided with zsh that help you input characters.
@@ -2495,7 +2448,6 @@ url(http://www.unicode.org/charts/)(http://www.unicode.org/charts/).
   See also url(http://www.cl.cam.ac.uk/~mgk25/unicode.html#input)(http://www.cl.cam.ac.uk/~mgk25/unicode.html#input)
   for general information on entering Unicode characters from a keyboard.
 
-
 chapter(The future of zsh)
 
 sect(What bugs are currently known and unfixed? (Plus recent \
@@ -2512,7 +2464,6 @@ label(61)
   most important changes, and in particular draws attention to
   incompatibilities you might notice.
 
-
 sect(Where do I report bugs, get more info / who's working on zsh?)
 label(62)
 
@@ -2577,7 +2528,6 @@ label(62)
   Of course, you can also post zsh queries to the Usenet group
   comp.unix.shell; if all else fails, you could even e-mail me.
 
-
 sect(What's on the wish-list?)
 
   The code bears the marks of the ages and many things could be done much
@@ -2601,7 +2551,6 @@ sect(What's on the wish-list?)
   it() Option for glob qualifiers to follow perl syntax (a traditional item).
   )
 
-
 sect(Did zsh have problems in the year 2000?)
 
   Not that I heard of; it's up to you to be careful with two-digit dates,
@@ -2609,7 +2558,6 @@ sect(Did zsh have problems in the year 2000?)
   and also by the command `tt(print -P)'.  Earlier versions of zsh may
   show problems here.
 
-
 sect(When reporting a bug, how do I reduce my mytt(.zshrc) into a minimal reproduction recipe?)
 
   When reporting a bug, the gold standard is to include with the bug
@@ -2623,9 +2571,8 @@ sect(When reporting a bug, how do I reduce my mytt(.zshrc) into a minimal reprod
   and then, within that instance of the shell, run a minimal short
   sequence of commands that reproduces the bug.  A good way to devise
   such recipes is the following:
-
 COMMENT(For reference, here's Vim's write-up of a similar process:
-https://github.com/chrisbra/vim_faq/blob/de424bd8e08bcf0e6b1e0563ee49514dfed926ae/vim_faq.txt#L1153-L1228)
+https://github.com/chrisbra/vim_faq/blob/de424bd8e08bcf0e6b1e0563ee49514dfed926ae/vim_faq.txt#L1153-L1228)\
 
   enumeration(
   myeit() First, ensure the bug is reproducible.  To do this, start
@@ -2701,7 +2648,6 @@ https://github.com/chrisbra/vim_faq/blob/de424bd8e08bcf0e6b1e0563ee49514dfed926a
   Bug reports should be emailed to the mytt(zsh-workers@zsh.org) public
   mailing list; see link(6.2)(62) for details.
 
-
 nsect(Acknowledgments:)
 
 Thanks to zsh-list, in particular Bart Schaefer, for suggestions
@@ -2713,7 +2659,6 @@ thanks.  The world is eternally in the debt of Paul Falstad for inventing
 zsh in the first place (though the wizzo extended completion is by Sven
 Wischnowsky).
 
-
 nsect(Copyright Information:)
 
 This document is copyright (C) P.W. Stephenson, 1995, 1996, 1997,

^ permalink raw reply	[relevance 1%]

* Re: Minor bug(s) with NO_MULTI_FUNC_DEF
  2022-05-31 17:14  0%     ` Bart Schaefer
@ 2022-06-06  8:45  0%       ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2022-06-06  8:45 UTC (permalink / raw)
  To: Zsh hackers list

> On 31 May 2022 at 18:14 Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Tue, May 31, 2022 at 10:07 AM Bart Schaefer
> <schaefer@brasslantern.com> wrote:
> >
> > On Tue, May 31, 2022 at 2:06 AM Peter Stephenson
> > <p.w.stephenson@ntlworld.com> wrote:
> > > I don't see a good argument for
> > > doing it differently depending on the option setting.
> >
> > ... do we need to worry about sh / POSIX compatibility?
> 
> To be more precise ... we still don't need to do it differently based
> on the option, but we might need to retain the "name()" format when
> it's not affected by the option.

Hmm, this is a real issue.  As NO_MULTI_FUNC_DEF is in effect
for sh emulation, we could in fact tie it to the option.  But your
suggestion has a much lower effect on output of compiled shell code, so that
could be the way to go.

pws


^ permalink raw reply	[relevance 0%]

* Re: Minor bug(s) with NO_MULTI_FUNC_DEF
  2022-05-31 17:07  3%   ` Bart Schaefer
@ 2022-05-31 17:14  0%     ` Bart Schaefer
  2022-06-06  8:45  0%       ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-05-31 17:14 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Tue, May 31, 2022 at 10:07 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Tue, May 31, 2022 at 2:06 AM Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> > I don't see a good argument for
> > doing it differently depending on the option setting.
>
> ... do we need to worry about sh / POSIX compatibility?

To be more precise ... we still don't need to do it differently based
on the option, but we might need to retain the "name()" format when
it's not affected by the option.


^ permalink raw reply	[relevance 0%]

* Re: Minor bug(s) with NO_MULTI_FUNC_DEF
  @ 2022-05-31 17:07  3%   ` Bart Schaefer
  2022-05-31 17:14  0%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-05-31 17:07 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Tue, May 31, 2022 at 2:06 AM Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
>
> So the question is, is it time to output all functions (except anonymous)
> using the other syntax, which is the one we recommend anyway?

In the case of multiple names, definitely.  In the case of a single name ...

> I don't see a good argument for
> doing it differently depending on the option setting.

... do we need to worry about sh / POSIX compatibility?


^ permalink raw reply	[relevance 3%]

* Re: Bug in function in function
  2022-05-20 17:25  0%       ` Klaus Ethgen
  2022-05-20 17:46  0%         ` Peter Stephenson
@ 2022-05-20 17:47  0%         ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2022-05-20 17:47 UTC (permalink / raw)
  To: Klaus Ethgen; +Cc: Mikael Magnusson, Zsh hackers list

On Fri, May 20, 2022 at 10:25 AM Klaus Ethgen <Klaus@ethgen.ch> wrote:
>
> Am Fr den 20. Mai 2022 um 18:16 schrieb Mikael Magnusson:
> > On 5/20/22, Klaus Ethgen <Klaus@ethgen.ch> wrote:
> > >
> > > I have an alias `alias ls="LC_COLLATE=POSIX ls $_ls_opts"` before this
> > > line but that should not interfere the function definition.
> >
> > In fact it should, and it does.

I'm now curious whether this "worked" in a prior version of zsh?  That
is, how long have you had both the alias and the function definition?

> Putting a `function` in front of `ls()` work.
>
> However, I was thinking, `function` (in that context) is deprecated.

No ... in fact, since the introduction of the NO_MULTI_FUNC_DEF
option, using "function" there is there recommended way to create
several functions with identical bodies.

However, you don't need both the "function" keyword and the empty parens.


^ permalink raw reply	[relevance 0%]

* Re: Bug in function in function
  2022-05-20 17:25  0%       ` Klaus Ethgen
@ 2022-05-20 17:46  0%         ` Peter Stephenson
  2022-05-20 17:47  0%         ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2022-05-20 17:46 UTC (permalink / raw)
  To: zsh-workers

On Fri, 2022-05-20 at 18:25 +0100, Klaus Ethgen wrote:
> Am Fr den 20. Mai 2022 um 18:16 schrieb Mikael Magnusson:
> > On 5/20/22, Klaus Ethgen <Klaus@ethgen.ch> wrote:
> > > I have an alias `alias ls="LC_COLLATE=POSIX ls $_ls_opts"` before this
> > > line but that should not interfere the function definition.
> > 
> > In fact it should, and it does. Change your function definition(s) to
> > the form "function ls".
> 
> Putting a `function` in front of `ls()` work.
> 
> However, I was thinking, `function` (in that context) is deprecated.

No, it's valid syntax and will remain so --- just avoid using both
function in front AND () afterwards.  This is indeed the recommended fix
for this case.  The point, in case it isn't already obvious, is that
alias expands everything in command position before it's even been
parsed --- so your "ls" has turned into something else on input before
the shell has even swallowed the ().  With the function keyword, the
following word is no longer in command position.

pws



^ permalink raw reply	[relevance 0%]

* Re: Bug in function in function
  2022-05-20 17:16  0%     ` Mikael Magnusson
@ 2022-05-20 17:25  0%       ` Klaus Ethgen
  2022-05-20 17:46  0%         ` Peter Stephenson
  2022-05-20 17:47  0%         ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Klaus Ethgen @ 2022-05-20 17:25 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: Bart Schaefer, Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1206 bytes --]

Am Fr den 20. Mai 2022 um 18:16 schrieb Mikael Magnusson:
> On 5/20/22, Klaus Ethgen <Klaus@ethgen.ch> wrote:
> > Am Fr den 20. Mai 2022 um 16:37 schrieb Bart Schaefer:
> >> On Thu, May 19, 2022 at 12:34 PM Klaus Ethgen <Klaus@ethgen.ch> wrote:
> >> >
> >> > Now I get an error in the `ls()` line. It is even more strange that I
> >> > don't get an error when compiling it as zwc file!
> >>
> >> What's the error?
> >
> > /home/klaus/.zsh/zshrc/30_aliases:471: parse error near `()'
> >
> > This is the line `ls()`. the first function definition (`cd()`) does
> > work. And when compiling, both work as expected.
> >
> > I have an alias `alias ls="LC_COLLATE=POSIX ls $_ls_opts"` before this
> > line but that should not interfere the function definition.
> 
> In fact it should, and it does. Change your function definition(s) to
> the form "function ls".

Putting a `function` in front of `ls()` work.

However, I was thinking, `function` (in that context) is deprecated.

Regards
   Klaus
-- 
Klaus Ethgen                                       http://www.ethgen.ch/
pub  4096R/4E20AF1C 2011-05-16            Klaus Ethgen <Klaus@Ethgen.ch>
Fingerprint: 85D4 CA42 952C 949B 1753  62B3 79D0 B06F 4E20 AF1C

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 688 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: Bug in function in function
  2022-05-20 17:12  3%   ` Klaus Ethgen
@ 2022-05-20 17:16  0%     ` Mikael Magnusson
  2022-05-20 17:25  0%       ` Klaus Ethgen
  0 siblings, 1 reply; 200+ results
From: Mikael Magnusson @ 2022-05-20 17:16 UTC (permalink / raw)
  To: Klaus Ethgen; +Cc: Bart Schaefer, Zsh hackers list

On 5/20/22, Klaus Ethgen <Klaus@ethgen.ch> wrote:
> Am Fr den 20. Mai 2022 um 16:37 schrieb Bart Schaefer:
>> On Thu, May 19, 2022 at 12:34 PM Klaus Ethgen <Klaus@ethgen.ch> wrote:
>> >
>> > Now I get an error in the `ls()` line. It is even more strange that I
>> > don't get an error when compiling it as zwc file!
>>
>> What's the error?
>
> /home/klaus/.zsh/zshrc/30_aliases:471: parse error near `()'
>
> This is the line `ls()`. the first function definition (`cd()`) does
> work. And when compiling, both work as expected.
>
> I have an alias `alias ls="LC_COLLATE=POSIX ls $_ls_opts"` before this
> line but that should not interfere the function definition.

In fact it should, and it does. Change your function definition(s) to
the form "function ls".

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* Re: Bug in function in function
  @ 2022-05-20 17:12  3%   ` Klaus Ethgen
  2022-05-20 17:16  0%     ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Klaus Ethgen @ 2022-05-20 17:12 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 975 bytes --]

Am Fr den 20. Mai 2022 um 16:37 schrieb Bart Schaefer:
> On Thu, May 19, 2022 at 12:34 PM Klaus Ethgen <Klaus@ethgen.ch> wrote:
> >
> > Now I get an error in the `ls()` line. It is even more strange that I
> > don't get an error when compiling it as zwc file!
> 
> What's the error?

/home/klaus/.zsh/zshrc/30_aliases:471: parse error near `()'

This is the line `ls()`. the first function definition (`cd()`) does
work. And when compiling, both work as expected.

I have an alias `alias ls="LC_COLLATE=POSIX ls $_ls_opts"` before this
line but that should not interfere the function definition.

> > Is there any recent that has changed?
> 
> Quite a number of things, but you haven't told us enough yet to narrow it down.

What do you need?

Regards
   Klaus
-- 
Klaus Ethgen                                       http://www.ethgen.ch/
pub  4096R/4E20AF1C 2011-05-16            Klaus Ethgen <Klaus@Ethgen.ch>
Fingerprint: 85D4 CA42 952C 949B 1753  62B3 79D0 B06F 4E20 AF1C

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 688 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: E02 failing on Alpine / musl libc
  @ 2022-05-19  3:27  4%   ` dana
  0 siblings, 0 replies; 200+ results
From: dana @ 2022-05-19  3:27 UTC (permalink / raw)
  To: Jun T; +Cc: Zsh hackers list

On Mon 16 May 2022, at 21:33, Jun T wrote:
> So I think we need/should not "fix" this, because 0xfdXX (or \ufdXX) is the
> correct representation in their "special" C loale.

I think i see the argument for not trying to do any 'special' accounting
of this locale in the shell. As far as the tests, i guess we are
technically making assumptions about the wchar values of non-'portable'
characters that POSIX says we can't actually make, but not making those
assumptions seems annoying

For the E02 test in particular, as Peter says, it isn't a multi-byte test.
If there's not anything special about the code path for xtrace
preservation that's sensitive to weird function names maybe that aspect of
the test belongs in B13, C04, or D07...?


Here is some additional context/history behind these failing tests, in
case anyone's ever looking for it later. Don't read this, you probably
don't care:

The A03 and B03 tests that Jun mentioned here have been failing on musl
since at least zsh-5.5 — probably longer (despite workers/48578 indicating
that it'd only started 'recently'), since the """special""" (lol) locale
was introduced to musl in August 2015, and made its way into Alpine very
shortly afterwards

The LC_ALL=C in the failing E02 test was introduced by me and Jun in
workers/45537+45550 to fix a similar issue i was seeing with the way the
function name ヌ was being printed by `which` on macOS Mojave. I bet i was
having this problem because i had explicitly set LC_CTYPE to a UTF-8
locale, and Jun had not yet made the change in workers/49908 to have ztst
reset that back to C like it did with LANG and LC_ALL. It does now reset
it with the others so the LC_ALL=C is probably superfluous in that respect

However, if you don't have *any* LANG/LC_* variables set, on some systems,
including Alpine, where the 'implementation-defined default locale' is
UTF-8, you can get the same behaviour i was seeing where `which` just
prints ヌ back out without any escaping

I mention that because there are basically only two possibilities on a
typical musl system (either the 'special' POSIX locale or a UTF-8 one)
and both of them will cause the test to fail as written. And also because
there might be other systems that have a UTF-8 default locale where this
test and others could fail without an explicit LC_ALL=C because ztst only
resets the locale to C if we're *not* using the default one (which i don't
think i understand the reasoning for)


dana


^ permalink raw reply	[relevance 4%]

* Re: ERRNO is unset until set
  2022-04-29 17:02  3%         ` Bart Schaefer
@ 2022-04-29 17:08  0%           ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2022-04-29 17:08 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Fri, 29 Apr 2022 17:02 +00:00:
> On Fri, Apr 29, 2022 at 3:00 AM Mikael Magnusson <mikachu@gmail.com> wrote:
>>
>> When is this good or useful?
>
> I was wondering that myself.  The only thing I can think of is to make
> ${+ERRNO} show the "right" thing.
>
> Archive search is still offline (and I'm not sure it would help
> anyway) so I can't find the discussion that led up my patch from
> 32337,

https://zsh.org/workers/32157?

> but it seems to me that was intended to be just a first step to
> causing some of those variables to be non-special when zsh is started
> in emulation mode.  The second step just never happened, or at least
> not comprehensively.
>
> I'm no longer even sure why ERRNO was included, there's no reference
> to it in the POSIX shell specification.  Clash with some other shell?
> But which one?


^ permalink raw reply	[relevance 0%]

* Re: ERRNO is unset until set
  @ 2022-04-29 17:02  3%         ` Bart Schaefer
  2022-04-29 17:08  0%           ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-04-29 17:02 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: Zsh hackers list

On Fri, Apr 29, 2022 at 3:00 AM Mikael Magnusson <mikachu@gmail.com> wrote:
>
> When is this good or useful?

I was wondering that myself.  The only thing I can think of is to make
${+ERRNO} show the "right" thing.

Archive search is still offline (and I'm not sure it would help
anyway) so I can't find the discussion that led up my patch from
32337, but it seems to me that was intended to be just a first step to
causing some of those variables to be non-special when zsh is started
in emulation mode.  The second step just never happened, or at least
not comprehensively.

I'm no longer even sure why ERRNO was included, there's no reference
to it in the POSIX shell specification.  Clash with some other shell?
But which one?


^ permalink raw reply	[relevance 3%]

* Re: Test release: 5.8.1.2-test
  @ 2022-04-12  9:16  3%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2022-04-12  9:16 UTC (permalink / raw)
  To: zsh-workers

> On 10 April 2022 at 21:07 Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> On Sat, 2022-04-09 at 15:07 -0500, dana wrote:
> > I've tagged 5.8.1.2-test (test release for the upcoming zsh 5.9) and
> > uploaded the artefacts to:
> > 
> >   https://sourceforge.net/projects/zsh/files/zsh-test/5.8.1.2-test/
> > 
> > If you have the time, please test and report any issues found.
> 
> Thanks very much for this, fine on my Ubuntu system.  I'll be able to
> try out on RedHat and Cygwin tomorrow.

Seems entirely clean on Ubuntu 16.04 and 18.04 and RedHat EL7.

Compiles on Cygwin but the test system is a bit sick on my laptop ---
not actually that unusual.  Unlikely to have time to look at this.

A couple of fixes will remove compilation warnings; it looks like
POSIX systems are pretty safe about signed characters these days
so Cygwin is about the only place where they still cause issues.

pws

diff --git a/Src/exec.c b/Src/exec.c
index 27d49e005..47753da48 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -561,7 +561,7 @@ zexecve(char *pth, char **argv, char **newenvp)
                         isbinary = 1;
                         hasletter = 0;
                         for (ptr = execvebuf; ptr < ptr2; ptr++) {
-                            if (islower(*ptr) || *ptr == '$' || *ptr == '`')
+                            if (islower(STOUC(*ptr)) || *ptr == '$' || *ptr == '`')
                                 hasletter = 1;
                             if (hasletter && *ptr == '\n') {
                                 isbinary = 0;
diff --git a/Src/prompt.c b/Src/prompt.c
index 738c7fc7a..092de63a4 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -1666,7 +1666,7 @@ match_colour(const char **teststrp, int is_fg, int colour)
 	tc = TCBGCOLOUR;
     }
     if (teststrp) {
-	if (**teststrp == '#' && isxdigit((*teststrp)[1])) {
+	if (**teststrp == '#' && isxdigit(STOUC((*teststrp)[1]))) {
 	    struct color_rgb color;
 	    char *end;
 	    zlong col = zstrtol(*teststrp+1, &end, 16);


^ permalink raw reply	[relevance 3%]

* [PATCH] Re: 5.8.1.2-test - test failures running as root
  @ 2022-04-11 22:38  5% ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2022-04-11 22:38 UTC (permalink / raw)
  To: Zsh hackers list

On Mon, Apr 11, 2022 at 2:14 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> These are probably not new; found while experimenting with reproducing
> Axel's test fails.
>
> The first is obviously because of root's expanded privileges.  The
> second probably also so, just not immediately clear why.

Fixed the first by just skipping the test.  Fixed the second by
dropping privilege and then attempting to escalate again.

diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 72891a2a7..850a535e5 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -748,13 +748,21 @@
   touch glob.tmp/secret-d$1/dir/file
   chmod $1 glob.tmp/secret-d$1
  done
- print -raC 2 -- glob.tmp/secret-*/* glob.tmp/secret-*/file
+ if (( EUID == 0 )); then
+   ZTST_skip='Not testing unreadable directories (root reads anything)'
+ else
+   print -raC 2 -- glob.tmp/secret-*/* glob.tmp/secret-*/file
+ fi
 0:names inside unreadable directories can be globbed if searchable
 >glob.tmp/secret-d444/dir   glob.tmp/secret-d444/file
 >glob.tmp/secret-s444/dir   glob.tmp/secret-s444/file
 >glob.tmp/secret-d111/file  glob.tmp/secret-s111/file

- print -rC 2 -- glob.tmp/secret-*/dir/*
+ if (( EUID == 0 )); then
+   ZTST_skip='Not testing unreadable directories (root reads anything)'
+ else
+   print -rC 2 -- glob.tmp/secret-*/dir/*
+ fi
 0:glob files in readable directories inside unreadable directories
 >glob.tmp/secret-d111/dir/file  glob.tmp/secret-s111/dir/file

diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst
index caab97ab6..6ac4d1732 100644
--- a/Test/E03posix.ztst
+++ b/Test/E03posix.ztst
@@ -153,7 +153,7 @@ F:This may also need to apply to multibyte whitespace
 F:POSIX has neither math functions nor floating point
 >42

-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'EUID=10; echo "$EUID"'
+  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'EUID=1; EUID=10; echo $EUID'
 -f:EUID is not a special variable
 >10


^ permalink raw reply	[relevance 5%]

* Re: Test release: 5.8.1.2-test
  2022-04-11  0:32  4% ` Axel Beckert
@ 2022-04-11  8:30  0%   ` Axel Beckert
  0 siblings, 0 replies; 200+ results
From: Axel Beckert @ 2022-04-11  8:30 UTC (permalink / raw)
  To: zsh-workers

Hi,

On Mon, Apr 11, 2022 at 02:32:57AM +0200, Axel Beckert wrote:
> >   https://sourceforge.net/projects/zsh/files/zsh-test/5.8.1.2-test/
> > 
> > If you have the time, please test and report any issues found.
> 
> Builds fine on Debian Unstable locally and in a local, clean chroot,
> but seems to fail to build in Debian's Gitlab CI due to one test
> failure: https://salsa.debian.org/debian/zsh/-/jobs/2661258
> 
> The failure I noticed in the log:
> 
> 7266 Running test: POSIX: width in %s should be computed in bytes, not in characters
> 7267 Test ../../Test/D07multibyte.ztst was expected to fail, but passed.
> 7268 Was testing: POSIX: width in %s should be computed in bytes, not in characters
> 7269 ../../Test/D07multibyte.ztst: test XPassed.
> 7270 The following may (or may not) help identifying the cause:
> 7271  This is considered a bugfix in zsh
> 7272 ../../Test/D08cmdsubst.ztst: starting.
> 
> And in the end:
> 
> 8850 61 successful test scripts, 1 failure, 2 skipped
> 
> Hopefully that's the failure mentioned in the summary, because I found
> no other.
> 
> I've uploaded it to Debian Experimental anyway to see if it builds
> fine on the official build daemons. Will see later today.

Looks bad: Test suite failures on most architectures on the build daemons:

https://buildd.debian.org/status/package.php?p=zsh&suite=experimental

Those were the test suite didn't fail seem only 32-bit architectures
(although I'm not sure if all of them really are 32-bit architectures):

i386, hppa, hurd-i386, m68k (and "all" which is actually the
architecture-independent stuff like docs, etc. where the test suite
isn't running).

All other architectures have 1 test suite failure according to the
summary:

61 successful test scripts, 1 failure, 2 skipped

Haven't checked yet, if it always was the same issue (the one cited
above from the "git push" triggered CI), but I currently assume so.

		Kind regards, Axel
-- 
PGP: 2FF9CD59612616B5      /~\  Plain Text Ribbon Campaign, http://arc.pasp.de/
Mail: abe@deuxchevaux.org  \ /  Say No to HTML in E-Mail and Usenet
Mail+Jabber: abe@noone.org  X
https://axel.beckert.ch/   / \  I love long mails: https://email.is-not-s.ms/


^ permalink raw reply	[relevance 0%]

* Re: Test release: 5.8.1.2-test
    @ 2022-04-11  0:32  4% ` Axel Beckert
  2022-04-11  8:30  0%   ` Axel Beckert
  1 sibling, 1 reply; 200+ results
From: Axel Beckert @ 2022-04-11  0:32 UTC (permalink / raw)
  To: Zsh hackers list

Hi,

On Sat, Apr 09, 2022 at 03:07:05PM -0500, dana wrote:
> I've tagged 5.8.1.2-test (test release for the upcoming zsh 5.9) and
> uploaded the artefacts to:
> 
>   https://sourceforge.net/projects/zsh/files/zsh-test/5.8.1.2-test/
> 
> If you have the time, please test and report any issues found.

Builds fine on Debian Unstable locally and in a local, clean chroot,
but seems to fail to build in Debian's Gitlab CI due to one test
failure: https://salsa.debian.org/debian/zsh/-/jobs/2661258

The failure I noticed in the log:

7266 Running test: POSIX: width in %s should be computed in bytes, not in characters
7267 Test ../../Test/D07multibyte.ztst was expected to fail, but passed.
7268 Was testing: POSIX: width in %s should be computed in bytes, not in characters
7269 ../../Test/D07multibyte.ztst: test XPassed.
7270 The following may (or may not) help identifying the cause:
7271  This is considered a bugfix in zsh
7272 ../../Test/D08cmdsubst.ztst: starting.

And in the end:

8850 61 successful test scripts, 1 failure, 2 skipped

Hopefully that's the failure mentioned in the summary, because I found
no other.

I've uploaded it to Debian Experimental anyway to see if it builds
fine on the official build daemons. Will see later today.

BTW: I expected that scp tab completion fails with OpenSSH 9.0 as it
uses SFTP as backend now which needs less quoting. But to my surprise
it still seems to work.

		Kind regards, Axel
-- 
PGP: 2FF9CD59612616B5      /~\  Plain Text Ribbon Campaign, http://arc.pasp.de/
Mail: abe@deuxchevaux.org  \ /  Say No to HTML in E-Mail and Usenet
Mail+Jabber: abe@noone.org  X
https://axel.beckert.ch/   / \  I love long mails: https://email.is-not-s.ms/


^ permalink raw reply	[relevance 4%]

* Re: _time_zone gives me candidates other than timezones
  2022-04-05 23:18  3%       ` Jordan Russell
@ 2022-04-06 20:11  0%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2022-04-06 20:11 UTC (permalink / raw)
  To: Jordan Russell; +Cc: Jun. T, Zsh hackers list

On Tue, Apr 5, 2022 at 4:19 PM Jordan Russell
<jordan.likes.curry@gmail.com> wrote:
>
> I like Jun's solution.

That's good, because it's already been added to the repository.
However, I did notice that if one explicitly attempts to start a
timezone name with "z" or "l", the lower case file names are in fact
offered (instead of, for example, correcting to Zulu).

> I still have reservations about completing right/
> and posix/ (they could be flags instead to the calling program).

Do you mean the calling program might use those as keywords (with no
leading hyphen[s])?  Or do you mean the caller of _time_zone should
[be able to] specify whether to include them?

> >I guess it comes down to whether you call _time_zone to find a zoneinfo
> >/file/ or a timezone /name/.
[...]
> > But if you're completing filenames you'd also need to recover
> >the prefix which is lost when using -W as is used now.

Further, if you start completing the tail of an absolute path, normal
file completion occurs.


^ permalink raw reply	[relevance 0%]

* Re: _time_zone gives me candidates other than timezones
  @ 2022-04-05 23:18  3%       ` Jordan Russell
  2022-04-06 20:11  0%         ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Jordan Russell @ 2022-04-05 23:18 UTC (permalink / raw)
  To: Jun. T; +Cc: zsh-workers

I like Jun's solution. I still have reservations about completing right/
and posix/ (they could be flags instead to the calling program). But the
difference isn't a really big one.

That said I did write a big email about it and I think I only sent it to
Aaron Schrab (sorry). So now I'm quoting it here and actually CC'ing the list

>I guess it comes down to whether you call _time_zone to find a zoneinfo
>/file/ or a timezone /name/.
>
>If you're just completing the name of a timezone then whether the name
>of the timezone refers to a `right` timezone or a `posix` timezone seems
>like it could be better handled by the programmer calling
>_time_zone. After all the names under right/ and posix/ are identical so
>the directory prefix only adds a bit of semantic information, which
>would probably be better handled as an argument somehwere beforehand
>rather than parsed out later.
>
>If you're calling _time_zone to complete zoneinfo files themselves then
>excluding posix/ and right/ is wrong since each directory houses
>different files and so their differences can't be easily accounted for
>otherwise. But if you're completing filenames you'd also need to recover
>the prefix which is lost when using -W as is used now.
>
>> I'm a bit more puzzled about why the separate `posix` directory exists. 
>> At least for my local time zone it doesn't seem to matter if I use that 
>> or leave it out; while using the `right` one definitely makes a 
>> difference:
>Yeah, I get the same behavior on my system.
>
>So, no I wasn't aware of the difference between right/ and posix/ but I
>also don't think their exclusion will matter since I think _time_zone is
>more for completing names by way of files and the files themselves are
>not relevant in this context.
>


"Jun. T" <takimoto-j@kba.biglobe.ne.jp> writes:

>> 2022/03/30 9:12, Aaron Schrab <aaron@schrab.com> wrote:
>> 
>> While I don't think I've ever really needed to use zoneinfo entries from those directories, I'd certainly prefer they be offered for completion.
>
> How about this?
>
> diff --git a/Completion/Unix/Type/_time_zone b/Completion/Unix/Type/_time_zone
> index cd924bbc7..c437252a8 100644
> --- a/Completion/Unix/Type/_time_zone
> +++ b/Completion/Unix/Type/_time_zone
> @@ -6,4 +6,4 @@ if (( ! $+_zoneinfo_dirs )); then
>    _zoneinfo_dirs=( /usr/{share,lib,share/lib}/{zoneinfo*,locale/TZ}(/) )
>  fi
>  
> -_wanted time-zones expl 'time zone' _files -W _zoneinfo_dirs "$@" -
> +_wanted time-zones expl 'time zone' _files -g '[A-Z]*' -W _zoneinfo_dirs "$@" -


^ permalink raw reply	[relevance 3%]

* [PATCH] Change documentation, dedication, loose ends
@ 2022-04-03  3:29  5% dana
  0 siblings, 0 replies; 200+ results
From: dana @ 2022-04-03  3:29 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 11382 bytes --]

I've gone through the history since 5.8 and updated the documentation
for all of the changes we missed before. Attaching the patch here just
to make sure i've correctly understood what they all do.

I've also attached a patch for the dedication we discussed off-list.

And, unposted here, i've added the new -s option to _fc.

Some other minor loose ends:

* In workers/47922 Daniel had suggested some changes to the documentation
  for the CASE_PATHS option Bart added; these changes were never merged or
  commented on. Are we satisfied with Bart's original documentation?

* The ${name:offset:length} expansion documentation was not updated with
  Jun's change from workers/49853. Does it need to be?

PS: Trying a different mail client, please let me know if it messes
the text up. Patches also included as attachments just in case

dana


From 200d3209e591839de391752d330575adb7ada8ea Mon Sep 17 00:00:00 2001
From: dana <dana@dana.is>
Date: Sat, 2 Apr 2022 22:19:04 -0500
Subject: [PATCH 1/2] NEWS/README: Add missing change documentation for 5.9

This covers the following changes:

users/24971: ${(-)var} sorts on signed integers

47704: POSIX export and readonly ignore "-p" when parameter names also appear

47913: implement CASE_PATHS option to make NO_CASE_GLOB more sensible

48073: Add fc -s as POSIX way of rerunning command without starting editor

49307 with doc update: POSIX_TRAPS fix.

49528: allow multiple -D options to compadd

49561: add zformat -F option, similar to -f but ternary expressions check for
existence instead of doing math evaluation

49597: add a helper for completing numbers with unit suffixes and separate out
defaults, ranges and units in completion descriptions

49611 based on 49590 (Martijn Dekker): disable Inf and NaN in math expressions
for sh emulation

49646: allow colors in WATCHFMT with %F/%K

49694 + doc: Allow using empty STTY= to freeze tty for a single command

49853 + 49882/49883: make "${arr[*]:off}" compatible with ksh/bash
---
 NEWS   | 72 ++++++++++++++++++++++++++++++++++++++++++----------------
 README | 33 +++++++++++++++++++--------
 2 files changed, 76 insertions(+), 29 deletions(-)

diff --git a/NEWS b/NEWS
index 8441610b0..61ee32ef1 100644
--- a/NEWS
+++ b/NEWS
@@ -4,25 +4,8 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.8
------------------
-
-CVE-2021-45444: Some prompt expansion sequences, such as %F, support
-'arguments' which are themselves expanded in case they contain colour
-values, etc. This additional expansion would trigger PROMPT_SUBST
-evaluation, if enabled. This could be abused to execute code the user
-didn't expect. e.g., given a certain prompt configuration, an attacker
-could trick a user into executing arbitrary code by having them check
-out a Git branch with a specially crafted name.
-
-This is fixed in the shell itself by no longer performing PROMPT_SUBST
-evaluation on these prompt-expansion arguments.
-
-Users who are concerned about an exploit but unable to update their
-binaries may apply the partial work-around described in the file
-Etc/CVE-2021-45444-VCS_Info-workaround.patch included with the shell
-source. [ Reported by RyotaK <security@ryotak.me>. Additional thanks to
-Marc Cornellà <hello@mcornella.com>. ]
+Changes since 5.8.1
+-------------------
 
 When unsetting a hash element, the string enclosed in square brackets is
 interpreted literally after any normal command-line-argument expansions.
@@ -54,6 +37,9 @@ fractional seconds.
 The option CLOBBER_EMPTY was added to enable the overwrite behaviour
 of CLOBBER for empty files only. It is disabled by default.
 
+A (-) expansion flag was added. It works like (n) but correctly sorts
+negative numbers.
+
 The compinit function learnt a -w option to explain why compdump runs.
 When run without the -i or -u options and compaudit discovers security
 issues, answering "y" to the "Ignore insecure ..." prompt removes the
@@ -69,11 +55,37 @@ widgets.  This corresponds to long-standing behavior of other user ZLE
 widgets.  Use the _complete_debug widget to capture XTRACE output, or
 use "functions -T" to enable tracing of specific completion functions.
 
+The fc builtin learnt an -s option which is a POSIX equivalent to the
+`fc -e-` method of re-executing a command without invoking an editor.
+
+The option CASE_PATHS was added to control how NO_CASE_GLOB behaves.
+NO_CASE_GLOB + NO_CASE_PATHS is equivalent to the current NO_CASE_GLOB
+behaviour. NO_CASE_GLOB + CASE_PATHS treats only path components that
+contain globbing characters as case-insensitive; this behaviour may
+yield more predictable results on case-sensitive file systems.
+NO_CASE_PATHS is the default.
+
 With the new TYPESET_TO_UNSET option set, "typeset foo" leaves foo unset,
 in contrast to the default behavior which assigns foo="".  Any parameter
 attributes such as numeric type, sorting, and padding are retained until
 the parameter is explicitly unset or a conflicting value is assigned.
-This is similar to default behavior of bash and ksh.
+This is similar to default behavior of bash and ksh.  This option is
+disabled by default.
+
+The compadd builtin's -D option can now be specified more than once.
+
+The zsh/zutil module's zformat builtin learnt an -F option which behaves
+like -f except that ternary expressions check for existence instead of
+doing math evaluation.
+
+A _numbers helper function has been added to help completion functions
+complete numbers with unit suffixes, etc.
+
+The WATCHFMT parameter now supports colours via the %F and %K escapes.
+
+The STTY parameter can now be set to an empty string before running a
+command to automatically restore terminal settings after the command
+finishes.
 
 The "jobs" command and "$jobstates" and related parameters can report on
 parent shell jobs even in subshells.  This is a snapshot of the parent
@@ -81,6 +93,26 @@ state, frozen at the point the subshell started.  However, if a subshell
 starts its own background jobs, the parent state is discarded in order
 to report on those new jobs.
 
+Changes from 5.8 to 5.8.1
+-------------------------
+
+CVE-2021-45444: Some prompt expansion sequences, such as %F, support
+'arguments' which are themselves expanded in case they contain colour
+values, etc. This additional expansion would trigger PROMPT_SUBST
+evaluation, if enabled. This could be abused to execute code the user
+didn't expect. e.g., given a certain prompt configuration, an attacker
+could trick a user into executing arbitrary code by having them check
+out a Git branch with a specially crafted name.
+
+This is fixed in the shell itself by no longer performing PROMPT_SUBST
+evaluation on these prompt-expansion arguments.
+
+Users who are concerned about an exploit but unable to update their
+binaries may apply the partial work-around described in the file
+Etc/CVE-2021-45444-VCS_Info-workaround.patch included with the shell
+source. [ Reported by RyotaK <security@ryotak.me>. Additional thanks to
+Marc Cornellà <hello@mcornella.com>. ]
+
 Changes from 5.7.1-test-3 to 5.8
 --------------------------------
 
diff --git a/README b/README
index c27d6881a..21142e17c 100644
--- a/README
+++ b/README
@@ -5,11 +5,12 @@ THE Z SHELL (ZSH)
 Version
 -------
 
-This is version 5.8.1 of the shell.  This is a security and bugfix release.
+This is version 5.9 of the shell.  This is a security and feature release.
+There are several visible improvements since 5.8.1, as well as bug fixes.
 All zsh installations are encouraged to upgrade as soon as possible.
 
 Note in particular the changes highlighted under "Incompatibilities since
-5.8" below.  See NEWS for more information.
+5.8.1" below.  See NEWS for more information.
 
 Installing Zsh
 --------------
@@ -30,16 +31,13 @@ Zsh is a shell with lots of features.  For a list of some of these, see the
 file FEATURES, and for the latest changes see NEWS.  For more
 details, see the documentation.
 
-Incompatibilities since 5.8
----------------------------
+Incompatibilities since 5.8.1
+-----------------------------
 
 compinit: A "y" response to the "Ignore ... and continue?" prompt removes
 insecure elements from the set of completion functions, where previously
 it ignored the compaudit result and included all elements.
 
-PROMPT_SUBST expansion is no longer performed on arguments to prompt-
-expansion sequences such as %F.
-
 Build-time change: The default value of the --enable-gdbm configure
 argument has changed from "yes" to "no".  Thus, the zsh/db/gdbm module will
 not be built unless --enable-gdbm is passed explicitly.
@@ -105,11 +103,25 @@ emulate sh: When zsh emulates sh, the final command in a pipeline is now run in
 a subshell.  This differs from the behavior in the native (zsh) mode, but is
 consistent with most other sh implementations.
 
+The export and readonly builtins now ignore the -p option when there are
+operands given and POSIX_BUILTINS is enabled. This more closely matches the
+behaviour of bash and ksh.
+
 getopts now calculates OPTIND in a similar manner to other shells when the
 POSIX_BUILTINS option is enabled.
 
-Incompatibilities between 5.7.1 and 5.8
----------------------------------------
+Ignored-signal traps are now inherited by subshells when the POSIX_TRAPS
+option is enabled.
+
+emulate sh: Inf and NaN are now treated as parameter names in arithmetic
+context when zsh is emulating sh.
+
+The ${name:offset:length} expansion syntax now behaves more similarly to
+other shells in that the offset and length are applied as array indices
+prior to scalar conversion in e.g. "${*:0:2}".
+
+Incompatibilities between 5.7.1 and 5.8.1
+-----------------------------------------
 
 The history expansion !:1:t2 used to be interpreted such that the 2
 was a separate character added after the history expansion.  Now
@@ -140,6 +152,9 @@ changes made in the course of fixing CVE-2019-20044.  Please report this
 to the zsh-workers mailing list if your system is affected.  See NEWS for
 more.
 
+PROMPT_SUBST expansion is no longer performed on arguments to prompt-
+expansion sequences such as %F.
+
 Incompatibilities between 5.6.2 and 5.7.1
 -----------------------------------------
 
-- 
2.34.1


From 1ffc4b86c4d76d91d18661bcf12d0b306deb472a Mon Sep 17 00:00:00 2001
From: dana <dana@dana.is>
Date: Sat, 2 Apr 2022 22:20:55 -0500
Subject: [PATCH 2/2] NEWS: Dedicate zsh 5.9 to Sven Guckes

---
 NEWS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/NEWS b/NEWS
index 61ee32ef1..6c9112ad6 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,11 @@ Note also the list of incompatibilities in the README file.
 
 Changes since 5.8.1
 -------------------
+zsh 5.9 is dedicated in memory of Sven Guckes, who was, amongst other
+things, a long-time zsh advocate.
+
+  https://linuxnews.de/2022/02/sven-guckes-verstorben/
+  https://groups.google.com/g/vim_announce/c/MJBKVd-xrEE/m/joVNaDgAAgAJ
 
 When unsetting a hash element, the string enclosed in square brackets is
 interpreted literally after any normal command-line-argument expansions.
-- 
2.34.1

[-- Attachment #2: patch-1-changes.txt --]
[-- Type: text/plain, Size: 9412 bytes --]

From 200d3209e591839de391752d330575adb7ada8ea Mon Sep 17 00:00:00 2001
From: dana <dana@dana.is>
Date: Sat, 2 Apr 2022 22:19:04 -0500
Subject: [PATCH 1/2] NEWS/README: Add missing change documentation for 5.9

This covers the following changes:

users/24971: ${(-)var} sorts on signed integers

47704: POSIX export and readonly ignore "-p" when parameter names also appear

47913: implement CASE_PATHS option to make NO_CASE_GLOB more sensible

48073: Add fc -s as POSIX way of rerunning command without starting editor

49307 with doc update: POSIX_TRAPS fix.

49528: allow multiple -D options to compadd

49561: add zformat -F option, similar to -f but ternary expressions check for
existence instead of doing math evaluation

49597: add a helper for completing numbers with unit suffixes and separate out
defaults, ranges and units in completion descriptions

49611 based on 49590 (Martijn Dekker): disable Inf and NaN in math expressions
for sh emulation

49646: allow colors in WATCHFMT with %F/%K

49694 + doc: Allow using empty STTY= to freeze tty for a single command

49853 + 49882/49883: make "${arr[*]:off}" compatible with ksh/bash
---
 NEWS   | 72 ++++++++++++++++++++++++++++++++++++++++++----------------
 README | 33 +++++++++++++++++++--------
 2 files changed, 76 insertions(+), 29 deletions(-)

diff --git a/NEWS b/NEWS
index 8441610b0..61ee32ef1 100644
--- a/NEWS
+++ b/NEWS
@@ -4,25 +4,8 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.8
------------------
-
-CVE-2021-45444: Some prompt expansion sequences, such as %F, support
-'arguments' which are themselves expanded in case they contain colour
-values, etc. This additional expansion would trigger PROMPT_SUBST
-evaluation, if enabled. This could be abused to execute code the user
-didn't expect. e.g., given a certain prompt configuration, an attacker
-could trick a user into executing arbitrary code by having them check
-out a Git branch with a specially crafted name.
-
-This is fixed in the shell itself by no longer performing PROMPT_SUBST
-evaluation on these prompt-expansion arguments.
-
-Users who are concerned about an exploit but unable to update their
-binaries may apply the partial work-around described in the file
-Etc/CVE-2021-45444-VCS_Info-workaround.patch included with the shell
-source. [ Reported by RyotaK <security@ryotak.me>. Additional thanks to
-Marc Cornellà <hello@mcornella.com>. ]
+Changes since 5.8.1
+-------------------
 
 When unsetting a hash element, the string enclosed in square brackets is
 interpreted literally after any normal command-line-argument expansions.
@@ -54,6 +37,9 @@ fractional seconds.
 The option CLOBBER_EMPTY was added to enable the overwrite behaviour
 of CLOBBER for empty files only. It is disabled by default.
 
+A (-) expansion flag was added. It works like (n) but correctly sorts
+negative numbers.
+
 The compinit function learnt a -w option to explain why compdump runs.
 When run without the -i or -u options and compaudit discovers security
 issues, answering "y" to the "Ignore insecure ..." prompt removes the
@@ -69,11 +55,37 @@ widgets.  This corresponds to long-standing behavior of other user ZLE
 widgets.  Use the _complete_debug widget to capture XTRACE output, or
 use "functions -T" to enable tracing of specific completion functions.
 
+The fc builtin learnt an -s option which is a POSIX equivalent to the
+`fc -e-` method of re-executing a command without invoking an editor.
+
+The option CASE_PATHS was added to control how NO_CASE_GLOB behaves.
+NO_CASE_GLOB + NO_CASE_PATHS is equivalent to the current NO_CASE_GLOB
+behaviour. NO_CASE_GLOB + CASE_PATHS treats only path components that
+contain globbing characters as case-insensitive; this behaviour may
+yield more predictable results on case-sensitive file systems.
+NO_CASE_PATHS is the default.
+
 With the new TYPESET_TO_UNSET option set, "typeset foo" leaves foo unset,
 in contrast to the default behavior which assigns foo="".  Any parameter
 attributes such as numeric type, sorting, and padding are retained until
 the parameter is explicitly unset or a conflicting value is assigned.
-This is similar to default behavior of bash and ksh.
+This is similar to default behavior of bash and ksh.  This option is
+disabled by default.
+
+The compadd builtin's -D option can now be specified more than once.
+
+The zsh/zutil module's zformat builtin learnt an -F option which behaves
+like -f except that ternary expressions check for existence instead of
+doing math evaluation.
+
+A _numbers helper function has been added to help completion functions
+complete numbers with unit suffixes, etc.
+
+The WATCHFMT parameter now supports colours via the %F and %K escapes.
+
+The STTY parameter can now be set to an empty string before running a
+command to automatically restore terminal settings after the command
+finishes.
 
 The "jobs" command and "$jobstates" and related parameters can report on
 parent shell jobs even in subshells.  This is a snapshot of the parent
@@ -81,6 +93,26 @@ state, frozen at the point the subshell started.  However, if a subshell
 starts its own background jobs, the parent state is discarded in order
 to report on those new jobs.
 
+Changes from 5.8 to 5.8.1
+-------------------------
+
+CVE-2021-45444: Some prompt expansion sequences, such as %F, support
+'arguments' which are themselves expanded in case they contain colour
+values, etc. This additional expansion would trigger PROMPT_SUBST
+evaluation, if enabled. This could be abused to execute code the user
+didn't expect. e.g., given a certain prompt configuration, an attacker
+could trick a user into executing arbitrary code by having them check
+out a Git branch with a specially crafted name.
+
+This is fixed in the shell itself by no longer performing PROMPT_SUBST
+evaluation on these prompt-expansion arguments.
+
+Users who are concerned about an exploit but unable to update their
+binaries may apply the partial work-around described in the file
+Etc/CVE-2021-45444-VCS_Info-workaround.patch included with the shell
+source. [ Reported by RyotaK <security@ryotak.me>. Additional thanks to
+Marc Cornellà <hello@mcornella.com>. ]
+
 Changes from 5.7.1-test-3 to 5.8
 --------------------------------
 
diff --git a/README b/README
index c27d6881a..21142e17c 100644
--- a/README
+++ b/README
@@ -5,11 +5,12 @@ THE Z SHELL (ZSH)
 Version
 -------
 
-This is version 5.8.1 of the shell.  This is a security and bugfix release.
+This is version 5.9 of the shell.  This is a security and feature release.
+There are several visible improvements since 5.8.1, as well as bug fixes.
 All zsh installations are encouraged to upgrade as soon as possible.
 
 Note in particular the changes highlighted under "Incompatibilities since
-5.8" below.  See NEWS for more information.
+5.8.1" below.  See NEWS for more information.
 
 Installing Zsh
 --------------
@@ -30,16 +31,13 @@ Zsh is a shell with lots of features.  For a list of some of these, see the
 file FEATURES, and for the latest changes see NEWS.  For more
 details, see the documentation.
 
-Incompatibilities since 5.8
----------------------------
+Incompatibilities since 5.8.1
+-----------------------------
 
 compinit: A "y" response to the "Ignore ... and continue?" prompt removes
 insecure elements from the set of completion functions, where previously
 it ignored the compaudit result and included all elements.
 
-PROMPT_SUBST expansion is no longer performed on arguments to prompt-
-expansion sequences such as %F.
-
 Build-time change: The default value of the --enable-gdbm configure
 argument has changed from "yes" to "no".  Thus, the zsh/db/gdbm module will
 not be built unless --enable-gdbm is passed explicitly.
@@ -105,11 +103,25 @@ emulate sh: When zsh emulates sh, the final command in a pipeline is now run in
 a subshell.  This differs from the behavior in the native (zsh) mode, but is
 consistent with most other sh implementations.
 
+The export and readonly builtins now ignore the -p option when there are
+operands given and POSIX_BUILTINS is enabled. This more closely matches the
+behaviour of bash and ksh.
+
 getopts now calculates OPTIND in a similar manner to other shells when the
 POSIX_BUILTINS option is enabled.
 
-Incompatibilities between 5.7.1 and 5.8
----------------------------------------
+Ignored-signal traps are now inherited by subshells when the POSIX_TRAPS
+option is enabled.
+
+emulate sh: Inf and NaN are now treated as parameter names in arithmetic
+context when zsh is emulating sh.
+
+The ${name:offset:length} expansion syntax now behaves more similarly to
+other shells in that the offset and length are applied as array indices
+prior to scalar conversion in e.g. "${*:0:2}".
+
+Incompatibilities between 5.7.1 and 5.8.1
+-----------------------------------------
 
 The history expansion !:1:t2 used to be interpreted such that the 2
 was a separate character added after the history expansion.  Now
@@ -140,6 +152,9 @@ changes made in the course of fixing CVE-2019-20044.  Please report this
 to the zsh-workers mailing list if your system is affected.  See NEWS for
 more.
 
+PROMPT_SUBST expansion is no longer performed on arguments to prompt-
+expansion sequences such as %F.
+
 Incompatibilities between 5.6.2 and 5.7.1
 -----------------------------------------
 
-- 
2.34.1

[-- Attachment #3: patch-2-dedication.txt --]
[-- Type: text/plain, Size: 848 bytes --]

From 1ffc4b86c4d76d91d18661bcf12d0b306deb472a Mon Sep 17 00:00:00 2001
From: dana <dana@dana.is>
Date: Sat, 2 Apr 2022 22:20:55 -0500
Subject: [PATCH 2/2] NEWS: Dedicate zsh 5.9 to Sven Guckes

---
 NEWS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/NEWS b/NEWS
index 61ee32ef1..6c9112ad6 100644
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,11 @@ Note also the list of incompatibilities in the README file.
 
 Changes since 5.8.1
 -------------------
+zsh 5.9 is dedicated in memory of Sven Guckes, who was, amongst other
+things, a long-time zsh advocate.
+
+  https://linuxnews.de/2022/02/sven-guckes-verstorben/
+  https://groups.google.com/g/vim_announce/c/MJBKVd-xrEE/m/joVNaDgAAgAJ
 
 When unsetting a hash element, the string enclosed in square brackets is
 interpreted literally after any normal command-line-argument expansions.
-- 
2.34.1

^ permalink raw reply	[relevance 5%]

* PATCH: Add nonblock to sysopen
@ 2022-03-31  3:58  3% Matthew Martin
  0 siblings, 0 replies; 200+ results
From: Matthew Martin @ 2022-03-31  3:58 UTC (permalink / raw)
  To: zsh-workers

A while back CcxWrk on IRC noted sysopen doesn't support O_NONBLOCK.

The POSIX spec for open requires O_NONBLOCK; however, since the spec
also requires O_CLOEXEC, O_NOFOLLOW, and O_SYNC, I wrapped nonblock in
an ifdef as well.

While here, the name member of the struct ought to be const.


diff --git a/Doc/Zsh/mod_system.yo b/Doc/Zsh/mod_system.yo
index 399b6fe03..884c3e753 100644
--- a/Doc/Zsh/mod_system.yo
+++ b/Doc/Zsh/mod_system.yo
@@ -62,6 +62,9 @@ suppress updating of the file atime
 item(tt(nofollow))(
 fail if var(file) is a symbolic link
 )
+item(tt(nonblock))(
+the file is opened in nonblocking mode
+)
 item(tt(sync))(
 request that writes wait until data has been physically written
 )
diff --git a/Src/Modules/system.c b/Src/Modules/system.c
index ecd4e2546..71745548f 100644
--- a/Src/Modules/system.c
+++ b/Src/Modules/system.c
@@ -280,7 +280,7 @@ bin_syswrite(char *nam, char **args, Options ops, UNUSED(int func))
 }
 
 
-static struct { char *name; int oflag; } openopts[] = {
+static struct { const char *name; int oflag; } openopts[] = {
 #ifdef O_CLOEXEC
     { "cloexec", O_CLOEXEC },
 #else
@@ -296,6 +296,9 @@ static struct { char *name; int oflag; } openopts[] = {
 #endif
 #ifdef O_NOATIME
     { "noatime", O_NOATIME },
+#endif
+#ifdef O_NONBLOCK
+    { "nonblock", O_NONBLOCK},
 #endif
     { "excl", O_EXCL | O_CREAT },
     { "creat", O_CREAT },


^ permalink raw reply	[relevance 3%]

* Re: _time_zone gives me candidates other than timezones
  2022-03-29 23:22  3% ` Bart Schaefer
@ 2022-03-30  0:12  5%   ` Aaron Schrab
    0 siblings, 1 reply; 200+ results
From: Aaron Schrab @ 2022-03-30  0:12 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Jordan Russell, Zsh hackers list

At 16:22 -0700 29 Mar 2022, Bart Schaefer <schaefer@brasslantern.com> wrote:
>On Thu, Mar 24, 2022 at 12:28 PM Jordan Russell
><jordan.likes.curry@gmail.com> wrote:
>>
>> I would like _time_zone to exclude these filenames that are not
>> timezones [...]
>>
>> If I modify it to just exclude those files that begin with a lowercase
>> letter then it gives me only proper timezone names.
>
>That excludes the directories "posix" and "right" on my system (I have
>no idea what the latter one means).

Quoting from https://www.ucolick.org/~sla/leapsecs/right+gps.html:

    The "right" files in the tz (zoneinfo) database have a subtle 
    difference from the POSIX standard. POSIX requires that the system 
    clock value of time_t represent the number of non-leap seconds since 
    1970-01-01. This is the same as requiring POSIX seconds to be mean 
    solar seconds of UT, not the atomic seconds that UTC has counted 
    since 1972-01-01.

   The "right" zoneinfo files assert that the system clock value of 
   time_t represent the actual number of seconds in the internationally 
   approved broadcast time scale since 1970-01-01. As a result the value 
   of time_t which is expected by the "right" zoneinfo files is greater 
   than the value of time_t specified by POSIX. The difference in the 
   values of time_t is the number of leap seconds which have been 
   inserted into the internationally approved broadcast time scale. As of 
   year 2011 the difference is 24 seconds. 

I'm a bit more puzzled about why the separate `posix` directory exists. 
At least for my local time zone it doesn't seem to matter if I use that 
or leave it out; while using the `right` one definitely makes a 
difference:

date; TZ=right/America/New_York date; TZ=posix/America/New_York date
2022-03-29T20:07:47 EDT
2022-03-29T20:07:20 EDT
2022-03-29T20:07:47 EDT

>Is everyone OK with that?

While I don't think I've ever really needed to use zoneinfo entries from 
those directories, I'd certainly prefer they be offered for completion.


^ permalink raw reply	[relevance 5%]

* Re: _time_zone gives me candidates other than timezones
  @ 2022-03-29 23:22  3% ` Bart Schaefer
  2022-03-30  0:12  5%   ` Aaron Schrab
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2022-03-29 23:22 UTC (permalink / raw)
  To: Jordan Russell; +Cc: Zsh hackers list

On Thu, Mar 24, 2022 at 12:28 PM Jordan Russell
<jordan.likes.curry@gmail.com> wrote:
>
> I would like _time_zone to exclude these filenames that are not
> timezones [...]
>
> If I modify it to just exclude those files that begin with a lowercase
> letter then it gives me only proper timezone names.

That excludes the directories "posix" and "right" on my system (I have
no idea what the latter one means).

Is everyone OK with that?


^ permalink raw reply	[relevance 3%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  2022-03-23  7:14  4%         ` Jun T
@ 2022-03-29  9:10 15%           ` Jun T
  0 siblings, 0 replies; 200+ results
From: Jun T @ 2022-03-29  9:10 UTC (permalink / raw)
  To: zsh-workers


> 2022/03/23 16:14, I wrote:
> 
> If the 'expected to fail' test exists for reminding us that we are
> (intentionally?) contradicting with POSIX, the test need be run under
> UTF-8 locale (in D07multibyte.ztst), with
> 
>> < Stéphane>      # single ' ' before 'S'


In the following patch the test is moved to D07multibyte.ztst, and
another test (expected to fail) is added to indicate that the precision
(5 in '%7.5s') should also be computed in bytes.


diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index 7f046525a..cbd802f23 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -347,6 +347,18 @@
 0:Multibyte characters in printf widths
 > főo
 
+# TODO?: POSIX requires that printf should always compute width and
+# precision of '%s' conversion in bytes, while zsh computes them in
+# characters if multi-byte locale is in use.
+  ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%10s>\n' St$'\M-C\M-)'phane"
+0f:POSIX: width in %s should be computed in bytes, not in characters
+F:This is considered a bugfix in zsh
+>< Stéphane>
+
+  ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%7.5s>\n' St$'\M-C\M-)'phane"
+0f:POSIX: precision should also be computed in bytes, not in characers
+><  Stép>
+
 # We ask for case-insensitive sorting here (and supply upper case
 # characters) so that we exercise the logic in the shell that lowers the
 # case of the string for case-insensitive sorting.
diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst
index b191199ad..caab97ab6 100644
--- a/Test/E03posix.ztst
+++ b/Test/E03posix.ztst
@@ -157,10 +157,5 @@ F:POSIX has neither math functions nor floating point
 -f:EUID is not a special variable
 >10
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%10s>\n' St$'\M-C\M-)'phane"
-0f:Width of %s is computed in bytes not characters
-F:This is considered a bugfix in zsh
-><  Stéphane>
-
   PPID=foo
 -f:PPID is not a readonly variable

^ permalink raw reply	[relevance 15%]

* [PATCH] Re: Parallel processing
       [not found]         ` <CAH+w=7ZRAQTVBfvw1XN=2xEGVNf2ShD6eck+_iv=fGLcEqBLBg@mail.gmail.com>
@ 2022-03-27 17:38  4%       ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2022-03-27 17:38 UTC (permalink / raw)
  To: Zsh hackers list

[-- Attachment #1: Type: text/plain, Size: 1218 bytes --]

[Moving to -workers]

On Sat, Mar 26, 2022 at 3:19 PM Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> > Anyways, zargs is not doing a stellar job currently with collecting
> > exit statuses from commands ran in parallel:
>
> There might be something more that could be done now, to
> pick up the status of the rest ... but I'm reluctant to mess with that
> while the segfault is unfixed.

I found a different reproducer for the segfault, and had an idea about
zargs, so ... I messed with it ...

> Hmm ... zargs uses
>   wait ${${jobstates[(R)running:*]/#*:/}/%=*/}

$jobstates can be avoided by collecting the values of $! in a local array.

> However, that "wait" returns the exit status of only one

As noted in the comments in (the current iteration of) zargs, "wait
$j1 $j2 $j3 ..." waits for all those jobs and returns the status of
whichever one exits last.  However, "wait" with no arguments places
all the exit status in the internal list of exited jobs, after which
the statuses may be collected individually by "wait $j1; wait $j2;
wait $j3".  It's not possible to wait for the same specific job more
than once, so it doesn't work to first wait for a list of jobs and
then wait again for each of them.

[-- Attachment #2: zargs_jobs.txt --]
[-- Type: text/plain, Size: 2461 bytes --]

diff --git a/Functions/Misc/zargs b/Functions/Misc/zargs
index ecd69f7e4..81916a3ac 100644
--- a/Functions/Misc/zargs
+++ b/Functions/Misc/zargs
@@ -43,14 +43,12 @@
 # than 127 for "command not found" so this function incorrectly returns
 # 123 in that case if used with zsh 4.0.x.
 #
-# With the --max-procs option, zargs may not correctly capture the exit
-# status of the backgrounded jobs, because of limitations of the "wait"
-# builtin.  If the zsh/parameter module is not available, the status is
-# NEVER correctly returned, otherwise the status of the longest-running
-# job in each batch is captured.
+# Because of "wait" limitations, --max-procs spawns max-procs jobs, then
+# waits for all of those, then spawns another batch, etc.
 #
-# Also because of "wait" limitations, --max-procs spawns max-procs jobs,
-# then waits for all of those, then spawns another batch, etc.
+# The maximum number of parallel jobs for which exit status is available
+# is determined by the sysconf CHILD_MAX parameter, which can't be read
+# or changed from within the shell.
 #
 # Differences from POSIX xargs:
 #
@@ -69,6 +67,9 @@
 #   -I/-L and implementations reportedly differ.)  In zargs, -i/-I have
 #   this behavior, as do -l/-L, but when -i/-I appear anywhere then -l/-L
 #   are ignored (forced to 1).
+#
+# * The use of SIGUSR1 and SIGUSR2 to change the number of parallel jobs
+#   is not supported.
 
 # First, capture the current setopts as "sticky emulation"
 if zmodload zsh/parameter
@@ -86,7 +87,7 @@ fi
 emulate -L zsh || return 1
 local -a opts eof n s l P i
 
-local ZARGS_VERSION="1.5"
+local ZARGS_VERSION="1.7"
 
 if zparseopts -a opts -D -- \
 	-eof::=eof e::=eof \
@@ -264,17 +265,19 @@ if (( P != 1 && ARGC > 1 ))
 then
     # These setopts are necessary for "wait" on multiple jobs to work.
     setopt nonotify nomonitor
-    bg='&'
-    if zmodload -i zsh/parameter 2>/dev/null
-    then
-	wait='wait ${${jobstates[(R)running:*]/#*:/}/%=*/}'
-    else
-	wait='wait'
-    fi
+    local -a _zajobs
+    local j
+    bg='& _zajobs+=( $! )'
+    wait='wait'
+    analyze='
+    for j in $_zajobs; do
+      wait $j
+      '"$analyze"'
+    done; _zajobs=()'
 fi
 
-# Everything has to be in a subshell just in case of backgrounding jobs,
-# so that we don't unintentionally "wait" for jobs of the parent shell.
+# Everything has to be in a subshell so that we don't "wait" for any
+# unrelated jobs of the parent shell.
 (
 
 while ((ARGC))

^ permalink raw reply	[relevance 4%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  2022-03-23 10:38  5%           ` Stephane Chazelas
@ 2022-03-23 16:17  0%             ` Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2022-03-23 16:17 UTC (permalink / raw)
  To: zsh-workers

On 2022-03-23 10:38:35 +0000, Stephane Chazelas wrote:
> It's been raised several times on the POSIX mailing list, and
> my understanding the opengroup doesn't consider it as a bug, and
> they have made it clear that they would not address it. They may
> consider specifying ksh93's %Ls (which pads based on display
> width, not byte nor character count) if enough implementations
> start to support it.
> 
> That's why I didn't bother raising it as a bug personally, but
> to me, that position (where printf(1) is meant to be an
> interface to printf(3) without decoding those bytes into
> characters) does not make sense. printf is to print formatted
> text, not doing padding of binary strings. printf(3) was
> extended with wprintf(3) to handle wide characters, printf(1)
> should have been enhanced to switch to that or equivalent just
> like every other text utility is now specified to be able to
> cope with wide characters.

Counting bytes seems useful, e.g. because file formats have fields
with some maximum length in *bytes*. Counting characters seems
less common. It would be more interesting to search for scripts
that use %s with a width and/or a precision, and see what they
expect.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 0%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  2022-03-23  2:26  3%         ` Vincent Lefevre
@ 2022-03-23 10:38  5%           ` Stephane Chazelas
  2022-03-23 16:17  0%             ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2022-03-23 10:38 UTC (permalink / raw)
  To: zsh-workers

2022-03-23 03:26:44 +0100, Vincent Lefevre:
> On 2022-03-22 14:04:30 -0700, Bart Schaefer wrote:
> > Specifically in this instance, we consider it a POSIX bug that '%s'
> > always counts byte positions and that zsh has fixed this when it
> > counts character positions.
> 
> But, AFAIK, on the POSIX side, it has never been regarded as a bug
> (I haven't seen any bug report).
[...]

It's been raised several times on the POSIX mailing list, and
my understanding the opengroup doesn't consider it as a bug, and
they have made it clear that they would not address it. They may
consider specifying ksh93's %Ls (which pads based on display
width, not byte nor character count) if enough implementations
start to support it.

That's why I didn't bother raising it as a bug personally, but
to me, that position (where printf(1) is meant to be an
interface to printf(3) without decoding those bytes into
characters) does not make sense. printf is to print formatted
text, not doing padding of binary strings. printf(3) was
extended with wprintf(3) to handle wide characters, printf(1)
should have been enhanced to switch to that or equivalent just
like every other text utility is now specified to be able to
cope with wide characters.

printf(1) should need to decode arguments into text if only
because in the format or %b arguments, the "\" character (also
"%" in the format) is being interpreted specially. zsh doesn't
btw (which may be considered a bug, but then again those
non-UTF8 multibyte charsets are poorly supported throughout,
and to me it doesn't seem worth the effort given that hardly
anybody uses multibyte charsets other than UTF-8 these days):

$ LC_ALL=zh_HK SHELL=/bin/zsh luit
zsh$ locale charmap
BIG5-HKSCS
zsh$ printf 'αb' | hd
00000000  a3 08                                             |..|
00000002

(as α is encoded as 0xa3 0x5c in BIG5-HKSCS as used in that
locale, 0x5c being also \)

Yash is probably the only shell that does implement the POSIX
spec as POSIXly likely intends it to be:

~$ LC_ALL=zh_HK SHELL=yash luit
yash$ printf 'αb' | hd
00000000  a3 5c 62                                          |.\b|
00000003
yash$ printf %5s 'αb' | hd
00000000  20 20 a3 5c 62                                    |  .\b|
00000005
yash$ printf %5b 'αb' | hd
00000000  20 20 a3 5c 62                                    |  .\b|
00000005

That is bytes are decoded into characters for those backslashes
to be interpreted "correctly" (yash does decode everything, it's
not specific to printf¹), and then encoded back to behave as if
being passed to printf(3) as POSIX requires.

I've not verified it, but I've read somewhere the C standard was
considering enhancing printf("%.3s") so it doesn't break
characters in the middle (or maybe it's already the case?).
So printf '%.3s\n' Stéphane, where é is UTF-8 encoded in a
locale using UTF-8 would output "St" instead of "St<0xc3>".

My opinion would be:

- not change how %5s works in zsh. To me, zsh made an effort to
  fix that, I can't expect anyone relying on the POSIX
  behaviour which to me is a bug. One can always do

    printf() {
      set -o localoptions +o multibyte; builtin printf "$@"
    }

  if they want the POSIX behaviour.

- no need to fix the problems with backslashes in those
  messed-up multibyte encodings as I'd expect they're being
  phased out.

- maybe implement ksh93's %Ls (zsh does have a ${(ml[5])param}
  alternative though it does both padding and truncation).

---
¹ That approach is not tenable IMO as that means yash can't cope
with arbitrary file paths, arguments, or environment variables

-- 
Stephane


^ permalink raw reply	[relevance 5%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  2022-03-22 21:04  5%       ` Bart Schaefer
  2022-03-23  2:26  3%         ` Vincent Lefevre
@ 2022-03-23  7:14  4%         ` Jun T
  2022-03-29  9:10 15%           ` Jun T
  1 sibling, 1 reply; 200+ results
From: Jun T @ 2022-03-23  7:14 UTC (permalink / raw)
  To: zsh-workers


> 2022/03/23 6:04, Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
> On Mon, Mar 21, 2022 at 8:33 PM Jun T <takimoto-j@kba.biglobe.ne.jp> wrote:
> 
>> [2] Why is the test marked "expected to fail"?
> 
> POSIX printf counts bytes regardless of locale, zsh printf counts
> characters in multibyte locales.

>> What does 'F:This is considered a bugfix in zsh' mean?

> Specifically in this instance, we consider it a POSIX bug that '%s'
> always counts byte positions and that zsh has fixed this when it
> counts character positions.

Thanks for the explanation.

If the 'expected to fail' test exists for reminding us that we are
(intentionally?) contradicting with POSIX, the test need be run under
UTF-8 locale (in D07multibyte.ztst), with

>< Stéphane>      # single ' ' before 'S'

as the POSIX-conforming output. Am I right?



^ permalink raw reply	[relevance 4%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  2022-03-22 21:04  5%       ` Bart Schaefer
@ 2022-03-23  2:26  3%         ` Vincent Lefevre
  2022-03-23 10:38  5%           ` Stephane Chazelas
  2022-03-23  7:14  4%         ` Jun T
  1 sibling, 1 reply; 200+ results
From: Vincent Lefevre @ 2022-03-23  2:26 UTC (permalink / raw)
  To: zsh-workers

On 2022-03-22 14:04:30 -0700, Bart Schaefer wrote:
> Specifically in this instance, we consider it a POSIX bug that '%s'
> always counts byte positions and that zsh has fixed this when it
> counts character positions.

But, AFAIK, on the POSIX side, it has never been regarded as a bug
(I haven't seen any bug report).

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  @ 2022-03-22 21:04  5%       ` Bart Schaefer
  2022-03-23  2:26  3%         ` Vincent Lefevre
  2022-03-23  7:14  4%         ` Jun T
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2022-03-22 21:04 UTC (permalink / raw)
  To: Jun T; +Cc: Zsh hackers list

On Mon, Mar 21, 2022 at 8:33 PM Jun T <takimoto-j@kba.biglobe.ne.jp> wrote:
>
> [1] Does this patch solve the problem?

All tests pass for me on Ubuntu (which isn't a change from before the
patch, but is not a regression either)

> [2] Why is the test marked "expected to fail"?

POSIX printf counts bytes regardless of locale, zsh printf counts
characters in multibyte locales.  The test is expected to fail because
the sample output represents counting characters.  If the test
succeeds, zsh is not following POSIX printf requirements, and we need
to find out why.  Theoretically, if we've correctly implemented
POSIX_BUILTINS, we should not have to test in the C locale in order
for this test to "fail as expected" and if it succeeds (as not
expected) in any locale, something is wrong with the builtin.

Sorry for not following up on that sooner.  It may mean your patch is
actually masking a problem.

> What does 'F:This is considered a bugfix in zsh' mean?

# It is also possible to add lines in the redirection section beginning
# with `F:'.  The remaining text on all such lines will be concatenated
# (with newlines in between) and displayed in the event of an error.

Specifically in this instance, we consider it a POSIX bug that '%s'
always counts byte positions and that zsh has fixed this when it
counts character positions.

> If the test is expected to be run in C locale, then isn't
> < Stéphane>  (a single space before S)
> the "correct" result?

Yes it is, but it's also the expected result for POSIX_BUILTINS if run
in a different locale.


^ permalink raw reply	[relevance 5%]

* Re: Test ./E03posix.ztst was expected to fail, but passed.
  @ 2022-03-16 15:30  7%   ` Jun. T
    0 siblings, 1 reply; 200+ results
From: Jun. T @ 2022-03-16 15:30 UTC (permalink / raw)
  To: zsh-workers


> 2022/03/16 1:53, Mikael Magnusson <mikachu@gmail.com> wrote:
> 
> On 3/15/22, Vincent Lefevre <vincent@vinc17.net> wrote:
>> 
>> Test ./E03posix.ztst was expected to fail, but passed.
>> Was testing: Width of %s is computed in bytes not characters
>> ./E03posix.ztst: test XPassed.
(snip)
>> I don't know the current status... Has this been discussed in the
>> austin-group list?
(snip)
> Noticed and discussed a bit on IRC the other week/month (sorry for
> unedited irc log)
(snip)
> 19:26 <Mikachu> but my LC_CTYPE is set to that, and LC_ALL is unset


Please try the following patch.

The patch for E03posix.ztst may not be necessary for fixing the
current problem, but I think it is always safer to use 'zsh -f'.


diff --git a/Test/E03posix.ztst b/Test/E03posix.ztst
index b191199ad..9695777f6 100644
--- a/Test/E03posix.ztst
+++ b/Test/E03posix.ztst
@@ -125,39 +125,39 @@
 F:POSIX requires a solitary "-" to be a plain argument
 >-
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'foreach() { true; }'
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'foreach() { true; }'
 -f:"foreach" is not a reserved word
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'end() { true; }
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'end() { true; }
 -f:"end" is not a reserved word
 
-  a='a:b:' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a'
+  a='a:b:' ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'IFS=:; printf "<%s>\n" $a'
 0f:IFS is a separator, not a delimiter
 ><a>
 ><b>
 
-  a=$'\ra\r\rb' ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=:; printf "<%s>\n" $a'
+  a=$'\ra\r\rb' ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'IFS=:; printf "<%s>\n" $a'
 0f:All whitespace characters are "IFS whitespace"
 F:isspace('\r') is true so \r should behave like space, \t, \n
 F:This may also need to apply to multibyte whitespace
 ><a>
 ><b>
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'IFS=2; printf "<%s>\n" $((11*11))'
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'IFS=2; printf "<%s>\n" $((11*11))'
 0f:IFS applies to math results (numbers treated as strings)
 ><1>
 ><1>
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'inf=42; echo $((inf))'
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'inf=42; echo $((inf))'
 0:All identifiers are variable references in POSIX arithmetic
 F:POSIX has neither math functions nor floating point
 >42
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c 'EUID=10; echo "$EUID"'
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc 'EUID=10; echo "$EUID"'
 -f:EUID is not a special variable
 >10
 
-  ARGV0=sh $ZTST_testdir/../Src/zsh -c "printf '<%10s>\n' St$'\M-C\M-)'phane"
+  ARGV0=sh $ZTST_testdir/../Src/zsh -fc "printf '<%10s>\n' St$'\M-C\M-)'phane"
 0f:Width of %s is computed in bytes not characters
 F:This is considered a bugfix in zsh
 ><  Stéphane>
diff --git a/Test/ztst.zsh b/Test/ztst.zsh
index a59c06dcf..43f8ed730 100755
--- a/Test/ztst.zsh
+++ b/Test/ztst.zsh
@@ -25,6 +25,7 @@ emulate -R zsh
 # Ensure the locale does not screw up sorting.  Don't supply a locale
 # unless there's one set, to minimise problems.
 [[ -n $LC_ALL ]] && LC_ALL=C
+[[ -n $LC_CTYPE ]] && LC_CTYPE=C
 [[ -n $LC_COLLATE ]] && LC_COLLATE=C
 [[ -n $LC_NUMERIC ]] && LC_NUMERIC=C
 [[ -n $LC_MESSAGES ]] && LC_MESSAGES=C






^ permalink raw reply	[relevance 7%]

* Re: Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1
  2022-03-03 11:52  5%   ` Peter Stephenson
@ 2022-03-03 22:59  0%     ` Lyude Paul
  0 siblings, 0 replies; 200+ results
From: Lyude Paul @ 2022-03-03 22:59 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers

Woo - seems to fix the problem on my end! :)

Don't know if y'all use these, but feel free to consider this patch:

Tested-by: Lyude Paul <lyude@redhat.com>

On Thu, 2022-03-03 at 11:52 +0000, Peter Stephenson wrote:
> diff --git a/Src/input.c b/Src/input.c
> index caeaff0e3..50cd2cd78 100644
> --- a/Src/input.c
> +++ b/Src/input.c
> @@ -223,13 +223,20 @@ shingetchar(void)
>         return STOUC(*shinbufptr++);
>  
>      shinbufreset();
> -    do {
> +    for (;;) {
>         errno = 0;
> -       nread = read(SHIN, shinbuffer, SHINBUFSIZE);
> -    } while (nread < 0 && errno == EINTR);
> -    if (nread <= 0)
> +       nread = read(SHIN, shinbufendptr, 1);
> +       if (nread > 0) {
> +           /* Use line buffering (POSIX requirement) */
> +           if (*shinbufendptr++ == '\n')
> +               break;
> +           if (shinbufendptr == shinbuffer + SHINBUFSIZE)
> +               break;
> +       } else if (nread == 0 || errno != EINTR)
> +           break;
> +    }
> +    if (shinbufendptr == shinbuffer)
>         return -1;
> -    shinbufendptr = shinbuffer + nread;
>      return STOUC(*shinbufptr++);
>  }
>  
> diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
> index 4e39a8f3c..0312fe94e 100644
> --- a/Test/A01grammar.ztst
> +++ b/Test/A01grammar.ztst
> @@ -961,3 +961,12 @@ F:Note that the behaviour of 'exit' inside try-list
> inside a function is unspeci
>  F:This test was written to ensure the behaviour doesn't change silently.
>  F:If this test fails during development, it *might* be appropriate to
> change
>  F:its expectations.
> +
> + (
> +   export VALUE=first
> +   print -l 'echo Value is $VALUE' 'VALUE=second sh' 'echo Value is $VALUE'
> |
> +   $ZTST_testdir/../Src/zsh -f
> + )
> +0:Non-interactive shell command input is line buffered
> +>Value is first
> +>Value is second

-- 
Cheers,
 Lyude Paul (she/her)
 Software Engineer at Red Hat



^ permalink raw reply	[relevance 0%]

* Re: Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1
  2022-03-03  9:39  5% ` Peter Stephenson
@ 2022-03-03 11:52  5%   ` Peter Stephenson
  2022-03-03 22:59  0%     ` Lyude Paul
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2022-03-03 11:52 UTC (permalink / raw)
  To: Lyude Paul, zsh-workers

> On 03 March 2022 at 09:39 Peter Stephenson <p.w.stephenson@ntlworld.com> wrote> > On 02 March 2022 at 22:38 Lyude Paul <lyude@redhat.com> wrote:
> > Running on zsh 5.8 returns:
> > 
> >    Shell is 70
> >    Shell is 71
> > 
> > Running on zsh 5.8.1 however, returns:
> > 
> >    Shell is 86396
> >    Shell is 86396
> 
> Thanks for the nice simple test --- I'll try and concoct something similar
> but predictable for the shell tests.

Added to the patch; I've confirmed this succeeds or fails as expected.

pws

diff --git a/Src/input.c b/Src/input.c
index caeaff0e3..50cd2cd78 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -223,13 +223,20 @@ shingetchar(void)
 	return STOUC(*shinbufptr++);
 
     shinbufreset();
-    do {
+    for (;;) {
 	errno = 0;
-	nread = read(SHIN, shinbuffer, SHINBUFSIZE);
-    } while (nread < 0 && errno == EINTR);
-    if (nread <= 0)
+	nread = read(SHIN, shinbufendptr, 1);
+	if (nread > 0) {
+	    /* Use line buffering (POSIX requirement) */
+	    if (*shinbufendptr++ == '\n')
+		break;
+	    if (shinbufendptr == shinbuffer + SHINBUFSIZE)
+		break;
+	} else if (nread == 0 || errno != EINTR)
+	    break;
+    }
+    if (shinbufendptr == shinbuffer)
 	return -1;
-    shinbufendptr = shinbuffer + nread;
     return STOUC(*shinbufptr++);
 }
 
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index 4e39a8f3c..0312fe94e 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -961,3 +961,12 @@ F:Note that the behaviour of 'exit' inside try-list inside a function is unspeci
 F:This test was written to ensure the behaviour doesn't change silently.
 F:If this test fails during development, it *might* be appropriate to change
 F:its expectations.
+
+ (
+   export VALUE=first
+   print -l 'echo Value is $VALUE' 'VALUE=second sh' 'echo Value is $VALUE' |
+   $ZTST_testdir/../Src/zsh -f
+ )
+0:Non-interactive shell command input is line buffered
+>Value is first
+>Value is second


^ permalink raw reply	[relevance 5%]

* Re: Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1
  2022-03-02 22:38  4% Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1 Lyude Paul
@ 2022-03-03  9:39  5% ` Peter Stephenson
  2022-03-03 11:52  5%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2022-03-03  9:39 UTC (permalink / raw)
  To: Lyude Paul, zsh-workers


> On 02 March 2022 at 22:38 Lyude Paul <lyude@redhat.com> wrote:
> 
> 
> Hi! I'm reporting this here because after some discussion in #zsh, it was
> determined this is likely both a regression, and also isn't POSIX compliant.
> Keep in mind I don't have as clear of an understanding of what's happening
> below the hood here as I'd like, so I'm not 100% the subject line here is
> correct. I've got plenty of examples to clarify though :)
> 
> Basically, what seems to be happening is that since 5.8.1 zsh no longer seems
> to correctly handle input from stdin unless the terminal is in interactive
> mode.
> 
> Here's a simple example script that demonstrates what I mean:
> 
>    printf '%s\n' 'echo Shell is $$' sh 'echo Shell is $$' | zsh
> 
> Running on zsh 5.8 returns:
> 
>    Shell is 70
>    Shell is 71
> 
> Running on zsh 5.8.1 however, returns:
> 
>    Shell is 86396
>    Shell is 86396

Thanks for the nice simple test --- I'll try and concoct something similar
but predictable for the shell tests.

I hope it's as simple as the following.  I can't think of any optimisation
or a case where line buffering would be wrong.

pws

diff --git a/Src/input.c b/Src/input.c
index caeaff0e3..50cd2cd78 100644
--- a/Src/input.c
+++ b/Src/input.c
@@ -223,13 +223,20 @@ shingetchar(void)
 	return STOUC(*shinbufptr++);
 
     shinbufreset();
-    do {
+    for (;;) {
 	errno = 0;
-	nread = read(SHIN, shinbuffer, SHINBUFSIZE);
-    } while (nread < 0 && errno == EINTR);
-    if (nread <= 0)
+	nread = read(SHIN, shinbufendptr, 1);
+	if (nread > 0) {
+	    /* Use line buffering (POSIX requirement) */
+	    if (*shinbufendptr++ == '\n')
+		break;
+	    if (shinbufendptr == shinbuffer + SHINBUFSIZE)
+		break;
+	} else if (nread == 0 || errno != EINTR)
+	    break;
+    }
+    if (shinbufendptr == shinbuffer)
 	return -1;
-    shinbufendptr = shinbuffer + nread;
     return STOUC(*shinbufptr++);
 }


^ permalink raw reply	[relevance 5%]

* Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1
@ 2022-03-02 22:38  4% Lyude Paul
  2022-03-03  9:39  5% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Lyude Paul @ 2022-03-02 22:38 UTC (permalink / raw)
  To: zsh-workers

Hi! I'm reporting this here because after some discussion in #zsh, it was
determined this is likely both a regression, and also isn't POSIX compliant.
Keep in mind I don't have as clear of an understanding of what's happening
below the hood here as I'd like, so I'm not 100% the subject line here is
correct. I've got plenty of examples to clarify though :)

Basically, what seems to be happening is that since 5.8.1 zsh no longer seems
to correctly handle input from stdin unless the terminal is in interactive
mode.

Here's a simple example script that demonstrates what I mean:

   printf '%s\n' 'echo Shell is $$' sh 'echo Shell is $$' | zsh

Running on zsh 5.8 returns:

   Shell is 70
   Shell is 71

Running on zsh 5.8.1 however, returns:

   Shell is 86396
   Shell is 86396

This can end up being an issue when trying to do things like (assuming sudo is
configured on this system to not request a password, and zsh is the default
shell):

   ssh foo <<- _EOF_
   whoami
   sudo -s
   whoami
   _EOF_

While that's maybe not the best way of doing such things in shell, I have
quite a number of scripts that rely on this working and have for quite some
time. According to llua from #zsh as well, this is also likely not POSIX
compliant according to:

   https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html (see the
   section labeled "INPUT FILES")

llua suggested that this breakage may have come from
e5cd2dd980302f328d232d933f646c3dc02828bf ("49290: Replace stdio for buffered
shell input."), which I've confirmed to be true by bisecting this locally. 

For reference: I originally reproduced this on Fedora 35, although I have a
feeling that probably doesn't matter too much here. If there's any other
information I can provide that would help with getting this fixed, don't
hesistate to ask. And thank you ahead of time!
-- 
Cheers,
 Lyude Paul (she/her)
 Software Engineer at Red Hat



^ permalink raw reply	[relevance 4%]

* can we have an option for cd to do a plain chdir()
@ 2022-02-06 17:44  2% Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2022-02-06 17:44 UTC (permalink / raw)
  To: Zsh hackers list

I was surprised to see that after:

ln -s /proc/self/cwd/.. link; cd link

I ended up two directories up instead of one.

strace revealed:

$ strace -fe getcwd,readlink,chdir,fchdir zsh -c 'cd link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
chdir("/home/chazelas/link")            = 0
chdir("/home/chazelas/link")            = 0
+++ exited with 0 +++

Not sure why the two chdir()s there.

That it prepends $PWD to the path is also a problem if the
current working directory has been renamed, but most shells do
that without -P.

It's better in that case with cd -P or with chaselinks:

$ strace -fe getcwd,readlink,chdir,fchdir zsh -c 'cd -P link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
chdir("/home/chazelas/link")            = 0
readlink("/home", 0x7ffe6ba34f00, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffe6ba34f00, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas/link", "/proc/self/cwd/..", 4096) = 17
readlink("/proc", 0x7ffe6ba2fe70, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/self", "1000438", 4096) = 7
readlink("/proc/1000438", 0x7ffe6ba2ade0, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/1000438/cwd", "/home", 4096) = 5
readlink("/home", 0x7ffe6ba2ade0, 4096) = -1 EINVAL (Invalid argument)
chdir("..")                             = 0
chdir("/home")                          = 0
+++ exited with 0 +++
~$ strace -fe getcwd,readlink,chdir,fchdir zsh -o chaselinks -c 'cd link'
readlink("/proc/self/fd/0", "/dev/pts/4", 4095) = 10
readlink("/home", 0x7ffdfc3e0f40, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffdfc3e0f40, 4096) = -1 EINVAL (Invalid argument)
chdir("/home/chazelas/link")            = 0
readlink("/home", 0x7ffdfc3df960, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas", 0x7ffdfc3df960, 4096) = -1 EINVAL (Invalid argument)
readlink("/home/chazelas/link", "/proc/self/cwd/..", 4096) = 17
readlink("/proc", 0x7ffdfc3da8d0, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/self", "1002598", 4096) = 7
readlink("/proc/1002598", 0x7ffdfc3d5840, 4096) = -1 EINVAL (Invalid argument)
readlink("/proc/1002598/cwd", "/home", 4096) = 5
readlink("/home", 0x7ffdfc3d5840, 4096) = -1 EINVAL (Invalid argument)
chdir("..")                             = 0
chdir("/home")                          = 0
+++ exited with 0 +++

But that sounds a bit overkill and racy.

In scripts, you usually want your cd's to do plain chdir()s but
there are many things that get in the way:

- the need for -P to avoid the logical traversal
- the need to -- as usual for avoid problems with dirnames
  starting with -
- CDPATH (it is inherited from the environment but at least when
  not in POSIX mode, that doesn't take precedence over actual
  relative path).
- The "-" string that is taken as $OLDPWD
- Also in zsh, the -n +n ones.
- and then there's that special fancy chasing of symlinks

So, to do an actual chdir, we need something like:

chdir() {
  case $1 in
    (/*) cd -P "$1";;
    ('') print -u2 "not sure out to chdir to an empty string";;
    (*) cd -P "./$1";;
  esac
}

Which addresses the first 5 points, but not the 6th.

It would be nice if we could just do for instance cd -r -- $dir
which would just a do chdir($dir) and set $PWD to getcwd() if
successful.

(or have chdir (which atm exits as a builtin for tcsh junkies I
suppose) do that and not take any option).

What do you think?

-- 
Stephane


^ permalink raw reply	[relevance 2%]

* [PATCH] new completions for csplit, pr, ptx, truncate
@ 2022-01-31 14:32  3% Jun. T
  0 siblings, 0 replies; 200+ results
From: Jun. T @ 2022-01-31 14:32 UTC (permalink / raw)
  To: zsh-workers

These commands are in GNU coreutils, but there are non-GNU variants also.

pr accepts -2 -3 -4 ... for specifying number of columns.
The _pr below offers only -2 and -3, but I think it's enough.
pr also accepts +page_number to start printing from the specified page.
It is taken care of before calling _arguments.

csplit, pr and ptx accept a single '-' as a file name (to read from stdin).
For non-GNU variant (i.e., for BSD variant) we need to use
_argument -A '-?*'   (or -A '[-+]?*' for pr)
to stop completing options for 'csplit - -<TAB>'.



diff --git a/Completion/Unix/Command/_csplit b/Completion/Unix/Command/_csplit
new file mode 100644
index 000000000..5f72232bb
--- /dev/null
+++ b/Completion/Unix/Command/_csplit
@@ -0,0 +1,51 @@
+#compdef csplit
+
+local curcontext=$curcontext cnt_info ret=1
+local -a state state_descr line specs optA
+typeset -A opt_args
+
+# common specs
+specs=(
+  '(hv -f --prefix)'{-f+,--prefix=}'[specify prefix for output file names]:prefix [xx]: '
+  '(hv -n --digits -b --suffix-format)'{-n+,--digits=}'[specify number of digits in output file names]:number [2]: '
+  '(hv -k --keep-files)'{-k,--keep-files}'[do not remove output files on errors]'
+  '(hv -s --quiet --silent)'{-s,--quiet,--silent}'[do not print counts of output file sizes]'
+  '(hv)1: :_files'
+  '(hv)*: :->patterns'
+)
+
+if _pick_variant gnu=GNU unix --version; then
+  # GNU coreutils 8.32
+  specs+=(
+    '(hv -b --suffix-format -n --digits)'{-b+,--suffix-format=}'[specify format for numbers in output file names]:format [%%02d]: '
+    '(hv)--suppress-matched[suppress the lines matching the pattern]'
+    '(hv -z --elide-empty)'{-z,--elide-empty-files}'[remove empty output files]'
+    + hv
+    '(: * -)--help[display help and exit]'
+    '(: * -)--version[output version information and exit]'
+  )
+  cnt_info="(integer or '*')"
+else
+  # POSIX ({Free,Open}BSD, DragonFly, macOS)
+  specs=( ${specs:#(|*\))--*} )  # remove long options
+  optA=( -A '-?*' )  # a single '-' is a valid file name (stdin)
+fi
+
+_arguments -C -s -S $optA : $specs && ret=0
+
+case $state in
+  patterns)
+    if compset -P '(/?*/|%?*%)'; then
+      _message '[+|-]offset' && ret=0
+    elif compset -P '[/%]'; then
+      _message 'regex' && ret=0
+    elif compset -P '(|\\){'; then
+      _message "count $cnt_info" && ret=0
+    elif compset -P '[0-9]*'; then
+      _message 'line number' && ret=0
+    elif [[ ${words[CURRENT]} != -* ]] then
+      _message "line_number, '/regex/[offset]', '%%regex%%[offset]', or '{count}'" && ret=0
+    fi
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_pr b/Completion/Unix/Command/_pr
new file mode 100644
index 000000000..2aeeb13b3
--- /dev/null
+++ b/Completion/Unix/Command/_pr
@@ -0,0 +1,103 @@
+#compdef pr
+
+local curcontext=$curcontext variant msg ret=1
+local -a state state_descr line specs optA
+typeset -A opt_args
+
+# take care of '+FIRST_PAGE[:LAST_PAGE]' (GNU) or '+FIRST_PAGE' (POSIX)
+if _pick_variant -r variant gnu=GNU $OSTYPE --version; then
+  msg='FIRST_PAGE[:LAST_PAGE]'
+else
+  msg='first page'
+fi
+
+if [[ $words[CURRENT] = +* ]]; then
+  _message "$msg" && return
+fi
+
+if (( ! ${words[(I)+[0-9]*]} )); then
+  # if +number is not on the command line
+  specs=( '(hv)--pages=[specify first and last page numbers]: : _message $msg' )
+fi
+
+# common specs
+specs+=(
+  '(hv -a --across)'{-a,--across}'[with multi-column output, print columns across rather than down]'
+  '(hv -d --double-space)'{-d,--double-space}'[double space the output]'
+  '(hv -e --expand-tabs)'{-e-,--expand-tabs=-}'[expand tab (or specified char) with specified number of spaces]::number of spaces [8]:->char_number'
+  '(hv -h --header -t --omit-header)'{-h+,--header=}'[specify text used in header]:header: '
+  '(hv -i --output-tabs)'{-i-,--output-tabs=-}'[replace specified number of spaces with tab (or specified char)]::number of spaces [8]:->char_number'
+  '(hv -l --length)'{-l+,--length=}'[specify the page length]:number of lines [66]: '
+  '(hv -m --merge)'{-m,--merge}'[print all files in parallel, one in each column]'
+  '(hv -n --number-lines)'{-n-,--number-lines=-}'[number lines with specified separator and width]::number of digits [5]:->char_number'
+  '(hv -o --indent)'{-o+,--indent=}'[specify left margin]:margin [0]: '
+  '(hv -r -no-file-warnings)'{-r,--no-file-warnings}'[omit warning when a file cannot be opened]'
+  '(hv -s --separator)'{-s-,--separator=-}'[specify column separator character]:character [tab]: '
+  '(hv -t --omit-header -h --header)'{-t,--omit-header}'[omit page headers and trailers]'
+  '(hv -w --width)'{-w+,--width=}'[specify page width for multi-column output]:number of characters [72]: '
+  '(hv)*: :_files'
+)
+# XXX: pr accepts -2 -3 -4 ... for specifying the number of columns.
+#      Here we offer only -2 and -3, and do so only if there is no
+#      -2 -3 -4 ... or --columns on the command line.
+if (( ! ${words[(I)-([0-9]##*|-columns*)]} )); then
+  specs+=( {-2,-3}'[specify number of columns]' )
+fi
+
+if [[ $variant = gnu ]]; then
+  # GNU coreutils 8.32
+  specs+=(
+    '(hv -c --show-control-chars)'{-c,--show-control-chars}'[use hat (^G) and octal backslash notation]'
+    '(hv -D --date-format)'{-D+,--date-format=}'[specify format for the header date]: :_date_formats'
+    '(hv -f -F --form-feed)'{-f,-F,--form-feed}'[use form feeds instead of newlines to separate pages]'
+    '(hv -J --join-lines)'{-J,--join-lines}'[merge full lines in multi-column output]'
+    '(hv -N --first-line-number)'{-N+,--first-line-number=}'[specify the line number of the 1st line]:number: '
+    '(hv -S --sep-string)'{-S-,--sep-string=-}'[specify column separator string]:string: '
+    '(hv -T --omit-pagination)'{-T,--omit-pagination}'[omit page headers and trailers, eliminate any pagination]'
+    '(hv -v --show-nonprinting)'{-v,--show-nonprinting}'[use octal backslash notation]'
+    '(hv -W --page-width)'{-W+,--page-width=}'[specify page width always]:number of characters [72]: '
+  )
+  if (( ! ${words[(I)-[0-9]##*]} )); then
+    # if -2 -3 -4 ... are not on the command line
+    specs+=(
+      '(hv)--columns=[specify number of columns]:number of columns: '
+      + hv
+      '(- *)--help[display help and exit]'
+      '(- *)--version[output version information and exit]'
+    )
+  fi
+else
+  specs=( ${specs:#(|*\))--*} )    # remove long options
+  case $variant in
+    freebsd*|dragonfly*|darwin*|netbsd*)
+      specs+=(
+	'(-f)-F[use form feeds instead of newlines to separate pages]'
+	'(-F)-f[same as -F but pause before the 1st page if stdout is terminal]'
+	'-p[pause before each page if stdout is terminal]'
+      )
+      ;|
+    freebsd*|dragonfly*|darwin*)
+      specs+=( '-L+[specify locale to use]: :_locales' )
+      ;;
+    openbsd*)
+      specs+=( '(-f -F)'{-f,-F}'[use form feeds instead of newlines to separate pages]' )
+      ;;
+  esac
+  optA=( -A '[-+]?*' )  # a single '-' is a valid file name (stdin)
+fi
+
+_arguments -C -s -S $optA : $specs && ret=0
+
+case $state in
+  char_number)
+    # argument for option -e (and -i, -n) can be -e. -e10 or -e.10
+    # where . is any non-digit character
+    if compset -p 1; then
+      _message "$state_descr" && ret=0
+    else
+      _message "a character [tab] (optional), and $state_descr" && ret=0
+    fi
+    ;;
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_ptx b/Completion/Unix/Command/_ptx
new file mode 100644
index 000000000..12f1d2c9a
--- /dev/null
+++ b/Completion/Unix/Command/_ptx
@@ -0,0 +1,54 @@
+#compdef ptx
+
+local -a specs optA
+
+# common specs
+specs=(
+  '(hv -b --break-file)'{-b+,--break-file=}'[use characters in specified file as word separators]:break file:_files'
+  '(hv -f --ignore-case)'{-f,--ignore-case}'[fold lower case to upper case for sorting]'
+  '(hv -g --gap-size)'{-g+,--gap-size=}'[specify gap size between output fields]:number of chars [3]: '
+  '(hv -i --ignore-file)'{-i+,--ignore-file=}'[ignore keywords listed in specified file]:ignore file:_files'
+  '(hv -o --only-file)'{-o+,--only-file=}'[use only the keywords listed in specified file]:only file:_files'
+  '(hv -r --references)'{-r,--references}'[first field of each line is a reference]'
+  '(hv -w --width)'{-w+,--width=}'[specify page width, reference excluded]:number of characters [72]: '
+)
+
+if _pick_variant gnu=GNU unix --version; then
+  # GNU coreutils 8.32
+  specs+=(
+    '(hv -A --auto-reference)'{-A,--auto-reference}'[output automatically generated references]'
+    '(hv -G --traditional)'{-G,--traditional}"[behave more like System V 'ptx']"
+    '(hv -F --flag-truncation)'{-F+,--flag-truncation=}'[specify string for flagging line truncations]:string [/]: '
+    '(hv -M --macro-name)'{-M+,--macro-name=}"[specify macro name to use instead of 'xx']:macro name: "
+    '(hv)-O[generate output as roff directives]'
+    '(hv -R --right-side-refs)'{-R,--right-side-refs}'[put references at right, not counted in -w]'
+    '(hv -S --sentence-regexp)'{-S+,--sentence-regexp=}'[specify regexp for end of lines/sentences]:regexp: '
+    '(hv)-T[generate output as TeX directives]'
+    '(hv -W --word-regexp -b --break-file)'{-W+,--word-regexp=}'[specify regexp to match each keyword]:regexp: '
+    '(hv)--format=[specify the output format]:format:(roff tex)'
+    !{-t,--typeset-mode}'[not implemented]'
+    + hv
+    '(: * -)--help[display help and exit]'
+    '(: * -)--version[output version information and exit]'
+  )
+  if (( $words[(I)(-G|--traditional)] )); then
+    specs+=( + arg '1:input file:_files'  '2:output file:_files' )
+  else
+    specs+=( + arg '(-G --traditional)*:input file:_files' )
+  fi
+else
+  # The only non-GNU implementation I can find is the one in
+  # heirloom-doctools. FreeBSD has a package for this.
+  specs=( ${specs:#(|*\))--*} )    # remove long options
+  # remove '+' from -b+ -g+ -i+ -o+ -w+
+  local MATCH MBEGIN MEND
+  specs=( ${specs/(#m)-[bgiow]+/$MATCH[1,-2]} )
+  specs+=(
+    '-t[prepare output for typesetter]'
+    '1:input file:_files'
+    '2:output file:_files'
+  )
+  optA=( -A '-?*' )  # a single '-' is a valid file name (stdin)
+fi
+
+_arguments -s -S $optA : $specs
diff --git a/Completion/Unix/Command/_truncate b/Completion/Unix/Command/_truncate
new file mode 100644
index 000000000..117be9702
--- /dev/null
+++ b/Completion/Unix/Command/_truncate
@@ -0,0 +1,69 @@
+#compdef truncate
+
+local curcontext=$curcontext variant rs ret=1
+local -a state state_descr line specs optA
+typeset -A opt_args
+
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+[[ $variant != gnu ]] && rs='-r -s' # -r/-s mutually exclusive
+
+# common specs
+specs=(
+  '(hv -c --no-create)'{-c,--no-create}'[do not create any files]'
+  "(hv $rs -r --reference)"{-r+,--reference=}'[base size on the specified file]:reference file:_files'
+  "(hv $rs -s --size)"{-s+,--size=}'[set or adjust the file size by specified bytes]:size:->size'
+  '(hv)*: :_files'
+)
+
+case $variant in
+  gnu) # GNU coreutils 8.32
+    specs+=(
+      '(hv -o --io-blocks)'{-o,--io-blocks}'[treat the specified size as number of IO blocks instead of bytes]'
+      + 'hv'
+      '(- *)--help[display help and exit]'
+      '(- *)--version[output version information and exit]'
+    )
+    ;;
+  *) # FreeBSD/DragonFly
+    specs=( ${specs:#(|*\))--*} )    # remove long options
+    optA=( -A '-*' )
+    ;;
+esac
+
+_arguments -C -s -S : $specs && ret=0
+
+case $state in
+  size)
+    local unit=bytes
+    (( ${#opt_args[(I)(-o|--io-blocks)]} )) && unit=blocks
+    local -a suffix=( K:1024 M G T )
+    local -a prefix=( '+:extend by' '-:reduce by' )
+    local prefix_char='[-+]'
+    case $variant in
+      gnu|freebsd*)
+	prefix+=( '/:round down to multiple of' '%:round up to multiple of' )
+	;|
+      gnu)
+	suffix=( K:1024 KB:1000 {M,G,T,P,E,Z,Y}{,B} )
+	prefix+=( '<:at most' '>:at least' )
+	prefix_char='([-+/%]|\\[<>])'
+	;;
+      freebsd*)
+	prefix_char='[-+/%]'
+	;;
+    esac
+    local -a numbers=( _numbers -u $unit size $suffix )
+
+    if compset -P "$prefix_char"; then
+      $numbers && ret=0
+    elif (( ${#opt_args[(I)(-r|--reference)]} )); then
+      # prefix is required if the reference file is given
+      _describe -t 'prefixes' 'prefix' prefix && ret=0
+    else
+      _alternative "prefixes:prefix:((${(@q)prefix}))" \
+      		   "sizes: :$numbers" && ret=0
+    fi
+  ;;
+esac
+
+return ret





^ permalink raw reply	[relevance 3%]

* PATCH: update zfs completion
@ 2021-12-27 21:37  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2021-12-27 21:37 UTC (permalink / raw)
  To: Zsh workers

This brings the zfs completion up-to-date.

I've been using openzfs 2.1 on Linux, FreeBSD 13.0 and two year-old
Solaris 11 as my reference points.

We need to complete dataset properties for zpool so rather than retain
that duplication, I moved all of _zpool into _zfs. This also allows
_zfs_keysource_props (which was Solaris specific anyway) to be brought
into _zfs. I've reindented the function because very little is otherwise
unchanged anyway.

_zfs_dataset and _zfs_pool do need to be separated because they are
called from other functions. They should have been given plural names.
Any views on perhaps renaming them?

Otherwise, _zfs_dataset is fixed to work with the awk on Solaris, to
preserve descriptions and to handle the new bookmarks feature of
openzfs.

Many of the items marked with TODO in comments have been addressed but
some still remain. Completion of vdevs for, e.g zpool create is a lot
better but could be further improved as some combinations are not
possible. user/group quota is also much improved.

Oliver

diff --git a/Completion/Unix/Command/_zfs b/Completion/Unix/Command/_zfs
index 51da9170b..be4a64b33 100644
--- a/Completion/Unix/Command/_zfs
+++ b/Completion/Unix/Command/_zfs
@@ -1,561 +1,1350 @@
-#compdef zfs
-# Synced with the S11U1 man page
+#compdef zfs zdb zpool
 
-_zfs() {
-	local context state line expl implementation
-	typeset -A opt_args
-	local -a subcmds rw_properties rw_propnames ro_properties create_properties
-	local -a share_nfs_ro_properties share_nfs_rw_properties
-	local -a share_smb_ro_properties share_smb_rw_properties
-	local -a share_ro_properties share_rw_properties
-	local -a difffields delegatable_perms
+local curcontext="$curcontext" implementation nm="$compstate[nmatches]"
+local -a state curstate line state_descr expl alts args
+typeset -A opt_args val_args
+local MATCH MBEGIN MEND
+local -a subcmds
+local -a share_nfs_ro_properties share_nfs_rw_properties
+local -a share_smb_ro_properties share_smb_rw_properties
+local -a share_ro_properties share_rw_properties
+local -a difffields delegatable_perms key_properties
+local -a ds_types sum_algorithms comp_algorithms dedup_algorithms
 
-	_pick_variant -r implementation -c 'zpool upgrade -v' openzfs='This system supports ZFS pool feature flags' solaris
+local -a ds_propnames ro_ds_props rw_ds_props ci_ds_props # dataset properties
+local -a po_propnames ro_po_props rw_po_props ci_po_props # pool properties
 
-	subcmds=(
-		"create" "destroy" "clone" "promote" "rename" "snapshot"
-		"rollback" "list" "set" "get" "inherit" "mount" "unmount"
-		"share" "unshare" "send" "receive" "allow" "unallow"
-		"upgrade" "userspace" "groupspace" "hold" "holds" "release"
-		"diff" "key" "help"
-	)
+_pick_variant -r implementation -c 'zpool upgrade -v' openzfs='This system supports ZFS pool feature flags' solaris
 
-  [[ $OSTYPE == freebsd<7->.* ]] && subcmds+=(jail unjail)
+ds_types=( filesystem snapshot volume all )
+sum_algorithms=( on off fletcher2 fletcher4 sha256 )
+comp_algorithms=( on off lzjb lz4 gzip gzip-{1..9} zle )
+dedup_algorithms=( on off verify sha256 sha256,verify )
 
-	share_nfs_ro_properties=(
-		"share.nfs.all"
-	)
+ro_po_props=( # readonly
+  'all[all properties]'
+  'allocated[space allocated]'
+  'capacity[space used (percentage)]'
+  'dedupratio[deduplication ratio]'
+  'free[space unallocated]'
+  'health[health status]'
+  'size[total size]'
+)
+ci_po_props=( # only set at create or import
+  'altroot[alternate root directory]:path:_directories'
+  'guid[unique identifier]:identifier'
+  'readonly[whether the pool can be modified]:value:(on off)'
+)
+rw_po_props=(
+  'autoexpand[automatic pool expansion]:value:(on off)'
+  'autoreplace[automatic device replacement]:value:(on off)'
+  'bootfs[default bootable dataset]:dataset:_zfs_dataset'
+  'cachefile[pool configuration cache file location]:value'
+  'dedupditto[threshold for number of copies]:value [0]'
+  'delegation[delegated administration]:value:(on off)'
+  'failmode[failure-mode behavior]:value:(wait continue panic)'
+  "listshares[show shares in 'zfs list']:value:(on off)"
+  "listsnaps[show snapshots in 'zfs list']:value:(on off)"
+  'version[pool version]:version'
+)
 
-	share_nfs_rw_properties=(
-		"share.nfs:value:(on off)"
-		"share.nfs.aclok:value:(on off)"
-		"share.nfs.acflfab:value:(on off)"
-		"share.nfs.anon:uid:"
-		"share.nfs.charset.euc-cn:access-list:"
-		"share.nfs.charset.euc-jpms:access-list:"
-		"share.nfs.charset.euc-kr:access-list:"
-		"share.nfs.charset.euc-tw:access-list:"
-		"share.nfs.charset.iso8859-1:access-list:"
-		"share.nfs.charset.iso8859-2:access-list:"
-		"share.nfs.charset.iso8859-5:access-list:"
-		"share.nfs.charset.iso8859-6:access-list:"
-		"share.nfs.charset.iso8859-7:access-list:"
-		"share.nfs.charset.iso8859-8:access-list:"
-		"share.nfs.charset.iso8859-9:access-list:"
-		"share.nfs.charset.iso8859-13:access-list:"
-		"share.nfs.charset.iso8859-15:access-list:"
-		"share.nfs.charset.koi8-r:access-list:"
-		"share.nfs.index:file:_files"
-		"share.nfs.log:nfslog.conf tag:"
-		"share.nfs.nosub:value:(on off)"
-		"share.nfs.nosuid:value:(on off)"
-		"share.nfs.public:value:(on off)"
-		"share.nfs.sec:security-mode-list:"
-		"share.nfs.sec.default.none:access-list:"
-		"share.nfs.sec.default.ro:access-list:"
-		"share.nfs.sec.default.root:access-list:"
-		"share.nfs.sec.default.root_mapping:uid:"
-		"share.nfs.sec.default.rw:access-list:"
-		"share.nfs.sec.default.window:seconds"
-		"share.nfs.sec.dh.none:access-list:"
-		"share.nfs.sec.dh.ro:access-list:"
-		"share.nfs.sec.dh.root:access-list:"
-		"share.nfs.sec.dh.root_mapping:uid:"
-		"share.nfs.sec.dh.rw:access-list:"
-		"share.nfs.sec.dh.window:seconds"
-		"share.nfs.sec.krb5.none:access-list:"
-		"share.nfs.sec.krb5.ro:access-list:"
-		"share.nfs.sec.krb5.root:access-list:"
-		"share.nfs.sec.krb5.root_mapping:uid:"
-		"share.nfs.sec.krb5.rw:access-list:"
-		"share.nfs.sec.krb5.window:seconds"
-		"share.nfs.sec.krb5i.none:access-list:"
-		"share.nfs.sec.krb5i.ro:access-list:"
-		"share.nfs.sec.krb5i.root:access-list:"
-		"share.nfs.sec.krb5i.root_mapping:uid:"
-		"share.nfs.sec.krb5i.rw:access-list:"
-		"share.nfs.sec.krb5i.window:seconds"
-		"share.nfs.sec.krb5p.none:access-list:"
-		"share.nfs.sec.krb5p.ro:access-list:"
-		"share.nfs.sec.krb5p.root:access-list:"
-		"share.nfs.sec.krb5p.root_mapping:uid:"
-		"share.nfs.sec.krb5p.rw:access-list:"
-		"share.nfs.sec.krb5p.window:seconds"
-		"share.nfs.sec.none.none:access-list:"
-		"share.nfs.sec.none.ro:access-list:"
-		"share.nfs.sec.none.root:access-list:"
-		"share.nfs.sec.none.root_mapping:uid:"
-		"share.nfs.sec.none.rw:access-list:"
-		"share.nfs.sec.none.window:seconds"
-		"share.nfs.sec.sys.none:access-list:"
-		"share.nfs.sec.sys.ro:access-list:"
-		"share.nfs.sec.sys.root:access-list:"
-		"share.nfs.sec.sys.root_mapping:uid:"
-		"share.nfs.sec.sys.rw:access-list:"
-		"share.nfs.sec.sys.window:seconds"
-	)
+# TODO: userused@ and groupused@ could have more extensive handling
+ro_ds_props=(
+  name type creation space used available referenced compressratio mounted
+  origin usedbychildren usedbydataset usedbyrefreservation usedbysnapshots
+  defer_destroy userused@ userrefs groupused@ keystatus
+)
+ci_ds_props=(
+  'casesensitivity:value:(sensitive insensitive mixed)'
+  'normalization:value:(none formC formD formKC formKD)'
+  'utf8only:value:(on off)'
+)
+rw_ds_props=(
+  'aclinherit:value:(discard noallow restricted passthrough passthrough-x)'
+  'atime:value:(on off)'
+  'canmount:value:(on off noauto)'
+  "checksum:value:($sum_algorithms)"
+  "compression:value:($comp_algorithms)"
+  'copies:value:(1 2 3)'
+  "dedup:value:($dedup_algorithms)"
+  'devices:value:(on off)'
+  'encryption:value:(off on aes128-ccm aes-192-ccm aes-256-ccm aes-128-gcm aes-192-gcm aes-256-gcm)'
+  'exec:value:(on off)'
+  'groupquota@'
+  'logbias:value:(latency throughput)'
+  "mountpoint: : _alternative \
+      'properties:property:(none legacy)' \
+      'paths:mountpoint:_directories -W / -P /'"
+  'multilevel:value:(on off)'
+  'nbmand:value:(on off)'
+  'primarycache:value:(all none metadata)'
+  'quota: :->quotas'
+  'readonly:value:(on off)'
+  'recordsize:value:(512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M)'
+  'refquota: :->quotas'
+  "refreservation: : _alternative \
+      'sizes: :_numbers -M \"m:{a-zA-Z}={A-Za-z}\" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
+      'properties:property:(auto none)'"
+  'reservation: :->quotas'
+  'rstchown:value:(on off)'
+  'secondarycache:value:(all none metadata)'
+  'setuid:value:(on off)'
+  'shadow:value' # TODO: complete URI|none
+  'share:share properties'
+  'snapdir:value:(hidden visible)'
+  'sync:value:(standard always disabled)'
+  'userquota@'
+  'version:value'
+  'volsize:size:_numbers -M "m:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}'
+)
 
-	share_smb_ro_properties=(
-		"share.smb.all"
-	)
+case $service:$implementation in
+  *:openzfs)
+    ds_types+=( bookmark )
+    sum_algorithms+=( noparity sha512 skein edonr )
+    comp_algorithms+=( zstd zstd-{1..19} zstd-fast zstd-fast-{{1..9}{,0},100,500,1000} )
+    dedup_algorithms+=( {sha512,skein}{,\,verify} edonr,verify )
+    share_rw_properties=( sharesmb:option sharenfs:option )
+    ro_po_props+=(
+      'expandsize[uninitialized space within the pool]'
+      'fragmentation[amount of fragmentation in the pool]'
+      'freeing[amount of space remaining to be reclaimed]'
+      'used[amount of storage space used within the pool]'
+      'load_guid[unique identifier generated when pool is loaded]'
+    )
+    ci_po_props+=(
+      'ashift[pool sector size exponent]:exponent:((9\:512 10\:1024 11\:2048 12\:4096 13\:8192 14\:16384 15\:32768 16\:65536))'
+    )
+    rw_po_props+=(
+      'autotrim[periodically trim recently freed space]:value:(on off)'
+      'comment[text string that is available even if the pool becomes faulted]:value'
+      'multihost[perform pool activity check during import]:value:(on off)'
+    )
+    rw_ds_props+=(
+      'aclmode:value:(discard groupmask passthrough restricted)'
+      'acltype:value:(off noacl nfsv4 posix posixacl)'
+      'mlslabel:value:(none)' # TODO: list sensitivity labels
+      'redundant_metadata:value:(all most)'
+      'vscan:value:(on off)'
+      'xattr:value:(on off dir sa)'
+      "filesystem_limit: :{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ -prefix n ]]; then compadd none; else _message -e limits 'number or none'; fi}"
+      "snapshot_limit: :{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ -prefix n ]]; then compadd none; else _message -e limits 'number or none'; fi}"
+      'volmode:mode:((
+        default\:use\ system-wide\ tunable
+        full\:expose\ as\ block\ devices
+        geom\:expose\ as\ block\ devices
+        dev\:hide\ partitions
+        none\:not\ exposed\ outside\ zfs
+      ))'
+    )
+    ro_ds_props+=(
+      createtxg clones filesystem_count guid logicalreferenced logicalused
+      receive_resume_token refcompressratio snapshot_count volblocksize written
+    )
+    delegatable_perms=(
+      bookmark load-key change-key userobjquota userobjused groupobjquota
+      groupobjused projectused projectquota projectobjused projectobjquota
+    )
+  ;|
+  *:solaris)
+    ds_types+=( share )
+    sum_algorithms+=( sha256+mac )
+    share_nfs_ro_properties=( share.nfs.all )
+    share_nfs_rw_properties=(
+      'share.nfs:value:(on off)'
+      'share.nfs.aclok:value:(on off)'
+      'share.nfs.aclfab:value:(on off)'
+      'share.nfs.anon:uid'
+      'share.nfs.charset.'{cp932,euc-{cn,jpns,kr,tw},iso8859-{1,2,5,6,7,8,9,13,15},koi8-r,shift_jis}':access-list'
+      'share.nfs.index:file:_files'
+      'share.nfs.labeled:value:(on off)'
+      'share.nfs.noaclfab:value:(on off)'
+      'share.nfs.log:nfslog.conf tag'
+      'share.nfs.nosub:value:(on off)'
+      'share.nfs.nosuid:value:(on off)'
+      'share.nfs.public:value:(on off)'
+      'share.nfs.sec:security-mode-list'
+      'share.nfs.sec.'{default,dh,krb5{,i,p},none,sys}.{ro,root,rw}':access-list'
+      'share.nfs.sec.'{default,dh,krb5{,i,p},none,sys}.root_mapping':uid'
+      'share.nfs.sec.'{default,dh,krb5{,i,p},none,sys}.window':credential lifetime (seconds)'
+      'share.nfs.sec.sys.resvport:value:(on off)'
+    )
+    share_smb_ro_properties=( share.smb.all )
+    share_smb_rw_properties=(
+      'share.smb:value:(on off)'
+      'share.smb.abe'
+      'share.smb.ad-container'
+      'share.smb.catia:value:(on off)'
+      'share.smb.csc:value:(disabled manual auto vdo)'
+      'share.smb.dfsroot:value:(on off)'
+      'share.smb.encrypt:value:(on off)'
+      'share.smb.guestok:value:(on off)'
+      'share.smb.oplocks:value:(disabled enabled)'
+      'share.smb.cont_avail:value:(on off)'
+      'share.smb.'{none,ro,rw}':access-list'
+    )
+    share_ro_properties=(
+      share.all share.fs share.name share.point share.protocols share.state
+      $share_nfs_ro_properties $share_smb_ro_properties
+    )
+    share_rw_properties=(
+      'share.desc:description'
+      'share.auto:value:(on off)'
+      'share.autoname:value'
+      'share.nfs.cksum:value'
+      'share.path:path'
+      $share_nfs_rw_properties $share_smb_rw_properties
+    )
+    ro_po_props+=(
+      'lastscrub[start time of the last successful scrub]'
+    )
+    rw_po_props+=(
+      'clustered[pool is imported as a global pool in Oracle Solaris Cluster]:value:(on off)'
+      'scrubinternal[time interval between scheduled scrubs]:interval'
+    )
+    ro_ds_props+=( keychangedate rekeydate effective{read,write}limit )
+    rw_ds_props+=(
+      'aclmode:value:(discard mask passthrough)'
+      "defaultreadlimit: : _alternative \
+          'sizes: :_guard \[0-9\]\#\(\|\[BKMGTPEZ\]\) size\ \(bytes\ per\ second\)' \
+          'properties:property:(none)'"
+      "defaultwritelimit: : _alternative \
+          'sizes: :_guard \[0-9\]\#\(\|\[BKMGTPEZ\]\) size\ \(bytes\ per\ second\)' \
+          'properties:property:(none)'"
+      'defaultuserquota:->quotas'
+      'defaultgroupquota: :->quotas'
+      'keysource:value:->keysources'
+    )
+    ci_ds_props+=(
+      'volblocksize:value:compadd -o nosort 512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M'
+    )
+    difffields=(
+      object parent size links linkschange name oldname user group
+      ctime mtime atime crtime mountpoint dataset_name
+    )
+    delegatable_perms=( key keychange )
+  ;|
+  zfs:openzfs)
+    subcmds+=(
+      bookmark change-key load-key program project projectspace redact
+      unload-key wait
+    )
+  ;|
+  zpool:openzfs)
+    subcmds+=(
+      checkpoint events labelclear initialize reopen resilver sync trim wait
+      version
+    )
+  ;|
+  zfs:solaris)
+    subcmds+=( key help )
+  ;|
+  zpool:solaris)
+    subcmds+=( help label monitor )
+  ;|
 
-	share_smb_rw_properties=(
-		"share.smb:value:(on off)"
-		"share.smb.ad-container"
-		"share.smb.abe"
-		"share.smb.csc:value:(disabled manual auto vdo)"
-		"share.smb.catia:value:(on off)"
-		"share.smb.dfsroot:value:(on off)"
-		"share.smb.guestok:value:(on off)"
-		"share.smb.ro:access-list:"
-		"share.smb.rw:access-list:"
-		"share.smb.none:access-list:"
-	)
+  zfs:*)
+    subcmds+=(
+      create destroy clone promote rename snapshot rollback list set get
+      inherit mount unmount share unshare send receive allow unallow upgrade
+      userspace groupspace hold holds release diff
+    )
+    [[ $OSTYPE = freebsd<7->.* ]] && subcmds+=( jail unjail )
+  ;;
+  zpool:*)
+    subcmds+=(
+      add attach clear create destroy detach export get history import iostat
+      list offline online reguid remove replace scrub set split status upgrade
+    )
+  ;;
+esac
 
-	share_ro_properties=(
-		"share.all"
-		"share.fs"
-		"share.name"
-		"share.point"
-		"share.protocols"
-		"share.state"
-		$share_nfs_ro_properties
-		$share_smb_ro_properties
-	)
+case $OSTYPE in
+  solaris*)
+    rw_ds_props+=( 'zoned:value:(on off)' )
+  ;;
+  freebsd*)
+    [[ $OSTYPE = freebsd<-12>.* ]] && subcmds+=( remap )
+    rw_ds_props+=( 'jailed:value:(on off)' )
+  ;;
+  linux-gnu)
+    rw_ds_props+=( 'relatime:value:(on off)' )
+    ci_ds_props+=(
+      {,fs,def,root}'context:SELinux context:_selinux_contexts'
+    )
+  ;;
+esac
 
-	share_rw_properties=(
-		"share.desc:description:"
-		"share.noauto:value:(on off)"
-		"share.path:path:"
-		$share_nfs_rw_properties
-		$share_smb_rw_properties
-	)
+delegatable_perms+=(
+  allow clone create destroy diff hold key keychange mount promote receive
+  release rename rollback send share snapshot groupquota groupused userprop
+  userused ${ci_ds_props%%:*}
+)
 
-	# TODO: userused@ and groupused@ could have more extensive handling
-	ro_properties=(
-		"name" "type" "creation" "space" "used" "available" "referenced"
-		"compressratio" "mounted" "origin" "usedbychildren"
-		"usedbydataset" "usedbyrefreservation" "usedbysnapshots"
-		"defer_destroy" "userused@" "userrefs" "groupused@"
-		"keychangedate" "keystatus" "rekeydate"
-		$share_ro_properties
-	)
+key_properties=(
+  'keylocation:location [prompt]:_files -P file\:// -W /'
+  'keyformat:format:(raw hex passphrase)'
+  'pbkdf2iters:iterations [350000]'
+)
 
-	# TODO: Be cleverer about what values can be set.  Is there any way to
-	# set the sorting for *size properties to false by default?
-	rw_properties=(
-		"aclinherit:value:(discard noallow restricted passthrough passthrough-x)"
-		"atime:value:(on off)"
-		"canmount:value:(on off noauto)"
-		"checksum:value:(on off fletcher2 fletcher4 sha256 sha256+mac)"
-		"compression:value:(on off lzjb lz4 gzip gzip-{1..9} zle)"
-		"copies:value:(1 2 3)"
-		"dedup:value:(on off verify sha256 sha256,verify)"
-		"devices:value:(on off)"
-		"encryption:value:(off on aes128-ccm aes-192-ccm aes-256-ccm aes-128-gcm aes-192-gcm aes-256-gcm)"
-		"exec:value:(on off)"
-		"groupquota@:value:" # TODO: complete group=size|none
-		"keysource:value:_zfs_keysource_props"
-		"logbias:value:(latency throughput)"
-		"mlslabel:value:(none)" # TODO: list sensitivity labels
-		"mountpoint:path, 'legacy', or 'none':{if [[ -prefix /* ]]; then _path_files -/; else _wanted mountpoints expl 'mountpoint (type \"/\" to start completing paths)' compadd legacy none; fi}"
-		"multilevel:value:(on off)"
-		"nbmand:value:(on off)"
-		"primarycache:value:(all none metadata)"
-		"quota: : _alternative \
-				'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
-				'properties:property:(none)'"
-		"readonly:value:(on off)"
-		"recordsize:value:(512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M)"
-		"refquota: : _alternative \
-				'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
-				'properties:property:(none)'"
-		"refreservation: : _alternative \
-				'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
-				'properties:property:(auto none)'"
-		"reservation: : _alternative \
-				'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
-				'properties:property:(none)'"
-		"rstchown:value:(on off)"
-		"secondarycache:value:(all none metadata)"
-		"setuid:value:(on off)"
-		"shadow:value:" # TODO: complete URI|none
-		"share:share properties:"
-		"snapdir:value:(hidden visible)"
-		"sync:value:(standard always disabled)"
-		"userquota@:value:" # TODO: complete user=size|none
-		"version:value:(1 2 3 4 current)"
-		"volsize:value:" # <size>
-		"vscan:value:(on off)"
-		"xattr:value:(on off)"
-		"zoned:value:(on off)"
-		$share_rw_properties
-	)
+ro_ds_props+=( $share_ro_properties )
+rw_ds_props+=( $share_rw_properties )
+ci_ds_props+=( $rw_ds_props )
 
-		if [[ "$OSTYPE" == "linux-gnu" ]]; then
-			rw_properties+=("acltype:value:(off noacl posixacl)")
-		elif [[ "$implementation" == "solaris" ]]; then
-			rw_properties+=("aclmode:value:(discard mask passthrough)")
-		else
-			rw_properties+=("aclmode:value:(discard groupmask passthrough restricted)")
-		fi
+ds_propnames=( ${rw_ds_props%%:*} )
+po_propnames=( ${ro_po_props%%:*} ${ci_po_props%%:*} ${rw_po_props%%:*} )
 
 
-	create_properties=(
-		$rw_properties
-		"casesensitivity:value:(sensitive insensitive mixed)"
-		"normalization:value:(none formC formD formKC formKD)"
-		"utf8only:value:(on off)"
-		"volblocksize:value:(512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M)"
-	)
+case $service in
+  zfs|zpool)
+    _arguments -C -A "-*" \
+      '-?[display usage information]' \
+      '*::command:->subcmd' && return 0
 
-	delegatable_perms=(
-		"allow" "clone" "create" "destroy" "diff" "hold" "key"
-		"keychange" "mount" "promote" "receive" "release" "rename"
-		"rollback" "send" "share" "snapshot"
-		"groupused" "userused" "userprop"
-		${create_properties%%:*}
-	)
+    if (( CURRENT == 1 )); then
+      _wanted commands expl "subcommand" compadd -a subcmds
+      return
+    fi
+    curcontext="${curcontext%:*}-$words[1]:"
+  ;;
+  zdb)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-mm[also display free space histogram associated with each metaslab]'
+        {-mmm,-MM}'[display more free space information]'
+        {-mmmm,-MMM}'[display every spacemap record]'
+        '-DD[display a histogram of deduplication statistics]'
+        '-DDD[display deduplication statistics independently for each table]'
+        '-DDDD[dump the contents of the deduplication tables describing duplicate blocks]'
+        '-DDDDD[also dump the contents of the deduplication tables describing unique blocks]'
+        '-E+[decode and display block from a given embedded block pointer]:word'
+        '(-l)-ll+[like -l but display L2ARC log blocks]:device:_files'
+        '(-l -ll)-lll+[like -l but display every configuration, unique or not]:device:_files'
+        "-q[don't print labels (with -l)]"
+        '-k[examine the checkpointed state of the pool]'
+        '-M[display the offset, spacemap, and free space of each metaslab]' \
+        '-O+[look up the specified path inside of the dataset]:dataset:_zfs_dataset:path:_files'
+        '-o+[set the given global libzpool variable]:variable'
+        '-r+[copy the specified path inside of the dataset to the specified destination]:dataset:_zfs_dataset:path:_files:destination:_files'
+        '-x+[copy all blocks accessed to files in the specified directory]:directory:_directories'
+        '-V[attempt verbatim import]'
+        '-Y[attempt all possible combinations when reconstructing indirect split blocks]'
+        '-y[perform validation for livelists that are being deleted]'
+      )
+    else
+      args=(
+        '-?[display usage information]'
+        '-M+[dump MOS contents]:contents: _values -s , raw_config all objset dir pool_props metaslab sync_bplist dtl config spares l2cache history errlog_scrub errlog_last bpmap-vdev bpmap_defer_obj dtl-scan ddt2'
+        '-r[dump datasets recursively]'
+        '-z[report zombies only]'
+        '-V[verify DDT xtree block data]'
+        "-a[don't import l2arc cache data]"
+        '-f[attempt to force import (with -e)]'
+        '-w+[specify directory to save shadow copy of all accessed disk locations]: :_directories'
+        '-x+[set kernel tunable]:tunable'
+        '-G[dump the contents of the zfs_dbgmsg buffer before exiting]'
+        '-I[limit the number of outstanding checksum I/Os to the specified value]'
+      )
+    fi
+    _arguments -A "-*" -S $args \
+      '(-C)-b[display block statistics]' \
+      '(-C)*-c[verify checksum of metadata blocks]' \
+      '(-b -c -d)-C[display configuration information]' \
+      '(-C)*-d[display dataset information]' \
+      '-h[display pool history]' \
+      '-i[display intent log (ZIL) information]' \
+      '-l+[read the vdev labels from the specified device]:device:_files' \
+      '-m[display the offset, spacemap, and free space of each metaslab]' \
+      '-s[report statistics on zdb I/O]' \
+      '*-u[also display the uberblocks on the device (with -l)]' \
+      '*-v[enable verbose output]' \
+      '-D[display deduplication statistics]' \
+      '-S[simulate the effects of deduplication, displaying constructed DDT as with -DD]' \
+      '-L[disable leak detection and the loading of space maps]' \
+      '-R+[read and display a block from the specified device]:device' \
+      "-A[don't abort should any assertion fail]" \
+      "-AA[enable panic recovery]" \
+      '-F[try progressively older transactions until pool is readable]' \
+      '-U+[specify cache file to use]:cache file [/etc/zfs/zpool.cache]:_files' \
+      '-X[attempt "extreme" transaction rewind]' \
+      '-e[operate on an exported pool]' \
+      '-p[specify path under which to search for devices (with -e)]:path:_files' \
+      '-P[use exact (parsable) numeric output]' \
+      '-t+[specify the highest transaction to use when searching for uberblocks]:transaction' \
+      '1:pool:_zfs_pool'
+    return
+  ;;
+esac
 
-	rw_propnames=( ${rw_properties%%:*} )
+case $service:$words[1] in
+  zfs:create)
+    [[ $implementation = openzfs ]] && args=(
+      '-P[print machine-parsable verbose information about the created dataset]'
+      '-n[do a dry-run, no dataset will be created]'
+      '-v[print verbose information about the created dataset]'
+    )
+    _arguments -C -A "-*" -S $args \
+      '-p[create parent datasets]' \
+      '*-o+[set initial propertyvalue]:property:->create-properties' \
+      - set1 \
+      ':filesystem:_zfs_dataset -t fs -e "parent dataset"' \
+      - set2 \
+      '-s[create sparse volume]' \
+      '-b+[set volblocksize]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes blocksize \:B {k,M,G,T,P,E,Z}{,B}' \
+      '-V+[set size]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size \:B {k,M,G,T,P,E,Z}{,B}' \
+      ':volume:_zfs_dataset -t fs -e "parent dataset"'
+  ;;
 
-	difffields=(
-		object parent size links linkschange name oldname user group
-		ctime mtime atime crtime
-	)
+  zfs:destroy)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-n[do a dry-run, no data will be deleted]'
+        '-p[print machine-parsable verbose information about the deleted data]'
+        '-v[print verbose information about the deleted data]'
+      )
+    else
+      args=( '-s[destroy snapshots synchronously - only return when blocks freed]' )
+    fi
+    _arguments -A "-*" -S $args \
+      '-r[recursively destroy all children]' \
+      '-R[recursively destroy all dependents]' \
+      '(-f)-d[delete or mark deferred]' \
+      '(-d)-f[force unmounts]' \
+      ':dataset:_zfs_dataset -t fs -t vol ${=${opt_args[(i)-f]:--t snap}:/-f/} ${=${opt_args[(i)-*]:--t bookmark}:/-?/}'
+  ;;
 
-	if [[ $service == "zfs" ]]; then
-		_arguments -C -A "-*" \
-			'-\?[Help]' \
-			'*::command:->subcmd' && return 0
+  zfs:snap(|shot))
+    _arguments -C -A "-*" -S \
+      '-r[recursively snapshot all descendant datasets]' \
+      '*-o+[set property]:property:->create-properties' \
+      ':filesystem/volume:_zfs_dataset -t fs -t vol -S@'
+  ;;
 
-		if (( CURRENT == 1 )); then
-			_wanted commands expl "zfs subcommand" compadd -a subcmds
-			return
-		fi
-		service="$words[1]"
-		curcontext="${curcontext%:*}=$service:"
-	fi
+  zfs:rollback)
+    _arguments -A "-*" -S \
+      '-r[recursively destroy more recent snapshots]' \
+      '-R[recursively destroy more recent snapshots and clones]' \
+      '-f[force unmounts]' \
+      ':snapshot:_zfs_dataset -t snap'
+  ;;
 
-	case $service in
-	("create")
-		_arguments -A "-*" \
-			'-p[Create parent datasets]' \
-			'*-o[Set initial properties]:property:_values -s , "property" $create_properties' \
-			- set1 \
-			':filesystem:_zfs_dataset -t fs -e "parent dataset"' \
-			- set2 \
-			'-s[Create sparse volume]' \
-			'-b+[set volblocksize]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes blocksize :B {k,M,G,T,P,E,Z}{,B}' \
-			'-V+[set size]: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
-			':volume:_zfs_dataset -t fs -e "parent dataset"'
-		;;
+  zfs:clone)
+    [[ $implementation = solaris ]] && args+=(
+    '-K[create encryption key]'
+  )
+  _arguments -C -A "-*" -S $args \
+    '-p[create parent datasets]' \
+    '*-o+[set property]:property:->create-properties' \
+    ':snapshot:_zfs_dataset -t snap' \
+    ':filesystem/volume:_zfs_dataset -t fs -e "parent dataset"'
+  ;;
 
-	("destroy")
-		_arguments -A "-*" \
-			'-r[Recursively destroy all children]' \
-			'-R[Recursively destroy all dependents]' \
-			- set1 \
-			'-d[delete or mark deferred]' \
-			':snapshot:_zfs_dataset -t snap' \
-			- set2 \
-			'-f[Force unmounts]' \
-			':filesystem/volume/snapshot:_zfs_dataset -t fs -t vol'
-		;;
+  zfs:promote)
+    _arguments \
+      ':filesystem:_zfs_dataset -t clone' \
+  ;;
 
-	(snap(|shot))
-		_arguments -A "-*" \
-			'-r[Recursively snapshot all descendant datasets]' \
-			'*-o[Set property]:property:_values -s , "property" $create_properties' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol -S@'
-		;;
+  zfs:rename)
+    [[ $implementation = openzfs ]] && args=(
+      '(-r -u)-f[force unmount any filesystems]'
+      "(-r -f)-u[don't remount file systems during rename]"
+    )
+    _arguments -A "-*" -S $args \
+      '(-r)-p[create parent datasets]' \
+      '(-p -u -f)-r[recursively rename snapshots of all descendent datasets]' \
+      ':dataset:_zfs_dataset -r1' \
+      ':dataset:_zfs_dataset -r2'
+  ;;
 
-	("rollback")
-		_arguments -A "-*" \
-			'-r[Recursively destroy more recent snapshots]' \
-			'-R[Recursively destroy more recent snapshots and clones]' \
-			'-f[Force unmounts]' \
-			':snapshot:_zfs_dataset -t snap'
-		;;
+  zfs:bookmark)
+    _arguments \
+      ':snapshot or bookmark:_zfs_dataset -t snap -t bookmark' \
+      ':bookmark'
+  ;;
 
-	("clone")
-		# XXX needs to bail if there are no snapshots
-		_arguments -A "-*" \
-			'-p[Create parent datasets]' \
-			'-K[Create encryption key]' \
-			'*-o[Set property]:property:_values -s , "property" $create_properties' \
-			':snapshot:_zfs_dataset -t snap' \
-			':filesystem/volume:_zfs_dataset -t fs -e "parent dataset"'
-		;;
+  zfs:program)
+    _arguments -A "-*" -S \
+      '-j[display channel program output in JSON format]' \
+      '-n[execute a read-only channel program]' \
+      '-t+[limit the number of Lua instructions to execute]:instruction limit' \
+      '-m+[specify memory limit]:memory limit (bytes) [10MB]' \
+      ':pool:_zfs_pool' \
+      ':script:_files' \
+      '*: :_default'
+  ;;
 
-	("promote")
-		_arguments \
-			':filesystem:_zfs_dataset -t clone' \
-		;;
+  zfs:list)
+    if [[ $implementation = solaris ]]; then
+      args=( '-I+[specify dataset states to display instead of normal datasets]:dataset state:_sequence compadd - receiving resumable hidden all' )
+    else
+      args=( '-p[use exact (parsable) numeric output]' )
+    fi
+    _arguments -A "-*" -S $args \
+      '(-d)-r[recursively display children]' \
+      '-H[suppress printing of headers]' \
+      '(-r)-d+[depth]:value' \
+      '-o+[specify properties to list]: :_values -s , "property" $ro_ds_props $ds_propnames' \
+      '*-s+[specify sort key (ascending)]: :_values "property" $ro_ds_props $ds_propnames' \
+      '*-S+[specify sort key (descending)]: :_values "property" $ro_ds_props $ds_propnames' \
+      '-t+[specify dataset types to list]: :_values -s , "dataset type" $ds_types' \
+      '*:filesystem/volume/snapshot/path:_zfs_dataset -p'
+  ;;
 
-	("rename")
-		_arguments -A "-*" \
-			'(-r)-p[Create parent datasets]' \
-			'(-p)-r[Recursively rename snapshots of all descendent datasets]' \
-			':dataset:_zfs_dataset -r1' \
-			':dataset:_zfs_dataset -r2'
-		;;
+  zfs:set)
+    [[ $implementation = solaris ]] && args=(
+      '-r[recursively apply value]' \
+    )
+    _arguments -C -A "-*" -S $args \
+      ':property:->set-properties' \
+      '*:filesystem/volume:_zfs_dataset -t fs -t vol'
+  ;;
 
-	("list")
-		_arguments -A "-*" \
-			'-r[Recursively display children]' \
-			'-H[Scripting mode]' \
-			'-d[Depth]:value:' \
-			'-o[Properties to list]:property:_values -s , "property" $ro_properties $rw_propnames' \
-			'*-s[Sort key (ascending)]:property:_values "property" $ro_properties $rw_propnames' \
-			'*-S[Sort key (descending)]:property:_values "property" $ro_properties $rw_propnames' \
-			'-t[Dataset types to list]:dataset type:_values -s , "dataset type" all filesystem snapshot volume' \
-			'*:filesystem/volume/snapshot/path:_zfs_dataset -p'
-		;;
+  zfs:get)
+    if [[ $implementation == openzfs ]]; then
+      args=( '-t+[specify dataset types to display]: :_values -s , "dataset type" $ds_types' )
+    else
+      args=( '-e[expand property sublists to any depth]' )
+    fi
+    _arguments -A "-*" -S $args \
+      "(-d)-r[recursively display children's properties]" \
+      '(-r)-d+[depth]:value' \
+      '-H[suppress printing of headers]' \
+      '-p[use exact (parsable) numeric output]' \
+      '-s+[specify sources]: :_values -s , "source" local default inherited received temporary none' \
+      '-o+[specify fields]: :_values -s , "field" name property received value source' \
+      ':property:_values -s , "property" $ro_ds_props $ds_propnames all' \
+      '*:filesystem/volume/snapshot:_zfs_dataset'
+  ;;
 
-	("set")
-		_arguments \
-			'-r[Recursively apply value]' \
-			':property:_values -s , "property" $rw_properties' \
-			'*:filesystem/volume:_zfs_dataset -t fs -t vol'
-		;;
+  zfs:inherit)
+    _arguments -C -A "-*" -S \
+      '-r[recursively inherit property for all children]' \
+      '-S[revert to received property value]' \
+      ':property:_values "property" $ro_ds_props ${rw_ds_props%%:*}' \
+      '*:filesystem/volume:_zfs_dataset -t fs -t vol'
+  ;;
 
-	("get")
-		_arguments -A "-*" \
-			"-r[Recursively display children's properties]" \
-			'-d[Depth]:value:' \
-			'-H[Scripting mode]' \
-			'-p[Display numbers exactly]' \
-			'-s[Specify sources]:source:_values -s , "source" local default inherited temporary none' \
-			'-o[Specify fields]:field:_values -s , "field" name property value source' \
-			':property:_values -s , "property" $ro_properties $rw_propnames all' \
-			'*:filesystem/volume/snapshot:_zfs_dataset'
-		;;
+  zfs:remap)
+    _arguments \
+      ':filesystem or volume:_zfs_dataset -t fs -t vol'
+  ;;
 
-	("inherit")
-		_arguments -A "-*" \
-			'-r[Recursively inherit property for all children]' \
-			'-S[Revert to received property value]' \
-			':property:_values -s , "property" $ro_properties $rw_properties' \
-			'*:filesystem/volume:_zfs_dataset -t fs -t vol'
-		;;
+  zfs:upgrade)
+    _arguments -A "-*" -S \
+      '(- :)-v[display supported ZFS versions]' \
+      '(-v :)-a[upgrade all filesystems on all pools]' \
+      '(-v)-r[upgrade descendent filesystems, too]' \
+      '(-v)-V+[upgrade to specified version]:version' \
+      '(-a -v):filesystem:_zfs_dataset -t fs'
+  ;;
 
-	("userspace"|"groupspace")
-		_arguments -A "-*" \
-			'-n[Print numeric ID]' \
-			'-i[Translate SID to POSIX ID]' \
-			'-H[Tab-delimited output with no headers]' \
-			'-p[Parseable mode]' \
-			'-o[Properties to list]:property:_values -s , "property" type name used quota' \
-			'*-s[Sort key (ascending)]:property:_values "property" type name used quota' \
-			'*-S[Sort key (descending)]:property:_values "property" type name used quota' \
-			'-t[Types to list]:type:_values -s , "type" all posixuser smbuser posixgroup smbgroup' \
-			'*:filesystem/volume/snapshot:_zfs_dataset'
-		;;
+  zfs:(user|group)space)
+    args=(
+      '-n[print numeric ID]'
+      '-i[translate SID to POSIX ID]'
+    )
+  ;& # fall-through
+  zfs:projectspace)
+    [[ $implementation = solaris ]] && args+=(
+      '(- *)'{-h,--help}'[display usage information]'
+    )
+    _arguments -A "-*" -S $args \
+      '-H[suppress printing of headers, tab-delimit columns]' \
+      '-p[use exact (parsable) numeric output]' \
+      '-o+[specify properties to list]:property:_values -s , "property" type name used quota' \
+      '*-s+[specify sort key (ascending)]: :_values "property" type name used quota' \
+      '*-S+[specify sort key (descending)]: :_values "property" type name used quota' \
+      '-t+[specify types to list]:type:_values -s , "type" all posixuser smbuser posixgroup smbgroup' \
+      '*:filesystem/volume/snapshot:_zfs_dataset'
+  ;;
 
-	("mount")
-		_arguments -A "-*" \
-			'-o[Mount options]:mount options:_values -s , "option" {,no}{devices,exec,setuid} ro rw' \
-			'-O[Overlay mount]' \
-			'-v[Report mount progress]' \
-			- set1 \
-			':filesystem:_zfs_dataset -t fs' \
-			- set2 \
-			'-a[Mount all available ZFS filesystems]'
-		;;
+  zfs:project)
+    _arguments -A "-*" -S \
+      '(-r -C -k -p -s)-d[act on the directory project ID and inherit flag, not its children]' \
+      '(-d)-r[act on subdirectories recursively]' \
+      '(-0 -c -d -s)-C[clear project inherit flag and/or ID on the file(s) or directories]' \
+      '(-0 -c -d -p -s)-k[keep the project ID unchanged]' \
+      '(-k -C -s)-c[check project ID and inherit flag on the file(s) or directories]' \
+      '(-k -C -s)-0[print file name with a trailing NUL instead of newline]' \
+      '(-k)-p+[specify project ID]:project ID' \
+      '(-0 -c -k -C)-s[set project inherit flag on the given file(s) or directories]' \
+      '*:file:_files'
+  ;;
 
-	("unmount")
-		_arguments -A "-*" \
-			- set1 \
-			'-f[Force unmount]' \
-			':filesystem:_zfs_dataset -t fs -t mtpt' \
-			- set2 \
-			'-a[Unmount all ZFS filesystems]'
-		;;
+  zfs:mount)
+    [[ $OSTYPE != freebsd* ]] && args=( '-O[overlay mount]' )
+    [[ $implementation = openzfs ]] && args+=(
+    '-l[load keys for encrypted filesystems as they are being mounted]'
+    )
+    _arguments -A "-*" -S $args \
+      '-o+[specify temporary file system options]: :_values -s , "option" {,no}{atime,dev,exec,relatime,suid,xattr} ro rw' \
+      '-v[report mount progress]' \
+      '-f[force mount]' \
+      '(:)-a[mount all available ZFS filesystems]' \
+      '(-a):filesystem:_zfs_dataset -t fs'
+  ;;
 
-	("share")
-		_arguments -A "-*" \
-			- set1 \
-			'-a[Share all available ZFS filesystems]' \
-			- set2 \
-			'-r[Share filesystems recursively]' \
-			':filesystem:_zfs_dataset -t fs' \
-			- set3 \
-			'*-o[Create a share with these properties]:property:_values -w "share properties" $share_rw_properties' \
-			'-u[Create a share without sharing it]' \
-			':filesystem:_zfs_dataset -t fs' \
-			- set4 \
-			':filesystem:_zfs_dataset -t fs -t mtpt -t share'
-		;;
+  zfs:u(|n)mount)
+    [[ $implementation = openzfs ]] && args+=(
+      '-u[unload keys for any unmounted encryption roots]'
+    )
+    _arguments -A "-*" -S $args \
+      '-f[force unmount]' \
+      '(:)-a[unmount all ZFS filesystems]' \
+      '(-a):dataset or mountpoint:_zfs_dataset -t fs -t mtpt'
+  ;;
 
-	("unshare")
-		_arguments -A "-*" \
-			- set1 \
-			'-a[Unshare all shared ZFS filesystems]' \
-			- set2 \
-			'-r[Unshare filesystems recursively]' \
-			':filesystem:_zfs_dataset -t fs' \
-			- set3 \
-			':filesystem:_zfs_dataset -t fs -t mtpt -t share'
-		;;
+  zfs:share)
+    [[ $implementation = solaris ]] && args=(
+      - set2 \
+      '-r[share filesystems recursively]' \
+      ':dataset:_zfs_dataset -t fs' \
+      - set3 \
+      '*-o+[create a share with specified properties]: :_values -w "share properties" $share_rw_properties' \
+      '-u[create a share without sharing it]' \
+      ':dataset:_zfs_dataset -t fs' \
+    )
+    _arguments -A "-*" -S \
+      - set1 \
+      '-a[share all available ZFS filesystems]' \
+      $args \
+      - set4 \
+      ':dataset or mountpoint:_zfs_dataset -t fs -t mtpt -t share'
+  ;;
 
-	("send")
-		_arguments -A "-*" \
-			'-b' \
-			'-i[Generate an incremental stream]:snapshot:_zfs_dataset -t snap' \
-			'-D[Perform dedup processing]' \
-			'-p[Send properties]' \
-			'-v[Verbose]' \
-			- set1 \
-			'-I[Generate an incremental stream with intermediary snapshots]:snapshot:_zfs_dataset -t snap' \
-			'-R[Generate a replication stream package]' \
-			':snapshot:_zfs_dataset -t snap' \
-			- set2 \
-			'-c[Create a self-contained stream]' \
-			'-r[Generate a recursive stream package]' \
-			':snapshot:_zfs_dataset -t snap'
-		;;
+  zfs:unshare)
+    [[ $implementation = solaris ]] && args=(
+      - set2
+      '-r[unshare filesystems recursively]'
+      ':filesystem:_zfs_dataset -t fs'
+    )
+    _arguments -A "-*" -S $args \
+      - set1 \
+      '-a[unshare all shared ZFS filesystems]' \
+      - set3 \
+      ':filesystem:_zfs_dataset -t fs -t mtpt -t share'
+  ;;
 
-	("receive")
-		_arguments -A "-*" \
-			'-v[Verbose]' \
-			'-n[Do not receive the stream]' \
-			'-F[Force a rollback if necessary]' \
-			'-u[Filesystem is not mounted]' \
-			'-o[Include property change in the stream]::' \
-			'-x[Exclude property change from the stream]:property:' \
-			- set1 \
-			':filesystem/volume/snapshot:_zfs_dataset' \
-			- set2 \
-			'(-e)-d[Set path prefix from stream, excluding only pool name]' \
-			'(-d)-e[Set path prefix from stream, using last path element]' \
-			'-:filesystem:_zfs_dataset -t fs'
-		;;
+  zfs:send)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '(-L --large-block)'{-L,--large-block}'[generate a stream which may contain blocks larger than 128KB]'
+        '(-P --parsable)'{-P,--parsable}'[print machine-parsable verbose information about the stream generated]'
+        '(-e --embed)'{-e,--embed}'[more compact stream for blocks stored with the embedded_data feature]'
+        '(-c --compressed)'{-c,--compressed}'[more compact stream for compressed blocks]'
+        '(-h --holds)'{-h,--holds}'[send snapshot holds]'
+        '-V[set the process title to a per-second report of how much data has been send]'
+        '-t[create a send stream that resumes an interrupted receive]:resume token'
+        '(-w --raw)'{-w,--raw}'[keep encrypted data exactly as it exists on disk]'
+        - redact
+        '(-h -V -t -w --raw)--redact[generate a redacted send stream]'
+        - saved
+        '(-S --saved)'{-S,--saved}'[generate stream from partially received dataset]'
+      )
+    else
+      args=(
+        '-w+[send compressed filesystem blocks as compressed in the stream]:compression:(compress none)'
+        '-m+[limit amount of memory used by deduplication processing]: :_numbers -u bytes "memory size" K M G'
+        '-s+[set stream options]:token:(streamsize check nocheck memsize)'
+        '-C[read a receive checkpoint from stdin]'
+        '-c[create a self-contained stream]'
+        '(-R)-r[generate a recursive stream package]'
+      )
+    fi
+    _arguments -A "-*" -S \
+      '-b[send only received property values]' \
+      '(-I)-i[generate an incremental stream]:snapshot:_zfs_dataset -t snap' \
+      '-D[perform dedup processing]' \
+      "-n[don't send the stream]" \
+      '-p[send properties]' \
+      '-v[verbose]' \
+      '(-i)-I[generate an incremental stream with intermediary snapshots]:snapshot:_zfs_dataset -t snap' \
+      '(-r)-R[generate a replication stream package]' \
+      ':snapshot:_zfs_dataset -t snap -t bookmark' \
+      $args
+  ;;
 
-	("allow")
-		_arguments -A "-*" \
-			'(1 -g -e -c -s)-u[delegate to user]:user:_users' \
-			'(1 -u -e -c -s)-g[delegate to group]:group:_groups' \
-			'(1 -g -u -c -s)-e[delegate to everyone]' \
-			'(1 -u -g -e -l -d -s)-c[set permissions for newly-created descendant filesystems]' \
-			'(1 -u -g -e -l -d -c)-s[define or modify permission sets]:permission set' \
-			'(1 -c -s)-l[allow for named dataset]' \
-			'(1 -c -s)-d[allow for descendent datasets]' \
-			'1::filesystem/volume:_zfs_dataset -t fs -t vol' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol' \
-		;;
+  zfs:redact)
+    _arguments \
+      ':snapshot:_zfs_dataset -t snap' \
+      ':bookmark:_zfs_dataset -t bookmark' \
+      ':redaction snapshot:_zfs_dataset -t snap'
+  ;;
 
-	("unallow")
-		_arguments -A "-*" \
-			'-r[Recursive removal]' \
-			- set1 \
-			'-s[Remove permissions from or delete a permission set]:permission set:' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol' \
-			- set2 \
-			'(-g)-u[User]:user:_users' \
-			'(-u)-g[Group]:group:_groups' \
-			'-l[Allow for named dataset]' \
-			'-d[Allow for descendent datasets]' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol' \
-			- set3 \
-			'-e[Everyone]' \
-			'-l[Allow for named dataset]' \
-			'-d[Allow for descendent datasets]' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol' \
-			- set4 \
-			'-c[Create-time permissions]' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol'
-		;;
+  zfs:(receive|recv))
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-h[skip the receive of holds]'
+        '-s[if the receive is interrupted, save the partially received state]'
+        '(- set2)-A[abort an interrupted zfs recv -s, deleting its saved partially received state]'
+      )
+      [[ $OSTYPE != linux* ]] && args+=(
+        '-M[force an unmount of the file system while receiving a snapshot]'
+      )
+    else
+      args=( '(-)-C[write a receive checkpoint to stdout]' )
+    fi
+    _arguments -A "-*" -S $args \
+      '-v[verbose]' \
+      "-n[don't receive the stream]" \
+      '-F[force a rollback if necessary]' \
+      '-u[filesystem is not mounted]' \
+      '-o[include property change in the stream]:property' \
+      '-x[exclude property change from the stream]:property' \
+      - set1 \
+      ':filesystem/volume/snapshot:_zfs_dataset' \
+      - set2 \
+      '(-e)-d[set path prefix from stream, excluding only pool name]' \
+      '(-d)-e[set path prefix from stream, using last path element]' \
+      ':filesystem:_zfs_dataset -t fs'
+  ;;
 
-	("upgrade")
-		_arguments -A "-*" \
-			- set1 \
-			'-v[Verbose]' \
-			- set2 \
-			'-a[Upgrade all filesystems on all pools]' \
-			'-r[Upgrade descendent filesystems, too]' \
-			'-V[Upgrade to specified version]:version:(1 2)' \
-			- set3 \
-			'-r[Upgrade descendent filesystems, too]' \
-			'-V[Upgrade to specified version]:version:(1 2)' \
-			':filesystem:_zfs_dataset -t fs'
-		;;
+  zfs:allow)
+    _arguments -C -A "-*" -S \
+      '(-g -e -c -s)-u[delegate to user]' \
+      '(-u -e -c -s)-g[delegate to group]' \
+      '(1 -g -u -c -s)-e[delegate to everyone]' \
+      '(1 -u -g -e -l -d -s)-c[set permissions for newly-created descendant filesystems]' \
+      '(-u -g -e -l -d -c)-s[define or modify permission sets]:permission set' \
+      '(-c -s)-l[allow for named dataset]' \
+      '(-c -s)-d[allow for descendent datasets]' \
+      '1: :->first' \
+      ':permission list:_values -s , "permission or set" $delegatable_perms' \
+      ':filesystem/volume:_zfs_dataset -t fs -t vol'
 
-	("hold")
-		_arguments -A "-*" \
-			'-r[Apply hold recursively]' \
-			':tag:' \
-			':snapshot:_zfs_dataset -t snap'
-		;;
+    if [[ -n $state ]]; then
+      case $opt_args[(I)-[ugs]] in
+        ^-[ug]) alts+=( 'permission-sets: :_guard "(|@*)" "permission set"' ) ;|
+        ^-[gs]) alts+=( 'users:user:_users' ) ;|
+        ^-[us]) alts+=( 'groups:group:_groups' ) ;|
+        '')
+          alts+=(
+            'all:everyone:(everyone)'
+            'filesystems:filesystem/volume:_zfs_dataset -t fs -t vol'
+          )
+        ;;
+      esac
+      _alternative $alts
+    fi
+  ;;
 
-	("holds")
-		_arguments -A "-*" \
-			'-r[List holds recursively]' \
-			':snapshot:_zfs_dataset -t snap'
-		;;
+  zfs:unallow)
+    _arguments -A "-*" -S \
+      '-r[recursive removal]' \
+      '(-e -g -s -c)-u[user]' \
+      '(-e -u -s -c)-g[group]' \
+      '(1 -g -u -s -c)-e[everyone]' \
+      '(1 -u -g -e -s -l -d)-c[create-time permissions]' \
+      '(-e -u -g -c)-s[remove permissions from or delete a permission set]:permission set' \
+      '(-c -s)-l[allow for named dataset]' \
+      '(-c -s)-d[allow for descendent datasets]' \
+      '1: :->first' \
+      '::permissions or sets:_values -s , "permission or set" $delegatable_perms' \
+      ':filesystem/volume:_zfs_dataset -t fs -t vol'
 
-	("release")
-		_arguments -A "-*" \
-			'-r[Release holds recursively]' \
-			':tag:' \
-			':snapshot:_zfs_dataset -t snap'
-		;;
+    if [[ -n $state ]]; then
+      case $opt_args[(I)-[ugs]] in
+        ^-[ug]) alts+=( 'permission-sets: :_guard "(|@*)" "permission set"' ) ;|
+        ^-[gs]) alts+=( 'users:user:_users' ) ;|
+        ^-[us]) alts+=( 'groups:group:_groups' ) ;|
+        '') alts+=( 'all:everyone:(everyone)' ) ;;
+      esac
+      _alternative $alts
+    fi
+  ;;
 
-	("diff")
-		_arguments -A "-*" \
-			'-F[Add column for filetype character]' \
-			'-H[Parseable output]' \
-			'-e[Only show new and changed files]' \
-			'*-o[Show fields]:field:_values "field" $difffields' \
-			'-t[Add column for ctime]' \
-			- set1 \
-			':snapshot:_zfs_dataset -t snap' \
-			':snapshot or filesystem:_zfs_dataset -t snap -t fs' \
-			- set2 \
-			'-E[Show difference from empty]' \
-			':snapshot or filesystem:_zfs_dataset -t snap -t fs'
-		;;
+  zfs:hold)
+    _arguments -A "-*" -S \
+      '-r[apply hold recursively]' \
+      ':tag' \
+      ':snapshot:_zfs_dataset -t snap'
+  ;;
 
-	("key")
-		_arguments -A "-*" \
-			- set1 \
-			'-a[Apply to all datasets in all pools]' \
-			'(-u -K -f)-l[Load the encryption key]' \
-			'(-l -K)-u[Unload the encryption key]' \
-			'(-l -u -f)-K[Create a new data encryption key]' \
-			'(-l -K)-f[Unmount the dataset before unloading the encryption key]' \
-			'-r[Apply recursively]' \
-			':filesystem or volume:_zfs_dataset -t fs -t vol' \
-			- set2 \
-			'-c[Change the encryption key]' \
-			'-o[Change a property]:property:_zfs_keysource_props' \
-			':filesystem or volume:_zfs_dataset -t fs -t vol'
-		;;
+  zfs:holds)
+    [[ $implementation = openzfs ]] && args=(
+      '-H[suppress printing of headers, tab-delimit columns]'
+    )
+    [[ $OSTYPE = freebsd<-12>.* ]] && args+=(
+      # features were lost with the openzfs rebase
+      '-p[use exact (parsable) numeric output]'
+      '(-r)-d+[depth]:value'
+    )
+    _arguments -A "-*" -S $args \
+      '(-d)-r[list holds recursively]' \
+      ':snapshot:_zfs_dataset -t snap'
+  ;;
 
-	("jail"|"unjail")
-		_arguments \
-			'1: : _jails' \
-			'2:filesystem:_zfs_dataset -t fs'
-		;;
+  zfs:release)
+    _arguments -A "-*" -S \
+      '-r[release holds recursively]' \
+      ':tag' \
+      ':snapshot:_zfs_dataset -t snap'
+  ;;
 
-	("help")
-		_arguments -A "-*" \
-			- set1 \
-			':command:($subcmds $delegatable_perms $ro_properties ${rw_properties%%:*} properties)' \
-			- set2 \
-			'-l[Display property information]' \
-			': :(properties)'
-		;;
+  zfs:diff)
+    [[ $implementation = solaris ]] && args=(
+      '(-E)-e[only show new and changed files, no deleted]'
+      '*-o+[show specified fields]:field:_values "field" $difffields'
+      '-q[silence warnings for missing snapshots on recursive datasets]'
+      '-N[enumerate new child datasets (with -r)]'
+      '(1 -e)-E[show difference from empty]'
+    )
+    _arguments -A "-*" -S $args \
+      '-F[add column for filetype character, similar to ls(1)]' \
+      '-H[suppress printing of headers and arrows, tab-delimit columns]' \
+      '-t[add column for ctime]' \
+      '(-E)1:snapshot:_zfs_dataset -t snap' \
+      '2:snapshot or filesystem:_zfs_dataset -t snap -t fs'
+  ;;
 
-	(*)
-		_message "unknown zfs subcommand: $service"
-		;;
-	esac
-}
+  zfs:wait)
+    _arguments -A "-*" -S \
+      '-t[specify background activity]:activity:(deleteq)' \
+      ':filesystem:_zfs_dataset'
+  ;;
 
-_zfs "$@"
+  zfs:key)
+    _arguments -C -A "-*" -S \
+      '-t+[only apply to given dataset type]: :_values -s , "dataset type" $ds_types' \
+      '(-u -c -K -f -o)-l[load the encryption key]' \
+      "(-u -c -K -f -o)-M[don't mount file systems after loading their keys]" \
+      "(-u -c -K -f -o)-S[don't share file systems after loading their keys]" \
+      '(-l -c -K -o -M -S)-u[unload the encryption key]' \
+      '(-l -c -K -o -M -S)-f[force unmount the dataset before unloading the encryption key]' \
+      '(-l -u -K -f -M -S)-c[change the encryption key]' \
+      '(-l -u -K -f -M -S)-o+[change a property]:property:->keysources' \
+      '(-l -c -u -f -o -M -S)-K[create a new data encryption key]' \
+      '(1 -r)-a[apply to all datasets in all pools]' \
+      '(-a)-r[apply recursively]' \
+      ':filesystem or volume:_zfs_dataset -t fs -t vol'
+  ;;
+
+  zfs:load-key)
+    _arguments -A "-*" -S \
+      "-L+[specify location of user's encryption key]:key location [prompt]:_files -P file\:// -W /" \
+      '(:)-a[load keys for all encryption roots in all imported pools]' \
+      '-n[do a dry-run, simply check that the provided key is correct]' \
+      '-r[load keys for datasets recursively]' \
+      '(-a):filesystem or volume:_zfs_dataset -t fs -t vol'
+  ;;
+
+  zfs:unload-key)
+    _arguments -A "-*" -S \
+      '(:)-a[unload keys for all encryption roots in all imported pools]' \
+      '-r[unload keys for datasets recursively]' \
+      '(-a):filesystem or volume:_zfs_dataset -t fs -t vol'
+  ;;
+
+  zfs:change-key)
+    _arguments -A "-*" -S \
+      '(-o)-i[make filesystem inherit key from its parent]' \
+      '-l[ensure key is loaded before attempting to change it]' \
+      '(-i)*-o+[change encryption key property]: :_values -s , "property" $key_properties' \
+      ':filesystem or volume:_zfs_dataset -t fs -t vol'
+  ;;
+
+  zfs:jail|zfs:unjail)
+    _arguments \
+      '1: : _jails' \
+      '2:filesystem:_zfs_dataset -t fs'
+  ;;
+
+  zfs:help)
+    _arguments -A "-*" -S \
+      - set1 \
+      ':command:($subcmds $delegatable_perms $ro_ds_props ${rw_ds_props%%:*} properties)' \
+      - set2 \
+      '(2)-l[display property information]' \
+      ':help topic:(property)' \
+      ':property:($delegatable_perms $ro_ds_props ${rw_ds_props%%:*})'
+  ;;
+
+  zpool:help)
+    _arguments -A "-*" -S \
+      - commands \
+      ':command:($subcmds)' \
+      - properties \
+      '(2)-l[display property information]' \
+      ':help topic:(property)' \
+      ':property:(${po_propnames%%\[*})'
+  ;;
+
+  zpool:add)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-g[display vdev, GUIDs instead of the normal device names]'
+        '-L[display real paths for vdevs resolving all symbolic links]'
+        '-o+[set given pool properties]: :_values -s , "property" "${(@M)ci_po_props\:#ashift*}"' \
+        '-P[display real paths for vdevs instead of only the last component of the path]'
+      )
+    elif [[ $implementation = solaris ]]; then
+      args=( '-l[display configuration in /dev/chassis location form]' )
+    fi
+    _arguments -A "-*" -S $args \
+      '-f[force use of in-use devices]' \
+      '-n[display configuration without modifying pool]' \
+      ':pool:_zfs_pool' \
+      '*:virtual device:->virtual-devices'
+  ;;
+
+  zpool:attach)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-w[wait until new device has finished resilvering before returning]'
+        '-s[reconstruct sequentially to restore redundancy as quickly as possible]'
+        '-o+[set given pool properties]: :_values -s , "property" "${(@M)ci_po_props\:#ashift*}"'
+      )
+    fi
+    _arguments -A "-*" -S $args \
+      '-f[force attach, even if in use]' \
+      ':pool:_zfs_pool' \
+      ':virtual device:->pool-devices' \
+      ':virtual device:->disk-devices'
+  ;;
+
+  zpool:checkpoint)
+    _arguments -A "-*" -S \
+      '(-d --discard)'{-d,--discard}'[discard an existing checkpoint from the pool]' \
+      '(-w --wait)'{-w,--wait}'[wait until the checkpoint has finished being discarded before returning]' \
+      ':pool:_zfs_pool'
+  ;;
+
+  zpool:clear)
+    [[ $implementation = solaris ]] && args=(
+      '-f[ignore fmadm acquit and fmadm repair failures]'
+    )
+    _arguments -C -A "-*" -S $args \
+      '-F[discard transactions to allow pool opening]' \
+      '-n[with -F, check if discarding transactions would work]' \
+      '-X[(undocumented) extreme rewind of transactions]' \
+      ':pool:_zfs_pool' \
+      '*:virtual device:->pool-devices'
+  ;;
+
+  zpool:create)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        "-d[don't enable any features on the new pool]"
+      )
+    else
+      args=(
+        '-B[create EFI boot partition on whole disks]'
+        '-l[display configuration in /dev/chassis location form]'
+        "-N[create pool but don't mount or share]"
+      )
+    fi
+    _arguments -C -A "-*" -S $args \
+      '-o+[set pool property at creation time]:property:->newpool-properties' \
+      '-O+[set dataset property at creation time]:property:->create-properties' \
+      '-f[force use of in-use devices]' \
+      '-n[display configuration without creating pool]' \
+      '-R+[use alternate root]:alternate root:_directories' \
+      '-m+[set mountpoint for root dataset]:mountpoint' \
+      '-t+[use a temporary pool name]:pool name' \
+      ':pool :_guard "^-*" "pool name"' \
+      '*: :->virtual-devices'
+  ;;
+
+  zpool:destroy)
+    _arguments -A "-*" -S \
+      '-f[force active datasets to be unmounted]' \
+      ':pool:_zfs_pool'
+  ;;
+
+  zpool:detach)
+    _arguments -C \
+      ':pool:_zfs_pool' \
+      ':virtual device:->pool-devices'
+  ;;
+
+  zpool:events)
+    _arguments -A "-*" -S \
+      '(- 1)-c[clear all previous events]' \
+      '-f[follow mode - continue running, showing new events]' \
+      '-H[suppress headers and tab-delimit fields]' \
+      '-v[print the entire payload for each event]' \
+      '(-c)1:pool:_zfs_pool'
+  ;;
+
+  zpool:export)
+    [[ $implementation = openzfs ]] && args=( '(*)-a[export all pools]' )
+    _arguments -A "-*" -S $args \
+      '-f[forcefully unmount all datasets]' \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:get)
+    [[ $implementation = solaris ]] && args=(
+      '-s+[specify sources to display]: :_values -s "source" local default none'
+    )
+    _arguments -A "-*" -S $args \
+      '-H[suppress headers and tab-delimit fields]' \
+      '-p[display numbers in parseable (exact) values]' \
+      '-o+[specify fields to display]: : _values -s , field name property value source' \
+      ':property:_values -s , "property" $po_propnames' \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:history)
+    _arguments -A "-*" -S \
+      '-i[display internal events]' \
+      '-l[long format]' \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:import)
+    # TODO: -o should complete mount options, too
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-t[new pool name is temporary]'
+        '-l[request encryption keys for all encrypted datasets]'
+        '--rewind-to-checkpoint[rewind pool to the checkpointed state]'
+        '-s[scan using the default search path]'
+        '(-F -X)-T[specify the txg to use for rollback]'
+      )
+    else
+      args=(
+        '(-a)-t+[use a temporary pool name]:pool name'
+        '-l[display configuration in /dev/chassis location form]'
+      )
+    fi
+    _arguments -C -A "-*" -S $args \
+      '(1 2 -t)-a[search for and import all pools found]' \
+      '-D[destroyed pools only]' \
+      '(-d)*-c+[use cache file]:cache file:_files' \
+      '(-c -D)*-d+[search for devices or files in directory]:directory:_files -/' \
+      '-F[recovery mode: discard transactions if required]' \
+      '-X[(undocumented) extreme rewind of transactions]' \
+      '!-V' \
+      '-f[force import]' \
+      '-m[ignore missing log devices]' \
+      '-N[import pool without mounting any filesystems]' \
+      "-n[with -F; don't perform input]" \
+      '-R+[specify alternate root]:alternate root:_files -/' \
+      '-o+[set pool or dataset property]:property:->import-properties' \
+      '1:pool name or id:_zfs_pool' \
+      '2::new pool name'
+  ;;
+
+  zpool:initialize)
+    _arguments -A "-*" -S \
+      '(-s --suspend -c --cancel)'{-c,--cancel}'[cancel initializing on specified devices]' \
+      '(-s --suspend -c --cancel)'{-s,--suspend}'[suspend initializing on specified devices]' \
+      '(-w --wait)'{-w,--wait}'[wait until devices have finished initializing before returning]' \
+      ':pool:_zfs_pool' \
+      '*:device:pool-devices'
+  ;;
+
+  zpool:iostat)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-c[run scripts on each vdev]:script:_files -W "($ZPOOL_SCRIPTS_PATH /etc/zfs/zpool.d ~/.zpool.d)"'
+        '-g[display vdev GUIDs instead of normal device names]'
+        '-H[suppress headers and tab-delimit fields]'
+        '-L[display real paths for vdevs resolving all symbolic links]'
+        '-n[print headers only once]'
+        '-p[display numbers in parsable (exact) values and times in nanoseconds]'
+        '-P[display full paths for vdevs instead of only the last component of the path]'
+        "-r[print request size histograms for the leaf vdev's IO]"
+        '-y[omit statistics since boot]'
+        '-w[display latency histograms]'
+        '-l[include average latency statistics]'
+        '-q[include active queue statistics]'
+      )
+    else
+      args=( '-l[display configuration in /dev/chassis location form]' )
+    fi
+    _arguments -A "-*" -S $args \
+      '-T+[display a timestamp]:format:((d\:standard u\:internal))' \
+      '-v[verbose statistics]' \
+      '*::pool:_zfs_pool' \
+      '::interval' \
+      '::count'
+  ;;
+
+  zpool:label)
+    _arguments -C -A "-*" -S \
+      '(-c)*-d+[specify path in which to search for devices or files]:path:_directories' \
+      '(-d)-c+[read configuration from specified cache file]:cache file:_files' \
+      '(-R)-C[clear ZFS metadata on an inactive pool or device]' \
+      '(-C)-R[recover ZFS metadata for a pool]' \
+      '1::pool:_zfs_pool' \
+      '2:device:->pool-devices'
+  ;;
+
+  zpool:labelclear)
+    _arguments -A "-*" -S \
+      '-f[treat exported or foreign devices as inactive]' \
+      '*:virtual device:_files'
+  ;;
+
+  zpool:list)
+    [[ $implementation = openzfs ]] && args=(
+      '-g[display vdev GUIDs instead of normal device names]'
+      '-L[display real paths for vdevs resolving all symbolic links]'
+      '-p[display numbers in parsable (exact) values]'
+      '-P[display full paths for vdevs instead of only the last component of the path]'
+      '-v[report usage statistics for individual vdevs within the pool]'
+    )
+    _arguments -A "-*" -S $args \
+      '-H[suppress headers and tab-delimit fields]' \
+      '-T+[display a timestamp]:format:((d\:standard u\:internal))' \
+      '-o+[specify fields to list]: :_values -s , "field" $po_propnames' \
+      '::pool:_zfs_pool'
+  ;;
+
+  zpool:monitor)
+    _arguments -A "-*" -S \
+      '-t+[specify provider]:provider:(send receive scrub resilver ddtmigrate destroy)' \
+      '-o+[specify fields]: :_values -s , field done other pctdone pool provider speed starttime tag timeleft timestmp total' \
+      '-T+[display a timestamp]:format:((d\:standard u\:internal))' \
+      '-p[use machine-parseable output format]' \
+      '1:pool:_zfs_pool' \
+      '2:interval' \
+      '3:count'
+  ;;
+
+  zpool:offline)
+    [[ $implementation = openzfs ]] && args=(
+      '-f[force disk into faulted state]'
+    )
+    _arguments -C -A "-*" -S $args \
+      '-t[offline until next reboot]' \
+      ':pool:_zfs_pool' \
+      '*:virtual device:->pool-devices'
+  ;;
+
+  zpool:online)
+    _arguments -C -A "-*" -S \
+      '-e[expand device to use all available space]' \
+      ':pool:_zfs_pool' \
+      '*:virtual device:->pool-devices'
+  ;;
+
+  zpool:reopen)
+    _arguments -A "-*" -S \
+      "-n[don't restart an in-progress scrub operation]" \
+      '1:pool:_zfs_pool'
+  ;;
+
+  zpool:reguid)
+    _zfs_pool
+  ;;
+
+  zpool:remove)
+    [[ $implementation = openzfs ]] && args=(
+      '(-s)-w[wait until removal has completed before returning]'
+    )
+    _arguments -C -A "-*" -S $args \
+      "(-s)-n[don't perform the removal, display mapping table memory use]" \
+      '(-s)-p[with -n, display numbers in parseable (exact) values]' \
+      '(- *)-s[stop and cancel an in-progress removal]' \
+      '1:pool:_zfs_pool' \
+      '*:device:->pool-devices'
+  ;;
+
+  zpool:replace)
+    [[ $implementation = openzfs ]] && args=(
+      '-w[wait until replacement has completed before returning]'
+      '-s[reconstruct sequentially to restore redundancy as quickly as possible]'
+      '-o+[set given pool properties]: :_values -s , "property" "${(@M)ci_po_props\:#ashift*}"'
+    )
+    _arguments -A "-*" -S $args \
+      '-f[force attach, even if in use]' \
+      ':pool:_zfs_pool' \
+      ':virtual device:_files' \
+      '::virtual device:_files'
+  ;;
+
+  zpool:(resilver|sync))
+    _arguments \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:scrub)
+    [[ $implementation = openzfs ]] && args=(
+      '(-s)-p[pause scrubbing]'
+      '-w[wait until scrub has completed before returning]'
+    )
+    _arguments -A "-*" -S $args \
+      '(-p)-s[stop scrubbing]' \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:set)
+    _arguments -C -A "-*" -S \
+      ':property:->set-pool-properties' \
+      '*:pool:_zfs_pool'
+  ;;
+
+  zpool:split)
+    if [[ $implementation = solaris ]]; then
+      args=( '-l[display configuration in /dev/chassis location form]' )
+    else
+      args=(
+        '-g[display vdev GUIDs instead of normal device names]'
+        '-L[display real paths for vdevs resolving all symbolic links]'
+        '-l[request encryption keys for encrypted datasets]'
+        '-P[display full paths for vdevs instead of only the last component of the path]'
+      )
+    fi
+    _arguments -C -A "-*" -S $args \
+      '-R+[specify alternate root]:alternate root:_files -/' \
+      '-n[display configuration without splitting]' \
+      '-o+[set pool or dataset property]:property:->import-properties' \
+      ':pool name or id:_zfs_pool' \
+      ':new pool name' \
+      '*:virtual device:->pool-devices'
+  ;;
+
+  zpool:status)
+    if [[ $implementation = openzfs ]]; then
+      args=(
+        '-D[display a histogram of deduplication statistics]'
+        '-c[run scripts on each vdev]:script:_files -W "($ZPOOL_SCRIPTS_PATH /etc/zfs/zpool.d ~/.zpool.d)"'
+        '-i[display vdev initialization status]'
+        '-g[display vdev GUIDs instead of the normal device names]'
+        '-L[display real paths for vdevs resolving all symbolic links]'
+        '-p[display numbers in parsable (exact) values and times in nanoseconds]'
+        '-P[display full paths for vdevs instead of only the last component of the path]'
+        '-s[display the number of leaf VDEV slow IOs]'
+        '-t[display vdev TRIM status]'
+      )
+    else
+      args=( '-l[display configuration in /dev/chassis location form]' )
+    fi
+    _arguments -A "-*" -S $args\
+      '-v[verbose information]' \
+      '-x[show only unhealthy pools]' \
+      '-T+[display a timestamp]:format:((d\:standard u\:internal))' \
+      '*::pool:_zfs_pool' \
+      ':: :_guard "[0-9]#" interval' \
+      ':: :_guard "[0-9]#" count'
+  ;;
+
+  zpool:trim)
+    _arguments -C -A "-*" -S \
+      '(-d --secure)'{-d,--secure}'[initiate a secure TRIM]' \
+      '(-r --rate)'{-r,--rate}'[set rate at which the TRIM operation progresses]:rate (bytes per second)' \
+      '(-c --cancel)'{-c,--cancel}'[cancel trimming]' \
+      '(-s --suspend)'{-s,--suspend}'[suspend trimming]' \
+      '(-w --wait)'{-w,--wait}'[wait until devices are done being trimmed]' \
+      '1:pool:_zfs_pool' \
+      '*:device:->pool-devices'
+  ;;
+
+  zpool:upgrade)
+    _arguments -A "-*" -S \
+      '(- *)-v[display ZFS versions and descriptions]'
+      "(-v)-V+[upgrade to given version]:version" \
+      '(-v *)-a[upgrade all pools]' \
+      '(-a -v)*:pool:_zfs_pool'
+  ;;
+
+  zpool:wait)
+    _arguments -A "-*" -S \
+      '-H[suppress printing of headers, tab-delimit columns]' \
+      '-P[use exact (parsable) numeric output]' \
+      '-t+[specify background activity]: : _values -s , activity discard free initialize replace remove resilver scrub trim' \
+      '-T+[display a timestamp]:format:((d\:standard u\:internal))' \
+      ':pool:_zfs_pool' \
+      ':interval'
+  ;;
+
+  *)
+    _default
+  ;;
+esac
+
+while (( $#state )); do
+  curstate=$state
+  state=()
+  case $curstate in
+    virtual-devices)
+      local -a vdevtypes
+      vdevtypes=( mirror raidz{,1,2,3} spare log cache )
+      if [[ $implementation = openzfs ]]; then
+        vdevtypes+=( draid{,1,2,3} dedup special )
+      else
+        vdevtypes+=( meta )
+      fi
+      # cache can't be a mirror
+      [[ $words[CURRENT-1] != cache ]] && alts=(
+        'vdev-types:vdev type:compadd -a vdevtypes'
+      )
+      [[ -prefix / ]] || alts+=(
+        'disk-vdevs:disk vdev:_files -g "*(-%)" -W /dev'
+      )
+      _alternative $alts 'file-vdevs:file vdev:_files -W / -P /'
+    ;;
+
+    pool-devices)
+      local -a devices
+      devices=( ${${${(M)${(f)"$(_call_program devices zpool status $line[1])"}:#$'\t' *}##[[:blank:]]#}%%[[:blank:]]*} )
+      if (( $#devices )); then
+        _description devices expl "$state_descr"
+        compadd "$expl[@]" -a devices
+        break
+      fi
+    ;& # fall-through if we found none
+
+    disk-devices)
+      [[ -prefix / ]] || alts=(
+        'disk-vdevs:disk vdev:_files -g "*(-%)" -W /dev'
+      )
+      _alternative $alts 'file-vdevs:file vdev:_files -W / -P /'
+    ;;
+
+    keysources)
+      local -a suf
+
+      compset -S ",*" || suf=(-S ,)
+      if compset -P 1 "*,"; then
+        _alternative \
+          'zfs-keylocator-prompt:"prompt" locator:(prompt)' \
+          'zfs-keylocator-file:file locator:_files' \
+          'zfs-keylocator-pkcs11: : _message -e zfs-keylocator-pkcs11 "PKCS#11 locator"' \
+          'zfs-keylocator-https: : _message -e zfs-keylocator-https "HTTPS URL locator"'
+      else
+        _description keysource-formats expl "keysource format"
+        compadd $suf -q "$expl[@]" "$@" raw hex passphrase
+      fi
+    ;;
+
+    quotas)
+      _alternative \
+        'sizes: :_numbers -M "m:{a-zA-Z}={A-Za-z}" -u bytes size :B {k,M,G,T,P,E,Z}{,B}' \
+        'properties:property:(none)'
+    ;;
+
+    import-properties) args=( $ci_ds_props $rw_ds_props $ci_po_props ) ;|
+    create-properties) args=( $ci_ds_props ) ;|
+    set-properties) args=( $rw_ds_props ) ;|
+    newpool-properties) args=( $rw_po_props $ci_po_props ) ;|
+    set-pool-properties) args=( $rw_po_props ) ;|
+
+    *-properties)
+      if compset -P 1 '(#m)*@'; then
+        if compset -P 1 '*='; then
+          case $MATCH in
+            *quota@) _alternative \
+              'sizes: :_numbers -M "m\:{a-zA-Z}={A-Za-z}" -u bytes size \:B {k,M,G,T,P,E,Z}{,B}' \
+              'properties:property:(none)'
+            ;;
+          esac
+        else
+          case $MATCH in
+            user*@) _users -S = ;;
+            group*@) _groups -S = ;;
+            project*@) _message -e projects project ;;
+          esac
+        fi
+      else
+        _wanted values expl "$state_descr" compadd -S@ ${${(M)args:#*@}%@}
+        _values -C "$state_descr" ${args:#*@}
+      fi
+    ;;
+  esac
+done
+
+[[ nm -ne "$compstate[nmatches]" ]]
diff --git a/Completion/Unix/Command/_zpool b/Completion/Unix/Command/_zpool
deleted file mode 100644
index d9c2caa52..000000000
--- a/Completion/Unix/Command/_zpool
+++ /dev/null
@@ -1,311 +0,0 @@
-#compdef zpool
-# Synced with the S11U1 man page
-
-_zpool() {
-	local context state line expl implementation
-	local -a subcmds fields ro_props rw_props versions create_properties_dataset
-
-	_pick_variant -r implementation -c 'zpool upgrade -v' openzfs='This system supports ZFS pool feature flags' solaris
-
-	subcmds=(
-		create destroy add remove list iostat status online
-		offline clear attach detach replace scrub import export
-		upgrade history get set split help
-	)
-
-	if [[ $implementation = openzfs ]] && [[ $OSTYPE != solaris* ]]; then
-		subcmds+=( labelclear initialize )
-	fi
-
-	versions=(
-		${${${(M)"${(f)$(_call_program versions zpool upgrade -v)}":#[[:space:]]#<->*}##[[:space:]]}%%[[:space:]]*}
-	)
-
-	ro_props=(
-		"all[All properties]"
-		"allocated[Space allocated]"
-		"capacity[Space used (percentage)]"
-		"dedupratio[Deduplication ratio]"
-		"free[Space unallocated]"
-		"guid[Unique identifier]"
-		"health[Health status]"
-		"size[Total size]"
-	)
-
-	rw_props=(
-		"altroot[Alternate root directory]:value:"
-		"autoexpand[Automatic pool expansion]:value:(on off)"
-		"autoreplace[Automatic device replacement]:value:(on off)"
-		"bootfs[Default bootable dataset]:value:"
-		"cachefile[Pool configuration cache file location]:value:"
-		"dedupditto[Threshold for number of copies]:value:"
-		"delegation[Delegated administration]:value:(on off)"
-		"failmode[Failure-mode behavior]:value:(wait continue panic)"
-		"listshares[Show shares in 'zfs list']:value:(on off)"
-		"listsnaps[Show snapshots in 'zfs list']:value:(on off)"
-		"readonly[Controls whether the pool can be modified]:value:(on off)"
-		"version[Pool version]:version:($versions)"
-	)
-
-	fields=( ${ro_props%%:*} ${rw_props%%:*} )
-
-	create_properties_dataset=(
-		"aclinherit:value:(discard noallow restricted passthrough passthrough-x)"
-		"aclmode:value:(discard mask passthrough)"
-		"atime:value:(on off)"
-		"canmount:value:(on off noauto)"
-		"checksum:value:(on off fletcher2 fletcher4 sha256 sha256+mac)"
-		"compression:value:(on off lzjb gzip gzip-{1..9} zle)"
-		"copies:value:(1 2 3)"
-		"dedup:value:(on off verify sha256 sha256,verify)"
-		"devices:value:(on off)"
-		"encryption:value:(off on aes128-ccm aes-192-ccm aes-256-ccm aes-128-gcm aes-192-gcm aes-256-gcm)"
-		"exec:value:(on off)"
-		"groupquota@:value:" # TODO: complete group=size|none
-		"keysource:value:_zfs_keysource_props"
-		"logbias:value:(latency throughput)"
-		"mlslabel:value:(none)" # TODO: list sensitivity labels
-		"mountpoint:path, 'legacy', or 'none':{if [[ -prefix /* ]]; then _path_files -/; else _wanted mountpoints expl 'mountpoint (type \"/\" to start completing paths)' compadd legacy none; fi}"
-		"nbmand:value:(on off)"
-		"primarycache:value:(all none metadata)"
-		"quota:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == quota= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'quota' compadd none; fi}"
-		"readonly:value:(on off)"
-		"recordsize:value:(512 1K 2K 4K 8K 16K 32K 64K 128K 256K 512K 1M)"
-		"refquota:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == refquota= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'refquota' compadd none; fi}"
-		"refreservation:number or 'none':{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == refreservation= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'refreservation' compadd none; fi}"
-		"reservation:value:{if [[ -prefix [0-9]## ]]; then _message -e 'number'; elif [[ $PREFIX == reservation= ]]; then _wanted none expl 'number or none' compadd none; else _wanted none expl 'reservation' compadd none; fi}"
-		"rstchown:value:(on off)"
-		"secondarycache:value:(all none metadata)"
-		"setuid:value:(on off)"
-		"shadow:value:" # TODO: complete URI|none
-		"share:share properties:"
-		"sharenfs:value:(on off)"
-		"sharesmb:value:(on off)"
-		"snapdir:value:(hidden visible)"
-		"sync:value:(standard always disabled)"
-		"userquota@:value:" # TODO: complete user=size|none
-		"version:value:(1 2 3 4 current)"
-		"volsize:value:" # <size>
-		"vscan:value:(on off)"
-		"xattr:value:(on off)"
-		"zoned:value:(on off)"
-	)
-
-	if [[ $service == "zpool" ]]; then
-		_arguments -C \
-			'-\?[show help information]' \
-			'1:subcommand:compadd -a subcmds' \
-			'*:: :->subcmd' && return
-
-		service="$words[1]"
-		curcontext="${curcontext%:*}-$service:"
-	fi
-
-	case $service in
-	(help)
-		_arguments -A "-*" \
-			- set1 \
-			':command/property:($subcmds ${fields%%\[*} properties)' \
-			- set2 \
-			'-l[Display property information]' \
-			': :(properties)'
-		;;
-
-	(clear)
-		_arguments -A "-*" \
-			'-F[Discard transactions to allow pool opening]' \
-			'-f[Ignore fmadm acquit and fmadm repair failures]' \
-			'-n[With -F, check if discarding transactions would work]' \
-			':pool name:_zfs_pool' \
-			'*:virtual device:_files'
-		;;
-
-	(create)
-		# TODO: investigate better vdev handling
-		_arguments -A "-*" \
-			'-B[Create EFI boot partition on whole disks]' \
-			'-o[Set pool property at creation time]:property:_values -s , "property" $rw_props' \
-			'-O[Set dataset property at creation time]:property:_values -s , "property" $create_properties_dataset' \
-			'-f[Force use of in-use devices]' \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-n[Display configuration without creating pool]' \
-			'-R[Use alternate root]:alternate root:_files -/' \
-			'-m[Set mountpoint for root dataset]:mountpoint:' \
-			':pool name:' \
-			'*:virtual device:_files'
-		;;
-
-	(destroy)
-		_arguments -A "-*" \
-			'-f[Force active datasets to be unmounted]' \
-			':pool name:_zfs_pool'
-		;;
-
-	(add)
-		_arguments -A "-*" \
-			'-f[Force use of in-use devices]' \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-n[Display configuration without modifying pool]' \
-			':pool name:_zfs_pool' \
-			'*:virtual device:_files'
-		;;
-
-	(list)
-		_arguments \
-			'-H[Scripted mode]' \
-			'-T[timestamp]:value:(u d)' \
-			'-o[Fields to list]:field:_values -s , "field" $fields' \
-			'::pool name:_zfs_pool'
-		;;
-
-	(initialize)
-		_arguments -A "-*" \
-			'(-c --cancel)'{-c,--cancel}'[cancel initializing on specified devices]' \
-			'(-s --suspend)'{-s,--suspend}'[suspend initializing on specified devices]' \
-			':pool name:_zfs_pool' \
-			'*:device:_files'
-		;;
-
-	(iostat)
-		_arguments -A "-*" \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-T[timestamp]:value:(u d)' \
-			'-v[Verbose statistics]' \
-			'*::pool name:_zfs_pool' \
-			'::interval:' \
-			'::count:'
-		;;
-
-	(labelclear)
-		_arguments -A "-*" \
-			'-f[treat exported or foreign devices as inactive]' \
-			'*:virtual device:_files'
-		;;
-
-	(status)
-		_arguments -A "-*" \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-v[Verbose information]' \
-			'-x[Show only unhealthy pools]' \
-			'-T[timestamp]:value:(u d)' \
-			'*::pool name:_zfs_pool'
-		;;
-
-	(offline)
-		_arguments -A "-*" \
-			'-t[Offline until next reboot]' \
-			':pool name:_zfs_pool' \
-			'*:virtual device:_files'
-		;;
-
-	(online)
-		_arguments \
-			'-e[Expand device to use all available space]' \
-			':pool name:_zfs_pool' \
-			'*:virtual device:_files'
-		;;
-
-	(attach)
-		# TODO: first device should choose first from existing.
-		_arguments \
-			'-f[Force attach, even if in use]' \
-			':pool name:_zfs_pool' \
-			':virtual device:_files' \
-			':virtual device:_files'
-		;;
-
-	(detach)
-		_arguments \
-			':pool name:_zfs_pool' \
-			':virtual device:_files'
-		;;
-
-	(replace)
-		_arguments -A "-*" \
-			'-f[Force attach, even if in use]' \
-			':pool name:_zfs_pool' \
-			':virtual device:_files' \
-			'::virtual device:_files'
-		;;
-
-	(scrub)
-		_arguments -A "-*" \
-			'-s[Stop scrubbing]' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(export)
-		_arguments -A "-*" \
-			'-f[Forcefully unmount all datasets]' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(import)
-		# TODO: -o should complete mount options, too
-		_arguments -A "-*" \
-			'-D[Destroyed pools]' \
-			'(-d)*-c[Use cache file]:cache file:_files' \
-			'(-c -D)*-d[Search for devices or files in directory]:directory:_files -/' \
-			'-F[Recovery mode: discard transactions if required]' \
-			'-f[Force import]' \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-m[Ignore missing log devices]' \
-			'-N[Import pool without mounting any filesystems]' \
-			'-n[With -F; do not perform input]' \
-			'-R[Alternate root]:alternate root:_files -/' \
-			'-o[Set pool or dataset property]:property:_values -s , "property" $create_properties_dataset $rw_props' \
-			- set1 \
-			'*:pool name or id:_zfs_pool' \
-			'::new pool name:' \
-			- set2 \
-			'-N[Do not mount any filesystems]' \
-			'-a[All pools]'
-		;;
-
-	(get)
-		_arguments -A "-*" \
-			':property:_values -s , "property" $fields' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(set)
-		_arguments -A "-*" \
-			':property:_values -s , "property" $rw_props' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(split)
-		_arguments -A "-*" \
-			'-R[Alternate root]:alternate root:_files -/' \
-			'-l[Display configuration in /dev/chassis location form]' \
-			'-n[Display configuration without splitting]' \
-			'-o[Set pool or dataset property]:property:_values -s , "property" $create_properties_dataset $rw_props' \
-			':pool name or id:_zfs_pool' \
-			':new pool name:' \
-			'*::virtual device:_files -/'
-		;;
-
-	(upgrade)
-		_arguments -A "-*" \
-			- set1 \
-			'-v[Display ZFS versions and descriptions]' \
-			- set2 \
-			"-V[Upgrade to given version]:version:($versions)" \
-			'-a[Upgrade all pools]' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(history)
-		_arguments -A "-*" \
-			'-i[Display internal events]' \
-			'-l[Long format]' \
-			'*:pool name:_zfs_pool'
-		;;
-
-	(*)
-		_message "unknown zpool subcommand: $service"
-		;;
-	esac
-}
-
-_zpool "$@"
diff --git a/Completion/Unix/Type/_zfs_dataset b/Completion/Unix/Type/_zfs_dataset
index 63384afc6..7edcfd5d7 100644
--- a/Completion/Unix/Type/_zfs_dataset
+++ b/Completion/Unix/Type/_zfs_dataset
@@ -11,10 +11,12 @@ local expl_type
 # -t takes arguments (what kinds of datasets) and can appear multiple times
 zparseopts -D -E e:=expl_type_arr p=paths_allowed r1=rsrc r2=rdst t+:=type
 
-[[ -n $type[(r)fs] ]]    && typearg=( filesystem )
-[[ -n $type[(r)vol] ]]   && typearg=( $typearg volume )
-[[ -n $type[(r)snap] ]]  && typearg=( $typearg snapshot )
-[[ -n $type[(r)share] ]]  && typearg=( $typearg share )
+[[ -n $type[(r)fs] ]] && typearg=( filesystem )
+[[ -n $type[(r)vol] ]] && typearg+=( volume )
+[[ -n $type[(r)snap] ]] && typearg+=( snapshot )
+[[ -n $type[(r)share] && $implementation = solaris ]] && typearg+=( share )
+[[ -n $type[(r)bookmark] && $implementation = openzfs ]] &&
+    typearg+=( bookmark )
 if [[ -n $typearg ]]; then
 	typearg=( -t ${(j:,:)typearg} )
 # We know we're in zfs list if paths_allowed is non-empty.
@@ -58,7 +60,7 @@ if [[ ${#rdst} -gt 0 ]]; then
 fi
 
 if [[ -n $type[(r)clone] ]]; then
-	datasetlist=( ${(f)"$(zfs list -H -o name,origin -t filesystem 2>/dev/null | awk -F $'\t' "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
+  datasetlist=( ${(f)"$(zfs list -H -o name,origin -t filesystem 2>/dev/null | awk -F$'\t' "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
 else
 	datasetlist=( ${(f)"$(zfs list -H -o name $typearg 2>/dev/null)":#no datasets available} )
 fi
@@ -74,4 +76,5 @@ if [[ -n $expl_type_arr[2] ]]; then
 	expl_type=$expl_type_arr[2]
 fi
 
-_wanted dataset expl "$expl_type" _multi_parts "$@" -q / datasetlist
+_description datasets expl "$expl_type"
+_multi_parts "$@" "$expl[@]" -q / datasetlist
diff --git a/Completion/Unix/Type/_zfs_keysource_props b/Completion/Unix/Type/_zfs_keysource_props
deleted file mode 100644
index 01f63257a..000000000
--- a/Completion/Unix/Type/_zfs_keysource_props
+++ /dev/null
@@ -1,15 +0,0 @@
-#autoload
-
-local -a suf
-local expl
-
-compset -S ",*" || suf=(-S ,)
-if compset -P 1 "*,"; then
-	_alternative "zfs-keylocator-prompt:\"prompt\" locator:(prompt)" \
-		"zfs-keylocator-file:file locator:_path_files" \
-		"zfs-keylocator-pkcs11:PKCS#11 locator: " \
-		"zfs-keylocator-https:HTTPS URL locator: "
-else
-	_description format expl "keysource format"
-	compadd $suf -q "$expl[@]" "$@" raw hex passphrase
-fi


^ permalink raw reply	[relevance 1%]

* Writing XFail tests (was: Re: [BUG] POSIX arith: inf, nan should be variables)
  2021-12-01  3:37  9%       ` Bart Schaefer
@ 2021-12-01  4:27  4%         ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2021-12-01  4:27 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Wed, 01 Dec 2021 03:37 +00:00:
> On Tue, Nov 30, 2021 at 7:36 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>>
>> Maybe add a test based on the above code snippet?
>
> There's already an xfail test:
>
> Test ./E03posix.ztst was expected to fail, but passed.
> Was testing: All identifiers are variable references in POSIX arithmetic
>
> Just need to flip the state on that one.

I've taken the liberty of doing so.

Incidentally, when writing xfail tests I like to write them with minimal
expectations, so that the test will trigger as soon as zsh's behaviour
changes:
.
     what-is-2-plus-2
    -fD:Unit test for a future builtin
    *>[0-9]

Here, the test looks for something on stdout and is xfail, so it expects
no specific exit code and no specific stderr.  This way, the test will
flip as soon as stdout becomes correct, regardless of whether the exit
code and stderr are at that time also what the they are expected to be
in the end (usually 0 and empty, respectively).

The test also uses a pattern on stdout, so that the test will pass even if
there are, say, whitespace differences between the predicted output (at
the time the xfail test is written) and the actual output (later, when
the bug is fixed).  See workers/48916 for an example of this.

Once the bug is fixed, the test's expectations (all three of them:
stdout, stderr, exit code) can be changed to their permanent form:
.
     what-is-2-plus-2
    0:Unit test for what-is-2-plus-2
    >4

That is: I'd suggest to use «f» flag in conjunction with two of the
three flags [-dD].

Cheers,

Daniel


^ permalink raw reply	[relevance 4%]

* Re: [BUG] POSIX arith: inf, nan should be variables
  2021-12-01  3:31  5%     ` Daniel Shahaf
@ 2021-12-01  3:37  9%       ` Bart Schaefer
  2021-12-01  4:27  4%         ` Writing XFail tests (was: Re: [BUG] POSIX arith: inf, nan should be variables) Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2021-12-01  3:37 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: Zsh hackers list

On Tue, Nov 30, 2021 at 7:36 PM Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
>
> Maybe add a test based on the above code snippet?

There's already an xfail test:

Test ./E03posix.ztst was expected to fail, but passed.
Was testing: All identifiers are variable references in POSIX arithmetic

Just need to flip the state on that one.


^ permalink raw reply	[relevance 9%]

* Re: [BUG] POSIX arith: inf, nan should be variables
  2021-11-28 20:34  5%   ` Oliver Kiddle
@ 2021-12-01  3:31  5%     ` Daniel Shahaf
  2021-12-01  3:37  9%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2021-12-01  3:31 UTC (permalink / raw)
  To: zsh-workers

Oliver Kiddle wrote on Sun, Nov 28, 2021 at 21:34:41 +0100:
> On 16 Nov, Vincent Lefevre wrote:
> > On 2021-11-15 18:40:17 +0100, Martijn Dekker wrote:
> > > $ zsh --emulate sh -c 'inf=1; nan=2; echo $((inf)) $((nan))'
> > > Inf NaN
> > > 
> > > Expected: 1 2
> >
> > FYI, this had already been discussed in April in this subthread:
> 
> And it'll probably come up again if we don't do anything. Unless anyone
> has better ideas, I'm inclined to go with the following variant of
> Martijn's patch.

Maybe add a test based on the above code snippet?

Cheers,

Daniel


> 
> diff --git a/Src/math.c b/Src/math.c
> index 4f24361a4..777ad9c31 100644
> --- a/Src/math.c
> +++ b/Src/math.c
> @@ -863,7 +863,7 @@ zzlex(void)
>  
>  		p = ptr;
>  		ptr = ie;
> -		if (ie - p == 3) {
> +		if (ie - p == 3 && !EMULATION(EMULATE_SH)) {
>  		    if ((p[0] == 'N' || p[0] == 'n') &&
>  			(p[1] == 'A' || p[1] == 'a') &&
>  			(p[2] == 'N' || p[2] == 'n')) {
> 


^ permalink raw reply	[relevance 5%]

* Re: [BUG] POSIX arith: inf, nan should be variables
  2021-11-16 12:55  5% ` Vincent Lefevre
@ 2021-11-28 20:34  5%   ` Oliver Kiddle
  2021-12-01  3:31  5%     ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Oliver Kiddle @ 2021-11-28 20:34 UTC (permalink / raw)
  To: zsh-workers

On 16 Nov, Vincent Lefevre wrote:
> On 2021-11-15 18:40:17 +0100, Martijn Dekker wrote:
> > $ zsh --emulate sh -c 'inf=1; nan=2; echo $((inf)) $((nan))'
> > Inf NaN
> > 
> > Expected: 1 2
>
> FYI, this had already been discussed in April in this subthread:

And it'll probably come up again if we don't do anything. Unless anyone
has better ideas, I'm inclined to go with the following variant of
Martijn's patch.

Oliver

diff --git a/Src/math.c b/Src/math.c
index 4f24361a4..777ad9c31 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -863,7 +863,7 @@ zzlex(void)
 
 		p = ptr;
 		ptr = ie;
-		if (ie - p == 3) {
+		if (ie - p == 3 && !EMULATION(EMULATE_SH)) {
 		    if ((p[0] == 'N' || p[0] == 'n') &&
 			(p[1] == 'A' || p[1] == 'a') &&
 			(p[2] == 'N' || p[2] == 'n')) {


^ permalink raw reply	[relevance 5%]

* [PATCH] Do not define _POSIX_C_SOURCE when checking for sigset_t on Solaris
@ 2021-11-23  6:46  3% Claes Nästén
  0 siblings, 0 replies; 200+ results
From: Claes Nästén @ 2021-11-23  6:46 UTC (permalink / raw)
  To: zsh-workers

Trying to compile zsh on Solaris 10 fails for me right after
configuration due to misleading information in config.h

The check for sigset_t fails, due to:

configure:8654: checking for sigset_t
configure:8673: gcc -c  -Wall -Wmissing-prototypes -O2  conftest.c >&5
In file included from /usr/include/sys/types.h:17,
                 from conftest.c:85:
/usr/pkg/gcc8/lib/gcc/sparc64-sun-solaris2.10/8.4.0/include-fixed/sys/feature_tee
sts.h:346:2: error: #error "Compiler or options invalid for pre-UNIX 03 X/Open aa
pplications     and pre-2001 POSIX applications"
 #error "Compiler or options invalid for pre-UNIX 03 X/Open applications \
  ^~~~~
conftest.c: In function 'main':
conftest.c:90:10: warning: unused variable 'tempsigset' [-Wunused-variable]
 sigset_t tempsigset;
          ^~~~~~~~~~
configure:8673: $? = 1

Looking at the git history it seems _POSIX_C_SOURCE is defined to ensure
configure works with systems using musl libc so the patch should not cause
any issues as it's Linux only.

Tried configuring on Solaris 11 as well and it still detects sigset_t.

diff --git a/configure.ac b/configure.ac
index 297a7482f..7494b3529 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1135,7 +1135,9 @@ dnl Check for sigset_t.  Currently I'm looking in
 dnl <sys/types.h> and <signal.h>.  Others might need
 dnl to be added.
 AC_CACHE_CHECK(for sigset_t, zsh_cv_type_sigset_t,
-[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#define _POSIX_C_SOURCE 200809L
+[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#ifndef __sun
+  #define _POSIX_C_SOURCE 200809L
+#endif
 #include <sys/types.h>
 #include <signal.h>]], [[sigset_t tempsigset;]])],[zsh_cv_type_sigset_t=yes],[zsh_cv_type_sigset_t=no])])
 AH_TEMPLATE([sigset_t],



^ permalink raw reply	[relevance 3%]

* Re: [BUG] POSIX arith: inf, nan should be variables
  2021-11-15 17:40  9% [BUG] POSIX arith: inf, nan should be variables Martijn Dekker
  2021-11-16  9:06  5% ` Oliver Kiddle
@ 2021-11-16 12:55  5% ` Vincent Lefevre
  2021-11-28 20:34  5%   ` Oliver Kiddle
  1 sibling, 1 reply; 200+ results
From: Vincent Lefevre @ 2021-11-16 12:55 UTC (permalink / raw)
  To: zsh-workers

On 2021-11-15 18:40:17 +0100, Martijn Dekker wrote:
> $ zsh --emulate sh -c 'inf=1; nan=2; echo $((inf)) $((nan))'
> Inf NaN
> 
> Expected: 1 2

FYI, this had already been discussed in April in this subthread:

  https://www.zsh.org/mla/workers/2021/msg00717.html

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 5%]

* Re: [BUG] POSIX arith: inf, nan should be variables
  2021-11-15 17:40  9% [BUG] POSIX arith: inf, nan should be variables Martijn Dekker
@ 2021-11-16  9:06  5% ` Oliver Kiddle
  2021-11-16 12:55  5% ` Vincent Lefevre
  1 sibling, 0 replies; 200+ results
From: Oliver Kiddle @ 2021-11-16  9:06 UTC (permalink / raw)
  To: Martijn Dekker; +Cc: Zsh hackers list

Martijn Dekker wrote:
> $ zsh --emulate sh -c 'inf=1; nan=2; echo $((inf)) $((nan))'
> Inf NaN
>
> Expected: 1 2

> So, what shell option to tie that to? That's a bit difficult. It needs 

The closest comparable feature is the decision in params.c as to whether
it should setup other special variables that aren't in the standard.

That seems to only check something like !EMULATION(EMULATE_SH) rather
than an actual option. Much of that has to run before zsh has got as far
as sourcing dot files that might setup options so it likely never made
sense to create an option for it. Most uses of directly checking
emulation state seem to be in initialisation code.

I wouldn't rename an option for compatibility. And while OCTAL_ZEROES is
similar in controlling interpretation of numbers in math mode it differs
in that it enables a potentially problematic standard feature while
Inf/NaN are a zsh extension. So I wouldn't view preferences on them as
being intrinsically linked.

Oliver


^ permalink raw reply	[relevance 5%]

* [BUG] POSIX arith: inf, nan should be variables
@ 2021-11-15 17:40  9% Martijn Dekker
  2021-11-16  9:06  5% ` Oliver Kiddle
  2021-11-16 12:55  5% ` Vincent Lefevre
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2021-11-15 17:40 UTC (permalink / raw)
  To: Zsh hackers list

$ zsh --emulate sh -c 'inf=1; nan=2; echo $((inf)) $((nan))'
Inf NaN

Expected: 1 2

This is a POSIX compliance issue that ksh93 also has (I've just fixed in 
ksh 93u+m). I can see why this is needed for full floating point 
arithmetic support, but in POSIX sh, all case variants of inf and nan 
are perfectly legitimate variables that portable scripts should be able 
to use, including in arithmetic evaluation. Their recognition should be 
turned off for sh emulation, but not for ksh emulation as ksh93's native 
mode also supports floating point arithmetic.

So, what shell option to tie that to? That's a bit difficult. It needs 
to be an option that is on for sh, but off for ksh (or vice versa). A 
comparison of 'set -o' output between sh and ksh modes shows that the 
options are limited to the following:

bsdecho
ignorebraces
kshglob
kshoptionprint
localoptions
localtraps
octalzeroes
promptbang
sharehistory
singlelinezle

The only one of those that has anything to do with an arithmetic context 
is octalzeroes, so that one may be the least bad one to choose. The 
preliminary patch below does that.

Perhaps octalzeroes could be renamed to something like posixmath, so 
that it becomes legitimate to attach this and any other POSIX arithmetic 
quirks to this option without further crowding the shell option space.

Thoughts/opinions?

--- a/Src/math.c
+++ b/Src/math.c
@@ -863,7 +863,7 @@ zzlex(void)

  		p = ptr;
  		ptr = ie;
-		if (ie - p == 3) {
+		if (ie - p == 3 && !isset(OCTALZEROES)) {
  		    if ((p[0] == 'N' || p[0] == 'n') &&
  			(p[1] == 'A' || p[1] == 'a') &&
  			(p[2] == 'N' || p[2] == 'n')) {

-- 
||	modernish -- harness the shell
||	https://github.com/modernish/modernish
||
||	KornShell lives!
||	https://github.com/ksh93/ksh


^ permalink raw reply	[relevance 9%]

* Re: [BUG] _less incorrectly completes -" and -#
  @ 2021-10-23  0:26  3%   ` Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2021-10-23  0:26 UTC (permalink / raw)
  To: Roman Perepelitsa, Zsh hackers list

This is digging up another fairly old _arguments issue that I meant to
deal with before:

On 2 Oct 2020, I wrote:
> Roman Perepelitsa wrote:
> > Completing `less -` offers `-"` as a candidate. Accepting it literally
> > inserts `-"`. I think it should offer `-\"` and insert the same.

> The real problem is that from inside _arguments, the -Q option gets
> passed to compadd. Removing it is a fairly easy change. But I wish I
> knew why it was used in the first place. Maybe we should just do that
> and worry later about fixing any problems it creates afterwards.

The following patch does exactly this. _arguments has quite a few lines
that do compadd -Q - "${PREFIX}${SUFFIX}" which I've left alone. They
seem to be special case handling, possibly for _arguments' -w option.
It'd be nice to establish test cases that exercise them but the only
path I could contrive to use one of them did not result in what I'd take
to be intended behaviour (_arguments -s '-a=-' and -a<tab> giving a
space suffix).

Otherwise, this simple approach appears to work well in my testing.

One issue that isn't new is that completion after '- doesn't list
options for a completion that lacks rest-arguments. The _arguments C
code seems to have to deal with the command-line in quoted form. There
used to be a layer of unquoting in the _arguments C code that got
removed in 27218 but restoring it doesn't help anyway.

Most of the patch is completion functions that hard-coded now
superfluous quotes on options. The use of quotes within exclusion lists
was never useful.

Oliver

diff --git a/Completion/Base/Utility/_arguments b/Completion/Base/Utility/_arguments
index 3f1b39304..69e7ab235 100644
--- a/Completion/Base/Utility/_arguments
+++ b/Completion/Base/Utility/_arguments
@@ -513,8 +513,8 @@ if (( $# )) && comparguments -i "$autod" "$singopt[@]" "$@"; then
 	    tmp2=( "${PREFIX}${(@M)^${(@)${(@)tmp1%%:*}#[-+]}:#?}" )
 
             _describe -O option \
-                      tmp1 tmp2 -Q -S '' -- \
-		      tmp3 -Q
+                      tmp1 tmp2 -S '' -- \
+                      tmp3
 
             [[ -n "$optarg" && "$single" = next && nm -eq $compstate[nmatches] ]] &&
                 _all_labels options expl option \
@@ -525,9 +525,9 @@ if (( $# )) && comparguments -i "$autod" "$singopt[@]" "$@"; then
         else
           next+=( "$odirect[@]" )
           _describe -O option \
-                    next -Q -M "$matcher" -- \
-                    direct -QS '' -M "$matcher" -- \
-                    equal -QqS= -M "$matcher"
+                    next -M "$matcher" -- \
+                    direct -S '' -M "$matcher" -- \
+                    equal -qS= -M "$matcher"
         fi
 	PREFIX="$prevpre"
 	IPREFIX="$previpre"
diff --git a/Completion/Darwin/Command/_qtplay b/Completion/Darwin/Command/_qtplay
index 39a7c6de2..839efee83 100644
--- a/Completion/Darwin/Command/_qtplay
+++ b/Completion/Darwin/Command/_qtplay
@@ -15,6 +15,6 @@ _arguments -S \
   '-t[specify update time]:update time (seconds)' \
   '-T[kill time]:ticks' \
   '-V[volume]:percentage of normal volume' \
-  '(-)'{-?,--help,-h}'[display help information]' \
+  '(-)'{-\?,--help,-h}'[display help information]' \
   '(-)*:quicktime file:_files'
 
diff --git a/Completion/Unix/Command/_less b/Completion/Unix/Command/_less
index 0b474b991..ae912a633 100644
--- a/Completion/Unix/Command/_less
+++ b/Completion/Unix/Command/_less
@@ -80,9 +80,9 @@ _arguments -S -s -A "[-+]*"  \
   '--no-keypad[disable use of keypad terminal init string]' \
   '(-y --max-forw-scroll)'{-y,--max-forw-scroll}'[specify forward scroll limit]' \
   '(-z --window)'{-z+,--window=}'[specify scrolling window size]:lines' \
-  '(-\" --quotes)'{-\"+,--quotes=}'[change quoting character]:quoting characters' \
+  '(-" --quotes)'{-\"+,--quotes=}'[change quoting character]:quoting characters' \
   '(-~ --tilde)'{-~,--tilde}"[don't display tildes after end of file]" \
-  '(-\# --shift)'{-\#+,--shift=}"[specify amount to move when scrolling horizontally]:number" \
+  '(-# --shift)'{-\#+,--shift=}"[specify amount to move when scrolling horizontally]:number" \
   '--file-size[automatically determine the size of the input file]' \
   '--incsearch[search file as each pattern character is typed in]' \
   '--line-num-width=[set the width of line number field]:width [7]' \
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 79f537ac6..888f1ef87 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -53,7 +53,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
 	'(-C)--demangle[decode symbol names]'
 	'(--format -P)-f+[specify output format]:format:(bsd sysv posix)'
 	'(- *)--usage[give a short usage message]'
-	'(- *)-\\?[display help information]'
+	'(- *)-?[display help information]'
       )
     ;;
     binutils)
diff --git a/Completion/Unix/Command/_php b/Completion/Unix/Command/_php
index c4c4ab3e2..9a8f519b1 100644
--- a/Completion/Unix/Command/_php
+++ b/Completion/Unix/Command/_php
@@ -93,7 +93,7 @@ _php() {
     + '(hv)' # Help/version options; kept separate by convention
     '(- 1 *)'{-h,--help}'[display help information]'
     '(- 1 *)'{-v,--version}'[display version information]'
-    '!(- 1 *)'{-\?,-\\\?,--usage}
+    '!(- 1 *)'{-\?,--usage}
 
     + '(im)' # Info/module options (exclusive with everything but -c/-n)
     '(fi mc pb pf rf rn sc sv *)'{-i,--info}'[display configuration information (phpinfo())]'
diff --git a/Completion/Unix/Command/_strings b/Completion/Unix/Command/_strings
index af95af52f..685daa286 100644
--- a/Completion/Unix/Command/_strings
+++ b/Completion/Unix/Command/_strings
@@ -45,7 +45,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
     elfutils)
       args+=(
 	'(- *)--usage[display a short usage message]'
-	'(- *)-\\?[display help information]'
+	'(- *)-?[display help information]'
       )
     ;;
   esac
diff --git a/Completion/Unix/Command/_zip b/Completion/Unix/Command/_zip
index bc9aab1a5..cfa51be36 100644
--- a/Completion/Unix/Command/_zip
+++ b/Completion/Unix/Command/_zip
@@ -115,7 +115,7 @@ case $service in
       '(-U)-UU[ignore any Unicode fields]' \
       '-W[modify pattern matching so only ** matches /]' \
       '-\:[allow extraction outside of extraction base directory]' \
-      '-\\\^[allow control characters in extracted entries]' \
+      '-^[allow control characters in extracted entries]' \
       '-i[include the following names]:*-*:pattern' \
       '-x[exclude the following names]:*-*:pattern' \
       "(-p -f -u -l -t -z -n -o -j -C -X -q -qq -a -aa -v -L -M)1:zip file:_files -g '(#i)*.(zip|xpi|[ejw]ar)(-.)'" \
diff --git a/Completion/X/Command/_gnome-gv b/Completion/X/Command/_gnome-gv
index 25de6fadf..b1b66e2a4 100644
--- a/Completion/X/Command/_gnome-gv
+++ b/Completion/X/Command/_gnome-gv
@@ -1,6 +1,6 @@
 #compdef gnome-gv ggv
 
 _arguments \
-  '(--help)-\\?[help]' \
+  '(--help)-?[help]' \
   '(--windows)-w[number of empty windows]:number:' \
   '*:file: _pspdf -z' --


^ permalink raw reply	[relevance 3%]

* Re: Unexpected stdin-behavior
  @ 2021-10-22 14:24  3%       ` Tycho Kirchner
  0 siblings, 0 replies; 200+ results
From: Tycho Kirchner @ 2021-10-22 14:24 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list



I also sent an email to the dash-developers regarding the same issue, 
you may be interested in Chet's response:


On 10/22/21 7:11 AM, Tycho Kirchner wrote:
 > Dear DASH developers,
 > I think stdin should be consumed line by line in order to make 
passing to
 > other commands possible. Please consider the following difference 
between
 > the stdin "consumption" between bash and dash

If you're curious, POSIX specifies the bash behavior. From

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/sh.html#tag_20_117

"When the shell is using standard input and it invokes a command that also
uses standard input, the shell shall ensure that the standard input file
pointer points directly after the command it has read when the command
begins execution. It shall not read ahead in such a manner that any
characters intended to be read by the invoked command are consumed by the
shell (whether interpreted by the shell or not) or that characters that are
not read by the invoked command are not seen by the shell."

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet@case.edu    http://tiswww.cwru.edu/~chet/



^ permalink raw reply	[relevance 3%]

* Re: Question on unintuitive behaviour for function execution and parameter assignment
  2021-10-13  8:42  3%   ` Jett Husher
@ 2021-10-13  9:10  4%     ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2021-10-13  9:10 UTC (permalink / raw)
  To: zsh-workers


> On 13 October 2021 at 09:42 Jett Husher <jetthusher@pm.me> wrote:
> On Tuesday, October 12th, 2021 at 10:31, Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> > This is covered by the POSIX_BUILTINS option. Generally, the POSIX_* options are
> >
> > the place to look for this sort of think --- granted that can be a bit of hunt.
> 
> I wouldn't even think to look at POSIX_* variables because POSIX-2017
> explicitly tells that it's unspecified "Whether or not the variable assignments persist after
> the completion of the function", so, naturally, I though that this behaviour was compliant.

It's always worth (everyone) bearing in mind that zsh is not a POSIX shell by default.

In fact, it's not *completely* POSIX even in sh emulation, as this has been gradually
retrofitted, and not everything can be done within the current constraints.

cheers
pws


^ permalink raw reply	[relevance 4%]

* Re: Question on unintuitive behaviour for function execution and parameter assignment
  2021-10-12  8:31  3% ` Peter Stephenson
@ 2021-10-13  8:42  3%   ` Jett Husher
  2021-10-13  9:10  4%     ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Jett Husher @ 2021-10-13  8:42 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Tuesday, October 12th, 2021 at 10:31, Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> This is covered by the POSIX_BUILTINS option. Generally, the POSIX_* options are
>
> the place to look for this sort of think --- granted that can be a bit of hunt.

I wouldn't even think to look at POSIX_* variables because POSIX-2017
explicitly tells that it's unspecified "Whether or not the variable assignments persist after
the completion of the function", so, naturally, I though that this behaviour was compliant.

> Usually an easy test to see if zsh does have the POSIX behaviour available is
>
> to start a new shell as
>
> ARGV0=sh zsh
>
> and see what behaviour that gives you. That should be maximally compatible,
>
> although it doesn't help you find which option controls the behaviour.

I would keep that in mind next time. I used to compare the executions in bash, since I thought
it's more compliant, but I guess it's not the best option since GNU also states that it
takes the standards as a recommendation and not a rule.

I still believe this needs to be mentioned in FUNCTIONS or SIMPLE COMMANDS & PIPELINES of zshmisc(1).
Or zshparam(1) perhaps? I would love to suggest my help with updating man pages but I'm not sure
if you accept commits the side. Or even how the development is done around here :shrug:

Either way, a world of thanks for the help, Peter.
- Jett


^ permalink raw reply	[relevance 3%]

* Re: Question on unintuitive behaviour for function execution and parameter assignment
  2021-10-12  8:20  3% Question on unintuitive behaviour for function execution and parameter assignment Jett Husher
@ 2021-10-12  8:31  3% ` Peter Stephenson
  2021-10-13  8:42  3%   ` Jett Husher
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2021-10-12  8:31 UTC (permalink / raw)
  To: Jett Husher, zsh-workers


> On 12 October 2021 at 09:20 Jett Husher <jetthusher@pm.me> wrote:
> 
> 
> Good day!
> 
> Does a function `assign-hello` treat parameter assignment on simple command as local parameter in the following code snipped?
> 
> ```
> HELLO=WORLD
> 
> function assign-hello() HELLO=$1
> 
> assign-hello THERE
> echo $HELLO # Prints 'THERE', as expected
> 
> # This part trips me up
> HELLO= assign-hello WHY
> echo $HELLO # Why does it still print 'THERE'?
> ```

This is covered by the POSIX_BUILTINS option.  Generally, the POSIX_* options are
the place to look for this sort of think --- granted that can be a bit of hunt.

Usually an easy test to see if zsh does have the POSIX behaviour available is
to start a new shell as

ARGV0=sh zsh

and see what behaviour that gives you.  That should be maximally compatible,
although it doesn't help you find which option controls  the behaviour.

POSIX_BUILTINS <K> <S>
    When this option is set the command builtin can be used  to  execute  shell
    builtin  commands.   Parameter assignments specified before shell functions
    and special builtins are kept after the command completes unless  the  spe‐
    cial builtin is prefixed with the command builtin.  Special builtins are .,
    :, break, continue, declare, eval, exit, export, integer, local,  readonly,
    return, set, shift, source, times, trap and unset.

pws


^ permalink raw reply	[relevance 3%]

* Question on unintuitive behaviour for function execution and parameter assignment
@ 2021-10-12  8:20  3% Jett Husher
  2021-10-12  8:31  3% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Jett Husher @ 2021-10-12  8:20 UTC (permalink / raw)
  To: zsh-workers

Good day!

Does a function `assign-hello` treat parameter assignment on simple command as local parameter in the following code snipped?

```
HELLO=WORLD

function assign-hello() HELLO=$1

assign-hello THERE
echo $HELLO # Prints 'THERE', as expected

# This part trips me up
HELLO= assign-hello WHY
echo $HELLO # Why does it still print 'THERE'?
```

POSIX spec says that parameter assignment with function execution will alter the current shell environment and that it's not specified what's going to happen with this parameter at the end of the execution. `zshmisc(1)` in FUNCTIONS states that functions are called on a parent process, so my intuition was that this sort of code should not work for them. Unfortunately, I could not find any more information about this in the manuals or FAQs.

Can manuals be updated to cover this behaviour, please?

Thank you for your time.
- Jett


^ permalink raw reply	[relevance 3%]

* [PATCH 1/4] docs: Clean up some subsection references.
@ 2021-09-26  8:43  3% Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2021-09-26  8:43 UTC (permalink / raw)
  To: zsh-workers

---
 Doc/Zsh/calsys.yo      | 2 +-
 Doc/Zsh/contrib.yo     | 6 +++---
 Doc/Zsh/expn.yo        | 2 +-
 Doc/Zsh/intro.yo       | 2 +-
 Doc/Zsh/jobs.yo        | 2 +-
 Doc/Zsh/mod_newuser.yo | 2 +-
 Doc/Zsh/options.yo     | 4 ++--
 Doc/Zsh/params.yo      | 2 +-
 Doc/Zsh/roadmap.yo     | 2 +-
 Doc/Zsh/zle.yo         | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/Doc/Zsh/calsys.yo b/Doc/Zsh/calsys.yo
index c20c87e61..a8fd876a5 100644
--- a/Doc/Zsh/calsys.yo
+++ b/Doc/Zsh/calsys.yo
@@ -478,7 +478,7 @@ item(tt(calendar_add) [ tt(-BL) ] var(event) ...)(
 Adds a single event to the calendar in the appropriate location.
 The event can contain multiple lines, as described in
 ifnzman(noderef(Calendar File and Date Formats))\
-ifzman(the section Calendar File Format above).
+ifzman(the section `Calendar File Format' above).
 Using this function ensures that the calendar file is sorted in date
 and time order.  It also makes special arrangements for locking
 the file while it is altered.  The old calendar is left in a file
diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 94059eff6..0781c7eb3 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -2341,7 +2341,7 @@ directly.
 )
 tindex(bracketed-paste-magic)
 item(tt(bracketed-paste-magic))(
-The tt(bracketed-paste) widget (see ifzman(subsection Miscellaneous in
+The tt(bracketed-paste) widget (see ifzman(the subsection `Miscellaneous' in
 zmanref(zshzle))ifnzman(noderef(Miscellaneous) in noderef(Zle Widgets)))
 inserts pasted text literally into the editor buffer rather than interpret
 it as keystrokes.  This disables some common usages where the self-insert
@@ -3190,7 +3190,7 @@ investigate the command word found.  The default is tt(whence -c).
 tindex(zcalc-auto-insert)
 item(tt(zcalc-auto-insert))(
 This function is useful together with the tt(zcalc) function described in
-ifzman(the section Mathematical Functions)\
+ifzman(the section `Mathematical Functions')\
 ifnzman(noderef(Mathematical Functions)).
 It should be bound to a key representing a binary operator such
 as `tt(PLUS())', `tt(-)', `tt(*)' or `tt(/)'.  When running in zcalc,
@@ -3664,7 +3664,7 @@ types even if they are executable.  As this example shows, the complete
 file name is matched against the pattern, regardless of how the file
 was passed to the handler.  The file is resolved to a full path using
 the tt(:P) modifier described in
-ifzman(the subsection Modifiers in zmanref(zshexpn))\
+ifzman(the subsection `Modifiers' in zmanref(zshexpn))\
 ifnzman(noderef(Modifiers));
 this means that symbolic links are resolved where possible, so that
 links into other file systems behave in the correct fashion.
diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index c218ded05..50f70c9af 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1854,7 +1854,7 @@ has similar effects.
 
 To combine brace expansion with array expansion, see the
 tt(${^)var(spec)tt(}) form described
-ifzman(in the section Parameter Expansion)\
+ifzman(in the section `Parameter Expansion')\
 ifnzman(in noderef(Parameter Expansion))
 above.
 
diff --git a/Doc/Zsh/intro.yo b/Doc/Zsh/intro.yo
index 75d25ce27..474e537c2 100644
--- a/Doc/Zsh/intro.yo
+++ b/Doc/Zsh/intro.yo
@@ -45,7 +45,7 @@ zsh most closely resembles bf(ksh) but includes many enhancements.  It
 does not provide compatibility with POSIX or other shells in its
 default operating mode:  see
 ifnzman(the section noderef(Compatibility))\
-ifzman(the section Compatibility below).
+ifzman(the section `Compatibility' below).
 
 Zsh has command line editing, builtin spelling correction, programmable
 command completion, shell functions (with autoloading), a history
diff --git a/Doc/Zsh/jobs.yo b/Doc/Zsh/jobs.yo
index 331b91d8d..3ab0698ae 100644
--- a/Doc/Zsh/jobs.yo
+++ b/Doc/Zsh/jobs.yo
@@ -135,4 +135,4 @@ ifzman(the section PROCESS SUBSTITUTION in the zmanref(zshexpn) manual page)\
 ifnzman(noderef(Process Substitution)), and the handler processes for
 multios, see
 ifzman(the section MULTIOS in the zmanref(zshmisc) manual page)\
-ifnzman(the section Multios in noderef(Redirection)).
+ifnzman(the section em(Multios) in noderef(Redirection)).
diff --git a/Doc/Zsh/mod_newuser.yo b/Doc/Zsh/mod_newuser.yo
index 92a64a013..7937e43c3 100644
--- a/Doc/Zsh/mod_newuser.yo
+++ b/Doc/Zsh/mod_newuser.yo
@@ -44,4 +44,4 @@ even if the tt(zsh/newuser) module is disabled.  Note, however, that
 if the module is not installed the function will not be installed either.
 The function is documented in
 ifnzman(noderef(User Configuration Functions))\
-ifzman(the section User Configuration Functions in zmanref(zshcontrib)).
+ifzman(the section `User Configuration Functions' in zmanref(zshcontrib)).
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 4a8b85e08..cf4600769 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -602,7 +602,7 @@ Substitutions using the tt(:s) and tt(:&) history modifiers are performed
 with pattern matching instead of string matching.  This occurs wherever
 history modifiers are valid, including glob qualifiers and parameters.
 See
-ifzman(the section Modifiers in zmanref(zshexpn))\
+ifzman(the section `Modifiers' in zmanref(zshexpn))\
 ifnzman(noderef(Modifiers)).
 )
 pindex(IGNORE_BRACES)
@@ -1483,7 +1483,7 @@ The check is omitted if the commands run from the previous command line
 included a `tt(jobs)' command, since it is assumed the user is aware that
 there are background or suspended jobs.  A `tt(jobs)' command run from one
 of the hook functions defined in
-ifnzman(the section Special Functions in noderef(Functions))\
+ifnzman(the section `Special Functions' in noderef(Functions))\
 ifzman(the section SPECIAL FUNCTIONS in zmanref(zshmisc))
 is not counted for this purpose.
 )
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index b514eb072..583755dc7 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -106,7 +106,7 @@ may be in any order.  Note that this syntax is strict: tt([) and tt(]=) must
 not be quoted, and var(key) may not consist of the unquoted string
 tt(]=), but is otherwise treated as a simple string.  The enhanced forms
 of subscript expression that may be used when directly subscripting a
-variable name, described in the section Array Subscripts below, are not
+variable name, described in the section `Array Subscripts' below, are not
 available.
 
 The syntaxes with and without the explicit key may be mixed.  An implicit
diff --git a/Doc/Zsh/roadmap.yo b/Doc/Zsh/roadmap.yo
index 3f9a122af..2db90889b 100644
--- a/Doc/Zsh/roadmap.yo
+++ b/Doc/Zsh/roadmap.yo
@@ -20,7 +20,7 @@ The function is designed to be self-explanatory.  You can run it by hand
 with `tt(autoload -Uz zsh-newuser-install; zsh-newuser-install -f)'.
 See also
 ifnzman(noderef(User Configuration Functions))\
-ifzman(the section User Configuration Functions in zmanref(zshcontrib)).
+ifzman(the section `User Configuration Functions' in zmanref(zshcontrib)).
 
 
 sect(Interactive Use)
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 6d517b81b..70dfec333 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -50,7 +50,7 @@ argument causes the next command entered to be repeated the specified
 number of times, unless otherwise noted below; this is implemented
 by the tt(digit-argument) widget. See also
 ifzman(the em(Arguments) subsection of the em(Widgets) section )\
-ifnzman(noderef(Arguments) )\
+ifnzman(noderef(Arguments))\
 for some other ways the numeric argument can be modified.
 
 startmenu()


^ permalink raw reply	[relevance 3%]

* Dump of backlogged commits coming
@ 2021-09-06 21:55  3% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2021-09-06 21:55 UTC (permalink / raw)
  To: Zsh hackers list

I finally had several daylight hours with nothing else to do, so here
come 12 commits for patches that I either wrote or indicated that I
would commit on behalf of others (plus a 13th from Marlon that just
came in today).

Here's the ChangeLog entry:

2021-09-06  Bart Schaefer  <schaefer@zsh.org>

        * Stephane Chazelas: 45180: Doc/Zsh/contrib.yo,
        Functions/Example/zpgrep, Functions/Misc/regexp-replace: clarify
        doc for POSIX EREs, fix an issue with PCRE when the replacement
        was empty or generated more than one element

        * zeurkous: 49154: Doc/Zsh/exec.yo: clarify status on exec failure

        * Marlon Richert: 49378: Src/parse.c: skip check for collision
        of aliases and functions when NO_EXEC

        * Marlon Richert: 49292: Src/Zle/complist.c: turn off colors
        before clearing to end of line

        * 49282: set $0 correctly when calling functions from hooks

        * 49266: fix segfault on metacharacters in long job texts

        * Marlon Richert: 49218: Functions/Misc/run-help,
        Functions/Misc/run-help-btrfs, Functions/Misc/run-help-git,
        Functions/Misc/run-help-ip, Functions/Misc/run-help-p4,
        Functions/Misc/run-help-svk, Functions/Misc/run-help-svn:
        run-help filters cmd_args before calling run-help-<command>

        * unposted (cf. 49202 and 49217): Src/Zle/zle_hist.c: insertlastword
        ignores blank/missing history entries when repeating

        * 49196: Src/Modules/db_gdbm.c: gdbm keys not present in the
        database appear unset in tied hashes

        * Marlon Richert: 48969: fix for "zle -N" completion

        * 48888: Doc/Zsh/mod_system.yo, Doc/Zsh/params.yo, Test/E03posix.ztst:
        improve doc for $$ and $PPID, add fail test for PPID readonly-ness

        * 48832: Completion/Unix/Type/_urls: try _gnu_generic first


^ permalink raw reply	[relevance 3%]

* Re: tr [:lower:]
  2021-08-31  1:39  3% ` Phil Pennock
@ 2021-09-01 14:53  0%   ` Shineru
  0 siblings, 0 replies; 200+ results
From: Shineru @ 2021-09-01 14:53 UTC (permalink / raw)
  To: Shineru, zsh-workers

[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]

Thanks!

вт, 31 авг. 2021 г. в 11:39, Phil Pennock <
zsh-workers+phil.pennock@spodhuis.org>:

> On 2021-08-31 at 11:04 +1000, Shineru wrote:
> > zsh 5.8.1. Arch GNU/Linux
> >
> > zsh: echo "hello" | tr [:lower:] [:upper:]
> > zsh: no matches found: [:lower:]
>
> setopt nonomatch
> or:  unsetopt nomatch
> but: both of these are dangerous, because there's a real quoting issue
> here.
>
> % touch l p
> % echo "hello" | tr [:lower:] [:upper:]
> heppo
> bash$ echo "hello" | tr [:lower:] [:upper:]
> heppo
>
> Without quoting,
>   [:lower:] matches any of: l o w e r :
>   [:upper:] matches any of: u p e r :
> so the globbing turns the pipeline into:
>   echo "hello" | tr "l" "p"
>
> By default, zsh complains about unmatched patterns, rather than letting
> them fall through silently.  Falling through leads to this sort of
> "foot-gun" construct, where shells encourage you to do something which
> "only works as long as X is not true", instead of having reliable code.
>
> So you want, for safety, in any shell which resembles POSIX at all:
>
>   echo 'hello' | tr '[:lower:]' '[:upper:]'
>
> (This probably belongs on zsh-users.)
>
> -Phil
>

[-- Attachment #2: Type: text/html, Size: 1694 bytes --]

^ permalink raw reply	[relevance 0%]

* Re: tr [:lower:]
  @ 2021-08-31  1:39  3% ` Phil Pennock
  2021-09-01 14:53  0%   ` Shineru
  0 siblings, 1 reply; 200+ results
From: Phil Pennock @ 2021-08-31  1:39 UTC (permalink / raw)
  To: Shineru; +Cc: zsh-workers

On 2021-08-31 at 11:04 +1000, Shineru wrote:
> zsh 5.8.1. Arch GNU/Linux
> 
> zsh: echo "hello" | tr [:lower:] [:upper:]
> zsh: no matches found: [:lower:]

setopt nonomatch
or:  unsetopt nomatch
but: both of these are dangerous, because there's a real quoting issue
here.

% touch l p
% echo "hello" | tr [:lower:] [:upper:]
heppo
bash$ echo "hello" | tr [:lower:] [:upper:]
heppo

Without quoting,
  [:lower:] matches any of: l o w e r :
  [:upper:] matches any of: u p e r :
so the globbing turns the pipeline into:
  echo "hello" | tr "l" "p"

By default, zsh complains about unmatched patterns, rather than letting
them fall through silently.  Falling through leads to this sort of
"foot-gun" construct, where shells encourage you to do something which
"only works as long as X is not true", instead of having reliable code.

So you want, for safety, in any shell which resembles POSIX at all:

  echo 'hello' | tr '[:lower:]' '[:upper:]'

(This probably belongs on zsh-users.)

-Phil


^ permalink raw reply	[relevance 3%]

* PATCH: completion options update
@ 2021-08-27 12:43  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2021-08-27 12:43 UTC (permalink / raw)
  To: Zsh workers

This patch is an update based on help output diffs. There's more than
usual because I've not updated these for a little while. Lots of files
changed but I've tried to keep this to files that only need relatively
few updates. Sorry if this isn't the easest form for reviews.

Lastest checked versions for affected commands are:

  abcde 2.9.3
  ansible 2.11.1
  attr 2.4.48
  binutils 2.36.1
  btrfs 5.13.1
  cpupower 5.14
  cryptsetup 2.3.6
  dict 1.13.0
  dig 9.16.19
  dkms 2.6.1
  elfutils 0.185
  entr 4.9
  ethtool 5.13
  gem 3.1.6
  getfacl 2.3.1
  gnutls 3.7.2
  gprof 2.36.1
  java - incomplete from version 8
  less 590
  mtr 0.94
  networkmanager 1.30.0
  patchutils 0.4.2
  pigz 2.6
  procps 3.3.17 (pidof/pgrep/pkill)
  ri 6.3.1
  rpm 4.15.1
  ruby 2.7.3p183
  sudo 1.9.7p2
  sysstat 12.4.3
  tmux 3.2a
  util-linux 2.36.2 (findmnt/script/scriptreplay/wipefs)
  unrar 602
  valgrind 3.16.0
  vim 8.2.3081
  w3m 0.5.3
  wget 1.21.1
  wiggle 1.3
  xrandr 1.5.1
  xmlsoft 10134
  xterm 353
  xxd 2020-02-04

Oliver

diff --git Completion/Linux/Command/_btrfs Completion/Linux/Command/_btrfs
index d560928ae..bb0f724e6 100644
--- Completion/Linux/Command/_btrfs
+++ Completion/Linux/Command/_btrfs
@@ -17,11 +17,14 @@ cmds_7=( get set list )
 cmds_8=( enable disable rescan help )
 cmds_9=( assign remove create destroy show limit help )
 cmds_10=( start status cancel help )
-cmds_11=( chunk-recover fix-device-size super-recover zero-log )
+cmds_11=( chunk-recover fix-device-size super-recover zero-log create-control-device )
 
 _arguments -C -A "-*" "$args[@]" \
   '(- *)--help[print help information]' \
   '(- *)--version[print version information]' \
+  '(-v --verbose -q --quiet --help --version)'{-v,--verbose}'[verbose output of operation]' \
+  '(-v --verbose -q --quiet --help --version)'{-q,--quiet}'[suppress all messages except errors]' \
+  '(--help --version)--format=[specify output format]:format:(text json)' \
   '(--version)1: :->groups' \
   '2: :->cmds' \
   '*:: :->args' && ret=0
@@ -60,6 +63,11 @@ while (( $#state )); do
       fi
       args=( '(-)--help[print help information]' )
       case ${cont} in
+        (balance|replace):start|device:(add|delete|remove)|filesystem:resize)
+          args+=(
+            "--enqueue[wait if there's another exclusive operation running, otherwise continue]"
+          )
+        ;|
         subvolume:create)
           args+=(
             '*-i[add the newly created subvolume to a qgroup]:qgroup'
@@ -67,11 +75,10 @@ while (( $#state )); do
           )
         ;;
         subvolume:delete)
-          args+=(
+          args+=( '!-v' '!--verbose'
             '(-c --commit-after -C --commit-each)'{-c,--commit-after}'[wait for transaction commit at the end of the operation]'
             '(-c --commit-after -C --commit-each)'{-C,--commit-each}'[wait for transaction commit after deleting each subvolume]'
             '(-i --subvolid)'{-i+,--subvolid=}'[specify id of subvolume to be removed]:subvolume id'
-            '(-v --verbose)'{-v,--verbose}'[verbose output of operations]'
             '1:subvolume:_files -/'
           )
         ;;
@@ -113,7 +120,7 @@ while (( $#state )); do
         ;|
         subvolume:sync) args+=( '-s[sleep between checks]:delay (seconds) [1]' );;
         subvolume:find-new) args+=( '1:subvol:_files -/' '2:lastgen: _message "last gen"' );;
-        (device|filesystem|qgroup|subvolume):(df|du|show|usage))
+        (device|filesystem|qgroup|subvolume):(df|du|show|usage)|scrub:status)
           args+=(
             '--iec[use 1024 as a base]'
             '--si[use 1000 as a base]'
@@ -130,7 +137,7 @@ while (( $#state )); do
             '(-t --tbytes)'{-t,--tbytes}'[show sizes in TiB, or TB with --si]'
           )
         ;|
-        (filesystem|qgroup):(du|show))
+        (filesystem|qgroup|scrub):(du|show|status))
           args+=(
             '--raw[output raw numbers in bytes]'
             '--human-readable[output human friendly numbers, base 1024]'
@@ -142,8 +149,7 @@ while (( $#state )); do
         ;|
         filesystem:resize) args+=( '1:size:_guard "(|+|-)[0-9]#[GKM]"' '2:path:->mounts' );;
         filesystem:defragment)
-          args+=(
-            '-v[verbose]'
+          args+=( '!-v'
             '-r[defragment files recursively]'
             '-c+[compress files while defragmenting]::compression algorithm:(zlib lzo zstd)'
             '-r[defragment files recursively]'
@@ -193,10 +199,9 @@ while (( $#state )); do
         ;;
         device:ready) args+=( '1:device: _files -g "*(-%)"' );;
         scrub:(start|resume))
-          args+=(
+          args+=( '!-q'
             "-B[don't background and print statistics at end]"
             '-d[print separate statistics for each device]'
-            '-q[omit error message and statistics]'
             '-r[read only mode]'
             '-R[raw print mode]'
             '-c[set ioprio class]:class:(( 0\:none 1\:realtime 2\:best-effort 3\:idle))'
@@ -216,18 +221,17 @@ while (( $#state )); do
           )
         ;;
         balance:start)
-          args+=(
+          args+=( '!-v' '!--verbose'
             '(-m -s)-d+[act on data chunks]:filter:->filters'
             '(-d -s)-m+[act on metadata chunks]:filter:->filters'
             '(-d -m)-s+[act on system chunks (only under -f)]:filters:->filters'
-	    '(-v --verbose)'{-v,--verbose}'[verbose mode]'
             '-f[force a reduction of metadata integrity]'
             "--full-balance[don't print warning and don't delay start]"
             '(--background --bg)'{--background,--bg}'[run balance operation asynchronously in the background]'
             '1:path:_files -/'
           )
         ;;
-        balance:status) args+=( '(-v --verbose)'{-v,--verbose}'[verbose mode]' '1:path:_files -/' );;
+        balance:status) args+=( '!-v' '!--verbose' '1:path:_files -/' );;
         balance:(pause|cancel|resume)) args+=( '1:path:_files -/' );;
         property:set) args+=( '3:value' );&
         property:get) args+=( '2:property:(ro label compression)' );&
@@ -304,6 +308,8 @@ while (( $#state )); do
 	    '!(--dfs)--bfs'
 	    '--dfs[depth-first traversal of the trees]'
             '--hide-names[hide filenames/subvolume/xattrs and other name references]'
+            '--csum-headers[print node checksums stored in headers (metadata)]'
+            '--csum-items[print checksums stored in checksum items (data)]'
           )
         ;;
         inspect*:dump-super)
@@ -315,11 +321,10 @@ while (( $#state )); do
             '--bytenr[specify alternate superblock offset]:offset'
           )
         ;;
-        inspect*:inode*) args+=( '-v[verbose mode]' '1:inode:_files' '2:path:_files -/' );;
-        inspect*:subvol*) args+=( '-v[verbose mode]' '1:subvolid:_guard "[0-9]#" subvolume id' '2:path:_files -/' );;
+        inspect*:inode*) args+=( '!-v' '1:inode:_files' '2:path:_files -/' );;
+        inspect*:subvol*) args+=( '!-v' '1:subvolid:_guard "[0-9]#" subvolume id' '2:path:_files -/' );;
         inspect*:logical*)
-          args+=(
-            '-v[verbose mode]'
+          args+=( '!-v'
             '-P[skip the path resolving and print the inodes instead]'
             '-o[ignore offsets when matching references]'
             '-s[specify buffer size]:buffer size [4096]'
@@ -331,9 +336,8 @@ while (( $#state )); do
         inspect*:rootid) args+=( '1:path:_files -/' );;
         inspect*:tree*) args+=( '-b[print raw numbers in bytes]' );;
         rescue:(chunk|super)-recover)
-          args+=(
+          args+=( '!-v'
             '-y[assume yes to every question]'
-            '-v[verbose mode]'
             '1:device:_files'
           )
           [[ ${${(P)group}[cmd]} == chunk-recover ]] && args+=('(-)-h[display help]')
@@ -361,12 +365,11 @@ while (( $#state )); do
           )
         ;;
         restore)
-          args+=(
+          args+=( '!-v' '!--verbose'
             '(-s --snapshots)'{-s,--snapshots}'[get snapshots]'
             '(-x --xattr)'{-x,--xattr}'[restore extended attributes]'
             '(-m --metadata)'{-m,--metadata}'[restore owner, mode and times]'
             '(-S --symlink)'{-S,--symlink}'[restore symbolic links]'
-            '(-v --verbose)'{-v,--verbose}'[be verbose and output what is restored]'
             '(-i --ignore-errors)'{-i,--ignore-errors}'[ignore errors]'
             '(-o --overwrite)'{-o,--overwrite}'[overwrite directories and files]'
             '-t[specify tree location]:tree root'
@@ -383,23 +386,20 @@ while (( $#state )); do
           )
         ;;
         send|receive)
-          args+=( '(-q --quiet)'{-q,--quiet}'[suppress all messages except errors]' )
+          args+=( '!-q' '!--quiet' )
         ;|
         send)
-          args+=(
-            '*-v[verbose mode]'
+          args+=( '!-v'
             '-e[if sending multiple subvolumes at once, use the new format]'
             '-p[send incremental stream]:parent:_files -/'
             '*-c[use snapshot as clone source]:clone:_files -/'
             '-f[specify output file]:file:_files'
             '--no-data[send in NO_FILE_DATA mode]'
-            '(-v --verbose)'{-v,--verbose}'[enable verbose output]'
             '1:subvolume:_files -/'
           )
         ;;
         receive)
-          args+=(
-            '*-v[verbose mode]'
+          args+=( '!-v'
             '-f[input file]:file: _files'
             '-e[terminate after <end cmd>]'
             '(-C --chroot)'{-C,--chroot}'[confine the process to destination path using chroot(1)]'
diff --git Completion/Linux/Command/_cpupower Completion/Linux/Command/_cpupower
index ae1f1d3d1..6763bdd12 100644
--- Completion/Linux/Command/_cpupower
+++ Completion/Linux/Command/_cpupower
@@ -20,11 +20,12 @@ cmds=(
   'info:show global power parameters'
   'set:set global power parameters'
   'monitor:report frequency and idle statistics'
+  'powercap-info:show powercapping related kernel and hardware configurations'
   'help:print usage information'
 )
 case $state in
   cmds)
-    _describe command cmds && ret=0
+    _describe command cmds -M 'r:|-=* r:|=*' && ret=0
   ;;
   args)
     curcontext="${curcontext%:*}-$words[1]"
diff --git Completion/Linux/Command/_cryptsetup Completion/Linux/Command/_cryptsetup
index 45159d0be..f7149a76f 100644
--- Completion/Linux/Command/_cryptsetup
+++ Completion/Linux/Command/_cryptsetup
@@ -21,6 +21,7 @@ _arguments -s \
   '--new-keyfile-offset=[specify number of bytes to skip in newly added keyfile]:offset (bytes)' \
   '(-S --key-slot)'{-S+,--key-slot=}'[select key slot]:key slot' \
   '(-b --size)'{-b+,--size=}'[force device size]:sectors' \
+  '--device-size=[use only specified device size (ignore rest of device)]:size (bytes)' \
   '(-o --offset)'{-o+,--offset=}'[set start offset]:sectors' \
   '(-p --skip)'{-p+,--skip=}'[data to skip at beginning]:sectors' \
   '(-r --readonly)'{-r,--readonly}'[create a read-only mapping]' \
@@ -44,10 +45,12 @@ _arguments -s \
   '--veracrypt[scan also for VeraCrypt compatible device]' \
   '--veracrypt-pim=[specify personal iteration multiplier for VeraCrypt compatible device]:multiplier' \
   '--veracrypt-query-pim[query personal iteration multiplier for VeraCrypt compatible device]' \
-  '(-M --type)'{-M+,--type=}'[specify type of device metadata]:type:(luks plain loopaes tcrypt)' \
+  '(-M --type)'{-M+,--type=}'[specify type of device metadata]:type:(luks luks1 luks2 plain loopaes tcrypt bitlk)' \
   '--force-password[disable password quality check (if enabled)]' \
   '--perf-same_cpu_crypt[use dm-crypt same_cpu_crypt performance compatibility option]' \
   '--perf-submit_from_crypt_cpus[use dm-crypt submit_from_crypt_cpus performance compatibility option]' \
+  '--perf-no_read_workqueue[bypass dm-crypt workqueue and process read requests synchronously]' \
+  '--perf-no_write_workqueue[bypass dm-crypt workqueue and process write requests synchronously]' \
   '--deferred[device removal is deferred until the last user closes it]' \
   '--serialize-memory-hard-pbkdf[use global lock to serialize memory]' \
   '--pbkdf=[specify PBKDF algorithm for LUKS2]:algorithm:(argon2i argon2id pbkdf2)' \
@@ -60,14 +63,16 @@ _arguments -s \
   '(-I --integrity)'{-I+,--integrity=}'[specify data integrity algorithm (LUKS2 only)]:algorithm' \
   '--integrity-no-journal[disable journal for integrity device]' \
   "--integrity-no-wipe[don't wipe device after format]" \
+  '--integrity-legacy-padding[use inefficient legacy padding (old kernels)]' \
   "--token-only[don't ask for passphrase if activation by token fails]" \
   '--token-id=[specify token number]:number [any]' \
   '--key-description=[specify key description]:description' \
   '--sector-size=[specify encryption sector size]:size [512 bytes]' \
+  '--iv-large-sectors[use IV counted in sector size (not in 512 bytes)]' \
   '--persistent[set activation flags persistent for device]' \
   '--label=[set label for the LUKS2 device]:label' \
   '--subsystem=[set subsystem label for the LUKS2 device]:subsystem' \
-  '--unbound[create unbound (no assigned data segment) LUKS2 keyslot]' \
+  '--unbound[create or dump unbound (no assigned data segment) LUKS2 keyslot]' \
   '--json-file=[read or write token to json file]:json file:_files -g "*.json(-.)"' \
   '--luks2-metadata-size=[specify LUKS2 header metadata area size]:size (bytes)' \
   '--luks2-keyslots-size=[specify LUKS2 header keyslots area size]:size (bytes)' \
@@ -77,12 +82,13 @@ _arguments -s \
   '--encrypt[Encrypt LUKS2 device (in-place encryption)]' \
   '--decrypt[decrypt LUKS2 device (remove encryption)]' \
   '--init-only[initialize LUKS2 reencryption in metadata only]' \
+  '--resume-only[resume initialized LUKS2 reencryption only]' \
   '--reduce-device-size=[reduce data device size (move data offset)]:size (bytes)' \
   '--hotzone-size=[specify maximal reencryption hotzone size]:size (bytes)' \
   '--resilience=[specify reencryption hotzone resilience type]:resilience type:(checksum journal none)' \
   '--resilience-hash=[specify reencryption hotzone checksums hash]:string' \
   '--active-name=[override device autodetection of dm device to be reencrypted]:string' \
-  "${ign}(- : *)--version[show version information]" \
+  "${ign}(- : *)"{-V,--version}'[show version information]' \
   "${ign}(- : *)"{-\?,--help}'[display help information]' \
   "${ign}(- : *)--usage[display brief usage]" \
   ':action:->actions' \
@@ -111,6 +117,7 @@ case $state in
       'isLuks:check if device is a LUKS partition'
       'luksDump:dump header information'
       'tcryptDump:dump TCRYPT device information'
+      'bitlkDump:dump BITLK device information'
       'luksSuspend:suspend LUKS device and wipe key'
       'luksResume:resume suspended LUKS device'
       'luksHeaderBackup:store binary backup of headers'
diff --git Completion/Linux/Command/_dkms Completion/Linux/Command/_dkms
index a0a666e33..2a3c016c5 100644
--- Completion/Linux/Command/_dkms
+++ Completion/Linux/Command/_dkms
@@ -8,6 +8,7 @@ subcmds=(
   'add:add a module/version combination to the tree for builds and installs'
   'remove:remove a module from the tree'
   'build:compile a module for a kernel'
+  'unbuild:undoes the build of a module'
   "install:install a build module for it's corresponding kernel"
   'uninstall:uninstall a module for a kernel'
   'match:install every module that is installed for a template kernel for another kernel'
@@ -17,6 +18,7 @@ subcmds=(
   'mkrpm:create an RPM package for a module'
   'mkdeb:create a debian binary package for a module'
   'mkdsc:create a debian source package for a module'
+  'mkbmdeb:create a debian package containing just binary modules'
   'mkkmp:create a Kernel Module Package source RPM for a module'
   'status:display the current status of modules, versions and kernels within the tree'
   'autoinstall:try to install the latest revision of all modules that have been installed for other kernel revisions'
@@ -32,6 +34,7 @@ args=(
   '--installtree=:path:_directories'
   '--sourcetree=:path:_directories'
   '--dkmsframework=:path:_directories'
+  '--force-version-override'
   '1: : _describe -t commands command subcmds'
 )
 
@@ -44,7 +47,7 @@ else
     '(remove|build|install|uninstall|match|status|mk(^kmp))' 'k' \
     '(add|remove)' '-rpm_safe_upgrade' \
     'mk(driverdisk|kmp)' '-spec' \
-    'mk(deb|dsc|rpm)' '-legacy-postinst' \
+    'mk(deb|dsc|bmdeb|rpm)' '-legacy-postinst' \
     'mk(tarball|rpm|deb|dsc)' '-(source|binary)-only' \
     '(match|build|mkkmp)' '(k|-no-(prepare|clean)-kernel|-kernelsourcedir)' \
     '(|un)install' '-no-(depmod|initrd)' \
@@ -67,7 +70,7 @@ case $cmd in
   remove|build|install|uninstall|mk*|status)
     args+=( ': :->modules' )
   ;|
-  |remove|build|install|uninstall|match|status|mk(^kmp))
+  |remove|(un|)build|install|uninstall|match|status|mk(^kmp))
     args+=( '(--all)*-k[specify kernel version]:kernel:->kernels' )
   ;|
   |add|remove) args+=( "${ign}--rpm_safe_upgrade" ) ;|
@@ -77,7 +80,7 @@ case $cmd in
   |(mk|ld)tarball)
     args+=( "${ign}--archive=:tarball:_files -g '*.tar(-.)'" )
   ;|
-  |mk(deb|dsc|rpm))
+  |mk(deb|dsc|bmdeb|rpm))
     args+=( "${ign}--legacy-postinst=:value [1]:(0 1)" )
   ;|
   |mk(tarball|rpm|deb|dsc)) args+=( "${ign}(--source-only --binaries-only)--"{source,binaries}-only ) ;|
@@ -100,7 +103,7 @@ case $cmd in
       '-c[specify location of dkms.conf file]:location:_files'
     )
   ;|
-  |remove|build|install|status|mk(^kmp))
+  |remove|(un|)build|install|status|mk(^kmp))
     args+=( '(-a --arch -k)--all[specify all relevant kernels/arches]' )
   ;|
   |build)
diff --git Completion/Linux/Command/_ethtool Completion/Linux/Command/_ethtool
index dccda4684..95a8bbfb6 100644
--- Completion/Linux/Command/_ethtool
+++ Completion/Linux/Command/_ethtool
@@ -5,16 +5,21 @@ local -a state line expl cmds
 local -A opt_args
 
 _arguments -C \
+  '--debug[turn on debugging messages]:mask:((1\:parser\ information))' \
+  '--json[output results in JSON]' \
+  '(-I --include-statistics)'{-I,--include-statistics}'[include command-related statistics in the output]' \
+  '(cmds)'{-Q,--per-queue}'[apply per-queue command]: :(queue_mask):queue mask' \
   "1:interface:_net_interfaces" \
-  '*: :->args' \
+  '*:: :->args' \
+  + '(cmdc)' \
+  '(cmds)'{-c,--show-coalesce}'[query the specified ethernet device for coalescing information]' \
+  '(cmds)'{-C,--coalesce}'[change the coalescing settings of the specified ethernet device]' \
   + '(cmds)' \
   '(1)'{-h,--help}'[display help information]' \
   '(1)--version[display version information]' \
   {-s,--change}'[allow changing some or all settings of the specified ethernet device]' \
   {-a,--show-pause}'[query the specified ethernet device for pause parameter information]' \
   {-A,--pause}'[change the pause parameters of the specified ethernet device]' \
-  {-c,--show-coalesce}'[query the specified ethernet device for coalescing information]' \
-  {-C,--coalesce}'[change the coalescing settings of the specified ethernet device]' \
   {-g,--show-ring}'[query the specified ethernet device for RX/TX ring parameter information]' \
   {-G,--set-ring}'[change the RX/TX ring parameters of the specified ethernet device]' \
   {-k,--show-features,--show-offload}'[query the specified ethernet device for offload information]' \
@@ -46,10 +51,21 @@ _arguments -C \
   '--set-eee[set EEE settings]' \
   '--set-phy-tunable[set PHY tunable]' \
   '--get-phy-tunable[get PHY tunable]' \
+  '--get-tunable[get tunable parameters]' \
+  "--set-tunable[set driver's tunable parameters]" \
   '--reset[reset hardware components]' \
   '--show-fec[query device for forward error correction support]' \
   '--set-fec[configure forward error correction for device]' \
-  {-Q,--per-queue}'[apply per-queue command]' && return
+  '--cable-test[perform cable test and report the results]' \
+  '--cable-test-tdr[perform cable test and report Time Domain Reflectometer data]' \
+  '--show-tunnels[show tunnel-related device capabilities and state]' \
+  '--monitor[listen to netlink notifications and displays them]::command:(
+    --all -s --change -k --show-features --show-offload -K
+    --features --offload  --show-priv-flags --set-priv-flags -g --show-ring
+    -G --set-ring -l --show-channels -L --set-channels -c --show-coalesce
+    -C --coalesce -a --show-pause -A --pause --show-eee --set-eee
+    --cable-test --cable-test-tdr
+  )' && return
 
 if [[ -n $state ]]; then
   case $words[CURRENT-1] in
@@ -62,7 +78,8 @@ if [[ -n $state ]]; then
       _wanted onoff expl 'enabled' compadd off on
     fi
   ;;
-  autoneg|adaptive-[rt]x|raw|hex|sg|tso|ufo|gso|lro|eee|tx-lpi|downshift|fast-link-down)
+  autoneg|adaptive-[rt]x|raw|hex|sg|tso|ufo|gso|lro|eee|tx-lpi|downshift) ;&
+  fast-link-down|energy-detect-power-down|mode)
     _wanted onoff expl 'enabled' compadd off on
   ;;
   rx-usecs|rx-frames|rx-usecs-irq|rx-frames-irq|tx-usecs|tx-frames) ;&
@@ -71,6 +88,8 @@ if [[ -n $state ]]; then
   rx-frames-high|tx-usecs-high|tx-frames-high|sample-interval|dmac|rx-mini) ;&
   rx-jumbo|offset|length|magic|value|phyad|proto|tos|tclass|l4proto|src-port) ;&
   dst-port|spi|l4data|vlan-etype|vlan|user-def|action|vf|queue|loc) ;&
+  page|bank|i2c|first|last|step|pair|lanes) ;&
+  rx-copybreak|tx-copybreak|pfc-prevention-tout) ;&
   other|combined|tx-timer|count|msecs)
     _message -e numbers 'number'
   ;;
@@ -81,7 +100,10 @@ if [[ -n $state ]]; then
     _wanted duplex expl 'duplex mode' compadd half full
   ;;
   port)
-    _wanted port expl 'device port' compadd tp aui bnc mii fibre
+    _wanted port expl 'device port' compadd tp aui bnc mii fibre da
+  ;;
+  master-slave)
+    _wanted roles expl role compadd {preferred,forced}-{master,slave}
   ;;
   advertise)
     _values 'hexadecimal value (or a combination of the following)' \
@@ -93,7 +115,8 @@ if [[ -n $state ]]; then
       '0x020[1000 full]' \
       '0x8000[2500 full(not supported by IEEE standards)]' \
       '0x800[10000 full]' \
-      '0x03F[auto]'
+      '0x03F[auto]' \
+      'mode[set mode]'
   ;;
   xcvr)
     _wanted xcvr expl 'transceiver type' compadd internal external
@@ -144,7 +167,7 @@ if [[ -n $state ]]; then
     _message -e contexts 'RSS context'
   ;;
   *)
-    case $words[2] in
+    case ${${(Mk)opt_args:#cmd?*}[1]#cmd?-} in
     -A|--pause)
       _values -S ' ' -w 'pause parameter' \
         'autoneg[specify if pause autonegotiation is enabled]' \
@@ -192,6 +215,9 @@ if [[ -n $state ]]; then
     -p|--identify)
       (( CURRENT = 4 )) && _message -e length 'duration (seconds)'
     ;;
+    -S|--statistics)
+      _arguments '(-)--all-groups' '(-)--groups:eth-phy: :eth-mac: :eth-ctrl: :rmon'
+    ;;
     -t|--test)
       _values -S ' ' -w 'test mode' \
         '(online)offline:perform full set of tests possibly causing normal operation interruption (default)]' \
@@ -202,8 +228,10 @@ if [[ -n $state ]]; then
       if (( ! $words[(I)msglvl] )); then
         _values -S ' ' -w 'generic option' \
           'speed[set speed in Mb/s]' \
+          'lanes[set number of lanes]' \
           'duplex[set full or half duplex mode]' \
           'port[select device port]' \
+          'master-slave[configure interface role]' \
           'autoneg[specify if autonegotiation is enabled]' \
           'advertise[set the speed and duplex advertised by autonegotiation]' \
           'phyad[PHY address]' \
@@ -274,16 +302,23 @@ if [[ -n $state ]]; then
       fi
     ;;
     -m|--dump-module-eeprom|--module-info)
-      _wanted options expl option compadd -F line - raw hex offset length
+      _wanted options expl option compadd -F line - raw hex offset \
+          length page bank i2c
     ;;
     --set-eee)
       _wanted behaviours expl behaviour compadd -F line - eee advertise tx-lpi tx-timer
     ;;
     --set-phy-tunable)
-      _wanted options expl tunable compadd -F line - downshift count fast-link-down msecs
+      _wanted options expl tunable compadd -F line - downshift count \
+	  fast-link-down msecs energy-detect-power-down
     ;;
     --get-phy-tunable)
-      _wanted options expl tunable compadd downshift fast-link-down
+      _wanted options expl tunable compadd downshift fast-link-down \
+	  energy-detect-power-down
+    ;;
+    --[gs]et-tunable)
+      _wanted options expl tunable compadd rx-copybreak tx-copybreak \
+          pfc-prevention-tout
     ;;
     --reset)
       _wanted components expl component compadd flags dedicated all \
@@ -303,6 +338,9 @@ if [[ -n $state ]]; then
         _wanted options expl option compadd -c --show-coalescing -C --coalesce
       fi
     ;;
+    --cable-test-tdr)
+      _wanted options expl 'distance options' compadd first last step pair
+    ;;
     esac
   ;;
   esac
diff --git Completion/Linux/Command/_findmnt Completion/Linux/Command/_findmnt
index 9f13e695f..0c832364d 100644
--- Completion/Linux/Command/_findmnt
+++ Completion/Linux/Command/_findmnt
@@ -22,9 +22,12 @@ _arguments -s -C \
   '(H -M --mountpoint :)'{-M+,--mountpoint=}'[specify the mountpoint]: :->targets' \
   '(H -n --noheadings)'{-n,--noheadings}'[do not print a header line]' \
   '(H -O --options)'{-O+,--options=}'[only print the filesystems with the specified options]:list of options: ' \
-  '(H -o --output)'{-o+,--output=}'[specify output columns]: :->columns' \
+  '(H -o --output --output-all)'{-o+,--output=}'[specify output columns]: :->columns' \
+  '(H -o --output)--output-all[output all available columns]' \
   '(H -p --poll)'{-p+,--poll=}'[monitor changes in /proc/self/mountinfo]::action:(mount umount remount move)' \
+  '(H --real)--pseudo[print only pseudo-filesystems]' \
   '(H -R --submounts)'{-R,--submounts}'[print recursively all submounts]' \
+  '(H --pseudo)--real[print only real filesystems]' \
   '(H -S --source :)'{-S+,--source=}'[specify the mount source]: :->sources' \
   '(H -T --target :)'{-T+,--target=}'[specify the mount target]:target:_files' \
   '(H -t --types)'{-t+,--types=}'[specify the type of filesystems]:filesystem types:_sequence -s , _file_systems' \
@@ -39,7 +42,7 @@ _arguments -s -C \
   '(H)2:: :->targets' \
   + '(format)' \
   '(H)'{-D,--df}'[imitate the output of df command]' \
-  '(H)'{-J,--json}'[use JASON output format]' \
+  '(H)'{-J,--json}'[use JSON output format]' \
   '(H)'{-l,--list}'[use list output format]' \
   '(H)'{-P,--pairs}'[use key="value" output format]' \
   '(H)'{-r,--raw}'[use raw output format]' \
@@ -101,7 +104,7 @@ case $state in
 	'prefixes:prefix:compadd -S "" LABEL= UUID= PARTLABEL= PARTUUID='
       )
       [[ $state = sources_targets ]] &&
-	alts+=( 'mount-points:moutpoint:__findmnt_mountpoints' )
+	alts+=( 'mount-points:mountpoint:__findmnt_mountpoints' )
       _alternative $alts && ret=0
     fi
     ;;
diff --git Completion/Linux/Command/_networkmanager Completion/Linux/Command/_networkmanager
index c9b09d145..1e05252b2 100644
--- Completion/Linux/Command/_networkmanager
+++ Completion/Linux/Command/_networkmanager
@@ -244,7 +244,7 @@ _nm_device_wifi() {
   local curcontext="$curcontext" state line
 
   _arguments -C \
-    "1:command:(list connect hotspot rescan)" \
+    "1:command:(list connect hotspot rescan show-password)" \
     "*::arg:->args"
 
   case $line[1] in
@@ -252,6 +252,7 @@ _nm_device_wifi() {
     c*)  _nm_device_wifi_connect ;;
     ho*) _nm_device_wifi_hotspot ;;
     r*)  _nm_device_wifi_rescan ;;
+    s*)  _nm_device_wifi_show-password ;;
   esac
 }
 
@@ -362,6 +363,12 @@ _nm_device_wifi_rescan() {
     "4:ssid:_nm_device_wifi_ssids"
 }
 
+_nm_device_wifi_show-password() {
+  _arguments \
+    "1: :(ifname)" \
+    "2:interface:_nm_device_ifnames"
+}
+
 _nm_device_wifi_bssids() {
   local -a bssids
   bssids=(${(f)"$(_call_program nmcli nmcli -t -f bssid device wifi list)"})
diff --git Completion/Linux/Command/_pidof Completion/Linux/Command/_pidof
index 05fb23d45..dd0649ce9 100644
--- Completion/Linux/Command/_pidof
+++ Completion/Linux/Command/_pidof
@@ -9,6 +9,8 @@ _arguments -C -s -w \
   '(- *)'{-V,--version}'[print program version]' \
   "(-s --single-shot $exargs)"{-s,--single-shot}'[return one PID only]' \
   "(-c --check-root $exargs)"{-c,--check-root}'[omit processes with different root]' \
+  '-q[quiet mode, only set the exit code]' \
+  '(-w --with-workers)'{-w,--with-workers}'[show kernel workers too]' \
   "(-x $exargs)"-x'[include shells running named scripts]' \
   "($exargs)"\*{-o+,--omit-pid=}'[omit processes with PIDs]:pids:_sequence -s , _pids' \
   '(-S --separator)'{-S+,--separator=}'[specify separator put between PIDs]:separator' \
diff --git Completion/Linux/Command/_sysstat Completion/Linux/Command/_sysstat
index 4de855b69..eba99fc5a 100644
--- Completion/Linux/Command/_sysstat
+++ Completion/Linux/Command/_sysstat
@@ -11,6 +11,7 @@ _mpstat() {
     '--dec=-[specify the number of decimal places to use]:decimal places [2]:(0 1 2)' \
     '-o[display statistics in JSON]:format:(JSON)' \
     '(-A)-P[specify processor number]:processor: _values -s "," processor ALL {0..$(_call_program processors getconf _NPROCESSORS_ONLN)}' \
+    '-T[display topology elements in the CPU report]' \
     '-u[report CPU utilization]' \
     '(- 1 2)-V[display version information]' \
     '1: : _guard "^-*" interval' \
@@ -26,6 +27,7 @@ _cifsiostat() {
     '-t[print timestamp for each report]' \
     '(- 1 2)-V[print version number]' \
     '--human[print sizes in human readable format]' \
+    '--pretty[make the CIFS report easier to read by a human]' \
     '1: : _guard "^-*" interval' \
     '2: : _guard "^-*" count'
 }
@@ -49,7 +51,7 @@ _sadf() {
       '-H[display only the header of the report]' \
       '(-g -j -p -r -x)-h[print on a single line when used with -d]' \
       '-O[specify output options]: : _values -s , option
-        autoscale height\:value oneday packed showidle showinfo skipempty showhints' \
+        autoscale bwcol customcol height\:value oneday packed showidle showinfo showtoc skipempty hz\:value pcparchive\:name\:_files debug' \
       '-P[restrict processor dependant statistics]:processor number(zero indexed) or ALL:(ALL)' \
       '--dev=-[specify block devices for which statistics are to be displayed]:block device:_files -g "*(-%)"' \
       '--fs=-[specify filesystems for which statistics are to be displayed]:file system:_dir_list -s ,' \
@@ -66,6 +68,7 @@ _sadf() {
       '-d[output file in SQL format]' \
       '-g[print data in SVG format]' \
       '-j[output file in JSON]' \
+      '-l[export the contents of the data file to a PCP (Performance Co-Pilot) archive]' \
       '-p[print in format parsable by tools like awk]' \
       '-r[print raw contents of data file]' \
       '-x[output file in XML]' \
@@ -105,7 +108,7 @@ _sar() {
     '-o[save readings to file in binary form]:file:_files' \
     '-P[report per-processor statistics]:processor: _values -s "," processors ALL' \
     '-p[pretty-print device names]' \
-    '-q[report queue length and load averages]' \
+    '-q[report queue length and load averages]::keyword:(CPU IO LOAD MEM PSI ALL)' \
     '-R[report memory statistics]' \
     '-r[report memory utilization statistics]:: :(ALL)' \
     '-S[report swap space utilization]' \
diff --git Completion/Linux/Command/_valgrind Completion/Linux/Command/_valgrind
index 23a8cd734..b4bb3248e 100644
--- Completion/Linux/Command/_valgrind
+++ Completion/Linux/Command/_valgrind
@@ -205,6 +205,7 @@ _arguments -C ${(P)args} $cmd \
   '(--version)--tool=-[specify valgrind tool]:valgrind tool:->tools' \
   '(-h --help)'{-h,--help}'[show help information]' \
   '--help-debug[show help info including debugging options]' \
+  '--help-dyn-options[show the dynamically changeable options]' \
   '(-)--version[show version]' \
   '(-q --quiet)'{-q,--quiet}'[run silently; only print error msgs]' \
   '(-v --verbose)'{-v,--verbose}'[be more verbose]' \
diff --git Completion/Linux/Command/_wipefs Completion/Linux/Command/_wipefs
index 5142def8a..8642aab92 100644
--- Completion/Linux/Command/_wipefs
+++ Completion/Linux/Command/_wipefs
@@ -19,6 +19,7 @@ _arguments -s -S \
   '(H -p --parsable -i --no-headings -J --json)'{-p,--parsable}'[print out in parsable instead of printable format]' \
   '(H -q --quiet)'{-q,--quiet}'[suppress output messages]' \
   '(H -t --types)'{-t+,--types=}'[limit the set of filesystem, RAIDs or partition tables]:type:_file_systems' \
+  '(H)--lock=-[use exclusive device lock]::mode:(yes no nonblock)' \
   '(H)*:disk device:_files -g "*(-%)" -P / -W /' \
   + '(H)' \
   '(- *)'{-h,--help}'[display help information]' \
diff --git Completion/Redhat/Command/_rpm Completion/Redhat/Command/_rpm
index db7c1145d..d00f88429 100644
--- Completion/Redhat/Command/_rpm
+++ Completion/Redhat/Command/_rpm
@@ -129,6 +129,7 @@ _rpm () {
     '--scm=[select the SCM to use with %autosetup]:scm [patch]:(patch gendiff git quilt)'
     '*--buildpolicy=[set buildroot policy]:policy:->brp_policies'
     '!--sign'
+    '--trace[trace macro expansion]'
     "--nodebuginfo[don't generate debuginfo for this package]"
   )
 
diff --git Completion/Unix/Command/_abcde Completion/Unix/Command/_abcde
index 361b43091..3f748d373 100644
--- Completion/Unix/Command/_abcde
+++ Completion/Unix/Command/_abcde
@@ -1,50 +1,41 @@
 #compdef abcde
 
-(( $+functions[_abcde_fields] )) ||
-_abcde_fields(){
-  _values -s , field year genre
-}
-
-(( $+functions[_abcde_actions] )) ||
-_abcde_actions(){
-  _values -s , action cddb cue read getalbumart embedalbumart normalize encode tag move replaygain playlist clean
-}
-
-_arguments -s \
+_arguments -s -S -A "-*" \
   '(-t -T -p)-1[encode the whole CD in a single file]' \
-  '-a[comma-delimited list of actions to perform]:action:_abcde_actions' \
+  '-a[comma-delimited list of actions to perform]:action:_sequence compadd - cddb cue read getalbumart embedalbumart normalize encode tag move replaygain playlist clean' \
   '-b[enable batch mode normalization]' \
   '-B[enable automatic embedding of album art with certain containers]' \
-  '-c[specify an additional configuration file to parse]:config:_files' \
-  '-C[resume a session for discid when you no longer have the CD available]:discid' \
-  '-d[CD-ROM block device that contains audio tracks to be read]:cd-rom-file:_files' \
+  '-c+[specify an additional configuration file to parse]:config:_files' \
+  '-C+[resume a session when read was completed but CD is not present]:disc id:compadd abcde.*(N:e)' \
+  '-d+[specify CD device from which to read audio tracks]:CD device:_files -g "*(-%)" -P / -W /' \
   '-D[capture debugging information]' \
   '-e[erase information about encoded tracks from the internal status file]' \
   '-f[force the removal of the temporary ABCDETEMPDIR directory]' \
   "-g[enable lame's --nogap option]" \
   '-G[download album art using the getalbumart function]' \
   '(- :)-h[get help information]' \
-  '-j[start a specified number of encoder processes at once]:number' \
+  '-j+[start specified number of encoder processes at once]:number' \
   '-k[keep the wav files after encoding]' \
-  '-l[use the low-diskspace algorithm]' \
+  '-l[use the low disk space algorithm]' \
   '-L[use a local CDDB repository]' \
   '-m[create DOS-style playlists, modifying the resulting one by adding CRLF line endings those to work]' \
   "-n[don't query CDDB database]" \
   '-N[non interactive mode]' \
-  '-o[select output type]:outputtype:(vorbis ogg mp3 flac spx mpc m4a wav wv ape opus mka aiff)' \
+  '-o+[select output type]:output type [vorbis]:(vorbis ogg mp3 flac spx mpc m4a wav wv ape opus mka aiff)' \
   "-p[pads track numbers with 0's]" \
   '-P[use Unix PIPES to read and encode in one step]' \
-  '-r[remote encode on this comma-delimited list of machines using distmp3]:hosts:_sequence _hosts' \
-  '-s[fields to be shown in the CDDB parsed entries]:field:_abcde_fields' \
-  '-S[set the speed of the CD drive]:speed' \
-  '-t[start the numbering of the tracks at a given number]:track-number' \
-  '-T[start the numbering of the tracks at a given number and change internal tag numbering]:track-number' \
+  '-Q+[specify CD lookup methods]:lookup method [musicbrainz]:_sequence compadd - musicbrainz cddb cdtext' \
+  '-r+[remote encode on this comma-delimited list of machines using distmp3]:hosts:_sequence _hosts' \
+  '-s+[fields to be shown in the CDDB parsed entries]:field:_sequence compadd - year genre' \
+  '-S+[set the speed of the CD drive]:speed' \
+  '-t+[start the numbering of the tracks at a given number]:track-number' \
+  '-T+[start the numbering of the tracks at a given number and change internal tag numbering]:track-number' \
   '-U[set CDDBPROTO to version 5]' \
   '(- :)-v[show the version and exit]' \
   '-V[be more verbose]' \
   '-x[eject the CD when all tracks have been read]' \
-  '-X[use an alternative "cue2discid" implementation]:cue2discid' \
-  '-w[add a comment to the tracks ripped from the CD]:comment' \
-  "-W[concatenate CD's]:cd-number" \
+  '-X+[use an alternative "cue2discid" implementation]:cue2discid:_command_names -e' \
+  '-w+[add a comment to the tracks ripped from the CD]:comment' \
+  "-W+[concatenate CD's]:cd-number" \
   '-z[debug mode]' \
-  '*:tracks:'
+  '*: :_guard "^-*" "track list"'
diff --git Completion/Unix/Command/_ansible Completion/Unix/Command/_ansible
index 65cae148e..6ec7d0c2e 100644
--- Completion/Unix/Command/_ansible
+++ Completion/Unix/Command/_ansible
@@ -22,6 +22,8 @@ case $service in
     args+=(
       '(-K --ask-become-pass)'{-K,--ask-become-pass}'[ask for privilege escalation password]'
       '(-k --ask-pass)'{-k,--ask-pass}'[ask for connection password]'
+      '--list-hosts[output list of matching hosts]'
+      '(-l --limit)'{-l+,--limit=}'[further limit hosts to an additional pattern]:host subset:->hosts'
       '(-T --timeout)'{-T+,--timeout=}'[override the connection timeout]:timeout (seconds) [10]'
       '(-c --connection)'{-c+,--connection=}'[specify connection type]:connection type [smart]:->connect-types'
       '(-u --user)'{-u+,--user=}'[specify remote user for connection]:remote user:_users'
@@ -47,28 +49,14 @@ case $service in
   ansible|ansible-console|ansible-inventory|ansible-playbook|ansible-pull)
     args+=(
       --ask-vault-pass{,word}'[ask for vault password]'
+      '(-e --extra-vars)'{-e+,--extra-vars=}'[set additional variables]:key=value or YAML/JSON'
       '--vault-id=[specify vault identity to use]:vault identity'
       --vault-pass{,word}-file='[specify vault password file]:vault password file:_files'
-    )
-  ;|
-  ansible|ansible-console|ansible-inventory|ansible-playbook|ansible-pull)
-    args+=(
       \*{-i+,--inventory=}'[specify inventory host file or host list]: : _alternative "files\:inventory file\:_files"
 	"hosts\:host\: _sequence _hosts"'
       '!(-i --inventory)--inventory-file=:inventory file:_files'
     )
   ;|
-  ansible|ansible-console|ansible-playbook|ansible-pull)
-    args+=(
-      '--list-hosts[output list of matching hosts]'
-      '(-l --limit)'{-l+,--limit=}'[further limit hosts to an additional pattern]:host subset:->hosts'
-    )
-  ;|
-  ansible|ansible-playbook|ansible-pull)
-    args+=(
-      '(-e --extra-vars)'{-e+,--extra-vars=}'[set additional variables]:key=value or YAML/JSON'
-    )
-  ;|
   ansible|ansible-console|ansible-inventory)
     args+=(
       '--playbook-dir=[specify substitute playbook directory]:directory:_directories'
@@ -80,11 +68,16 @@ case $service in
       "--skip-tags[only run plays and tasks whose tags don't match]"
     )
   ;|
+  ansible|ansible-console)
+    args+=(
+      '--task-timeout[set the task timeout limit]:timeout (seconds)'
+    )
+  ;|
   ansible)
     args+=(
       '(-a --args)'{-a+,--args=}'[specify command or module arguments]:arguments:->args'
       '(-B --background)'{-B+,--background=}'[run asynchronously, failing after specified time]:fail timeout (seconds)'
-      '(-m --module-name)'{-m+,--module-name=}'[specify module]:module:->plugins'
+      '(-m --module-name)'{-m+,--module-name=}'[specify action to execute]: :->plugins'
       '(-o --one-line)'{-o,--one-line}'[condense output]'
       '(-P --poll)'{-P+,--poll=}'[specify the poll interval if using -B]:interval (seconds) [15]'
       '(-t --tree)'{-t+,--tree=}'[specify directory for log output]:directory:_directories'
@@ -111,11 +104,14 @@ case $service in
   ansible-doc)
     args+=(
       '!--metadata-dump' # "internal testing only"
-      '(-l --list -F --list_files -s --snippet)'{-j,--json}'[change output to json format]'
-      '(-l --list -F --list_files -s --snippet)'{-l,--list}'[list available plugins]'
-      '(-l --list -F --list_files -s --snippet)'{-F,--list_files}'[show plugin names and their source files without summaries]'
-      '(-l --list -F --list_files -s --snippet)'{-s,--snippet}'[show playbook snippet for specified plugins]'
-      '(-t --type)'{-t+,--type=}'[choose plugin type]:plugin type [module]:(become cache callback cliconf connection httpapi inventory lookup netconf shell module strategy vars)'
+      '(-l --list -F --list_files -s --snippet --metadata-dump -e --entry-point)'{-j,--json}'[change output to json format]'
+      '(-l --list -F --list_files -s --snippet --metadata-dump -e --entry-point)'{-l,--list}'[list available plugins]'
+      '(-l --list -F --list_files -s --snippet --metadata-dump -e --entry-point)'{-F,--list_files}'[show plugin names and their source files without summaries]'
+      '(-l --list -F --list_files -s --snippet --metadata-dump -e --entry-point)'{-s,--snippet}'[show playbook snippet for specified plugins]'
+      '(-l --list -F --list_files -s --snippet -e --entry-point)--metadata-dump[dump json metadata for all plugins]'
+      '(-l --list -F --list_files -s --snippet --metadata-dump -e --entry-point)'{-e+,--entry-point=}'[select the entry point for roles]:entry point'
+      '(-t --type)'{-t+,--type=}'[choose plugin type]:plugin type [module]:(become cache callback cliconf connection httpapi inventory lookup netconf shell vars module strategy role keyword)'
+      '(-r --roles-path)'{-r+,--roles-path=}'[specify directory containing roles]:directory:_directories'
       '*:plugin:->plugins'
     )
   ;;
@@ -389,6 +385,7 @@ case $state in
       encrypt_string)
 	args+=(
 	  '(-p --prompt)'{-p,--prompt}'[prompt for the string to encrypt]'
+          "--show-input[don't hide input when prompted for the string to encrypt]"
 	  '(-n --name)'{-n+,--name=}'[specify the variable name]:variable'
 	  '--stdin-name=[specify the variable name for stdin]:variable'
 	)
diff --git Completion/Unix/Command/_attr Completion/Unix/Command/_attr
index 121c0c539..efa7c5c4f 100644
--- Completion/Unix/Command/_attr
+++ Completion/Unix/Command/_attr
@@ -23,6 +23,7 @@ case $service in
       '(-e --encoding)'{-e+,--encoding=}'[encode values after retrieving them]:encoding:(text hex base64)' \
       '(-h --no-dereference)'{-h,--no-dereference}"[don't follow symbolic links]" \
       '(-m --match)'{-m+,--match=}'[only include attributes with names matching regex]:regular expression' \
+      '--one-file-system[skip files on different filesystems]' \
       "--absolute-names[don't strip leading slash characters]" \
       '--only-values[dump only attribute values]' \
       '(-R --recursive)'{-R,--recursive}'[list attributes of all files and directories recursively]' \
diff --git Completion/Unix/Command/_dict Completion/Unix/Command/_dict
index 202fc5bab..928728e06 100644
--- Completion/Unix/Command/_dict
+++ Completion/Unix/Command/_dict
@@ -21,6 +21,8 @@ _arguments -C -S \
   '(--key -k)'{--key=,-k+}'[specify key for authentication]:shared secret:' \
   '(-)'{--version,-V}'[display program version]' \
   '(-)'{--license,-L}'[display program license]' \
+  '(-6)-4[force use of IPv4 addresses only]' \
+  '(-4)-6[force use of IPv6 addresses only]' \
   '(-)--help[display usage info]' \
   '(--verbose -v)'{--verbose,-v}'[verbose output]' \
   '(--raw -r)'{--raw,-r}'[be very verbose]' \
diff --git Completion/Unix/Command/_dig Completion/Unix/Command/_dig
index 5245a2964..3081e2cfd 100644
--- Completion/Unix/Command/_dig
+++ Completion/Unix/Command/_dig
@@ -24,10 +24,12 @@ local -a alts args
   '*+'{no,}'ednsnegotiation[set EDNS version negotiation]'
   '*+ednsopt=[specify EDNS option]:code point'
   '*+noedns[clear EDNS options to be sent]'
+  '*+'{no,}'expandaaaa[expand AAAA records]'
   '*+'{no,}'expire[send an EDNS Expire option]'
   '*+'{no,}'header-only[send query without a question section]'
   '*+'{no,}'idnin[set processing of IDN domain names on input]'
   '*+'{no,}'idnout[set conversion of IDN puny code on output]'
+  '*+'{no,}'keepalive[request EDNS TCP keepalive]'
   '*+'{no,}'keepopen[keep TCP socket open between queries]'
   '*+'{no,}'mapped[allow mapped IPv4 over IPv6 to be used]'
   '*+'{no,}'recurse[set the RD (recursion desired) bit in the query]'
@@ -40,12 +42,15 @@ local -a alts args
   '*+'{no,}'identify[print IP and port of responder]'
   '*+'{no,}'comments[print comment lines in output]'
   '*+'{no,}'stats[print statistics]'
+  '*+padding[set padding block size]:size [0]'
   '*+'{no,}'qr[print query as it was sent]'
   '*+'{no,}'question[print question section of a query]'
+  '*+'{no,}'raflag[set RA flag in the query]'
   '*+'{no,}'answer[print answer section of a reply]'
   '*+'{no,}'authority[print authority section of a reply]'
   '*+'{no,}'all[set all print/display flags]'
   '*+'{no,}'subnet[send EDNS client subnet option]:addr/prefix-length'
+  '*+'{no,}'tcflag[set TC flag in the query]'
   '*+timeout=[set query timeout]:timeout (seconds) [5]'
   '*+tries=[specify number of UDP query attempts]:tries'
   '*+retry=[specify number of UDP query retries]:retries'
@@ -57,13 +62,12 @@ local -a alts args
   '*+'{no,}"fail[don't try next server on SERVFAIL]"
   '*+'{no,}'besteffort[try to parse even malformed messages]'
   '*+'{no,}'dnssec[request DNSSEC records]'
-  '*+'{no,}'sigchase[chase DNSSEC signature chains]'
-  '*+trusted-key=[specify file containing trusted keys]:file:_files'
-  '*+'{no,}'topdown[do DNSSEC validation in top down mode]'
   '*+'{no,}'nsid[include EDNS name server ID request in query]'
   '*+'{no,}'ttlid[display the TTL whening printing the record]'
   '*+'{no,}'ttlunits[display the TTL in human-readable units]'
+  '*+'{no,}'unexpected[print replies from unexpected sources]'
   '*+'{no,}'unknownformat[print RDATA in RFC 3597 "unknown" format]'
+  '*+'{no,}'yaml[present the results as YAML]'
   '*+'{no,}'zflag[set Z flag in query]'
 )
 _arguments -s -C $args \
diff --git Completion/Unix/Command/_entr Completion/Unix/Command/_entr
index 3e2261a18..438ab179a 100644
--- Completion/Unix/Command/_entr
+++ Completion/Unix/Command/_entr
@@ -11,6 +11,7 @@ _arguments -s -S \
   '-p[postpone first execution of the utility]' \
   '(-a)-r[reload a persistent child process]' \
   '(*)-s[evaluate the first argument using interpreter specified by $SHELL]' \
+  '-z[exit after the utility completes]' \
   '(-): :->command' \
   '*::arguments:_normal' && ret=0
 
diff --git Completion/Unix/Command/_gem Completion/Unix/Command/_gem
index 53adfb89c..7e244ccad 100644
--- Completion/Unix/Command/_gem
+++ Completion/Unix/Command/_gem
@@ -196,7 +196,7 @@ if [[ $state = command ]]; then
       )
     ;;
     environment)
-      args+=( '1:information:(packageversion gemdir gempath version remotesources platform)' )
+      args+=( '1:information:(gemdir gempath version remotesources platform)' )
     ;;
     fetch)
       def=( both \! local \! remote \! )
@@ -299,6 +299,9 @@ if [[ $state = command ]]; then
         '*:file:_files'
       )
     ;;
+    yank)
+      args+=( '--otp=[specify code for multifactor authentication]:code' )
+    ;;
   esac
   _arguments -C ${args:-'*: :_default'} \
     '(-)'{-h,--help}'[display usage information]' \
diff --git Completion/Unix/Command/_getfacl Completion/Unix/Command/_getfacl
index 15be06a1c..27b5ee1c8 100644
--- Completion/Unix/Command/_getfacl
+++ Completion/Unix/Command/_getfacl
@@ -22,6 +22,7 @@ _arguments -s -S \
   '(-P --physical)'{-P,--physical}"[physical walk, don't follow symbolic links]" \
   '(-t --tabular)'{-t,--tabular}'[use tabular output format]' \
   '(-n --numeric)'{-n,--numeric}'[print numeric user/group identifiers]' \
+  '--one-file-system[skip files on different filesystems]' \
   '(-p --absolute-names)'{-p,--absolute-names}"[don't strip leading '/' in pathnames]" \
   '(- *)'{-v,--version}'[display version information]' \
   '(- *)'{-h,--help}'[display help information]' \
diff --git Completion/Unix/Command/_gnutls Completion/Unix/Command/_gnutls
index 6c9956b10..b9f91264d 100644
--- Completion/Unix/Command/_gnutls
+++ Completion/Unix/Command/_gnutls
@@ -37,6 +37,8 @@ case "$service" in
       '--x509crlfile=[specify CRL file to use]:file:_files'
       '*--x509keyfile=[specify X.509 key file to use]:file:_files'
       '*--x509certfile=[specify X.509 certificate file to use]:file:_files'
+      '*--rawpkkeyfile=[specify private key file or URL to use]:file:_files'
+      '*--rawpkfile=[specify raw public-key file to use]:file:_files'
       '(-l --list -p --port)'{-l,--list}'[print list of the supported algorithms/modes]'
       '--keymatexport=[specify label used for exporting keying material]:label'
       '--keymatexportsize=[specify size of the exported keying material]:size'
@@ -70,7 +72,8 @@ case "$service" in
       '--fastopen[enable TCP Fast Open]'
       "--print-cert[print peer's certificate in PEM format]"
       "--save-cert=[save peer's certificate chain in the specified file in PEM format]:file:_files"
-      "--save-ocsp=[save peer's OCSP status response in the provided file]:file:_files"
+      "(--save-ocsp-multi)--save-ocsp=[save peer's OCSP status response in the provided file]:file:_files"
+      "(--save-ocsp)--save-ocsp-multi=[save all peer's OCSP responses in the provided file]:file:_files"
       '--save-server-trace=[save the server-side TLS message trace in the provided file]:file:_files'
       '--save-client-trace=[save the client-side TLS message trace in the provided file]:file:_files'
       '--dh-bits=[specify minimum number of bits allowed for DH]:bits'
@@ -93,6 +96,8 @@ case "$service" in
       '--inline-commands-prefix=[change delimiter used for inline commands]:delimiter [^]'
       '--fips140-mode[report status of FIPS140-2 mode in gnutls library]'
       '--logfile=[redirect informational messages to a specific file]:file:_files'
+      '--waitresumption[block waiting for the resumption data under TLS1.3]'
+      '--ca-auto-retrieve[enable automatic retrieval of missing CA certificates]'
     )
   ;;
 
@@ -109,6 +114,7 @@ case "$service" in
       "--nodb[don't use a resumption database]"
       '--http[act as an HTTP server]'
       '--echo[act as an Echo server]'
+      "--crlf[don't replace CRLF by LF in Echo server mode]"
       '(-a --disable-client-cert -r --require-client-cert)'{-a,--disable-client-cert}"[don't request a client certificate]"
       '(-a --disable-client-cert -r --require-client-cert)'{-r,--require-client-cert}'[require a client certificate]'
       '--verify-client-cert[if a client certificate is sent then verify it]'
@@ -144,7 +150,8 @@ case "$service" in
       '--verify-crl[verify a CRL]'
       '(--verify-email)--verify-hostname=[specify hostname to be used for certificate chain verification]:hostname:_hosts'
       '(--verify-hostname)--verify-email=[specify email to be used for certificate chain verification]:email:_email_addresses'
-      '--verify-purpose=[specify a purpose OID to be used for certificate chain verification]'
+      '--verify-purpose=[specify a purpose OID to be used for certificate chain verification]:purpose'
+      '--verify-profile=[specify a security level profile to be used for verification]:profile'
       '--p7-sign[sign using a PKCS #7 structure]'
       '--p7-detached-sign[sign using a detached PKCS #7 structure]'
       "--no-p7-include-cert[don't include signer's certificate will in the cert list]"
diff --git Completion/Unix/Command/_gprof Completion/Unix/Command/_gprof
index 3bb7a5765..a7e602fd5 100644
--- Completion/Unix/Command/_gprof
+++ Completion/Unix/Command/_gprof
@@ -3,8 +3,8 @@
 local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_arguments -C -s -{a,b,c,D,h,i,l,L,s,T,v,w,x,y,z} \
-           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,Z}:'function name:->funcs' \
+_arguments -C -s -{a,b,c,D,h,i,l,L,r,s,T,v,w,x,y,z} \
+           -{A,C,e,E,f,F,J,n,N,O,p,P,q,Q,R,S,t,Z}:'function name:->funcs' \
 	   '-I:directory:_dir_list' \
 	   '-d-:debug level:' '-k:function names:->pair' \
 	   '-m:minimum execution count:' \
diff --git Completion/Unix/Command/_gzip Completion/Unix/Command/_gzip
index 42d4ae705..8354b34d4 100644
--- Completion/Unix/Command/_gzip
+++ Completion/Unix/Command/_gzip
@@ -9,10 +9,14 @@ files=( '*:files:->files' )
 case "$service" in
 unpigz|pigz)
   pigz=(
-    '(-K --zip)'{-K,--zip}'[compress to PKWare zip format]'
+    '(-A --alias)'{-A+,--alias=}'[specify filename to use in zip entry for stdin]:filename'
+    '(-C --comment)'{-C+,--comment=}'[put specified comment in the gzip or zip header]'
+    '(-H --huffman -U --rle)'{-H,--huffman}'[use only Huffman coding for compression]'
+    '(-U --rle -H --huffman)'{-U,--rle}'[use run-length encoding for compression]'
+    '(-K --zip -z --zlib)'{-K,--zip}'[compress to PKWare zip format]'
     '(-b --blocksize)'{-b+,--blocksize}'[set compression block size]:size (KiB)'
     '(-p --processes)'{-p,--processes}'[specify number of processes to use]'
-    '(-z --zlib)'{-z,--zlib}'[compress to zlib (.zz) format]'
+    '(-z --zlib -K --zip)'{-z,--zlib}'[compress to zlib (.zz) format]'
     '(-m --no-time)'{-m,--no-time}"[don't store/restore modification time in/from header]"
     '(-M --time)'{-M,--time}"[store/restore modification time in/from header]"
     '(--synchronous)-Y[force output file write to permanent storage]'
diff --git Completion/Unix/Command/_iostat Completion/Unix/Command/_iostat
index f5291a19b..1152b0d8b 100644
--- Completion/Unix/Command/_iostat
+++ Completion/Unix/Command/_iostat
@@ -128,10 +128,13 @@ case $OSTYPE:l in
       '-c[display CPU utilization report]'
       '-d[display device utilization report]'
       '--dec=-[specify the number of decimal places to use]:decimal places [2]:(0 1 2)'
+      '-f[specify alternative directory to read device statistics from]:directory:_directories'
+      '+f[specify additional directory to read device statistics from]:directory:_directories'
       '*-g[display statistics for a group of devices]:group name'
       '-H[only display global statistics for group]'
       '(--human)-h[human readable device utilization report]'
       '--human[print sizes in human readable format]'
+      '--pretty[make report easier to read by a human]'
       '-j[display persistent device name]:name type:(ID LABEL PATH UUID)'
       '(-m)-k[display statistics in kB/s]'
       '(-k)-m[display statistics in MB/s]'
diff --git Completion/Unix/Command/_java Completion/Unix/Command/_java
index ee0441d97..ff6e82645 100644
--- Completion/Unix/Command/_java
+++ Completion/Unix/Command/_java
@@ -24,18 +24,24 @@ javac)
     '(-cp -classpath)'{-cp,-classpath}'[specify where to find user class files]:class path:->classpath' \
     '-sourcepath[specify where to find input source files]:source path:->sourcepath' \
     '-bootclasspath[override location of bootstrap class files]:bootstrap class path:->bootstrapclasspath' \
+    '-endorseddirs[override location of endorsed standards path]:path:->extdirs' \
     '-extdirs[override location of installed extensions]:extensions directories:->extdirs' \
     '-d[specify where to place generated class files]:directory:_files -/' \
     '-encoding[specify character encoding used by source files]:encoding:->encoding' \
     '-proc\:-[control annotation processing]:annotation processing:(none only)' \
     '-processor[specify annotation processors to run]:class:_files' \
     '-processorpath[specify where to find annotation processors]:directory:_directories' \
+    '-parameters[generate metadata for reflection on method parameters]' \
     '-s[specify directory for generated source files]:directory:_directories' \
+    '-h[specify where to place generated native header files]:directory:_directories' \
     '-source[provide source compatibility with specified release]:release:(1.{2..8} {5..8})' \
     '-target[specify VM version]:release:(1.{1..5})' \
+    '-profile[check that API used is available in the specified profile]:profile' \
     '(-)-help[print a synopsis of standard options]' \
     '(-)-version[print version information]' \
     '(-)-X[display information about non-standard options]' \
+    '-J-[pass flag directly to the runtime system]:flag' \
+    '-Werror[terminate compilation if warnings occur]' \
     '*:java source file:_files -g \*.java\(-.\)' && return 0
   ;;
 
@@ -75,6 +81,7 @@ java)
     '(- 1)-'{\?,help}'[print help message]' \
     '(- 1)-X-[non-standard java option]:option' \
     '(- 1)-jar[specify a program encapsulated as jar]:jar:_files -g \*.jar\(-.\)' \
+    '-splash\:-[show splash screen with specified image]:image:_files' \
     '(-):class:_java_class -m main ${(kv)opt_args[(i)(-classpath|-cp)]}' \
     '*::args:= _normal' \
      && return 0
@@ -90,15 +97,20 @@ javadoc)
     '-help[print help message]' \
     '-doclet[specify a doclet]:doclet:_java_class -t doclet ${(kv)opt_args[(i)-classpath]}' \
     '-docletpath[specify a path to search doclet]:doclet path:->docletpath' \
-    '-1.1[Javadoc 1.1 compatible output]' \
     '-sourcepath[specify path for source files]:source path:->sourcepath' \
-    '-classpath[specify path for user class files]:class path:->classpath' \
+    {-cp,-classpath}'[specify path for user class files]:class path:->classpath' \
+    '-exclude[specify a list of packages to exclude]:package list' \
+    '-subpackages[specify subpackages to recursively load]:subpackage list' \
+    '-breakiterator[compute first sentence with BreakIterator]' \
     '-bootclasspath[specify path for bootstrap class files]:bootstrap class path:->bootstrapclasspath' \
+    '-source[provide source compatibility with specified release]:release' \
     '-extdirs[specify directories for extensions]:extensions directories:->extdirs' \
     '-verbose[print verbose messages]' \
     '-locale[specify locale]:language_country_variant:' \
     '-encoding[specify character encoding for source files]:encoding:->encoding' \
+    "-quiet[don't display status messages]" \
     '-J-[specify java option]:java option:' \
+    '-X[print a synopsis of nonstandard options and exit]' \
     '-d[specify destination directory]:destination directory:_files -/' \
     '-use[display pages for use]' \
     '-version[include @version text]' \
@@ -111,15 +123,27 @@ javadoc)
     '-bottom[specify bottom text]:bottom text:' \
     '-link[generate a link to external reference classes]:document URL:' \
     '-linkoffline[generate a link for external reference class names]:document URL::package list URL:' \
+    '-excludedocfilessubdir[exclude any doc-files subdirectories with given name]:name:_directories' \
     '-group[generate tables for each group]:group heading::package patterns:' \
-    '-nodeprecated[do not document deprecated API]' \
-    '-nodeprecatedlist[do not generate deprecated API list]' \
-    '-notree[do not generate class and interface hierarchy]' \
-    '-noindex[do not generate index]' \
-    '-nohelp[do not generate help link]' \
-    '-nonavbar[do not generate navigation bar]' \
+    "-nodeprecated[don't include @deprecated information]" \
+    '-noqualifier[exclude the list of qualifiers from the output]:qualifier list' \
+    "-nosince[don't include @since information]" \
+    "-notimestamp[don't include hidden time stamp]" \
+    "-nodeprecatedlist[don't generate deprecated API list]" \
+    "-notree[don't generate class and interface hierarchy]" \
+    "-noindex[don't generate index]" \
+    "-nohelp[don't generate help link]" \
+    "-nonavbar[don't generate navigation bar]" \
+    '-serialwarn[generate warning about @serial tag]' \
+    '*-tag[specify single argument custom tag]:tag' \
+    '-taglet[specify fully qualified name of Taglet to register]:taglet' \
+    '-tagletpath[specify path to Taglets]:path:_directories' \
+    '-charset[specify charset of generated documentation]:charset:->encoding' \
     '-helpfile[specify alternative help link]:helpfile path/filename:' \
-    '-stylesheet[specify alternative HTML style sheet]:stylesheet path/filename:' \
+    '-linksource[generate source in HTML]' \
+    '-sourcetab[specify the number of spaces each tab takes up in the source]:spaces' \
+    '-keywords[include HTML meta tags with package, class and member info]' \
+    '-stylesheetfile[specify alternative HTML style sheet]:stylesheet path/filename:_directories' \
     '-docencoding[specify character encoding for output HTML files]:encoding:->encoding' \
     '*:package name, source file or @list:->docsrc' && ret=0
   ;;
@@ -143,9 +167,11 @@ jar)
       'f[specify archive file]' \
       'v[verbose mode]' \
       '(e)m[specify manifest file]' \
+      'n[perform Pack200 normalization after creating a new archive]' \
       '(m)e[specify class of for application entry point]' \
       '0[store only without using ZIP compression]' \
-      'M[do not create manifest file]' \
+      "M[don't create manifest file]" \
+      "P[preserve leading / and .. components on file names]" \
       'i[generate index information for specified jar files]' && return
   else
     jar_cmd="${words[2]#-}"
@@ -171,7 +197,7 @@ javah|javah_g)
     '-help[print help message]' \
     '-version[print version]' \
     '-jni[JNI-style native method function prototypes]' \
-    '-classpath[specify path for user class files]:class path:->classpath' \
+    {-cp,-classpath}'[specify path for user class files]:class path:->classpath' \
     '-bootclasspath[specify path for bootstrap class files]:bootstrap class path:->bootstrapclasspath' \
     '-old[generate old JDK1.0-style header files]' \
     '-force[force output]' \
@@ -182,17 +208,19 @@ javah|javah_g)
 javap)
   _arguments -C \
     '-help[print help message]' \
+    '-version[print version information]' \
+    {-v,-verbose}'[print additional information]' \
     '-l[line and local variable tables]' \
-    '-b[backward compatible to JDK1.1]' \
-    '-public[only public classes and members]' \
-    '-protected[only protected and public classes and members]' \
-    '-package[only package, protected and public classes and members (default)]' \
-    '-private[all classes and members]' \
+    '(-protected -package -p -private)-public[show only public classes and members]' \
+    '(-public -package -p -private)-protected[show only protected/public classes and members]' \
+    '(-public -protected -p -private)-package[show only package/protected/public classes and members (default)]' \
+    '(-public -package -protected -p -private)'{-p,-private}'[show all classes and members]' \
     '-J-[specify java option]:java option:' \
-    '-s[internal type signatures]' \
     '-c[disassemble code]' \
-    '-verbose[stack size, number of locals and args for methods]' \
-    '-classpath[specify path for user class files]:class path:->classpath' \
+    '-s[print internal type signatures]' \
+    '-sysinfo[show system info (path, size, date, MD5 hash) of class being processed]' \
+    '-constants[show final constants]' \
+    {-cp,-classpath}'[specify path for user class files]:class path:->classpath' \
     '-bootclasspath[specify path for bootstrap class files]:bootstrap class path:->bootstrapclasspath' \
     '-extdirs[specify directories for extensions]:extensions directories:->extdirs' \
     '*:class:_java_class ${(kv)opt_args[(i)-classpath]}' && return 0
diff --git Completion/Unix/Command/_less Completion/Unix/Command/_less
index cb71314a6..0b474b991 100644
--- Completion/Unix/Command/_less
+++ Completion/Unix/Command/_less
@@ -1,7 +1,7 @@
 #compdef less -value-,LESS,-default- -value-,LESSCHARSET,-default-
 
-local curcontext="$curcontext" state line expl ret=1
-local -a files
+local curcontext="$curcontext" fgbg=foreground ret=1
+local -a state line expl files basic suf
 
 case $service in
   *LESSCHARSET*)
@@ -37,15 +37,15 @@ _arguments -S -s -A "[-+]*"  \
   '(-b --buffers)'{-b+,--buffers=}'[specify amount of buffer space used for each file]:buffer space (kilobytes)' \
   '(-B --auto-buffers)'{-B,--auto-buffers}"[don't automatically allocate buffers for pipes]" \
   '(-C --CLEAR-SCREEN -c --clear-screen)'{-c,--clear-screen}'[repaint screen instead of scrolling]' \
-  '(-c --clear-screen -C --CLEAR-SCREEN)'{-C,--CLEAR-SCREEN}'[clear screen before repaints]' \
+  '!(-c --clear-screen)'{-C,--CLEAR-SCREEN} \
   '(-d --dumb)'{-d,--dumb}'[suppress error message if terminal is dumb]' \
+  '*-D+[set screen colors]: :->colors' \
   '(-e -E --quit-at-eof --QUIT-AT-EOF)'{-e,--quit-at-eof}'[exit the second time end-of-file is reached]' \
   '(-e -E --quit-at-eof --QUIT-AT-EOF)'{-E,--QUIT-AT-EOF}'[exit when end-of-file is reached]' \
   '(-f --force)'{-f,--force}'[force opening of non-regular files]' \
   '(-F --quit-if-one-screen)'{-F,--quit-if-one-screen}'[exit if entire file fits on first screen]' \
   '(-G --HILITE-SEARCH -g --hilite-search)'{-g,--hilite-search}'[highlight only one match for searches]' \
   '(-g --hilite-search -G --HILITE-SEARCH)'{-G,--HILITE-SEARCH}'[disable highlighting of search matches]' \
-  '--old-bot[revert to the old bottom of screen behavior]' \
   '(-h --max-back-scroll)'{-h+,--max-back-scroll=}'[specify backward scroll limit]:backward scroll limit (lines)' \
   '(-I --IGNORE-CASE -i --ignore-case)'{-i,--ignore-case}'[ignore case in searches that lack uppercase]' \
   '(-i --ignore-case -I --IGNORE-CASE)'{-I,--IGNORE-CASE}'[ignore case in all searches]' \
@@ -83,18 +83,49 @@ _arguments -S -s -A "[-+]*"  \
   '(-\" --quotes)'{-\"+,--quotes=}'[change quoting character]:quoting characters' \
   '(-~ --tilde)'{-~,--tilde}"[don't display tildes after end of file]" \
   '(-\# --shift)'{-\#+,--shift=}"[specify amount to move when scrolling horizontally]:number" \
+  '--file-size[automatically determine the size of the input file]' \
+  '--incsearch[search file as each pattern character is typed in]' \
+  '--line-num-width=[set the width of line number field]:width [7]' \
   '--follow-name[the F command changes file if the input file is renamed]' \
   '--mouse[enable mouse input]' \
   '--no-histdups[remove duplicates from command history]' \
   '--rscroll=[set the character used to mark truncated lines]:character [>]' \
   '--save-marks[retain marks across invocations of less]' \
+  '--status-col-width=[set the width of the -J status column]:width [2]' \
   '--use-backslash[subsequent options use backslash as escape char]' \
+  '--use-color[enable colored text]' \
   '--wheel-lines=[specify lines to move for each click of the mouse wheel]:lines' \
   "$files[@]" && ret=0
 
 
 if [[ -n "$state" ]]; then
   case $state in
+    colors)
+      if compset -P 1 \?; then
+        [[ $IPREFIX[-1] != [a-z] ]] || compset -P 1 + || _describe 'color application' '( +:add\ to\ existing\ attribute )'
+        suf=( -S '' )
+        compset -P 1 '([a-zA-Z]|*.)' && fgbg=background && suf=()
+        basic=( B:blue C:cyan G:green K:black M:magenta R:red W:white Y:yellow )
+        _describe -t colors "$fgbg color" \
+            "( -:default ${(j. .)${(@)basic/:/:light\ }} ${(Lj. .)basic} )" "$suf[@]"  && ret=0
+      else
+        _describe 'text' '(
+          B:binary\ characters
+          C:control\ characters
+          E:errors\ and\ informational\ messages
+          M:mark\ letters\ in\ the\ status\ column
+          N:line\ numbers\ enabled\ via\ the\ -N\ option
+          P:prompts
+          R:the\ rscroll\ character
+          S:search\ results
+          W:the\ highlight\ enabled\ via\ the\ -w\ option
+          d:bold\ text
+          k:blinking\ text
+          s:standout\ text
+          u:underlined\ text
+        )' -S '' && ret=0
+      fi
+    ;;
     prompts)
       if compset -p 1; then
 	_message -e prompt
diff --git Completion/Unix/Command/_mtr Completion/Unix/Command/_mtr
index 806e344d1..9a73cfbd4 100644
--- Completion/Unix/Command/_mtr
+++ Completion/Unix/Command/_mtr
@@ -4,6 +4,7 @@ _arguments -s -S \
   '(H -F --filename)'{-F,--filename}'[read hostnames from a file]' \
   '(H -6)-4[use IPv4 only]' \
   '(H -4)-6[use IPv6 only]' \
+  '(H -I --interface)'{-I+,--interface=}'[use named network interface]: :_net_interfaces' \
   '(H -a --address)'{-a+,--address=}'[bind outgoing packets to specific interface]:source IP:_hosts' \
   '(H -f --first-ttl)'{-f+,--first-ttl=}'[specify TTL to start]:TTL [1]' \
   '(H -m --max-ttl)'{-m+,--max-ttl=}'[specify maximum number of hops to probe]:hops [30]' \
@@ -17,7 +18,6 @@ _arguments -s -S \
   '(H -Q --tos)'{-Q+,--tos=}'[specify type of service for IP header]:tos (0-255)' \
   '(H -e --mpls)'{-e,--mpls}'[display ICMP MPLS information]' \
   '(H -Z --timeout)'{-Z+,--timeout=}'[specify how long to keep probe sockets open before giving up on the connection]:timeout (seconds)' \
-  '(H -M --mark)'{-M+,--mark=}'[mark each sent packet]:mark' \
   '(H -r --report)'{-r,--report}'[report mode]' \
   '(H -w --report-wide)'{-w,--report-wide}"[wide report mode\: don't truncate hostnames]" \
   '(H -c --report-cycles)'{-c+,--report-cycles=}'[report cycles]:number of pings' \
diff --git Completion/Unix/Command/_nm Completion/Unix/Command/_nm
index 2f608c5fc..79f537ac6 100644
--- Completion/Unix/Command/_nm
+++ Completion/Unix/Command/_nm
@@ -62,7 +62,8 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
         '!(--no-recurse-limit)--recurse-limit'
         '--no-recurse-limit[disable demangling recursion limit]'
 	'(-f --format -P)-f+[specify output format]:format:(bsd sysv posix)'
-	'(-C --no-demangle)--demangle=-[decode symbol names]::style:(auto gnu lucid arm hp edg gnu-v3 java gnat rust dlang)'
+	'(-C --no-demangle)--demangle=-[decode symbol names]::style [auto]:(auto gnu lucid arm hp edg gnu-v3 java gnat rust dlang)'
+        '--ifunc-chars=[specify characters to use for indirect function symbols]:characters for global/local indirect function symbols [ii]'
 	'--plugin[load specified plugin]:plugin'
 	'--special-syms[include special symbols in the output]'
 	'--synthetic[display synthetic symbols as well]'
diff --git Completion/Unix/Command/_objdump Completion/Unix/Command/_objdump
index 5152e6b6e..e2dde7e4c 100644
--- Completion/Unix/Command/_objdump
+++ Completion/Unix/Command/_objdump
@@ -67,7 +67,8 @@ case $variant in
       '(-z --disassemble-zeroes)'{-z,--disassemble-zeroes}"[don't skip blocks of zeroes when disassembling]"
 
       '--start-address=[only process data whose address is >= ADDR]:address'
-      '--stop-address=[only process data whose address is <= ADDR]:address'
+      '--stop-address=[only process data whose address is < ADDR]:address'
+      "--no-addresses[don't print address alongside disassembly]"
       '--prefix-addresses[print complete address alongside disassembly]'
       '(--show-raw-insn --no-show-raw-insn)'--{,no-}show-raw-insn'[display hex alongside symbolic disassembly]'
       '--insn-width=[display specified number of bytes on a single line with -d]:width (bytes)'
@@ -80,6 +81,7 @@ case $variant in
       '--dwarf-start=[display DIEs at specified or deeper depth]:depth'
       '--dwarf-check[perform additional dwarf internal consistency checks]'
       '--ctf-parent=[use specified section as the CTF parent]:section'
+      '--visualize-jumps=-[visualize jumps by drawing ASCII art lines]::color:(color extended-color off)'
     )
   ;;
   elfutils)
@@ -165,6 +167,7 @@ case "$state" in
     _values -s "" "dwarf section" \
         "l[rawline]" "L[decodedline]" "i[info]" "a[abbrev]" "p[pubnames]" \
         "r[aranges]" "m[macro]" "f[frames]" "F[frames-interp]" "s[str]" \
+        'O[str-offsets]' \
         "o[loc]" "R[ranges]" "t[pubtypes]" "U[trace_info]" "u[trace_abbrev]" \
         "T[trace_aranges]" "g[gdb_index]" "A[addr]" "c[cu_index]" "k[links]" \
         "K[follow-links]" && ret=0
@@ -172,7 +175,7 @@ case "$state" in
   dwarf-names)
     _sequence _wanted dwarf-sections expl "dwarf section" compadd - \
         rawline decodedline info abbrev pubnames aranges macro frames \
-        frames-interp str loc Ranges pubtypes gdb_index trace_info \
+        frames-interp str str-offsets loc Ranges pubtypes gdb_index trace_info \
         trace_abbrev trace_aranges addr cu_index links follow-links && ret=0
   ;;
   bfdnames)
diff --git Completion/Unix/Command/_patchutils Completion/Unix/Command/_patchutils
index 50ea3e4c4..a5f6441b1 100644
--- Completion/Unix/Command/_patchutils
+++ Completion/Unix/Command/_patchutils
@@ -85,6 +85,7 @@ case $service in
       '(-H --with-filename -h --no-filename)'{-h,--no-filename}"[don't print the name of the patch file containing each patch]"
       '(-f --file)'{-f+,--file=}'[read regular expressions from file]:file:_files'
       '--output-matching=[display the matching hunk- or file-level diffs]:level:(hunk file)'
+      '--only-match=[restrict regex to matching removals, additions or modifications]:limit:(rem removals add additions mod modifications all)'
     )
   ;;
   splitdiff)
diff --git Completion/Unix/Command/_pgrep Completion/Unix/Command/_pgrep
index 38b1aebd8..afd2fe54b 100644
--- Completion/Unix/Command/_pgrep
+++ Completion/Unix/Command/_pgrep
@@ -31,6 +31,7 @@ arguments=(
   '(-M)-N+[extract name list from specified system]:system file:_files'
   '(-o -n --oldest --newest)'{-n,--newest}'[match newest process]'
   '(-o -n --oldest --newest)'{-o,--oldest}'[match oldest process]'
+  '(-O --older)'{-O+,--older=}'[select where older than specified age]:age (seconds)'
   '(-P --parent)'{-P+,--parent=}'[match only on specified parent process IDs]: :->ppid'
   '(-l)-q[suppress normal output]'
   '(-r --runstates)'{-r+,--runstates}'[match runstates]:run state:compadd -S "" D I R S T t W X Z'
@@ -62,8 +63,8 @@ arguments=(
 case $OSTYPE in
   linux*)
     # Note: We deliberately exclude -v but not --inverse from pkill
-    pgopts=acdFfGghLlnoPrstUuVvwx-
-    pkopts=ceFfGghLnoPstUuVx-
+    pgopts=acdFfGghLlnoOPrstUuVvwx-
+    pkopts=ceFfGghLnoOPstUuVx-
     arguments=(
       ${arguments:#((#s)|*\))(\*|)-[acl]*}
       '(-c --count)'{-c,--count}'[display count of matching processes]'
diff --git Completion/Unix/Command/_rar Completion/Unix/Command/_rar
index 68982be60..d1d381974 100644
--- Completion/Unix/Command/_rar
+++ Completion/Unix/Command/_rar
@@ -4,6 +4,8 @@ local common expl
 
 common=(
   '-ad[append archive name to destination path]'
+  '-ad1[create a separate folder for files unpacked from each archive]'
+  "-ad2[like -ad1 but use archives' own folders]"
   '-ap[set path inside archive]'
   '-av\-[disable authenticity verification check]'
   '-c\-[disable comments show]'
@@ -13,6 +15,7 @@ common=(
   '-dh[open shared files]'
   '-ep[exclude paths from name]'
   '-f[freshen files]'
+  '-idn[hide archived names]'
   '-idp[disable percentage display]'
   '-ierr[send all messages to stderr]'
   '-inul[disable all messages]'
@@ -27,6 +30,7 @@ common=(
   '-tb+[process files modified before a date]:date (YYYYMMDDHHMMSS)'
   '-tn+[process files newer than a specified time]:time'
   '-to+[process files older than a specified time]:time'
+  '-ts-[save or restore time]:time:((m\:modification c\:change a\:access p\:preserve))'
   '-u[update files]'
   '-v[create volumes with size autodetection or list all volumes]'
   '-ver[file version control]'
diff --git Completion/Unix/Command/_readelf Completion/Unix/Command/_readelf
index edabc3da1..fc0fb7ce1 100644
--- Completion/Unix/Command/_readelf
+++ Completion/Unix/Command/_readelf
@@ -18,7 +18,7 @@ args=(
   '(-c --archive-index)'{-c,--archive-index}'[show symbol/file index in an archive]'
   \*{-x,--hex-dump=}"[dump contents of specified section as bytes]:section:($sections)"
   \*{-p,--string-dump=}"[dump contents of specified section as strings]:section:($sections)"
-  '-w+[show the contents of DWARF2 debug sections]::debug section:(l L i a p r m f F s o R t U u T g A c k K)'
+  '-w+[show the contents of DWARF2 debug sections]::debug section:(l L i a p r m f F s o O R t U u T g A c k K)'
   '--debug-dump=[show the contents of DWARF2 debug sections]::section:(rawline decodedline info abbrev pubnames aranges macro frames frames-interp str loc Ranges pubtypes gdb_index trace_info trace_abbrev trace_aranges addr cu_index links follow-links)'
   '(-I --histogram)'{-I,--histogram}'[show histogram of bucket list lengths]'
   '(-W --wide)'{-W,--wide}'[allow output width to exceed 80 characters]'
@@ -50,6 +50,12 @@ case $variant in
   ;|
   binutils)
     args+=(
+      '!(-C --demangle)--no-demangle'
+      '(--demangle)-C[decode symbol names]'
+      '(-C)--demangle=-[decode symbol names]::style [auto]:(auto gnu lucid arm hp edg gnu-v3 java gnat)'
+      '!(--no-recurse-limit)--recurse-limit'
+      '--no-recurse-limit[disable demangling recursion limit]'
+      '(-L --lint --enable-checks)'{-L,--lint,--enable-checks}'[display warning messages for possible problems]'
       \*{-R,--relocated-dump=}"[dump contents of specified section as relocated bytes]:section:($sections)"
       "--dwarf-depth=[don't show DIEs at greater than specified depth]:depth"
       '--dwarf-start=[show DIEs starting at specified depth or deeper]:depth'
@@ -57,6 +63,7 @@ case $variant in
       '--ctf-parent=[use specified section as the CTF parent]:section'
       '--ctf-symbols=[use specified section as the CTF external symbol table]:section'
       '--ctf-strings=[use specified section as the CTF external string table]:section'
+      '(-T --silent-truncation)'{-T,--silent-truncation}"[if a symbol name is truncated, don't add ... suffix]"
     )
   ;;
   elfutils)
diff --git Completion/Unix/Command/_ri Completion/Unix/Command/_ri
index 070f46ac2..4d5a72985 100644
--- Completion/Unix/Command/_ri
+++ Completion/Unix/Command/_ri
@@ -6,26 +6,29 @@ typeset -A opt_args
 _arguments -C \
   '(- *)'{-h,--help}'[print help information and exit]' \
   '(- *)'{-v,--version}'[display the version of ri]' \
-  '*'{-d,--doc-dir}'[directory to search for documentation]:ri doc directory:_files -/' \
-  '(-f --fmt --format)'{-f,--fmt,--format}'[format to use when displaying output]:output format:(ansi bs html plain simple)' \
+  '*'{-d+,--doc-dir=}'[directory to search for documentation]:ri doc directory:_directories' \
+  '(-f --format)'{-f+,--format=}'[format to use when displaying output]:output format [bs]:(ansi bs markdown rdoc)' \
   '(-T --no-pager)'{-T,--no-pager}'[send output directly to stdout]' \
-  '(-i, --interactive)'{-i,--interactive}'[interactive mode]' \
+  '(-i --interactive)'{-i,--interactive}'[interactive mode]' \
+  '(-a --all)'{-a,--all}'[show all documentation for a class or module]' \
+  '(-l --list)'{-l,--list}'[list classes ri knows about]' \
   '--list-doc-dirs[list the directories from which ri will source documentation]' \
-  '(-w --width)'{-w,--width}'[set the width of the output]:output width:' \
-  '--no-standard-docs[do not include documentation from the Ruby standard library, site_lib, installed gems, or ~/.rdoc]' \
-  '(--no-use-cache --use-cache)--'{no-,}'use-cache[whether or not to use ri'\''s cache]' \
-  '(--no-system --system)--'{no-,}'system[include documentation from Ruby'\''s standard library]' \
+  '(-w --width)'{-w+,--width=}'[set the width of the output]:output width [72]' \
+  '(-l --list)--server=-[run RDoc server on the given port]::port [8214]:_ports' \
+  "--no-standard-docs[don't include documentation from the Ruby standard library, site_lib, installed gems, or ~/.rdoc]" \
+  '(--no-use-cache --use-cache)--'{no-,}"use-cache[whether or not to use ri's cache]" \
+  '(--no-system --system)--'{no-,}"system[include documentation from Ruby's standard library]" \
   '(--no-site --site)--'{no-,}'site[include documentation from libraries installed in site_lib]' \
   '(--no-gems --gems)--'{no-,}'gems[include documentation from RubyGems]' \
   '(--no-home --home)--'{no-,}'home[include documentation stored in ~/.rdoc]' \
-  '*:ri name:->ri-name' && ret=0
+  '--profile[run with the Ruby profiler]' \
+  '--dump=[dump data from an ri cache or data file]:cache:_files' \
+  '*:ri name:->ri-name' && return
 
 if [[ "$state" = ri-name ]]; then
   local -a ri_dirs ri_ext ri_names ri_wants ri_names
   local class_dir esc_name dir curtag tag descr expl
 
-  ret=1
-
   if "ruby${words[1]#ri}" -rrdoc/ri/ri_options -e 1 >/dev/null 2>&1; then
     # Old-style Ruby 1.8.x RI
     ri_dirs=( ${(f)"$(_call_program ri-names "ruby${words[1]#ri}" -rrdoc/ri/ri_options -e '"o = RI::Options.instance; o.parse(ARGV); o.path.each { |p| puts p }"' -- ${(kv)opt_args[(I)-d|--doc-dir|--(system|site|gems|home)]})"} )
diff --git Completion/Unix/Command/_ruby Completion/Unix/Command/_ruby
index a57bffcda..0e1f5dbc0 100644
--- Completion/Unix/Command/_ruby
+++ Completion/Unix/Command/_ruby
@@ -15,7 +15,7 @@ all=(
 common=(
   '*-I+[specify $LOAD_PATH directory (may be used more than once)]:library directory:_files -/'
   '-w[turn warnings on for your script]'
-  '-W-[set warning level]:warning level:((0\:silent 1\:medium 2\:verbose))'
+  '-W-[set warning level]:warning level:((0\:silent 1\:medium 2\:verbose \\\:deprecated \\\:experimental))'
   '(-)1:ruby script:_files -g "*.rb(-.)"'
   '*::script argument:= ->normal'
 )
@@ -35,7 +35,7 @@ opts=(
   '(-n)-p[assume loop like -n but print line also like sed]'
   '-s[enable some switch parsing for switches after script name]'
   '-S[look for the script using PATH environment variable]'
-  '-T-[turn on tainting checks]::taint level [1]:((0\:strings\ from\ streams/environment/ARGV\ are\ tainted 1\:no\ dangerous\ operation\ by\ tainted\ value 2\:process/file\ operations\ prohibited 3\:all\ generated\ objects\ are\ tainted 4\:no\ global\ \(non-tainted\)\ variable\ modification/no\ direct\ output))'
+  '!-T-[turn on tainting checks]::taint level [1]:((0\:strings\ from\ streams/environment/ARGV\ are\ tainted 1\:no\ dangerous\ operation\ by\ tainted\ value 2\:process/file\ operations\ prohibited 3\:all\ generated\ objects\ are\ tainted 4\:no\ global\ \(non-tainted\)\ variable\ modification/no\ direct\ output))'
   '(--verbose)-v[print version number, then turn on verbose mode]'
   '(-v)--verbose[turn on verbose mode and disable script from stdin]'
   '-x-[strip off text before #!ruby line and perhaps cd to directory]:directory:_files -/'
@@ -49,11 +49,11 @@ opts=(
   '--jit[enable jit with default options]'
   '--jit-warnings[enable printing JIT warnings]'
   '--jit-debug[enable JIT debugging (very slow)]'
-  '--jit-wait[wait until JIT compilation is finished every time (for testing)]'
+  '--jit-wait[wait until JIT compilation finishes every time (for testing)]'
   '--jit-save-temps[save JIT temporary files]'
   '--jit-verbose=-[print JIT logs of level num or less to stderr]:maximum log level [0]'
-  '--jit-max-cache=-[specify max number of methods to be JIT-ed in a cache]:number [1000]'
-  '--jit-min-calls=-[specify number of calls to trigger JIT]:calls [5]'
+  '--jit-max-cache=-[specify max number of methods to be JIT-ed in a cache]:number [100]'
+  '--jit-min-calls=-[specify number of calls to trigger JIT]:calls [10000]'
 )
 
 irb=(
diff --git Completion/Unix/Command/_script Completion/Unix/Command/_script
index ac3bf3973..7a3960be0 100644
--- Completion/Unix/Command/_script
+++ Completion/Unix/Command/_script
@@ -4,14 +4,19 @@ local args hlp="-h --help -V --version"
 
 if [[ $service = scriptreplay ]]; then
   _arguments -S -s \
-    "(1 -t --timing $hlp)"{-t+,--timing=}'[specify file containing timing output]:timing file:_files' \
-    "(2 -s --typescript $hlp)"{-s+,--typescript=}'[specify file containing terminal output]:typescript file:_files' \
+    "(1 -t --timing -T --log-timing $hlp)"{-t+,-T+,--timing=,--log-timing=}'[specify file containing timing output]:timing file:_files' \
+    "(-I --log-in -B --log-io $hlp)"{-I+,--log-in=}'[specify file containing terminal input]:file:_files' \
+    "(2 -s --typescript -B --log-io $hlp)"{-s+,-O+,--typescript=,--log-out=}'[specify file containing terminal output]:typescript file:_files' \
+    "(-B --log-io -I --log-in -s -O --typescript --log-out $hlp)"{-B,--log-io}'[specify file containing terminal input and output]' \
+    "($hlp)--summary[display overview about recorded session and exit]" \
     "(3 -d --divisor $hlp)"{-d+,--divisor=}'[speed up replay]:factor' \
     "(-m --maxdelay $hlp)"{-m+,--maxdelay=}'[set maximum delay between updates]:delay (seconds)' \
+    "(-x --stream $hlp)"{-x+,--stream=}'[specify stream type]:name:(out in signal or info)' \
+    "(-c --cr-mode $hlp)"{-c+,--cr-mode=}'[specify CR char mode]:mode:(auto never always)' \
     '(- *)'{-h,--help}'[display help information]' \
     '(- *)'{-V,--version}'[display version information]' \
     "(-t --timing $hlp):timing file:_files" \
-    "(-s --typescript $hlp):typescript file:_files" \
+    "(-s --typescript -O --log-out $hlp):typescript file:_files" \
     "(-d --divisor $hlp): :_guard '[0-9.]#' 'timing divisor'"
   return
 fi
@@ -19,12 +24,18 @@ fi
 case $OSTYPE in
   linux*)
     args=( -S
-      "(-a --append $hlp)"{-a,--append}'[append output]'
+      "(-I --log-in $hlp)"{-I,--log-in}'[log stdin to file]:file:_files'
+      "(-O --log-out $hlp)"{-O,--log-out}'[log stdout to file]:file:_files'
+      "(-B --log-io $hlp)"{-B,--log-io}'[log stdin and stdout to file]:file:_files'
+      "(-T --log-timing -t --timing $hlp)"{-T+,--log-timing=}'[log timing information to file]:file:_files'
+      "(-m --logging-format $hlp)"{-m+,--logging-format=}'[specify log file format]:format:(classic advanced)'
+      "(-a --append $hlp)"{-a,--append}'[append to the log file]'
       "(-c --command $hlp)"{-c,--command=}'[run specified command instead of a shell]:command:_cmdstring'
       "(-e --return $hlp)"{-e,--return}'[return exit status of the child process]'
       "(-f --flush $hlp)"{-f,--flush}'[flush output after each write]'
+      "(-E --echo $hlp)"{-E+,--echo=}'[echo input]:when:(auto always never)'
       "($hlp)--force[use output file even when it is a link]"
-      '(-o --output-limit)'{-o+,--output-limit=}'[terminate if output files exceed specified size]:size (bytes)'
+      "(-o --output-limit $hlp)"{-o+,--output-limit=}'[terminate if output files exceed specified size]:size (bytes)'
       "(-q --quiet $hlp)"{-q,--quiet}'[be quiet]'
       "(-t --timing $hlp)"{-t-,--timing=-}'[output timing data]::timing file:_files'
       '(- 1)'{-h,--help}'[display help information]'
diff --git Completion/Unix/Command/_sqlite Completion/Unix/Command/_sqlite
index 0f03c61c1..7ef3c6daa 100644
--- Completion/Unix/Command/_sqlite
+++ Completion/Unix/Command/_sqlite
@@ -22,7 +22,7 @@ options+=(
 )
 
 output_modes=( column HTML line list )
-(( $+sqlite3 )) && output_modes+=( ascii csv quote )
+(( $+sqlite3 )) && output_modes+=( ascii box csv json markdown quote table tabs )
 exclusive=( $^dashes-${^output_modes:l} )
 for display_opt in $output_modes ; do
   # finagle the description to match the way SQLite's -help formats them
@@ -54,6 +54,7 @@ options+=(
   $^dashes'-memtrace[trace all memory allocations and deallocations]'
   $^dashes'-mmap[set default mmap size]:size'
   $^dashes'-newline[set output row separator]:separator [\n]'
+  $^dashes'-nofollow[refuse to open symbolic links to database files]'
   $^dashes'-pagecache[specify size and number of slots for page cache memory]:size (bytes): :slots'
   $^dashes'-readonly[open the database read-only]'
   $^dashes'-stats[print memory stats before each finalize]'
diff --git Completion/Unix/Command/_strip Completion/Unix/Command/_strip
index e7f3418d7..3e1a6b698 100644
--- Completion/Unix/Command/_strip
+++ Completion/Unix/Command/_strip
@@ -32,6 +32,7 @@ if _pick_variant gnu=GNU solaris --version; then
     "--no-merge-notes[don't attempt to remove redundant notes]"
     '*'{-K+,--keep-symbol=}'[keep given symbol]:symbol name'
     '*'{-N+,--strip-symbol=}'[strip given symbol]:symbol name'
+    "*--keep-section=[don't strip given section]:section"
     '(*)-o+[output file]:output file:_files'
     '(-p --preserve-dates)'{-p,--preserve-dates}'[preserve access and modification dates]'
     '(-w --wildcard)'{-w,--wildcard}'[permit wildcards in symbol names]'
diff --git Completion/Unix/Command/_sudo Completion/Unix/Command/_sudo
index e3d12d72f..29e5e6d75 100644
--- Completion/Unix/Command/_sudo
+++ Completion/Unix/Command/_sudo
@@ -14,7 +14,9 @@ done
 
 args=(
   '(-A --askpass)'{-A,--askpass}'[use a helper program for password prompting]'
+  '(-B --bell)'{-B,--bell}'[ring bell when prompting]'
   '(-C --close-from)'{-C+,--close-from=}'[close file descriptors]:lowest fd to close'
+  '(-D --chdir)'{-D+,--chdir=}'[change the working directory before running command]:directory:_directories'
   '(-g --group)'{-g+,--group=}'[run command as the specified group name or ID]:group:_groups'
   '(-)'{-h,--help}'[display help message and exit]'
   '(-h --host)'{-h+,--host=}'[run command on host]:host:_hosts'
@@ -23,6 +25,7 @@ args=(
   \*{-l,--list}"[list user's privileges or check a specific command]"
   '(-n --non-interactive)'{-n,--non-interactive}'[non-interactive mode, no prompts are used]'
   '(-p --prompt)'{-p+,--prompt=}'[use the specified password prompt]:prompt'
+  '(-R --chroot)'{-R+,--chroot=}'[change the root directory before running command]:directory:_directories'
   '(-r --role)'{-r+,--role=}'[create SELinux security context with specified role]: :_selinux_roles'
   '(-S --stdin)'{-S,--stdin}'[read password from standard input]'
   '(-t --type)'{-t+,--type=}'[create SELinux security context with specified type]: :_selinux_types'
diff --git Completion/Unix/Command/_tiff Completion/Unix/Command/_tiff
index da55b541c..ef12777de 100644
--- Completion/Unix/Command/_tiff
+++ Completion/Unix/Command/_tiff
@@ -59,6 +59,7 @@ tiff2pdf)
     '-s+[set document subject, overrides image image description default]:subject' \
     '-k+[set document keywords]:keywords' \
     '-b[set PDF "Interpolate" user preference]' \
+    '-m+[set memory allocation limit]:limit (MiB)' \
     '(- :)-h[display usage information]' \
     ':input file:_files -g "*.(#i)tif(|f)(-.)"'
   ;;
@@ -83,6 +84,7 @@ tiff2ps)
     '-i+[enable/disable (Nz/0) pixel interpolation]:state [enabled]:((0\:disable 1\:enable))' \
     '-l+[set the left margin]:margin (inches)' \
     '-m[use "imagemask" operator instead of "image"]' \
+    '-M+[set memory allocation limit]:limit (MiB)' \
     '-o+[set initial TIFF directory (file offset)]:file offset (bytes)' \
     '(-e)-p[generate non-Encapsulated PostScript]' \
     '-O+[specify output file]:output file:_files -g "*.(#i)(|e)ps(-.)"' \
@@ -121,6 +123,7 @@ tiffcp)
     '-i[ignore read errors]' \
     '-b+[specify bias (dark) monochrome image to be subtracted from all others]:file:_files' \
     '-,=-[specify substitute character for image indices]:character [,]' \
+    '-m+[set memory allocation limit]:limit (MiB)' \
     '-r+[specify rows per strip]:rows per strip' \
     '-w+[specify output tile width]:output tile width' \
     '-l+[specify output tile length]:output tile length' \
diff --git Completion/Unix/Command/_tmux Completion/Unix/Command/_tmux
index 284a325e5..844af58fc 100644
--- Completion/Unix/Command/_tmux
+++ Completion/Unix/Command/_tmux
@@ -127,6 +127,7 @@ _tmux_aliasmap=(
     confirm     confirm-before
     menu        display-menu
     display     display-message
+    popup       display-popup
 
     # buffers
     clearhist   clear-history
@@ -168,6 +169,7 @@ _tmux-attach-session() {
   _arguments -s \
     '-c+[specify working directory for the session]:directory:_directories' \
     '-d[detach other clients attached to target session]' \
+    '-f+[set client flags]: :_tmux_client_flags' \
     '-r[put the client into read-only mode]' \
     '-t+[specify target session]:target session: __tmux-sessions-separately' \
     "-E[don't apply update-environment option]" \
@@ -188,6 +190,8 @@ _tmux-bind-key() {
 _tmux-break-pane() {
   [[ -n ${tmux_describe} ]] && print "break a pane from an existing into a new window" && return
   _arguments -s \
+    '(-b)-a[move window to next index after]' \
+    '(-a)-b[move window to next index before]' \
     "-d[don't make the new window become the active one]" \
     '-F+[specify output format]:format:__tmux-formats' \
     '-P[print information of new window after it has been created]' \
@@ -221,6 +225,7 @@ _tmux-choose-buffer() {
     '-r[reverse sort order]' \
     '-F+[specify format for each list item]:format:__tmux-formats' \
     '-f+[filter items]:filter format:__tmux-formats' \
+    '-K+[specify format for each shortcut key]:format:__tmux-formats' \
     '-O+[initial sort order]:order:(time name size)' \
     '-t+[specify target window]:session:__tmux-windows' \
     '*:::template:= _tmux'
@@ -234,6 +239,7 @@ _tmux-choose-client() {
     '-r[reverse sort order]' \
     '-F+[specify format for each list item]:format:__tmux-formats' \
     '-f+[filter items]:filter format:__tmux-formats' \
+    '-K+[specify format for each shortcut key]:format:__tmux-formats' \
     '-O+[initial sort order]:order:(time name size)' \
     '-t+[specify target window]:session:__tmux-windows' \
     '*:::template:= _tmux'
@@ -248,6 +254,7 @@ _tmux-choose-tree() {
     '-r[reverse sort order]' \
     '-F+[specify format for each list item]:format:__tmux-formats' \
     '-f+[filter items]:filter format:__tmux-formats' \
+    '-K+[specify format for each shortcut key]:format:__tmux-formats' \
     '-O+[initial sort order]:order:(time name size)' \
     '-s[choose among sessions]' \
     '-t+[specify target window]:session:__tmux-windows' \
@@ -275,6 +282,8 @@ _tmux-command-prompt() {
     '-I+[specify list of initial inputs]:initial-text (comma-separated list)' \
     '-p+[specify list of prompts]:prompts (comma-separated list)' \
     '-t+[specify target client]:client:__tmux-clients' \
+    '(-W)-T[prompt is for a target - tab complete as appropriate]' \
+    '(-T)-W[prompt is for a window - tab complete as appropriate]' \
     '*:::template:= _tmux'
 }
 
@@ -289,6 +298,7 @@ _tmux-confirm-before() {
 _tmux-copy-mode() {
   [[ -n ${tmux_describe} ]] && print "enter copy mode" && return
   _arguments -s \
+    '-s+[specify source pane]:pane:__tmux-panes' \
     '-t+[specify target pane]:pane:__tmux-panes' \
     '-e[scrolling to the bottom should exit copy mode]' \
     '-H[hide the position indicator in the top right]' \
@@ -297,6 +307,16 @@ _tmux-copy-mode() {
     '-M[begin a mouse drag]'
 }
 
+_tmux-customize-mode() {
+  [[ -n ${tmux_describe} ]] && print "enter customize mode" && return
+  _arguments -s \
+    '-F+[specify format for each item in the tree]:format:__tmux-formats' \
+    '-f+[specify initial filter]:filter:__tmux-formats' \
+    '-N[start without the option information]' \
+    '-t+[specify target pane]:pane:__tmux-panes' \
+    '-Z[zoom the pane]'
+}
+
 _tmux-delete-buffer() {
   [[ -n ${tmux_describe} ]] && print "delete a paste buffer" && return
   _arguments '-b+[specify target buffer name]:buffer:__tmux-buffers'
@@ -318,6 +338,7 @@ _tmux-display-menu() {
   local -a state line expl
   _arguments -C -s -S -A "-*" \
     '-c+[specify target client]:client:__tmux-clients' \
+    "-O[don't close menu if mouse is released without making a selection]" \
     '-t+[specify target pane]:pane:__tmux-panes' \
     '-T+[specify title]:title' \
     '-x+[specify horizontal position]: : _alternative "columns\: \:_guard \[0-9\]\# column" "positions\:position\:((R\:right P\:bottom M\:mouse W\:window))"' \
@@ -326,7 +347,7 @@ _tmux-display-menu() {
 
   if [[ -n $state ]]; then
     case $(( CURRENT % 3 )) in
-      1) _message -e options 'menu option' ;;
+      1) _message -e menu-options 'menu option' ;;
       2) _message -e keys 'shortcut key' ;;
       0)
 	compset -q
@@ -345,7 +366,9 @@ _tmux-display-message() {
   _arguments -s -S -A "-*" \
     '(-p -F :)-a[list the format variables and their values]' \
     '-I[forward any input read from stdin to the target pane]' \
+    '-N[ignore key presses and only close after the delay]' \
     '-c+[specify target client]:client:__tmux-clients' \
+    '-d+[time to display message]:delay (milliseconds)' \
     '(-a)-p[print message to stdout]' \
     '-t+[specify target pane]:pane:__tmux-panes' \
     '(-a)-F+[specify output format]:format:__tmux-formats' \
@@ -362,9 +385,25 @@ _tmux-display-panes() {
     '*:::command:= _tmux'
 }
 
+_tmux-display-popup() {
+  [[ -n ${tmux_describe} ]] && print "display a popup box over a pane" && return
+  _arguments -s \
+    '-C[close any popup on the client]' \
+    '-c+[specify target client]:client:__tmux-clients' \
+    '-d+[specify working directory for the command]:directory:_directories' \
+    '-E[close the popup when the command exits]' \
+    '-w+[specify width]:width' \
+    '-h+[specify height]:height' \
+    '-t+[specify target pane]:pane:__tmux-panes' \
+    '-x+[specify horizontal position]:position' \
+    '-y+[specify vertical position]:position' \
+    ':shell command:_cmdstring'
+}
+
 _tmux-find-window() {
   [[ -n ${tmux_describe} ]] && print "search for a pattern in windows" && return
   _arguments -s \
+    '-i[ignore case]' \
     '-r[use regular expression matching]' \
     '-C[match visible contents]' \
     '-N[match window name]' \
@@ -454,6 +493,8 @@ _tmux-last-window() {
 _tmux-link-window() {
   [[ -n ${tmux_describe} ]] && print "link a window to another" && return
   _arguments -s \
+    '(-b)-a[move window to next index after destination window]' \
+    '(-a)-b[move window to next index before destination window]' \
     "-d[don't make the new window become the active one]" \
     '-k[kill the target window if it exists]' \
     '-s+[specify source window]:window:__tmux-windows' \
@@ -462,7 +503,9 @@ _tmux-link-window() {
 
 _tmux-list-buffers() {
   [[ -n ${tmux_describe} ]] && print "list paste buffers of a session" && return
-  _arguments '-F+[specify output format]:format:__tmux-formats'
+  _arguments \
+    '-F+[specify output format]:format:__tmux-formats' \
+    '-f+[filter items]:filter format:__tmux-formats'
 }
 
 _tmux-list-clients() {
@@ -498,12 +541,15 @@ _tmux-list-panes() {
   _arguments -s $args \
     '-a[list all panes the server possesses]' \
     '-F+[specify output format]:format:__tmux-formats' \
+    '-f+[filter items]:filter format:__tmux-formats' \
     '-s[if specified, -t chooses a session]'
 }
 
 _tmux-list-sessions() {
   [[ -n ${tmux_describe} ]] && print "list sessions managed by server" && return
-  _arguments '-F+[specify output format]:format:__tmux-formats'
+  _arguments \
+    '-F+[specify output format]:format:__tmux-formats' \
+    '-f+[filter items]:filter format:__tmux-formats'
 }
 
 _tmux-list-windows() {
@@ -511,6 +557,7 @@ _tmux-list-windows() {
   _arguments -s \
     '-a[list all windows the tmux server possesses]' \
     '-F[specify output format]:format:__tmux-formats' \
+    '-f+[filter items]:filter format:__tmux-formats' \
     '-t+[specify session]:session:__tmux-sessions'
 }
 
@@ -518,6 +565,8 @@ _tmux-load-buffer() {
   [[ -n ${tmux_describe} ]] && print "load a file into a paste buffer" && return
   _arguments -A "-*" -S \
     '-b+[specify target buffer name]:buffer:__tmux-buffers' \
+    '-t+[specify target client]:client:__tmux-clients' \
+    '-w[also send the buffer to the clipboard using the xterm escape sequence]' \
     '1:file:_files'
 }
 
@@ -537,21 +586,14 @@ _tmux-lock-session() {
 }
 
 _tmux-move-pane() {
-  [[ -n ${tmux_describe} ]] && print "move a pane into a new space" && return
-  _arguments -s \
-    '-b[join source pane left of or above target pane]' \
-    "-d[don't make the new window become the active one]" \
-    '-h[split horizontally]' \
-    '-v[split vertically]' \
-    "-l+[define new pane's size]:numeric value" \
-    "-p+[define new pane's size in percent]:numeric value" \
-    '-s+[specify source pane]:pane:__tmux-panes' \
-    '-t+[specify target pane]:pane:__tmux-panes'
+ _tmux-join-pane "$@"
 }
 
 _tmux-move-window() {
   [[ -n ${tmux_describe} ]] && print "move a window to another" && return
   _arguments -s \
+    '(-b)-a[move window to next index after destination window]' \
+    '(-a)-b[move window to next index before destination window]' \
     "-d[don't make the new window become the active one]" \
     '-k[kill the target window if it exists]' \
     '-s+[specify source window]:window:__tmux-windows' \
@@ -567,7 +609,9 @@ _tmux-new-session() {
     "-d[don't attach new session to current terminal]" \
     "-D[with -A, detach other clients attached to session]" \
     "-E[don't apply update-environment option]" \
+    '*-e[specify environment variable]:environment variable:_parameters -g "*export*" -qS=' \
     '-F+[specify output format]:format:__tmux-formats' \
+    '-f+[specify client flags]: :_tmux_client_flags' \
     '-n+[specify initial window name]:window name' \
     '-P[print information about new session after it is created]' \
     '-s+[name the session]:session name:__tmux-sessions' \
@@ -581,14 +625,16 @@ _tmux-new-session() {
 _tmux-new-window() {
   [[ -n ${tmux_describe} ]] && print "create a new window" && return
   _arguments -s -A "-*" -S \
-    '-a[insert new window at next free index from -t]' \
+    '(-b)-a[insert new window at next index after target]' \
+    '(-a)-b[insert new window at next index before target]' \
     '-c+[specify working directory for the session]:directory:_directories' \
     '*-e[specify environment variable]:environment variable:_parameters -g "*export*" -qS=' \
-    "-d[don't make the new window become the active one]" \
+    "(-S)-d[don't make the new window become the active one]" \
     '-F+[specify output format]:format:__tmux-formats' \
     '-k[destroy it if the specified window exists]' \
     '-n+[specify a window name]:window name' \
     '-P[print information about new window after it is created]' \
+    '(-d)-S[select window if name already exists]' \
     '-t+[specify target window]:window:__tmux-windows' \
     '*:: :_cmdambivalent'
 }
@@ -640,11 +686,13 @@ _tmux-previous-window() {
 
 _tmux-refresh-client() {
   [[ -n ${tmux_describe} ]] && print "refresh a client" && return
-  _arguments -s -S -A "-*" \
+  _arguments -s -A "-*" -S \
+    '-B+[set a subscription to a format for a control mode client]:subscription' \
+    '-A+[allow a control mode client to trigger actions on a pane]:pane:__tmux-panes -P% -S\:' \
     '-C+[set the width and height of a control client]:width,height' \
     '-c[reset so that the position follows the cursor]' \
     '-D[move visible portion of window down]' \
-    '-F+[specify flags]:flag:(no-output)' \
+    '-f+[set client flags]:flag:_tmux_client_flags' \
     '-L[move visible portion of window left]' \
     '-l[request clipboard from the client and store it in a new paste buf using xterm(1) escape sequence]' \
     "-S[only update the client's status bar]" \
@@ -677,6 +725,7 @@ _tmux-resize-pane() {
     '-R[resize to the right]' \
     '-U[resize upward]' \
     '-t+[specify target pane]:pane:__tmux-panes' \
+    '-T[trim lines below the cursor position and moves lines out of the history to replace them]' \
     '-x+[specify width]:width' \
     '-y+[specify height]:height' \
     '-Z[toggle zoom of pane]' \
@@ -729,10 +778,22 @@ _tmux-rotate-window() {
 
 _tmux-run-shell() {
   [[ -n ${tmux_describe} ]] && print "execute a command without creating a new window" && return
-  _arguments -s -A "-*" -S \
-    '-b[run shell command in background]' \
+  local curcontext="$curcontext" ret=1
+  local -a state line expl
+  _arguments -C -s -A "-*" -S \
+    '-b[run command in background]' \
+    '(1)-C[run a tmux command]' \
+    '-d+[specify delay before starting the command]:delay (seconds)' \
     '-t+[specify target pane]:pane:__tmux-panes' \
-    ':command:_cmdstring'
+    '(2)1:command:_cmdstring' \
+    '2:tmux command:->tmux-commands' && ret=0
+
+  if [[ -n $state ]]; then
+    compset -q
+    words=( run "$words[@]" )
+    (( CURRENT++ ))
+    _tmux && ret=0
+  fi
 }
 
 _tmux-save-buffer() {
@@ -815,6 +876,8 @@ _tmux-set-buffer() {
     '-a[append to rather than overwriting target buffer]' \
     '-b+[specify target buffer index]:pane:__tmux-buffers' \
     '-n+[specify new buffer name]:buffer-name' \
+    '-t+[specify target client]:client:__tmux-clients' \
+    '-w[also send the buffer to the clipboard using the xterm escape sequence]' \
     ':data'
 }
 
@@ -824,7 +887,9 @@ _tmux-set-environment() {
   local curcontext="$curcontext" state line ret=1
   typeset -A opt_args
   _arguments -C -s -A "-*" -S : \
+    '-F[expand value as a format]' \
     '(-t)-g[modify global environment]' \
+    '-h[mark the variable as hidden]' \
     '(-u)-r[remove variable before starting new processes]' \
     '(-r)-u[unset a variable]' \
     '(-g)-t[specify target session]:target session:__tmux-sessions' \
@@ -861,6 +926,7 @@ _tmux-set-option() {
     '-o[prevent setting of an option that is already set]' \
     '-q[suppress errors about unknown or ambiguous options]' \
     '-u[unset a non-global option]' \
+    '-U[unset a pane option across all panes in the window]' \
     '(-w -s)-p[change pane (no session) options]' \
     '(-p -s)-w[change window (not session) options]' \
     '(-p -w)-s[change server (not session) options]' \
@@ -899,6 +965,8 @@ _tmux-set-hook() {
     '-a[append to hook]' \
     '(-R)-g[add hook to global list]' \
     '(-g -u)-R[run hook immediately]' \
+    '(-w)-p[set pane hooks]' \
+    '(-p)-w[set window hooks]' \
     '(-R)-u[unset a hook]' \
     '-t+[specify target session]:session:__tmux-sessions' \
     ':hook name:_tmux_hooks' \
@@ -909,6 +977,8 @@ _tmux-show-hooks() {
   [[ -n ${tmux_describe} ]] && print "show the global list of hooks" && return
   _arguments -s -S -A "-*" \
     '-g[show global list of hooks]' \
+    '(-w)-p[show pane hooks]' \
+    '(-p)-w[show window hooks]' \
     '-t+[specify target session]:session:__tmux-sessions' \
 }
 
@@ -924,6 +994,7 @@ _tmux-show-environment() {
   typeset -A opt_args
   _arguments -C -A "-*" -s : \
     '(-t)-g[show global environment]' \
+    '-h[show hidden variables]' \
     '-s[format output as Bourne shell commands]' \
     '(-g)-t+[specify target session]:target session:__tmux-sessions' \
     '1:: :->name' && ret=0
@@ -986,6 +1057,7 @@ _tmux-show-window-options() {
 _tmux-source-file() {
   [[ -n ${tmux_describe} ]] && print "execute tmux commands from a file" && return
   _arguments \
+    '-F[expand path as a format]' \
     '-n[file is parsed but no commands are executed]' \
     "-q[don't report error if path doesn't exist]" \
     '-v[show parsed commands and line numbers if possible]' \
@@ -1006,6 +1078,7 @@ _tmux-split-window() {
     "(-p)-l[define new pane's size]:size" \
     "!(-f -l)-p+:size (percentage)" \
     '-t+[specify target pane]:pane:__tmux-panes' \
+    '-Z[zoom the pane]' \
     '(:)-I[create empty pane and forward stdin to it]' \
     ':command:_cmdambivalent'
   # Yes, __tmux-panes is correct here. The behaviour was changed
@@ -1065,6 +1138,7 @@ _tmux-unbind-key() {
   _arguments -C -s \
     '-a[remove all key bindings]' \
     '-n[remove a non-prefix binding]' \
+    '-q[prevent errors being returned]' \
     '-T[specify key table]:key table' \
     '*:: :->boundkeys'
 
@@ -1383,6 +1457,11 @@ _tmux_hooks() {
     'post-hooks:command post-hook:compadd - after-${_tmux_aliasmap}'
 }
 
+_tmux_client_flags() {
+  _values -s , flag active-pane ignore-size no-output \
+      'pause-after:time (seconds)' read-only wait-exit
+}
+
 function __tmux-get-optarg() {
     local opt="$1"
     local -i i
@@ -1607,16 +1686,11 @@ function __tmux-options-complete() {
 }
 
 function __tmux-panes() {
-    local expl line
+    local expl line orig="$IPREFIX"
     local -i num
     local -a panes opts
 
-    compset -P '*.'
-    if [[ -n ${IPREFIX} ]]; then
-        opts=( -t "${IPREFIX%.}" )
-    else
-        opts=( )
-    fi
+    compset -P '*.' && opts=( -t "${${IPREFIX%.}#$orig}" )
     num=0
     command tmux 2> /dev/null list-panes "${opts[@]}" | while IFS= read -r line; do
         panes+=( $(( num++ )):${line//:/} )
@@ -1761,10 +1835,13 @@ _tmux() {
     '-2[force using 256 colours]' \
     '-c[execute a shell command]:command name:_command_names' \
     '-C[start tmux in control mode. -CC disables echo]' \
+    "-D[don't start the tmux server as a daemon]" \
     '-f[specify configuration file]:tmux config file:_files -g "*(-.)"' \
     '-l[behave like a login shell]' \
     '-L[specify socket name]:socket name:__tmux-socket-name' \
+    "-N[don't start the server even if the command would normally do so]" \
     '-S[specify socket path]:server socket:_path_files -g "*(=,/)"' \
+    '-T+[set terminal features for the client]: : _values -s , 256 clipboard ccolour cstyle extkeys focus margins mouse overline rectfill RGB strikethrough sync title usstyle' \
     '-u[force using UTF-8]' \
     '-v[request verbose logging]' \
     '-V[report tmux version]' \
diff --git Completion/Unix/Command/_vim Completion/Unix/Command/_vim
index d9dc1a5b3..5c6054e70 100644
--- Completion/Unix/Command/_vim
+++ Completion/Unix/Command/_vim
@@ -27,9 +27,8 @@ arguments=(
   '-D[debugging mode]'
   '-n[no swap file (memory only)]'
   {-r,-L}'[list swap files and exit or recover from a swap file]::swap file:_vim_files -g "*.sw?(-.)"'
-  '(   -H -F)-A[start in Arabic mode]'
-  '(-A    -F)-H[start in Hebrew mode]'
-  '(-A -H   )-F[start in Farsi mode]'
+  '(-H)-A[start in Arabic mode]'
+  '(-A)-H[start in Hebrew mode]'
   '-u[use given vimrc file instead of default .vimrc]:config:->config'
   "--noplugin[don't load plugin scripts]"
   '-o-[number of windows to open (default: one for each file)]::window count: '
@@ -99,8 +98,11 @@ fi
 [[ $service != *view ]] && arguments+='-R[readonly mode]'
 [[ $service = *g* ]] || (( ${words[(I)-g]} )) && arguments+=(
   '(--nofork -f)'{--nofork,-f}'[do not detach the GUI version from the shell]'
+  '(-background -bg)'{-background,-bg}'[use specified color for the background]:color:_x_color'
+  '(-foreground -fg)'{-foreground,-fg}'[use specified color for normal text]:color:_x_color'
   '-font:font:_xft_fonts'
   '-geometry:geometry:_x_geometry'
+  '-iconic[start vim iconified]'
   '(-rv -reverse)'{-rv,-reverse}'[use reverse video]'
   '-display:display:_x_display'
   '--role[set unique role to identify main window]:role'
diff --git Completion/Unix/Command/_w3m Completion/Unix/Command/_w3m
index eff9901ca..de425cfb1 100644
--- Completion/Unix/Command/_w3m
+++ Completion/Unix/Command/_w3m
@@ -1,7 +1,5 @@
 #compdef w3m
 
-# w3m version w3m/0.5.1
-
 local curcontext="$curcontext" state line expl ret=1
 typeset -A opt_args
 
@@ -21,7 +19,7 @@ _arguments -C \
   '(-B *)-v[visual startup mode]' \
   '-M[monochrome display]' \
   '-N[open URL of command line on each new tab]' \
-  '-F[automatically render frame]' \
+  '-F[automatically render frames]' \
   '-cols[specify column width (used with -dump)]:column width' \
   '-ppc[specify the number of pixels per character (4.0...32.0)]:number of pixels (4.0...32.0):' \
   '-ppl[specify the number of pixels per line (4.0...64.0)]:number of pixels (4.0...64.0):' \
@@ -34,17 +32,17 @@ _arguments -C \
   '-header[insert string as a header]:header:' \
   '+-[goto specified line]:line number:_guard "[0-9]#" "line number"' \
   '-num[show line number]' \
+  '-session[use specified session]:id' \
   "-no-proxy[don't use proxy]" \
   '(-6)-4[IPv4 only (-o dns_order=4)]' \
   '(-4)-6[IPv6 only (-o dns_order=6)]' \
   "-no-mouse[don't use mouse]" \
   '(-no-cookie)-cookie[use cookie]' \
   "(-cookie)-no-cookie[don't use cookie]" \
-  '-pauth[proxy authentication]:user\:pass:->pauth' \
-  '(-no-graph)-graph[use graphic character]' \
-  "(-graph)-no-graph[don't use graphic character]" \
+  '(-no-graph)-graph[use DEC special graphics for border of table and menu]' \
+  '(-graph)-no-graph[use ASCII character for border of table and menu]' \
   '-S[squeeze multiple blank lines]' \
-  '-W[toggle wrap search mode]' \
+  '-W[toggle search wrap mode]' \
   "-X[don't use termcap init/deinit]" \
   '-title=[set buffer name to terminal title string]:terminal:_terminals' \
   '*-o[assign value to config option]:option=value:->option' \
@@ -97,14 +95,6 @@ case "$state" in
       _describe -t options 'option' options "$suf[@]" && ret=0
     fi
   ;;
-  pauth)
-    if compset -P 1 '*:'; then
-      _message -e passwords 'password'
-    else
-      compset -S ':*' || suf=( -S ':' )
-      _users "$suf[@]" && ret=0
-    fi
-  ;;
 esac
 
 return ret
diff --git Completion/Unix/Command/_wget Completion/Unix/Command/_wget
index d061fcd06..50fd7791a 100644
--- Completion/Unix/Command/_wget
+++ Completion/Unix/Command/_wget
@@ -34,6 +34,8 @@ _arguments -C -s \
   '(--server-response -S)'{--server-response,-S}'[print server response]' \
   "--spider[don't download anything]" \
   '(--timeout -T)'{--timeout=,-T+}'[set all timeout values]:timeout (seconds)' \
+  '--dns-servers=[specify DNS servers to query]:DNS server:_sequence _hosts' \
+  '--bind-dns-address=[bind DNS resolver to specified address]:hostname or IP on local host' \
   '(--timeout -T)--dns-timeout=[set the DNS lookup timeout]:DNS lookup timeout (seconds)' \
   '(--timeout -T)--connect-timeout=[set the connect timeout]:connect timeout (seconds)' \
   '(--timeout -T)--read-timeout=[set the read timeout]:read timeout (seconds)' \
@@ -107,7 +109,7 @@ _arguments -C -s \
   "--ca-directory=[specify dir where hash list of CA's are stored]:directory:_directories" \
   '--crl-file=[specify file with bundle of CRLs]:file:_files' \
   '--pinnedpubkey=:file:_files' \
-  '!--random-file=:file:_files' \
+  '--random-file[specify file with random data for seeding generator]:file:_files' \
   '--egd-file=[specify filename of EGD socket]:file:_files' \
   '--ciphers=[set the priority string (GnuTLS) or cipher list string (OpenSSL) directly]:string' \
   '--no-hsts[disable HSTS]' \
diff --git Completion/Unix/Command/_wiggle Completion/Unix/Command/_wiggle
index 0a2f0c0cb..1d747a479 100644
--- Completion/Unix/Command/_wiggle
+++ Completion/Unix/Command/_wiggle
@@ -1,15 +1,17 @@
 #compdef wiggle
 
-local fns='-m --merge -d --diff -x --extract'
+local fns='-m --merge -d --diff -x --extract -B --browse'
 
 _arguments \
   "($fns -1 -2 -3)"{-m,--merge}'[select the merge function]' \
   "($fns -3 3)"{-d,--diff}'[display differences between files]' \
   "($fns 2 3)"{-x,--extract}'[extract one branch of a patch or merge file]' \
   '(-w --words -l --lines)'{-w,--words}'[make operations and display word based]' \
-  '(-l --lines -w --words)'{-l,--lines}'[make operations and display line based]' \
+  '(-l --lines -w --words --non-space)'{-l,--lines}'[make operations and display line based]' \
+  '(-l --lines)--non-space[words are separated by spaces]' \
   '(-p --patch)'{-p,--patch}'[treat last named file as a patch]' \
   '(-r --replace)'{-r,--replace}'[replace original file with merged output]' \
+  '--no-backup[never save original file (as name.porig)]' \
   '(-R --reverse -x --extract)'{-R,--reverse}'[swap the files or revert changes]' \
   '(-2 -3 -m --merge)-1[select branch]' \
   '(-1 -3 -m --merge)-2[select branch]' \
diff --git Completion/Unix/Command/_xmlsoft Completion/Unix/Command/_xmlsoft
index 9f1206988..08b123e54 100644
--- Completion/Unix/Command/_xmlsoft
+++ Completion/Unix/Command/_xmlsoft
@@ -80,6 +80,7 @@ case $service in
       '(--dtdvalid --relaxng --schema)--postvalid[do a posteriori validation, i.e after parsing]' \
       '(--postvalid --relaxng --schema --dtdvalidfpi)--dtdvalid[do a posteriori validation against a given DTD]:DTD:_webbrowser' \
       '(--postvalid --relaxng --schema --dtdvalid)--dtdvalidfpi[as --dtdvalid but specify DTD with public identifier]:DTD identifier' \
+      '--quiet[be quiet when successful]' \
       '--timing[print some timings]' \
       '(--noout --output -o)'{--output,-o}'[save to a given file]:output file:_files' \
       '--repeat[repeat 100 times, for timing or profiling]' \
diff --git Completion/Unix/Command/_xxd Completion/Unix/Command/_xxd
index 3a8efd664..31d26ab64 100644
--- Completion/Unix/Command/_xxd
+++ Completion/Unix/Command/_xxd
@@ -39,6 +39,7 @@ arguments=(
   {-g+,-groupsize}'[specify the number of octets per group]: :_guard "[0-9]#" "number of octets per group"'
   {-l+,-len}'[specify number of octets to output]: :_guard "[0-9]#" "number of octets to output"'
   {-o+,-offset}'[add specified offset to displayed file position]:offset'
+  '-d[show offset in decimal instead of hex]'
   {-s,-skip,-seek}'[specify file offset to dump from]: :_guard "[0-9]#" "file offset to dump from (absolute or relative)"'
 
   ': :_files'
diff --git Completion/X/Command/_xrandr Completion/X/Command/_xrandr
index 6143054aa..2551e1958 100644
--- Completion/X/Command/_xrandr
+++ Completion/X/Command/_xrandr
@@ -36,6 +36,7 @@ _arguments -C \
   '*--set:property:(Backlight scaling\ mode):value:->value' \
   '*--scale:output scaling:' \
   '*--transform:transformation matrix:' \
+  '*--filter:mode:(nearest bilinear)' \
   '*--off[disable the output]' \
   '*--crtc:crtc to use:' \
   '*--panning:panning:' \
diff --git Completion/X/Command/_xterm Completion/X/Command/_xterm
index 6d98985e7..180c2eb21 100644
--- Completion/X/Command/_xterm
+++ Completion/X/Command/_xterm
@@ -3,7 +3,7 @@
 _xt_arguments \
   -+{132,ah,ai,aw,bc,bdc,cb,cjk_width,cm,cn,cu,dc,fbb,fbx,fullscreen,hf,hm,hold,ie,im,itc,j,k8,l,lc,ls,maximized,mb,mesg,mk_width,nul,pc,pob,rvc,rw,s,samename,sb,sf,si,sk,sm,sp,t,u8,uc,ulc,ulit,ut,vb,wc,wf} \
   -{version,help,leftbar,rightbar,C} \
-  '-report-'{charclass,colors,fonts} \
+  '-report-'{charclass,colors,fonts,icons,xres} \
   '-T:title' \
   '-b:inner border size:' \
   '-baudrate:rate [38400]' \


^ permalink raw reply	[relevance 1%]

* Re: [BUG] ignored trap and subshell
  2021-08-25 10:10  0% ` Peter Stephenson
@ 2021-08-25 10:47  0%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2021-08-25 10:47 UTC (permalink / raw)
  To: zsh-workers


> On 25 August 2021 at 11:10 Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> > On 24 August 2021 at 17:23 Vincent Lefevre <vincent@vinc17.net> wrote:
> > The zshmisc(1) man page says:
> > 
> >     ( list )
> >         Execute list in a subshell.  Traps set by the trap builtin are
> >         reset to their default values while executing list.
> > 
> > However, with "emulate sh", ignored traps should still be ignored
> > in the subshell according to POSIX, and zsh 5.8 fails do conform:
> 
> I think this is straightforward.  POSIXTRAPS is clearly the option for the job.

And some documentation; the place Vincent mentioned looks like the obvious one
(we have at least one piece of evidence it gets read...)

diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index 2eb2018d2..f8f4ada86 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -288,7 +288,9 @@ for each selection until a break or end-of-file is encountered.
 cindex(subshell)
 item(tt(LPAR()) var(list) tt(RPAR()))(
 Execute var(list) in a subshell.  Traps set by the tt(trap) builtin
-are reset to their default values while executing var(list).
+are reset to their default values while executing var(list); an
+exception is that ignored signals will continue to be ignored
+if the option tt(POSIXTRAPS) is set.
 )
 item(tt({) var(list) tt(}))(
 Execute var(list).
diff --git a/Src/exec.c b/Src/exec.c
index 49ff88b80..79d8064b6 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1033,7 +1033,8 @@ entersubsh(int flags, struct entersubsh_ret *retp)
 
     if (!(flags & ESUB_KEEPTRAP))
 	for (sig = 0; sig < SIGCOUNT; sig++)
-	    if (!(sigtrapped[sig] & ZSIG_FUNC))
+	    if (!(sigtrapped[sig] & ZSIG_FUNC) &&
+		!(isset(POSIXTRAPS) && (sigtrapped[sig] & ZSIG_IGNORED)))
 		unsettrap(sig);
     monitor = isset(MONITOR);
     job_control_ok = monitor && (flags & ESUB_JOB_CONTROL) && isset(POSIXJOBS);


^ permalink raw reply	[relevance 0%]

* Re: [BUG] ignored trap and subshell
  2021-08-24 16:23  3% [BUG] ignored trap and subshell Vincent Lefevre
  2021-08-24 17:29  0% ` Bart Schaefer
@ 2021-08-25 10:10  0% ` Peter Stephenson
  2021-08-25 10:47  0%   ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2021-08-25 10:10 UTC (permalink / raw)
  To: zsh-workers

> On 24 August 2021 at 17:23 Vincent Lefevre <vincent@vinc17.net> wrote:
> The zshmisc(1) man page says:
> 
>     ( list )
>         Execute list in a subshell.  Traps set by the trap builtin are
>         reset to their default values while executing list.
> 
> However, with "emulate sh", ignored traps should still be ignored
> in the subshell according to POSIX, and zsh 5.8 fails do conform:

I think this is straightforward.  POSIXTRAPS is clearly the option for the job.

pws

diff --git a/Src/exec.c b/Src/exec.c
index 49ff88b80..79d8064b6 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1033,7 +1033,8 @@ entersubsh(int flags, struct entersubsh_ret *retp)
 
     if (!(flags & ESUB_KEEPTRAP))
 	for (sig = 0; sig < SIGCOUNT; sig++)
-	    if (!(sigtrapped[sig] & ZSIG_FUNC))
+	    if (!(sigtrapped[sig] & ZSIG_FUNC) &&
+		!(isset(POSIXTRAPS) && (sigtrapped[sig] & ZSIG_IGNORED)))
 		unsettrap(sig);
     monitor = isset(MONITOR);
     job_control_ok = monitor && (flags & ESUB_JOB_CONTROL) && isset(POSIXJOBS);


^ permalink raw reply	[relevance 0%]

* Re: [BUG] ignored trap and subshell
  2021-08-24 17:29  0% ` Bart Schaefer
@ 2021-08-24 17:33  0%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2021-08-24 17:33 UTC (permalink / raw)
  To: Zsh hackers list

On Tue, Aug 24, 2021 at 10:29 AM Bart Schaefer
<schaefer@brasslantern.com> wrote:
>
> On Tue, Aug 24, 2021 at 9:24 AM Vincent Lefevre <vincent@vinc17.net> wrote:
> >
> > However, with "emulate sh", ignored traps should still be ignored
> > in the subshell according to POSIX, and zsh 5.8 fails do conform:
>
> "emulate sh" is NOT the same as "ARGV0=sh", and is never going to be.

However, it appears this behavior isn't covered in regular sh emulation either:

% ARGV0=sh Src/zsh -c 'trap "" INT; trap; echo A; ( trap; echo B;
sleep 3; ); echo $?'
trap -- '' INT
A
B
^C130

So we should look into this.


^ permalink raw reply	[relevance 0%]

* Re: [BUG] ignored trap and subshell
  2021-08-24 16:23  3% [BUG] ignored trap and subshell Vincent Lefevre
@ 2021-08-24 17:29  0% ` Bart Schaefer
  2021-08-24 17:33  0%   ` Bart Schaefer
  2021-08-25 10:10  0% ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2021-08-24 17:29 UTC (permalink / raw)
  To: Zsh hackers list

On Tue, Aug 24, 2021 at 9:24 AM Vincent Lefevre <vincent@vinc17.net> wrote:
>
> However, with "emulate sh", ignored traps should still be ignored
> in the subshell according to POSIX, and zsh 5.8 fails do conform:

"emulate sh" is NOT the same as "ARGV0=sh", and is never going to be.
We make no representation that "emulate sh" will enable all the same
standards behaviors as using "sh" as the command name.

That said, it might be possible to add control of this behavior to the
POSIX_TRAPS option, in which case it would be covered by "emulate sh".


^ permalink raw reply	[relevance 0%]

* [BUG] ignored trap and subshell
@ 2021-08-24 16:23  3% Vincent Lefevre
  2021-08-24 17:29  0% ` Bart Schaefer
  2021-08-25 10:10  0% ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Vincent Lefevre @ 2021-08-24 16:23 UTC (permalink / raw)
  To: zsh-workers

The zshmisc(1) man page says:

    ( list )
        Execute list in a subshell.  Traps set by the trap builtin are
        reset to their default values while executing list.

However, with "emulate sh", ignored traps should still be ignored
in the subshell according to POSIX, and zsh 5.8 fails do conform:

$ zsh -c 'emulate sh; trap "" INT; trap; echo A; ( trap; echo B; sleep 3; ); echo $?'
trap -- '' INT
A
B
^C130

where Ctrl-C immediately interrupts the sleep.

Compare to sh:

$ sh -c 'trap "" INT; trap; echo A; ( trap; echo B; sleep 3; ); echo $?'
trap -- '' INT
A
trap -- '' INT
B
^C0

where the sleep isn't interrupted by Ctrl-C.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 3%]

* Re: bug: nested for loop body is executed once!
  @ 2021-08-13  3:50  3% ` Lawrence Velázquez
  0 siblings, 0 replies; 200+ results
From: Lawrence Velázquez @ 2021-08-13  3:50 UTC (permalink / raw)
  To: Daniil Iaitskov; +Cc: zsh-workers

On Thu, Aug 12, 2021, at 11:13 PM, Daniil Iaitskov wrote:
> I just spot a following bug on Big Sur zsh 5.8 (x86_64-apple-darwin20.0)

It's not a bug.

> > $ K="1 2 3"
> > $ for i in $(for j in $K; do echo "ddd/$j" ; done) ; do echo  "$i" ; done
> > ddd/1
> > 2
> > 3
> 
> I would expect following output
> > ddd/1
> > ddd/2
> > ddd/3

By default, zsh does not word-split unquoted parameter expansions;
this behavior differs from most Bourne-adjacent shells.  Observe
that your "inner" loop actually only loops once, with $j taking on
the entire value of $K:

    % K="1 2 3"
    % for j in $K; do echo "<ddd/$j>"; done
    <ddd/1 2 3>

However, zsh *does* word-split unquoted command substitutions, so
the output of $(for j in $K; do echo "ddd/$j" ; done) is split into
'ddd/1', '2', and '3', and $i takes on each value in turn.

> > $ for i in $(for j in $(echo 1 2 3); do echo "ddd/$j" ; done) ; do echo  "$i" ; done
> 
> produce expected output:
> > ddd/1
> > ddd/2
> > ddd/3

In this example, $(echo 1 2 3) is word-split because it is a command
substitution.  Thus, $j takes on the values '1', '2', and '3', as
you expected.

> I don't know if this is a feature due to some legacy optimizations.
> I mostly use BASH and this behavior differs from BASH.
> BASH behaves exactly as I expect.

Actually, many zsh users consider the word-splitting of unquoted
parameter expansions to be a misfeature, which zsh's default behavior
remedies.  In any case, it's very much intentional.  You can obtain
word-splitting behavior with the ${=foo} form:

    % K="1 2 3"
    % for j in ${=K}; do echo "<ddd/$j>"; done
    <ddd/1>
    <ddd/2>
    <ddd/3>

You can also set SH_WORD_SPLIT, or rewrite the code to use an array.
If you're running code that relies on word-splitting (a POSIX script,
perhaps), you can run it under sh emulation.

> Wow! Are you still using just a mailing list for bug tracking?!

Yes.

-- 
vq


^ permalink raw reply	[relevance 3%]

* Re: read -r flag not working on 5.8.1
  @ 2021-08-08 14:04  5%     ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2021-08-08 14:04 UTC (permalink / raw)
  To: Mikael Magnusson; +Cc: David Milum, zsh-workers

2021-08-08 07:59:20 +0200, Mikael Magnusson:
[...]
> >> Hello, seems like the -r (raw mode) flag which should prevent it from
> >> interpreting backslashes is not working? My understanding is the
> >> following
> >> example shouldn't clear the "CLEAR" part. I can also demonstrate with new
> >> lines.
> >>
> >> $ read -r TEST
> >> asd\c CLEAR
> >> $ echo $TEST
> >> asd
> >> $ zsh --version
> >> zsh 5.8 (x86_64-pc-linux-gnu)
> 
> Your problem is not read, but echo. Try the above with echo -E $TEST
> instead and you will see the read command is fine.
[...]

More precisely, to print the contents of a scalar variable
verbatim followed by a newline character in zsh:

echo -E - $var # zsh only
print -r - $var # zsh
print -r -- $var # zsh
print -r - "$var" # zsh/ksh
printf '%s\n' "$var" # POSIX
echo -En "$var"$'\n' # zsh/bash and a few other echo
		     # implementations (but for bash, not if
		     # both the xpg_echo and posix options are
		     # enabled).
cat << EOF  # Bourne/POSIX
$var
EOF
cat <<< "$var" # zsh and a few other shells

See also

zmodload zsh/system
syswrite -- "$var"$'\n' ||
  syserror -p failed: $ERRNO

for a raw interface to the write() system call.

And btw, to read a line into a variable, the syntax is

IFS= read -r var

(in zsh or any other POSIX shell, though only zsh can read lines
containing NUL bytes).

See

https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo
https://unix.stackexchange.com/questions/209123/understanding-ifs-read-r-line

-- 
Stephane


^ permalink raw reply	[relevance 5%]

* PATCH: use singular form for completion group descriptions for consistency
@ 2021-07-06 23:53  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2021-07-06 23:53 UTC (permalink / raw)
  To: Zsh workers

When fixing one small thing in a completion function, it can be hard
to resist the temptation to clean up lots of other issues. Resulting
patches likely aren't easy to review. So I'll try the opposite tack for
a few particular issues that can be corrected across many functions. I
don't know if this is any easier for anyone else to digest? It is still
a patch touching many files but it mostly only does one thing.

The convention we generally use for the headings on completion match
groups is to use the singular form. I assume the original rationale is
that only one value gets completed (even if it forms one of a list). But
for the purposes of this patch, the rationale is consistency.

I was using grep to find plural descriptions so relied on most English
plurals ending in an s. I tried to avoid making other changes but have
corrected indentation, capitalised descriptions and fixed the tag where
tag and description were transposed (e.g. with _alternative). Also,
there were cases where the plural was indicative that a list was allowed
and _dir_list or _sequence could be used so I did correct that.

A common case that I didn't bother with is unused descriptions on
states, such as '*::args:->state'

Oliver

diff --git a/Completion/BSD/Command/_portmaster b/Completion/BSD/Command/_portmaster
index 48390c9ad..ee6fefc6e 100644
--- a/Completion/BSD/Command/_portmaster
+++ b/Completion/BSD/Command/_portmaster
@@ -8,11 +8,11 @@ _portmaster_ports() {
   local expl ret=1 _fbsd_ports _fbsd_cat
    _fbsd_cat=(${PORTSDIR:-/usr/ports}/[a-z]*(/:t))
    if [[ $PREFIX != */* ]] ; then
-     _wanted cat_packages expl 'category/ports' compadd -S '/' $_fbsd_cat
+     _wanted cat_packages expl 'category/port' compadd -S '/' $_fbsd_cat
    else
      compset -P '*/'
      _fbsd_ports=(${PORTSDIR:-/usr/ports}/$IPREFIX/*(/:t))
-     _wanted cat_packages expl 'category/ports' compadd $_fbsd_ports
+     _wanted cat_packages expl 'category/port' compadd $_fbsd_ports
    fi
   return ret
 }
@@ -77,7 +77,7 @@ _portmaster() {
       _arguments -s \
       $standalone_args \
       $common_args \
-      '*:packages and ports:_portmaster_pkgs_and_ports'
+        '*:package or port:_portmaster_pkgs_and_ports'
     else 
       case "$words[2]" in
 	--clean-distfiles|--clean-distfiles-all|--check-depends|--check-port-dbdir|--version|-help|-h)
@@ -86,14 +86,14 @@ _portmaster() {
 	*)
 	if (( $words[(I)-(e|r)] ));then
 	  _arguments -s \
-	  '*:packages:_portmaster_pkgs'
+            '*:package:_portmaster_pkgs'
 	elif (( kid=$words[(I)-o] ));then
 	  if (( CURRENT == $kid + 1 ));then
 	    _arguments -s \
-	    '*:ports replacing:_portmaster_ports'
+              '*:replacement port:_portmaster_ports'
 	  elif (( CURRENT == $kid + 2 )); then
 	    _arguments -s \
-	    '*:package to replace:_portmaster_pkgs'
+              '*:package to replace:_portmaster_pkgs'
 	  else 
 	    return 0
 	  fi
@@ -102,7 +102,7 @@ _portmaster() {
 	else
 	  _arguments -s \
 	  $common_args \
-	  '*:packages and ports:_portmaster_pkgs_and_ports'
+            '*:package or port:_portmaster_pkgs_and_ports'
 	fi
 	;;
       esac
diff --git a/Completion/BSD/Command/_sysrc b/Completion/BSD/Command/_sysrc
index f0c12a2be..892dac407 100644
--- a/Completion/BSD/Command/_sysrc
+++ b/Completion/BSD/Command/_sysrc
@@ -29,7 +29,7 @@ _sysrc() {
     '(- *)-h[print short usage message]' \
     '(- *)--help[print full usage message]' \
     '-i[ignore unknown variables]' \
-    '-j+[jail to operate within]:jails:_jails' \
+    '-j+[jail to operate within]:jail:_jails' \
     '-n[print only variable values]' \
     '-N[print only variable names]' \
     '-R+[specify an alternative root]:alternative root:_files -/' \
diff --git a/Completion/BSD/Command/_systat b/Completion/BSD/Command/_systat
index 7d837790a..03df07631 100644
--- a/Completion/BSD/Command/_systat
+++ b/Completion/BSD/Command/_systat
@@ -84,7 +84,7 @@ esac
 
 if (( $#screens )); then
   _arguments -M 'r:|.=* r:|=*' : $opts \
-    '1:systat(1) displays:(( ${pre}$^screens ))' \
+    '1:systat(1) display:(( ${pre}$^screens ))' \
     '2:refresh interval'
   return
 fi
diff --git a/Completion/Base/Widget/_bash_completions b/Completion/Base/Widget/_bash_completions
index 7abb654d4..feb721451 100644
--- a/Completion/Base/Widget/_bash_completions
+++ b/Completion/Base/Widget/_bash_completions
@@ -32,7 +32,7 @@ local key=$KEYS[-1] expl
 case $key in
   '!') _main_complete _command_names
        ;;
-  '$') _main_complete - parameters _wanted parameters expl 'exported parameters' \
+  '$') _main_complete - parameters _wanted parameters expl 'exported parameter' \
                                        _parameters -g '*export*'
        ;;
   '@') _main_complete _hosts
diff --git a/Completion/Base/Widget/_complete_tag b/Completion/Base/Widget/_complete_tag
index 5b50f1d85..397b8d901 100644
--- a/Completion/Base/Widget/_complete_tag
+++ b/Completion/Base/Widget/_complete_tag
@@ -50,13 +50,13 @@ if [[ -f $c_path$c_Tagsfile ]]; then
         -e '/^[a-zA-Z_].*/p' $c_path$c_Tagsfile))
 #  c_tags_array=($(perl -ne '/([a-zA-Z_0-9]+)[ \t:;,\(]*\x7f/ &&
 #                  print "$1\n"' $c_path$c_Tagsfile))
-  _main_complete - '' _wanted etags expl 'emacs tags' \
+  _main_complete - '' _wanted etags expl 'emacs tag' \
       compadd -a c_tags_array
 elif [[ -f $c_path$c_tagsfile ]]; then
   # tags doesn't have as much in, but the tag is easy to find.
   # we can use awk here.
   c_tags_array=($(awk '{ print $1 }' $c_path$c_tagsfile))
-  _main_complete - '' _wanted vtags expl 'vi tags' compadd -a c_tags_array
+  _main_complete - '' _wanted vtags expl 'vi tag' compadd -a c_tags_array
 else
   return 1
 fi
diff --git a/Completion/Darwin/Command/_defaults b/Completion/Darwin/Command/_defaults
index ca5d87e65..b05222af6 100644
--- a/Completion/Darwin/Command/_defaults
+++ b/Completion/Darwin/Command/_defaults
@@ -42,7 +42,7 @@ _defaults(){
       _arguments \
         "(1)-app:application:_mac_applications" \
         "(-app)1:domain:_defaults_domains" \
-        "2:keys:_defaults_keys"
+        "2:key:_defaults_keys"
       ;;
     write)
       _arguments \
diff --git a/Completion/Darwin/Command/_hdiutil b/Completion/Darwin/Command/_hdiutil
index 04e81e655..20e69cbc5 100644
--- a/Completion/Darwin/Command/_hdiutil
+++ b/Completion/Darwin/Command/_hdiutil
@@ -10,7 +10,7 @@ _hdiutil_disk() {
       disk_desc+=( "$disk_name:${${(M)REPLY%	*}#?}" )
     fi
   done
-  _describe -t devices disks disk_desc
+  _describe -t devices disk disk_desc
 }
 
 _hdiutil_device() {
@@ -143,7 +143,7 @@ _hdiutil(){
   _arguments -C '*:: :->subcmds'
 
   if (( CURRENT == 1 )); then
-    _describe -t commands "hdiutil subcommands" _1st_arguments
+    _describe -t commands "hdiutil subcommand" _1st_arguments
     return
   fi
 
diff --git a/Completion/Darwin/Command/_softwareupdate b/Completion/Darwin/Command/_softwareupdate
index 6db577b06..6054fd768 100644
--- a/Completion/Darwin/Command/_softwareupdate
+++ b/Completion/Darwin/Command/_softwareupdate
@@ -55,7 +55,7 @@ _softwareupdate() {
       ignored_subcmd=(add remove)
 
       if (( CURRENT == 1 )); then
-        _describe -t commands "subcommands" ignored_subcmd && return 0
+        _describe -t commands "subcommand" ignored_subcmd && return 0
       fi
       case $words[1] in
         add)
diff --git a/Completion/Debian/Command/_apt b/Completion/Debian/Command/_apt
index 4d60cd249..494d3bf82 100644
--- a/Completion/Debian/Command/_apt
+++ b/Completion/Debian/Command/_apt
@@ -531,7 +531,7 @@ _apt-cache () {
     --installed:bool \
     -- \
     /$'help\0'/ \| \
-    /$'add\0'/ /$'[^\0]#\0'/ ':files:index files:_files' \# \| \
+    /$'add\0'/ /$'[^\0]#\0'/ ':files:index file:_files' \# \| \
     /$'gencaches\0'/ \| \
     /$'showpkg\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \| \
     /$'showsrc\0'/ /$'[^\0]#\0'/ ':packages::_deb_packages "$expl_packages[@]" avail' \# \| \
diff --git a/Completion/Debian/Command/_axi-cache b/Completion/Debian/Command/_axi-cache
index bdefdd979..5fd4c38f8 100644
--- a/Completion/Debian/Command/_axi-cache
+++ b/Completion/Debian/Command/_axi-cache
@@ -10,7 +10,7 @@ _arguments \
   '*:args:->args' && return 0
 
 if (( CURRENT == 2 )); then
-  _wanted tag expl 'axi-cache commands' \
+  _wanted tag expl 'axi-cache command' \
     compadd help search more last show again info \
     rdetails depends madison policy showpkg showsrc
 else
diff --git a/Completion/Debian/Command/_lintian b/Completion/Debian/Command/_lintian
index 71e71ee3d..03491624f 100644
--- a/Completion/Debian/Command/_lintian
+++ b/Completion/Debian/Command/_lintian
@@ -8,8 +8,8 @@ case "$service" in
       '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-S,--setup-lab}'[setup or update the laboratory]' \
       '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-R,--remove-lab}'[remove the laboratory directory]' \
       '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-c,--check}'[run all checks over the specified packages]' \
-      '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-C,--check-part}'[run only the specified checks]:checks:_values -s , "lintian checks" binaries bin changelog-file chg conffiles cnf control-file dctrl control-files ctl copyright-file cpy cruft deb deb-format dfmt debconf dc debdiff dif debian-readme drm debhelper dh description des etcfiles etc fields fld files fil huge-usr-share hus infofiles info init.d ini manpages man md5sums md5 menus men menu-format mnf perl prl po-debconf pd scripts scr shared-libs shl spelling splr standards-version std' \
-      '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-X,--dont-check-part}'[run only the specified checks]:checks:_values -s , "lintian checks" binaries bin changelog-file chg conffiles cnf control-file dctrl control-files ctl copyright-file cpy cruft deb deb-format dfmt debconf dc debdiff dif debian-readme drm debhelper dh description des etcfiles etc fields fld files fil huge-usr-share hus infofiles info init.d ini manpages man md5sums md5 menus men menu-format mnf perl prl po-debconf pd scripts scr shared-libs shl spelling splr standards-version std' \
+      '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-C,--check-part}'[run only the specified checks]: :_values -s , "lintian check" binaries bin changelog-file chg conffiles cnf control-file dctrl control-files ctl copyright-file cpy cruft deb deb-format dfmt debconf dc debdiff dif debian-readme drm debhelper dh description des etcfiles etc fields fld files fil huge-usr-share hus infofiles info init.d ini manpages man md5sums md5 menus men menu-format mnf perl prl po-debconf pd scripts scr shared-libs shl spelling splr standards-version std' \
+      '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-X,--dont-check-part}'[run only the specified checks]: :_values -s , "lintian check" binaries bin changelog-file chg conffiles cnf control-file dctrl control-files ctl copyright-file cpy cruft deb deb-format dfmt debconf dc debdiff dif debian-readme drm debhelper dh description des etcfiles etc fields fld files fil huge-usr-share hus infofiles info init.d ini manpages man md5sums md5 menus men menu-format mnf perl prl po-debconf pd scripts scr shared-libs shl spelling splr standards-version std' \
       '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-u,--unpack}'[unpack up to unpack level]' \
       '(-c -r -u -C -R -S -X --check --check-part --dont-check-part --remove --remove-lab --setup-lab --unpack)'{-r,--remove}'[clean packages up to current unpack level]' \
       '(-h --help)'{-h,--help}'[help]' \
@@ -23,7 +23,7 @@ case "$service" in
       '(-o --no-override)'{-o,--no-override}'[do not use the overrides file]' \
       '--show-overrides[output tags that have been overridden]' \
       '--color:when:(never always auto)' \
-      '(-U --unpack-info)'{-U,--unpack-info}'[collect information]:info:_values -s , "collectibles" changelog-file copyright-file debfiles debian-readme diffstat doc-base-files file-info init.d md5sums menu-files objdump-info override-file scripts source-control-file' \
+      '(-U --unpack-info)'{-U,--unpack-info}'[collect information]:info:_values -s , "collectible" changelog-file copyright-file debfiles debian-readme diffstat doc-base-files file-info init.d md5sums menu-files objdump-info override-file scripts source-control-file' \
       '(-m --md5sums)'{-m,--md5sums}'[check md5sums when processing a .changes file]' \
       '--allow-root[override warning when run with superuser privileges]' \
       '--cfg:config file:_files' \
diff --git a/Completion/Debian/Command/_module-assistant b/Completion/Debian/Command/_module-assistant
index d75284954..b2c1e56ee 100644
--- a/Completion/Debian/Command/_module-assistant
+++ b/Completion/Debian/Command/_module-assistant
@@ -33,5 +33,5 @@ _arguments -A \
   '(-k --kernel-dir)'{-k,--kernel-dir}'[list of kernel headers/source directories, comma separated]:list of dirs:_files -/' \
   '(-t --text-mode)'{-t,--text-mode}'[no progress bars]' \
   '1:list of commands:_values -s , subcommands "${_module_assistant_commands[@]}"' \
-  '*:packages: compadd /usr/src/modass/var_cache_modass/*.avail_version(N:t:r) /var/cache/modass/*.avail_version(N:t:r)'
+  '*:package: compadd /usr/src/modass/var_cache_modass/*.avail_version(N:t:r) /var/cache/modass/*.avail_version(N:t:r)'
 
diff --git a/Completion/Linux/Command/_fusermount b/Completion/Linux/Command/_fusermount
index 02cb57237..41d3dec72 100644
--- a/Completion/Linux/Command/_fusermount
+++ b/Completion/Linux/Command/_fusermount
@@ -6,7 +6,7 @@ typeset -A opt_args
 _arguments \
   '-h[display help information]' \
   '-V[display version information]' \
-  '-o[specify mount options]:mount options:_fuse_values "mount options"' \
+  '-o[specify mount options]:mount option:_fuse_values "mount option"' \
   '-u[unmount a fuse mount]' \
   '-z[unmount lazily (work even when if the resource is still busy)]' \
   '-q[suppress nonessential output]' \
diff --git a/Completion/Linux/Command/_ipset b/Completion/Linux/Command/_ipset
index d05f13caf..061d16799 100644
--- a/Completion/Linux/Command/_ipset
+++ b/Completion/Linux/Command/_ipset
@@ -25,7 +25,7 @@ _set_types () {
 _ipsets () {
 	local -a vals
 	vals=( ${${(M)${(f)"$(_call_program ipsets ipset -L)"}%Name: *}#Name: } )
-	_describe -t ipsets "IP sets" vals
+	_describe -t ipsets "IP set" vals
 }
 _sets () {
 	_ipsets
@@ -118,7 +118,7 @@ _ips () {
 			if (( $ips )); then vals1+=$i; else bindings+=${i/ ->/:}; fi
 		done
 		_describe -t ips "IPs from $words[offset+3] set" vals1
-		_describe -t special_values "special values" vals2
+		_describe -t special_values "special value" vals2
 	fi
 }
 
diff --git a/Completion/Linux/Command/_mdadm b/Completion/Linux/Command/_mdadm
index b6dce7ccb..5b73ef4be 100644
--- a/Completion/Linux/Command/_mdadm
+++ b/Completion/Linux/Command/_mdadm
@@ -156,7 +156,7 @@ _mds () {
 	  return 1
 	fi
 	vals=( ${${${(M)${(f)"$(< $mdadm_conf)"}##ARRAY *}//ARRAY /}%%[[:blank:]]*} )
-	_describe -t mds "RAID devices" vals
+	_describe -t mds "RAID device" vals
 	_arguments \
 		"(-h --help)"{-h,--help}'[display a mode specific help message]'
 }
diff --git a/Completion/Linux/Command/_sysstat b/Completion/Linux/Command/_sysstat
index e091dd3ea..4de855b69 100644
--- a/Completion/Linux/Command/_sysstat
+++ b/Completion/Linux/Command/_sysstat
@@ -96,12 +96,12 @@ _sar() {
     '(--human -p)-h[make output easier to read: implies --human and -p]' \
     '(- 1 2)--help[display usage information]' \
     '--human[print sizes in human readable format]' \
-    '*-I[report statistics for interrupts]:interrupts: _values -s "," interrupts 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 SUM ALL XALL' \
+    '*-I[report statistics for interrupts]: : _values -s "," interrupt 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 SUM ALL XALL' \
     '-i[select records as close as possible to interval]:interval' \
     '--iface=-[specify network interfaces for which statistics are to be displayed]:network interface:_sequence _net_interfaces' \
     '-j[display persistent device names]:type:(ID LABEL PATH UUID)' \
-    '-m[report power management statistics]:keywords: _values -s "," keywords CPU FAN FREQ IN TEMP USB ALL' \
-    '-n[report network statistics]:keywords: _values -s "," keywords DEV EDEV NFS NFSD SOCK IP EIP ICMP EICMP TCP ETCP UDP SOCK6 IP6 EIP6 ICMP6 EICMP6 UDP6 FC SOFT ALL' \
+    '-m[report power management statistics]:keyword:_sequence compadd - CPU FAN FREQ IN TEMP USB ALL' \
+    '-n[report network statistics]:keyword:_sequence compadd - DEV EDEV NFS NFSD SOCK IP EIP ICMP EICMP TCP ETCP UDP SOCK6 IP6 EIP6 ICMP6 EICMP6 UDP6 FC SOFT ALL' \
     '-o[save readings to file in binary form]:file:_files' \
     '-P[report per-processor statistics]:processor: _values -s "," processors ALL' \
     '-p[pretty-print device names]' \
diff --git a/Completion/Linux/Type/_fuse_values b/Completion/Linux/Type/_fuse_values
index be830cb40..211eb5b35 100644
--- a/Completion/Linux/Type/_fuse_values
+++ b/Completion/Linux/Type/_fuse_values
@@ -47,7 +47,7 @@ fvals=(
 [[ -n $cvalsvar ]] && set -- "$@" ${(P)cvalsvar}
 
 if [[ $# -eq 0 ]]; then
-  set -- 'mount options' $fvals
+  set -- 'mount option' $fvals
 else
   set -- "$@" $fvals
 fi
diff --git a/Completion/Mandriva/Command/_urpmi b/Completion/Mandriva/Command/_urpmi
index d897f2c4b..9ab9e45b7 100644
--- a/Completion/Mandriva/Command/_urpmi
+++ b/Completion/Mandriva/Command/_urpmi
@@ -286,7 +286,7 @@ _urpmi() {
 	"($help --all --interactive  --name)--summary[print tag summary: summary]" \
 	"($help)--uniq[do not print identical lines]" \
 	"($help --all --interactive  --name)--url[print tag url: url]" \
-	"*:hdlist files:_files -g '*.cz(-.)'" \
+	"*:hdlist file:_files -g '*.cz(-.)'" \
       && ret=0
     ;;
   esac
diff --git a/Completion/Redhat/Command/_yum b/Completion/Redhat/Command/_yum
index a30aa579f..9425ba57c 100644
--- a/Completion/Redhat/Command/_yum
+++ b/Completion/Redhat/Command/_yum
@@ -167,7 +167,7 @@ _yumdb() {
 
       if [ "$cmd" = "help" ]; then
         if (( CURRENT == 2 )); then
-          _describe -t commands 'yum commands' _yum_cmds && ret=0
+          _describe -t commands 'yum command' _yum_cmds && ret=0
         else
           # help takes one argument
           _message 'no more arguments'
diff --git a/Completion/Solaris/Command/_coreadm b/Completion/Solaris/Command/_coreadm
index 7262e6423..655b48e63 100644
--- a/Completion/Solaris/Command/_coreadm
+++ b/Completion/Solaris/Command/_coreadm
@@ -40,6 +40,6 @@ _arguments -s \
   - set2 \
   '-p[PID-specific per-process core file name pattern]:' \
   '-P[PID-specific per-process core file content]:content:_values -s + "content" $content' \
-  '*:pids:_pids' \
+  '*:pid:_pids' \
   - set3 \
   '-u[update options from coreadm.conf]'
diff --git a/Completion/Solaris/Type/_svcs_fmri b/Completion/Solaris/Type/_svcs_fmri
index ffade6985..b090461c5 100644
--- a/Completion/Solaris/Type/_svcs_fmri
+++ b/Completion/Solaris/Type/_svcs_fmri
@@ -66,18 +66,18 @@ _svcs_fmri() {
 		# _wanted fmri expl "full or unambiguously abbreviated FMRIs" \
 		# 	_multi_parts -i / fmri_abbrevs
 
-		_wanted fmri expl "full or unambiguously abbreviated FMRIs" \
+		_wanted fmri expl "full or unambiguously abbreviated FMRI" \
 			compadd $fmri_abbrevs
 		;;
 
 	(-m)
-		_wanted fmri expl "milestone FMRIs" \
+		_wanted fmri expl "milestone FMRI" \
 			compadd $(svcs -H -o fmri svc:/milestone/\*) all
 		;;
 
 	(-r)
 		# TODO: need some way to pick out only restarters
-		_wanted fmri expl "restarter FMRIs" \
+		_wanted fmri expl "restarter FMRI" \
 			compadd master reset svc:/network/inetd:default
 		;;
 
diff --git a/Completion/Unix/Command/_ack b/Completion/Unix/Command/_ack
index e83a9330e..6dc3ab0d1 100644
--- a/Completion/Unix/Command/_ack
+++ b/Completion/Unix/Command/_ack
@@ -72,7 +72,7 @@ _arguments -C -s -S \
   '(1)-g[print files where the relative path + filename matches the given pattern]:pattern to match against filenames' \
   '--sort-files[sorts the found files lexically]' \
   '--show-types[print the file types that ack associates with each file]' \
-  '(--files-from -x)--files-from=[read the list of files to search from specified file]:files:_files' \
+  '(--files-from -x)--files-from=[read the list of files to search from specified file]:file:_files' \
   '(-x --files-from)-x[read the list of files to search from standard input]' \
   '*--ignore-dir'{,ectory}'=[ignore directory]:directory:_directories' \
   '*--noignore-dir'{,ectory}'=[remove directory from ignored list]:directory:_directories' \
@@ -86,7 +86,7 @@ _arguments -C -s -S \
   '*--type-'{add,set}'=[files with the given extensions are recognized as being of the given type]:type-def:->type-defs' \
   '*--type-del=[remove all filters associated with specified file type]: :->file-types' \
   '(--env)--noenv[ignore environment variables and global ackrc files]' '!(--noenv)--env)' \
-  '--ackrc=[specify an ackrc file to use]:files:_files' \
+  '--ackrc=[specify an ackrc file to use]:file:_files' \
   '--ignore-ack-defaults[ignore default definitions included with ack]' \
   "${ign}(- 1 *)--create-ackrc[output an ackrc based on customizations]" \
   "${ign}(- 1 *)"{-\?,--help}'[display usage information]' \
diff --git a/Completion/Unix/Command/_adb b/Completion/Unix/Command/_adb
index 75a447dfc..21cd68761 100644
--- a/Completion/Unix/Command/_adb
+++ b/Completion/Unix/Command/_adb
@@ -85,7 +85,7 @@ _adb() {
 	'-s[serial]: :_adb_device_serial' \
 	'(   -e)-d[device]' \
 	'(-d   )-e[emulator]' \
-	'1:options:_adb_options_handler' \
+	'1:option:_adb_options_handler' \
 	'*: : _default'
       
       return
@@ -141,7 +141,7 @@ _adb_dispatch_command () {
 	'(-d -e)-s[serial]: :_adb_device_serial' \
 	'(-s -e)-d[device]' \
 	'(-d -s)-e[emulator]' \
-	'*:options:_adb_options_handler'
+	'*:option:_adb_options_handler'
       ;;
   esac
 }
@@ -392,7 +392,7 @@ _adb_check_log_redirect () {
 
 (( $+functions[_adb_trace_opts] )) ||
 _adb_trace_opts() {
-  _values -s , 'adb trace options' \
+  _values -s , 'adb trace option' \
 	'(1 adb sockets packets rwx usb sync sysdeps transport jdwp)all' \
 	'(all adb sockets packets rwx usb sync sysdeps transport jdwp)1' \
 	'adb' \
@@ -418,7 +418,7 @@ _adb_device_serial() {
       devices[(i)${device%:*}:*]=$device
     fi
   done
-  _describe -t dev_serial 'available devices' devices
+  _describe -t dev_serial 'available device' devices
 }
 
 (( $+functions[_adb_logcat_filter_specification] )) ||
@@ -459,13 +459,13 @@ _adb_dispatch_logcat() {
 (( $+functions[_adb_options_handler] )) ||
 _adb_options_handler() {
   local expl
-  _wanted adb_options expl 'adb options' compadd "${ALL_ADB_COMMANDS[@]}"
+  _wanted adb_options expl 'adb option' compadd "${ALL_ADB_COMMANDS[@]}"
 }
 
 (( $+functions[_adb_shell_commands_handler] )) ||
 _adb_shell_commands_handler() {
   local expl
-  _wanted adb_shell_commands expl 'adb shell commands' compadd ls pm am mkdir rmdir rm cat 
+  _wanted adb_shell_commands expl 'adb shell command' compadd ls pm am mkdir rmdir rm cat
 }
 
 (( $+functions[_adb_device_available] )) ||
@@ -514,7 +514,7 @@ _adb_installed_packages() {
 _adb_users() {
   local -a users
   users=( ${${${(M)${(f)"$(adb shell pm list users)"}:#*UserInfo*}#*UserInfo\{}%:*} )
-  _describe -t users 'users' users
+  _describe -t users 'user' users
 }
 
 (( $+functions[_adb_cache_policy_single_command] )) ||
diff --git a/Completion/Unix/Command/_baz b/Completion/Unix/Command/_baz
index 6787f41e2..4dfcdf882 100644
--- a/Completion/Unix/Command/_baz
+++ b/Completion/Unix/Command/_baz
@@ -38,8 +38,8 @@ _baz_revisions () { _arch_namespace baz 4 "$argv[@]" }
 (( $+functions[_baz_local_revisions] )) ||
 _baz_local_revisions () {
   local expl1 expl2 tree_version=`$BAZ tree-version`
-  _description -V applied-patches expl1 "patches from this version"
-  _description -V other-patches expl2 "patches from other versions"
+  _description -V applied-patches expl1 "patch from this version"
+  _description -V other-patches expl2 "patch from other versions"
   compadd "$expl1[@]" `$BAZ logs`
   compadd "$expl2[@]" `$BAZ logs --full $($BAZ log-versions | grep -v $tree_version)`
   # This is incredibly slow.
@@ -82,7 +82,7 @@ _baz_limit () { #presently only does push-mirror style limits
 
     if [[ $PREFIX != *--* ]]; then
       _description -V categories expl "categories in $archive"
-      compadd -q -S -- "$expl[@]" `$BAZ categories $archive`
+      compadd -q -S -- "$expl[@]" `$BAZ category $archive`
     else
       _baz_namespace_branches 3
     fi
@@ -98,7 +98,7 @@ _baz_tree_or_rev () {
 _baz_libraries () {
   local libraries expl
   libraries=($(_call_program baz $BAZ my-revision-library))
-  _description -V libraries expl "revision libraries"
+  _description -V libraries expl "revision library"
   compadd "$expl[@]" -a libraries
 }
 
@@ -115,7 +115,7 @@ _baz_my_revision_library () {
 _baz_log_versions () {
   local logs expl
   logs=($(_call_program baz $BAZ log-versions))
-  _description -V versions expl "log versions"
+  _description -V versions expl "log version"
   compadd "$expl[@]" -a logs
 }
 
@@ -238,12 +238,12 @@ methods=(
 cmd_tagging_method=($cmd_id_tagging_method)
 
 local cmd_add cmd_add_id cmd_add_tag
-cmd_add=('*:files to add:_files')
+cmd_add=('*:file to add:_files')
 cmd_add_id=($cmd_add)
 cmd_add_tag=($cmd_add)
 
 local cmd_delete cmd_delete_id cmd_delete_tag
-cmd_delete=('*:files to delete:_files')
+cmd_delete=('*:file to delete:_files')
 cmd_delete_id=($cmd_delete)
 cmd_delete_tag=($cmd_delete)
 
@@ -272,7 +272,7 @@ cmd_changeset=(
   ':ORIG:_files -/'
   ':MOD:_files -/'
   ':DEST:_files -/'
-  '*:files:_files'
+  '*:file:_files'
 )
 cmd_mkpatch=("$cmd_changeset[@]")
 
@@ -288,7 +288,7 @@ local cmd_make_archive
 cmd_make_archive=('::name:' ':location:_files -/')
 
 local cmd_archive_setup
-cmd_archive_setup=('*:versions:_baz_branches --trailing-dashes')
+cmd_archive_setup=('*:version:_baz_branches --trailing-dashes')
 
 local cmd_make_category
 cmd_make_category=(':category:_baz_archives -S /')
@@ -304,7 +304,7 @@ cmd_import=('::version:_baz_versions')
 cmd_imprev=($cmd_import)
 
 local cmd_commit cmd_cmtrev
-cmd_commit=('*:files:_files')
+cmd_commit=('*:file:_files')
 cmd_cmtrev=($cmd_commit)
 
 local cmd_get cmd_getrev
@@ -573,7 +573,7 @@ _baz_main () {
     local -U cmds
     help=(${(f)"$($BAZ help)"})
     cmds=(${${${${(M)help:#* :*}/ #: #/:}%% ##}## #})
-    arguments=(':commands:(($cmds))')
+    arguments=(':command:(($cmds))')
   fi
   _arguments -S -A '-*' \
     {"${hide_short}(: -)-V",'(: -)--version'}'[display version]' \
diff --git a/Completion/Unix/Command/_bzr b/Completion/Unix/Command/_bzr
index 1b755b4ec..121c28166 100644
--- a/Completion/Unix/Command/_bzr
+++ b/Completion/Unix/Command/_bzr
@@ -65,7 +65,7 @@ case $cmd in
 	'--no-recurse[do not recurse into subdirectories]'
 	'(-q --quiet -v --verbose)'{--quiet,-q}'[be quiet]'
 	'(-v --verbose -q --quiet)'{--verbose,-v}'[display more information]'
-	'*:unknown files:_bzr_unknownFiles'
+	'*:unknown file:_bzr_unknownFiles'
 	)
     ;;
 
@@ -74,7 +74,7 @@ case $cmd in
 	'--all[show annotations on all lines]'
 	'--long[show date in annotations]'
 	'(-r --revision)'{--revision=,-r}'[the revision to show]:rev:'
-	'*:files:_bzr_versionedFiles'
+	'*:file:_bzr_versionedFiles'
 	)
     ;;
 
@@ -100,7 +100,7 @@ case $cmd in
 
 (rename|move|mv)
     if (( CURRENT == 2 )); then
-	args+=( '*:files:_bzr_versionedFiles' )
+	args+=( '*:file:_bzr_versionedFiles' )
     else
 	args=( '*:destination dir:_files -/' )
     fi
@@ -218,7 +218,7 @@ case $cmd in
 	'--unchanged[include unchanged files]'
 	'(-q --quiet -v --verbose)'{--quiet,-q}'[be quiet]'
 	'(-v --verbose -q --quiet)'{--verbose,-v}'[display more information]'
-	'*:modified files:_bzr_modifiedFiles'
+	'*:modified file:_bzr_modifiedFiles'
 	)
     ;;
 
@@ -229,7 +229,7 @@ case $cmd in
 	'--all[shelve all changes]'
 	'(-q --quiet)'{--quiet,-q}'[be quiet]'
 	'(-v --verbose)'{--verbose,-v}'[display more information]'
-	'*:modified files:_bzr_modifiedFiles'
+	'*:modified file:_bzr_modifiedFiles'
 	)
     ;;
 
@@ -279,7 +279,7 @@ case $cmd in
 	'(-r --revision)'{--revision=,-r}'[revision]:revision:'
 	'--diff-options=[options to pass to gdiff]:diff options:'
 	'(-p --prefix)'{--prefix,-p}'[set prefix added to old and new filenames]'
-	'*:files:_files'
+	'*:file:_files'
 	)
     ;;
 
@@ -376,7 +376,7 @@ case $cmd in
     args+=(
 	'--all[show annotations on all lines]'
 	"--plain[don't highlight annotation lines]"
-	'*:files:_bzr_versionedFiles'
+	'*:file:_bzr_versionedFiles'
 	)
     ;;
 
diff --git a/Completion/Unix/Command/_ctags b/Completion/Unix/Command/_ctags
index 3c80ba1c5..e2b28011b 100644
--- a/Completion/Unix/Command/_ctags
+++ b/Completion/Unix/Command/_ctags
@@ -147,7 +147,7 @@ if [ "$_ctags_type" = "universal" ]; then
     "--roles--[enable/disable tag roles for kinds of <lang>]:language:->languagedot"
     "--sort=-[should tags be sorted]:argument:(yes no foldcase)"
     "--tag-relative=-[should paths be relative to location of tag file]:argument:(yes no always never)"
-    "--totals=-[print stats about input and tag files]:arguments:(yes no extra)"
+    "--totals=-[print stats about input and tag files]:argument:(yes no extra)"
     "(--verbose -V)--verbose=-[enable verbose messages describing actions]:bool:(yes no)"
     "(--verbose -V)-V[enable verbose messages describing actions]"
     "--version[print version]"
@@ -196,7 +196,7 @@ elif [ "$_ctags_type" = "exuberant" ]; then
     "--regex--[define regex for locating tags in specific lang]:language:->language"
     "--sort=-[should tags be sorted]:argument:(yes no foldcase)"
     "--tag-relative=-[should paths be relative to location of tag file]:argument:(yes no)"
-    "--totals=-[print stats about input and tag files]:arguments:(yes no)"
+    "--totals=-[print stats about input and tag files]:argument:(yes no)"
     "(--verbose -V)--verbose=-[enable verbose messages describing actions]:bool:(yes no)"
     "(--verbose -V)-V[enable verbose messages describing actions]"
     "--version[print version]"
diff --git a/Completion/Unix/Command/_cvs b/Completion/Unix/Command/_cvs
index cba3eb773..4dc5b6c60 100644
--- a/Completion/Unix/Command/_cvs
+++ b/Completion/Unix/Command/_cvs
@@ -371,10 +371,10 @@ _cvs_log() {
     '-R[print the name of RCS file in the repository]' \
     '-N[don'\''t list tags]' \
     '(-h)-t[header with descriptive text]' \
-    '-d+[specify dates]:dates' \
+    '-d+[specify dates]:date range' \
     '-r-[specify revisions]:revisions' \
-    '-s+[specify states]:states:(Exp Stab Rel dead)' \
-    '-w-[specify logins]:logins' \
+    '-s+[specify states]:state:_sequence compadd - Exp Stab Rel dead' \
+    '-w-[specify logins]:login list' \
     '*:file:_cvs_files'
 }
 
@@ -388,10 +388,10 @@ _cvs_rlog() {
     '(-l)-R[recursive]' \
     '-N[don'\''t list tags]' \
     '(-h)-t[header with descriptive text]' \
-    '-d+[specify dates]:dates' \
+    '-d+[specify dates]:date range' \
     '-r-[specify revisions]:revisions' \
-    '-s+[specify states]:states:(Exp Stab Rel dead)' \
-    '-w-[specify logins]:logins' \
+    '-s+[specify states]:state:_sequence compadd - Exp Stab Rel dead' \
+    '-w-[specify logins]:login list' \
     '*:file:_cvs_modules'
 }
 
diff --git a/Completion/Unix/Command/_ecasound b/Completion/Unix/Command/_ecasound
index a39e426db..5fd9055a7 100644
--- a/Completion/Unix/Command/_ecasound
+++ b/Completion/Unix/Command/_ecasound
@@ -102,9 +102,9 @@ case $state in
     elif compset -P '*,*,'; then
       _message 'sampling rate'
     elif compset -P '*,'; then
-      _message 'channels'
+      _message 'channel'
     else
-      _values 'sampling parameters' \
+      _values 'sampling parameter' \
         'u8[unsigned 8-bit]' \
 	's16_le[signed 16-bit little endian]' \
 	's16_be[signed 16-bit big endian]' \
diff --git a/Completion/Unix/Command/_fetchmail b/Completion/Unix/Command/_fetchmail
index 31a92d984..bc5a39688 100644
--- a/Completion/Unix/Command/_fetchmail
+++ b/Completion/Unix/Command/_fetchmail
@@ -4,7 +4,7 @@ _arguments -S \
   {--bsmtp,'(--logfile)-L','(-L)--logfile','(--fetchmailrc)-f','(-f)--fetchmailrc','(--idfile)-i','(-i)--idfile'}':file:_files' \
   {--plugin,--plugout,'(--mda)-m','(-m)--mda'}':command:_command_names -e' \
   {'(--username)-u','(-u)--username'}:user:_users \
-  '--auth:authentication types:(password kerberos kerberos_v5)' \
+  '--auth:authentication type:(password kerberos kerberos_v5)' \
   {'(--protocol)-p','(-p)--protocol'}:protocol:'(auto pop2 pop3 apop rpop kpop sdps imap imap-k4 imap-gss etrn)' \
   {'(--port)-P','(-P)--port'}':port number' \
   '*:mail server:_hosts' \
diff --git a/Completion/Unix/Command/_ffmpeg b/Completion/Unix/Command/_ffmpeg
index c0b229f35..1329939cd 100644
--- a/Completion/Unix/Command/_ffmpeg
+++ b/Completion/Unix/Command/_ffmpeg
@@ -6,7 +6,7 @@ typeset -A opt_args
 (( $+functions[_ffmpeg_presets] )) || _ffmpeg_presets() {
     local presets
     presets=(~/.ffmpeg/*.ffpreset(:t:r) "$FFMPEG_DATADIR"/*.ffpreset(:t:r))
-    _wanted ffmpeg-presets expl 'select preset' compadd -a presets
+    _wanted ffmpeg-presets expl 'preset' compadd -a presets
 }
 
 (( $+functions[_ffmpeg_acodecs] )) || _ffmpeg_acodecs() {
@@ -49,7 +49,7 @@ typeset -A _ffmpeg_flags
 
 (( $+functions[_ffmpeg_flag_options] )) || _ffmpeg_flag_options() {
     local expl
-    _wanted options expl 'select flags' compadd -S '' -- {-,+}${^flag_options}
+    _wanted options expl 'flag' compadd -S '' -- {-,+}${^flag_options}
 }
 
 (( $+functions[_ffmpeg_more_flag_options] )) || _ffmpeg_more_flag_options() {
@@ -177,7 +177,7 @@ _arguments -C -S \
     && return
 
 [[ "$state" == "vfilters" ]] &&
-    _values -s , -S = 'video filters' \
+    _values -s , -S = 'video filter' \
     'aspect:set aspect ratio (rational number X\:Y or decimal number):' \
     'crop:crop input video (x\:y\:width\:height):' \
     'format: :_sequence -s : _ffmpeg_pix_fmts' \
diff --git a/Completion/Unix/Command/_find b/Completion/Unix/Command/_find
index 916fcf2e6..8ff60baf2 100644
--- a/Completion/Unix/Command/_find
+++ b/Completion/Unix/Command/_find
@@ -89,7 +89,7 @@ case $variant in
       '-X[warn if filename contains characters special to xargs]'
       '-f[specify file hierarchy to traverse]:path:_directories'
       "-x[don't span filesystems]"
-      '*-flags:flags:_chflags'
+      '*-flags:flag:_chflags'
     )
   ;|
   freebsd*|dragonfly*) args+=( '*-sparse' ) ;|
diff --git a/Completion/Unix/Command/_fuser b/Completion/Unix/Command/_fuser
index f497729fc..05de1c529 100644
--- a/Completion/Unix/Command/_fuser
+++ b/Completion/Unix/Command/_fuser
@@ -50,7 +50,7 @@ case $variant in
     )
     argf=( '*:name: _alternative "files:file:_files" "services:service:_fuser_services"' )
     [[ -prefix -  && -z ${${words[1,CURRENT-1]}[(r)-[A-Z][A-Z]*]} ]] &&
-        argf[1]+=' "signal:signals:_signals -P-"'
+        argf[1]+=' "signals:signal:_signals -P-"'
   ;;
   freebsd*|openbsd*|solaris2.<9->)
     args+=(
diff --git a/Completion/Unix/Command/_gem b/Completion/Unix/Command/_gem
index b35a5c358..53adfb89c 100644
--- a/Completion/Unix/Command/_gem
+++ b/Completion/Unix/Command/_gem
@@ -46,7 +46,7 @@ if [[ $state = command ]]; then
         'gem_dependencies:gem dependencies file guide'
         'platforms:show information about platforms'
       )
-      _describe -t topics 'help topics' helptopics -- && ret=0
+      _describe -t topics 'help topic' helptopics -- && ret=0
     ;&
     subcommands)
       cmds=( ${${${(M)${(f)"$(_call_program commands gem help commands)"}:#    [^ ]*}## #}/ ##/:} )
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 0267acfa8..d27b43098 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -76,8 +76,8 @@ _git-add () {
       declare -a ignored_files_alternatives
       if [[ -n ${opt_args[(I)-f|--force]} ]]; then
         ignored_files_alternatives=(
-          'ignored-modified-files:ignored modified files:__git_ignore_line_inside_arguments __git_modified_files --ignored'
-          'ignored-other-files:ignored other files:__git_ignore_line_inside_arguments __git_other_files --ignored')
+          'ignored-modified-files:ignored modified file:__git_ignore_line_inside_arguments __git_modified_files --ignored'
+          'ignored-other-files:ignored other file:__git_ignore_line_inside_arguments __git_other_files --ignored')
       fi
 
       _alternative \
@@ -330,7 +330,7 @@ _git-branch () {
     "($l $m $d -f --force)"{-f,--force}'[force the creation of a new branch]' \
     "($l $m $d -t --track)"{-t,--track}'[setup configuration so that pull merges from the start point]' \
     "($l $m $d)--no-track[override the branch.autosetupmerge configuration variable]" \
-    "($l $m $d -u --set-upstream --set-upstream-to --unset-upstream)"{-u+,--set-upstream-to=}'[set up configuration so that pull merges]:remote-branches:__git_remote_branch_names' \
+    "($l $m $d -u --set-upstream --set-upstream-to --unset-upstream)"{-u+,--set-upstream-to=}'[set up configuration so that pull merges]:remote branch:__git_remote_branch_names' \
     "($l $m $d -u --set-upstream --set-upstream-to --unset-upstream)--unset-upstream[remove upstream configuration]" \
     "($l $m $d)*--contains=[only list branches that contain the specified commit]: :__git_committishs" \
     "($l $m $d)*--no-contains=[only list branches that don't contain the specified commit]: :__git_committishs" \
@@ -3138,7 +3138,7 @@ __git_config_option-or-value () {
             ;;
           (*.)
             local -a existing_subsections=( ${${${(M)git_present_options:#${IPREFIX}*.*}#${IPREFIX}}%.*} )
-            _describe -t existing-subsections "existing subsections" existing_subsections -S . && ret=0
+            _describe -t existing-subsections "existing subsection" existing_subsections -S . && ret=0
             ;;
         esac
       else
@@ -4070,7 +4070,7 @@ _git-help () {
     '(-a --all -g --guides -c --config -i --info -m --man)'{-w,--web}'[display manual for the command in HTML format]' \
     '(-g --guides -c --config -i --info -m --man -w --web)'{-g,--guides}'[prints a list of useful guides on the standard output]' \
     '(-v --verbose)'{-v,--verbose}'[print command descriptions]' \
-    ': : _alternative commands:command:_git_commands "guides:git guides:(attributes cli core-tutorial cvs-migration diffcore everyday glossary hooks ignore modules namespaces repository-layout revisions tutorial tutorial-2 workflows)"'
+    ': : _alternative commands:command:_git_commands "guides:git guide:(attributes cli core-tutorial cvs-migration diffcore everyday glossary hooks ignore modules namespaces repository-layout revisions tutorial tutorial-2 workflows)"'
 }
 
 (( $+functions[_git-instaweb] )) ||
@@ -5381,7 +5381,7 @@ _git-pack-redundant () {
     '(:)--all[process all packs]' \
     '--alt-odb[do not require objects to be present in local packs]' \
     '--verbose[output some statistics to standard error]' \
-    '(--all)*::packs:_files -g "*.pack(-.)"'
+    '(--all)*::pack:_files -g "*.pack(-.)"'
 }
 
 (( $+functions[_git-rev-list] )) ||
@@ -7317,7 +7317,7 @@ __git_repositories () {
 __git_local_repositories () {
   local expl
 
-  _wanted local-repositories expl 'local repositories' _directories
+  _wanted local-repositories expl 'local repository' _directories
 }
 
 (( $+functions[__git_repositories_or_urls] )) ||
diff --git a/Completion/Unix/Command/_gradle b/Completion/Unix/Command/_gradle
index 9a75daefb..adf5e9aa8 100644
--- a/Completion/Unix/Command/_gradle
+++ b/Completion/Unix/Command/_gradle
@@ -95,18 +95,18 @@ if [[ $words[CURRENT] != -* ]]; then
                 _tags gradle_group gradle_all
                 while _tags; do
                     # Offer main tasks and secondary tasks in different tags.
-                    _requested gradle_group && _describe 'group tasks' gradle_group_tasks && ret=0
-                    _requested gradle_all && _describe 'secondary tasks' gradle_all_tasks && ret=0
+                    _requested gradle_group && _describe 'group task' gradle_group_tasks && ret=0
+                    _requested gradle_all && _describe 'secondary task' gradle_all_tasks && ret=0
                     (( ret )) || break
                 done
             elif [[ $state == alltask ]]; then
                 # After '--exclude-task', we don't make a distinction between main tasks and
                 # secondary tasks.
-                _describe 'all tasks' gradle_group_tasks -- gradle_all_tasks && ret=0
+                _describe 'task' gradle_group_tasks -- gradle_all_tasks && ret=0
             fi
         fi
     else
-        _describe 'built-in tasks' '(
+        _describe 'built-in task' '(
             "dependencies:Displays all dependencies declared in root project."
             "dependencyInsight:Displays the insight into a specific dependency in root project."
             "help:Displays a help message."
diff --git a/Completion/Unix/Command/_initctl b/Completion/Unix/Command/_initctl
index 2d7c2494b..b404c0c16 100644
--- a/Completion/Unix/Command/_initctl
+++ b/Completion/Unix/Command/_initctl
@@ -51,14 +51,14 @@ _initctl_known_events()
 _initctl_multiple_known_events()
 {
   [[ ${#_initctl_events_list} -eq 0 ]] && _initctl_fillarray_events_args
-  _values -s "," "Events" "$_initctl_events_list[@]"
+  _values -s "," "event" "$_initctl_events_list[@]"
 }
 
 # list KEY= arguments, generate array if necessary
 _initctl_known_eventargs()
 {
   [[ ${#_initctl_eventargs_list} -eq 0 ]] && _initctl_fillarray_events_args
-  _values "Argument Keys" "$_initctl_eventargs_list[@]"
+  _values "argument key" "$_initctl_eventargs_list[@]"
 }
 
 # describe and offer commands for initctl, then call matching completion function
@@ -82,7 +82,7 @@ _initctl_command()
     )
 
     if (( CURRENT == 1 )); then
-        _describe -t command "initctl Commands" cmds
+        _describe -t command "initctl command" cmds
     fi
 
     local cmd=$words[1]
@@ -97,8 +97,8 @@ _initctl_startstop()
     _arguments \
         '--no-wait[do not wait for operation to complete before exiting]' \
         "${common_args[@]}" \
-        ':Upstart Jobs:_initctl_helper_jobs' \
-        '*::Argument Keys:_initctl_known_eventargs'
+        ':upstart job:_initctl_helper_jobs' \
+        '*::argument key:_initctl_known_eventargs'
 }
 
 # completion for anything that takes one job
@@ -106,7 +106,7 @@ _initctl_argjob()
 {
     _arguments \
         "${common_args[@]}" \
-        ':Upstart Jobs:_initctl_helper_jobs' \
+        ':upstart job:_initctl_helper_jobs' \
         '*::'
 }
 
@@ -116,8 +116,8 @@ _initctl_emit()
     _arguments \
         '--no-wait[do not wait for event to finish before exiting]' \
         "${common_args[@]}" \
-        ':Events:_initctl_known_events' \
-        '*::Argument Keys:_initctl_known_eventargs'
+        ':event:_initctl_known_events' \
+        '*::argument key:_initctl_known_eventargs'
 }
 
 # the fallback, just the options
@@ -133,7 +133,7 @@ _initctl_show-config()
     _arguments \
       "(-e --enumerate)"{-e,--enumerate}"[enumerate emit lines]" \
         "${common_args[@]}" \
-        '::Upstart Jobs:_initctl_helper_jobs' \
+        '::upstart job:_initctl_helper_jobs' \
         '*::'
 }
 
@@ -144,7 +144,7 @@ _initctl_check-config()
       "(-i --ignore-events)"{-i,--ignore-events}"[list of comma-separated events to ignore]:Events:_initctl_multiple_known_events" \
       "(-w --warn)"{-w,--warn}"[treat any unknown jobs or events as error]" \
         "${common_args[@]}" \
-        '::Upstart Jobs:_initctl_helper_jobs' \
+        '::upstart job:_initctl_helper_jobs' \
         '*::'
 }
 
@@ -172,7 +172,7 @@ _initctl()
   # depending on which command was used, call different completion functions
   case $service in
     initctl)
-      _arguments "${common_args[@]}" '*::Initctl Commands:_initctl_command'
+      _arguments "${common_args[@]}" '*::initctl command:_initctl_command'
     ;;
     start|stop|restart|reload|status)
       _call_function ret _initctl_${cmd_completion_funcs[${service}]-${cmd_completion_default}}
diff --git a/Completion/Unix/Command/_install b/Completion/Unix/Command/_install
index 5ad84645e..364119961 100644
--- a/Completion/Unix/Command/_install
+++ b/Completion/Unix/Command/_install
@@ -106,7 +106,7 @@ case $state in
       'a[symlinks use absolute path]'
       'r[symlinks use relative path]'
     )
-    _values -S '' 'link flags' $tmp && ret=0
+    _values -S '' 'link flag' $tmp && ret=0
     ;;
 esac
 
diff --git a/Completion/Unix/Command/_joe b/Completion/Unix/Command/_joe
index 592c34a10..74b0bf1a3 100644
--- a/Completion/Unix/Command/_joe
+++ b/Completion/Unix/Command/_joe
@@ -36,4 +36,4 @@ _arguments \
   '-linums[display line numbers before each line]' \
   '-rdonly[make file read-only]' \
   '-keymap[use an alternate section of joerc for keybindings]:keymap name' \
-  '*:files:_files'
+  '*:file:_files'
diff --git a/Completion/Unix/Command/_locate b/Completion/Unix/Command/_locate
index 23305f798..af07473b3 100644
--- a/Completion/Unix/Command/_locate
+++ b/Completion/Unix/Command/_locate
@@ -44,7 +44,7 @@ case $variant in
       -u'[create slocate database starting at path /]'
       -U'[create slocate database starting at given path]:directory:_files -/'
       -c'[parse GNU locate updatedb with -u, -U]'
-      -e'[exclude directories with -u, -U]:directories:_files -/'
+      -e'[exclude directories with -u, -U]: : _dir_list -s,'
       -f'[exclude file system types from db with -u, -U]:file system:_file_systems'
       -l'[security level]:level:(0 1)'
       -q'[quiet mode]'
diff --git a/Completion/Unix/Command/_lp b/Completion/Unix/Command/_lp
index 914d63ff2..ad7e97203 100644
--- a/Completion/Unix/Command/_lp
+++ b/Completion/Unix/Command/_lp
@@ -83,7 +83,7 @@ _lp_job_options()
 	  "DuplexTumble:flip short side"
 	  "DuplexNoTumble:flip long side"
 	  "None")
-	_describe "duplex options" desc_opts
+	_describe "duplex option" desc_opts
 	;;
 
       (*)
@@ -103,11 +103,11 @@ _lp_job_options()
       eq_suffix=(-S '=')
     fi
 
-    _description lpopts expl "generic printer options"
+    _description lpopts expl "generic printer option"
     compadd "$expl[@]" $eq_suffix $lopts_with_args
     compadd "$expl[@]" $lopts_no_args
 
-    _description printeropts expl "printer specific options"
+    _description printeropts expl "printer specific option"
     compadd "$expl[@]" $eq_suffix \
       $(_call_program list-printer-options \
 	lpoptions $printer -l | cut -d/ -f1)
diff --git a/Completion/Unix/Command/_ls b/Completion/Unix/Command/_ls
index 1fd9383f5..df14e7e2c 100644
--- a/Completion/Unix/Command/_ls
+++ b/Completion/Unix/Command/_ls
@@ -196,7 +196,7 @@ else
     '(-q --hide-control-chars)--show-control-chars'
     '(- :)--help[display help information]'
     '(- :)--version[display version information]'
-    '*:files:_files'
+    '*:file:_files'
   )
   if [[ $OSTYPE = linux* ]]; then
     arguments+=(
diff --git a/Completion/Unix/Command/_make b/Completion/Unix/Command/_make
index 21ed56184..ae91440f0 100644
--- a/Completion/Unix/Command/_make
+++ b/Completion/Unix/Command/_make
@@ -204,7 +204,7 @@ _make() {
     ;;
 
     (debug)
-    _values -s , 'debug options' \
+    _values -s , 'debug option' \
       '(b v i j m)a[all debugging output]' \
       'b[basic debugging output]' \
       '(b)v[one level above basic]' \
diff --git a/Completion/Unix/Command/_moosic b/Completion/Unix/Command/_moosic
index 54d768c8c..475a0c75c 100644
--- a/Completion/Unix/Command/_moosic
+++ b/Completion/Unix/Command/_moosic
@@ -216,7 +216,7 @@ _moosic_cmd_version() {
 _moosic_song_files()
 {
     _arguments -A '-*' $main_opts $filelist_opts $auto_opts \
-               '*:song files:_files'
+               '*:song file:_files'
 }
 
 _moosic_cmd_append() {
@@ -282,7 +282,7 @@ _moosic_cmd_stagger-merge() {
 _moosic_cmd_interval-add() {
     _arguments -A '-*' $main_opts $filelist_opts \
                   '1:interval:' \
-                  '*:song files:_files'
+                  '*:song file:_files'
 }
 
 ### REMOVING COMMANDS
diff --git a/Completion/Unix/Command/_mysql_utils b/Completion/Unix/Command/_mysql_utils
index f1ad97bcd..a7b285f1c 100644
--- a/Completion/Unix/Command/_mysql_utils
+++ b/Completion/Unix/Command/_mysql_utils
@@ -187,7 +187,7 @@ _mysqladmin() {
 	  _wanted databases expl "MySQL database" _mysql_databases && ret=0
 	;;
 	kill)
-	  _message -e ids 'thread ids'
+	  _message -e ids 'thread id'
 	;;
 	password)
 	  _message -e passwords 'new password'
diff --git a/Completion/Unix/Command/_mysqldiff b/Completion/Unix/Command/_mysqldiff
index 4b46c86df..52b96ef21 100644
--- a/Completion/Unix/Command/_mysqldiff
+++ b/Completion/Unix/Command/_mysqldiff
@@ -20,8 +20,8 @@ _mysqldiff () {
 
 _mysql_db_or_file () {
   _alternative \
-    'databases:MySQL databases:_mysql_databases' \
-    'files:MySQL database definition files:_files -g "*.(my|)sql(-.)"'
+    'databases:MySQL database:_mysql_databases' \
+    'files:MySQL database definition file:_files -g "*.(my|)sql(-.)"'
 }
 
 _mysql_utils
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 423fd3223..2f608c5fc 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -66,7 +66,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
 	'--plugin[load specified plugin]:plugin'
 	'--special-syms[include special symbols in the output]'
 	'--synthetic[display synthetic symbols as well]'
-	"--target=[target object format]:targets:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
+	"--target=[target object format]:target:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
 	'--with-symbol-versions[display version strings after symbol names]'
       )
     ;;
diff --git a/Completion/Unix/Command/_objdump b/Completion/Unix/Command/_objdump
index 989cd3f0b..5152e6b6e 100644
--- a/Completion/Unix/Command/_objdump
+++ b/Completion/Unix/Command/_objdump
@@ -184,7 +184,7 @@ case "$state" in
         ${=${(M)${(f)"$(_call_program targets objdump --help)"}##* supported architectures:*}##*: } && ret=0
   ;;
   disassembler_options)
-    _values -s , "disassembler options" "${(@)${(@)${(@M)${(f)${(ps.-M switch.)$(_call_program targets objdump --help)}[2]}:#  [^ ]*}#  }%% *}" && ret=0
+    _values -s , "disassembler option" "${(@)${(@)${(@M)${(f)${(ps.-M switch.)$(_call_program targets objdump --help)}[2]}:#  [^ ]*}#  }%% *}" && ret=0
   ;;
   llvm_targets)
     _values "target architecture" "${(z)${(@)${(f)$(_call_program targets
diff --git a/Completion/Unix/Command/_perforce b/Completion/Unix/Command/_perforce
index 0d007e3bc..4e69dee78 100644
--- a/Completion/Unix/Command/_perforce
+++ b/Completion/Unix/Command/_perforce
@@ -1354,7 +1354,7 @@ _perforce_fstat_fields() {
     ${${${${(M)${(f)"$(_perforce_call_p4 help-fstat help fstat)"}:#[[:blank:]]#[a-zA-Z]##(|\#)[[:blank:]]##--*}##[[:blank:]]#}:#fstat *}//[[:blank:]]##--[[:blank:]]##/:}
   )
   compset -P '*[,[:blank:]]'
-  _describe -t fstat-fields 'Perforce fstat fields' values -S, -q
+  _describe -t fstat-fields 'Perforce fstat field' values -S, -q
 }
 
 
diff --git a/Completion/Unix/Command/_perl b/Completion/Unix/Command/_perl
index 4a917903c..d7e8f1b51 100644
--- a/Completion/Unix/Command/_perl
+++ b/Completion/Unix/Command/_perl
@@ -31,7 +31,7 @@ _perl () {
     "-u[dump core after parsing script]" \
     "-U[allow unsafe operations]" \
     "-v[print version, patchlevel and license]" \
-    "-V-[print perl configuration information]:configuration keys:_perl_config_vars" \
+    "-V-[print perl configuration information]:configuration key:_perl_config_vars" \
     '(   -W -X)-w[turn warnings on for compilation of your script (recommended)]' \
     "(-w    -X)-W[enable all warnings (ignores 'no warnings')]" \
     "(-w -W   )-X[disable all warnings (ignores 'use warnings')]" \
@@ -96,7 +96,7 @@ _perl_config_vars () {
 }
 
 _perl_unicode_flags () {
-  _values -s '' 'unicode bitmask or flags' \
+  _values -s '' 'unicode bitmask or flag' \
     '(S)I[  1 STDIN is assumed to be in UTF-8]' \
     '(S)O[  2 STDOUT will be in UTF-8]' \
     '(S)E[  4 STDERR will be in UTF-8]' \
diff --git a/Completion/Unix/Command/_perldoc b/Completion/Unix/Command/_perldoc
index 3e58d5a50..b724d74ee 100644
--- a/Completion/Unix/Command/_perldoc
+++ b/Completion/Unix/Command/_perldoc
@@ -3,7 +3,7 @@
 local curcontext="$curcontext" state line expl args ret=1
 typeset -A opt_args
 
-args=( '*:Perl pod pages:->perl-pods' )
+args=( '*:Perl pod page:->perl-pods' )
 
 if [[ $service = *PERLDOC* ]]; then
   compset -q
@@ -46,7 +46,7 @@ case  $state in
 
   perl-pods)
     if (( $+opt_args[-F] )); then
-      _wanted files expl 'Perl modules and .pods' \
+      _wanted files expl 'Perl module or .pod' \
           _files -g "*.(pod|pm)(-.)" && ret=0
     else
       _alternative \
diff --git a/Completion/Unix/Command/_ps b/Completion/Unix/Command/_ps
index 98dcd1cd0..9b54cbcc6 100644
--- a/Completion/Unix/Command/_ps
+++ b/Completion/Unix/Command/_ps
@@ -236,8 +236,8 @@ else
   [[ -z "$state" ]] && return ret
 fi
 
-_values -s '' -S ' ' 'options' $bsd && ret=0
-_values -S ' ' 'options' $bsdarg && ret=0
+_values -s '' -S ' ' 'option' $bsd && ret=0
+_values -S ' ' 'option' $bsdarg && ret=0
 if [[ -z $pids ]]; then
   _pids && ret=0
 fi
diff --git a/Completion/Unix/Command/_qemu b/Completion/Unix/Command/_qemu
index 3c21c3e74..30fcd6757 100644
--- a/Completion/Unix/Command/_qemu
+++ b/Completion/Unix/Command/_qemu
@@ -6,7 +6,7 @@ _qemu_log_items () {
     [[ $hline[1] = Log ]] && continue
     opts=($opts "${hline[1]}[${hline[2,-1]}]")
   done
-  _values -s , 'log items' $opts
+  _values -s , 'log item' $opts
 }
 
 local _qemu_machines
@@ -45,7 +45,7 @@ _arguments \
   '-s[wait gdb connection to port 1234]' \
   '-p[change gdb connection port]:port:_ports' \
   '-S[do not start CPU at startup]' \
-  '-d[output log in /tmp/qemu.log]:log items:_qemu_log_items' \
+  '-d[output log in /tmp/qemu.log]:log item:_qemu_log_items' \
   '-hdachs[force hard disk 0 geometry (usually qemu can guess it)]:hd0 geometry c,h,s:' \
   '-vga[select video card type]:card type:(std cirrus vmware qxl xenfb none)' \
   '-no-acpi[disable ACPI]' \
diff --git a/Completion/Unix/Command/_quilt b/Completion/Unix/Command/_quilt
index 8167bce1e..8f39dadac 100644
--- a/Completion/Unix/Command/_quilt
+++ b/Completion/Unix/Command/_quilt
@@ -36,7 +36,7 @@ _quilt_unapplied() {
 
 _arguments $help \
   '--trace[run the command in bash trace mode]' \
-  '--quiltrc=[use the specified configuration file]:files:_files' \
+  '--quiltrc=[use the specified configuration file]:file:_files' \
   '--version[print the version number and exit]' \
   ':quilt command:->cmd' \
   '*:: :->subcmd' && return
@@ -116,12 +116,12 @@ case $words[1] in
   add)
     _arguments -S $help \
       '-P+[specify patch to add files to]:patch:_quilt_applied' \
-      '*:files:_files' && return
+      '*:file:_files' && return
   ;;
   annotate)
     _arguments $help \
       '-P[stop checking for changes at the specified rather than the topmost patch]:patch:_quilt_series' \
-      ':files:_files' && return
+      ':file:_files' && return
   ;;
   applied) _arguments $help ':quilt series:_quilt_series' && return ;;
   delete)
@@ -142,9 +142,9 @@ case $words[1] in
       '(-P -z)--snapshot[diff against snapshot]' \
       '--diff=[use the specified utility for generating the diff]:diff utility:_command_names -e' \
       '--sort[sort files by name]' \
-      '*:files:_files' && return
+      '*:file:_files' && return
   ;;
-  edit) _arguments $help '*:files:_files' && return ;;
+  edit) _arguments $help '*:file:_files' && return ;;
   files)
     _arguments -s $help $verbose \
       '-a[list all files in all applied patches]' \
@@ -187,14 +187,14 @@ case $words[1] in
       '-P+[patch filename to use inside quilt]:quilt select patch filename: ' \
       '-f[overwrite/update existing patches]' \
       '-d+[header resolution when overwriting in existing patch]:resolution:((a\:all\ headers n\:new\ headers o\:old\ headers))' \
-      '*:files:_files' && return
+      '*:file:_files' && return
   ;;
   mail)
     _arguments $help \
       '(-h -M)-m[introduction text to use]:introduction text' \
       '(-h -m)-M[read introduction text from file]:file:_files' \
       '--prefix=[use an alternate prefix in the bracketed part of the subjects generated]:quilt select prefix: ' \
-      '--mbox=[store all messages in the specified file in mbox format]:files:_files' \
+      '--mbox=[store all messages in the specified file in mbox format]:file:_files' \
       '--send[send the messages directly]' \
       '--sender=[specify envelope sender address to use]:sender:_email_addresses -c' \
       '--from=[from header]:address:_email_addresses' \
@@ -202,13 +202,13 @@ case $words[1] in
       '*--to=[append a recipient to the To header]:recipient:_email_addresses' \
       '*--cc=[append a recipient to the Cc header]:recipient:_email_addresses' \
       '*--bcc=[append a recipient to the Bcc header]:recipient:_email_addresses' \
-      '--signature=[append specified signature file to messages]:files:_files' \
+      '--signature=[append specified signature file to messages]:file:_files' \
       '--reply-to=[add reply address to message]:address:_email_addresses' \
       '*:patch:_quilt_series' && return
   ;;
   new) _arguments $help $pstyle ':patch name' && return ;;
   next) _arguments $help ':patch:_quilt_series' && return ;;
-  patches) _arguments -S $help $verbose $color '*:files:_files' && return ;;
+  patches) _arguments -S $help $verbose $color '*:file:_files' && return ;;
   pop)
     _arguments -s $help $verbose \
       '-a[remove all applied patches]' \
@@ -253,7 +253,7 @@ case $words[1] in
   revert)
     _arguments $help \
       '-P[revert changes in the named patch]:patch:_quilt_series' \
-      '*:files:_files' && return
+      '*:file:_files' && return
   ;;
   series) _arguments $help $verbose $color && return ;;
   setup)
@@ -261,7 +261,7 @@ case $words[1] in
       '-d[specify path prefix for resulting source tree]:prefix:_files -W / -P /' \
       '--sourcedir[specify location of package sources]:directory:_directories' \
       '--fuzz=[set the maximum fuzz factor]:factor' \
-      ':files:_files' && return
+      ':file:_files' && return
   ;;
   snapshot) _arguments $help '-d[only remove current snapshot]' && return ;;
   unapplied) _arguments $help ':patch:_quilt_series' && return ;;
diff --git a/Completion/Unix/Command/_rclone b/Completion/Unix/Command/_rclone
index 40f06e0ba..27b4dd926 100644
--- a/Completion/Unix/Command/_rclone
+++ b/Completion/Unix/Command/_rclone
@@ -79,7 +79,7 @@ _arguments -C \
   '--dump-bodies[dump HTTP headers and bodies - may contain sensitive info]' \
   '--dump-headers[dump HTTP headers - may contain sensitive info]' \
   '--exclude[exclude files matching pattern]:stringArray' \
-  '--exclude-from[read exclude patterns from file]:files:_files' \
+  '--exclude-from[read exclude patterns from file]:file:_files' \
   '--exclude-if-present[exclude directories if filename is present]:string' \
   '--fast-list[use recursive list if available]' \
   '--files-from[read list of source-file names from file]:file:_files' \
@@ -339,8 +339,8 @@ _arguments -C \
 if [[ $state == 'files_or_remotes' ]]; then
   remotes=( $(_call_program rclone-remotes rclone listremotes) )
   _alternative \
-    "remote:rclone-remotes:compadd -a remotes" \
-    "file:files:_files" && ret=0
+    "rclone-remotes:remote:compadd -a remotes" \
+    "files:file:_files" && ret=0
 fi
 
 return ret
diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync
index e14c99cc6..b1a4f6046 100644
--- a/Completion/Unix/Command/_rsync
+++ b/Completion/Unix/Command/_rsync
@@ -71,14 +71,14 @@ _rsync_info() {
   local opts
   opts=( ${${(M)${(f)"$(_call_program values $words[1] --info=help)"}:#*Mention*}/ ##Me/[me} )
   (( $#opts )) && opts=( '(ALL NONE HELP)'${^opts}\] )
-  _values -s , 'info options' $opts ALL NONE HELP
+  _values -s , 'info option' $opts ALL NONE HELP
 }
 
 _rsync_debug() {
   local opts
   opts=( ${${(M)${(f)"$(_call_program values $words[1] --debug=help)"}:#*Debug*}/ ##De/[de} )
   (( $#opts )) && opts=( '(ALL NONE HELP)'${^opts}\] )
-  _values -s , 'debug options' $opts ALL NONE HELP
+  _values -s , 'debug option' $opts ALL NONE HELP
 }
 
 _rsync_files() {
diff --git a/Completion/Unix/Command/_runit b/Completion/Unix/Command/_runit
index 81ba26a44..5c22cc54e 100644
--- a/Completion/Unix/Command/_runit
+++ b/Completion/Unix/Command/_runit
@@ -19,7 +19,7 @@ _sv_commands() {
     'kill':'send SIGKILL if service is running'
     'exit':'send SIGTERM and SIGCONT if service is running. Do not restart service.'
   )
-  _describe -t commands "sv commands" sv_ary -V sv_commands
+  _describe -t commands "sv command" sv_ary -V sv_commands
 }
 
 _sv_lsb() {
@@ -41,7 +41,7 @@ _sv_lsb() {
 }
 
 _sv_additional() {
-  _describe -t additional-commands "sv additional commands" '("check:check status of service")' -V sv_addl_comm
+  _describe -t additional-commands "sv additional command" '("check:check status of service")' -V sv_addl_comm
 }
 
 local curcontext="$curcontext" state line
@@ -68,6 +68,6 @@ case $state in
     )
 
     sv_services=( ${sv_services#$svdir/} )
-    _describe -t services "sv services" sv_services
+    _describe -t services "sv service" sv_services
   ;;
 esac
diff --git a/Completion/Unix/Command/_scons b/Completion/Unix/Command/_scons
index 2c620cc1a..77fe6dfb0 100644
--- a/Completion/Unix/Command/_scons
+++ b/Completion/Unix/Command/_scons
@@ -19,7 +19,7 @@ _arguments -s -S \
   '(-)-'{h,-help}'[display defined usage information]' \
   '(-)-'{H,-help-options}'[display usage information]' \
   '(-i -ignore-errors)-'{i,-ignore-errors}'[ignore errors from build actions]' \
-  \*{-I,--include-dir=}'[add directory to search Python modules]:directories:_directories' \
+  \*{-I,--include-dir=}'[add directory to search Python modules]:directory:_directories' \
   '(--implicit-deps-changed --implicit-deps-unchanged)--implicit-cache[cache scanned dependencies]' \
   '(--implicit-cache --implicit-deps-changed)--implicit-deps-changed[rescan dependencies]' \
   '(--implicit-cache --implicit-deps-unchanged)--implicit-deps-unchanged[ignore changes to scanned dependencies]' \
diff --git a/Completion/Unix/Command/_ssh b/Completion/Unix/Command/_ssh
index 82a2a1827..ffdc4999f 100644
--- a/Completion/Unix/Command/_ssh
+++ b/Completion/Unix/Command/_ssh
@@ -392,7 +392,7 @@ _ssh () {
           state=dynforward
           ;;
         (#i)kbdinteractivedevices=*)
-          _values -s , 'keyboard-interactive authentication methods' \
+          _values -s , 'keyboard-interactive authentication method' \
               'bsdauth' 'pam' 'skey' && ret=0
           ;;
         (#i)(kexalgorithms|gssapikexalgorithms)=*)
diff --git a/Completion/Unix/Command/_tla b/Completion/Unix/Command/_tla
index 1e4cdd8d9..33dfc005f 100644
--- a/Completion/Unix/Command/_tla
+++ b/Completion/Unix/Command/_tla
@@ -45,8 +45,8 @@ _tla_revisions () { _arch_namespace tla 4 "$argv[@]" }
 (( $+functions[_tla_local_revisions] )) ||
 _tla_local_revisions () {
   local expl1 expl2 tree_version=`$TLA tree-version`
-  _description -V applied-patches expl1 "patches from this version"
-  _description -V other-patches expl2 "patches from other versions"
+  _description -V applied-patches expl1 "patch from this version"
+  _description -V other-patches expl2 "patch from other versions"
   compadd "$expl1[@]" `$TLA logs`
   compadd "$expl2[@]" `$TLA logs --full $($TLA log-versions | grep -v $tree_version)`
   # This is incredibly slow.
@@ -90,7 +90,7 @@ _tla_limit () { #presently only does push-mirror style limits
   if [ $archive ]; then
 
     if [[ $PREFIX != *--* ]]; then
-      _description -V categories expl "categories in $archive"
+      _description -V categories expl "category in $archive"
       compadd -q -S -- "$expl[@]" `$TLA categories -A $archive`
     else
       _tla_namespace_branches 3
@@ -107,7 +107,7 @@ _tla_tree_or_rev () {
 _tla_libraries () {
   local libraries expl
   libraries=($(_call_program tla $TLA my-revision-library))
-  _description -V libraries expl "revision libraries"
+  _description -V libraries expl "revision library"
   compadd "$expl[@]" -a libraries
 }
 
@@ -128,7 +128,7 @@ _tla_log_versions () {
   else
     logs=($(_call_program tla $TLA logs))
   fi
-  _description -V versions expl "log versions"
+  _description -V versions expl "log version"
   compadd "$expl[@]" -a logs
 }
 
@@ -278,12 +278,12 @@ methods=(
 cmd_tagging_method=($cmd_id_tagging_method)
 
 local cmd_add cmd_add_id cmd_add_tag
-cmd_add=('*:files to add:_files')
+cmd_add=('*:file to add:_files')
 cmd_add_id=($cmd_add)
 cmd_add_tag=($cmd_add)
 
 local cmd_delete cmd_delete_id cmd_delete_tag
-cmd_delete=('*:files to delete:_files')
+cmd_delete=('*:file to delete:_files')
 cmd_delete_id=($cmd_delete)
 cmd_delete_tag=($cmd_delete)
 
@@ -312,7 +312,7 @@ cmd_changeset=(
   ':ORIG:_files -/'
   ':MOD:_files -/'
   ':DEST:_files -/'
-  '*:files:_files'
+  '*:file:_files'
 )
 cmd_mkpatch=("$cmd_changeset[@]")
 
@@ -328,7 +328,7 @@ local cmd_make_archive
 cmd_make_archive=('::name:' ':location:_files -/')
 
 local cmd_archive_setup
-cmd_archive_setup=('*:versions:_tla_branches --trailing-dashes')
+cmd_archive_setup=('*:version:_tla_branches --trailing-dashes')
 
 local cmd_make_category
 cmd_make_category=(':category:_tla_archives -S /')
@@ -344,7 +344,7 @@ cmd_import=('::version:_tla_versions')
 cmd_imprev=($cmd_import)
 
 local cmd_commit cmd_cmtrev
-cmd_commit=('::version:_tla_versions' ':separator:(--)' '*:files:_files')
+cmd_commit=('::version:_tla_versions' ':separator:(--)' '*:file:_files')
 cmd_cmtrev=($cmd_commit)
 
 local cmd_get cmd_getrev
@@ -619,7 +619,7 @@ _tla_main () {
     local -U cmds
     help=(${(f)"$($TLA help)"})
     cmds=(${${${${(M)help:#* :*}/ #: #/:}%% ##}## #})
-    arguments=(':commands:(($cmds))')
+    arguments=(':command:(($cmds))')
   fi
   _arguments -S -A '-*' \
     {"${hide_short}(: -)-V",'(: -)--version'}'[display version]' \
diff --git a/Completion/Unix/Command/_tmux b/Completion/Unix/Command/_tmux
index f4e5619a0..284a325e5 100644
--- a/Completion/Unix/Command/_tmux
+++ b/Completion/Unix/Command/_tmux
@@ -1114,7 +1114,7 @@ function __tmux-buffers() {
     fi
 
     buffers=( ${${(f)"$(command tmux 2> /dev/null list-buffers "${bopts[@]}")"}/:[ $'\t']##/:} )
-    _describe -t buffers 'buffers' buffers
+    _describe -t buffers 'buffer' buffers
 }
 
 function __tmux-bound-keys() {
@@ -1122,14 +1122,14 @@ function __tmux-bound-keys() {
     local -a keys
 
     keys=( ${${${${(f)"$(command tmux 2> /dev/null list-keys "$@")"}/:[ $'\t']##/:}/(#s)[ $'\t']##/}/(#s):/\\:} )
-    _describe -t keys 'keys' keys
+    _describe -t keys 'key' keys
 }
 
 function __tmux-clients() {
     local expl
     local -a clients
     clients=( ${${(f)"$(command tmux 2> /dev/null list-clients)"}/:[ $'\t']##/:} )
-    _describe -t clients 'clients' clients
+    _describe -t clients 'client' clients
 }
 
 function __tmux-environment-variables() {
@@ -1165,7 +1165,7 @@ function __tmux-environment-variables() {
                 descriptions+=( "${k//:/\\:}:$v" )
             done
             # TODO: this if/else is because '_describe ${hint:+"-x"}' prints the "No matches" error in addition to the message.
-            local msg="${dash_g[1]:+"global "}environment variables${hint}"
+            local msg="${dash_g[1]:+"global "}environment variable${hint}"
             if _describe -t parameters $msg descriptions; then
                 :
             elif [[ -n $hint ]]; then
@@ -1621,9 +1621,9 @@ function __tmux-panes() {
     command tmux 2> /dev/null list-panes "${opts[@]}" | while IFS= read -r line; do
         panes+=( $(( num++ )):${line//:/} )
     done
-    _describe -t panes 'panes' panes "$@"
+    _describe -t panes 'pane' panes "$@"
     if [[ ${IPREFIX} != *. ]]; then
-        _wanted windows expl 'windows' __tmux-windows -S.
+        _wanted windows expl 'window' __tmux-windows -S.
     fi
 }
 
@@ -1648,14 +1648,14 @@ function __tmux-server-options() {
 function __tmux-sessions() {
     local -a sessions
     sessions=( ${${(f)"$(command tmux 2> /dev/null list-sessions)"}/:[ $'\t']##/:} )
-    _describe -t sessions 'sessions' sessions "$@"
+    _describe -t sessions 'session' sessions "$@"
 }
 
 function __tmux-sessions-attached() {
     local -a sessions
     sessions=( ${${(f)"$(command tmux 2> /dev/null list-sessions)"}/:[ $'\t']##/:} )
     sessions=( ${(M)sessions:#*"(attached)"} )
-    _describe -t sessions 'attached sessions' sessions "$@"
+    _describe -t sessions 'attached session' sessions "$@"
 }
 
 # Complete attached-sessions and detached-sessions as separate tags.
@@ -1671,8 +1671,8 @@ function __tmux-sessions-separately() {
     _tags detached-sessions attached-sessions
     # Placing detached before attached means the default behaviour of this
     # function better suits its only current caller, _tmux-attach-session().
-    _requested detached-sessions && _describe -t detached-sessions 'detached sessions' detached_sessions "$@" && ret=0
-    _requested attached-sessions && _describe -t attached-sessions 'attached sessions' attached_sessions "$@" && ret=0
+    _requested detached-sessions && _describe -t detached-sessions 'detached session' detached_sessions "$@" && ret=0
+    _requested attached-sessions && _describe -t attached-sessions 'attached session' attached_sessions "$@" && ret=0
 
     return ret
 }
@@ -1744,9 +1744,9 @@ function __tmux-windows() {
         opts=( )
     fi
     wins=( ${${(M)${(f)"$(command tmux 2> /dev/null list-windows "${opts[@]}")"}:#<->*}/:[ $'\t']##/:} )
-    _describe -t windows 'windows' wins "$@"
+    _describe -t windows 'window' wins "$@"
     if [[ ${IPREFIX} != *: ]]; then
-        _wanted sessions expl 'sessions' __tmux-sessions -S:
+        _wanted sessions expl 'session' __tmux-sessions -S:
     fi
 }
 
@@ -1775,11 +1775,11 @@ _tmux() {
   if (( CURRENT == 1 )); then
     zstyle -s ":completion:${curcontext}:subcommands" mode mode || mode='both'
     if [[ ${mode} == 'commands' ]]; then
-      _describe -t subcommands 'tmux commands' _tmux_commands && ret=0
+      _describe -t subcommands 'tmux command' _tmux_commands && ret=0
     elif [[ ${mode} == 'aliases' ]]; then
-      _describe -t subcommands 'tmux aliases' _tmux_aliases && ret=0
+      _describe -t subcommands 'tmux alias' _tmux_aliases && ret=0
     else
-      _describe -t subcommands 'tmux commands and aliases' _tmux_commands -- _tmux_aliases && ret=0
+      _describe -t subcommands 'tmux command or alias' _tmux_commands -- _tmux_aliases && ret=0
     fi
   else
     tmuxcommand="${words[1]}"
diff --git a/Completion/Unix/Command/_tput b/Completion/Unix/Command/_tput
index a3b4e949c..abba3e8c0 100644
--- a/Completion/Unix/Command/_tput
+++ b/Completion/Unix/Command/_tput
@@ -14,5 +14,5 @@ esac
 _arguments : \
   $args - set3 \
   '(-S -V)-T+[terminal type]:terminal type:_terminals' \
-  '1:terminal capabilities:( init reset longname ${(k)terminfo} )' \
+  '1:terminal capability:( init reset longname ${(k)terminfo} )' \
   '*:capability parameters:{ [[ $words[1] != (init|reset|longname) ]] && _message parameter }'
diff --git a/Completion/Unix/Command/_unison b/Completion/Unix/Command/_unison
index 5963d66c6..91fa57e5b 100644
--- a/Completion/Unix/Command/_unison
+++ b/Completion/Unix/Command/_unison
@@ -6,7 +6,7 @@ typeset -A opt_args
 _arguments \
     '-auto[automatically accept default (nonconflicting) actions]' \
     '-batch[batch mode\: ask no questions at all]' \
-    '-doc[show documentation]:topics:(about people lists status copying ack install tutorial basics failures running ssh news all topics)' \
+    '-doc[show documentation]:topic:(about people lists status copying ack install tutorial basics failures running ssh news all topics)' \
     '-follow[add a pattern to the follow list]:pattern:' \
     '-force[force changes from this replica to the other]:replica:' \
     '-group[synchronize group attributes]' \
diff --git a/Completion/Unix/Command/_w3m b/Completion/Unix/Command/_w3m
index 6e83a6781..8b45ad730 100644
--- a/Completion/Unix/Command/_w3m
+++ b/Completion/Unix/Command/_w3m
@@ -84,7 +84,7 @@ case "$state" in
     _alternative \
       'files:file:_files -g "*.x#html(-.)"' \
       'urls:URL:_urls' \
-      'bookmarks:bookmarks:compadd -a bookmarks' \
+      'bookmarks:bookmark:compadd -a bookmarks' \
       'history:history:compadd -a w3mhistory' && ret=0
   ;;
   option)
diff --git a/Completion/Unix/Command/_wget b/Completion/Unix/Command/_wget
index 49c8e8b01..d061fcd06 100644
--- a/Completion/Unix/Command/_wget
+++ b/Completion/Unix/Command/_wget
@@ -137,7 +137,7 @@ _arguments -C -s \
   '(--reject -R)'{--reject=,-R+}'[specify rejected extensions]:extensions' \
   --{accept,reject}-regex=:regex '--regex-type=:regex type:(posix pcre)' \
   '(--domains -D)'{--domains=,-D+}'[specify accepted domains]:domains:_domains' \
-  '--exclude-domains=:rejected domains:_domains' \
+  '--exclude-domains=:rejected domain:_sequence _domains' \
   '--follow-ftp' \
   '--follow-tags=:HTML tags:' \
   '--ignore-tags=[specify ignored HTML tags]:HTML tags' \
diff --git a/Completion/Unix/Command/_xmlsoft b/Completion/Unix/Command/_xmlsoft
index 487974fdb..6f7e3b7c9 100644
--- a/Completion/Unix/Command/_xmlsoft
+++ b/Completion/Unix/Command/_xmlsoft
@@ -45,7 +45,7 @@ case $service in
       '--encoding[the input document character encoding]:encoding:(${encoding[@]})' \
       '*--param[pass a parameter,value pair]:name::value (xpath expression)' \
       '*--stringparam[pass a parameter]:name::value' \
-      '--path[provide a set of paths for resources]:paths:_files -/' \
+      '--path[provide a set of paths for resources]:path:_dir_list' \
       '--nonet[refuse to fetch DTDs or entities over network]' \
       '--nowrite[refuse to write to any file or resource]' \
       '--nomkdir[refuse to create directories]' \
@@ -70,7 +70,7 @@ case $service in
       '--noent[substitute entity references by their value]' \
       '--noenc[ignore any encoding specified inside the document]' \
       "(--output -o)--noout[don't output the result tree]" \
-      '--path[provide a set of paths for resources]:paths:_files -/' \
+      '--path[provide a set of paths for resources]:path:_dir_list' \
       '--load-trace[print trace of all external entities loaded]' \
       '--nonet[refuse to fetch DTDs or entities over network]' \
       '--nocompact[do not generate compact text nodes]' \
diff --git a/Completion/Unix/Command/_xmms2 b/Completion/Unix/Command/_xmms2
index 525d5177c..ca2383b2f 100644
--- a/Completion/Unix/Command/_xmms2
+++ b/Completion/Unix/Command/_xmms2
@@ -43,7 +43,7 @@ _xmms2_command() {
 	)
 
     if (( CURRENT == 1 )); then
-	_describe -t command "xmms2 commands" xmms2_cmds
+	_describe -t command "xmms2 command" xmms2_cmds
     else
 	local curcontext="$curcontext"
     fi
@@ -63,7 +63,7 @@ _xmms2_command() {
 	 fi
      done
      
-     _values -s ' ' 'playlist items' ${(On)playlistitems}
+     _values -s ' ' 'playlist item' ${(On)playlistitems}
 
 }
 
@@ -84,7 +84,7 @@ _xmms2_mlib() {
 
 	)
     if (( CURRENT == 2 )); then
-	_describe -t command "xmms2 mlib commands" mlib_cmds
+	_describe -t command "xmms2 mlib command" mlib_cmds
     else
 	local curcontext="$curcontext"
     fi
@@ -107,7 +107,7 @@ _xmms2_playlist() {
 	remove:"Remove a playlist"
 	)
     if (( CURRENT == 2 )); then
-	_describe -t command "xmms2 playlist commands" playlist_cmds
+	_describe -t command "xmms2 playlist command" playlist_cmds
     else
 	local curcontext="$curcontext"
     fi
@@ -121,14 +121,14 @@ _xmms2_playlist() {
 _xmms2_playlist_load() {
     local list
     list=($(xmms2 playlist list))
-    _describe -t command "xmms2 playlists" list
+    _describe -t command "xmms2 playlist" list
 }
 
 
 _xmms2_playlist_remove() {
     local list
     list=($(xmms2 playlist list))
-    _describe -t command "xmms2 playlists" list
+    _describe -t command "xmms2 playlist" list
 }
 
 
@@ -146,7 +146,7 @@ _xmms2_coll() {
 	attr:"Get/set an attribute for a saved collection"
 	)
     if (( CURRENT == 2 )); then
-	_describe -t command "xmms2 collection commands" coll_cmds
+	_describe -t command "xmms2 collection command" coll_cmds
     else
 	local curcontext="$curcontext"
     fi
@@ -160,7 +160,7 @@ _xmms2_coll() {
 _xmms2_coll_helper() {
     local list
     list=($(xmms2 coll list))
-    _describe -t command "xmms2 playlists" list
+    _describe -t command "xmms2 playlist" list
 }
 
 _xmms2_coll_rename() {
diff --git a/Completion/Unix/Command/_yafc b/Completion/Unix/Command/_yafc
index 1e0a601a1..946c0b4ce 100644
--- a/Completion/Unix/Command/_yafc
+++ b/Completion/Unix/Command/_yafc
@@ -32,7 +32,7 @@ _yafc_bookmarks() {
     if [[ -f $bkmfile ]]; then
         local -a bkms expl
         bkms=(${${${(M)"${(f)$(<$bkmfile)}":#machine*alias ##\'*\' #}##machine*alias ##\'}%%\' #}) #" vim syntax goes crazy
-        _wanted bookmarks expl 'bookmarks' compadd "$@" -a - bkms
+        _wanted bookmarks expl 'bookmark' compadd "$@" -a - bkms
     fi
 }
 
diff --git a/Completion/Unix/Type/_email_addresses b/Completion/Unix/Type/_email_addresses
index 8a5877a9c..d5f175a79 100644
--- a/Completion/Unix/Type/_email_addresses
+++ b/Completion/Unix/Type/_email_addresses
@@ -69,7 +69,7 @@ _email-ldap() {
     fi
   done
   compstate[insert]=menu
-  _wanted email-ldap expl 'matching names' \
+  _wanted email-ldap expl 'matching name' \
       compadd -U -i "$IPREFIX" -I "$ISUFFIX" "$@" -a - ali
 }
 
diff --git a/Completion/Unix/Type/_urls b/Completion/Unix/Type/_urls
index 5d4990442..f9cdd58cd 100644
--- a/Completion/Unix/Type/_urls
+++ b/Completion/Unix/Type/_urls
@@ -103,7 +103,7 @@ case "$scheme" in
   bookmark)
     if [[ -f "$urls/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" &&
 	  -s "$urls/$scheme/${(Q)PREFIX}${(Q)SUFFIX}" ]]; then
-      _wanted -C bookmark bookmarks expl bookmarks \
+      _wanted -C bookmark bookmarks expl bookmark \
           compadd "$@" -U - \
               "$ipre$(<"$urls/$scheme/${(Q)PREFIX}${(Q)SUFFIX}")" && ret=0
     else
diff --git a/Completion/X/Command/_mozilla b/Completion/X/Command/_mozilla
index 64f4d9450..0be25b8d3 100644
--- a/Completion/X/Command/_mozilla
+++ b/Completion/X/Command/_mozilla
@@ -95,7 +95,7 @@ if [[ "$state" = "remote" ]]; then
     ;;
     *)
       compset -S '(|\\)\(*' || suf="${${QIPREFIX:+(}:-\(}"
-      _wanted commands expl 'remote commands' \
+      _wanted commands expl 'remote command' \
           compadd -qS "$suf" -M 'm:{a-zA-Z}={A-Za-z}' -a \
                   remote_commands && ret=0
     ;;
diff --git a/Completion/X/Command/_mplayer b/Completion/X/Command/_mplayer
index a913960fe..1f99a1789 100644
--- a/Completion/X/Command/_mplayer
+++ b/Completion/X/Command/_mplayer
@@ -131,13 +131,13 @@ case "$state" in
   ;;
   audio-drivers)
     vals=( help ${${${(f)"$(_call_program audio-drivers mplayer -ao help 2>/dev/null)"}[(r)	*,-1]#?}/	/:} )
-    _describe -t audio-drivers 'audio drivers' vals && ret=0
+    _describe -t audio-drivers 'audio driver' vals && ret=0
   ;;
   audio-codec-families)
     compset -P '*,'
     compset -S ',*'
     vals=( help ${${${(f)"$(_call_program audio-codec-families mplayer -afm help 2>/dev/null)"}[(r) [^:]#,-1]## ##}/ ##/:} )
-    _describe -t audio-codec-families 'audio drivers' vals && ret=0
+    _describe -t audio-codec-families 'audio driver' vals && ret=0
   ;;
   audio-plugins)
     _values -s : 'audio output plugin' \
@@ -154,7 +154,7 @@ case "$state" in
   ;;
   video-drivers)
     vals=( help ${${${(f)"$(_call_program video-drivers mplayer -vo help 2>/dev/null)"}[(r)	*,-1]#?}/	/:} )
-    _describe -t video-drivers 'video drivers' vals && ret=0
+    _describe -t video-drivers 'video driver' vals && ret=0
   ;;
   video-output-plugins)
     vals=( help ${${${${(f)"$(_call_program video-output-plugins mplayer -vop help 2>/dev/null)"}[(r)	*,-1]}/	/}/ #: /:} )
diff --git a/Completion/X/Command/_netscape b/Completion/X/Command/_netscape
index e1d02ae90..78b2da649 100644
--- a/Completion/X/Command/_netscape
+++ b/Completion/X/Command/_netscape
@@ -52,7 +52,7 @@ if [[ "$state" = "remote" ]]; then
     ;;
     *)
       compset -S '(|\\)\(*' || suf="${${QIPREFIX:+(}:-\(}"
-      _wanted commands expl 'remote commands' \
+      _wanted commands expl 'remote command' \
           compadd -qS "$suf" -M 'm:{a-zA-Z}={A-Za-z}' -a \
                   remote_commands && ret=0
     ;;
diff --git a/Completion/X/Command/_pdftk b/Completion/X/Command/_pdftk
index b8c43f754..1ac3223f7 100644
--- a/Completion/X/Command/_pdftk
+++ b/Completion/X/Command/_pdftk
@@ -24,7 +24,7 @@ case $words[CURRENT-1] in
     (allow)
 	#_description permissions expl "permission"
 	#compadd $expl \
-	_values -s , permissions \
+	_values -s , permission \
 	    Printing DegradedPrinting ModifyContents Assembly CopyContents \
 	    ScreenReaders ModifyAnnotations FillIn AllFeatures
 	;;
@@ -34,12 +34,12 @@ case $words[CURRENT-1] in
 	;;
 
     (fill_form)
-	_description files expl 'FDF and XFDF files'
+	_description files expl 'FDF and XFDF file'
 	_files "$@" $expl -g '(#i)*.(fdf|xfdf)'
 	;;
 
     ((multibackground|background|stamp|multistamp|output))
-	_description files expl 'PDF files'
+	_description files expl 'PDF file'
 	_files "$@" $expl -g '(#i)*.pdf'
 	;;
 
@@ -53,11 +53,11 @@ case $words[CURRENT-1] in
 esac && return 0
 
 if [[ -n $words[(r)(${(j:|:)operations})] ]]; then
-    _description options expl "options"
+    _description options expl "option"
     compadd $@ $expl $opts
 else
     _tags files operations
     _alternative \
-	'files:PDF files:_pdfwithhandle' \
-	"operations:operations:($operations)"
+	'files:PDF file:_pdfwithhandle' \
+	"operations:operation:($operations)"
 fi
diff --git a/Completion/X/Command/_vnc b/Completion/X/Command/_vnc
index d60616f21..9263ab930 100644
--- a/Completion/X/Command/_vnc
+++ b/Completion/X/Command/_vnc
@@ -86,7 +86,7 @@ case $service in
   ;;
   *vncviewer) 
     _xt_arguments -shared -viewonly -fullscreen -bgr233 -owncmap -truecolour \
-      '-encodings:encodings:_values -s " " encoding copyrect hextile corre rre raw' \
+      '-encodings: :_values -s " " encoding copyrect hextile corre rre raw' \
       '-depth:depth' \
       '-passwd:file:_files' \
       '(1)-listen:display number' \
diff --git a/Completion/X/Command/_xauth b/Completion/X/Command/_xauth
index 14dfc8400..22ebffecd 100644
--- a/Completion/X/Command/_xauth
+++ b/Completion/X/Command/_xauth
@@ -41,7 +41,7 @@ while [[ -n "$state" ]]; do
 	  group) _message -e ids 'group-id';;
 	  data) _message -e values 'hexdata';;
 	  *) 
-	    _wanted options expl 'xauth generate options' \
+	    _wanted options expl 'xauth generate option' \
 	      compadd trusted untrusted timeout group data && ret=0
 	    ;;
 	  esac
diff --git a/Completion/X/Command/_xournal b/Completion/X/Command/_xournal
index 066ef55f5..c36210c26 100644
--- a/Completion/X/Command/_xournal
+++ b/Completion/X/Command/_xournal
@@ -2,5 +2,5 @@
 
 local expl
 
-_description files expl 'PDF and Xournal files'
+_description files expl 'PDF or Xournal file'
 _files "$@" "$expl[@]" -g '*.(#i){xoj,pdf}(-.)'
diff --git a/Completion/Zsh/Command/_bindkey b/Completion/Zsh/Command/_bindkey
index 81ae69974..df9c8f225 100644
--- a/Completion/Zsh/Command/_bindkey
+++ b/Completion/Zsh/Command/_bindkey
@@ -27,7 +27,7 @@ _arguments -C -s -S \
   '(-l -L -d -D -A -N -m -p -r *)-s[bind each in-string to each out-string]:*:key string' \
   '(-e -v -a -M -l -L -d -D -A -N -m -p)-R[interpret in-strings as ranges]' \
   '(-l -L -d -A -N -m -p -r -s):in-string' \
-  '(-l -L -d -A -N -m -p -r -s)*::widgets:_widgets' && ret=0
+  '(-l -L -d -A -N -m -p -r -s)*::widget:_widgets' && ret=0
 
 case $state in
   keymap)
diff --git a/Completion/Zsh/Command/_disable b/Completion/Zsh/Command/_disable
index 52b82a6e9..da3803039 100644
--- a/Completion/Zsh/Command/_disable
+++ b/Completion/Zsh/Command/_disable
@@ -7,10 +7,10 @@ sali_arr=(${(k)saliases})
 func_arr=(${(k)functions})
 
 _arguments -C -s -A "-*" -S \
-  "(-f -r -s -p)-a[act on regular or global aliases]:*:regular or global aliases:compadd -k ali_arr" \
-  "(-a -r -s -p)-f[act on functions]:*:functions:compadd -k func_arr" \
-  "(-a -f -s -p)-r[act on reserved words]:*:reserved-words:compadd -k reswords" \
-  "(-a -f -r -p)-s[act on suffix aliases]:*:suffix aliases:compadd -k sali_arr" \
-  "(-a -f -r -s)-p[act on pattern characters]:*:pattern characters:compadd -k patchars" \
+  "(-f -r -s -p)-a[act on regular or global aliases]:*:regular or global alias:compadd -k ali_arr" \
+  "(-a -r -s -p)-f[act on functions]:*:function:compadd -k func_arr" \
+  "(-a -f -s -p)-r[act on reserved words]:*:reserved-word:compadd -k reswords" \
+  "(-a -f -r -p)-s[act on suffix aliases]:*:suffix alias:compadd -k sali_arr" \
+  "(-a -f -r -s)-p[act on pattern characters]:*:pattern character:compadd -k patchars" \
   '-m[treat arguments as patterns]' \
   "*:builtin command:(${(k)builtins})"
diff --git a/Completion/Zsh/Command/_enable b/Completion/Zsh/Command/_enable
index 9410651b7..b62619d89 100644
--- a/Completion/Zsh/Command/_enable
+++ b/Completion/Zsh/Command/_enable
@@ -7,10 +7,10 @@ sali_arr=(${(k)dis_saliases})
 func_arr=(${(k)dis_functions})
 
 _arguments -C -s -A "-*" -S \
-  "(-f -r -s -p)-a[act on regular or global aliases]:*:aliases:compadd -k ali_arr" \
-  "(-a -r -s -p)-f[act on functions]:*:functions:compadd -k func_arr" \
-  "(-a -f -s -p)-r[act on reserved words]:*:reserved-words:compadd -k dis_reswords" \
-  "(-a -f -r -p)-s[act on suffix aliases]:*:suffix aliases:compadd -k sali_arr" \
-  "(-a -f -r -s)-p[act on pattern characters]:*:pattern characters:compadd -k dis_patchars" \
+  "(-f -r -s -p)-a[act on regular or global aliases]:*:alias:compadd -k ali_arr" \
+  "(-a -r -s -p)-f[act on functions]:*:function:compadd -k func_arr" \
+  "(-a -f -s -p)-r[act on reserved words]:*:reserved-word:compadd -k dis_reswords" \
+  "(-a -f -r -p)-s[act on suffix aliases]:*:suffix alias:compadd -k sali_arr" \
+  "(-a -f -r -s)-p[act on pattern characters]:*:pattern character:compadd -k dis_patchars" \
   '-m[treat arguments as patterns]' \
   "*:builtin command:(${(k)dis_builtins})"
diff --git a/Completion/Zsh/Command/_sched b/Completion/Zsh/Command/_sched
index e8ff5ab87..888708684 100644
--- a/Completion/Zsh/Command/_sched
+++ b/Completion/Zsh/Command/_sched
@@ -10,7 +10,7 @@ if [[ CURRENT -eq 2 ]]; then
     else
       disp=()
     fi
-    [[ -z $lines ]] || _wanted jobs expl 'scheduled jobs' \
+    [[ -z $lines ]] || _wanted jobs expl 'scheduled job' \
                            compadd "$disp[@]" - {1..$#lines}
     return
   else
diff --git a/Completion/Zsh/Command/_typeset b/Completion/Zsh/Command/_typeset
index ae33ae539..aecacb112 100644
--- a/Completion/Zsh/Command/_typeset
+++ b/Completion/Zsh/Command/_typeset
@@ -127,7 +127,7 @@ if [[ "$state" = vars_eq ]]; then
 	[[ $PREFIX != [_.]* ]]; then
 	args=(${args:#_*})
       fi
-      _wanted functions expl 'shell functions' compadd -a args
+      _wanted functions expl 'shell function' compadd -a args
     else
       _functions
     fi
diff --git a/Completion/Zsh/Command/_zmodload b/Completion/Zsh/Command/_zmodload
index 3416d50c6..f3e38c0f6 100644
--- a/Completion/Zsh/Command/_zmodload
+++ b/Completion/Zsh/Command/_zmodload
@@ -23,7 +23,7 @@ _arguments -n -C -S -s \
   '(-e -u)-L[output in the form of calls to zmodload]' \
   '(-b -c -d -I -f -F -P -l -m -A -R)-p[autoload module for parameters]' \
   '(-u -b -c -d -p -f -A -R)-P[array param for features]:array name:_parameters' \
-  '(-)*:params:->params' && ret=0
+  '(-)*:param:->params' && ret=0
 
 [[ $state = params ]] || return ret
 
@@ -66,7 +66,7 @@ else
   while _tags; do
     _requested builtins expl 'builtin command' \
       compadd "$@" -k builtins && ret=0
-    _requested loadedmodules expl 'loaded modules' \
+    _requested loadedmodules expl 'loaded module' \
       compadd -k 'modules[(R)loaded]' && ret=0
     _requested files expl 'module file' \
       _files -W module_path -g '*.(dll|s[ol]|bundle)(:r)' && ret=0
diff --git a/Completion/Zsh/Command/_zstyle b/Completion/Zsh/Command/_zstyle
index 9d06076e4..0c81c2f2e 100644
--- a/Completion/Zsh/Command/_zstyle
+++ b/Completion/Zsh/Command/_zstyle
@@ -491,7 +491,7 @@ while (( $#state )); do
       elif compset -P '*:'; then
         _message -e tags tag
       else
-        _message -e patterns 'glob patterns'
+        _message -e patterns 'glob pattern'
       fi
       ;;
 
diff --git a/Completion/Zsh/Context/_subscript b/Completion/Zsh/Context/_subscript
index 0d9632864..25cedd193 100644
--- a/Completion/Zsh/Context/_subscript
+++ b/Completion/Zsh/Context/_subscript
@@ -80,7 +80,7 @@ elif compset -P '\('; then
     );;
   esac
 
-  _values -s '' 'subscript flags' $flags
+  _values -s '' 'subscript flag' $flags
 elif [[ ${(Pt)${compstate[parameter]}} = assoc* ]]; then
   local suf MATCH MBEGIN MEND
   local -a keys
diff --git a/Completion/Zsh/Context/_zcalc_line b/Completion/Zsh/Context/_zcalc_line
index 50fb8c17c..ab8e42df9 100644
--- a/Completion/Zsh/Context/_zcalc_line
+++ b/Completion/Zsh/Context/_zcalc_line
@@ -16,7 +16,7 @@ _zcalc_line_escapes() {
     "function:define math function (also \:func or \:f)"
   )
   cmds=("\:"${^cmds})
-  _describe -t command-escapes "command escapes" cmds -Q
+  _describe -t command-escapes "command escape" cmds -Q
 }
 
 _zcalc_line() {
diff --git a/Completion/Zsh/Function/_add-zsh-hook b/Completion/Zsh/Function/_add-zsh-hook
index 4d8a96dab..5b1ff0e42 100644
--- a/Completion/Zsh/Function/_add-zsh-hook
+++ b/Completion/Zsh/Function/_add-zsh-hook
@@ -3,7 +3,7 @@
 _add-zsh-hook_hooks() {
   local expl
   if (( $+opt_args[-d] )); then
-    _wanted functions expl "installed hooks" compadd -a - "$line[1]_functions" && return 0
+    _wanted functions expl "installed hook" compadd -a - "$line[1]_functions" && return 0
   else
     _functions && return 0
   fi
diff --git a/Completion/openSUSE/Command/_hwinfo b/Completion/openSUSE/Command/_hwinfo
index aac0a05ad..7dff82805 100644
--- a/Completion/openSUSE/Command/_hwinfo
+++ b/Completion/openSUSE/Command/_hwinfo
@@ -5,7 +5,7 @@ _arguments \
   '--version[show libhd version]' \
   '--short[just a short listing]' \
   '--log[write info to logfile]:logfile:_files' \
-  '--debug[set debuglevel]:debuglevels:(1 2 3 4 5 6 7 8 9)' \
+  '--debug[set debuglevel]:debug level:(1 2 3 4 5 6 7 8 9)' \
   '--dump-db[dump hardware data base, 0: external, 1: internal]:dumpdb:(0 1)' \
   '--bios' \
   '--block' \
diff --git a/Completion/openSUSE/Command/_zypper b/Completion/openSUSE/Command/_zypper
index 25a32c3f1..3f3402bd9 100644
--- a/Completion/openSUSE/Command/_zypper
+++ b/Completion/openSUSE/Command/_zypper
@@ -65,17 +65,17 @@ _zypper() {
 _all_repos() {
     local -a repos
     repos=( $(zypper -q lr | tail -n +3 | cut -d'|' -f 2) )
-    _describe -t repos 'Available repositories' repos && return
+    _describe -t repos 'available repository' repos && return
 }
 
 _enabled_repos() {
     repos=( $(zypper -x lr | grep 'enabled="1"' | cut -d\" -f 2) )
-    _describe -t repos 'Available repositories' repos && return
+    _describe -t repos 'available repository' repos && return
 }
 
 _disabled_repos() {
     repos=( $(zypper -x lr | grep 'enabled="0"' | cut -d\" -f 2) )
-    _describe -t repos 'Available repositories' repos && return
+    _describe -t repos 'available repository' repos && return
 }
 
 _zypper_cmd_do() {
@@ -107,7 +107,7 @@ _zypper_cmd_do() {
         case ${words[CURRENT - 1]} in
             --from)
                 repos=( $(zypper -x lr | grep 'enabled="1"' | cut -d\" -f 2) )
-                _describe -t repos 'Available repositories' repos && return
+                _describe -t repos 'available repository' repos && return
                ;;
             (--enable|-e)
                 case $cmd in
@@ -128,7 +128,7 @@ _zypper_cmd_do() {
                 case $cmd in
                     (if|info|se|search|in|install) 
                         types=( pattern srcpackage package patch )
-                        _describe -t types 'Package types' types && return
+                        _describe -t types 'package type' types && return
                     ;;
                 esac
                 ;;
@@ -143,7 +143,7 @@ _zypper_cmd_do() {
                 ;;
             (in|install)
                 local expl
-                _description files expl 'RPM files' 
+                _description files expl 'RPM file'
                 _files "$expl[@]" -g '*.(#i)rpm(.)'
                 ;;
         esac


^ permalink raw reply	[relevance 1%]

* Re: [PR] vcs_info-examples: optimize +vi-git-untracked() #76
  @ 2021-06-28 17:16  3%   ` Suraj N. Kurapati
  0 siblings, 0 replies; 200+ results
From: Suraj N. Kurapati @ 2021-06-28 17:16 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh-workers

[-- Attachment #1: Type: text/plain, Size: 517 bytes --]

On Sun, 27 Jun 2021 11:13:53 +0200, Oliver Kiddle wrote:
> > Speed up the prompt on large and/or deep working directories by
> > stopping grep(1) as soon as it finds a single match, with `-q`.  
> 
> The -q option to grep isn't strictly portable. It is certainly lacking
> on Solaris.

POSIX (IEEE Std 1003.1-2017) says that grep(1) supports the `-q` option:

  https://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html

Consequently, I'm surprised to hear that Solaris doesn't implement this.

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 963 bytes --]

^ permalink raw reply	[relevance 3%]

* Re: [BUG] builtin echo doesn't check write error
  2021-06-09 18:16  3%   ` Stephane Chazelas
  2021-06-10  8:11  0%     ` Vincent Lefevre
@ 2021-06-24  8:47  0%     ` Vincent Lefevre
  1 sibling, 0 replies; 200+ results
From: Vincent Lefevre @ 2021-06-24  8:47 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

Since this message from Stephane got truncated in the archives
before a line starting with "From "

  https://www.zsh.org/mla/workers/2021/msg01272.html

I'm including it entirely below, quoted to avoid this issue.
I've just posted a message

  https://www.zsh.org/mla/workers/2021/msg01334.html
  archived messages with "From " get truncated

about this truncation issue.

Note also about the bug in echo/print/etc., this actually seems
to affect *all* builtins. For instance:

zira% (exec >&-; echo)
zsh: write error: bad file descriptor
zira% (exec >&-; echo >&-)
zira% (exec >&-; print)
zsh: write error: bad file descriptor
zira% (exec >&-; print >&-)
zira% (exec >&-; printf "\n")
zsh: write error: bad file descriptor
zira% (exec >&-; printf "\n" >&-)
zira% (exec >&-; pwd)
zsh: write error: bad file descriptor
zira% (exec >&-; pwd >&-)
zira% (exec >&-; history)
zsh: write error: bad file descriptor
zira% (exec >&-; history >&-)
zira% 

On 2021-06-09 19:16:17 +0100, Stephane Chazelas wrote:
> 2021-06-09 09:13:42 -0700, Bart Schaefer:
> [...]
> > My (possibly poor) recollection is that this was made this way in part
> > for ports to environments that don't have a /dev/null device
> 
> While that sounds like a very plausible reason for the original
> behaviour whereby "print" would not report any write error,
> that doesn't really tie up with the current behaviour where
> the error is supressed only when print/echo's stdout is
> explicitly closed.
> 
> Why would one write print foo >&- in the first place, other than
> to check whether print reports error or not (and in that regard,
> the behaviour is very misleading)
> 
> From looking at the history, it looks more like:
> 
> 1990 (1.0) echo ignores write failures (by design or not).
> 1999 workers/9129 Peter writes the "print foo >&-" succeeds, no
>      error test case, just documenting the actual behaviour of
>      print ignoring errors (here using >&- as the easiest way to
>      trigger a write error).
> 2002 workers/16503 Clint adds some error messages upon write
>      errors.
> 2002 workers/16556 we realise it breaks the test case above, so
>      Bart removes the error message on EBADF for that test case
>      to pass again. The fact that there's still an error message
>      in (print)>&- looks like an oversight. The error in that
>      case is output by execcmd_exec after print has returned as
>      it tries to fflush stdout again,, not bin_print (you'll
>      notice the error message doesn't mention "print").
> 2011 workers/29845 Peter notices the error is displayed in
>      (exec >&-; print) and adds a test case for it, but I'm not
>      sure he correctly identified why.
> 
> It very much looks like an (multiple) accident of
> implementation.
> 
> POSIX does say that printf/echo should return with a non-zero
> exit status upon error, and stderr be used for diagnostix
> errors as usual. It's not clear to me if implementations are at
> liberty to decide whether a write() error is considered an error
> or not.
> 
> In any case, it would be useful from an error point of view to
> be able to detect when writing fails.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 0%]

* archived messages with "From " get truncated
@ 2021-06-24  8:36  2% Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2021-06-24  8:36 UTC (permalink / raw)
  To: zsh-workers

Below is a message that was sent by Stephane to workers.
It has been archived here:

  https://www.zsh.org/mla/workers/2021/msg01272.html

but got truncated just before a line starting with "From ".
It seems that the mail archive software is buggy, thinking
that this starts a new mail message.

In the archives, there is a risk that this message gets truncated
in the forwarded message below, for the same reason. For those who
read the archive, one has, with quotes to avoid the truncation:

[...]
> Why would one write print foo >&- in the first place, other than
> to check whether print reports error or not (and in that regard,
> the behaviour is very misleading)
> 
> From looking at the history, it looks more like:
> 
> 1990 (1.0) echo ignores write failures (by design or not).
[...]

----- Forwarded message from Stephane Chazelas <stephane@chazelas.org> -----

Date: Wed, 9 Jun 2021 19:16:17 +0100
From: Stephane Chazelas <stephane@chazelas.org>
To: Bart Schaefer <schaefer@brasslantern.com>
Cc: Zsh hackers list <zsh-workers@zsh.org>
Subject: Re: [BUG] builtin echo doesn't check write error

2021-06-09 09:13:42 -0700, Bart Schaefer:
[...]
> My (possibly poor) recollection is that this was made this way in part
> for ports to environments that don't have a /dev/null device

While that sounds like a very plausible reason for the original
behaviour whereby "print" would not report any write error,
that doesn't really tie up with the current behaviour where
the error is supressed only when print/echo's stdout is
explicitly closed.

Why would one write print foo >&- in the first place, other than
to check whether print reports error or not (and in that regard,
the behaviour is very misleading)

From looking at the history, it looks more like:

1990 (1.0) echo ignores write failures (by design or not).
1999 workers/9129 Peter writes the "print foo >&-" succeeds, no
     error test case, just documenting the actual behaviour of
     print ignoring errors (here using >&- as the easiest way to
     trigger a write error).
2002 workers/16503 Clint adds some error messages upon write
     errors.
2002 workers/16556 we realise it breaks the test case above, so
     Bart removes the error message on EBADF for that test case
     to pass again. The fact that there's still an error message
     in (print)>&- looks like an oversight. The error in that
     case is output by execcmd_exec after print has returned as
     it tries to fflush stdout again,, not bin_print (you'll
     notice the error message doesn't mention "print").
2011 workers/29845 Peter notices the error is displayed in
     (exec >&-; print) and adds a test case for it, but I'm not
     sure he correctly identified why.

It very much looks like an (multiple) accident of
implementation.

POSIX does say that printf/echo should return with a non-zero
exit status upon error, and stderr be used for diagnostix
errors as usual. It's not clear to me if implementations are at
liberty to decide whether a write() error is considered an error
or not.

In any case, it would be useful from an error point of view to
be able to detect when writing fails.

-- 
Stephane

----- End of forwarded message -----

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 2%]

* Re: [PATCH (not final)] (take three?) unset "array[$anything]"
  @ 2021-06-14  7:19  5%                         ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2021-06-14  7:19 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Peter Stephenson, Zsh hackers list

2021-06-13 14:44:03 -0700, Bart Schaefer:
> On Sun, Jun 13, 2021 at 12:50 PM Peter Stephenson
> <p.w.stephenson@ntlworld.com> wrote:
> >
> > Yes, in fact those are the same thoughts that flitted through my mind.
> 
> One other idea ... NO_UNSET could warn if you unset something that's
> not set, as well as when you $deref something that's not set.  That
> would at least blat at you if your hash key was misinterpreted.

Note that nounset is a POSIX option. And for the unset special
utility:

"Unsetting a variable or function that was not previously set
shall not be considered an error and does not cause the shell to
abort."

POSIX has no jurisdiction over arrays/hashes, but that does mean
we can't have unset fail on unset variables when in sh emulation
at least.

A shell that would fail upon:

  unset var

When var was not previously set would not be compliant.

A script that would do

  unset "var[foo]"

Would not be a POSIX script as var[foo] is not a valid variable
name, so implementations are free to do whatever they want for
them. But if zsh returned failure for when var[foo] is not set
and not in unset var, that would make it quite inconsistent.

Changing the behaviour would likely break some scripts that use
errexit as well.

-- 
Stephane


^ permalink raw reply	[relevance 5%]

* Re: Where is this =(:) construct documented?
  @ 2021-06-11 19:58  3%   ` Roman Perepelitsa
  0 siblings, 0 replies; 200+ results
From: Roman Perepelitsa @ 2021-06-11 19:58 UTC (permalink / raw)
  To: Zach Riggle, Zsh hackers list

On Fri, Jun 11, 2021 at 9:53 PM Stephane Chazelas <stephane@chazelas.org> wrote:
>
> That's the third form of process substitution.

And the colon in =(:) is a builtin that does nothing (the same as
true). It's mandated by POSIX.

Roman.


^ permalink raw reply	[relevance 3%]

* Re: [BUG] builtin echo doesn't check write error
  2021-06-09 18:16  3%   ` Stephane Chazelas
@ 2021-06-10  8:11  0%     ` Vincent Lefevre
  2021-06-24  8:47  0%     ` Vincent Lefevre
  1 sibling, 0 replies; 200+ results
From: Vincent Lefevre @ 2021-06-10  8:11 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

On 2021-06-09 19:16:17 +0100, Stephane Chazelas wrote:
> 2011 workers/29845 Peter notices the error is displayed in
>      (exec >&-; print) and adds a test case for it, but I'm not
>      sure he correctly identified why.

I also find this disturbing:

zira% (exec >&-; echo)
zsh: write error: bad file descriptor
zira% (exec >&-; echo >&-)
zira% 

(or with "print" instad of "echo").

> POSIX does say that printf/echo should return with a non-zero
> exit status upon error, and stderr be used for diagnostix
> errors as usual. It's not clear to me if implementations are at
> liberty to decide whether a write() error is considered an error
> or not.

Well, in almost all cases, e.g. when the close is not in the same
command, and when this is not fd 1 (stdout), but other fd, such as
in "echo foo 3>&- >&3", one gets an error. So this is already very
inconsistent.

-- 
Vincent Lefèvre <vincent@vinc17.net> - Web: <https://www.vinc17.net/>
100% accessible validated (X)HTML - Blog: <https://www.vinc17.net/blog/>
Work: CR INRIA - computer arithmetic / AriC project (LIP, ENS-Lyon)


^ permalink raw reply	[relevance 0%]

* Re: [BUG] builtin echo doesn't check write error
  @ 2021-06-09 18:16  3%   ` Stephane Chazelas
  2021-06-10  8:11  0%     ` Vincent Lefevre
  2021-06-24  8:47  0%     ` Vincent Lefevre
  0 siblings, 2 replies; 200+ results
From: Stephane Chazelas @ 2021-06-09 18:16 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2021-06-09 09:13:42 -0700, Bart Schaefer:
[...]
> My (possibly poor) recollection is that this was made this way in part
> for ports to environments that don't have a /dev/null device

While that sounds like a very plausible reason for the original
behaviour whereby "print" would not report any write error,
that doesn't really tie up with the current behaviour where
the error is supressed only when print/echo's stdout is
explicitly closed.

Why would one write print foo >&- in the first place, other than
to check whether print reports error or not (and in that regard,
the behaviour is very misleading)

From looking at the history, it looks more like:

1990 (1.0) echo ignores write failures (by design or not).
1999 workers/9129 Peter writes the "print foo >&-" succeeds, no
     error test case, just documenting the actual behaviour of
     print ignoring errors (here using >&- as the easiest way to
     trigger a write error).
2002 workers/16503 Clint adds some error messages upon write
     errors.
2002 workers/16556 we realise it breaks the test case above, so
     Bart removes the error message on EBADF for that test case
     to pass again. The fact that there's still an error message
     in (print)>&- looks like an oversight. The error in that
     case is output by execcmd_exec after print has returned as
     it tries to fflush stdout again,, not bin_print (you'll
     notice the error message doesn't mention "print").
2011 workers/29845 Peter notices the error is displayed in
     (exec >&-; print) and adds a test case for it, but I'm not
     sure he correctly identified why.

It very much looks like an (multiple) accident of
implementation.

POSIX does say that printf/echo should return with a non-zero
exit status upon error, and stderr be used for diagnostix
errors as usual. It's not clear to me if implementations are at
liberty to decide whether a write() error is considered an error
or not.

In any case, it would be useful from an error point of view to
be able to detect when writing fails.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH (not final)] (take three?) unset "array[$anything]"
  @ 2021-06-05 17:05  4%                   ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2021-06-05 17:05 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2021-06-04 17:20:29 -0700, Bart Schaefer:
[...]
> > array[1 + 1]=4
> >
> > That is pretty annoying.
> 
> That's just shell whitespace rules, though.  If you have nobadpattern
> set, you get
> 
> zsh: command not found: array[1
> 
> And if the parser doesn't eventually find ]= then what?  Re-parse the
> whole thing to word-split it?
[...]

Note that all other shells that support a[1]=value (ksh, pdksh,
bash) do it.

In effect that makes them non-POSIX as there's nothing in the
spec POSIX that says

a[1 + 1]=2

May not run the a[1 with +] and =2 as arguments.

I did bring that up a few years ago at:
https://www.mail-archive.com/austin-group-l@opengroup.org/msg04563.html
(see also https://austingroupbugs.net/view.php?id=1279)

There is variation in behaviour between shells if the first word
starts with name[ and either a matching ] or matching ] followed
by = is not found, and how that matching is done or what kind of
quoting are supported inside the [...].

But all in all, even if it may not be pretty when you look closely,
that does work fine there as long as you're not trying to fool
the parser.

In zsh, that would be even less problematic as (at least when
not in sh emulation), zsh complains about unmatched [s or ]s
(except for [ alone)

Even:

$ /bin/[ a = a ]
zsh: bad pattern: /bin/[

So we wouldn't be breaking anything if we started to accept:

hash[foo bar; baz]=x

or

array[1 + 1]=x

We would if we started to accept.

hash['x]y'-$'\n']=x

like ksh93/bash do though.

For literal hash[key]=value assignment, I never remember what needs
to be quoted and how. I generally resort to doing
var=key; hash[$var]=x
or
hash+=(key x)
which I know are fine.

-- 
Stephane


^ permalink raw reply	[relevance 4%]

Results 1-200 of ~2400   | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2019-12-16 21:10     regexp-replace and ^, word boundary or look-behind operators Stephane Chazelas
2019-12-16 21:27     ` Stephane Chazelas
2019-12-17  7:38       ` Stephane Chazelas
2019-12-17 11:11         ` [PATCH] " Stephane Chazelas
2019-12-18  0:22           ` Daniel Shahaf
2020-01-01 14:03             ` [PATCH v2] " Stephane Chazelas
2021-04-30  6:11               ` Stephane Chazelas
2021-04-30 23:13                 ` Bart Schaefer
2021-05-05 11:45                   ` [PATCH v3] regexp-replace and ^, word boundary or look-behind operators (and more) Stephane Chazelas
2024-03-08 15:30  2%                 ` Stephane Chazelas
2020-10-01 12:11     [BUG] _less incorrectly completes -" and -# Roman Perepelitsa
2020-10-02 14:47     ` Oliver Kiddle
2021-10-23  0:26  3%   ` Oliver Kiddle
2021-01-29 19:35     [PATCH] FAQ update for aliasing Bart Schaefer
2022-06-12 13:10  1% ` Jun. T
2021-06-03  2:04     [PATCH (not final)] (take three?) unset "array[$anything]" Bart Schaefer
2021-06-03  2:42     ` Bart Schaefer
2021-06-03  6:12       ` Bart Schaefer
2021-06-03  8:54         ` Peter Stephenson
2021-06-03 13:13           ` Stephane Chazelas
2021-06-03 14:41             ` Peter Stephenson
2021-06-04 19:25               ` Bart Schaefer
2021-06-05 18:18                 ` Peter Stephenson
2021-06-09 23:31                   ` Bart Schaefer
2021-06-13 16:51                     ` Peter Stephenson
2021-06-13 18:04                       ` Bart Schaefer
2021-06-13 19:48                         ` Peter Stephenson
2021-06-13 21:44                           ` Bart Schaefer
2021-06-14  7:19  5%                         ` Stephane Chazelas
2021-06-03 18:12             ` Bart Schaefer
2021-06-04  8:02               ` Stephane Chazelas
2021-06-04 18:36                 ` Bart Schaefer
2021-06-04 20:21                   ` Stephane Chazelas
2021-06-05  0:20                     ` Bart Schaefer
2021-06-05 17:05  4%                   ` Stephane Chazelas
2021-06-09 14:09     [BUG] builtin echo doesn't check write error Vincent Lefevre
2021-06-09 16:13     ` Bart Schaefer
2021-06-09 18:16  3%   ` Stephane Chazelas
2021-06-10  8:11  0%     ` Vincent Lefevre
2021-06-24  8:47  0%     ` Vincent Lefevre
2021-06-11 19:17     Where is this =(:) construct documented? Zach Riggle
2021-06-11 19:53     ` Stephane Chazelas
2021-06-11 19:58  3%   ` Roman Perepelitsa
2021-06-24  8:36  2% archived messages with "From " get truncated Vincent Lefevre
2021-06-27  6:09     [PR] vcs_info-examples: optimize +vi-git-untracked() #76 Suraj N. Kurapati
2021-06-27  9:13     ` Oliver Kiddle
2021-06-28 17:16  3%   ` Suraj N. Kurapati
2021-07-06 23:53  1% PATCH: use singular form for completion group descriptions for consistency Oliver Kiddle
2021-08-08  5:38     read -r flag not working on 5.8.1 David Milum
2021-08-08  5:53     ` David Milum
2021-08-08  5:59       ` Mikael Magnusson
2021-08-08 14:04  5%     ` Stephane Chazelas
2021-08-13  3:13     bug: nested for loop body is executed once! Daniil Iaitskov
2021-08-13  3:50  3% ` Lawrence Velázquez
2021-08-24 16:23  3% [BUG] ignored trap and subshell Vincent Lefevre
2021-08-24 17:29  0% ` Bart Schaefer
2021-08-24 17:33  0%   ` Bart Schaefer
2021-08-25 10:10  0% ` Peter Stephenson
2021-08-25 10:47  0%   ` Peter Stephenson
2021-08-27 12:43  1% PATCH: completion options update Oliver Kiddle
2021-08-31  1:04     tr [:lower:] Shineru
2021-08-31  1:39  3% ` Phil Pennock
2021-09-01 14:53  0%   ` Shineru
2021-09-06 21:55  3% Dump of backlogged commits coming Bart Schaefer
2021-09-26  8:43  3% [PATCH 1/4] docs: Clean up some subsection references Daniel Shahaf
2021-10-12  8:20  3% Question on unintuitive behaviour for function execution and parameter assignment Jett Husher
2021-10-12  8:31  3% ` Peter Stephenson
2021-10-13  8:42  3%   ` Jett Husher
2021-10-13  9:10  4%     ` Peter Stephenson
2021-10-21 12:40     Unexpected stdin-behavior Tycho Kirchner
2021-10-21 15:55     ` Bart Schaefer
     [not found]       ` <13d30855-d91c-7def-6834-f0ec24cfd598@mail.de>
2021-10-21 19:14         ` Bart Schaefer
2021-10-22 14:24  3%       ` Tycho Kirchner
2021-11-15 17:40  9% [BUG] POSIX arith: inf, nan should be variables Martijn Dekker
2021-11-16  9:06  5% ` Oliver Kiddle
2021-11-16 12:55  5% ` Vincent Lefevre
2021-11-28 20:34  5%   ` Oliver Kiddle
2021-12-01  3:31  5%     ` Daniel Shahaf
2021-12-01  3:37  9%       ` Bart Schaefer
2021-12-01  4:27  4%         ` Writing XFail tests (was: Re: [BUG] POSIX arith: inf, nan should be variables) Daniel Shahaf
2021-11-23  6:46  3% [PATCH] Do not define _POSIX_C_SOURCE when checking for sigset_t on Solaris Claes Nästén
2021-12-27 21:37  1% PATCH: update zfs completion Oliver Kiddle
2022-01-31 14:32  3% [PATCH] new completions for csplit, pr, ptx, truncate Jun. T
2022-02-06 17:44  2% can we have an option for cd to do a plain chdir() Stephane Chazelas
2022-03-02 22:38  4% Regression with stdin handling in non-interactive mode between 5.8 and 5.8.1 Lyude Paul
2022-03-03  9:39  5% ` Peter Stephenson
2022-03-03 11:52  5%   ` Peter Stephenson
2022-03-03 22:59  0%     ` Lyude Paul
2022-03-15 16:33     Test ./E03posix.ztst was expected to fail, but passed Vincent Lefevre
2022-03-15 16:53     ` Mikael Magnusson
2022-03-16 15:30  7%   ` Jun. T
2022-03-22  3:32         ` Jun T
2022-03-22 21:04  5%       ` Bart Schaefer
2022-03-23  2:26  3%         ` Vincent Lefevre
2022-03-23 10:38  5%           ` Stephane Chazelas
2022-03-23 16:17  0%             ` Vincent Lefevre
2022-03-23  7:14  4%         ` Jun T
2022-03-29  9:10 15%           ` Jun T
2022-03-24 18:36     _time_zone gives me candidates other than timezones Jordan Russell
2022-03-29 23:22  3% ` Bart Schaefer
2022-03-30  0:12  5%   ` Aaron Schrab
2022-03-31 15:25         ` Jun. T
2022-04-05 23:18  3%       ` Jordan Russell
2022-04-06 20:11  0%         ` Bart Schaefer
     [not found]     <1E0E1226-E3E8-40AD-87CD-93A602B1B08B@easesoftware.com>
     [not found]     ` <CAH+w=7baN47QxGiga9WVTHHny7JnjbbCudfkDKR+qEq1pAgcnw@mail.gmail.com>
     [not found]       ` <36966db7bf519a888d7daca39fdd39f1e39b8511.camel@fifi.org>
     [not found]         ` <CAH+w=7ZRAQTVBfvw1XN=2xEGVNf2ShD6eck+_iv=fGLcEqBLBg@mail.gmail.com>
2022-03-27 17:38  4%       ` [PATCH] Re: Parallel processing Bart Schaefer
2022-03-31  3:58  3% PATCH: Add nonblock to sysopen Matthew Martin
2022-04-03  3:29  5% [PATCH] Change documentation, dedication, loose ends dana
2022-04-09 20:07     Test release: 5.8.1.2-test dana
2022-04-10 20:07     ` Peter Stephenson
2022-04-12  9:16  3%   ` Peter Stephenson
2022-04-11  0:32  4% ` Axel Beckert
2022-04-11  8:30  0%   ` Axel Beckert
2022-04-11 21:14     5.8.1.2-test - test failures running as root Bart Schaefer
2022-04-11 22:38  5% ` [PATCH] " Bart Schaefer
2022-04-28 13:18     Possible missing status info for builtins sysopen and sysseek in zsh/system module Jim
2022-04-28 14:07     ` ERRNO is unset until set Matthew Martin
2022-04-28 14:16       ` Matthew Martin
2022-04-29  6:44         ` Bart Schaefer
2022-04-29 10:00           ` Mikael Magnusson
2022-04-29 17:02  3%         ` Bart Schaefer
2022-04-29 17:08  0%           ` Daniel Shahaf
2022-05-16  7:14     E02 failing on Alpine / musl libc dana
2022-05-17  2:33     ` Jun T
2022-05-19  3:27  4%   ` dana
2022-05-19 19:34     Bug in function in function Klaus Ethgen
2022-05-20 15:37     ` Bart Schaefer
2022-05-20 17:12  3%   ` Klaus Ethgen
2022-05-20 17:16  0%     ` Mikael Magnusson
2022-05-20 17:25  0%       ` Klaus Ethgen
2022-05-20 17:46  0%         ` Peter Stephenson
2022-05-20 17:47  0%         ` Bart Schaefer
2022-05-30 20:31     Minor bug(s) with NO_MULTI_FUNC_DEF Bart Schaefer
2022-05-31  9:03     ` Peter Stephenson
2022-05-31 17:07  3%   ` Bart Schaefer
2022-05-31 17:14  0%     ` Bart Schaefer
2022-06-06  8:45  0%       ` Peter Stephenson
2022-08-19  2:06  3% zargs error with some combinations of arguments Alan Wagner-Krankel
2022-08-19 22:32     An incompatible behavior from bash? Liu Xin
2022-08-20  0:39     ` Lawrence Velázquez
2022-08-22  7:54       ` Liu Xin
2022-08-22 21:44  5%     ` Bart Schaefer
2022-08-23  5:42  0%       ` Liu Xin
2022-08-31 19:36     [RFC PATCH 3/3] FAQ: sync newuser-install Bart Schaefer
2022-09-01  0:23     ` Vincent Lefevre
2022-09-01  0:35       ` Bart Schaefer
2022-09-01  1:21         ` Vincent Lefevre
2022-09-01  2:42           ` [PATCH] initialization of main keymap Bart Schaefer
2022-09-02  0:04             ` Vincent Lefevre
2022-09-02  5:06               ` Bart Schaefer
2022-09-02 13:15                 ` Vincent Lefevre
2022-09-04  9:42                   ` ${EDITOR} with spaces (was: Re: [PATCH] initialization of main keymap) Daniel Shahaf
2022-09-04 10:48                     ` Mikael Magnusson
2022-09-05  9:15  5%                   ` Vincent Lefevre
2022-09-05 21:17  3%                     ` Lawrence Velázquez
2022-09-10 16:04     Deprecation of egrep Vin Shelton
2022-09-10 17:26  3% ` Ellenor Bjornsdottir
2022-10-23 20:19 10% Minimum POSIX standard Clinton Bunch
2022-10-23 21:57  5% ` Mikael Magnusson
2022-10-26  1:51  9%   ` Clinton Bunch
2022-10-26 20:18  5%     ` Bart Schaefer
2022-10-26 20:39  5%       ` Clinton Bunch
2022-10-26 20:44  5%         ` Bart Schaefer
2022-10-26 20:48  5%           ` Clinton Bunch
2022-10-27  7:40  5%             ` Štěpán Němec
2022-11-02 17:13     [PATCH] zsh/random module Clinton Bunch
2022-11-04  3:17     ` dana
2022-11-04  6:22       ` Clinton Bunch
2022-11-04  7:27         ` dana
2022-11-04 12:57           ` Clinton Bunch
2022-11-08  0:18             ` [PATCH] zsh/random module [UPDATED] Clinton Bunch
2022-11-23 19:46               ` Daniel Shahaf
2022-11-24  2:58  4%             ` Clinton Bunch
2022-11-04 16:37     Inconsistent behavior of ERR_EXIT with conditionals Philippe Altherr
2022-11-06 20:45     ` Bart Schaefer
2022-11-07  3:50       ` Bart Schaefer
2022-11-08  4:58         ` Philippe Altherr
2022-11-08  5:36           ` Bart Schaefer
2022-11-08  8:04  3%         ` Lawrence Velázquez
2022-11-08 18:51               ` Philippe Altherr
2022-11-08 19:20  4%             ` Lawrence Velázquez
2022-11-08 23:28  4%             ` Bart Schaefer
2022-11-09  4:11  4%               ` Philippe Altherr
2022-11-06 16:54     There seems to be a problem with the test harness on Solaris 11.4 Clinton Bunch
2022-11-06 18:12     ` Bart Schaefer
2022-11-06 18:28       ` Clinton Bunch
2022-11-06 18:34         ` Clinton Bunch
2022-11-06 19:09  3%       ` Bart Schaefer
2022-11-06 19:32  0%         ` Clinton Bunch
2022-11-07 19:39  0%           ` Clinton Bunch
2022-11-09  3:29  0%             ` [PATCH] diff for test harness (was: There seems to be a problem with the test harness on Solaris 11.4) Clinton Bunch
2022-11-12 22:16  3% [PATCH] More ERR_EXIT (was Re: Tests RE behavior of ERR_EXIT) Philippe Altherr
2022-11-13  3:59  3% ` Philippe Altherr
2022-11-13  4:11       ` Bart Schaefer
2022-11-13 13:55         ` Philippe Altherr
2022-11-13 16:45           ` Bart Schaefer
2022-11-15  1:11             ` Bart Schaefer
2022-11-15  7:01               ` [PATCH] Even more ERR_EXIT (was Re: More ERR_EXIT " Bart Schaefer
2022-11-15  7:30                 ` Philippe Altherr
2022-11-15 19:50  3%               ` Philippe Altherr
2022-11-15  7:26               ` [PATCH] More ERR_EXIT (was " Philippe Altherr
2022-11-15 19:18                 ` Philippe Altherr
2022-11-16  2:41  3%               ` Lawrence Velázquez
2022-11-16  5:51                   ` Bart Schaefer
2022-11-16  7:56  4%                 ` Philippe Altherr
2022-11-16 14:21  0%                   ` Philippe Altherr
2022-11-16 14:40  2% [PATCH] Fix ERR_EXIT behavior in function calls and "always" statements Philippe Altherr
2022-11-19 13:39  0% ` Philippe Altherr
2022-11-21  0:43       ` Bart Schaefer
2022-11-21  7:22         ` Lawrence Velázquez
2022-11-22  2:52  2%       ` Philippe Altherr
2022-11-22 10:17  0%         ` Peter Stephenson
2022-11-23  8:11  3%           ` Lawrence Velázquez
2022-11-23  6:59  3%         ` Lawrence Velázquez
2022-11-23  9:43  4%           ` Philippe Altherr
2022-11-24  4:28  5%             ` Lawrence Velázquez
     [not found]     <f29162cd-28d1-85ed-6a3c-9bec1fb2e13a@eastlink.ca>
     [not found]     ` <CAA-Ti-hhbwZD3-aeMvy_tm5f7SKHw7XN4muJn8ymez1q7rAE_A@mail.gmail.com>
     [not found]       ` <CAN=4vMpCUNgKYgSR+4rmREpA25v_sLHYcS4nfTk8EQ_0Cg5yyw@mail.gmail.com>
     [not found]         ` <5d0c4e22-80b0-2fd2-ee75-6902da52d121@eastlink.ca>
     [not found]           ` <CAH+w=7aeERdOcpPzTmKVQFK7HLduh2s1J9VFzumCh6W0SJFqpg@mail.gmail.com>
     [not found]             ` <57e8e248-bb1a-663a-8557-e3fc13f671d4@eastlink.ca>
     [not found]               ` <CAH+w=7aW9meLuEKSGsKiZMXoAd7KBc9fgakXZnB_t2iphq=BPQ@mail.gmail.com>
     [not found]                 ` <e35c2f14-abda-93d7-bf2c-6823d6d3215d@eastlink.ca>
     [not found]                   ` <CAN=4vMrZzxYVjc63DwU=Scks39FhzmK+E57XerOwusmd64QOjw@mail.gmail.com>
     [not found]                     ` <c2f348d1-8982-d4a4-2c78-a0dd67319b8c@eastlink.ca>
     [not found]                       ` <CAGdYchv9T6ByD7meADqWzdJwAF2SG2YXhasT0=+AQvV+08ZRrA@mail.gmail.com>
2022-12-01 16:30                         ` ERR_RETURN doc Bart Schaefer
2022-12-01 19:30  3%                       ` Philippe Altherr
2022-12-10 11:33  0%                         ` Daniel Shahaf
2022-12-10 14:06  3%                           ` Philippe Altherr
2022-12-11  1:24  4%                             ` Bart Schaefer
2022-12-12 23:35  3%                               ` Philippe Altherr
2022-12-06 18:18     `return` does not behave properly under `!` Michael Greenberg
2022-12-07  8:42  4% ` Stephane Chazelas
2022-12-07 15:05  3%   ` Michael Greenberg
2022-12-07 16:01  3%     ` Stephane Chazelas
2022-12-07 17:10  3%       ` Michael Greenberg
2022-12-09 15:22  3%         ` Michael Greenberg
2022-12-09 16:21  0%           ` Bart Schaefer
2022-12-09 19:20  0%             ` Michael Greenberg
2022-12-07 19:02     [bug report] prompt can erase messages written on the terminal by background processes Millian Poquet
2022-12-07 22:55     ` Roman Perepelitsa
2022-12-08  3:46       ` Bart Schaefer
2022-12-08  8:21         ` Get cursor position (Was: [bug report] prompt can erase messages written on the terminal by background processes) Stephane Chazelas
2022-12-08  8:34           ` Roman Perepelitsa
2022-12-08 10:02             ` Stephane Chazelas
2022-12-08 10:10  3%           ` Stephane Chazelas
2022-12-09  2:19               ` Bart Schaefer
2022-12-09 12:46                 ` Philippe Altherr
2022-12-11 18:00  3%               ` Stephane Chazelas
2022-12-08 21:45     [PATCH] NEWS item about the ERR_EXIT fixes Philippe Altherr
2022-12-09  0:24     ` Bart Schaefer
2022-12-09  6:44  5%   ` Lawrence Velázquez
2022-12-10 11:32  0%     ` Daniel Shahaf
2022-12-10 13:49  3%       ` Philippe Altherr
2022-12-11  3:32  3%         ` Lawrence Velázquez
2022-12-09 14:10     xtrace output sets ERRNO to 9 (EBADF) Stephane Chazelas
2022-12-10  2:57     ` Bart Schaefer
2022-12-10 11:38       ` Daniel Shahaf
2022-12-11 18:35         ` Stephane Chazelas
2022-12-11 18:52           ` Bart Schaefer
2022-12-11 20:01  3%         ` Stephane Chazelas
2022-12-09 15:42  3% read -d $'\200' doesn't work with set +o multibyte Stephane Chazelas
2022-12-09 20:05  2% ` Oliver Kiddle
2022-12-10  9:06  2%   ` read -d $'\200' doesn't work with set +o multibyte (and [PATCH]) Stephane Chazelas
2022-12-13 11:12         ` Jun T
2022-12-14 21:42           ` Oliver Kiddle
2022-12-15 12:37             ` Jun. T
2022-12-16  8:29               ` Oliver Kiddle
2022-12-18 10:51  5%             ` Jun. T
2022-12-18 17:58  3%               ` Stephane Chazelas
2022-12-12 16:06  6% [PATCH] NEWS and README items about ERR_EXIT and ERR_RETURN changes Philippe Altherr
2022-12-16 16:42     zsh_error_db --- hash-based database of error messages Peter Stephenson
2022-12-17 21:33  3% ` Oliver Kiddle
2022-12-19  9:19  0%   ` Peter Stephenson
2022-12-30  5:37  3% Read a line from user without clearing screen below the prompt while allowing user to use arrow keys to make edits in middle of line OG Code Poet
2022-12-30  8:58  0% ` Mikael Magnusson
2023-01-11 23:19     PATCH: move $ERRNO to the system module Oliver Kiddle
2023-01-12 17:14     ` Daniel Shahaf
2023-01-16 21:34  3%   ` Bart Schaefer
2023-01-13  8:02  3% $var not expanded in ${x?$var} Stephane Chazelas
2023-01-28  1:52     ksh compatibility: initial value of $_ Bart Schaefer
2023-03-23 10:40     ` Jun T
2023-03-31  8:18       ` Jun T
2023-03-31 14:31         ` Jun. T
2023-03-31 17:45  3%       ` Bart Schaefer
2023-04-03 12:13         ` Jun. T
2023-04-03 16:50           ` Bart Schaefer
2023-04-04 16:24             ` Jun. T
2023-04-05  1:03  3%           ` Oliver Kiddle
2023-04-05  8:15  0%             ` zeurkous
     [not found]     <1621619253.265114.1678847919086.ref@mail.yahoo.com>
2023-03-15  2:38  2% ` bug report : printf %.1s outputting more than 1 character Jason C. Kwan
2023-03-15  3:46  3%   ` Bart Schaefer
2023-03-15  4:56  1%     ` Jason C. Kwan
2023-03-20  2:16     [PATCH 0/1] Update nm options Shohei YOSHIDA
2023-03-20  2:16 21% ` [PATCH 1/1] " Shohei YOSHIDA
2023-05-05 23:35     PATCH: migrate pcre module to pcre2 Oliver Kiddle
2023-05-06  4:44  3% ` named capture groups with PCRE matching (Was: PATCH: migrate pcre module to pcre2) Stephane Chazelas
2023-05-12 23:12  3% ` PATCH: migrate pcre module to pcre2 Phil Pennock
2023-05-24 18:11  0%   ` Oliver Kiddle
2023-06-13  7:35     ` Jun T
2023-06-19  8:20  4%   ` Jun T
2023-06-04 13:51  4% [Bug] modules zsh/tcp, zsh/zftp unloadable, probably affecting most modern Linuxes Marcus Müller
2023-06-04 20:37  0% ` Marcus Müller
2023-06-04 21:17       ` Philippe Troin
2023-06-05 19:35         ` Marcus Müller
2023-06-05 20:07           ` Bart Schaefer
2023-06-06  6:42             ` Jun T
2023-06-06  9:05               ` Peter Stephenson
2023-06-06 14:38                 ` Jun. T
2023-06-06 15:01                   ` Peter Stephenson
2023-06-06 16:37                     ` Philippe Troin
2023-06-06 17:54  3%                   ` Mikael Magnusson
2023-07-18  9:54  4% [PATCH] Add option like tcsh's dextract Tim Eliseo
2023-08-06 22:41     Bug: The capability CAP_WAKE_ALARM should be whitelisted Robert Woods
2023-08-14 18:39  5% ` [PATCH] 52027: whitelist capability CAP_WAKE_ALARM in 'privasserted' function Robert Woods
2023-10-05 21:29     $watch, log and Cyrillic usernames Максим
2023-10-07  2:05  2% ` Oliver Kiddle
2023-10-07 16:49  0%   ` Максим
2023-10-15 21:54  9% [PATCH] README, NEWS, BUGS updates Bart Schaefer
2023-11-11  5:10  3% Suggested changes to Etc/FAQ Bart Schaefer
2023-11-13 14:18     ` Peter Stephenson
2023-11-16  2:32  3%   ` Bart Schaefer
2023-11-20  0:11  1% PATCH: completion options update Oliver Kiddle
2023-11-24 23:46  2% PATCH: add -q option to kill for sigqueue Oliver Kiddle
     [not found]     <876b57b2-94ec-4e3b-95b8-1aded0562d42@zentaur.org>
     [not found]     ` <d514e295-7bb5-4965-b4fb-f9c1459a6476@app.fastmail.com>
     [not found]       ` <12207c43-6c60-43b5-a993-f3c4dfa72cdb@zentaur.org>
     [not found]         ` <1fad1c05-b6cf-4ec0-b209-1ab04b0fd4ce@app.fastmail.com>
     [not found]           ` <CAH+w=7YrzKuBygXeDt+BkmScJTvqqSwWm-6Y_oFgW1tuFdtk+g@mail.gmail.com>
2023-12-16 20:33  3%         ` set temporary environment variables for builtins Bart Schaefer
2023-12-26  6:01     [PATCH v2] string.c: remove use of strcat() after strlen() James Tirta Halim
2023-12-31  4:22     ` Bart Schaefer
2023-12-31  5:10  3%   ` James
2023-12-31  5:20  0%     ` Bart Schaefer
2024-01-28  0:57  0%     ` Oliver Kiddle
2024-01-19 23:22  9% [PATCH] Fix jobs -p to be POSIX compliant Wesley Schwengle
2024-01-20 12:30  7% ` [PATCH v2] " Wesley Schwengle
2024-01-20 21:14  9%   ` Bart Schaefer
2024-02-04  9:06  6% [PATCH][nitpick-BUG] shebang less scripts and paths starting with -/+ Stephane Chazelas
2024-02-10 16:32  6% ` Stephane Chazelas
2024-02-16 20:09     Is this intentional behavior of typeset -g ? Bart Schaefer
2024-02-17  6:29     ` Regression of typeset output with "private" Bart Schaefer
2024-02-18 19:35  5%   ` Bart Schaefer
2024-02-20  4:54  3%     ` [PATCH] (take 2) Local specials and " Bart Schaefer
2024-02-24 22:01  3% PATCH: real-time signals support Oliver Kiddle
2024-03-04  5:37     [PATCH] Fix crash on unset-through-nameref Bart Schaefer
2024-03-04  6:29     ` Stephane Chazelas
2024-03-04  8:39       ` Bart Schaefer
2024-03-04 19:34         ` Stephane Chazelas
2024-03-04 23:18  3%       ` Bart Schaefer
2024-03-05  8:18  4%         ` Stephane Chazelas
2024-03-05 18:42  0%           ` Bart Schaefer
2024-03-05 19:48  9%             ` unset, POSIX and the export attribute (Was: [PATCH] Fix crash on unset-through-nameref) Stephane Chazelas
2024-03-05  5:52     [PATCH?] Nofork and removing newlines Bart Schaefer
2024-03-05  6:56     ` Stephane Chazelas
2024-03-05 22:48       ` Bart Schaefer
2024-03-06 17:57         ` Stephane Chazelas
2024-03-06 19:45           ` Bart Schaefer
2024-03-06 22:22             ` Mikael Magnusson
2024-03-07  4:53               ` Bart Schaefer
2024-03-07  7:10  3%             ` Stephane Chazelas
2024-03-06 19:43  3%     ` Stephane Chazelas
2024-03-12  4:13     "typeset -p" and no_GLOBAL_EXPORT, other misc Bart Schaefer
2024-03-12  8:49     ` Stephane Chazelas
2024-03-12 18:32       ` Bart Schaefer
2024-03-12 20:06  4%     ` Stephane Chazelas
2024-03-12 20:26         ` Stephane Chazelas
2024-03-12 20:38           ` Bart Schaefer
2024-03-14  2:11  8%         ` [PATCH] More "typeset -p" and GLOBAL_EXPORT Bart Schaefer
2024-03-21 10:07  3% behavior of test true -a \( ! -a \) Vincent Lefevre
2024-03-21 10:28  0% ` Peter Stephenson
2024-03-21 11:04  3%   ` Vincent Lefevre
2024-03-21 11:29  0%     ` Peter Stephenson
2024-03-21 12:18  3%       ` Vincent Lefevre
2024-03-25 16:38  0%       ` Peter Stephenson
2024-03-25 17:36  3%         ` Bart Schaefer
2024-04-03 13:59  5%           ` Vincent Lefevre
2024-03-21 17:39     ` Bart Schaefer
2024-03-23 21:48       ` Bart Schaefer
2024-03-23 22:20  3%     ` Vincent Lefevre
2024-03-23 22:41  0%       ` Bart Schaefer
2024-03-23 23:33  4%         ` Lawrence Velázquez
2024-03-24  0:14  0%           ` Bart Schaefer
2024-03-24  2:52  0%             ` Lawrence Velázquez
2024-03-25 10:23  0%         ` Vincent Lefevre
2024-03-25 15:21  0%           ` Bart Schaefer
2024-04-01 19:59     Aliases that ignore "noaliases" Bart Schaefer
2024-04-01 20:18  3% ` Stephane Chazelas

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).