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: expr length "$val" returns the wrong length for values containing NULL (\\0)
  @ 2015-12-10  4:18  0%   ` D Gowers
  2015-12-10  4:29  0%     ` Nikolay Aleksandrovich Pavlov (ZyX)
  0 siblings, 1 reply; 200+ results
From: D Gowers @ 2015-12-10  4:18 UTC (permalink / raw)
  To: Nikolay Aleksandrovich Pavlov (ZyX); +Cc: zsh-workers

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

Ah, okay. That (commandline arguments not being able to contain NUL)
seems.. a bit anachronistic. But I guess it's never been enough of a
problem to warrant the considerable bother to fix it. Fair enough.

On Thu, Dec 10, 2015 at 2:26 PM, Nikolay Aleksandrovich Pavlov (ZyX) <
kp-pav@yandex.ru> wrote:

>
> 10.12.2015, 04:52, "D Gowers" <finticemo@gmail.com>:
> > Test case:
> >
> > v=$(printf foo\\0bar);expr length "$v";expr length $v
> >
> > alternatively:
> >
> > v=foo$'\0'bar;expr length "$v";expr length $v
> >
> > In zsh, the values returned are 3 and 3.
> > In dash and zsh, the values returned are 6 and 6.
> >
> > Both of those results are wrong, AFAICS (foo$'0'bar is 7 characters
> long).
> > But the zsh result is more severely wrong. I could understand the
> bash/dash
> > result, at least, as 'NULL characters are not counted towards length'.
>
> Both results are *right*. In both cases you ask the length of the string
> and you get it.
>
> In dash (also posh, bash and busybox ash) zero byte is skipped when
> storing. So length of the $v *is* six. You may question whether it is right
> storing without zero byte, but the fact that all four shells have exactly
> the same behaviour makes me think this is part of the POSIX standard. In
> any case non-C strings are not on the list of features of these shells
> unlike zsh (it also internally uses C NUL-terminated strings, but zero
> bytes and some other characters are “metafied” (i.e. escaped) and
> unmetafied when passed to the outer world e.g. by doing `echo $v` to pass
> string to terminal).
>
> As I said in zsh zero byte is stored. But C strings which are the only
> ones that can be arguments to any program are **NUL-terminated**. So what
> you do is passing string "foo" because NUL terminates the string. You
> cannot possibly get the answer you think is right here thus, unless you
> reimplement `expr` as a zsh function.
>
> >
> > In any case, it is easily demonstrated that the string is not 3
> characters
> > long, by running 'echo "$V"' or 'print "$v"' or 'echo ${#v}'
> >
> > `zsh --version` = 'zsh 5.2 (x86_64-unknown-linux-gnu)'
>

^ permalink raw reply	[relevance 0%]

* Re: expr length "$val" returns the wrong length for values containing NULL (\\0)
  2015-12-10  4:18  0%   ` D Gowers
@ 2015-12-10  4:29  0%     ` Nikolay Aleksandrovich Pavlov (ZyX)
  2015-12-10  5:00  0%       ` D Gowers
  0 siblings, 1 reply; 200+ results
From: Nikolay Aleksandrovich Pavlov (ZyX) @ 2015-12-10  4:29 UTC (permalink / raw)
  To: D Gowers; +Cc: zsh-workers

10.12.2015, 07:18, "D Gowers" <finticemo@gmail.com>:
> Ah, okay. That (commandline arguments not being able to contain NUL) seems.. a bit anachronistic. But I guess it's never been enough of a problem to warrant the considerable bother to fix it. Fair enough.

This has nothing to do with the commandline itself. In some very earlier days it was decided that strings will be NUL-terminated (in place of e.g. being structs with size_t size and char *data) and this statement sneaked into many parts of many standards. If you write C code you will have problems when dealing with NUL-terminated string because every library function that accepts something other then void* pointer with “generic data” assumes that string should terminate with NUL. Projects like zsh or almost every programming language have to write their own string implementations: in zsh it is C strings with escaped characters, in most other cases it is length+data pair.

Since one of the functions having NUL convention is exec* function family which is used to launch programs and another is main() function on the other side that accepts NUL-terminated strings you cannot really do anything to fix this: replacing one of the core conventions is *very* expensive, especially since you must do this in a backward-compatible way.

> On Thu, Dec 10, 2015 at 2:26 PM, Nikolay Aleksandrovich Pavlov (ZyX) <kp-pav@yandex.ru> wrote:
>> 10.12.2015, 04:52, "D Gowers" <finticemo@gmail.com>:
>>> Test case:
>>>
>>> v=$(printf foo\\0bar);expr length "$v";expr length $v
>>>
>>> alternatively:
>>>
>>> v=foo$'\0'bar;expr length "$v";expr length $v
>>>
>>> In zsh, the values returned are 3 and 3.
>>> In dash and zsh, the values returned are 6 and 6.
>>>
>>> Both of those results are wrong, AFAICS (foo$'0'bar is 7 characters long).
>>> But the zsh result is more severely wrong. I could understand the bash/dash
>>> result, at least, as 'NULL characters are not counted towards length'.
>>
>> Both results are *right*. In both cases you ask the length of the string and you get it.
>>
>> In dash (also posh, bash and busybox ash) zero byte is skipped when storing. So length of the $v *is* six. You may question whether it is right storing without zero byte, but the fact that all four shells have exactly the same behaviour makes me think this is part of the POSIX standard. In any case non-C strings are not on the list of features of these shells unlike zsh (it also internally uses C NUL-terminated strings, but zero bytes and some other characters are “metafied” (i.e. escaped) and unmetafied when passed to the outer world e.g. by doing `echo $v` to pass string to terminal).
>>
>> As I said in zsh zero byte is stored. But C strings which are the only ones that can be arguments to any program are **NUL-terminated**. So what you do is passing string "foo" because NUL terminates the string. You cannot possibly get the answer you think is right here thus, unless you reimplement `expr` as a zsh function.
>>
>>>
>>> In any case, it is easily demonstrated that the string is not 3 characters
>>> long, by running 'echo "$V"' or 'print "$v"' or 'echo ${#v}'
>>>
>>> `zsh --version` = 'zsh 5.2 (x86_64-unknown-linux-gnu)'


^ permalink raw reply	[relevance 0%]

* Re: expr length "$val" returns the wrong length for values containing NULL (\\0)
  2015-12-10  4:29  0%     ` Nikolay Aleksandrovich Pavlov (ZyX)
@ 2015-12-10  5:00  0%       ` D Gowers
  0 siblings, 0 replies; 200+ results
From: D Gowers @ 2015-12-10  5:00 UTC (permalink / raw)
  To: Nikolay Aleksandrovich Pavlov (ZyX); +Cc: zsh-workers

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

I am aware of the prevalence of NUL-terminated strings, since I've coded in
C in the past, that's why I wrote 'considerable bother to fix it'.
Nevertheless, for a purpose such as argument passing, size + data is
clearly better (easier to secure and more flexible)

On Thu, Dec 10, 2015 at 2:59 PM, Nikolay Aleksandrovich Pavlov (ZyX) <
kp-pav@yandex.ru> wrote:

> 10.12.2015, 07:18, "D Gowers" <finticemo@gmail.com>:
> > Ah, okay. That (commandline arguments not being able to contain NUL)
> seems.. a bit anachronistic. But I guess it's never been enough of a
> problem to warrant the considerable bother to fix it. Fair enough.
>
> This has nothing to do with the commandline itself. In some very earlier
> days it was decided that strings will be NUL-terminated (in place of e.g.
> being structs with size_t size and char *data) and this statement sneaked
> into many parts of many standards. If you write C code you will have
> problems when dealing with NUL-terminated string because every library
> function that accepts something other then void* pointer with “generic
> data” assumes that string should terminate with NUL. Projects like zsh or
> almost every programming language have to write their own string
> implementations: in zsh it is C strings with escaped characters, in most
> other cases it is length+data pair.
>
> Since one of the functions having NUL convention is exec* function family
> which is used to launch programs and another is main() function on the
> other side that accepts NUL-terminated strings you cannot really do
> anything to fix this: replacing one of the core conventions is *very*
> expensive, especially since you must do this in a backward-compatible way.
>
> > On Thu, Dec 10, 2015 at 2:26 PM, Nikolay Aleksandrovich Pavlov (ZyX) <
> kp-pav@yandex.ru> wrote:
> >> 10.12.2015, 04:52, "D Gowers" <finticemo@gmail.com>:
> >>> Test case:
> >>>
> >>> v=$(printf foo\\0bar);expr length "$v";expr length $v
> >>>
> >>> alternatively:
> >>>
> >>> v=foo$'\0'bar;expr length "$v";expr length $v
> >>>
> >>> In zsh, the values returned are 3 and 3.
> >>> In dash and zsh, the values returned are 6 and 6.
> >>>
> >>> Both of those results are wrong, AFAICS (foo$'0'bar is 7 characters
> long).
> >>> But the zsh result is more severely wrong. I could understand the
> bash/dash
> >>> result, at least, as 'NULL characters are not counted towards length'.
> >>
> >> Both results are *right*. In both cases you ask the length of the
> string and you get it.
> >>
> >> In dash (also posh, bash and busybox ash) zero byte is skipped when
> storing. So length of the $v *is* six. You may question whether it is right
> storing without zero byte, but the fact that all four shells have exactly
> the same behaviour makes me think this is part of the POSIX standard. In
> any case non-C strings are not on the list of features of these shells
> unlike zsh (it also internally uses C NUL-terminated strings, but zero
> bytes and some other characters are “metafied” (i.e. escaped) and
> unmetafied when passed to the outer world e.g. by doing `echo $v` to pass
> string to terminal).
> >>
> >> As I said in zsh zero byte is stored. But C strings which are the only
> ones that can be arguments to any program are **NUL-terminated**. So what
> you do is passing string "foo" because NUL terminates the string. You
> cannot possibly get the answer you think is right here thus, unless you
> reimplement `expr` as a zsh function.
> >>
> >>>
> >>> In any case, it is easily demonstrated that the string is not 3
> characters
> >>> long, by running 'echo "$V"' or 'print "$v"' or 'echo ${#v}'
> >>>
> >>> `zsh --version` = 'zsh 5.2 (x86_64-unknown-linux-gnu)'
>

^ permalink raw reply	[relevance 0%]

* [BUG] 'command' + special built-in exits shell on error
@ 2015-12-23 11:53  3% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-12-23 11:53 UTC (permalink / raw)
  To: zsh-workers

Special built-ins may cause the shell to exit on error. Sometimes this
is inconvenient as you cannot test for errors without forking a subshell.

POSIX provides a way around this: the 'command' builtin disables the two
"special built-in" properties of special built-ins, including exiting
from the shell on error.

This means:
    set -o nonexistent_shell_option || echo oops
should produce only an error message and cause the shell to exit, whereas
    command set -o nonexistent_shell_option || echo oops
should output "oops" after the error message and script execution should
continue.

My bug report is that zsh still exits even when 'command' is used, and
even when emulating sh.

bash, ksh93, mksh (as of R51), dash, FreeBSD /bin/sh, NetBSD /bin/sh,
Busybox ash, and yash all do the right thing, suggesting that this
should be fixed in zsh at least in 'emulate sh' mode.

References:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html#tag_20_22
> If the command_name is the same as the name of one of the special
> built-in utilities, the special properties in the enumerated list at
> the beginning of Special Built-In Utilities shall not occur.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14
> [...] the special built-in utilities described here differ from
> regular built-in utilities in two respects:
> 
> 1.  A syntax error in a special built-in utility may cause a shell
> executing that utility to abort, while a syntax error in a regular
> built-in utility shall not cause a shell executing that utility to
> abort. (See Consequences of Shell Errors for the consequences of
> errors on interactive and non-interactive shells.) If a special
> built-in utility encountering a syntax error does not abort the
> shell, its exit value shall be non-zero.
> 
> 2.  Variable assignments specified with special built-in utilities
> remain in effect after the built-in completes; this shall not be the
> case with a regular built-in or other utility.

Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* [BUG] emulate sh: arith assignment assigns variable type
@ 2016-01-01 20:03  3% Martijn Dekker
    0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-01 20:03 UTC (permalink / raw)
  To: zsh-workers

When an assignment is done to an unset variable using an arithmetic
expression, zsh assigns a numerical or arithmetic type to that variable,
causing subsequent normal shell assignments to be interpreted as
arithmetic expressions.

This causes an incompatibility with other shells under 'emulate sh',
because the POSIX shell is supposed to be a typeless language. In sh
emulation mode, arithmetic assignment should not assign a variable type.

Steps to reproduce:

$ emulate sh
$ X=a:b:c
$ : $((X=1))	# no type assignment as variable was already et
$ X=a:b:c
$ unset X
$ : $((X=1))	# variable now restricted to arith expressions
$ X=a:b:c
zsh: bad math expression: ':' without '?'

Expected behaviour: the last assignment should succeed in sh emulation
mode (and does on all other shells).

Confirmed in zsh 4.1.1 through current.

Thanks, and happy new year.

- Martijn


^ permalink raw reply	[relevance 3%]

* [BUG] functions can't create global readonly variables
@ 2016-01-02  3:27  3% Martijn Dekker
  2016-01-02  4:27  4% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-02  3:27 UTC (permalink / raw)
  To: zsh-workers

It is apparently impossible to create global readonly variables from
within a function.

If a variable is created with a command like
    readonly var=value
then the entire variable gets a function-local scope, as if 'local' were
used.

If a global variable is set first, then set to readonly with 'readonly'
or 'typeset -r', then the read-only attribute only lasts within the
function, and the global variable remains read/write.

I don't know if this is intended behaviour for native zsh mode; the
'zshbuiltins' man page does not mention anything about this. But it is
certainly a bug for POSIX/'emulate sh' mode.

Steps to reproduce:

$ fn() { readonly var=foo; var=bar; }
$ fn
fn: read-only variable: var
$ echo $var

$ var=writtento
$ echo $var
writtento
$ fn() { var=foo; readonly var; var=bar; }
$ fn
fn: read-only variable: var
$ echo $var
foo
$ var=writtento
$ echo $var
writtento

Confirmed in zsh 4.1.1 through current.

Thanks,

- Martijn


^ permalink raw reply	[relevance 3%]

* Re: [BUG] functions can't create global readonly variables
  2016-01-02  3:27  3% [BUG] functions can't create global readonly variables Martijn Dekker
@ 2016-01-02  4:27  4% ` Bart Schaefer
  2016-01-02 18:18  3%   ` Peter Stephenson
  2016-01-02 19:39  5%   ` Martijn Dekker
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2016-01-02  4:27 UTC (permalink / raw)
  To: zsh-workers

On Jan 2,  4:27am, Martijn Dekker wrote:
}
} It is apparently impossible to create global readonly variables from
} within a function.

    typeset -gr var=value
or
    readonly -g var=value

} I don't know if this is intended behaviour for native zsh mode; the
} 'zshbuiltins' man page does not mention anything about this.

Of course it does:

    readonly
	 Same as typeset -r.

    typeset ...
	 Set or display attributes and values for shell parameters.

	 A parameter is created for each NAME that does not already refer
	 to one.  When inside a function, a new parameter is created for
	 every NAME (even those that already exist), and is unset again
	 when the function completes.

} But it is certainly a bug for POSIX/'emulate sh' mode.

I think it's undefined behavior for POSIX/'emulate sh'.  Certainly bash
agrees with us:

$ foo() { typeset -r bar; typeset -p bar; }
$ foo
declare -r bar
$ typeset -p bar
bash: typeset: bar: not found


^ permalink raw reply	[relevance 4%]

* Re: [BUG] functions can't create global readonly variables
  2016-01-02  4:27  4% ` Bart Schaefer
@ 2016-01-02 18:18  3%   ` Peter Stephenson
  2016-01-02 20:36  6%     ` Bart Schaefer
  2016-01-02 19:39  5%   ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2016-01-02 18:18 UTC (permalink / raw)
  To: zsh-workers

On Fri, 1 Jan 2016 20:27:10 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> I think it's undefined behavior for POSIX/'emulate sh'.  Certainly bash
> agrees with us:
> 
> $ foo() { typeset -r bar; typeset -p bar; }
> $ foo
> declare -r bar
> $ typeset -p bar
> bash: typeset: bar: not found

Bash is treating "typeset -r bar" differently from "readonly bar".
"readonly" affects any existing parameter or creates its own.
I think readonly is equivalent to "typeset -rg", so it stomps
on any existing global, too (unless it was already readonly).

We could make this optional behaviour for compatibility, possibly with
POSIX_BUILTINS which is a real ragbag of POSIX funnies.

pws


^ permalink raw reply	[relevance 3%]

* Re: [BUG] functions can't create global readonly variables
  2016-01-02  4:27  4% ` Bart Schaefer
  2016-01-02 18:18  3%   ` Peter Stephenson
@ 2016-01-02 19:39  5%   ` Martijn Dekker
  1 sibling, 0 replies; 200+ results
From: Martijn Dekker @ 2016-01-02 19:39 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer schreef op 02-01-16 om 05:27:
> On Jan 2,  4:27am, Martijn Dekker wrote:
> } I don't know if this is intended behaviour for native zsh mode; the
> } 'zshbuiltins' man page does not mention anything about this.
> 
> Of course it does:

I blame insufficient caffeination at the time of writing.

> } But it is certainly a bug for POSIX/'emulate sh' mode.
> 
> I think it's undefined behavior for POSIX/'emulate sh'.  Certainly bash
> agrees with us:
> 
> $ foo() { typeset -r bar; typeset -p bar; }
> $ foo
> declare -r bar
> $ typeset -p bar
> bash: typeset: bar: not found

But 'typeset' is not POSIX. When using the POSIX 'readonly' special
builtin, bash acts like other POSIX shells and unlike zsh:

$ foo() { readonly bar=baz; typeset -p bar; }
$ foo
declare -r bar="baz"
$ typeset -p bar
declare -r bar="baz"

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: [BUG] functions can't create global readonly variables
  2016-01-02 18:18  3%   ` Peter Stephenson
@ 2016-01-02 20:36  6%     ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-01-02 20:36 UTC (permalink / raw)
  To: zsh-workers

On Jan 2,  6:18pm, Peter Stephenson wrote:
} 
} I think readonly is equivalent to "typeset -rg", so it stomps
} on any existing global, too (unless it was already readonly).
} 
} We could make this optional behaviour for compatibility, possibly with
} POSIX_BUILTINS which is a real ragbag of POSIX funnies.

Yes, this seems like a job for POSIX_BUILTINS.

I would note that even with -g there is no way to create an actual global
variable in the event that some intervening function has declared a name
to be local.

BIN_EXPORT was defined but never used, so ...

What additional test case should we have?


diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index dc0b947..fb630a7 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1465,7 +1465,10 @@ cancels both tt(-p) and tt(-u).
 The tt(-c) or tt(-l) flags cancel any and all of tt(-kpquz).
 )
 cindex(parameters, marking readonly)
-alias(readonly)(typeset -r)
+item(tt(readonly))(
+Same as tt(typeset -r).  With the tt(POSIX_BUILTINS) option set, same
+as tt(typeset -gr).
+)
 alias(rehash)(hash -r)
 findex(return)
 cindex(functions, returning from)
diff --git a/Src/builtin.c b/Src/builtin.c
index 05907f1..557487c 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -62,7 +62,7 @@ static struct builtin builtins[] =
     BUILTIN("enable", 0, bin_enable, 0, -1, BIN_ENABLE, "afmprs", NULL),
     BUILTIN("eval", BINF_PSPECIAL, bin_eval, 0, -1, BIN_EVAL, NULL, NULL),
     BUILTIN("exit", BINF_PSPECIAL, bin_break, 0, 1, BIN_EXIT, NULL, NULL),
-    BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_EXPORT, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
+    BUILTIN("export", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "E:%F:%HL:%R:%TUZ:%afhi:%lprtu", "xg"),
     BUILTIN("false", 0, bin_false, 0, -1, 0, NULL, NULL),
     /*
      * We used to behave as if the argument to -e was optional.
@@ -106,7 +106,7 @@ static struct builtin builtins[] =
     BUILTIN("pwd", 0, bin_pwd, 0, 0, 0, "rLP", NULL),
     BUILTIN("r", 0, bin_fc, 0, -1, BIN_R, "IlLnr", NULL),
     BUILTIN("read", 0, bin_read, 0, -1, 0, "cd:ek:%lnpqrst:%zu:AE", NULL),
-    BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, 0, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"),
+    BUILTIN("readonly", BINF_PLUSOPTS | BINF_MAGICEQUALS | BINF_PSPECIAL | BINF_ASSIGN, (HandlerFunc)bin_typeset, 0, -1, BIN_READONLY, "AE:%F:%HL:%R:%TUZ:%afghi:%lptux", "r"),
     BUILTIN("rehash", 0, bin_hash, 0, 0, 0, "df", "r"),
     BUILTIN("return", BINF_PSPECIAL, bin_break, 0, 1, BIN_RETURN, NULL, NULL),
     BUILTIN("set", BINF_PSPECIAL | BINF_HANDLES_OPTS, bin_set, 0, -1, 0, NULL, NULL),
@@ -2533,6 +2533,10 @@ bin_typeset(char *name, char **argv, LinkList assigns, Options ops, int func)
     if (OPT_ISSET(ops,'f'))
 	return bin_functions(name, argv, ops, func);
 
+    /* POSIX handles "readonly" specially */
+    if (func == BIN_READONLY && isset(POSIXBUILTINS) && !OPT_PLUS(ops, 'g'))
+	ops->ind['g'] = 1;
+
     /* Translate the options into PM_* flags.   *
      * Unfortunately, this depends on the order *
      * these flags are defined in zsh.h         */
diff --git a/Src/hashtable.h b/Src/hashtable.h
index b6346bb..3606e97 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -53,7 +53,7 @@
 #define BIN_LOGOUT   19
 #define BIN_TEST     20
 #define BIN_BRACKET  21
-#define BIN_EXPORT   22
+#define BIN_READONLY 22
 #define BIN_ECHO     23
 #define BIN_DISABLE  24
 #define BIN_ENABLE   25
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 7d65cc8..681fe73 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -479,12 +479,12 @@
    setopt POSIXBUILTINS
    readonly pbro
    print ${+pbro} >&2
-   (typeset pbro=3)
+   (typeset -g pbro=3)
    (pbro=4)
-   readonly -p | grep pbro >&2  # shows up as "readonly" although unset
-   typeset -r pbro        # idempotent (no error)...
+   readonly -p pbro >&2   # shows up as "readonly" although unset
+   typeset -gr pbro       # idempotent (no error)...
    print ${+pbro} >&2     # ...so still readonly...
-   typeset +r pbro        # ...can't turn it off
+   typeset -g +r pbro     # ...can't turn it off
  )
 1:readonly with POSIX_BUILTINS
 ?0


^ permalink raw reply	[relevance 6%]

* Re: [BUG] emulate sh: arith assignment assigns variable type
  @ 2016-01-02 21:12  4%     ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-01-02 21:12 UTC (permalink / raw)
  To: zsh-workers

On Sat, 2 Jan 2016 12:46:59 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On the other hand, is this --
> 
> }  	pm = createparam(t, ss ? PM_ARRAY :
> } +			 isset(POSIXIDENTIFIERS) ? PM_SCALAR :
> }  			 (val.type & MN_INTEGER) ? PM_INTEGER : PM_FFLOAT);
> 
> -- really the correct fix?  I was thinking more along the lines of
> creating it as an integer but then changing the type back to scalar
> at the time of assignment if the assigned string did not parse as an
> arithmetic expression.

That's obviously not what other POSIX shells do, so I don't see how that
can be right.  It's forcing arithmetic evaaluation in cases those shells
wouldn't.  The POSIX* options aren't supposed to be for anything more
than strict(ish) compatibility.

pws


^ permalink raw reply	[relevance 4%]

* [BUG] quoting within bracket patterns has no effect
@ 2016-01-18  4:23  3% Martijn Dekker
    0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-18  4:23 UTC (permalink / raw)
  To: zsh-workers, ast-developers

Quotes should disable the special meaning of characters in glob
patterns[*]. So this:

case b in
( ['a-c'] ) echo 'false match' ;;
( [a-c] )   echo 'correct match' ;;
esac

should output "correct match". But on zsh and AT&T ksh93 (and only
those), it outputs "false match". Meaning, quoting the characters within
the bracket pattern does not disable the special meaning of '-' in the
bracket pattern.

This hinders a realistic use case: the ability to pass a series of
arbitrary characters in a variable for use within a bracket pattern.
Quoting the variable does not have any effect; if the series contains a
'-', the result is unexpected. For example:

mychars='abs$ad-f3ra'  # arbitrary series of characters containing '-'
somevar=qezm           # this contains none of the characters above
case $somevar in
( *["$mychars"]* )  echo "$somevar contains one of $mychars" ;;
esac

produces a false positive on zsh and ksh93.

A workaround is to make sure the '-', if any, is always last in the
string of characters to match against.

The same thing also affects glob patterns in other contexts, e.g.
removing characters using parameter substitution.

Other shells, at least bash, (d)ash variants, pdksh, mksh and yash, all
act like POSIX says they should, according to my tests.	

Thanks,

- Martijn

[*] "If any character (ordinary, shell special, or pattern special) is
quoted, that pattern shall match the character itself."
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01


^ permalink raw reply	[relevance 3%]

* test is not posix
@ 2016-01-20 21:06  9% Trek
  2016-01-20 21:38  5% ` Bart Schaefer
  2016-01-20 23:46 10% ` Martijn Dekker
  0 siblings, 2 replies; 200+ results
From: Trek @ 2016-01-20 21:06 UTC (permalink / raw)
  To: zsh-workers

the -n and -z options of the test utility are not posixly correct if the
argument is "!", "(", ")" or "-a"

with a posix shell:

  $ sh -c 'test -n "!" && echo ok'
  ok

with zsh called as sh:

  $ zsh/sh -c 'test -n "!" && echo ok'
  zsh:test:1: too many arguments

a workaround exist:

  $ zsh/sh -c 'test "X!" != "X" && echo ok'
  ok

but the posix standard requires -n and -z to be safe even if the
argument is '!' or '(':

  The two commands: test "$1" and test ! "$1" could not be used reliably
  on some historical systems. Unexpected results would occur if such a
  string expression were used and $1 expanded to '!', '(', or a known
  unary primary. Better constructs are: test -n "$1" and test -z "$1"
  respectively. 

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_16


I discovered this bug developing a small shell library, where you can
find an use case in the n_str_set function of the lib/str.sh file
included in http://www.trek.eu.org/devel/naive/naive-0.0.2.tar.gz

c-ya!


^ permalink raw reply	[relevance 9%]

* Re: test is not posix
  2016-01-20 21:06  9% test is not posix Trek
@ 2016-01-20 21:38  5% ` Bart Schaefer
  2016-01-20 21:44  5%   ` Trek
  2016-01-20 23:46 10% ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2016-01-20 21:38 UTC (permalink / raw)
  To: Trek, zsh-workers

On Jan 20, 10:06pm, Trek wrote:
}
} the -n and -z options of the test utility are not posixly correct if the
} argument is "!", "(", ")" or "-a"

I'm not able to reproduce this; what is the $ZSH_VERSION or $ZSH_PATCHLEVEL
that you are testing?  What do you see if you run with the -x option?

% ARGV0=sh Src/zsh -c 'test -n "!" && echo OK'
OK
% 



^ permalink raw reply	[relevance 5%]

* Re: test is not posix
  2016-01-20 21:38  5% ` Bart Schaefer
@ 2016-01-20 21:44  5%   ` Trek
  0 siblings, 0 replies; 200+ results
From: Trek @ 2016-01-20 21:44 UTC (permalink / raw)
  To: zsh-workers

On Wed, 20 Jan 2016 13:38:58 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:

> On Jan 20, 10:06pm, Trek wrote:
> } the -n and -z options of the test utility are not posixly correct
> if the } argument is "!", "(", ")" or "-a"
> 
> I'm not able to reproduce this; what is the $ZSH_VERSION or
> $ZSH_PATCHLEVEL that you are testing?  What do you see if you run
> with the -x option?

sorry, I missed to include that I'm using the 5.0.7-5 version included
in Debian GNU/Linux 8 (jessie)

> % ARGV0=sh Src/zsh -c 'test -n "!" && echo OK'
> OK

happy to see that it is already fixed in the latest version, where on my
system it prints the same error reported

c-ya!


^ permalink raw reply	[relevance 5%]

* Re: test is not posix
  2016-01-20 21:06  9% test is not posix Trek
  2016-01-20 21:38  5% ` Bart Schaefer
@ 2016-01-20 23:46 10% ` Martijn Dekker
  2016-01-21 12:41  5%   ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-20 23:46 UTC (permalink / raw)
  To: Trek, zsh-workers

Trek schreef op 20-01-16 om 22:06:
> with zsh called as sh:
> 
>   $ zsh/sh -c 'test -n "!" && echo ok'
>   zsh:test:1: too many arguments

I think this might be the same bug that I reported back in May with
  test -n '('
and
  test -n ')'
http://www.zsh.org/mla/workers/2015/msg01225.html

Peter Stephenson fixed it less than 45 minutes later:
http://www.zsh.org/mla/workers/2015/msg01230.html

I hadn't noticed it fails on a single exclamation point as well.
It is in zsh 5.0.6 and 5.0.7. Got fixed in 5.0.8.

A lot more POSIX bugs have been fixed since, so the latest version is
recommended if you care about POSIX compliance.

> I discovered this bug developing a small shell library, where you can
> find an use case in the n_str_set function of the lib/str.sh file
> included in http://www.trek.eu.org/devel/naive/naive-0.0.2.tar.gz

As luck would have it, I'm developing a shell library too, including a
whole battery of bug and feature tests for POSIX shells. We should
exchange notes. I won't have time for the next few days, but I'll be in
touch.

Thanks,

- Martijn


^ permalink raw reply	[relevance 10%]

* Re: test is not posix
  2016-01-20 23:46 10% ` Martijn Dekker
@ 2016-01-21 12:41  5%   ` Peter Stephenson
  2016-01-21 13:06  9%     ` [BUG] 'test' returns 1 (not >1) on error [was: test is not posix] Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-01-21 12:41 UTC (permalink / raw)
  To: zsh-workers

On Thu, 21 Jan 2016 00:46:47 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> Trek schreef op 20-01-16 om 22:06:
> > with zsh called as sh:
> > 
> >   $ zsh/sh -c 'test -n "!" && echo ok'
> >   zsh:test:1: too many arguments
> 
> I think this might be the same bug that I reported back in May with
>   test -n '('
> and
>   test -n ')'
> http://www.zsh.org/mla/workers/2015/msg01225.html

Yes, we now have tests for the following cases.  It's trivial to add more
if you can think of any that might be problematic.

pws

  test -z \( || print Not zero 1
  test -z \< || print Not zero 2
  test -n \( && print Not zero 3
  test -n \) && print Not zero 4
  [ -n \> ] && print Not zero 5
  [ -n \! ] && print Not zero 6
0:test with two arguments and a token
>Not zero 1
>Not zero 2
>Not zero 3
>Not zero 4
>Not zero 5
>Not zero 6


^ permalink raw reply	[relevance 5%]

* [BUG] 'test' returns 1 (not >1) on error [was: test is not posix]
  2016-01-21 12:41  5%   ` Peter Stephenson
@ 2016-01-21 13:06  9%     ` Martijn Dekker
  2016-01-21 16:20  4%       ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-21 13:06 UTC (permalink / raw)
  To: zsh-workers; +Cc: Peter Stephenson

Peter Stephenson schreef op 21-01-16 om 13:41:
> Yes, we now have tests for the following cases.  It's trivial to add more
> if you can think of any that might be problematic.

Something I also noticed back in May, and which I'm now reminded of, is
that test/[ returns status 1, and not 2 or higher, if an error occurs.

$ [ x = a b ]
[: too many arguments
$ echo $?
1
$ [ 1 -eq ]
zsh: parse error: condition expected: 1
$ echo $?
1

This makes it impossible to test for the failure of test/[ using the
exit status.

POSIX says the status should be 2 or higher on error:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html#tag_20_128_14

Thanks,

- Martijn


^ permalink raw reply	[relevance 9%]

* Re: [BUG] 'test' returns 1 (not >1) on error [was: test is not posix]
  2016-01-21 13:06  9%     ` [BUG] 'test' returns 1 (not >1) on error [was: test is not posix] Martijn Dekker
@ 2016-01-21 16:20  4%       ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-01-21 16:20 UTC (permalink / raw)
  To: zsh-workers

On Thu, 21 Jan 2016 14:06:38 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> Something I also noticed back in May, and which I'm now reminded of, is
> that test/[ returns status 1, and not 2 or higher, if an error occurs.

It's correct inside the condition code, so this is yet another thing the
test builtin needs fixing up for.

diff --git a/Src/builtin.c b/Src/builtin.c
index dd20f9e..98ecb09 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -6531,7 +6531,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
 	for (s = argv; *s; s++);
 	if (s == argv || strcmp(s[-1], "]")) {
 	    zwarnnam(name, "']' expected");
-	    return 1;
+	    return 2;
 	}
 	s[-1] = NULL;
     }
@@ -6574,19 +6574,19 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
     if (errflag) {
 	errflag &= ~ERRFLAG_ERROR;
 	zcontext_restore();
-	return 1;
+	return 2;
     }
 
     if (!prog || tok == LEXERR) {
 	zwarnnam(name, tokstr ? "parse error" : "argument expected");
 	zcontext_restore();
-	return 1;
+	return 2;
     }
     zcontext_restore();
 
     if (*curtestarg) {
 	zwarnnam(name, "too many arguments");
-	return 1;
+	return 2;
     }
 
     /* syntax is OK, so evaluate */
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 0b4608a..88cad0d 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -223,27 +223,27 @@ F:Failures in these cases do not indicate a problem in the shell.
 0:substitution in `[' builtin
 
   [ -n foo scrimble ]
-1:argument checking for [ builtin
+2:argument checking for [ builtin
 ?(eval):[:1: too many arguments
 
   test -n foo scramble
-1:argument checking for test builtin
+2:argument checking for test builtin
 ?(eval):test:1: too many arguments
 
   [ -n foo scrimble scromble ]
-1:argument checking for [ builtin
+2:argument checking for [ builtin
 ?(eval):[:1: too many arguments
 
   test -n foo scramble scrumble
-1:argument checking for test builtin
+2:argument checking for test builtin
 ?(eval):test:1: too many arguments
 
   [ -n foo -a -n bar scrimble ]
-1:argument checking for [ builtin
+2:argument checking for [ builtin
 ?(eval):[:1: too many arguments
 
   test -n foo -a -z "" scramble
-1:argument checking for test builtin
+2:argument checking for test builtin
 ?(eval):test:1: too many arguments
 
   fn() {


^ permalink raw reply	[relevance 4%]

* Re: [BUG] quoting within bracket patterns has no effect
  @ 2016-01-23  1:49  3%     ` Bart Schaefer
  2016-01-26  4:03  0%       ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-01-23  1:49 UTC (permalink / raw)
  To: zsh-workers

On Jan 23, 12:17am, Martijn Dekker wrote:
}
} However, for variables there is now a new problem, the opposite of the
} old one: unlike in every other shell, a range is not recognised even if
} the variable is *not* quoted. So quoting a variable still has no effect,
} it's just that range parsing from variables was disabled altogether. The
} following code:
} 
} myrange='a-z'
} somevar='c'
} case $somevar in
} ( *[$myrange]* )  echo "$somevar is part of $myrange" ;;
} esac
} 
} outputs "c is part of a-z" on every shell except current zsh.

This is related to long-standing behavior for zsh in native mode.

In as-close-as-zsh-has-to-POSIX mode:

schaefer[655] ARGV0=sh Src/zsh
$ myrange='a-z'
$ somevar='c'
$ case $somevar in
> ( *[$myrange]* )  echo "$somevar is part of $myrange" ;;
> esac
c is part of a-z
$ 


In native mode you need to use $~param to activate pattern characters
in the expanded value:

schaefer[656] Src/zsh -f
torch% myrange='a-z'
torch% somevar='c'
torch% case $somevar in
case> ( *[$~myrange]* )  echo "$somevar is part of $myrange" ;;
case> esac
c is part of a-z
torch% 


It's true that needing this inside a character class now differs from
previous versions of zsh for native mode.  I'm not sure it's possible
to have it both ways.


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] typeset: set $? on incidental error
  @ 2016-01-24  3:32  3% ` Eric Cook
  0 siblings, 0 replies; 200+ results
From: Eric Cook @ 2016-01-24  3:32 UTC (permalink / raw)
  To: zsh-workers

On 01/23/2016 06:53 PM, Daniel Shahaf wrote:
> Between all the replies I'm convinced that the builtin interface of
> 'local' shouldn't be changed: «builtin local x=$(false)» should set $?
> to 0.  (I meant to say that in a previous email.)
> 
> However, the question remains, in my eyes, whether the change should be
> made to the reserved word interface.  The reserved word 'typeset' is not
> a command, but part of the shell's language, so in
> .
>     typeset x=$(foo) y=$(bar)
> .
> the last command executed is 'bar'.  I would expect that line to behave
> as similarly to
> .
>     x=$(foo) y=$(bar)
> .
> as possible, so for example, I'd expect the former to set $? to the exit
> code of 'bar', as the latter statement does.
> 
> Cheers,
> 
> Daniel
> 

1(again): the other shells with typeset don't behave that way,
the chances of those shells seeing this a good idea and implementing it
are pretty slim in my opinion.

typeset originated in ksh and ksh93's development has pretty much stalled
over the past few years. When not following posix sh, bash tends to align with
the way ksh does things. needless to say that the other kshs tend to do the same.

Most likely resulting in one more way our typeset differs. zsh's typeset became
a reserved word recently in an attempt behave more like the other typesets.

2: typeset while now part of the `language', still retains it's own exit statuses
from when it was a builtin command.
''
typeset -T foo=bar baz=qux; echo $?; typeset -p foo baz
typeset: second argument of tie must be array: baz
1
typeset: no such variable: foo
typeset: no such variable: baz
''

So in the event that typeset _and_ your arbitrary commands errors, what should $?
be set to?
''
typeset -Z 1.1 foo=$(exit 42)
echo $? # 1 or 42?
''

3: in the `real world' if you are assigning a parameter via command substitution
and there is a possibility that the command substitution could return nothing.
You would get the parameter a default value. During assignment or during expansion.
''
typeset foo=${"$(exit 42)":-default}
# or
echo ${foo:=default} # or :-
''


^ permalink raw reply	[relevance 3%]

* Re: Amusing (?) behavior of zsh/parameter specials
  @ 2016-01-24 18:26  3% ` Peter Stephenson
  2016-01-26  5:11  3%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-01-24 18:26 UTC (permalink / raw)
  To: zsh-workers

On Sat, 23 Jan 2016 09:07:36 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> Maybe autoloaded parameters should always be hidden until they load?

That's definitely arguable, yes.  -p and its features are there as a
concession to POSIX-style order, in order to make it easy to restore
parameters the user has defined, and autoloaded parameters, whether
disappearing or not, don't fit that picture.

pws


^ permalink raw reply	[relevance 3%]

* Re: [BUG] quoting within bracket patterns has no effect
  2016-01-23  1:49  3%     ` Bart Schaefer
@ 2016-01-26  4:03  0%       ` Martijn Dekker
  2016-01-26  4:48  4%         ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-26  4:03 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

Bart Schaefer schreef op 23-01-16 om 01:49:
> This is related to long-standing behavior for zsh in native mode.
> 
> In as-close-as-zsh-has-to-POSIX mode:

(Which, by the way, is very close now.)

> In native mode you need to use $~param to activate pattern characters
> in the expanded value:
> 
> schaefer[656] Src/zsh -f
> torch% myrange='a-z'
> torch% somevar='c'
> torch% case $somevar in
> case> ( *[$~myrange]* )  echo "$somevar is part of $myrange" ;;
> case> esac
> c is part of a-z
> torch% 
> 
> 
> It's true that needing this inside a character class now differs from
> previous versions of zsh for native mode.  I'm not sure it's possible
> to have it both ways.

In normal variable expansion, setting the option SH_WORD_SPLIT causes
unquoted $var to be equivalent to ${~var} in variable expansion.
Wouldn't it make sense to have SH_WORD_SPLIT activate pattern characters
in unquoted variables in range expressions as well? This would make zsh
under 'emulate sh' exactly compatible with bash, (d)ash, {pd,m}ksh and yash.

- Martijn


^ permalink raw reply	[relevance 0%]

* Re: [BUG] quoting within bracket patterns has no effect
  2016-01-26  4:03  0%       ` Martijn Dekker
@ 2016-01-26  4:48  4%         ` Bart Schaefer
  2016-01-26 14:07  0%           ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-01-26  4:48 UTC (permalink / raw)
  To: zsh-workers

On Jan 26,  4:03am, Martijn Dekker wrote:
}
} In normal variable expansion, setting the option SH_WORD_SPLIT causes
} unquoted $var to be equivalent to ${~var} in variable expansion.
} Wouldn't it make sense to have SH_WORD_SPLIT activate pattern characters
} in unquoted variables in range expressions as well?

Look again at my first example from the previous message:

schaefer[691] Src/zsh -f
torch% emulate sh
torch% myrange='a-z'
torch% somevar='c'
torch% case $somevar in
case> ( *[$myrange]* )  echo "$somevar is part of $myrange" ;;
case> esac
c is part of a-z
torch% print $ZSH_PATCHLEVEL
zsh-5.2-103-g69c86cd

What about that is incorrect?  You need $~myrange for "emulate zsh" but
NOT for "emulate sh", unless I'm missing something.

Also it's never been "setopt shwordsplit" that enables patterns in a
parameter expansion, rather it's "setopt globsubst":

schaefer[692] Src/zsh -f
torch% x='c*h'
torch% print $x
c*h
torch% setopt shwordsplit
torch% print $x
c*h
torch% setopt globsubst
torch% print $x
config.h config.modules.sh

What I was pointing out when I said "I'm not sure it's possible to have
it both ways" has ONLY to do with "emulate zsh".  The problem is that
the parsing happens at two different places -- at the time $myrange is
expanded, I don't believe the parameter substitution code knows it's
inside a character set in an active pattern; so there's no way to
temporarily activate globsubst except by explicity doing so.

This may be a case where native zsh is incompatible with POSIX at a
fairly fundamental level; old working zsh scripts are potentially going
to break, and I don't think we can do anything about it unless we want
to tell POSIX to go pound sand.


^ permalink raw reply	[relevance 4%]

* Re: Amusing (?) behavior of zsh/parameter specials
  2016-01-24 18:26  3% ` Peter Stephenson
@ 2016-01-26  5:11  3%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-01-26  5:11 UTC (permalink / raw)
  To: zsh-workers

On Jan 24,  6:26pm, Peter Stephenson wrote:
} Subject: Re: Amusing (?) behavior of zsh/parameter specials
}
} On Sat, 23 Jan 2016 09:07:36 -0800
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > Maybe autoloaded parameters should always be hidden until they load?
} 
} That's definitely arguable, yes.  -p and its features are there as a
} concession to POSIX-style order, in order to make it easy to restore
} parameters the user has defined, and autoloaded parameters, whether
} disappearing or not, don't fit that picture.

Two competing potential patches for this.


I lean a little bit toward this one:

diff --git a/Src/params.c b/Src/params.c
index b2e8897..a1f0292 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5258,7 +5258,8 @@ printparamnode(HashNode hn, int printflags)
 
     if (printflags & PRINT_TYPESET) {
 	if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
-	    (PM_READONLY|PM_SPECIAL)) {
+	    (PM_READONLY|PM_SPECIAL) ||
+	    (p->node.flags & PM_AUTOLOAD)) {
 	    /*
 	     * It's not possible to restore the state of
 	     * these, so don't output.


But this one has its attractions as well:

diff --git a/Src/params.c b/Src/params.c
index b2e8897..0ec0042 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5265,7 +5265,10 @@ printparamnode(HashNode hn, int printflags)
 	     */
 	    return;
 	}
-	printf("typeset ");
+	if (p->node.flags & PM_AUTOLOAD)
+	    printf("unset ");
+	else
+	    printf("typeset ");
     }
 
     /* Print the attributes of the parameter */


The main problem with the latter one is that, if the parameter really
is read-only after autoloading, "restoring" the unset will fail.  I
guess the point is to restore the parameters that ARE set, so now that
I've written this all down I lean even more to the first variant.


^ permalink raw reply	[relevance 3%]

* Re: [BUG] quoting within bracket patterns has no effect
  2016-01-26  4:48  4%         ` Bart Schaefer
@ 2016-01-26 14:07  0%           ` Martijn Dekker
  2016-01-27  3:05  4%             ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-01-26 14:07 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

Bart Schaefer schreef op 26-01-16 om 04:48:
> What about that is incorrect?  You need $~myrange for "emulate zsh" but
> NOT for "emulate sh", unless I'm missing something.
[...]
> What I was pointing out when I said "I'm not sure it's possible to have
> it both ways" has ONLY to do with "emulate zsh".

Indeed, I got the wrong end of the stick there. Sorry about that.

> This may be a case where native zsh is incompatible with POSIX at a
> fairly fundamental level;

Sure, but native zsh is its own entity, which is fine.

Thanks,

- M.


^ permalink raw reply	[relevance 0%]

* Re: [BUG] quoting within bracket patterns has no effect
  2016-01-26 14:07  0%           ` Martijn Dekker
@ 2016-01-27  3:05  4%             ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-01-27  3:05 UTC (permalink / raw)
  To: zsh-workers

On Jan 26,  2:07pm, Martijn Dekker wrote:
}
} > This may be a case where native zsh is incompatible with POSIX at a
} > fairly fundamental level;
} 
} Sure, but native zsh is its own entity, which is fine.

Yes, but the point is this incompatibility is so fundamental that the
same code can't even support both alternatives.  To support POSIX we
have to "break" native zsh.


^ permalink raw reply	[relevance 4%]

* Is "command" working right, yet?
@ 2016-02-03  0:37  4% Bart Schaefer
  2016-02-07 15:24  4% ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-02-03  0:37 UTC (permalink / raw)
  To: zsh-workers

command [ -pvV ]
     The command word is taken to be the name of an external command,
     rather than a shell function or builtin.   If the POSIX_BUILTINS
     option is set, builtins will also be executed but certain special
     properties of them are suppressed. The -p flag causes a default
     path to be searched instead of that in $path. With the -v flag,
     command is similar to whence and with -V, it is equivalent to
     whence -v.

Prelimnaries:

I've created my own "true" at the head of $path to be able to distinguish
the builtin from the external command.  It just echoes EXTERNAL, like so:

burner% disable true
burner% true
EXTERNAL

First let's talk about option parsing.

burner% command -p -V true
zsh: command not found: -V
burner% command -V -p true
command: bad option: -p
burner% command -pv true
zsh: command not found: -pv

Those options can be combined in both bash and ksh.  Setting posixbuiltins
makes no difference to zsh:

burner% setopt posixbuiltins
burner% command -p -V true
zsh: command not found: -V
burner% command -V -p true  
command: bad option: -p

I think this is pretty clearly a bug.

The next question has to do with builtins and path search.  There was a
long thread about this on the austin-group (POSIX standards) list several
weeks ago and I'm still not sure what the final outcome implies.  The
issue is the circumstances in which builtins are allowed to mask commands
in $PATH. Starting over with a fresh "zsh -f" so the builtin is enabled
and NO_POSIX_BUILTINS, "command" runs the external but "command -p" runs
the builtin:

burner% command true
EXTERNAL
burner% command -p true
burner% 

The latter seems a little odd to me, but I suppose that means that when
the doc says "a default path" it means one with builtins implicitly at the
front?  However, it relates to the last question:

Using the versions available on my Ubuntu desktop, and default $PATH, all
of bash, ksh, and zsh with POSIX_BUILTINS, execute the builtin for both
"command" and "command -p".  Anybody know if that's correct?  If it is,
how does one force the use of the external command in [the forthcoming]
POSIX?  (If it involves magic syntax in $PATH, I can't assert that zsh
is going to adopt it, but I'd still like to know the answer.)


^ permalink raw reply	[relevance 4%]

* Re: Should (t)path = array-unique-special work this way
  @ 2016-02-05 17:15  3% ` Bart Schaefer
  2016-02-14 10:04  0%   ` Sebastian Gniazdowski
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-02-05 17:15 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 5,  2:45pm, Sebastian Gniazdowski wrote:
}
} typeset -U path
} PATH="$PATH:/component/nr1"
} path+="/component/nr2"
} PATH="/component/nr2:$PATH"
} print "${(t)path}"
} declare -p path

I'm not really sure what question(s) you're asking.

Aside:
 Although it works to append to an array with path+="/component/nr2",
 it's really not good form.  Get used to path+=("/component/nr2") and
 you'll have much less trouble later.

Back to main topic:

} Outputs:
} array-unique-special

So far so good.

} typeset -a path
} path=( /component/nr2 /usr/local/bin /usr/bin /bin /usr/games /component/nr1 /component/nr2 )

For 5.3, this will change to

typeset -a path=( /component/nr2 /usr/local/bin /usr/bin /bin /usr/games /component/nr1 /component/nr2 )

Other things you might be asking about:

Q: Why is nr2 repeated when path is declared -U ?
A: Because it's repeated in $PATH.  Array uniqueness of tied arrays is
   only applied when assigning to the array; when assigning to the tied
   scalar, the array faithfully copies the value of the scalar.  If this
   were not the case, you could end up with a feedback loop (scalar is
   changed -> array uniquifies -> scalar changes again -> etc.).  This
   in turn is because scalars don't have a "uniqueness" property, so if
   the user is explicitly assigning to the scalar then we presume it is
   expected to reflect the value so assigned.

Q: Why doesn't -U appear in the "declare -p" output?
A: Good question.  It doesn't appear for non-special arrays either.  It
   may be intentional because -U isn't a POSIX-supported option, but I
   suspect it's just an accidental omission.


^ permalink raw reply	[relevance 3%]

* Re: Is "command" working right, yet?
  2016-02-03  0:37  4% Is "command" working right, yet? Bart Schaefer
@ 2016-02-07 15:24  4% ` Martijn Dekker
  2016-09-25 23:31  3%   ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-02-07 15:24 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

Bart Schaefer schreef op 03-02-16 om 00:37:
[...]
> burner% setopt posixbuiltins
> burner% command -p -V true
> zsh: command not found: -V
> burner% command -V -p true  
> command: bad option: -p
> 
> I think this is pretty clearly a bug.

Agreed, these options should combine without a problem.

> Using the versions available on my Ubuntu desktop, and default $PATH, all
> of bash, ksh, and zsh with POSIX_BUILTINS, execute the builtin for both
> "command" and "command -p".

The same for dash, pdksh/mksh and yash.

> Anybody know if that's correct?

I believe so. Normally, builtins are searched for $PATH. The spec for
'command -p'[*] says the command is executed with a default $PATH that
is guaranteed to find all of the standard utilities, but not that
builtins aren't searched first as usual. According to POSIX, builtins
are supposed to be standard commands equivalent to their external
correspondents, so in theory it shouldn't make any difference.

> If it is, how does one force the use of the external command in [the
> forthcoming] POSIX?

The only way I know of is to run it with an explicit path, such as
/bin/echo hi

To find out the path of an external command without considering
builtins, there is 'which' on most systems, but it is not POSIX. I don't
know of any current system without it, though.

For 100% cross-platform compatibility guarantee, it is not too hard to
write a shell function that finds the absolute path of a command. I
wrote this once for an installer that is compatible with the original
Bourne shell as well as POSIX:

# Output the first path of each given command, or, if given -a, all possible
# paths, in the given order, according to the system $PATH. Like BSD
'which'.
# Returns successfully if at least one path was found, unsuccessfully if
not.
# This abridged function ignores paths (as in 'which /bin/ls').
which() { (
    unset opt_allpaths flag_somenotfound
    IFS=':'  # separator in $PATH
    test "$1" = '-a' && opt_allpaths='y' && shift
    for arg do
        unset flag_foundthisone
        cmd=`basename $arg`
        for dir in $PATH; do  # for native zsh, you want ${=PATH}
            if test -f "$dir/$cmd" -a -x "$dir/$cmd"; then
                flag_foundthisone='y'
                printf '%s/%s\n' "$dir" "$cmd"
                test -z "$opt_allpaths" && break
            fi
        done
        test -n "$flag_foundthisone" || flag_somenotfound=y
    done
    test -z "$flag_somenotfound"
); }

- M.

[*]
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html#tag_20_22_04


^ permalink raw reply	[relevance 4%]

* Re: Should (t)path = array-unique-special work this way
  2016-02-05 17:15  3% ` Bart Schaefer
@ 2016-02-14 10:04  0%   ` Sebastian Gniazdowski
  2016-02-14 14:34  0%     ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Sebastian Gniazdowski @ 2016-02-14 10:04 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

On 5 February 2016 at 18:15, Bart Schaefer <schaefer@brasslantern.com> wrote:
>
> Q: Why doesn't -U appear in the "declare -p" output?
> A: Good question.  It doesn't appear for non-special arrays either.  It
>    may be intentional because -U isn't a POSIX-supported option, but I
>    suspect it's just an accidental omission.

Wanted to write a snapshot feature, basically declare -p > snapshot;
setopt typesetsilent; source ./snapshot, but the omission of -U is
quite a blocker. Other interesting thing is that typeset -a a doesn't
fully redefine a, uniqueness still holds if it was present.

% typeset -Ua a
% a=( a a )
% echo ${a[@]}
a
% declare -p > snapshot
% source ./snapshot
% a=( a a )
% echo ${a[@]}
a
% echo ${(t)a}
array-unique
% unset a
% source ./snapshot
% echo ${(t)a}
array
% a=( a a )
% echo ${a[@]}
a a

Best regards,
Sebastian Gniazdowski


^ permalink raw reply	[relevance 0%]

* Re: Should (t)path = array-unique-special work this way
  2016-02-14 10:04  0%   ` Sebastian Gniazdowski
@ 2016-02-14 14:34  0%     ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-02-14 14:34 UTC (permalink / raw)
  To: Sebastian Gniazdowski; +Cc: Zsh hackers list

Sebastian Gniazdowski wrote on Sun, Feb 14, 2016 at 11:04:02 +0100:
> On 5 February 2016 at 18:15, Bart Schaefer <schaefer@brasslantern.com> wrote:
> >
> > Q: Why doesn't -U appear in the "declare -p" output?
> > A: Good question.  It doesn't appear for non-special arrays either.  It
> >    may be intentional because -U isn't a POSIX-supported option, but I
> >    suspect it's just an accidental omission.
> 
> Wanted to write a snapshot feature, basically declare -p > snapshot;
> setopt typesetsilent; source ./snapshot, but the omission of -U is
> quite a blocker. Other interesting thing is that typeset -a a doesn't
> fully redefine a, uniqueness still holds if it was present.

If the parameter already exists, 'typeset' will modify it rather than
replace it.  For example, 'typeset x=foo; readonly x; echo $x' prints
'foo' rather than an empty string.

You might need to call 'unset' before calling 'typeset'?  I'm not sure
whether that has any edgecases to beware of.


^ permalink raw reply	[relevance 0%]

* minor 'select' snag
@ 2016-02-14 23:05  4% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2016-02-14 23:05 UTC (permalink / raw)
  To: zsh-workers

I'm analysing the behaviour of 'select' in various shells and found a a
way in which it's different in zsh from bash, ksh93 and {pd,m}ksh.

If a user presses Ctrl-D (EOF) within a 'select' loop, the REPLY
variable is left unchanged on zsh. On the other shells with 'select', it
is cleared, which is the same behaviour as 'read' (including 'read' on
zsh) and seems more logical. This makes it possible to decide whether to
continue after the loop by testing for the emptiness of $REPLY without
having to initialise it before entering the loop. It would be nice if
this worked the same way on zsh.

Thanks,

- M.

(Note of possible side interest: My experimental cross-platform shell
library, "modernish" <http://github.com/modernish/modernish> has a
module providing its own 'select' implementation for POSIX shells. It
mimics native implementations as closely as possible. On bash, *ksh and
zsh, the module does nothing except a check for a particular shell bug.
End result: all POSIX shells can use 'select'. There are just some minor
differences to account for, including the above-mentioned one.)


^ permalink raw reply	[relevance 4%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  @ 2016-02-16  9:57  5% ` Peter Stephenson
  2016-02-16 12:46 11%   ` Peter Stephenson
  2016-02-16 23:38  5%   ` Martijn Dekker
  0 siblings, 2 replies; 200+ results
From: Peter Stephenson @ 2016-02-16  9:57 UTC (permalink / raw)
  To: zsh-workers

On Mon, 15 Feb 2016 06:11:13 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> The POSIX_TRAPS option for the EXIT trap does not work if both of the
> following conditions apply:

Oh, you mean the POSIXness of the trap is not sticky.  It should be
marked as to be run at the end of the programme based on the emulation
when it was started.  I don't think we've ever claimed it would be,
but it would be clearly be useful to change as the intention in
POSIX emulation is unambiguous.

I think that's probably fixable with a bit of flaggery, but we'll
probably need to compromise and agree that if someone sets an EXIT trap
once the emulation is left, which therefore picks up non-POSIX behaviour
(if that's how the shell was started), it will wipe out the trap
completely.  Otherwise we're in a weird and wonderful world of multiple
parallel EXIT traps.  Presumably that's no big issue, since even in
POSIX mode a new EXIT trap wipes out the one you've just set.

pws


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-16  9:57  5% ` Peter Stephenson
@ 2016-02-16 12:46 11%   ` Peter Stephenson
  2016-02-16 23:38  5%   ` Martijn Dekker
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2016-02-16 12:46 UTC (permalink / raw)
  To: zsh-workers

This makes the POSIX behaviour of the EXIT trap sticky based on the
setting of POSIX_TRAPS at the point where the EXIT trap was set.  It's
hard to see how this can not be what the script writer intended.  In
other words, it doesn't care about the stickiness of the emulator
surrounding it.

I've pointed out knock-on effects in the README; I suspect anyone
relying on those side effects was on a hiding to nothing anyway.

diff --git a/README b/README
index 8b8ab57..d5343db 100644
--- a/README
+++ b/README
@@ -65,6 +65,20 @@ remainder of the value discarded.  This could lead to different behaviour
 if the argument contains non-numeric characters, or if the argument has
 leading zeroes and the OCTAL_ZEROES option is set.
 
+3) For some time the shell has had a POSIX_TRAPS option which determines
+whether the EXIT trap has POSIX behaviour (the trap is only run at shell
+exit) or traditional zsh behaviour (the trap is run once and discarded
+when the enclosing fuction or shell exits, whichever happens first).
+The use of this option has now been made "sticky" on the EXIT trap ---
+in other words, the setting of the option at the point where the trap is
+set now determines whether the trap has POSIX or traditional zsh
+behaviour.  This means that changing the option after the trap was set
+no longer has any effect.
+
+Other aspects of EXIT trap handling have not changed --- there is still
+only one EXIT trap at any point in a programme, so it is not generally
+useful to combine POSIX and non-POSIX behaviour in the same script.
+
 Incompatibilities between 5.0.8 and 5.2
 ---------------------------------------
 
diff --git a/Src/signals.c b/Src/signals.c
index aa0b5aa..32452ae 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -55,6 +55,15 @@ mod_export Eprog siglists[VSIGCOUNT];
 /**/
 mod_export int nsigtrapped;
 
+/*
+ * Flag that exit trap has been set in POSIX mode.
+ * The setter's expectation is therefore that it is run
+ * on programme exit, not function exit.
+ */
+
+/**/
+static int exit_trap_posix;
+
 /* Variables used by signal queueing */
 
 /**/
@@ -755,7 +764,7 @@ killjb(Job jn, int sig)
  * at once, so just use a linked list.
  */
 struct savetrap {
-    int sig, flags, local;
+    int sig, flags, local, posix;
     void *list;
 };
 
@@ -774,6 +783,7 @@ dosavetrap(int sig, int level)
     st = (struct savetrap *)zalloc(sizeof(*st));
     st->sig = sig;
     st->local = level;
+    st->posix = (sig == SIGEXIT) ? exit_trap_posix : 0;
     if ((st->flags = sigtrapped[sig]) & ZSIG_FUNC) {
 	/*
 	 * Get the old function: this assumes we haven't added
@@ -873,6 +883,10 @@ settrap(int sig, Eprog l, int flags)
      * works just the same.
      */
     sigtrapped[sig] |= (locallevel << ZSIG_SHIFT) | flags;
+    if (sig == SIGEXIT) {
+	/* Make POSIX behaviour of EXIT trap sticky */
+	exit_trap_posix = isset(POSIXTRAPS);
+    }
     unqueue_signals();
     return 0;
 }
@@ -908,7 +922,7 @@ removetrap(int sig)
      * already one at the current locallevel we just overwrite it.
      */
     if (!dontsavetrap &&
-	(sig == SIGEXIT ? !isset(POSIXTRAPS) : isset(LOCALTRAPS)) &&
+	(sig == SIGEXIT ? !exit_trap_posix : isset(LOCALTRAPS)) &&
 	locallevel &&
 	(!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
 	dosavetrap(sig, locallevel);
@@ -935,6 +949,8 @@ removetrap(int sig)
 #endif
              sig != SIGCHLD)
         signal_default(sig);
+    if (sig == SIGEXIT)
+	exit_trap_posix = 0;
 
     /*
      * At this point we free the appropriate structs.  If we don't
@@ -978,7 +994,7 @@ starttrapscope(void)
      * so give it the next higher one. dosavetrap() is called
      * automatically where necessary.
      */
-    if (sigtrapped[SIGEXIT] && !isset(POSIXTRAPS)) {
+    if (sigtrapped[SIGEXIT] && !exit_trap_posix) {
 	locallevel++;
 	unsettrap(SIGEXIT);
 	locallevel--;
@@ -1005,7 +1021,7 @@ endtrapscope(void)
      * Don't do this inside another trap.
      */
     if (!intrap &&
-	!isset(POSIXTRAPS) && (exittr = sigtrapped[SIGEXIT])) {
+	!exit_trap_posix && (exittr = sigtrapped[SIGEXIT])) {
 	if (exittr & ZSIG_FUNC) {
 	    exitfn = removehashnode(shfunctab, "TRAPEXIT");
 	} else {
@@ -1031,7 +1047,9 @@ endtrapscope(void)
 		if (st->flags & ZSIG_FUNC)
 		    settrap(sig, NULL, ZSIG_FUNC);
 		else
-		    settrap(sig, (Eprog) st->list, 0);
+			settrap(sig, (Eprog) st->list, 0);
+		if (sig == SIGEXIT)
+		    exit_trap_posix = st->posix;
 		dontsavetrap--;
 		/*
 		 * counting of nsigtrapped should presumably be handled
@@ -1042,16 +1060,26 @@ endtrapscope(void)
 		if ((sigtrapped[sig] = st->flags) & ZSIG_FUNC)
 		    shfunctab->addnode(shfunctab, ((Shfunc)st->list)->node.nam,
 				       (Shfunc) st->list);
-	    } else if (sigtrapped[sig])
-		unsettrap(sig);
+	    } else if (sigtrapped[sig]) {
+		/*
+		 * Don't restore the old state if someone has set a
+		 * POSIX-style exit trap --- allow this to propagate.
+		 */
+		if (sig != SIGEXIT || !exit_trap_posix)
+		    unsettrap(sig);
+	    }
 
 	    zfree(st, sizeof(*st));
 	}
     }
 
     if (exittr) {
-	if (!isset(POSIXTRAPS))
-	    dotrapargs(SIGEXIT, &exittr, exitfn);
+	/*
+	 * We already made sure this wasn't set as a POSIX exit trap.
+	 * We respect the user's intention when the trap in question
+	 * was set.
+	 */
+	dotrapargs(SIGEXIT, &exittr, exitfn);
 	if (exittr & ZSIG_FUNC)
 	    shfunctab->freenode((HashNode)exitfn);
 	else
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 4b2843a..d8183a4 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -399,6 +399,26 @@
 >}
 >No, really exited
 
+   (cd ..; $ZTST_exe -fc 'unsetopt posixtraps;
+   echo start program
+   emulate sh -c '\''testfn() {
+     echo start function
+     set -o | grep posixtraps
+     trap "echo EXIT TRAP TRIGGERED" EXIT
+     echo end function
+   }'\''
+   testfn
+   echo program continuing
+   echo end of program')
+0:POSIX_TRAPS effect on EXIT trap is sticky
+>start program
+>start function
+>noposixtraps          off
+>end function
+>program continuing
+>end of program
+>EXIT TRAP TRIGGERED
+
    (set -e
     printf "a\nb\n" | while read line
     do


^ permalink raw reply	[relevance 11%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-16  9:57  5% ` Peter Stephenson
  2016-02-16 12:46 11%   ` Peter Stephenson
@ 2016-02-16 23:38  5%   ` Martijn Dekker
  2016-02-17  4:25  5%     ` Bart Schaefer
                       ` (2 more replies)
  1 sibling, 3 replies; 200+ results
From: Martijn Dekker @ 2016-02-16 23:38 UTC (permalink / raw)
  To: zsh-workers; +Cc: Peter Stephenson

Peter Stephenson schreef op 16-02-16 om 10:57:
> On Mon, 15 Feb 2016 06:11:13 +0100
> Martijn Dekker <martijn@inlv.org> wrote:
>> The POSIX_TRAPS option for the EXIT trap does not work if both of the
>> following conditions apply:
> 
> Oh, you mean the POSIXness of the trap is not sticky.  It should be
> marked as to be run at the end of the programme based on the emulation
> when it was started.  I don't think we've ever claimed it would be,
> but it would be clearly be useful to change as the intention in
> POSIX emulation is unambiguous.

That's a much better way of putting it.

> I think that's probably fixable with a bit of flaggery, but we'll
> probably need to compromise and agree that if someone sets an EXIT trap
> once the emulation is left, which therefore picks up non-POSIX behaviour
> (if that's how the shell was started), it will wipe out the trap
> completely.  Otherwise we're in a weird and wonderful world of multiple
> parallel EXIT traps.  Presumably that's no big issue, since even in
> POSIX mode a new EXIT trap wipes out the one you've just set.

However, since POSIX traps are inherently global, the expectation that
POSIX traps wipe out previous traps only applies to global traps. Could
you make an exception for function-local traps?

IMO, no one would expect a function-local trap to wipe out a global
trap, whether or not the global trap was set in POSIX mode. For
sticky-POSIX library functions to play nice with a native zsh script, it
would be necessary for native function-local traps to still work as
expected.

In other words, in my view, the following ought to work:

#! Src/zsh -f
emulate sh -c 'trap "echo POSIX exit trap triggered" EXIT'
fn() {
	trap "echo native zsh function-local exit trap triggered" EXIT
	echo entering native zsh function
}
fn

Expected output:

entering program
entering native zsh function
native zsh function-local exit trap triggered
exiting program
POSIX exit trap triggered

With your current patch, the function-local trap wipes out the global
POSIX exit trap, so the last line of expected output doesn't appear.

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-16 23:38  5%   ` Martijn Dekker
@ 2016-02-17  4:25  5%     ` Bart Schaefer
  2016-02-17  5:24  5%       ` Martijn Dekker
  2016-02-17 10:36  0%     ` Peter Stephenson
  2016-02-25 11:53 11%     ` Peter Stephenson
  2 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-02-17  4:25 UTC (permalink / raw)
  To: zsh-workers

On Feb 17, 12:38am, Martijn Dekker wrote:
} 
} With your current patch, the function-local trap wipes out the global
} POSIX exit trap, so the last line of expected output doesn't appear.

Hrm.  I think the point is that there are no function-local traps in
POSIX, so the POSIX trap obeys the POSIX rules even when another trap
is set in non-POSIX scope.

I could see an argument either way, though.  I could also see an argument
that the localtraps option should affect this (even though it's not usually
needed for global traps).


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-17  4:25  5%     ` Bart Schaefer
@ 2016-02-17  5:24  5%       ` Martijn Dekker
  2016-02-19 18:59  5%         ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-02-17  5:24 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

Bart Schaefer schreef op 17-02-16 om 05:25:
> On Feb 17, 12:38am, Martijn Dekker wrote:
> } 
> } With your current patch, the function-local trap wipes out the global
> } POSIX exit trap, so the last line of expected output doesn't appear.
> 
> Hrm.  I think the point is that there are no function-local traps in
> POSIX, so the POSIX trap obeys the POSIX rules even when another trap
> is set in non-POSIX scope.

But POSIX is irrelevant to function-local traps because they are not
defined in POSIX, so, once emulation mode is exited, there is nothing
that compels you to make them wipe out a global POSIX trap.

I think it would actually be more consistent with the intention of the
POSIX trap if it survived a function-local native zsh trap; the
intention of the POSIX trap was for it to be executed on program exit,
so having it wiped out by a temporary function-local trap doesn't seem
helpful.

> I could see an argument either way, though.  I could also see an argument
> that the localtraps option should affect this (even though it's not usually
> needed for global traps).

How do you think that option should affect this?

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-16 23:38  5%   ` Martijn Dekker
  2016-02-17  4:25  5%     ` Bart Schaefer
@ 2016-02-17 10:36  0%     ` Peter Stephenson
  2016-02-25 11:53 11%     ` Peter Stephenson
  2 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-02-17 10:36 UTC (permalink / raw)
  To: zsh-workers

On Wed, 17 Feb 2016 00:38:15 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> However, since POSIX traps are inherently global, the expectation that
> POSIX traps wipe out previous traps only applies to global traps. Could
> you make an exception for function-local traps?

Quite possibly; I'll commit what I've got and look at tweaks when I get
a moment.

pws


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-17  5:24  5%       ` Martijn Dekker
@ 2016-02-19 18:59  5%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-02-19 18:59 UTC (permalink / raw)
  To: zsh-workers

On Feb 17,  6:24am, Martijn Dekker wrote:
}
} But POSIX is irrelevant to function-local traps because they are not
} defined in POSIX, so, once emulation mode is exited, there is nothing
} that compels you to make them wipe out a global POSIX trap.

That's sort of the point -- there's nothing that compels us, hence ...

} > I could see an argument either way

... and your argument is a pretty good one.

} > I could also see an argument
} > that the localtraps option should affect this
} 
} How do you think that option should affect this?

To be pedantic, I didn't say I think that; I said I could understand how
one might argue that position.  To try to frame it -- the implication is
that a trap created under LOCAL_TRAPS should *never* alter traps in any
outer scope.  This ought to include the global scope, regardless of the
context in which the global trap was created.

I.e. given "setopt POSIX_TRAPS LOCAL_TRAPS" this argues that LOCAL_TRAPS
should "win".  With PWS's patch, POSIX_TRAPS prevails.


^ permalink raw reply	[relevance 5%]

* Re: ZSH_SCRIPT
  @ 2016-02-25  9:33  3%   ` Peter Stephenson
  2016-02-25 17:59  0%     ` ZSH_SCRIPT Greg Klanderman
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-02-25  9:33 UTC (permalink / raw)
  To: Zsh list

On Wed, 24 Feb 2016 14:31:53 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Feb 24, 12:34pm, Greg Klanderman wrote:
> }
> } Sorry I dropped the ball on this topic back in early 2011, see
> } discussion in thread 'loading user startup files for zsh scripts',
> 
> I don't think anyone else remembered that this had been discussed before.
> The choice of ZSH_SCRIPT as a parameter name was convergent evolution.
> 
> Personally I'd be fine with ZSH_SCRIPT being unset at the top level, but
> there are considerations of POSIX_ARGZERO etc. now which didn't exist at
> the time of the 2011 thread.

The variable is new --- we could have a different one to make the POSIX
$0 permanently available.

pws


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-16 23:38  5%   ` Martijn Dekker
  2016-02-17  4:25  5%     ` Bart Schaefer
  2016-02-17 10:36  0%     ` Peter Stephenson
@ 2016-02-25 11:53 11%     ` Peter Stephenson
  2016-02-25 13:52  5%       ` Martijn Dekker
  2 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-02-25 11:53 UTC (permalink / raw)
  To: zsh-workers

On Wed, 17 Feb 2016 00:38:15 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> However, since POSIX traps are inherently global, the expectation that
> POSIX traps wipe out previous traps only applies to global traps. Could
> you make an exception for function-local traps?

I think this makes nested native mode EXIT traps work while preserving
a global POSIX mode EXIT trap.

pws

diff --git a/Src/signals.c b/Src/signals.c
index 32452ae..1344395 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -920,9 +920,14 @@ removetrap(int sig)
      * Note that we save the trap here even if there isn't an existing
      * one, to aid in removing this one.  However, if there's
      * already one at the current locallevel we just overwrite it.
+     *
+     * Note we save EXIT traps based on the *current* setting of
+     * POSIXTRAPS --- so if there is POSIX EXIT trap set but
+     * we are in native mode it can be saved, replaced by a function
+     * trap, and then restored.
      */
     if (!dontsavetrap &&
-	(sig == SIGEXIT ? !exit_trap_posix : isset(LOCALTRAPS)) &&
+	(sig == SIGEXIT ? !isset(POSIXTRAPS) : isset(LOCALTRAPS)) &&
 	locallevel &&
 	(!trapped || locallevel > (sigtrapped[sig] >> ZSIG_SHIFT)))
 	dosavetrap(sig, locallevel);
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index d8183a4..f4466b5 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -419,6 +419,23 @@
 >end of program
 >EXIT TRAP TRIGGERED
 
+   (cd ..; $ZTST_exe -fc '
+     echo entering program
+     emulate sh -c '\''trap "echo POSIX exit trap triggered" EXIT'\''
+     fn() {
+        trap "echo native zsh function-local exit trap triggered" EXIT
+        echo entering native zsh function
+     }
+     fn
+     echo exiting program
+   ')
+0:POSX EXIT trap can have nested native mode EXIT trap
+>entering program
+>entering native zsh function
+>native zsh function-local exit trap triggered
+>exiting program
+>POSIX exit trap triggered
+
    (set -e
     printf "a\nb\n" | while read line
     do


^ permalink raw reply	[relevance 11%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-25 11:53 11%     ` Peter Stephenson
@ 2016-02-25 13:52  5%       ` Martijn Dekker
  2016-03-04 18:02 16%         ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-02-25 13:52 UTC (permalink / raw)
  To: zsh-workers; +Cc: Peter Stephenson

Peter Stephenson schreef op 25-02-16 om 12:53:
> I think this makes nested native mode EXIT traps work while preserving
> a global POSIX mode EXIT trap.

It's nearly there. The new test case in C03traps.ztst succeeds.

But if a function defined with sticky emulation sets a POSIX trap, and
that function is called from native zsh, then the old behaviour returns
and a subsequent function-local trap wipes out the global POSIX trap. So
this still kills my POSIX library functions that set a trap.

New test script that does not succeed yet:

#! Src/zsh -f
echo entering program
emulate sh -c 'spt() { trap "echo POSIX exit trap triggered" EXIT; }'
fn() {
   trap "echo native zsh function-local exit trap triggered" EXIT
   echo entering native zsh function
}
spt
fn
echo exiting program

Expected output is identical to that of the C03traps.ztst test case.

Many thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: ZSH_SCRIPT
  2016-02-25  9:33  3%   ` ZSH_SCRIPT Peter Stephenson
@ 2016-02-25 17:59  0%     ` Greg Klanderman
    0 siblings, 1 reply; 200+ results
From: Greg Klanderman @ 2016-02-25 17:59 UTC (permalink / raw)
  To: zsh-workers

>>>>> On February 25, 2016 Peter Stephenson <p.stephenson@samsung.com> wrote:

> The variable is new --- we could have a different one to make the POSIX
> $0 permanently available.

Hi Peter and Bart,

Are you saying this is new enough that it can still be changed?  I
would be OK leaving it, and adding another variable as I had
originally proposed, but I do think that ZSH_SCRIPT is a bit better
name for what I had originally proposed, i.e. the name of the script
or empty, and that something like ZSH_ARGZERO might be better for what
is currently called ZSH_SCRIPT.

LKM what you prefer, and if you want me to submit a patch.

thank you,
Greg


^ permalink raw reply	[relevance 0%]

* Why zsh chose to be non-compliant in pattern matching
@ 2016-02-26  1:02  3% Cuong Manh Le
  0 siblings, 0 replies; 200+ results
From: Cuong Manh Le @ 2016-02-26  1:02 UTC (permalink / raw)
  To: zsh-workers

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

POSIX documentation for pattern matching (
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13_01)
said that any quoted characters in pattern will be match literally.

AFAICT, `["!"a]` will match `!` or `a`, most of shell behave like that
except zsh (and also ksh):

case a in ["!"a]) echo 1;; esac


print nothing. While:

case b in ["!"a]) echo 1;; esac


print 1. zsh treats `["!"a]` the same as `[!a]`.

Is there any reason for this behavior?

PS: The full question can be seen here
http://unix.stackexchange.com/q/265431/38906

Thanks.

^ permalink raw reply	[relevance 3%]

* [PATCH] make 'set +o' useful and POSIX compatible
@ 2016-02-27  3:11  4% Martijn Dekker
  2016-02-27 13:47  5% ` Martijn Dekker
  2016-02-28  5:27  5% ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2016-02-27  3:11 UTC (permalink / raw)
  To: Zsh hackers list

The command 'set -o' shows the current shell options in an unspecified
format. Less well-known is the variant 'set +o', which should output the
current shell options "in a format that is suitable for reinput to the
shell as commands that achieve the same options settings".[*]

That means it should be possible to do

        save_options=$(set +o)

then change some options, then later restore the shell options with

        eval "$save_options"

On zsh (as well as all pdksh variants), 'set +o' is currently inadequate
for that purpose because it only outputs the currently active shell
options, and not the inactive ones.

The zshbuiltins(1) man page also implies that 'set +o' should print the
complete current option states.

This is my first time trying my hand at a zsh patch.

Thanks,

- M.

[*]
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25_03
    (scroll down to '+o')

diff --git a/Src/options.c b/Src/options.c
index 17c46c3..18619c8 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -847,9 +847,10 @@ printoptionnodestate(HashNode hn, int hadplus)
     int optno = on->optno;

     if (hadplus) {
-        if (defset(on, emulation) != isset(optno))
-	    printf("set -o %s%s\n", defset(on, emulation) ?
-		   "no" : "", on->node.nam);
+	printf("set %co %s%s\n",
+	       defset(on, emulation) != isset(optno) ? '-' : '+',
+	       defset(on, emulation) ? "no" : "",
+	       on->node.nam);
     } else {
 	if (defset(on, emulation))
 	    printf("no%-19s %s\n", on->node.nam, isset(optno) ? "off" : "on");


^ permalink raw reply	[relevance 4%]

* Re: [PATCH] make 'set +o' useful and POSIX compatible
  2016-02-27  3:11  4% [PATCH] make 'set +o' useful and POSIX compatible Martijn Dekker
@ 2016-02-27 13:47  5% ` Martijn Dekker
  2016-02-28  5:27  5% ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Martijn Dekker @ 2016-02-27 13:47 UTC (permalink / raw)
  To: Zsh hackers list

Martijn Dekker schreef op 27-02-16 om 04:11:
> That means it should be possible to do
> 
>         save_options=$(set +o)
> 
> then change some options, then later restore the shell options with
> 
>         eval "$save_options"

Hmm. There is still a problem with this.

Two options are turned off in subshells, so the command substitution
subshell $(set +o) will not store the output you want.

$ set +o >1
$ (set +o) >2
$ diff 1 2
116c116
< set -o monitor
---
> set +o monitor
177c177
< set -o zle
---
> set +o zle

This only seems to be relevant on interactive shells though, as
'monitor' and 'zle' are turned off in scripts.

- M.


^ permalink raw reply	[relevance 5%]

* Re: [PATCH] make 'set +o' useful and POSIX compatible
  2016-02-27  3:11  4% [PATCH] make 'set +o' useful and POSIX compatible Martijn Dekker
  2016-02-27 13:47  5% ` Martijn Dekker
@ 2016-02-28  5:27  5% ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2016-02-28  5:27 UTC (permalink / raw)
  To: Zsh hackers list

On Feb 27,  4:11am, Martijn Dekker wrote:
}
} On zsh (as well as all pdksh variants), 'set +o' is currently inadequate
} for that purpose because it only outputs the currently active shell
} options, and not the inactive ones.

This is almost certainly not coincidental.  In the early years of zsh
development, ksh was only available on closed-source UNIX platforms,
so any ksh-isms that were incorporated were either derived from reading
man pages (which led by misunderstanding to the "coproc" command and
an unusual syntax for writing base-N values in arithmetic context) or
borrowed from pdksh.

I don't see any reason not to accept this patch.


^ permalink raw reply	[relevance 5%]

* Re: ZSH_SCRIPT
  @ 2016-03-01  9:27  3%           ` Peter Stephenson
  2016-03-01 14:39  0%             ` ZSH_SCRIPT Greg Klanderman
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-03-01  9:27 UTC (permalink / raw)
  To: zsh-workers

On Mon, 29 Feb 2016 18:36:18 -0500
Greg Klanderman <gak@klanderman.net> wrote:
> >>>>> On February 25, 2016 Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
> > On Feb 25, 12:59pm, Greg Klanderman wrote:
> > }
> > } Are you saying this is new enough that it can still be changed?
> 
> > That's how I interpret what Peter said, yes.  I don't really have any
> > preference here.
> 
> OK, Peter what do you prefer?

I'm happy with ZSH_SCRIPT only being set for the script and something
else like ZSH_ARGZERO indicating the POSIX $0, if that makes sense.

pws


^ permalink raw reply	[relevance 3%]

* Re: ZSH_SCRIPT
  2016-03-01  9:27  3%           ` ZSH_SCRIPT Peter Stephenson
@ 2016-03-01 14:39  0%             ` Greg Klanderman
  0 siblings, 0 replies; 200+ results
From: Greg Klanderman @ 2016-03-01 14:39 UTC (permalink / raw)
  To: zsh-workers

>>>>> On March 1, 2016 Peter Stephenson <p.stephenson@samsung.com> wrote:

> I'm happy with ZSH_SCRIPT only being set for the script and something
> else like ZSH_ARGZERO indicating the POSIX $0, if that makes sense.

Thank you Peter & Bart.. how about this?

Should we explicitly document that ZSH_SCRIPT is empty rather than
unset when not invoked as a script?

thanks,
Greg


diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index ae859ce..a3ce880 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -933,6 +933,13 @@ tt(zsh/zutil) module.
 )
 enditem()
 )
+vindex(ZSH_ARGZERO)
+item(tt(ZSH_ARGZERO))(
+If zsh was invoked to run a script, this is the name of the script.
+Otherwise, it is the name used to invoke the current shell.  This is
+the same as the value of tt($0) when the tt(POSIX_ARGZERO) option is
+set, but is always available.
+)
 vindex(ZSH_EXECUTION_STRING)
 item(tt(ZSH_EXECUTION_STRING))(
 If the shell was started with the option tt(-c), this contains
@@ -951,17 +958,14 @@ track of versions of the shell during development between releases;
 hence most users should not use it and should instead rely on
 tt($ZSH_VERSION).
 )
-vindex(ZSH_SCRIPT)
-item(tt(ZSH_SCRIPT))(
-If zsh was invoked to run a script, this is the name of the script.
-Otherwise, it is the name used to invoke the current shell.  This is
-the same as the value of tt($0) when the tt(POSIX_ARGZERO) option is
-set, but is always available.
-)
 item(tt(zsh_scheduled_events))(
 See ifzman(the section `The zsh/sched Module' in zmanref(zshmodules))\
 ifnzman(noderef(The zsh/sched Module)).
 )
+vindex(ZSH_SCRIPT)
+item(tt(ZSH_SCRIPT))(
+If zsh was invoked to run a script, this is the name of the script.
+)
 vindex(ZSH_SUBSHELL <S>)
 item(tt(ZSH_SUBSHELL))(
 Readonly integer.  Initially zero, incremented each time the shell forks
diff --git a/Src/init.c b/Src/init.c
index 4097327..e96ad2c 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1657,6 +1657,7 @@ zsh_main(UNUSED(int argc), char **argv)
     opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
     /* sets ZLE, INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
     parseargs(argv, &runscript, &cmd);
+    zsh_script = runscript;
 
     SHTTY = -1;
     init_io(cmd);
diff --git a/Src/params.c b/Src/params.c
index 8bd8a8e..c6c6d82 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -81,7 +81,8 @@ char *argzero,		/* $0           */
      *rprompt2,		/* $RPROMPT2    */
      *sprompt,		/* $SPROMPT     */
      *wordchars,	/* $WORDCHARS   */
-     *zsh_name;		/* $ZSH_NAME    */
+     *zsh_name,		/* $ZSH_NAME    */
+     *zsh_script;	/* $ZSH_SCRIPT  */
 /**/
 mod_export
 char *ifs,		/* $IFS         */
@@ -813,7 +814,8 @@ createparamtable(void)
     setsparam("TTY", ztrdup_metafy(ttystrname));
     setsparam("VENDOR", ztrdup_metafy(VENDOR));
     setsparam("ZSH_NAME", ztrdup_metafy(zsh_name));
-    setsparam("ZSH_SCRIPT", ztrdup(posixzero));
+    setsparam("ZSH_ARGZERO", ztrdup(posixzero));
+    setsparam("ZSH_SCRIPT", ztrdup(zsh_script));
     setsparam("ZSH_VERSION", ztrdup_metafy(ZSH_VERSION));
     setsparam("ZSH_PATCHLEVEL", ztrdup_metafy(ZSH_PATCHLEVEL));
     setaparam("signals", sigptr = zalloc((SIGCOUNT+4) * sizeof(char *)));


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Sticky-sh POSIX_TRAPS are function-local
  2016-02-25 13:52  5%       ` Martijn Dekker
@ 2016-03-04 18:02 16%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-03-04 18:02 UTC (permalink / raw)
  To: zsh-workers

On Thu, 25 Feb 2016 14:52:24 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> But if a function defined with sticky emulation sets a POSIX trap, and
> that function is called from native zsh, then the old behaviour returns
> and a subsequent function-local trap wipes out the global POSIX trap. So
> this still kills my POSIX library functions that set a trap.

It looks like I've figured this out.

pws

diff --git a/Src/signals.c b/Src/signals.c
index 1344395..2eefc07 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -877,16 +877,21 @@ settrap(int sig, Eprog l, int flags)
             sig != SIGCHLD)
             install_handler(sig);
     }
+    sigtrapped[sig] |= flags;
     /*
      * Note that introducing the locallevel does not affect whether
      * sigtrapped[sig] is zero or not, i.e. a test without a mask
      * works just the same.
      */
-    sigtrapped[sig] |= (locallevel << ZSIG_SHIFT) | flags;
     if (sig == SIGEXIT) {
 	/* Make POSIX behaviour of EXIT trap sticky */
 	exit_trap_posix = isset(POSIXTRAPS);
+	/* POSIX exit traps are not local. */
+	if (!exit_trap_posix)
+	    sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
     }
+    else
+	sigtrapped[sig] |= (locallevel << ZSIG_SHIFT);
     unqueue_signals();
     return 0;
 }
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -429,14 +429,32 @@
      fn
      echo exiting program
    ')
-0:POSX EXIT trap can have nested native mode EXIT trap
+0:POSIX EXIT trap can have nested native mode EXIT trap
 >entering program
 >entering native zsh function
 >native zsh function-local exit trap triggered
 >exiting program
 >POSIX exit trap triggered
 
-   (set -e
+   (cd ..; $ZTST_exe -fc '
+     echo entering program
+     emulate sh -c '\''spt() { trap "echo POSIX exit trap triggered" EXIT; }'\''
+     fn() {
+	trap "echo native zsh function-local exit trap triggered" EXIT
+	echo entering native zsh function
+     }
+     spt
+     fn
+     echo exiting program
+   ')
+0:POSIX EXIT trap not replaced if defined within function
+>entering program
+>entering native zsh function
+>native zsh function-local exit trap triggered
+>exiting program
+>POSIX exit trap triggered
+
+    (set -e
     printf "a\nb\n" | while read line
     do
        [[ $line = a* ]] || continue


^ permalink raw reply	[relevance 16%]

* Re: [PATCH] zsh locale completion
  @ 2016-05-28 14:38  3%     ` Eric Cook
  0 siblings, 0 replies; 200+ results
From: Eric Cook @ 2016-05-28 14:38 UTC (permalink / raw)
  To: zsh-workers

On 05/10/2016 11:32 AM, Marko Myllynen wrote:
> Hi,
> 
> On 2016-05-10 01:14, Daniel Shahaf wrote:
>> Marko Myllynen wrote on Mon, May 09, 2016 at 15:55:00 +0300:
>>> +++ b/Completion/Unix/Command/_locale
>>> @@ -0,0 +1,28 @@
>>> +local curcontext="$curcontext" state line expl ret=1
>> ⋮
>>> +_arguments -A -C -S -s \
>> ⋮
>>> +  '*:name:->catkey' \
>>> +  && return=0
>>
>> Typo: s/return/ret/
> 
> Good catch - updated patch below. It seems that using return is
> required as otherwise we end up inside the if-statement even in
> cases like locale -<tab>.
> 
> ---
>  Completion/Unix/Command/_locale | 28 ++++++++++++++++++++++++++++
>  1 file changed, 28 insertions(+)
>  create mode 100644 Completion/Unix/Command/_locale
> 
> diff --git a/Completion/Unix/Command/_locale b/Completion/Unix/Command/_locale
> new file mode 100644
> index 0000000..af6e90c
> --- /dev/null
> +++ b/Completion/Unix/Command/_locale
> @@ -0,0 +1,28 @@
> +#compdef locale
> +
> +local curcontext="$curcontext" state line expl ret=1
> +local exargs="-? --help --usage -V --version"
> +
> +_arguments -A -C -S -s \
> +  '(- *)'{-\?,--help}'[display help information]' \
> +  '(- *)--usage[display a short usage message]' \
> +  '(- *)'{-V,--version}'[print program version]' \
> +  - set1 \
> +  "(-a --all-locales $exargs)"{-a,--all-locales}'[list all available locales]' \
> +  "(-v --verbose $exargs)"{-v,--verbose}'[display additional information]' \
> +  - set2 \
> +  "(-m --charmaps $exargs)"{-m,--charmaps}'[list all available charmaps]' \
> +  - set3 \
> +  "(-c --category-name $exargs)"{-c,--category-name}'[print also locale category]' \
> +  "(-k --keyword-name $exargs)"{-k,--keyword-name}'[print also keyword of each value]' \
> +  '*:name:->catkey' \
> +  && return 0
> +
> +if [[ $state == catkey ]]; then
> +  typeset -a cats keys
> +  cats=( ${${${(f)"$(locale)"}%=*}%(LANG|LANGUAGE|LC_ALL)} )
> +  keys=( ${${(f)"$(locale -k $cats 2>/dev/null)"}%=*} )
> +  _wanted values expl name compadd "$@" -a - cats keys && ret=0
> +fi
> +
> +return ret
> 
> Thanks,
> 

Could you also test the version locale? possibly with _pick_variant and if the locale(1)
isn't glibc's locale; only present the options mandated by posix?[1]
also for bonus points, openbsd's locale only has the options -a and -m

[1] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/locale.html


^ permalink raw reply	[relevance 3%]

* [PATCH v2] zsh localedef completion
@ 2016-05-30 17:36  2% Marko Myllynen
  2016-05-31 16:44  0% ` Baptiste Daroussin
  0 siblings, 1 reply; 200+ results
From: Marko Myllynen @ 2016-05-30 17:36 UTC (permalink / raw)
  To: zsh workers

Hi,

Below is zsh completions for the localedef(1) command, I've tested this
on RHEL 7 against the glibc provided localedef command. Otherwise it
works nicely but I'm a bit wondering two things here:

$ localedef -Afoo -<TAB>

offers --alias-file (unexpected to me) alongside the others but

$ localedef --alias-file=foo -<TAB>

does not offer -A (IMHO expected).

$ localedef -c<TAB>

offers also V/? although I hoped them to get excluded in that case.

Anyway, I don't think neither of these are critical issues so I think
this would be already worth merging as-is but if you happen to know the
needed tweaks to address those issues all the better.

As Eric Cook pointed out, there's life outside of GNU and this patch now
supports Darwin/Dragonfly/GNU/POSIX. Since I don't have access to a
Solaris system I didn't implement that yet, would be probably pretty
straightforward but would be good to actually test it.

As with locale(1) completion, I chose to duplicate few lines so that if
something needs to be changed for non-GNU which I haven't tested, it's
probably easier to tweak the already separate if-block then.

References:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/localedef.html
http://man7.org/linux/man-pages/man1/localedef.1.html
https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/localedef.1.html
https://docs.oracle.com/cd/E26502_01/html/E29030/localedef-1.html
https://www.dragonflybsd.org/cgi/web-man?command=localedef&section=1

---
 Completion/Unix/Command/_localedef | 98 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 98 insertions(+)
 create mode 100644 Completion/Unix/Command/_localedef

diff --git a/Completion/Unix/Command/_localedef b/Completion/Unix/Command/_localedef
new file mode 100644
index 0000000..4f37c56
--- /dev/null
+++ b/Completion/Unix/Command/_localedef
@@ -0,0 +1,98 @@
+#compdef localedef
+
+# TODO: Solaris opts
+
+local curcontext="$curcontext" state line expl ret=1
+typeset -A opt_args
+
+if _pick_variant gnu='(GNU|EGLIBC)' unix --version; then
+
+  local exargs="-? --help --usage -V --version"
+  _arguments -A "-*" -C -S -s \
+    '(- *)'{-\?,--help}'[display help information]' \
+    '(- *)--usage[display a short usage message]' \
+    '(- *)'{-V,--version}'[print program version]' \
+    "(-A --alias-file= $exargs)"{-A+,--alias-file=}'[specify locale alias file]:alias file:_files' \
+    "($exargs)--prefix=[specify path prefix]:prefix:_files" \
+    "(-c --force $exargs)"{-c,--force}'[force write despite of warnings]' \
+    "(-v --verbose $exargs)"{-v,--verbose}'[display additional information]' \
+    "($exargs)--quiet[suppress messages and warnings]" \
+    - set1 \
+    "(-f --charmap= $exargs)"{-f+,--charmap=}'[specify locale charmap file]:charmap:->charmap' \
+    "(-i --inputfile= $exargs)"{-i+,--inputfile=}'[specify locale definition file]:locale file:_files' \
+    "(-u --repertoire-map= $exargs)"{-u+,--repertoire-map=}'[specify repertoire map file]:repertoire map file:_files' \
+    '1:path:_files' \
+    - set2 \
+    "(--list-archive $exargs)--list-archive[list locales in archive]" \
+    - set3 \
+    "(--delete-from-archive $exargs)--delete-from-archive[delete locale from archive]" \
+    '*:locale:->locale' \
+    - set4 \
+    "(--add-to-archive $exargs)--add-to-archive[add locale to archive]" \
+    "(--replace $exargs)--replace[replace locale in archive]" \
+    "(--no-archive $exargs)--no-archive[use subdir not archive]" \
+    '*:compiled path:_files -/' \
+    && return 0
+
+  case "$state" in
+    charmap)
+      if [[ $words[-1] == */* ]]; then
+        _wanted values expl charmap _files && ret=0
+      else
+        typeset -a charmaps
+        charmaps=( ${(f)"$(locale -m)"} )
+        _wanted values expl charmap compadd "$@" \
+          -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \
+          -a - charmaps && ret=0
+      fi
+    ;;
+    locale)
+      typeset -a locales
+      local pref=${opt_args[--prefix]}
+      local p=${pref:+--prefix}
+      locales=( ${(f)"$(localedef --list-archive $p $pref)"} )
+      _wanted values expl locale compadd "$@" -a - locales && ret=0
+    ;;
+  esac
+
+  return ret
+
+else
+
+  typeset -a u_opt dragonfly_opts
+  [[ $OSTYPE != darwin* ]] && u_opt=(
+      "(-u)"-u+'[specify target codeset]:codeset:_files'
+    )
+  [[ $OSTYPE == dragonfly* ]] && dragonfly_opts=(
+      "(-D)"-D'[create BSD-style output]' \
+      "(-U)"-U'[ignore undefined character symbols]' \
+      "(-v)"-v'[verbose deguggin output]' \
+      "(-w)"-w+'[specify width file]:width file:_files' \
+    )
+
+  _arguments -A "-*" -C \
+    "(-c)"-c'[force write despite of warnings]' \
+    "(-f)"-f+'[specify locale charmap file]:charmap:->charmap' \
+    "(-i)"-i+'[specify locale definition file]:locale file:_files' \
+    $u_opt \
+    $dragonfly_opts \
+    '1:path:_files' \
+    && return 0
+
+  case "$state" in
+    charmap)
+      if [[ $words[-1] == */* ]]; then
+        _wanted values expl charmap _files && ret=0
+      else
+        typeset -a charmaps
+        charmaps=( ${(f)"$(locale -m)"} )
+        _wanted values expl charmap compadd "$@" \
+          -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \
+          -a - charmaps && ret=0
+      fi
+    ;;
+  esac
+
+  return ret
+
+fi

Thanks,

-- 
Marko Myllynen


^ permalink raw reply	[relevance 2%]

* [PATCH v2] zsh locale completion
@ 2016-05-30 17:36  4% Marko Myllynen
  0 siblings, 0 replies; 200+ results
From: Marko Myllynen @ 2016-05-30 17:36 UTC (permalink / raw)
  To: zsh workers

Hi,

Below is zsh completions for the locale(1) command, I've tested this on
RHEL 7 against the glibc provided locale command. Otherwise it works
nicely but I'm a bit wondering why after "locale -a<TAB>" I'm getting
all other options offered, I would have thought getting -v offered only.

On Eric Cook's suggestion supports now GNU/OpenBSD/POSIX. I duplicated
the category/keyword handling under GNU/POSIX sections as I don't have
any non-GNU systems to test on and if any changes are needed for non-GNU
it's probably easier to tweak the already separate if-block then.

References:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/locale.html
http://man7.org/linux/man-pages/man1/locale.1.html
https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/locale.1.html
https://docs.oracle.com/cd/E26502_01/html/E29030/locale-1.html
https://www.freebsd.org/cgi/man.cgi?locale
http://netbsd.gw.com/cgi-bin/man-cgi?locale+1+NetBSD-current
http://man.openbsd.org/locale.1
https://www.dragonflybsd.org/cgi/web-man?command=locale&section=1

---
 Completion/Unix/Command/_locale | 68 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)
 create mode 100644 Completion/Unix/Command/_locale

diff --git a/Completion/Unix/Command/_locale b/Completion/Unix/Command/_locale
new file mode 100644
index 0000000..3b3aa22
--- /dev/null
+++ b/Completion/Unix/Command/_locale
@@ -0,0 +1,68 @@
+#compdef locale
+
+# TODO: FreeBSD: locale -k list [prefix]
+
+local curcontext="$curcontext" state line expl ret=1
+
+if _pick_variant gnu='(GNU|EGLIBC)' unix --version; then
+
+  local exargs="-? --help --usage -V --version"
+
+  _arguments -A "-*" -C -S -s \
+    '(- *)'{-\?,--help}'[display help information]' \
+    '(- *)--usage[display a short usage message]' \
+    '(- *)'{-V,--version}'[print program version]' \
+    - set1 \
+    "(-a --all-locales $exargs)"{-a,--all-locales}'[list all available locales]' \
+    "(-v --verbose $exargs)"{-v,--verbose}'[display additional information]' \
+    - set2 \
+    "(-m --charmaps $exargs)"{-m,--charmaps}'[list all available charmaps]' \
+    - set3 \
+    "(-c --category-name $exargs)"{-c,--category-name}'[print also locale category]' \
+    "(-k --keyword-name $exargs)"{-k,--keyword-name}'[print also keyword of each value]' \
+    '*:name:->catkey' \
+    && return 0
+
+  if [[ $state == catkey ]]; then
+    typeset -a cats keys
+    cats=( ${${${(f)"$(locale)"}%=*}%(LANG|LANGUAGE|LC_ALL)} )
+    keys=( ${${(f)"$(locale -k $cats 2>/dev/null)"}%=*} )
+    _wanted values expl name compadd "$@" -a - cats keys && ret=0
+  fi
+
+  return ret
+
+elif [[ $OSTYPE == openbsd* ]]; then
+
+  _arguments \
+    - set1 \
+    "(-a)"-a'[list all available locales]' \
+    - set2 \
+    "(-m)"-m'[list all available charmaps]' \
+    && return 0
+
+  return ret
+
+else
+
+  _arguments -A "-*" -C \
+    - set1 \
+    "(-a)"-a'[list all available locales]' \
+    - set2 \
+    "(-m)"-m'[list all available charmaps]' \
+    - set3 \
+    "(-c)"-c'[print also locale category]' \
+    "(-k)"-k'[print also keyword of each value]' \
+    '*:name:->catkey' \
+    && return 0
+
+  if [[ $state == catkey ]]; then
+    typeset -a cats keys
+    cats=( ${${${(f)"$(locale)"}%=*}%(LANG|LANGUAGE|LC_ALL)} )
+    keys=( ${${(f)"$(locale -k $cats 2>/dev/null)"}%=*} )
+    _wanted values expl name compadd "$@" -a - cats keys && ret=0
+  fi
+
+  return ret
+
+fi

Thanks,

-- 
Marko Myllynen


^ permalink raw reply	[relevance 4%]

* Re: [PATCH v2] zsh localedef completion
  2016-05-30 17:36  2% [PATCH v2] zsh localedef completion Marko Myllynen
@ 2016-05-31 16:44  0% ` Baptiste Daroussin
  0 siblings, 0 replies; 200+ results
From: Baptiste Daroussin @ 2016-05-31 16:44 UTC (permalink / raw)
  To: Marko Myllynen; +Cc: zsh workers

FreeBSD expect the same options as Dragonfly given we share the same code here

Can you please add freebsd ?

2016-05-30 19:36 GMT+02:00 Marko Myllynen <myllynen@redhat.com>:
> Hi,
>
> Below is zsh completions for the localedef(1) command, I've tested this
> on RHEL 7 against the glibc provided localedef command. Otherwise it
> works nicely but I'm a bit wondering two things here:
>
> $ localedef -Afoo -<TAB>
>
> offers --alias-file (unexpected to me) alongside the others but
>
> $ localedef --alias-file=foo -<TAB>
>
> does not offer -A (IMHO expected).
>
> $ localedef -c<TAB>
>
> offers also V/? although I hoped them to get excluded in that case.
>
> Anyway, I don't think neither of these are critical issues so I think
> this would be already worth merging as-is but if you happen to know the
> needed tweaks to address those issues all the better.
>
> As Eric Cook pointed out, there's life outside of GNU and this patch now
> supports Darwin/Dragonfly/GNU/POSIX. Since I don't have access to a
> Solaris system I didn't implement that yet, would be probably pretty
> straightforward but would be good to actually test it.
>
> As with locale(1) completion, I chose to duplicate few lines so that if
> something needs to be changed for non-GNU which I haven't tested, it's
> probably easier to tweak the already separate if-block then.
>
> References:
>
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/localedef.html
> http://man7.org/linux/man-pages/man1/localedef.1.html
> https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/localedef.1.html
> https://docs.oracle.com/cd/E26502_01/html/E29030/localedef-1.html
> https://www.dragonflybsd.org/cgi/web-man?command=localedef&section=1
>
> ---
>  Completion/Unix/Command/_localedef | 98 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 98 insertions(+)
>  create mode 100644 Completion/Unix/Command/_localedef
>
> diff --git a/Completion/Unix/Command/_localedef b/Completion/Unix/Command/_localedef
> new file mode 100644
> index 0000000..4f37c56
> --- /dev/null
> +++ b/Completion/Unix/Command/_localedef
> @@ -0,0 +1,98 @@
> +#compdef localedef
> +
> +# TODO: Solaris opts
> +
> +local curcontext="$curcontext" state line expl ret=1
> +typeset -A opt_args
> +
> +if _pick_variant gnu='(GNU|EGLIBC)' unix --version; then
> +
> +  local exargs="-? --help --usage -V --version"
> +  _arguments -A "-*" -C -S -s \
> +    '(- *)'{-\?,--help}'[display help information]' \
> +    '(- *)--usage[display a short usage message]' \
> +    '(- *)'{-V,--version}'[print program version]' \
> +    "(-A --alias-file= $exargs)"{-A+,--alias-file=}'[specify locale alias file]:alias file:_files' \
> +    "($exargs)--prefix=[specify path prefix]:prefix:_files" \
> +    "(-c --force $exargs)"{-c,--force}'[force write despite of warnings]' \
> +    "(-v --verbose $exargs)"{-v,--verbose}'[display additional information]' \
> +    "($exargs)--quiet[suppress messages and warnings]" \
> +    - set1 \
> +    "(-f --charmap= $exargs)"{-f+,--charmap=}'[specify locale charmap file]:charmap:->charmap' \
> +    "(-i --inputfile= $exargs)"{-i+,--inputfile=}'[specify locale definition file]:locale file:_files' \
> +    "(-u --repertoire-map= $exargs)"{-u+,--repertoire-map=}'[specify repertoire map file]:repertoire map file:_files' \
> +    '1:path:_files' \
> +    - set2 \
> +    "(--list-archive $exargs)--list-archive[list locales in archive]" \
> +    - set3 \
> +    "(--delete-from-archive $exargs)--delete-from-archive[delete locale from archive]" \
> +    '*:locale:->locale' \
> +    - set4 \
> +    "(--add-to-archive $exargs)--add-to-archive[add locale to archive]" \
> +    "(--replace $exargs)--replace[replace locale in archive]" \
> +    "(--no-archive $exargs)--no-archive[use subdir not archive]" \
> +    '*:compiled path:_files -/' \
> +    && return 0
> +
> +  case "$state" in
> +    charmap)
> +      if [[ $words[-1] == */* ]]; then
> +        _wanted values expl charmap _files && ret=0
> +      else
> +        typeset -a charmaps
> +        charmaps=( ${(f)"$(locale -m)"} )
> +        _wanted values expl charmap compadd "$@" \
> +          -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \
> +          -a - charmaps && ret=0
> +      fi
> +    ;;
> +    locale)
> +      typeset -a locales
> +      local pref=${opt_args[--prefix]}
> +      local p=${pref:+--prefix}
> +      locales=( ${(f)"$(localedef --list-archive $p $pref)"} )
> +      _wanted values expl locale compadd "$@" -a - locales && ret=0
> +    ;;
> +  esac
> +
> +  return ret
> +
> +else
> +
> +  typeset -a u_opt dragonfly_opts
> +  [[ $OSTYPE != darwin* ]] && u_opt=(
> +      "(-u)"-u+'[specify target codeset]:codeset:_files'
> +    )
> +  [[ $OSTYPE == dragonfly* ]] && dragonfly_opts=(
> +      "(-D)"-D'[create BSD-style output]' \
> +      "(-U)"-U'[ignore undefined character symbols]' \
> +      "(-v)"-v'[verbose deguggin output]' \
> +      "(-w)"-w+'[specify width file]:width file:_files' \
> +    )
> +
> +  _arguments -A "-*" -C \
> +    "(-c)"-c'[force write despite of warnings]' \
> +    "(-f)"-f+'[specify locale charmap file]:charmap:->charmap' \
> +    "(-i)"-i+'[specify locale definition file]:locale file:_files' \
> +    $u_opt \
> +    $dragonfly_opts \
> +    '1:path:_files' \
> +    && return 0
> +
> +  case "$state" in
> +    charmap)
> +      if [[ $words[-1] == */* ]]; then
> +        _wanted values expl charmap _files && ret=0
> +      else
> +        typeset -a charmaps
> +        charmaps=( ${(f)"$(locale -m)"} )
> +        _wanted values expl charmap compadd "$@" \
> +          -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \
> +          -a - charmaps && ret=0
> +      fi
> +    ;;
> +  esac
> +
> +  return ret
> +
> +fi
>
> Thanks,
>
> --
> Marko Myllynen


^ permalink raw reply	[relevance 0%]

* [PATCH 2/3] Fix the ':A' word modifier on paths with '..' components.
  @ 2016-06-10 17:36  6% ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-06-10 17:36 UTC (permalink / raw)
  To: zsh-workers

The fix is to stop calling chabspath() at the top of chrealpath().

Also remove an incorrect comment (passing a non-absolute path would have been
fine because the chabspath() call would have made it absolute).
---

This is an incompatible change; see the test and docs changes for details.

Daniel

 Doc/Zsh/expn.yo   |  6 ++++--
 README            |  9 +++++++++
 Src/hist.c        | 22 ++++++++++------------
 Test/D02glob.ztst |  6 ++++++
 4 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index c6e7b6f..50b8479 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -225,9 +225,11 @@ intervening directories do not exist.
 )
 item(tt(A))(
 As `tt(a)', but also resolve use of symbolic links where possible.
-Note that resolution of `tt(..)' occurs em(before) resolution of symbolic
-links.  This call is equivalent to tt(a) unless your system has the
+This call is equivalent to tt(a) unless your system has the
 tt(realpath) system call (modern systems do).
+
+em(Note): In zsh 5.2 and earlier, resolution of `tt(..)' occurred em(before)
+resolution of symbolic links.
 )
 item(tt(c))(
 Resolve a command name into an absolute path by searching the command
diff --git a/README b/README
index d5343db..84bb6bc 100644
--- a/README
+++ b/README
@@ -79,6 +79,15 @@ Other aspects of EXIT trap handling have not changed --- there is still
 only one EXIT trap at any point in a programme, so it is not generally
 useful to combine POSIX and non-POSIX behaviour in the same script.
 
+4) On systems that have the realpath(3) library function, the ':A' word
+modifier now resolves symbolic links before '..' path components.  This
+could lead to different, but usually more desirable, results: the
+tranformed value will now always identify the same directory entry as the
+the pre-transformation value.
+
+The behaviour of 5.2 and older can be achieved by chaining modifiers:
+'<expression>:a:A'.
+
 Incompatibilities between 5.0.8 and 5.2
 ---------------------------------------
 
diff --git a/Src/hist.c b/Src/hist.c
index 5fc40bd..07f56b0 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -1837,8 +1837,8 @@ chabspath(char **junkptr)
 int
 chrealpath(char **junkptr)
 {
-    char *str;
 #ifdef HAVE_REALPATH
+    char *str;
 # ifdef REALPATH_ACCEPTS_NULL
     char *lastpos, *nonreal, *real;
 # else
@@ -1850,19 +1850,17 @@ chrealpath(char **junkptr)
     if (!**junkptr)
 	return 1;
 
-    /* Notice that this means ..'s are applied before symlinks are resolved! */
-    if (!chabspath(junkptr))
-	return 0;
-
 #ifndef HAVE_REALPATH
-    return 1;
+    return chabspath(junkptr);
 #else
-    /*
-     * Notice that this means you cannot pass relative paths into this
-     * function!
-     */
-    if (**junkptr != '/')
+
+    if (**junkptr != '/') {
+	*junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr);
+    }
+    if (**junkptr != '/') {
+	/* Can happen after 'rmdir $PWD; zsh' */
 	return 0;
+    }
 
     unmetafy(*junkptr, NULL);
 
@@ -1909,9 +1907,9 @@ chrealpath(char **junkptr)
     } else {
 	*junkptr = metafy(nonreal, lastpos - nonreal + 1, META_HEAPDUP);
     }
-#endif
 
     return 1;
+#endif
 }
 
 /**/
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 8618378..dc1a655 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -670,3 +670,9 @@
  () { set -- ${PWD}/$^@; print -l -- $@:A } glob.tmp/nonexistent/foo/bar/baz
 0:modifier ':A' doesn't require existence
 *>*/glob.tmp/nonexistent/foo/bar/baz
+
+ ln -s dir3/subdir glob.tmp/link
+ () { print ${1:A} } glob.tmp/link/../../hello
+ rm glob.tmp/link
+0:modifier ':A' resolves symlinks before '..' components
+*>*glob.tmp/hello


^ permalink raw reply	[relevance 6%]

* Re: [PATCH] add-zle-hook-widget
  @ 2016-06-21  1:41  2%         ` Daniel Shahaf
  2016-07-01 20:11  2%           ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2016-06-21  1:41 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Thu, Jun 16, 2016 at 22:20:55 -0700:
> On Jun 15, 11:24pm, Daniel Shahaf wrote:
> }
> } Bart Schaefer wrote on Tue, Jun 14, 2016 at 11:10:54 -0700:
> } > Mostly I made that decision because add-zsh-hook explicitly declares
> } > that its values are arrays and displays their values with "typeset"
> } > if the -L option is passed.
> } 
> } Then how about saying that registrations may only be added/removed
> } through calls to add-z-h-w [-d], without documenting how its storage
> } is implemented?
> 
>   > it seemed odd to expose this
>   > detail in one case and hide it in the other.
> 

I see your later patch adopted this suggestion.  I of course concede the
asymmetry but I think leaving ourselves room to change the implementation
is preferable.

> } > The whole ordering thing depends on the cooperation of whoever declared
> } > widgets A and B in the first place.  Declarer(A) could as easily make
> } > capricious changes to his index as not provide it at all.
> } 
> } Let's not assume the author of (A) is malicious.
> 
> I'm not assuming malice, just inconsistency, or a well-meaning decision
> that (A) should come after (B) even though declarer(B) thinks exactly
> the opposite.

Good point: perhaps (A) does have a reason to want to be last.
(I should have thought about that sooner: z-sy-h asks to be last...)

> } The question is whether the API enables the problem to happen, and
> } the answer is it does: permitting registrations that specify no index
> } means plugins _will_ register without specifying an index.
> 
> I'm not convinced that's a problem; no index means "I don't care when
> this runs, and it shouldn't matter."  If it turns out otherwise for
> some other widget, then that other widget merely has to delete the
> un-indexed widget and re-declare it with an index.
> 

Having (B) unhook/rehook (A)'s hook sounds like a recipe for
hard-to-diagnose bugs.

I think making indices mandatory would resolve this: there could be
a convention that "use index=999 to run last" and then if (A) sets 999
and (B) consciously override (A), (B) can register at 1000.  There are
enough integers so this design wouldn't give either (A) or (B) preference.
[But see below for another idea]

> I think this is better than the situation with add-zsh-hook where
> somebody has to be sure ALL the add-* calls are made in exactly the
> right sequence ... or else has to know the implementation and muck
> with it directly.
> 

Agreed, although there _is_ something to be said for the "or else"
alternative: it is a thin/KISS solution, "here's the explicit order
hooks will be called in, have a field day".

> } I strongly suspect that the releasing the current interface would be
> } a mistake: with the current interface, the majority of registrants will
> } specify no index, and then regitrants that _do_ wish to take advantage
> } of the ordering facility won't be able to.
> 
> The choice of index numbers can't be made in a vaccuum, and maybe it
> can't even be made by anyone other than the user editing his .zshrc.
> In the previous example, declarer(B) has to be aware of widget (A)
> and know what index it uses in order to choose another index that
> comes after it; how does that differ from being aware of (A) and
> therefore asserting new indices for both?  If (B) is NOT aware of (A)
> then what difference could it make what index declarer(A) chose?
> 

Writing (B) to correctly register itself in the correct relative order 
both to plugins it knows about and to one it doesn't is an interesting
question.

Perhaps we should ditch indexing and use topological sorting [tsort(1)
is in POSIX] instead: then we can let registrants specify "before:" and
"after:" clauses, so B could do "add-zsh-hook zle-line-init B_hook
before:A_hook".  That would handle dependencies to known other plugins;
to handle dependencies to unknown other plugins — say, having all
$BUFFER-modifying hooks to run before all non-$BUFFER-modifying hooks —
we could add a virtual "BUFFER-modifying-done" sequence point (which
won't correspond to a hook) to let plugins register themselves with
"before:BUFFER-modifying-done".  If no before: nor after: clauses are
specified, all registered hooks would be run in unspecified order (or
perhaps in registration order).

I'm not sure whether this is simpler or more complicated than indices.

> } So, what I think _will_ work is either of three options: drop indices
> } altogether (restoring parity with add-zsh-hook); declare "no index" as
> } equivalent to index == 42 (for some well-known value 42); make indices
> } mandatory.  I don't have a preference among these three options.
> 
> These all degenerate to the same problem in the right circumstances;
> e.g. what happens if (A) and (B) both have index 42 and then (C) wants
> to run *between* them?
> 

Good point.  Using tsort would enable (C) to achieve this:
add-z-h-w C_${hook} before:B_${hook} after:A_${hook}

One issue with topological sort is cycles (add-z-h-w x A_hook before:B;
add-z-h-w x B_hook before:A;).  On both linux and freebsd, tsort warns
about cycles to stderr but prints _some_ ordering to stdout anyway,
which is good for add-zsh-hook-widget's use-case.

> What you have convinced me is that in the absence of an explicit index
> there's some value in retaining the order in which the add-* calls
> were made, which the code as last pushed doesn't.
> 

Okay :)

> } > I'm strongly of the opinion that this is the WRONG way to manipulate a
> } > non-special editor widget, and that the right way needs more help than
> } > this kind of facility can provide, and that I'm not going to attempt
> } > to explain all the details in this thread.
> } 
> } You do not have to agree with me, but it is common for whoever states
> } a disagreeing opinion to give at least a brief glimpse of the technical
> } considerations underlying their different assessment.
> 
> The gist is that these special widgets by definition do nothing unless
> user-defined, so there's no distinction between replacing the widget
> action and augmenting it.  Non-special widgets each have an intended
> semantic, so there *is* that distinction, and *usually* it's desired
> to augment rather than replace.  For special widgets it's reasonable
> to simply enumerate a list of actions; for non-special that's not good
> enough.
> 

Thank you for detailing.  I am not convinced, but as I don't have
a strong opinion on the issue I'll defer to your judgement.

> } % autoload -U +X add-zle-hook-widget 
> 
> Oh.  It doesn't work with +X, it only works with -X.  That's because the
> file is designed to be "source"-able rather than "autoload +X"-able.
> I'm not sure there's a way to make it safe for all three of autoload +X,
> source, and kshautoload.

Wouldn't the following work?

$ cat f
f() { echo I have been called with "$@" }
if [[ "$zsh_eval_context" != *\ file && ! -o kshautoload ]]; then
    f "$@"
fi
$ zsh -f
% fpath+=$PWD
% autoload f
% f arg
I have been called with arg

$ zsh -f
% fpath+=$PWD
% setopt kshautoload 
% autoload -k f 
% f arg 
I have been called with arg

$ zsh -f
% fpath+=$PWD
% source f
% f arg
I have been called with arg

$ zsh -f
% fpath+=$PWD
% autoload +X f 
% f arg
I have been called with arg

$ zsh -f
% fpath+=$PWD
% setopt kshautoload
% autoload +X -k f
% f arg
I have been called with arg

Cheers,

Daniel


^ permalink raw reply	[relevance 2%]

* [PATCH v2 2/3] Fix the ':A' word modifier on paths with '..' components.
  @ 2016-06-21  1:53  5%   ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-06-21  1:53 UTC (permalink / raw)
  To: zsh-workers

The fix is to stop calling chabspath() at the top of chrealpath().

Preserve the old behaviour when CHASE_DOTS is set.

Also remove an incorrect comment (passing a non-absolute path would have been
fine because the chabspath() call would have made it absolute).
---
 Doc/Zsh/expn.yo    | 12 +++++++++---
 Doc/Zsh/options.yo |  7 ++++++-
 README             |  9 +++++++++
 Src/hist.c         | 27 +++++++++++++++------------
 Test/D02glob.ztst  | 11 ++++++++++-
 5 files changed, 49 insertions(+), 17 deletions(-)

diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index c6e7b6f..82d2c9f 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -225,9 +225,15 @@ intervening directories do not exist.
 )
 item(tt(A))(
 As `tt(a)', but also resolve use of symbolic links where possible.
-Note that resolution of `tt(..)' occurs em(before) resolution of symbolic
-links.  This call is equivalent to tt(a) unless your system has the
-tt(realpath) system call (modern systems do).
+
+By default, symbolic links are resolved before `tt(..)' components.  However,
+if the tt(CHASE_DOTS) option is set, `tt(..)' components are resolved before
+symbolic links.  Furthermore, on systems that lack the tt(realpath+LPAR()RPAR())
+system call (modern systems have it), symbolic links are never resolved and
+this modifier is equivalent to the `tt(a)' modifier.
+
+em(Note): In zsh 5.2 and earlier, resolution of `tt(..)' occurred em(before)
+resolution of symbolic links regardless of the tt(CHASE_DOTS) option.
 )
 item(tt(c))(
 Resolve a command name into an absolute path by searching the command
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 0eaaeca..da93912 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -106,6 +106,11 @@ Without this option set, `tt(cd /foo/bar/..)' changes to tt(/foo); with it
 set, it changes to tt(/alt).  The same applies if the current directory
 is tt(/foo/bar) and `tt(cd ..)' is used.  Note that all other symbolic
 links in the path will also be resolved.
+
+This option also affects the interpretation of the `tt(:A)' history modifier,
+see
+ifzman(the section `Modifiers' in zmanref(zshexpn))\
+ifnzman(noderef(Modifiers)).
 )
 pindex(CHASE_LINKS)
 pindex(NO_CHASE_LINKS)
@@ -569,7 +574,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)
diff --git a/README b/README
index d5343db..6857253 100644
--- a/README
+++ b/README
@@ -79,6 +79,15 @@ Other aspects of EXIT trap handling have not changed --- there is still
 only one EXIT trap at any point in a programme, so it is not generally
 useful to combine POSIX and non-POSIX behaviour in the same script.
 
+4) On systems that have the realpath(3) library function, the ':A' word
+modifier now resolves symbolic links before '..' path components.  This
+could lead to different, but usually more desirable, results: the
+tranformed value will now always identify the same directory entry as the
+the pre-transformation value.
+
+The behaviour of 5.2 and older can be achieved by chaining modifiers,
+as in '<expression>:a:A', or by setting the CHASE_DOTS option.
+
 Incompatibilities between 5.0.8 and 5.2
 ---------------------------------------
 
diff --git a/Src/hist.c b/Src/hist.c
index 5fc40bd..30a1bef 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -1837,8 +1837,8 @@ chabspath(char **junkptr)
 int
 chrealpath(char **junkptr)
 {
-    char *str;
 #ifdef HAVE_REALPATH
+    char *str;
 # ifdef REALPATH_ACCEPTS_NULL
     char *lastpos, *nonreal, *real;
 # else
@@ -1850,19 +1850,22 @@ chrealpath(char **junkptr)
     if (!**junkptr)
 	return 1;
 
-    /* Notice that this means ..'s are applied before symlinks are resolved! */
-    if (!chabspath(junkptr))
-	return 0;
-
 #ifndef HAVE_REALPATH
-    return 1;
+    return chabspath(junkptr);
 #else
-    /*
-     * Notice that this means you cannot pass relative paths into this
-     * function!
-     */
-    if (**junkptr != '/')
+
+    /* With CHASE_DOTS, resolve '..' components before symlinks.  (This was always
+     * done first in 5.2 and earlier.) */
+    if (isset(CHASEDOTS))
+      chabspath(junkptr);
+
+    if (**junkptr != '/') {
+	*junkptr = zhtricat(metafy(zgetcwd(), -1, META_HEAPDUP), "/", *junkptr);
+    }
+    if (**junkptr != '/') {
+	/* Can happen after 'rmdir $PWD; zsh' */
 	return 0;
+    }
 
     unmetafy(*junkptr, NULL);
 
@@ -1909,9 +1912,9 @@ chrealpath(char **junkptr)
     } else {
 	*junkptr = metafy(nonreal, lastpos - nonreal + 1, META_HEAPDUP);
     }
-#endif
 
     return 1;
+#endif
 }
 
 /**/
diff --git a/Test/D02glob.ztst b/Test/D02glob.ztst
index 7befbc2..bec9826 100644
--- a/Test/D02glob.ztst
+++ b/Test/D02glob.ztst
@@ -673,8 +673,17 @@
 
  ln -s dir3/subdir glob.tmp/link
  () {
+   setopt localoptions chasedots
    print ${1:A} | grep glob.tmp
  } glob.tmp/link/../../hello
  rm glob.tmp/link
-0:modifier ':A' resolves '..' components before symlinks
+0:modifier ':A' resolves '..' components before symlinks with CHASE_DOTS
 # There should be no output
+
+ ln -s dir3/subdir glob.tmp/link
+ () {
+   print ${1:A} | grep glob.tmp
+ } glob.tmp/link/../../hello
+ rm glob.tmp/link
+0:modifier ':A' resolves symlinks before '..' components with NO_CHASE_DOTS
+*>*glob.tmp/hello


^ permalink raw reply	[relevance 5%]

* Re: Regression: broken completion on modification time
  @ 2016-06-21 14:31 17%               ` Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2016-06-21 14:31 UTC (permalink / raw)
  To: zsh-workers

Daniel Shahaf wrote:
> Change it how?  I don't see how max-verbose and extra-verbose can be
> combined, since the former is an int and the latter a bool.

Ah, ok. I didn't check out the details of max-verbose.

> Another display option would be to use a dummy "string without a match"
> as Bart said (compadd -E1) for something like
>
>     → sense
>     (for the "exactly" sense, skip/omit this field)

I've gone with "sense [default exactly]" as the explanation heading.
We've used square brackets to indicate defaults elsewhere.
The patch now also covers find.

Oliver

diff --git a/Completion/Unix/Command/_find b/Completion/Unix/Command/_find
index e736f32..3854d6c 100644
--- a/Completion/Unix/Command/_find
+++ b/Completion/Unix/Command/_find
@@ -1,7 +1,7 @@
 #compdef find gfind
 
-local curcontext="$curcontext" state_descr variant
-local -a state line args alts
+local curcontext="$curcontext" state_descr variant default
+local -a state line args alts disp smatch
 
 _pick_variant -r variant gnu=GNU $OSTYPE -version
 
@@ -101,7 +101,7 @@ case $variant in
       '-D[print diagnostics]:debug option:(help tree search stat rates opt exec)'
       '-O+[enable query optimisation]:level:(1 2 3)'
       '*-daystart'
-      '-regextype:regexp syntax:(emacs posix-awk posix-basic posix-egrep posix-extended)'
+      '-regextype:regexp syntax:(help findutils-default awk egrep ed emacs gnu-awk grep posix-awk posix-basic posix-egrep posix-extended posix-minimal-basic sed)'
       '*-warn'
       '*-nowarn'
       '*-xautofs'
@@ -147,13 +147,21 @@ _arguments -C $args \
   '*-user:user:_users' \
   '*-xdev' \
   '*-a' '*-o' \
-  '*:directory:_files -/'
+  '(-D -E -H -L -O -P -f -s -x --help --version)*:directory:_files -/'
 
 if [[ $state = times ]]; then
   if ! compset -P '[+-]' || [[ -prefix '[0-9]' ]]; then
-    disp=( 'before' 'exactly' 'since' )
     compstate[list]+=' packed'
-    alts=( "senses:sense:compadd -V times -S '' -d disp - + '' -" )
+    if zstyle -t ":completion:${curcontext}:senses" verbose; then
+      zstyle -s ":completion:${curcontext}:senses" list-separator sep || sep=--
+      default=" [default exactly]"
+      disp=( "- $sep before" "+ $sep since" )
+      smatch=( - + )
+    else
+      disp=( before exactly since )
+      smatch=( - '' + )
+    fi
+    alts=( "senses:sense${default}:compadd -V times -S '' -d disp -a smatch" )
   fi
   alts+=( "times:${state_descr}:_dates -f d" )
   _alternative $alts
diff --git a/Completion/Zsh/Type/_globquals b/Completion/Zsh/Type/_globquals
index ed9c008..6eef168 100644
--- a/Completion/Zsh/Type/_globquals
+++ b/Completion/Zsh/Type/_globquals
@@ -1,7 +1,7 @@
 #autoload
 
-local state=qual expl char delim timespec
-local -a alts tdisp sdisp
+local state=qual expl char delim timespec default
+local -a alts tdisp sdisp tmatch smatch
 local -A specmap
 
 while [[ -n $PREFIX ]]; do
@@ -118,11 +118,27 @@ while [[ -n $PREFIX ]]; do
       timespec=$PREFIX[1]
       if ! compset -P '[Mwhmsd]' && [[ -z $PREFIX ]]; then
 	tdisp=( seconds minutes hours days weeks Months )
-        alts+=( "time-specifiers:time specifier:compadd -E 0 -d tdisp -S '' - s m h d w M" )
+	tmatch=( s m h d w M )
+	if zstyle -t ":completion:${curcontext}:time-specifiers" verbose; then
+	  zstyle -s ":completion:${curcontext}:time-specifiers" list-separator sep || sep=--
+          print -v tdisp -f "%s ${sep//(#m)[%\\]/$MATCH$MATCH} %s\0" ${tmatch:^^tdisp}
+	  tdisp=( ${(0)tdisp} )
+	fi
+	alts+=( "time-specifiers:time specifier:compadd -E 0 -d tdisp -S '' -a tmatch" )
       fi
       if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then
 	sdisp=( before exactly since )
-        alts+=("senses:sense:compadd -E 0 -d sdisp -S '' - + '' -")
+	smatch=( - '' + )
+	if zstyle -t ":completion:${curcontext}:senses" verbose; then
+	  zstyle -s ":completion:${curcontext}:senses" list-separator sep || sep=--
+	  default=" [default exactly]"
+	  sdisp=( "- $sep before" "+ $sep since" )
+	  smatch=( - + )
+	else
+	  sdisp=( before exactly since )
+	  smatch=( - '' + )
+	fi
+        alts+=( "senses:sense${default}:compadd -E 0 -d sdisp -S '' -a smatch" )
       fi
       specmap=( M months w weeks h hours m minutes s seconds '(|+|-|d)' days)
       alts+=('digits:digit ('${${specmap[(K)${timespec:-d}]}:-invalid time specifier}'):_dates -f ${${timespec/[-+]/d}:-d} -S ""' )


^ permalink raw reply	[relevance 17%]

* Re: [PATCH] add-zle-hook-widget
  2016-06-21  1:41  2%         ` Daniel Shahaf
@ 2016-07-01 20:11  2%           ` Bart Schaefer
  2016-07-05  4:57  0%             ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-07-01 20:11 UTC (permalink / raw)
  To: zsh-workers

Delayed response.

On Jun 21,  1:41am, Daniel Shahaf wrote:
} Subject: Re: [PATCH] add-zle-hook-widget
}
} Bart Schaefer wrote on Thu, Jun 16, 2016 at 22:20:55 -0700:
} > I think this is better than the situation with add-zsh-hook where
} > somebody has to be sure ALL the add-* calls are made in exactly the
} > right sequence ... or else has to know the implementation and muck
} > with it directly.
} 
} Agreed, although there _is_ something to be said for the "or else"
} alternative: it is a thin/KISS solution, "here's the explicit order
} hooks will be called in, have a field day".

You can't have it both ways -- either the implementation must be
documented, which you objected to, or it has to be possible to do
what's needed without knowing.

} Perhaps we should ditch indexing and use topological sorting [tsort(1)
} is in POSIX] instead: then we can let registrants specify "before:" and
} "after:" clauses

I don't think we want to get into the business of storing a partial
orderting and attempting to resolve it to a total one.  For one thing,
more information arrives every time add-zsh-hook is called.  Redo the
whole tsort each time?

} so B could do "add-zsh-hook zle-line-init B_hook before:A_hook"

How does that differ from:

} Having (B) unhook/rehook (A)'s hook sounds like a recipe for
} hard-to-diagnose bugs.

??  It's just the internals heuristically doing the unhook/re-hook at
B's behest, instead of B doing it explicitly.

Still, there might be something.  Just thinking aloud:

Firstly, I chose the syntax "index:name" to allow multiple items to be
added at once, but add-zsh-hook doesn't work that way so there's no
longer any reason for add-zle-hook-widget to work that way.  So let's
make the syntax be
	add-zle-hook-widget HOOK WIDGETNAME [INDEX]
instead of embedding the index in the widgetname.

(This might be tricky/confusing given that the widget list would still
need to be stored with each index attached.)

Secondly, the index could be symbolic as you suggest; perhaps first,
last, "before:otherwidget" and "after:otherwidget".  The difference
from a topological sort would be that before/after apply immediately,
so if there is no "otherwidget" present yet, they mean nothing.  You
still have to call add-zle-hook-widget in some kind of sequence, but
you don't have to know what index was assigned to otherwidget.  Also,
"otherwidget" should be a pattern.

Thirdly, allow multiple symbolic indices, to cover "before:X after:Y".
Try them until one fails, ignoring any that are meaningless.  If all
succeed, add the hook, else report error?

One other thought -- it probably doesn't work to have a single sequence
point for e.g. whether buffer modification happens.

} I'm not sure whether this is simpler or more complicated than indices.

Well, it sounds a lot more complicated to me, but it depends on whether
you mean complicated for the user to figure out beforehand what index to
use, or complicated for the shell to manage and the user to understand
afterward why a particular order of execution was chosen.

As tsort(1) itself says:
> Note that for a given partial ordering, generally there is no unique
> total ordering.

That means the widgets might start running in different order after a
new hook is added, for no reason the user is able to plainly see.  I like
the notion that a known total ordering can be imposed without having to
express increasingly detailed partial orders for each new addition.


^ permalink raw reply	[relevance 2%]

* [PATCH] improve iostat completion
@ 2016-07-04 21:12  3% Eric Cook
  2016-07-12  1:51  3% ` [PATCH v2] " Eric Cook
  0 siblings, 1 reply; 200+ results
From: Eric Cook @ 2016-07-04 21:12 UTC (permalink / raw)
  To: zsh-workers

for other OSs

---
 Completion/Linux/Command/_sysstat |  37 ++++-------
 Completion/Unix/Command/_iostat   | 132 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 143 insertions(+), 26 deletions(-)
 create mode 100644 Completion/Unix/Command/_iostat

diff --git a/Completion/Linux/Command/_sysstat b/Completion/Linux/Command/_sysstat
index 2a7128c..d41e5ef 100644
--- a/Completion/Linux/Command/_sysstat
+++ b/Completion/Linux/Command/_sysstat
@@ -1,4 +1,4 @@
-#compdef -P mpstat (|cifs)iostat isag sadf sar pidstat
+#compdef -P mpstat cifsiostat isag sadf sar pidstat
 # -V can appear with other options, so (- *) isn't needed.
 #TODO:
 # sysstat-nfsiostat - there seems to be two nfsiostat(1)s. one from oracle and one by redhat.
@@ -10,24 +10,8 @@ _mpstat() {
     '-P[specify processor number]:processor: _values -s "," processor ON ALL {1..$(_call_program processors getconf _NPROCESSORS_ONLN)}' \
     '-u[report CPU utilization]' \
     '-V[print version number]' \
-    '1:interval' \
-    '2:count'
-}
-
-_iostat() {
-  _arguments : \
-    '-c[display CPU utilization report]' \
-    '-d[display device utilization report]' \
-    '-T[only display global statistics for group_name]' \
-    '-g[display statistics for a group of devices]:group name' \
-    '-h[human readable device utilization report]' \
-    '-j[display persistent device name]' \
-    '(-m)-k[display statistics in kB/s]' \
-    '(-k)-m[display statistics in MB/s]' \
-    '-N[display registered device mapper names]' \
-    '::device:_files -W /dev -g "*(-%)"' \
-    ': :_guard "[0-9]#" "interval"' \
-    ':count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _cifsiostat() {
@@ -37,8 +21,8 @@ _cifsiostat() {
     '(-k)-m[display statistics in MB/s]' \
     '-t[print timestamp for each report]' \
     '-V[print version number]' \
-    '1:interval' \
-    '2:count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _isag() {
@@ -68,8 +52,8 @@ _sadf() {
       '(-t -T)-U[display in seconds since epoch (UTC)]' \
       '-V[print version number]' \
       '(-j -d -p)-x[output file in XML]' \
-      '1:interval' \
-      '2:count' \
+      '1: : _guard "^-*" interval' \
+      '2: : _guard "^-*" count' \
       '3:data file:_files' && ret=0
   else
     _arguments : '*::sar: _sar' && ret=0
@@ -107,8 +91,8 @@ _sar() {
     '-W[report swapping statistics]' \
     '-w[report task creation and system switching activity]' \
     '-y[report TTY device activity]' \
-    '1:interval' \
-    '2:count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _pidstat() {
@@ -128,7 +112,8 @@ _pidstat() {
     '-V[print version number]' \
     '-v[display values from kernel table]' \
     '-w[report task switching activity]' \
-    ':interval' ':count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _sysstat() {
diff --git a/Completion/Unix/Command/_iostat b/Completion/Unix/Command/_iostat
new file mode 100644
index 0000000..7dc33a1
--- /dev/null
+++ b/Completion/Unix/Command/_iostat
@@ -0,0 +1,132 @@
+#compdef iostat
+
+local -a args
+
+case $OSTYPE:l in
+  *bsd*)
+    args+=(
+      '-c[repeat the display N times]:count'
+      '-C[display CPU statistics]'
+      '-d[display only device statistics]'
+      '-I[display total statistics for a given period, rather than average]'
+      '-M[extract values of the name list from specified file]:core:_files'
+      '-N[extract the name list from the specified file]:system:_files'
+      '-T[display TTY statistics]'
+      '-w[specify the duration of pauses between each display]:duration'
+    )
+    ;|
+  freebsd*)
+    args+=(
+      '-h[top mode]'
+      '-K[display block count in kilobytes, not block size]'
+      '-o[display old-style iostat device statistics]'
+      '-t[specify which type of device to display]: :->devicetype'
+      '-x[show extended disk statistics]'
+      '-z[omit lines for devices with no activity]'
+      '-?[display a usage statement and exit]'
+      '*:drives:( ${${(M)${(f)"$(geom disk list)"}\:#Geom name\:*}#*\: } )'
+    )
+    ;;
+  openbsd*)
+    args+=(
+      '-D[display alternate disk statistics]'
+      '*:drives:( ${${(s.,.)"$(sysctl -n hw.disknames)"}%\:*} )'
+    )
+    ;;
+  netbsd*)
+    args+=(
+      '-D[display alternate disk statistics]'
+      '-x[show extended disk statistics]'
+      '*:drives:( $(sysctl -n hw.disknames) )'
+    )
+    ;;
+  aix*)
+    args=(
+      '(-b -q -Q -f -F)-a[displays the adapter throughput report]'
+      '(-b)-A[displays the legacy asynchronous IO utilization report, and turns off the display of TTY utilization report]'
+      '-b[displays the block I/O device utilization statistics]'
+      '(-b)-d[turns off the display of TTY utilization report or CPU utilization report]'
+      '(-b -f -F)-D[displays the extended tape/drive utilization report]'
+      '(-a -b -D)-f[displays the file system utilization report]'
+      '(-a -b -D)-F[displays the file system utilization report, and turns off other utilization reports]'
+      '(-b)-l[displays the output in long listing mode]'
+      '(-b -t)-m[displays the path utilization report]'
+      '(-b)-p[displays the tape utilization report]'
+      '(-b)-P[displays the POSIX asynchronous IO utilization report]'
+      '(-b)-q[specifies AIO queues and their request counts]'
+      '(-b)-Q[displays a list of all the mounted file systems and the associated queue numbers with their request counts]'
+      '(-b)-R[specifies that the reset of min* and max* values should happen at each interval]'
+      '(-b)-s[specifies the system throughput report]'
+      '(-b)-S[displays the processor statistics that are multiplied by a value of 10]:power'
+      '(-b -m)-t[turns off the display of disk utilization report]'
+      '-T[displays the time stamp]'
+      '(-b)-V[displays valid nonzero statistics]'
+      '(-b)-z[resets the disk input/output statistics]'
+      '(-b)-@[reports I/O activities of a workload partition]:workload:(ALL Global)'
+      '*:drives:_files' # not sure how to enumerate drives on aix
+    )
+    ;;
+  solaris*)
+    args=(
+      '-c[report percentage of time the system spent in user/system mode, dtrace probes and idling]'
+      '-C[report extended disk statistics aggregated by controller id, when used with -x]'
+      '-d[report the number of kilobytes tranferred per second, tranfers per second and average service time]'
+      '-D[report reads/writes per second and percentage disk utilization]'
+      '-e[display device error summary statistics]'
+      '-E[display all device error statistics]'
+      '-i[display Device ID instead of the Serial No, when used with -E]'
+      '-I[report counts in each interval]'
+      '-l[limit the number of disks included in the report]:number of disks'
+      '-m[report file system mount points]'
+      '-M[display data throughtput in MB/sec instead of KB/sec]'
+      '-n[display names in descriptive format]'
+      '-p[report per-partition statistics]'
+      '-P[report per-partition statistics only]'
+      '-r[display data in comma-separated format]'
+      '-s[suppress message related to state changes]'
+      '-t[report the number of characters read and written to terminals per second]'
+      '-T[display a timestamp]:format:(( "u\:internal representation of time" "d\:standard date format" ))'
+      '-X[report statistics for lun.controller, for disks under scsi_vhci(7D) control]'
+      '-x[report extended disk statistics]'
+      '-Y[report statistics for lun.targetport and lun.targetport.controller, for disks under scsi_vhci(7D) control]'
+      '-z[ignore lines where data values are all zeros]'
+      '::device:( ${${${(f)"$(iostat -rx 1 1)"}[3,-1]}%%,*} )'
+    )
+    ;;
+  darwin*)
+    args=(
+      '-C[display CPU statistics]'
+      '-c[number of times to display statistics]'
+      '-d[display only device statistics]'
+      '-l[total statstics for a given time period]'
+      '-K[display block count in kilobytes]'
+      '-n[limit the number of disks included in the report]:number of disks'
+      '-o[display old-style iostat device statistics]'
+      '-T[display TTY statistics]'
+      '-U[display system load averages]'
+      '-w[specify the duration of pauses between each display]:duration'
+      '*::device:_files -W /dev -g "disk*"'
+    )
+    ;;
+  *linux*)
+    args=(
+      '-c[display CPU utilization report]'
+      '-d[display device utilization report]'
+      '-T[only display global statistics for group_name]'
+      '-g[display statistics for a group of devices]:group name'
+      '-h[human readable device utilization report]'
+      '-j[display persistent device name]'
+      '(-m)-k[display statistics in kB/s]'
+      '(-k)-m[display statistics in MB/s]'
+      '-N[display registered device mapper names]'
+      '*::device:_files -W /dev -g "*(-%)"'
+    )
+    ;;
+esac
+
+if (( $#args )); then
+  _arguments -s -w -A '-*' : $args
+  return
+fi
+
+_normal
-- 
2.6.6


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] add-zle-hook-widget
  2016-07-01 20:11  2%           ` Bart Schaefer
@ 2016-07-05  4:57  0%             ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-07-05  4:57 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Fri, Jul 01, 2016 at 13:11:58 -0700:
> On Jun 21,  1:41am, Daniel Shahaf wrote:
> } Subject: Re: [PATCH] add-zle-hook-widget
> }
> } Bart Schaefer wrote on Thu, Jun 16, 2016 at 22:20:55 -0700:
> } > I think this is better than the situation with add-zsh-hook where
> } > somebody has to be sure ALL the add-* calls are made in exactly the
> } > right sequence ... or else has to know the implementation and muck
> } > with it directly.
> } 
> } Agreed, although there _is_ something to be said for the "or else"
> } alternative: it is a thin/KISS solution, "here's the explicit order
> } hooks will be called in, have a field day".
> 
> You can't have it both ways -- either the implementation must be
> documented, which you objected to, or it has to be possible to do
> what's needed without knowing.

I haven't changed my opinion; I was simply trying to say that each of
these options has its merits.

> } Perhaps we should ditch indexing and use topological sorting [tsort(1)
> } is in POSIX] instead: then we can let registrants specify "before:" and
> } "after:" clauses
> 
> I don't think we want to get into the business of storing a partial
> orderting and attempting to resolve it to a total one.  For one thing,
> more information arrives every time add-zsh-hook is called.  Redo the
> whole tsort each time?

Considering that vcs_info works, and is presumably more expensive than
a tsort, we could probably do the tsort every precmd() and nobody would
complain (*cough* cygwin *cough*).

Or we could use a just-in-time approach: have add-zle-hook-widget just
stash $argv[2,-1] somewhere and invalidate the cache, and have azhw:$1()
tsort the somewhere, cache the resulting sorted order, and thereafter
use the cached answer.  (But that may be a premature optimisation...)

> } so B could do "add-zsh-hook zle-line-init B_hook before:A_hook"
> 
> How does that differ from:
> 
> } Having (B) unhook/rehook (A)'s hook sounds like a recipe for
> } hard-to-diagnose bugs.
> 

The difference is whether the order of A_hook relative to hooks *other
than* B_hook may be affected.

If B changes the index A_hook is registered at, that order may be
affected.  If B adds a "after:B_hook" constraint to A_hook, that order
shouldn't be affected [unless the additional constraint creates
a circular dependency].

> ??  It's just the internals heuristically doing the unhook/re-hook at
> B's behest, instead of B doing it explicitly.

See previous paragraphs.

> Still, there might be something.  Just thinking aloud:
> 
> Firstly, I chose the syntax "index:name" to allow multiple items to be
> added at once, but add-zsh-hook doesn't work that way so there's no
> longer any reason for add-zle-hook-widget to work that way.  So let's
> make the syntax be
> 	add-zle-hook-widget HOOK WIDGETNAME [INDEX]
> instead of embedding the index in the widgetname.
> 

+1

> (This might be tricky/confusing given that the widget list would still
> need to be stored with each index attached.)

I'm not sure what's tricky/confusing here.?

> Secondly, the index could be symbolic as you suggest; perhaps first,
> last, "before:otherwidget" and "after:otherwidget".  The difference
> from a topological sort would be that before/after apply immediately,
> so if there is no "otherwidget" present yet, they mean nothing.  You
> still have to call add-zle-hook-widget in some kind of sequence, but
> you don't have to know what index was assigned to otherwidget.  Also,
> "otherwidget" should be a pattern.
> 
> Thirdly, allow multiple symbolic indices, to cover "before:X after:Y".
> Try them until one fails, ignoring any that are meaningless.  If all
> succeed, add the hook, else report error?
> 

This sounds exactly like topological sort except that the before:/after:
constraints may only refer to already-registered widgets, and
consequently, the responsibility for declaring interdependencies between
two plugins lies entirely with the plugin sourced latter of the two.

In other words: a plugin cannot declare what order its hook should be
run in relative to plugins that have not yet been sourced.  Perhaps
virtual sequence points (see next paragraphs) can serve instead,
though.

> One other thought -- it probably doesn't work to have a single sequence
> point for e.g. whether buffer modification happens.
> 

I was thinking that would be a convention, not enforced by code.  For
example, zsh-syntax-highlighting wants to run once BUFFER is settled
down in its final form, but doesn't care which hooks are installed that
modify BUFFER.  What arguments should it pass to add-zle-hook-widget then?

This may be comparable to the 'first' / 'last' ordering constraints you
described.

> } I'm not sure whether this is simpler or more complicated than indices.
> 
> Well, it sounds a lot more complicated to me, but it depends on whether
> you mean complicated for the user to figure out beforehand what index to
> use, or complicated for the shell to manage and the user to understand
> afterward why a particular order of execution was chosen.
> 

I meant "is tsort the right way to model and solve this problem".

> As tsort(1) itself says:
> > Note that for a given partial ordering, generally there is no unique
> > total ordering.
> 
> That means the widgets might start running in different order after a
> new hook is added, for no reason the user is able to plainly see.  I like
> the notion that a known total ordering can be imposed without having to
> express increasingly detailed partial orders for each new addition.

Fair point.

Note there are alternatives to specifying detailed partial orders: for
example, one could hook a single function that invokes a few other ones:
.
    order-sensitive() {
       local w
       for w in foo bar baz; do zle -- $w -Nw -- "$@"; done
    }
    add-zle-hook-widget line-init order-sensitive
    add-zle-hook-widget line-init qux             # qux can be ordered either before or after the foo,bar,baz group

Cheers,

Daniel


^ permalink raw reply	[relevance 0%]

* [PATCH v2] improve iostat completion
  2016-07-04 21:12  3% [PATCH] improve iostat completion Eric Cook
@ 2016-07-12  1:51  3% ` Eric Cook
  0 siblings, 0 replies; 200+ results
From: Eric Cook @ 2016-07-12  1:51 UTC (permalink / raw)
  To: zsh-workers

Removed useless use of compdef -P
---
 Completion/Linux/Command/_sysstat |  37 ++++-------
 Completion/Unix/Command/_iostat   | 132 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 143 insertions(+), 26 deletions(-)
 create mode 100644 Completion/Unix/Command/_iostat

diff --git a/Completion/Linux/Command/_sysstat b/Completion/Linux/Command/_sysstat
index 2a7128c..d41e5ef 100644
--- a/Completion/Linux/Command/_sysstat
+++ b/Completion/Linux/Command/_sysstat
@@ -1,4 +1,4 @@
-#compdef -P mpstat (|cifs)iostat isag sadf sar pidstat
+#compdef mpstat cifsiostat isag sadf sar pidstat
 # -V can appear with other options, so (- *) isn't needed.
 #TODO:
 # sysstat-nfsiostat - there seems to be two nfsiostat(1)s. one from oracle and one by redhat.
@@ -10,24 +10,8 @@ _mpstat() {
     '-P[specify processor number]:processor: _values -s "," processor ON ALL {1..$(_call_program processors getconf _NPROCESSORS_ONLN)}' \
     '-u[report CPU utilization]' \
     '-V[print version number]' \
-    '1:interval' \
-    '2:count'
-}
-
-_iostat() {
-  _arguments : \
-    '-c[display CPU utilization report]' \
-    '-d[display device utilization report]' \
-    '-T[only display global statistics for group_name]' \
-    '-g[display statistics for a group of devices]:group name' \
-    '-h[human readable device utilization report]' \
-    '-j[display persistent device name]' \
-    '(-m)-k[display statistics in kB/s]' \
-    '(-k)-m[display statistics in MB/s]' \
-    '-N[display registered device mapper names]' \
-    '::device:_files -W /dev -g "*(-%)"' \
-    ': :_guard "[0-9]#" "interval"' \
-    ':count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _cifsiostat() {
@@ -37,8 +21,8 @@ _cifsiostat() {
     '(-k)-m[display statistics in MB/s]' \
     '-t[print timestamp for each report]' \
     '-V[print version number]' \
-    '1:interval' \
-    '2:count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _isag() {
@@ -68,8 +52,8 @@ _sadf() {
       '(-t -T)-U[display in seconds since epoch (UTC)]' \
       '-V[print version number]' \
       '(-j -d -p)-x[output file in XML]' \
-      '1:interval' \
-      '2:count' \
+      '1: : _guard "^-*" interval' \
+      '2: : _guard "^-*" count' \
       '3:data file:_files' && ret=0
   else
     _arguments : '*::sar: _sar' && ret=0
@@ -107,8 +91,8 @@ _sar() {
     '-W[report swapping statistics]' \
     '-w[report task creation and system switching activity]' \
     '-y[report TTY device activity]' \
-    '1:interval' \
-    '2:count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _pidstat() {
@@ -128,7 +112,8 @@ _pidstat() {
     '-V[print version number]' \
     '-v[display values from kernel table]' \
     '-w[report task switching activity]' \
-    ':interval' ':count'
+    '1: : _guard "^-*" interval' \
+    '2: : _guard "^-*" count'
 }
 
 _sysstat() {
diff --git a/Completion/Unix/Command/_iostat b/Completion/Unix/Command/_iostat
new file mode 100644
index 0000000..7dc33a1
--- /dev/null
+++ b/Completion/Unix/Command/_iostat
@@ -0,0 +1,132 @@
+#compdef iostat
+
+local -a args
+
+case $OSTYPE:l in
+  *bsd*)
+    args+=(
+      '-c[repeat the display N times]:count'
+      '-C[display CPU statistics]'
+      '-d[display only device statistics]'
+      '-I[display total statistics for a given period, rather than average]'
+      '-M[extract values of the name list from specified file]:core:_files'
+      '-N[extract the name list from the specified file]:system:_files'
+      '-T[display TTY statistics]'
+      '-w[specify the duration of pauses between each display]:duration'
+    )
+    ;|
+  freebsd*)
+    args+=(
+      '-h[top mode]'
+      '-K[display block count in kilobytes, not block size]'
+      '-o[display old-style iostat device statistics]'
+      '-t[specify which type of device to display]: :->devicetype'
+      '-x[show extended disk statistics]'
+      '-z[omit lines for devices with no activity]'
+      '-?[display a usage statement and exit]'
+      '*:drives:( ${${(M)${(f)"$(geom disk list)"}\:#Geom name\:*}#*\: } )'
+    )
+    ;;
+  openbsd*)
+    args+=(
+      '-D[display alternate disk statistics]'
+      '*:drives:( ${${(s.,.)"$(sysctl -n hw.disknames)"}%\:*} )'
+    )
+    ;;
+  netbsd*)
+    args+=(
+      '-D[display alternate disk statistics]'
+      '-x[show extended disk statistics]'
+      '*:drives:( $(sysctl -n hw.disknames) )'
+    )
+    ;;
+  aix*)
+    args=(
+      '(-b -q -Q -f -F)-a[displays the adapter throughput report]'
+      '(-b)-A[displays the legacy asynchronous IO utilization report, and turns off the display of TTY utilization report]'
+      '-b[displays the block I/O device utilization statistics]'
+      '(-b)-d[turns off the display of TTY utilization report or CPU utilization report]'
+      '(-b -f -F)-D[displays the extended tape/drive utilization report]'
+      '(-a -b -D)-f[displays the file system utilization report]'
+      '(-a -b -D)-F[displays the file system utilization report, and turns off other utilization reports]'
+      '(-b)-l[displays the output in long listing mode]'
+      '(-b -t)-m[displays the path utilization report]'
+      '(-b)-p[displays the tape utilization report]'
+      '(-b)-P[displays the POSIX asynchronous IO utilization report]'
+      '(-b)-q[specifies AIO queues and their request counts]'
+      '(-b)-Q[displays a list of all the mounted file systems and the associated queue numbers with their request counts]'
+      '(-b)-R[specifies that the reset of min* and max* values should happen at each interval]'
+      '(-b)-s[specifies the system throughput report]'
+      '(-b)-S[displays the processor statistics that are multiplied by a value of 10]:power'
+      '(-b -m)-t[turns off the display of disk utilization report]'
+      '-T[displays the time stamp]'
+      '(-b)-V[displays valid nonzero statistics]'
+      '(-b)-z[resets the disk input/output statistics]'
+      '(-b)-@[reports I/O activities of a workload partition]:workload:(ALL Global)'
+      '*:drives:_files' # not sure how to enumerate drives on aix
+    )
+    ;;
+  solaris*)
+    args=(
+      '-c[report percentage of time the system spent in user/system mode, dtrace probes and idling]'
+      '-C[report extended disk statistics aggregated by controller id, when used with -x]'
+      '-d[report the number of kilobytes tranferred per second, tranfers per second and average service time]'
+      '-D[report reads/writes per second and percentage disk utilization]'
+      '-e[display device error summary statistics]'
+      '-E[display all device error statistics]'
+      '-i[display Device ID instead of the Serial No, when used with -E]'
+      '-I[report counts in each interval]'
+      '-l[limit the number of disks included in the report]:number of disks'
+      '-m[report file system mount points]'
+      '-M[display data throughtput in MB/sec instead of KB/sec]'
+      '-n[display names in descriptive format]'
+      '-p[report per-partition statistics]'
+      '-P[report per-partition statistics only]'
+      '-r[display data in comma-separated format]'
+      '-s[suppress message related to state changes]'
+      '-t[report the number of characters read and written to terminals per second]'
+      '-T[display a timestamp]:format:(( "u\:internal representation of time" "d\:standard date format" ))'
+      '-X[report statistics for lun.controller, for disks under scsi_vhci(7D) control]'
+      '-x[report extended disk statistics]'
+      '-Y[report statistics for lun.targetport and lun.targetport.controller, for disks under scsi_vhci(7D) control]'
+      '-z[ignore lines where data values are all zeros]'
+      '::device:( ${${${(f)"$(iostat -rx 1 1)"}[3,-1]}%%,*} )'
+    )
+    ;;
+  darwin*)
+    args=(
+      '-C[display CPU statistics]'
+      '-c[number of times to display statistics]'
+      '-d[display only device statistics]'
+      '-l[total statstics for a given time period]'
+      '-K[display block count in kilobytes]'
+      '-n[limit the number of disks included in the report]:number of disks'
+      '-o[display old-style iostat device statistics]'
+      '-T[display TTY statistics]'
+      '-U[display system load averages]'
+      '-w[specify the duration of pauses between each display]:duration'
+      '*::device:_files -W /dev -g "disk*"'
+    )
+    ;;
+  *linux*)
+    args=(
+      '-c[display CPU utilization report]'
+      '-d[display device utilization report]'
+      '-T[only display global statistics for group_name]'
+      '-g[display statistics for a group of devices]:group name'
+      '-h[human readable device utilization report]'
+      '-j[display persistent device name]'
+      '(-m)-k[display statistics in kB/s]'
+      '(-k)-m[display statistics in MB/s]'
+      '-N[display registered device mapper names]'
+      '*::device:_files -W /dev -g "*(-%)"'
+    )
+    ;;
+esac
+
+if (( $#args )); then
+  _arguments -s -w -A '-*' : $args
+  return
+fi
+
+_normal
-- 
2.6.6


^ permalink raw reply	[relevance 3%]

* PATCH: update BSD completions
@ 2016-07-17 10:01  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2016-07-17 10:01 UTC (permalink / raw)
  To: Zsh workers

This updates various completion functions to reflect updates to FreeBSD
commands. Mostly just new options.

Oliver

diff --git a/Completion/BSD/Command/_bsdconfig b/Completion/BSD/Command/_bsdconfig
index 8c7597e..f882555 100644
--- a/Completion/BSD/Command/_bsdconfig
+++ b/Completion/BSD/Command/_bsdconfig
@@ -2,6 +2,7 @@
 
 local -a shortcuts
 shortcuts=(
+  api
   'console:utilities to customize the behavior of the system console'
   'defaultrouter:default router/gateway'
   'diskmgmt:manage disk partitions and/or labels using sade(8)'
@@ -12,6 +13,7 @@ shortcuts=(
   'groupedit:edit/view groups'
   'groupmgmt:utilities to add/change/view/delete group accounts'
   'hostname:set hostname/domainname'
+  includes
   'kern_securelevel:set kern.securelevel variable'
   'mouse:utilities for configuring, exploring, and enabling console mouse support'
   'mouse_disable:disable mouse support'
@@ -43,13 +45,19 @@ shortcuts=(
   'userdel:delete users'
   'useredit:edit/view users'
   'usermgmt:utilities to add/edit/view/delete user accounts'
+  vt_font
+  vt_keymap
+  vt_repeat
+  vt_saver
+  vt_screenmap
+  vt_ttys
 )
 
 _arguments -s -w -A '-*' : \
   '-d[debug mode]' \
   '-D[send debug info to file]: :{ compset -P 1 +; _files }' \
   '-f[load file as script then exit]: : _files' \
-  '-h[print usage then exit]' \
+  '-h[display help information]' \
   '-S[secure X11 mode]' \
   '-X[use Xdialog(1)]' \
-  '1:bsdconfig(8) menus:(( $shortcuts ))'
+  '1:bsdconfig(8) menu:(( $shortcuts ))'
diff --git a/Completion/BSD/Command/_fetch b/Completion/BSD/Command/_fetch
index 3136763..ac1264b 100644
--- a/Completion/BSD/Command/_fetch
+++ b/Completion/BSD/Command/_fetch
@@ -1,30 +1,43 @@
 #compdef fetch
-# Deprecated arguments are removed from the completion
 
-_arguments -s \
-	'-1[stop and return exit code 0 at the first successfully retrieved file]' \
-	'-4[forces fetch to use IPv4 addresses only]' \
-	'-6[forces fetch to use IPv6 addresses only]' \
-	'-A[do not automatically follow "temporary" (302) redirects]' \
-	'-a[automatically retry the transfer upon soft failures]' \
-	'-B[specify the read buffer size in bytes]:bytes:' \
-	'-d[use a direct connection even if a proxy is configured]' \
-	'-F[in combination with the -r flag, forces a restart]' \
-	'-l[if the target is a file-scheme URL, make a symbolic link to the target]' \
-	'-M' \
-	'-m[mirror mode]' \
-	'-N[use file instead of ~/.netrc to look up login names and pass- words for FTP sites]' \
-	'-n[do not preserve the modification time]' \
-	'-o[set the output file name]:file:_files' \
-	'-P' \
-	'-p[use passive FTP]' \
-	'-q[quiet mode]' \
-	'-R[do not delete the output file in any circumstances]' \
-	'-r[restart a previously interrupted transfer]' \
-	'-S[require the file size reported by the server to match the specified value]' \
-	'-s[print the size in bytes, without fetching it]' \
-	'-T[set timeout value]:seconds:' \
-	'-U[when using passive FTP, allocate the port for the data connection from the low port range]' \
-	'-v[increase verbosity level]' \
-	'-w[wait successive retries]:seconds:' \
-	'*:URL to fetch:_urls'
+# Deprecated arguments are prefixed with ! so they aren't listed but their arguments are completed
+_arguments -s -S \
+  '(-1 --one-file)'{-1,--one-file}'[stop and return exit code 0 at the first successfully retrieved file]' \
+  '(-4 --ipv4-only)'{-4,--ipv4-only}'[forces fetch to use IPv4 addresses only]' \
+  '(-6 --ipv6-only)'{-6,--ipv6-only}'[forces fetch to use IPv6 addresses only]' \
+  '(-A --no-redirect)'{-A,--no-redirect}"[don't automatically follow "temporary" (302) redirects]" \
+  '(-a --retry)'{-a,--retry}'[automatically retry the transfer upon soft failures]' \
+  '(-B --buffer-size)'{-B+,--buffer-size=}'[specify the read buffer size in bytes]:buffer size (bytes)' \
+  '--bind-address=[specify address to which outgoing connections will be bound]:host:_hosts' \
+  '--ca-cert=[specify certificate bundle containing trusted CA certificates]:file:_files' \
+  '--ca-path=[specify directory containing trusted CA hashes]:path:_directories' \
+  '--cert=[specify PEM encoded client key for authentication]:file:_files -g "*.pem(-.)"' \
+  '--crl=[specify certificate revocation list file]:file:_files' \
+  '(-d --direct)'{-d,--direct}'[use a direct connection even if a proxy is configured]' \
+  '(-F --force-restart)'{-F,--force-restart}'[in combination with the -r flag, forces a restart]' \
+  '(-i --if-modified-since)'{-i+,--if-modified-since=}'[only retrieve if remote file newer than specified local file]:file:_files' \
+  '--key=[specify PEM encoded client key]:key file:_files -g "*.pem(-.)"' \
+  '(-l --symlink)'{-l,--symlink}'[if the target is a file-scheme URL, make a symbolic link to the target]' \
+  '-M' \
+  '(-m --mirror -r --restart)'{-m,--mirror}'[mirror mode]' \
+  '(-N --netrc)'{-N+,--netrc=}'[use file instead of ~/.netrc to look up login names and pass- words for FTP sites]' \
+  '(-n --no-mtime)'{-n,--no-mtime}"[don't preserve the modification time]" \
+  '--no-passive[force FTP code to use active mode]' \
+  '--no-proxy=[hosts on which to disable proxoes]:host:_sequence _hosts' \
+  '--no-sslv3' '--no-tlsv1' --no-verify-hostname --no-verify-peer \
+  '(-o --output)'{-o+,--output=}'[set the output file name]:file:_files' \
+  '-P' \
+  '(-p --passive)'{-p,--passive}'[use passive FTP]' \
+  '--referer=:URL:_urls' \
+  '(-q --quiet)'{-q,--quiet}'[quiet mode]' \
+  '(-R --keep-output)'{-R,--keep-output}"[don't delete the output file in any circumstances]" \
+  '(-r --restart -m --mirror)'{-r,--restart}'[restart a previously interrupted transfer]' \
+  '(-S --require-size)'{-S+,--require-size=}'[require the file size reported by the server to match the specified value]' \
+  '(-s --print-size)'{-s,--print-size}'[print the size in bytes, without fetching it]' \
+  '(-T --timeout)'{-T+,--timeout=}'[set timeout value]:seconds:' \
+  '(-U --passive-portrange-default)'{-U,--passive-portrange-default}'[when using passive FTP, allocate the port for the data connection from the low port range]' \
+  '--user-agent=:user agent' \
+  '(-v --verbose)'{-v,--verbose}'[increase verbosity level]' \
+  '(-w --retry-delay)'{-w+,--retry-delay=}'[wait successive retries]:delay (seconds)' \
+  '!(*)-h+:host:_hosts' '!(*)-f+:file:_files' '!(*)-c+:remote directory:_directories' \
+  '*:URL to fetch:_urls'
diff --git a/Completion/BSD/Command/_freebsd-update b/Completion/BSD/Command/_freebsd-update
index 11235ba..36b4a01 100644
--- a/Completion/BSD/Command/_freebsd-update
+++ b/Completion/BSD/Command/_freebsd-update
@@ -7,14 +7,17 @@ flags=(
   '(install rollback)upgrade[fetch files necessary for upgrading to a new release]'
   '(upgrade rollback)install[install the most recently fetched updates or upgrade]'
   '(upgrade install)rollback[uninstall the most recently installed updates]'
+  'IDS[compare the system against an index of "known good" files]'
 )
 
-_arguments -s \
+_arguments \
   '-b[operate on a system mounted at basedir]:basedir:_files -/' \
   '-d[store working files in workdir]:workdir:_files -/' \
   '-f[read configuration options from conffile]:conf file:_files' \
-  '-k[trust an RSA key with SHA256 of KEY]:RSA key:' \
-  '-r[specify the new release]:new release:' \
+  '-F[force freebsd-update fetch to proceed where it normally would not]' \
+  '-k[trust an RSA key with SHA256 of KEY]:RSA key' \
+  '-r[specify the new release]:new release' \
   '-s[fetch files from the specified server or server pool]:server:_hosts' \
-  '-f[mail output of cron command, if any, to address]:address:' \
+  '-t[mail output of cron command, if any, to address]:address' \
+  '--currently-running[assume specified release as current]:release' \
   ':command:_values -S " " -w "commands" $flags[@]'
diff --git a/Completion/BSD/Command/_fstat b/Completion/BSD/Command/_fstat
index 3e8d617..5487e6c 100644
--- a/Completion/BSD/Command/_fstat
+++ b/Completion/BSD/Command/_fstat
@@ -1,15 +1,12 @@
 #compdef fstat
 
-local pids
-pids=(${${${(f)"$(/usr/bin/procstat -ah)"}/[[:space:]]#/}/[[:space:]]*[[:space:]](ELF[[:digit:]]#[[:space:]]|-[[:space:]]#)/:})
-
 _arguments -s \
 '-f[restrict examination to files open in the same file systems as the named file arguments]' \
-'-M[extract values associated with the name list from the specified core]:core:_files' \
-'-N[extract the name list from the specified system]:system:' \
+'-M+[extract values associated with the name list from the specified core]:core:_files' \
+'-N+[extract the name list from the specified system]:system' \
 '-m[include memory-mapped files in the listing]' \
 '-n[numerical format]' \
-'-p[report all files open by the specified process]:process id:(($pids))' \
-'-u[report all files open by the specified user]:user:_users' \
+'-p+[report all files open by the specified process]:process id:_pids' \
+'-u+[report all files open by the specified user]:user:_users' \
 '-v[verbose mode]' \
 '*:files:_files'
diff --git a/Completion/BSD/Command/_gstat b/Completion/BSD/Command/_gstat
index 55b7db7..7baaf0d 100644
--- a/Completion/BSD/Command/_gstat
+++ b/Completion/BSD/Command/_gstat
@@ -1,11 +1,11 @@
 #compdef gstat
 
-_arguments -s -w : \
+_arguments -s : \
   '-a[only display providers that are at least 0.1% busy]' \
   '-b[batch mode]' \
   '-c[enable the display geom(4) consumers]' \
   '-d[enable the display delete operations]' \
-  '-f[filter by regex]:regex' \
+  '-f+[filter by regex]:regex' \
   '-o[enable the display for other operations]' \
-  '-I[display refresh rate]:interval' \
+  '-I+[display refresh rate]:interval (ms)' \
   '-p[only display physical providers]'
diff --git a/Completion/BSD/Command/_jexec b/Completion/BSD/Command/_jexec
index f065ea1..279812b 100644
--- a/Completion/BSD/Command/_jexec
+++ b/Completion/BSD/Command/_jexec
@@ -9,7 +9,8 @@ _jexec_normal() {
 }
 
 _jexec() {
-  _arguments -s -w -A "-*" : \
+  _arguments -s -S -A "-*" : \
+    '-l[execute in a clean environment]' \
     '(-U)-u[host environment user whom command runs as]:host user:_users' \
     '(-u)-U[jail environment user whom command runs as]:jail user:_users' \
     '1:jail:_jails' \
diff --git a/Completion/BSD/Command/_kld b/Completion/BSD/Command/_kld
index 34f26f1..9452895 100644
--- a/Completion/BSD/Command/_kld
+++ b/Completion/BSD/Command/_kld
@@ -24,14 +24,17 @@ _kld() {
   unset _cache_sysctlvars
 
   case "$service" in
-  kldload)
-    _arguments -s \
+    kldload)
+      _arguments -s -S -A "-*" \
+        "-n[don't try to load module if already loaded]"
         '-v[be verbose]' \
+        '-q[silence any extraneous warnings]' \
         '*:module to load:_kld_module'
     ;;
 
-  kldunload)
-    _arguments -s \
+    kldunload)
+      _arguments -s -S -A "-*" \
+        '-f[force the unload]' \
         '-v[be verbose]' \
         '(-n)-i:module id to unload:_kld_unload_id' \
         '(-i)-n:module to unload:_kld_unload' \
diff --git a/Completion/BSD/Command/_procstat b/Completion/BSD/Command/_procstat
index f8bc542..e160576 100644
--- a/Completion/BSD/Command/_procstat
+++ b/Completion/BSD/Command/_procstat
@@ -1,17 +1,24 @@
 #compdef procstat
 
-local pids
-#get list of pids and associated process name as comment
-pids=(${${${(f)"$(/usr/bin/procstat -ah)"}/[[:space:]]#/}/[[:space:]]*[[:space:]](ELF[[:digit:]]#[[:space:]]|-[[:space:]]#)/:})
-
-_arguments -s \
-'-b[display binary information for the process]' \
-'-c[display command line arguments for the process]' \
-'-f[display file descriptor information for the process]' \
-'-k[display the stacks of kernel threads in the process]' \
-'-s[display security credential information for the process]' \
-'-t[display thread information for the process]' \
-'-v[display virtual memory mappings for the process]' \
-'-h[suppress table headers]' \
-'-a[all processes]' \
-':process id:(($pids))'
+_arguments -s -A "-*" -S \
+  '-b[show binary information]' \
+  '-c[show command line arguments]' \
+  '-e[show environment variables]' \
+  '-f[show file descriptor information]' \
+  '-i[show signal pending and disposition]' \
+  '-k[show stacks of kernel threads]' \
+  '-l[show resource limits]' \
+  '-r[show resource usage]' \
+  '-s[show security credential information]' \
+  '-S[show cpuset information]' \
+  '-t[show thread information]' \
+  '-v[show virtual memory mappings]' \
+  '-x[show ELF auxiliary vector]' \
+  '-h[suppress table headers]' \
+  '(1)-a[all processes]' \
+  '-w+[repeat information after specified interval]:delay (seconds)' \
+  '-C[print additional capability information for file descriptors]' \
+  '-H[statistics per-thread rather than per-process]' \
+  '-n[numeric form for signals]' \
+  '1::core file:_path_files -g "*core*(-.)"' \
+  '*:process id:_pids'
diff --git a/Completion/BSD/Command/_sysrc b/Completion/BSD/Command/_sysrc
index d8bc4ef..651c18b 100644
--- a/Completion/BSD/Command/_sysrc
+++ b/Completion/BSD/Command/_sysrc
@@ -1,39 +1,50 @@
 #compdef sysrc
+
 _sysrc_caching_policy() {
   local -a oldp
   oldp=( "$1"(Nm+1) )
   (( $#oldp ))
 }
 
-
 _sysrc() {
-  _arguments -A '-*' : \
+  local curcontext="$curcontext" state line ret=1
+  typeset -A opt_args
+  local -a rc_conf_vars
+
+  _arguments -C -s -A '-*' : \
+    '(-l)-e[print variables as sh(1) compatible syntax]' \
+    '-E[list only existing files]' \
+    '(-l)-q[quiet mode]' \
+    '(-L)-s+[process additional rc.conf.d entries for specified service name]:service name:_services' \
+    '(-L)*-f+[operate on specified file(s), not \`rc_conf_files'\'']: : _files' \
+    '(-l)-v[verbose mode]' \
+    '*:configuration variable:->confvars' \
+    - set \
+    '(-A)-a[list all non-default configuration variables]' \
+    '(-a)-A[list all configuration variables]' \
     '-c[check only, return success if vars are set]' \
     '-d[print variable(s) description]' \
     '-D[print default value(s) only]' \
-    '-e[print variables as sh(1) compatible syntax]' \
-    '*-f[operate on specified file(s), not \`rc_conf_files'\'']: : _files' \
     '-F[print only the last rc.conf(5) file each directive is in]' \
-    '-h[print short usage message]' \
-    '--help[print full usage message]' \
+    '(- *)-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]:jails:_jails' \
     '-n[print only variable values]' \
     '-N[print only variable names]' \
-    '-q[quiet mode]' \
-    '-R[specify an alternative root]:alternative root:_files -/' \
-    '-v[verbose mode]' \
-    '--version[print version information]' \
+    '-R+[specify an alternative root]:alternative root:_files -/' \
+    '(- *)--version[print version information]' \
     '-x[remove specified variables from specified file(s)]' \
-    '*:configuration variable:->confvars' \
-    - set1 \
-    '-a[list all non-default configuration variables]' \
-    - set2 \
-    '-A[list all configuration variables]'
+    - lists \
+    '(-e -q -v)-l[list config files used at startup]' \
+    - lista \
+    '(-s -f)-L[list all configuration files including rc.conf.d entries]' && ret=0
 
   if [[ $state  == confvars ]]; then
-    local k v opt curcontext="${curcontext%:*}:values"; local -a rc_conf_vars
-    if [[ -prefix *=* ]]; then
+    local k v opt
+    if (( $+opt_args[lista--L] )); then
+      _services && ret=0
+    elif [[ -prefix *=* ]]; then
       # do you really want to go down this hole?
       _message -e values value
     else
@@ -65,13 +76,15 @@ _sysrc() {
 
       if (( $#rc_conf_vars )); then
         if [[ $opt == N ]]; then
-          _values -w -C variable ${^rc_conf_vars%%\[*}'::value'
+          _values -w -C variable ${^rc_conf_vars%%\[*}'::value' && ret=0
         else
-          _values -w -C variable ${^rc_conf_vars}'::value'
+          _values -w -C variable ${^rc_conf_vars}'::value' && ret=0
         fi
       fi
     fi
   fi
+
+  return ret
 }
 
 _sysrc "$@"
diff --git a/Completion/BSD/Command/_systat b/Completion/BSD/Command/_systat
index c8348c7..35b8421 100644
--- a/Completion/BSD/Command/_systat
+++ b/Completion/BSD/Command/_systat
@@ -1,12 +1,13 @@
 #compdef systat
 
-local -a screens args opts
+local -a screens opts
 local pre
 case $OSTYPE in
   freebsd*)
     pre=-
     screens=(
       'pigs:processes consuming the most CPU time'
+      'sctp:SCTP statistics'
       icmp{6,}':ICMP statistics'
       ip{6,}':IP and UDP statistics'
       'tcp:TCP statistics'
diff --git a/Completion/Unix/Command/_cat b/Completion/Unix/Command/_cat
index e223d90..57b1970 100644
--- a/Completion/Unix/Command/_cat
+++ b/Completion/Unix/Command/_cat
@@ -30,6 +30,9 @@ elif [[ "$OSTYPE" == (freebsd|dragonfly|darwin)* ]]; then
     '-v[display non-printing chars as ^X or M-a]'
     '(-)*:files:_files'
   )
+  [[ $OSTYPE = freebsd* ]] && args+=(
+    '-l[set a lock on the stdout file descriptor]'
+  )
 
 else
   # POSIX reqires '-u', and most OSes may support '-n'
diff --git a/Completion/Unix/Command/_sysctl b/Completion/Unix/Command/_sysctl
index 9d9e8b9..cf88c3d 100644
--- a/Completion/Unix/Command/_sysctl
+++ b/Completion/Unix/Command/_sysctl
@@ -1,21 +1,39 @@
 #compdef sysctl
 
+local -a args
+
 case $OSTYPE in
+  freebsd<10->.*)
+    args+=(
+      '-f+[specify file of name/value pairs to process first]:file:_files'
+      '-T[display only variables that are setable via loader]'
+      '-W[display only writable variables that are not statistical]'
+    )
+  ;|
+  dragonfly*|freebsd<8->.*)
+    args+=( "-i[silently exit if variable doesn't exist]" )
+  ;|
   *freebsd<5->.*|freebsd4.[4-9]*)
     local -a sysctlvars
     sysctlvars=( $(_call_program sysctl-variables sysctl -aN) )
-    _arguments -s -A "-*" \
+    _arguments -s -S -A "-*" $args \
+      '(-a -o *)-A[equivalent to -o -a (for compatibility)]' \
       '(*)-a[list all]' \
       '-b[binary output]' \
+      '-d[print the description of the variable instead of its value]' \
+      '(-N -n)-e[separate name and value with =]' \
+      '-h[format output for human readability]' \
       '(-n)-N[show only variable names]' \
       '(-N)-n[show only variable values]' \
       '(-x)-o[show opaques as well (values suppressed)]' \
+      '-q[suppress some warnings]' \
+      '(* -o)-X[equivalent to -x -a (for compatibility)]' \
       '(-o)-x[show opaques as well (entire values)]' \
       '(-a)*:sysctl variable:_multi_parts -i . sysctlvars'
   ;;
   freebsd[0-4].*|darwin*|dragonfly*)
     : ${(A)_cache_sysctlvars:=${${$(sysctl -A 2>/dev/null):#[^a-z]*}%%:*}}
-    _arguments -s -A "-*" \
+    _arguments -s -A "-*" $args \
       '(-w -X *)-a[list all]' \
       '(-w -X *)-A[show all opaques (values suppressed)]' \
       '(-w)-b[binary output]' \
diff --git a/Completion/Unix/Command/_vmstat b/Completion/Unix/Command/_vmstat
index 02fa6be..7082cbb 100644
--- a/Completion/Unix/Command/_vmstat
+++ b/Completion/Unix/Command/_vmstat
@@ -18,40 +18,38 @@ case $OSTYPE in
       '1:delay' '2:count'
     )
   ;;
-  freebsd*)
+  freebsd*|openbsd*)
     specs=(
-      '-a[include statistics about all interrupts]'
       '-c[number of times to refresh the display]:count'
       '-f[report on the number fork syscalls since boot and pages of virtual memory for each]'
-      '-h[human readable memory columns output]'
-      '-H[scriptable memory columns output]'
       '-i[report the number of interrupts taken by devices since boot]'
       '-M[source file to extract values associated with the name list from]:core:_files'
       '-N[source file to extract the name list from]:system:_files'
+      '-w[specify delay between each display]:delay (seconds)'
+      '*:disk:_files'
+    )
+  ;|
+  freebsd*)
+    specs+=(
+      '-a[include statistics about all interrupts]'
+      '-h[human readable memory columns output]'
+      '-H[scriptable memory columns output]'
       '-m[report on the usage of kernel dynamic memory allocated using malloc(9) by type]'
       '-n[change the maximum number of disks to display]:number of disks to display'
+      '-o[list virtual memory objects]'
       '-P[report per-cpu system/user/idle cpu statistics]'
       '-p[specify which types of devices to display]: :->devices'
       '-s[display the contents of the SUM structure]:sum'
-      '-w[delay N seconds between each display]:delay'
       '-z[report on memory used by the kernel zone allocator, uma(9), by zone]'
-      '*:disks:_files'
     )
   ;;
   openbsd*)
-    specs=(
-      '-c[number of times to refresh the display]:count'
-      '-f[report on the number fork syscalls since boot and pages of virtual memory for each]'
-      '-i[report the number of interrupts taken by devices since boot]'
-      '-M[source file to extract values associated with the name list from]:core:_files'
+    specs+=(
       '-m[report usage of kernel dynamic memory listed first by size of allocation then type of usage]'
-      '-N[source file to extract the name list from]:system:_files'
       '-s[display the contents of the UVMEXP structure]:uvmexp'
       '-t[report on the number of page in and page reclaims since boot]'
       '-v[print more verbose information]'
-      '-w[delay N seconds between each display]:delay'
       '-z[include statistics about all interrupts]'
-      '*:disks:_files'
     )
   ;;
 esac
diff --git a/Completion/Unix/Command/_zfs b/Completion/Unix/Command/_zfs
index f3869da..553996d 100644
--- a/Completion/Unix/Command/_zfs
+++ b/Completion/Unix/Command/_zfs
@@ -149,7 +149,7 @@ _zfs() {
 		"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)"
+		"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)"
@@ -247,7 +247,7 @@ _zfs() {
 			':filesystem/volume/snapshot:_zfs_dataset -t fs -t vol'
 		;;
 
-	("snapshot")
+	(snap(|shot))
 		_arguments -A "-*" \
 			'-r[Recursively snapshot all descendant datasets]' \
 			'*-o[Set property]:property:_values -s , "property" $create_properties' \
@@ -418,30 +418,16 @@ _zfs() {
 
 	("allow")
 		_arguments -A "-*" \
-			- set1 \
-			':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]' \
+			'(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' \
-			- 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' \
-			- set5 \
-			'-s[Define or modify permission sets]' \
-			':setname:' \
-			':permissions or sets:_values -s , "permission or set" $delegatable_perms' \
-			':filesystem/volume:_zfs_dataset -t fs -t vol'
 		;;
 
 	("unallow")
diff --git a/Completion/Unix/Type/_zfs_dataset b/Completion/Unix/Type/_zfs_dataset
index 5fa3e9e..6c625e9 100644
--- a/Completion/Unix/Type/_zfs_dataset
+++ b/Completion/Unix/Type/_zfs_dataset
@@ -58,14 +58,14 @@ if [[ ${#rdst} -gt 0 ]]; then
 fi
 
 if [[ -n $type[(r)clone] ]]; then
-	datasetlist=( ${="$(zfs list -H -o name,origin -t filesystem | awk "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
+	datasetlist=( ${="$(zfs list -H -o name,origin -t filesystem 2>/dev/null | awk "\$2 != \"-\" {print \$1}")":#no cloned filesystems available} )
 else
-	datasetlist=( ${="$(zfs list -H -o name $typearg)":#no datasets available} )
+	datasetlist=( ${="$(zfs list -H -o name $typearg 2>/dev/null)":#no datasets available} )
 fi
 
 expl_type=${typearg[2,-1]//,/\/}
 if [[ -n $type[(r)mtpt] ]]; then
-	mlist=( ${="$(zfs list -H -o mountpoint $typearg)":#no mountpoints available} )
+	mlist=( ${="$(zfs list -H -o mountpoint $typearg 2>/dev/null)":#no mountpoints available} )
 	datasetlist=( $datasetlist $mlist )
 	expl_type="$expl_type/mountpoint"
 fi


^ permalink raw reply	[relevance 1%]

* Re: Script interpreter path length limit (POUNDBANGLIMIT)
  @ 2016-08-11  2:20  3% ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-08-11  2:20 UTC (permalink / raw)
  To: zsh-workers

On Aug 10,  8:41pm, Dennis Sperlich wrote:
}
} It seems like there is a arbitrary 63 character limit on the interpreter
} char buffer. At least this is what i understand from the code in
} Src/exec.c starting line 431.

The specific choice of 64 for the buffer size (63+nul) is historical and
loosely based on OS limitations of the 1990s.

A LOT of info about this here:

    http://www.in-ulm.de/~mascheck/various/shebang/#results

Rather lacking in very-recent OS's, but you get the idea how inconsistent
this is.  I can't find anything about a standard way to look up the limit
on the build architecture, probably because POSIX defines #! as optional.

The limit in zsh could be expanded to allow the OS to flag the error.


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] New :P history modifier.
  @ 2016-08-17  7:02  3% ` Bart Schaefer
  2016-08-17 16:31  0%   ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-08-17  7:02 UTC (permalink / raw)
  To: zsh-workers

On Aug 16, 11:54pm, Daniel Shahaf wrote:
}
} WDYT?

The code changes are essentially OK; my only thought is, maybe we
should just remove the dependency on the POSIX realpath() call even
from :A, and use xsymlink() everywhere?

Picking at the docs ...

Given that we went to the trouble of hashing it out, it is probably
worth noting that :a is intended to result in the path to along which
"cd" would change under the default setopts (no_chase_dots), and :A
is meant to result in the physical directory at the end of that path.

} +	"a:absolute path, resolve '..' logically"
} +	"A:same, then resolve symlinks"
} +	"P:realpath, resolve '..' physically"

You should spell out what "same" means, because the two descriptions
may not always appear together.  I'm not sure "logical" and "physical"
are the right words here, but "by text replacement" and "by filesystem
reference" seem a bit too verbose, so I don't have a suggestion, just
calling attention.

(Aside:  The doc for "cd" doesn't ever describe how it behaves when
CHASE_DOTS is not set; the user is left to infer it from the doc that
explains what happens when CHASE_DOTS is set.)

} +The new word modifier ':P' computes the realpath() of the argument.
} +It is different from the existing ':a' modifier which does not resolve
} +symlinks, and from the existing ':A' modifier which always resolves
   ^^^^^^^^

If you're going to compare to both :a and :A, symlinks aren't the largest
difference vs. :a -- following ".." is.  In fact I'd say following ".."
is more important to the distinction than symlinks are.

} +/before/here/../after to /before/after --- even if /before/here is
} +a symbolic link.  It is recommended to review uses of ':A' and, if
} +appropriate, convert them to ':P' as soon as compatibility with 5.2 is
} +no longer a requirement.

So how about e.g.:

 The new word modifier ':P' computes the physical path of the argument.
 it is different from the existing ':a' modifier which does always
 resolves /before/here/../after to /before/after, and differs from the
 existing ':A' modifier which resolves symlinks only after here/.. is
 removed even when /before/here is itself a symbolic link.

That's all.


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] New :P history modifier.
  2016-08-17  7:02  3% ` Bart Schaefer
@ 2016-08-17 16:31  0%   ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-08-17 16:31 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Wed, Aug 17, 2016 at 00:02:40 -0700:
> On Aug 16, 11:54pm, Daniel Shahaf wrote:
> }
> } WDYT?
> 
> The code changes are essentially OK; my only thought is, maybe we
> should just remove the dependency on the POSIX realpath() call even
> from :A, and use xsymlink() everywhere?
> 

Two thoughts:

- Does anyone actually build zsh on a system that doesn't have realpath()?

- xsymlink() is not a drop-in replacement: it tolerates trailing
  non-existing path components.  The single callsite in current master
  wouldn't care, though.

> Picking at the docs ...
> 
> Given that we went to the trouble of hashing it out, it is probably
> worth noting that :a is intended to result in the path to along which
> "cd" would change under the default setopts (no_chase_dots),

38945 made such a change; do you think further changes are needed?

> and :A is meant to result in the physical directory at the end of that
> path.

No wording comes to mind, here.

> 
> } +	"a:absolute path, resolve '..' logically"
> } +	"A:same, then resolve symlinks"
> } +	"P:realpath, resolve '..' physically"
> 
> I'm not sure "logical" and "physical"
> are the right words here, but "by text replacement" and "by filesystem
> reference" seem a bit too verbose, so I don't have a suggestion, just
> calling attention.

They might work as parentheticals: "a:... logically (by text
replacement)" and "P:... physically (by filesystem lookup)"?

Some other options:

- :a   syntactically / lexically / "like 'cd'"
- :P   semantically / "like stat(2)"

(yes, "like 'cd'" is inaccurate if CHASE_* are set)

> You should spell out what "same" means, because the two descriptions
> may not always appear together.

I'll change "same" to "as ':a'".

I wonder if there's a way to make the :A completion text convey "Unless
you're trying to predict what 'cd' is about to do, you probably want :P,
not :A"...

> } +The new word modifier ':P' computes the realpath() of the argument.
> } +It is different from the existing ':a' modifier which does not resolve
> } +symlinks, and from the existing ':A' modifier which always resolves
>    ^^^^^^^^
> 
> If you're going to compare to both :a and :A, symlinks aren't the largest
> difference vs. :a -- following ".." is.  In fact I'd say following ".."
> is more important to the distinction than symlinks are.
>
> } +/before/here/../after to /before/after --- even if /before/here is
> } +a symbolic link.  It is recommended to review uses of ':A' and, if
> } +appropriate, convert them to ':P' as soon as compatibility with 5.2 is
> } +no longer a requirement.
> 
> So how about e.g.:
> 
>  The new word modifier ':P' computes the physical path of the argument.
>  it is different from the existing ':a' modifier which does always
>  resolves /before/here/../after to /before/after, and differs from the
>  existing ':A' modifier which resolves symlinks only after here/.. is
>  removed even when /before/here is itself a symbolic link.
> 

Looks good to me.

What about the "It is recommended [to audit uses of :A and change them
to :P]" sentence that the original patch had, should it be kept or
removed?

> That's all.

Thanks for the review!

Daniel


^ permalink raw reply	[relevance 0%]

* Re: [PATCHv2] [bug] $SHLVL decremented for the last command of a subshell
  2016-08-30 19:54  3%             ` Stephane Chazelas
@ 2016-08-30 20:10  0%               ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2016-08-30 20:10 UTC (permalink / raw)
  To: Peter Stephenson, Zsh hackers list

2016-08-30 20:54:29 +0100, Stephane Chazelas:
[...]
> Yes, it's not POSIX. It was probably either a tcsh or bash
> invention as both had it in 1990 and ksh88 didn't and still
> doesn't have it.
[...]

tcsh.

https://groups.google.com/forum/#!original/net.sources/WdFUCQb7vr0/o3NafIxCUV4J
https://groups.google.com/forum/#!original/net.sources/VpHdbFdEi0w/a_AgLdbJbxkJ
(1984) a patch for tcsh with SHLVL referenced.

Strangely though, tcsh 5.7 from 1987 didn't have it.

-- 
Stephane


^ permalink raw reply	[relevance 0%]

* Re: buggy configure completion - when both --enable-foo and --disable-foo are listed
  @ 2016-08-31  9:09  3%     ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-08-31  9:09 UTC (permalink / raw)
  To: zsh-workers

Vincent Lefevre wrote on Wed, Aug 31, 2016 at 08:15:55 +0200:
> On 2016-08-31 03:00:55 +0000, Daniel Shahaf wrote:
> > Vincent Lefevre wrote on Wed, Aug 31, 2016 at 01:23:32 +0200:
> > > With zsh 5.2, I get the following, which doesn't make sense:
> > > 
> > > zira:~/software/mpfr> ./configure --enable-decimal-float[Tab]
> > > Completing option
> > > --enable-decimal-float  -- build conversion functions from/to decimal floats
> > > --enable-decimal-float  -- explicitly disable decimal floats support
> > > 
> > > One has from the "configure --help" output:
> > > 
> > >   --disable-decimal-float explicitly disable decimal floats support
> > >   --enable-decimal-float  build conversion functions from/to decimal floats
> > >                           [default=autodetect]
> > 
> > What do you expect to see?  How should the two strings ("build .." and
> > "explicitly ...") be handled?
> > 
> > Minimal example:
> > 
> > % print -rl -- '#!/bin/sh' 'cat <<"EOF"' '  --enable-foo  enable foo' '  --disable-foo  disable foo' 'EOF' >configure
> > % chmod +x configure
> > % ./configure --<TAB>
> > --disable-foo  --enable-foo  -- enable foo                                    
> > --disable-foo  --enable-foo  -- disable foo                                   
> 
> The problem is that it says "build conversion functions from/to
> decimal floats" after --enable-decimal-float while it corresponds
> to --disable-decimal-float.

I see.  I missed that in my previous reply.  Thanks for spelling it out.

I agree, the current completion is misleading.  This occurs with zsh's
configure script too:
.
% ./configure --enable-<TAB>
--enable-dynamic             -- turn off dynamically loaded binary modules

> So, I'd say, either
> 
> --enable-decimal-float  -- build conversion functions from/to decimal floats
> --disable-decimal-float -- explicitly disable decimal floats support
> 

You can sort of get this with a matchspec.  If you take the _configure
function in master, delete the -s parameter, and add a -M parameter,
like this:

_configure () {
        _arguments -M 'B:--en=--dis B:--dis=--en' : -- -i '(--(disable|enable)-FEATURE* --(with|without)-PACKAGE*)' '*=(E|)PREFIX*:prefix directory:_files -/' '*=PROGRAM*:program:_command_names -e' '*=NAME*executable*:program:_command_names -e' '*=NAME*:file:_files'
}

The behaviour of this function is different in three ways from the
_configure function in current master:

1) This function shows the correct --disable/--enable argument to the
left of each description:
.
% ./configure --en<TAB>
> option
--disable-dynamic            - turn off dynamically loaded binary modules
--disable-dynamic-nss        - do not call functions that will require dynamic NSS
--disable-gdbm               - turn off search for gdbm library
   …able-additional-fpath    - add directories to default function path
   …able-ansi2knr            - translate source to K&R C before compiling
   …able-cap                 - enable the search for POSIX capabilities (may
.
... and if you choose one of the first three options, the string inserted
in to the command line is "--enable-dynamic", not "--disable-dynamic".

2) Completing «./configure --<TAB>» will show next to each docstring
*either* the --enable-* or --disable-*, but not both.  This means the
user can tell at a glance whether the docstring describes --enable or
--disable, but also that (in the above example) the user has to type 'e'
'n' <TAB> to get compsys to fill in the rest of the word "-enable-dynamic".

3) «./configure --e<TAB>» won't offer the --enable-* counterparts of
options shown in the first output as --disable-*.  (I assume some smarter
matchspec could take care of this.)

Or maybe there's a better approach that doesn't use matchspecs at all.

> (thus skipping the --disable-decimal-float when one completes on
> --enable[Tab]), or add "=no" for the disable cases, e.g.:
> 
> --enable-decimal-float    -- build conversion functions from/to decimal floats
> --enable-decimal-float=no -- explicitly disable decimal floats support

Cheers,

Daniel


^ permalink raw reply	[relevance 3%]

* Re: [PATCHv2] [bug] $SHLVL decremented for the last command of a subshell
  @ 2016-08-30 19:54  3%             ` Stephane Chazelas
  2016-08-30 20:10  0%               ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2016-08-30 19:54 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

2016-08-30 18:00:32 +0100, Peter Stephenson:
[...]
> When this was introduced in zsh, there was some controversy over whether
> it was the right thing to do.  I decided it was on the basis that the
> "level" is how deep you are in the process hierarchy, rather than how
> many processes have previously been executed to get where you are,
> seeing as the latter isn't really visible in the current context.
> But I'm not aware of any requirement specification [remember those?]
> saying what the purpose of SHLVL is.
[...]

Yes, it's not POSIX. It was probably either a tcsh or bash
invention as both had it in 1990 and ksh88 didn't and still
doesn't have it.

And zsh behaves like tcsh and bash here (in that SHLVL is
decreased in zsh -c 'exec cmd').

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: buggy configure completion - when both --enable-foo and --disable-foo are listed
  @ 2016-09-02 21:02  2%       ` m0viefreak
  0 siblings, 0 replies; 200+ results
From: m0viefreak @ 2016-09-02 21:02 UTC (permalink / raw)
  To: zsh-workers


On 02.09.2016 03:27, Bart Schaefer wrote:
> On Aug 31, 10:27pm, m0viefreak wrote:
> }
> } On 31.08.2016 05:00, Daniel Shahaf wrote:
> } > I think that's the best we can do without writing new C code to suport
> } > multiline descriptions.
> } 
> } This has been working well for me:
> } 
> } zstyle ':completion:*:configure:*:options' command $'print -r -- "${$(COLUMNS=9999 ${~words[1]} --help)//\n        #/ }"'
> 
> If that works, then we ought to be able to rewrite the loop starting
> at about line 91 of _arguments.  But that loop already seems to be
> looking for lines with leading spaces, whereas if I'm reading your
> pattern correctly you're unfolding lines with more than six leading
> spaces to make them part of the previous line?
> 
> I have to update that to look for more than eight spaces for it to work
> right for zsh's ./configure

Oh, right, I'm missing one #. It should have been '[8spaces]##':

zstyle ':completion:*:configure:*:options' command $'print -r -- "${$(COLUMNS=9999 ${~words[1]} --help)//\n        ##/ }"'


> and even then it mysteriously fails to pick
> out defaults [/usr/local] and [PREFIX] for --prefix and --exec-prefix
> respectively, though it gets it right for --datarootdir et al.

This works fine for me:

~/sources/zsh $ ./configure --e<TAB>
Completing: option
--enable-additional-fpath    -- add directories to default function path
--enable-ansi2knr            -- translate source to K&R C before compiling
--enable-cap                 -- enable the search for POSIX capabilities (may require additional headers to be added by hand)
--enable-cflags              -- specify C compiler flags
--enable-cppflags            -- specify C preprocessor flags
--enable-custom-patchlevel   -- set a custom ZSH_PATCHLEVEL value
--enable-etcdir              -- the default directory for global zsh scripts
--enable-fndir               -- the directory in which to install functions
--enable-function-subdirs    -- install functions in subdirectories
--enable-ldflags             -- specify linker flags
--enable-libc-musl           -- compile with musl as the C library
--enable-libs                -- specify link libraries
--enable-maildir-support     -- enable maildir support in MAIL and MAILPATH
--enable-max-function-depth  -- limit function depth to MAX, default 1000
--enable-multibyte           -- support multibyte characters
--enable-pcre                -- enable the search for the pcre library (may create run-time library dependencies)
--enable-readnullcmd         -- pager used when READNULLCMD is not set
--enable-runhelpdir          -- the directory in which to install run-help files
--enable-scriptdir           -- the directory in which to install scripts
--enable-site-fndir          -- same for site functions (not version specific)
--enable-site-scriptdir      -- same for site scripts (not version specific)
--enable-stack-allocation    -- allocate stack memory e.g. with `alloca'
--enable-zlogin              -- the full pathname of the global zlogin script
--enable-zlogout             -- the full pathname of the global zlogout script
--enable-zprofile            -- the full pathname of the global zprofile script
--enable-zsh-debug           -- compile with debug code and debugger symbols
--enable-zsh-hash-debug      -- turn on debugging of internal hash tables
--enable-zsh-heap-debug      -- turn on error checking for heap allocation
--enable-zsh-mem             -- compile with zsh memory allocation routines
--enable-zsh-mem-debug       -- debug zsh memory allocation routines
--enable-zsh-mem-warning     -- print warnings for errors in memory allocation
--enable-zsh-secure-free     -- turn on error checking for free()
--enable-zsh-valgrind        -- turn on support for valgrind debugging of heap memory
--enable-zshenv              -- the full pathname of the global zshenv script
--enable-zshrc               -- the full pathname of the global zshrc script
--exec-prefix                -- install architecture-dependent files in EPREFIX (PREFIX)

~/sources/zsh $ ./configure --p<TAB>
Completing: option
--pdfdir                  -- pdf documentation (DOCDIR)
--prefix                  -- install architecture-independent files in PREFIX (/usr/local)
--program-prefix          -- prepend PREFIX to installed program names
--program-suffix          -- append SUFFIX to installed program names
--program-transform-name  -- run sed PROGRAM on installed program names
--psdir                   -- ps documentation (DOCDIR)


Also, slightly related:
The _configure completion could benefit from my patch I sent back in march:
http://www.zsh.org/mla/workers//2016/msg00674.html


^ permalink raw reply	[relevance 2%]

* PATCH: completion updates for new options
@ 2016-09-03  8:41  8% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2016-09-03  8:41 UTC (permalink / raw)
  To: Zsh workers

This is another batch of updates for options added in newer versions of
various software. Specifically:

_git: updated for 2.10.0 which was only just released this morning.
_ss: 160808, new --kill and --no-header options
_ant: 1.9.2 which isn't the latest, only a -silent option.
_dmidecode: 3.0, options for dumping data to a file
_espeak: 1.48.03, quite a few changes
_look: long options on linux where it is util-linux 2.28.1
_md5sum: coreutils 8.25, new --ignore-missing option
_patch: GNU 2.7.5 plus some fixes to the patterns for FreeBSD and Solaris
_prove: 3.36, only a -V alias for --version
_tin: 2.4.0: was out-of-date by many years but only adds IPv4/6 options

Oliver

diff --git a/Completion/Linux/Command/_ss b/Completion/Linux/Command/_ss
index 520fd4b..90d83a4 100644
--- a/Completion/Linux/Command/_ss
+++ b/Completion/Linux/Command/_ss
@@ -32,7 +32,9 @@ _arguments -C -s \
   "($info -d --dccp)"{-d,--dccp}'[display DCCP sockets]' \
   "($info -w --raw)"{-w,--raw}'[display RAW sockets]' \
   "($info -x --unix)"{-x,--unix}'[display Unix domain sockets]' \
-  "($info -f --family)"{-f,--family}'[display sockets of specified type]:family:(unix inet inet6 link netlink)' \
+  "($info -f --family)"{-f,--family}'[display sockets of specified type]:family:(unix inet inet6 link netlink unix)' \
+  "($info -K --kill)"{-K,--kill}'[forcibly close sockets, display what was closed]' \
+  "($info -H --no-header)"{-H,--no-header}'[suppress header line]' \
   "($info -A --query --socket)"{-A,--query,--socket}'[specify socket tables to show]: :_values -s , socket\ table all inet tcp udp raw unix packet netlink unix_dgram unix_stream unix_seqpacket packet_raw packet_dgram' \
   "($info -D)"{-D,--diag=}'[dump raw info to file]:file:_files' \
   "($info -F)"{-F,--filter=}'[read filter information from a file]:file:_files' \
diff --git a/Completion/Unix/Command/_ant b/Completion/Unix/Command/_ant
index ee9f7d9..195a543 100644
--- a/Completion/Unix/Command/_ant
+++ b/Completion/Unix/Command/_ant
@@ -41,6 +41,7 @@ _arguments -C \
   '(- *)-version[display version information]' \
   '(- *)-diagnostics[print information helpful to diagnosis or report problems]' \
   '(-q -quiet)'{-q,-quiet}'[be extra quiet]' \
+  '(-s -silent)'{-s,-silent}'[print nothing but task outputs and build failures]' \
   '(-v -verbose)'{-v,-verbose}'[be extra verbose]' \
   '(-d -debug)'{-d,-debug}'[print debugging information]' \
   '(-e -emacs)'{-e,-emacs}'[produce logging information without adornments]' \
diff --git a/Completion/Unix/Command/_dmidecode b/Completion/Unix/Command/_dmidecode
index 0ff5611..5701a94 100644
--- a/Completion/Unix/Command/_dmidecode
+++ b/Completion/Unix/Command/_dmidecode
@@ -1,10 +1,13 @@
 #compdef dmidecode
 
-_arguments \
-  '(-d --dev-mem)'{-d,--dev-mem}':memory device:_files' \
+_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]' \
-  '(-t --type -u --dump -s --string)'{-s,--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)' \
-  '(-t --type)'{-t,--type}':types to display:(bios system baseboard chassis processor memory cache connector slot)' \
-  '(-q --quiet -u --dump -s --string)'{-u,--dump}'[do not decode]' \
-  '(-h --help)'{-h,--help}'[display usage information]' \
-  '(-V --version)'{-V,--version}'[display version information]'
+  '(--type -u --dump --dump-bin -s --string)'{-s+,--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 --dump-bin)'{-t+,--type=}'[only display entries of specified type]:entry type:(bios system baseboard chassis processor memory cache connector slot)' \
+  '(-q --quiet -u --dump -s --string)'{-u,--dump}"[don't decode entries]" \
+  '--dump-bin=[dump DMI data to a binary file]:file:_files' \
+  '(-d --dev-mem)--from-dump=[read DMI data from a binary file]:file:_files' \
+  "--no-sysfs[don't attempt to read DMI data from sysfs files]" \
+  '(-)'{-V,--version}'[display version information]'
diff --git a/Completion/Unix/Command/_espeak b/Completion/Unix/Command/_espeak
index d868c79..4ab443b 100644
--- a/Completion/Unix/Command/_espeak
+++ b/Completion/Unix/Command/_espeak
@@ -1,33 +1,46 @@
 #compdef espeak
 
-#TODO: complete non-existing filenames for -w and --phonout
-#TODO: describe special cases for -k
-#TODO: complete --punct better?
+local curcontext="$curcontext" state line expl ret=1
+typeset -A opt_args
 
-_arguments \
-    '-h[help]' \
-    '-f[file to speak]:text file:_files' \
-    '--stdin[speak from stdin]' \
-    '-q[quiet, no sound output]' \
-    '-a[amplitude]:integer:(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
-18 19 20)' \
-    '-l[line length]:integer: ' \
-    '-p[pitch]:integer:(0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
-19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
-43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
-67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
-91 92 93 94 95 96 97 98 99)' \
-    '-s[speed]:words per minute: ' \
-    '-v[voice]:voice name:(afrikaans bosnian catalan czech welsh-test danish-test german greek default en-scottish english lancashire english_rp english_wmids english-us en-westindies esperanto spanish spanish-latin-american finnish french french greek-ancient hindi-test croatian hungarian armenian armenian-west indonesian-test icelandic-test italian test/jbo kurdish latin latvian macedonian-test dutch-test norwegian-test test/pap polish brazil portugal romanian russian_test slovak albanian serbian swedish swahihi-test tamil turkish vietnam-test Mandarin cantonese-test)' \
-    '-b[8-bit text]' \
-    '-m[SSML or other XML text]' \
-    '-w[wav output]:filename: ' \
-    '-x[output phoneme mnemonics]' \
-    '-X[output phoneme mnemonics and translation trace]' \
-    '--stdout[output speech to stdout]' \
-    '-k[capital letter indication]:integer:' \
-    '--punct=-::characters: ' \
-    '--voices=-[list available voices]::language code:(af bs ca cs cy da de el en en-sc en-uk en-uk-north en-uk-rp en-uk-wmids en-us en-wi eo es es-la fi fr fr-be grc hi hr hu hy hy id is it jbo ku la lv mk nl no pap pl pt pt-pt ro ru sk sq sr sv sw ta tr vi zh zh-yue)' \
-    '--path=-[espeak-data path]:path:_files -/' \
-    '--compile=-[compile]::voicename or debug: ' \
-    '--phonout=-[output filename for -x/-X]:filename: ' 
+_arguments -C \
+  '(1 --stdin)-f+[specify file to speak]:text file:_files' \
+  '(1 -f)--stdin[speak from stdin]' \
+  '(-q)-a+[specify amplitude]:amplitude (0-200) [100]' \
+  '(-q)-g+[specify pause between words]:pause (10ms) [1]' \
+  '-k[capital letter indication]:integer:((1\:sound 2\:the\ word\ "capitals"))' \
+  '-l[specify line length below which clause is ended]:length' \
+  '(-q)-p+[specify pitch adjustment]:adjustment (0-99)' \
+  '(-q)-s+[specify speed]:speed (words per minute) [175]' \
+  '(-q)-v+[voice]:voice name:->voices' \
+  '(--stdout -q)-w+[write speech to wav file]:wav file:_files -g "*.wav(-.)"' \
+  '-b+[specify input encoding]:encoding:((1\:UTF-8 2\:8-bit 3\:16-bit))' \
+  '-m[interpret SSML markup, ignore other XML]' \
+  '(-a -g -p -s -v -w -z --split --stdout)-q[quiet, no sound output]' \
+  '(-x --ipa)-x[output phoneme mnemonics]' \
+  '(-X --ipa)-X[output phoneme mnemonics and translation trace]' \
+  '(-q)-z[suppress final sentence pause at the end of the text]' \
+  '--compile=-[compile pronunciation rules and dictionary]::voicename or debug' \
+  '(-x -X)--ipa=-[output phonemes using International Phonetic Alphabet]::options:((1\:use\ ties 2\:use\ ZWJ 3\:separate\ with\ _))' \
+  '--path=[specify espeak-data path]:path:_files -/' \
+  '--pho[output mbrola phoneme data]' \
+  '--phonout=[output filename for -x/-X/--ipa]:filename:_files' \
+  '--punct=-[speak names of punctuation characters]::characters' \
+  '(-q --stdout)--split=[periodically start new wav file]:period (minutes)' \
+  '(-w -q --split)--stdout[output speech to stdout]' \
+  '--voices=-[list available voices]::language code:->languages' \
+  '(-)'{-h,--help}'[display help information]' \
+  '(-)--version[display version information]' && ret=0
+
+case $state in
+  voices)
+    _wanted voices expl voice compadd \
+        ${${${(f)"$(_call_program voices $words[1] --voices)"}[2,-1]#?(#c22)}%% *} && ret=0
+  ;;
+  languages)
+    _wanted languages expl language compadd \
+        ${${${(f)"$(_call_program voices $words[1] --voices)"}[2,-1]#?(#c4)}%% *} && ret=0
+  ;;
+esac
+
+return ret
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index 8d3bd63..2178b82 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -1353,6 +1353,7 @@ _git-push () {
     '(--no-signed --sign)--signed[GPG sign the push]' \
     "(--sign --signed)--no-signed[don't GPG sign the push]" \
     '--atomic[request atomic transaction on remote side]' \
+    '(-o --push-option)'{-o+,--push-option=}'[transmit string to server to pass to pre/post-receive hooks]:string' \
     '(-4 --ipv4 -6 --ipv6)'{-4,--ipv4}'[use IPv4 addresses only]' \
     '(-4 --ipv4 -6 --ipv6)'{-6,--ipv6}'[use IPv6 addresses only]' \
     ': :__git_any_repositories' \
@@ -1767,6 +1768,7 @@ _git-submodule () {
 	    '(--merge --rebase)--checkout[checkout commit recorded in the superproject in the submodule on a detached HEAD]' \
 	    '(--checkout --rebase)--merge[merge commit recorded in superproject into current branch of submodule]' \
 	    '(--checkout --merge)--rebase[rebase current branch onto commit recorded in superproject]' \
+	    '--no-recommend-shallow[ignore submodule.<name>.shallow from .gitmodules]' \
             '--reference=[remote repository to clone]: :__git_any_repositories' \
             '--recursive[traverse submodules recursively]' \
             '--remote[use the status of the submodule''s remote-tracking branch]' \
@@ -1968,6 +1970,8 @@ _git-worktree() {
         add:'create a new working tree'
         prune:'prune working tree information'
         list:'list details of each worktree'
+	lock:'prevent a working tree from being pruned'
+	unlock:'allow working tree to be pruned, moved or deleted'
       )
 
       _describe -t commands command commands && ret=0
@@ -1986,6 +1990,7 @@ _git-worktree() {
 	    '(-B --detach)-b+[create a new branch]: :__git_branch_names' \
 	    '(-b --detach)-B+[create or reset a branch]: :__git_branch_names' \
 	    '(-b -B)--detach[detach HEAD at named commit]' \
+	    '--no-checkout[suppress file checkout in new worktree]' \
 	    ':path:_files' $args && ret=0
 	;;
         (prune)
@@ -1997,6 +2002,14 @@ _git-worktree() {
         (list)
 	  _arguments '--porcelain[machine-readable output]' && ret=0
 	;;
+	(lock)
+	  _arguments -C '--reason=[specify reason for locking]:reason' ': :->worktrees' && ret=0
+	  [[ -z $state ]] && return ret
+	;&
+	(unlock)
+	  _wanted directories expl 'working tree' compadd -S ' ' -f -M 'r:|/=* r:|=*' \
+	      ${${(M)${(f)"$(_call_program directories git worktree list --porcelain)"}:#worktree*}#* }
+	;;
       esac
     ;;
   esac
@@ -3539,8 +3552,8 @@ _git-remote () {
 _git-repack () {
   # TODO: --quiet is undocumented.
   _arguments -s \
-    '(-A)-a[pack all objects into a single pack]' \
-    '(-a)-A[pack all objects into a single pack, but unreachable objects become loose]' \
+    '(-A --unpack-unreachable)-a[pack all objects into a single pack]' \
+    '(-a -k --keep-unreachable)-A[pack all objects into a single pack, but unreachable objects become loose]' \
     '-d[remove redundant packs after packing]' \
     "--unpack-unreachable=[with -A, don't loosen objects older than specified date]:date" \
     '-f[pass --no-reuse-delta option to git pack-objects]' \
@@ -3550,6 +3563,7 @@ _git-repack () {
     '(-l --local)'{-l,--local}'[pass --local option to git pack-objects]' \
     '(-b --write-bitmap-index)'{-b,--write-bitmap-index}'[write a bitmap index]' \
     "--unpack-unreachable=[with -A, don't loosen objects older than specified time]:time" \
+    '(-k --keep-unreachable)'{-k,--keep-unreachable}'[with -a, repack unreachable objects]' \
     '--window=[number of objects to consider when doing delta compression]:number of objects' \
     '--window-memory=[scale window size dynamically to not use more than specified amount of memory]: : __git_guard_bytes' \
     '--depth=[maximum delta depth]:maximum delta depth' \
@@ -3678,6 +3692,7 @@ _git-fsck () {
     '(-v --verbose)'{-v,--verbose}'[output additional information]' \
     '--lost-found[write dangling objects into .git/lost-found]' \
     '--progress[show progress]' \
+    '--name-objects[show verbose names for reachable objects]' \
     '*: :__git_objects'
 }
 
@@ -4548,6 +4563,7 @@ _git-pack-objects () {
     '(: --max-pack-size)--stdout[output pack to stdout]' \
     '--include-tag[include unasked-for annotated tags if object they reference is included]' \
     '(--unpack-unreachable)--keep-unreachable[keep unreachable ]' \
+    '--pack-loose-unreachable[pack loose unreachable objects]' \
     '(--keep-unreachable)--unpack-unreachable=-[unpack unreachable objects newer than specified time]::time' \
     '--include-tag[include tag objects that refer to objects to be packed]' \
     $thin_opt \
@@ -5205,12 +5221,11 @@ _git-upload-archive () {
 
 (( $+functions[_git-upload-pack] )) ||
 _git-upload-pack () {
-  # TODO: --advertise-refs is undocumented.
-  # TODO: --stateless-rpc is undocumented.
   _arguments -S -A '-*' \
+    '--stateless-rpc[quit after a single request/response exchange]' \
+    '--advertise-refs[exit immediately after initial ref advertisement]' \
     "--strict[don't try <directory>/.git/ if <directory> is not a git directory]" \
-    '--timeout=-[interrupt transfer after given number of seconds of inactivity]: :__git_guard_number "inactivity timeout"' \
-    --advertise-refs --stateless-rpc \
+    '--timeout=-[interrupt transfer after period of inactivity]: :__git_guard_number "inactivity timeout (seconds)"' \
     ': :_directories'
 }
 
diff --git a/Completion/Unix/Command/_look b/Completion/Unix/Command/_look
index 24a016a..be8cf8c 100644
--- a/Completion/Unix/Command/_look
+++ b/Completion/Unix/Command/_look
@@ -1,16 +1,34 @@
 #compdef look
 
-local curcontext="$curcontext" state line expl ret=1
+local curcontext="$curcontext" state line expl args sep='+' ret=1
 typeset -A opt_args
 
-_arguments -C -s \
-  '-t+[termination character]:termination character:' \
-  '-f[case insensitive]' \
-  '-d[dictionary order]' \
-  ':string:->string' \
-  ':dictionary file:_files' && ret=0
+case $OSTYPE in
+  linux*)
+    args=(
+      '(2 -a --alternative)'{-a,--alternative}'[use alternative dictionary file]'
+      '(-d --alphanum)'{-d,--alphanum}'[dictionary order]'
+      '(-f --ignore-case)'{-f,--ignore-case}'[case insensitive]'
+      '(-t --terminate)'{-t+,--terminate=}'[specify termination character]:termination character'
+      '(-)'{-h,--help}'[display help information]'
+      '(-)'{-V,--version}'[display version information]'
+    )
+  ;;
+  solaris*) sep='-' ;&
+  *)
+    args=( -A "-*"
+      "-t${sep}[specify termination character]:termination character"
+      '-f[case insensitive]'
+      '-d[dictionary order]'
+    )
+  ;;
+esac
+
+_arguments -C -s -S $args \
+  '1:string:->string' \
+  '2:dictionary file:_files' && ret=0
 
 [[ -n "$state" && ! -prefix - ]] && _wanted values expl 'word prefix' \
-    compadd - $(_call_program words $words[1] '"$PREFIX"' 2>/dev/null) && return
+    compadd - $(_call_program words $words[1] '"$PREFIX"') && return
 
 return ret
diff --git a/Completion/Unix/Command/_md5sum b/Completion/Unix/Command/_md5sum
index c881a4e..073e6be 100644
--- a/Completion/Unix/Command/_md5sum
+++ b/Completion/Unix/Command/_md5sum
@@ -5,10 +5,11 @@ _arguments -S \
   '(-c --check)'{-c,--check}'[read MD5 sums from the FILEs and check them]' \
   '--tag[create a BSD-style checksum]' \
   '(-t --text)'{-t,--text}'[read in text mode]' \
+  "--ignore-missing[don't fail or report status for missing files]" \
   '(-q --quiet)'{-q,--quiet}"[don't print OK for each successfully verified file]" \
   '--status[no output, status code shows success]' \
   '--strict[exit non-zero for improperly formatted checksum lines]' \
   '(-w --warn)'{-w,--warn}'[warn about improperly formatted checksum lines]' \
-  '--help[display help and exit]' \
-  '--version[output version information and exit]' \
+  '(-)--help[display help and exit]' \
+  '(-)--version[output version information and exit]' \
   '*:files:_files'
diff --git a/Completion/Unix/Command/_patch b/Completion/Unix/Command/_patch
index c0df00c..c2725d4 100644
--- a/Completion/Unix/Command/_patch
+++ b/Completion/Unix/Command/_patch
@@ -9,8 +9,7 @@ if (( ! $+_patch_args )); then
   [[ "$help" = *--[^h]* || "$help" = *\[-c\|-e\|-n\]* ]] && arg=+
 
   optionmap=(
-    '*\[-p\[strip-count\]\]*' '(--strip)-p-[number of path prefix components to strip]:number of path prefix components to strip:'"{$comp_p}"
-    '*( -p NUM[, ]|\[-p num\])*' '(--strip)-p+[number of path prefix components to strip]:number of path prefix components to strip:'"{$comp_p}"
+    '*( -p NUM[, ]|\[-p (num|strip-count)\])*' '(--strip)-p+[number of path prefix components to strip]:number of path prefix components to strip:'"{$comp_p}"
     '*\[--strip\[=strip-count\]\]*' '(-p)--strip=-[number of path prefix components to strip]:number of path prefix components to strip:'"{$comp_p}"
     '* --strip=NUM[, ]*' '(-p)--strip=[number of path prefix components to strip]:number of path prefix components to strip:'"{$comp_p}"
 
@@ -35,8 +34,8 @@ if (( ! $+_patch_args )); then
     '*(\[-[a-zA-Z]#R[a-zA-Z]#\]| -R[, ])*' '(--reverse)-R[reverse mode]'
     '*(\[--reverse\]| --reverse[, ])*' '(-R)--reverse[reverse mode]'
 
-    '*(\[-i patchfile\]| -i PATCHFILE[, ])*' '(--input)-i+[patch file]:patch file:_files'
-    '* --input=PATCHFILE[, ]*' '(-i)--input=[patch file]:patch file:_files'
+    '*(\[-i patchfile\]| -i PATCHFILE[, ])*' '*-i+[specify input patch file]:patch file:_files'
+    '* --input=PATCHFILE[, ]*' '*--input=[specify input patch file]:patch file:_files'
 
     '*(\[-o out-file\]| -o FILE[, ]|\[-o outfile\])*' "(--output)-o${arg}[output file]:output file:_files"
     '*(\[--output=out-file\]| --output=FILE[, ])*' '(-o)--output=[output file]:output file:_files'
@@ -46,6 +45,8 @@ if (( ! $+_patch_args )); then
     '*(\[-D symbol\]| -D NAME[, ]|\[-D define\])*' '(--ifdef)-D+[cpp symbol]:symbol:'
     '*(\[--ifdef=symbol\]| --ifdef=NAME[, ])*' '(-D)--ifdef=[cpp symbol]:symbol:'
 
+    '* --merge*' '(--reject-file --reject-format -r)--merge[merge using conflict markers instead of creating reject files]'
+
     '*(\[-[a-zA-Z]#E[a-zA-Z]#\]| -E[, ])*' '(--remove-empty-files)-E[remove empty files]'
     '*(\[--remove-empty-files\]| --remove-empty-files[, ])*' '(-E)--remove-empty-files[remove empty files]'
 
@@ -62,6 +63,7 @@ if (( ! $+_patch_args )); then
     '* --no-backup-if-mismatch[, ]*' '(--backup-if-mismatch)--no-backup-if-mismatch[back up only if otherwise requested]'
 
     '*(\[-V {numbered,existing,simple}\]| -V STYLE[, ])*' "(--version-control)-V${arg}[backup method]:backup method:(numbered existing simple)"
+    '*\[-V t \| nil \| never\]*' '(-B)-V+[specify backup method]:backup method:((t\:numbered nil\:existing never\:simple))'
     '*(\[--version-control={numbered,existing,simple}\]| --version-control=STYLE[, ])*' '(-V)--version-control=[backup method]:backup method:(numbered existing simple)'
 
     '*(\[-B backup-prefix\]| -B PREFIX[, ])*' "(--prefix)-B${arg}[specify backup prefix]:backup prefix:"
@@ -69,6 +71,7 @@ if (( ! $+_patch_args )); then
     '* -Y PREFIX[, ]*' '(--basename-prefix)-Y+[specify backup basename prefix]:backup basename prefix:'
     '* --basename-prefix=PREFIX[, ]*' '(-Y)--basename-prefix=[specify backup basename prefix]:backup basename prefix:'
     '*\[-b backup-ext\]*'                              "(   -z --suffix)-b${arg}[specify backup suffix]:backup suffix:(.bak)"
+    '*\[-z backup-ext\]*' '(--suffix)-z+[specify backup suffix]:backup suffix [.orig]:(.bak)'
     '* -z SUFFIX[, ]*'                                 '(-b    --suffix)-z+[specify backup suffix]:backup suffix:(.bak)'
     '*(\[--suffix=backup-ext\]| --suffix=SUFFIX[, ])*' '(-b -z         )--suffix=[specify backup suffix]:backup suffix:(.bak)'
 
@@ -90,24 +93,28 @@ if (( ! $+_patch_args )); then
     '*(\[--silent\]|--silent[, ])*'        '(-s --quiet         )--silent[silent mode]'
 
     '* --verbose[, ]*' '--verbose[verbose mode]'
-    '* --dry-run[, ]*' '--dry-run[don'\''t actually change files]'
-    '* --posix[, ]*' '--posix[POSIX mode]'
+
+    '*(\[-[a-zA-Z]#C[a-zA-Z]#\])*' '(--check)-C[only check that the patch would apply cleanly]'
+    '*\[--check\]*' '(-C)--check[only check that the patch would apply cleanly]'
+    '* --dry-run[, ]*' '--dry-run[only check that the patch would apply cleanly]'
+
+    '*--posix*' '--posix[POSIX mode]'
 
     '*(\[-d directory\]| -d DIR[, ]|\[-d dir\])*' '(--directory)-d+[change the working directory]:chdir to:_files -/'
     '*(\[--directory=directory\]| --directory=DIR[, ])*' '(-d)--directory=[change the working directory]:chdir to:_files -/'
 
+    '* --reject-format=*' '--reject-format=[specify format of rejects]:format:(context unified)'
+    '* --read-only=*' '--read-only=[specify how to handle read-only input files]:behaviour [warn]: (ignore warn fail)'
+
     '* --binary[, ]*' '--binary[binary mode]'
 
-    '*(\[-[a-zA-Z]#v[a-zA-Z]#\]| -v[, ])*' '(--version)-v[print version]'
-    '*(\[--version\]| --version[, ])*' '(-v)--version[print version]'
-    '* --help[, ]*' '--help[print help message]'
+    '*(\[-[a-zA-Z]#v[a-zA-Z]#\]| -v[, ])*' '(-)-v[print version]'
+    '*(\[--version\]| --version[, ])*' '(-)--version[print version]'
+    '* --help[, ]*' '(-)--help[print help message]'
 
     '*\[-[a-zA-Z]#S[a-zA-Z]#\]*' '*-S[ignore this patch]'
     '*\[--skip\]*' '*--skip[ignore this patch]'
 
-    '*(\[-[a-zA-Z]#C[a-zA-Z]#\])*' '(--check)-C[check only]'
-    '*\[--check\]*' '(-C)--check[check only]'
-
     '*\[--index-first\]*' '--index-first[take Index: line precedence]'
 
     '* --use-index-line *' '--use-index-line[deal with Index: line]'
diff --git a/Completion/Unix/Command/_prove b/Completion/Unix/Command/_prove
index 1f21423..17b48a5 100644
--- a/Completion/Unix/Command/_prove
+++ b/Completion/Unix/Command/_prove
@@ -7,7 +7,7 @@
 _arguments \
   '(- *)'{-h,--help}'[display help and exit]' \
   '(- *)'{-H,--man}'[display longer help and exit]' \
-  '(- *)--version[display version and exit]' \
+  '(- *)'{-V,--version}'[display version and exit]' \
   '(--quiet -q -Q --QUIET)'{-v,--verbose}'[print all test lines]' \
   {-l,--lib}'[add lib to path]' \
   {-b,--blib}'[add blib to path]' \
diff --git a/Completion/Unix/Command/_tin b/Completion/Unix/Command/_tin
index c63ccd9..61d203d 100644
--- a/Completion/Unix/Command/_tin
+++ b/Completion/Unix/Command/_tin
@@ -3,6 +3,8 @@
 local newshosts expl state line curcontext="$curcontext" ret=1
 
 _arguments -C -s \
+  '(-6)-4[force connecting via IPv4]' \
+  '(-4)-6[force connecting via IPv6]' \
   '-a[toggle color flag]' \
   '-A[force authentication on connect]' \
   '-c[mark all news as read in subscribed groups]' \


^ permalink raw reply	[relevance 8%]

* [PATCH] Fix ENV handling in sh/ksh emulation
@ 2016-09-03 21:06  3% Teubel György
  0 siblings, 0 replies; 200+ results
From: Teubel György @ 2016-09-03 21:06 UTC (permalink / raw)
  To: zsh-workers

At sh/ksh emulation the value of the ENV parameter is stored
before sourcing ~/.profile.  Hence setting the ENV parameter
in ~/.profile has no effect.

Additionally the ENV is sourced regardless of the interactive state of
the shell.  POSIX standard says that the ENV should be sourced
when and only when an interactive shell is invoked.
---
 Doc/Zsh/params.yo |  3 ++-
 Src/init.c        | 25 ++++++++++++++-----------
 2 files changed, 16 insertions(+), 12 deletions(-)

diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 55930ed..03625ce 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -1059,7 +1059,8 @@ If the tt(ENV) environment variable is set when zsh is invoked as tt(sh)
 or tt(ksh), tt($ENV) is sourced after the profile scripts.  The value of
 tt(ENV) is subjected to parameter expansion, command substitution, and
 arithmetic expansion before being interpreted as a pathname.  Note that
-tt(ENV) is em(not) used unless zsh is emulating bf(sh) or bf(ksh).
+tt(ENV) is em(not) used unless the shell is interactive and zsh is
+emulating bf(sh) or bf(ksh).
 )
 vindex(FCEDIT)
 item(tt(FCEDIT))(
diff --git a/Src/init.c b/Src/init.c
index 20a07eb..3dea179 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -712,7 +712,7 @@ init_term(void)
     if (tgetent(termbuf, term) != TGETENT_SUCCESS)
 #endif
     {
-	if (isset(INTERACTIVE))
+	if (interact)
 	    zerr("can't find terminal definition for %s", term);
 	errflag &= ~ERRFLAG_ERROR;
 	termflags |= TERM_BAD;
@@ -1205,19 +1205,22 @@ run_init_scripts(void)
 	if (islogin)
 	    source("/etc/profile");
 	if (unset(PRIVILEGED)) {
-	    char *s = getsparam("ENV");
 	    if (islogin)
 		sourcehome(".profile");
-	    noerrs = 2;
-	    if (s) {
-		s = dupstring(s);
-		if (!parsestr(&s)) {
-		    singsub(&s);
-		    noerrs = 0;
-		    source(s);
+
+	    if (interact) {
+		noerrs = 2;
+		char *s = getsparam("ENV");
+		if (s) {
+		    s = dupstring(s);
+		    if (!parsestr(&s)) {
+			singsub(&s);
+			noerrs = 0;
+			source(s);
+		    }
 		}
+		noerrs = 0;
 	    }
-	    noerrs = 0;
 	} else
 	    source("/etc/suid_profile");
     } else {
@@ -1227,7 +1230,7 @@ run_init_scripts(void)
 
 	if (isset(RCS) && unset(PRIVILEGED))
 	{
-	    if (isset(INTERACTIVE)) {
+	    if (interact) {
 		/*
 		 * Always attempt to load the newuser module to perform
 		 * checks for new zsh users.  Don't care if we can't load it.
-- 
2.9.3


^ permalink raw reply	[relevance 3%]

* [PATCH] Add zsh/re2 module with conditions
@ 2016-09-08  4:15  8% Phil Pennock
  0 siblings, 0 replies; 200+ results
From: Phil Pennock @ 2016-09-08  4:15 UTC (permalink / raw)
  To: zsh-workers

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

Folks,

I tend to get automatically kicked off the -workers list by ezmlm
because I reject mails which are self-declared as spam, so please CC
replies to me.  Also: my commit-bit is currently
surrended-for-safekeeping because I've not been doing much with Zsh, so
someone else will need to merge this, if it's accepted.

RE2 is a regular expression library, written in C++, from Google.  It
offers most of the features of PCRE, excluding those which can't be
handled without backtracking.  It's BSD-licensed.  This patch adds the
zsh/re2 module.  It used the `cre` library to have C-language bindings.

At this point, I haven't done anything about rebinding =~ to handle
this.  It's purely new infix-operators based on words.  I'm thinking
perhaps something along the lines of $zsh_reop_modules=(regex), with
`setopt rematch_pcre` becoming a compatibility interface that acts as
though `pcre` were prepended to that list and

  zsh_reop_modules=(pcre regex)

having the same effect.  Then I could use `zsh_reop_modules=(re2 regex)`.
Does this seem sane?  Anyone have better suggestions?  I do want to have
=~ able to use this module, but the current work stands alone and should
be merge-able as-is.

Is there particular interest in having command-forms too?  There's no
"study" concept, but I suppose compiling a hairy regexp only once might
be good in some situations (but why use shell for those?)

This has been tested on MacOS 10.10.5.

My ulterior motive is that I want "better than zsh/regex" available by
default on MacOS, where Apple build without GPL modules for the system
Zsh.  I hope that by offering this option, Apple's engineers might
incorporate this one day and I can be happier. :)

I've also pushed this code to a GitHub repo, philpennock/zsh-code on the
re2 branch: https://github.com/philpennock/zsh-code/tree/re2

Tested with re2 20160901 installed via Brew, cre2 installed via:

    git clone https://github.com/marcomaggi/cre2
    cd cre2
      LIBTOOLIZE=glibtoolize sh ./autogen.sh
      CXX=g++-6 CC=gcc-6 ./configure --prefix=/opt/regexps
      make doc/stamp-vti
      make
      make install

and Zsh configured with:

    CPPFLAGS=-I/opt/regexps/include LDFLAGS=-L/opt/regexps/lib \
      ./configure --prefix=/opt/zsh-devel --enable-pcre --enable-re2 \
         --enable-cap --enable-multibyte --enable-zsh-secure-free \
         --with-tcsetpgrp --enable-etcdir=/etc

Feedback welcome.
(Oh, I can't spell "tough", it seems; deferring fix for now).

Regards,
-Phil

----------------------------8< git patch >8-----------------------------
Add support for Google's BSD-licensed RE2 library, via the cre
C-language bindings (also BSD-licensed).

Guard with --enable-re2 for now.

Adds 4 infix conditions.  Currently no commands, no support for changing
how =~ binds.

Includes tests & docs
---
 Doc/Makefile.in     |   2 +-
 Doc/Zsh/mod_re2.yo  |  65 +++++++++++
 INSTALL             |   8 ++
 Src/Modules/re2.c   | 324 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 Src/Modules/re2.mdd |   5 +
 Test/V11re2.ztst    | 170 +++++++++++++++++++++++++++
 configure.ac        |  14 +++
 7 files changed, 587 insertions(+), 1 deletion(-)
 create mode 100644 Doc/Zsh/mod_re2.yo
 create mode 100644 Src/Modules/re2.c
 create mode 100644 Src/Modules/re2.mdd
 create mode 100644 Test/V11re2.ztst

diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 2752096..8c00876 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -65,7 +65,7 @@ Zsh/mod_datetime.yo Zsh/mod_db_gdbm.yo Zsh/mod_deltochar.yo \
 Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_langinfo.yo \
 Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_newuser.yo \
 Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
-Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
+Zsh/mod_re2.yo Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
 Zsh/mod_stat.yo  Zsh/mod_system.yo Zsh/mod_tcp.yo \
 Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
 Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
diff --git a/Doc/Zsh/mod_re2.yo b/Doc/Zsh/mod_re2.yo
new file mode 100644
index 0000000..5527440
--- /dev/null
+++ b/Doc/Zsh/mod_re2.yo
@@ -0,0 +1,65 @@
+COMMENT(!MOD!zsh/re2
+Interface to the RE2 regular expression library.
+!MOD!)
+cindex(regular expressions)
+cindex(re2)
+The tt(zsh/re2) module makes available the following test conditions:
+
+startitem()
+findex(re2-match)
+item(var(expr) tt(-re2-match) var(regex))(
+Matches a string against an RE2 regular expression.
+On successful match,
+matched portion of the string will normally be placed in the tt(MATCH)
+variable.  If there are any capturing parentheses within the regex, then
+the tt(match) array variable will contain those.
+If the match is not successful, then the variables will not be altered.
+
+In addition, the tt(MBEGIN) and tt(MEND) variables are updated to point
+to the offsets within var(expr) for the beginning and end of the matched
+text, with the tt(mbegin) and tt(mend) arrays holding the beginning and
+end of each substring matched.
+
+If tt(BASH_REMATCH) is set, then the array tt(BASH_REMATCH) will be set
+instead of all of the other variables.
+
+Canonical documentation for this syntax accepted by this regular expression
+engine can be found at:
+uref(https://github.com/google/re2/wiki/Syntax)
+)
+enditem()
+
+startitem()
+findex(re2-match-posix)
+item(var(expr) tt(-re2-match-posix) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax.
+)
+enditem()
+
+startitem()
+findex(re2-match-posixperl)
+item(var(expr) tt(-re2-match-posixperl) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax, with the Perl classes and word-boundary extensions re-enabled
+too.
+
+This thus adds support for:
+tt(\d), tt(\s), tt(\w), tt(\D), tt(\S), tt(\W), tt(\b), and tt(\B).
+)
+enditem()
+
+startitem()
+findex(re2-match-longest)
+item(var(expr) tt(-re2-match-longest) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to find
+the longest match, instead of the left-most.
+
+For example, given
+
+example([[ abb -re2-match-longest ^a+LPAR()b|bb+RPAR() ]])
+
+This will match the right-branch, thus tt(abb), where tt(-re2-match) would
+instead match only tt(ab).
+)
+enditem()
diff --git a/INSTALL b/INSTALL
index 99895bd..887dd8e 100644
--- a/INSTALL
+++ b/INSTALL
@@ -558,6 +558,14 @@ only be searched for if the option --enable-pcre is passed to configure.
 
 (Future versions of the shell may have a better fix for this problem.)
 
+--enable-re2:
+
+The RE2 library is written in C++, so a C-library shim layer is needed for
+use by Zsh.  We use https://github.com/marcomaggi/cre2 for this, which is
+currently at version 0.3.1.  Both re2 and cre2 need to be installed for
+this option to successfully enable the zsh/re2 module.  The Zsh
+functionality is currently experimental.
+
 --enable-cap:
 
 This searches for POSIX capabilities; if found, the `cap' library
diff --git a/Src/Modules/re2.c b/Src/Modules/re2.c
new file mode 100644
index 0000000..e542723
--- /dev/null
+++ b/Src/Modules/re2.c
@@ -0,0 +1,324 @@
+/*
+ * re2.c
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2016 Phil Pennock
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Phil Pennock or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Phil Pennock and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Phil Pennock and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Phil Pennock and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+/* This is heavily based upon my earlier regex module, with Peter's fixes
+ * for the tought stuff I had skipped / gotten wrong. */
+
+#include "re2.mdh"
+#include "re2.pro"
+
+/*
+ * re2 itself is a C++ library; zsh needs C language bindings.
+ * These come from <https://github.com/marcomaggi/cre2>.
+ */
+#include <cre2.h>
+
+/* the conditions we support */
+#define ZRE2_COND_RE2		0
+#define ZRE2_COND_POSIX		1
+#define ZRE2_COND_POSIXPERL	2
+#define ZRE2_COND_LONGEST	3
+
+/**/
+static int
+zcond_re2_match(char **a, int id)
+{
+    cre2_regexp_t *rex;
+    cre2_options_t *opt;
+    cre2_string_t *m, *matches = NULL;
+    char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta;
+    char **result_array, **x;
+    char *s;
+    char **mbegin, **mend, **bptr, **eptr;
+    size_t matchessz = 0;
+    int return_value, ncaptures, matched, nelem, start, n, indexing_base;
+    int remaining_len, charlen;
+    zlong offs;
+
+    return_value = 0; /* 1 => matched successfully */
+
+    lhstr_zshmeta = cond_str(a,0,0);
+    rhre_zshmeta = cond_str(a,1,0);
+    lhstr = ztrdup(lhstr_zshmeta);
+    unmetafy(lhstr, NULL);
+    rhre = ztrdup(rhre_zshmeta);
+    unmetafy(rhre, NULL);
+
+    opt = cre2_opt_new();
+    if (!opt) {
+	zwarn("re2 opt memory allocation failure");
+	goto CLEANUP_UNMETAONLY;
+    }
+    /* nb: we can set encoding here; re2 assumes UTF-8 by default */
+    cre2_opt_set_log_errors(opt, 0); /* don't hit stderr by default */
+    if (!isset(CASEMATCH)) {
+	cre2_opt_set_case_sensitive(opt, 0);
+    }
+
+    /* "The following options are only consulted when POSIX syntax is enabled;
+     * when POSIX syntax is disabled: these features are always enabled and
+     * cannot be turned off."
+     * Seems hard to mis-parse, but I did.  Okay, Perl classes \d,\w and friends
+     * always on normally, can _also_ be enabled in POSIX mode. */
+
+    switch (id) {
+    case ZRE2_COND_RE2:
+	/* nothing to do, this is default */
+	break;
+    case ZRE2_COND_POSIX:
+	cre2_opt_set_posix_syntax(opt, 1);
+	break;
+    case ZRE2_COND_POSIXPERL:
+	cre2_opt_set_posix_syntax(opt, 1);
+	/* we enable Perl classes (\d, \s, \w, \D, \S, \W)
+	 * and boundaries/not (\b \B) */
+	cre2_opt_set_perl_classes(opt, 1);
+	cre2_opt_set_word_boundary(opt, 1);
+	break;
+    case ZRE2_COND_LONGEST:
+	cre2_opt_set_longest_match(opt, 1);
+	break;
+    default:
+	DPUTS(1, "bad re2 option");
+	goto CLEANUP_UNMETAONLY;
+    }
+
+    rex = cre2_new(rhre, strlen(rhre), opt);
+    if (!rex) {
+	zwarn("re2 regular expression memory allocation failure");
+	goto CLEANUP_OPT;
+    }
+    if (cre2_error_code(rex)) {
+	zwarn("re2 rexexp compilation failed: %s", cre2_error_string(rex));
+	goto CLEANUP;
+    }
+
+    ncaptures = cre2_num_capturing_groups(rex);
+    /* the nmatch for cre2_match follows the usual pattern of index 0 holding
+     * the entire matched substring, index 1 holding the first capturing
+     * sub-expression, etc.  So we need ncaptures+1 elements. */
+    matchessz = (ncaptures + 1) * sizeof(cre2_string_t);
+    matches = zalloc(matchessz);
+
+    matched = cre2_match(rex,
+			 lhstr, strlen(lhstr), /* text to match against */
+			 0, strlen(lhstr), /* substring of text to consider */
+			 CRE2_UNANCHORED, /* user should explicitly anchor */
+			 matches, (ncaptures+1));
+    if (!matched)
+	goto CLEANUP;
+    return_value = 1;
+
+    /* We have a match, we will return success, we have array of cre2_string_t
+     * items, each with .data and .length fields pointing into the matched text,
+     * all in unmetafied format.
+     *
+     * We need to collect the results, put together various arrays and offset
+     * variables, while respecting options to change the array set, the indexing
+     * of that array and everything else that 26 years of history has endowed
+     * upon us. */
+    /* option BASHREMATCH set:
+     *    set $BASH_REMATCH instead of $MATCH/$match
+     *    entire matched portion in index 0 (useful with option KSH_ARRAYS)
+     * option _not_ set:
+     *    $MATCH scalar gets entire string
+     *    $match array gets substrings
+     *    $MBEGIN $MEND scalars get offsets of entire match
+     *    $mbegin $mend arrays get offsets of substrings
+     *    all of the offsets depend upon KSHARRAYS to determine indexing!
+     */
+
+    if (isset(BASHREMATCH)) {
+	start = 0;
+	nelem = ncaptures + 1;
+    } else {
+	start = 1;
+	nelem = ncaptures;
+    }
+    result_array = NULL;
+    if (nelem) {
+	result_array = x = (char **) zalloc(sizeof(char *) * (nelem + 1));
+	for (m = matches + start, n = start; n <= ncaptures; ++n, ++m, ++x) {
+	    /* .data is (const char *), metafy can modify in-place so takes
+	     * (char *) but doesn't modify given META_DUP, so safe to drop
+	     * the const. */
+	    *x = metafy((char *)m->data, m->length, META_DUP);
+	}
+	*x = NULL;
+    }
+
+    if (isset(BASHREMATCH)) {
+	setaparam("BASH_REMATCH", result_array);
+	goto CLEANUP;
+    }
+
+    indexing_base = isset(KSHARRAYS) ? 0 : 1;
+
+    setsparam("MATCH", metafy((char *)matches[0].data, matches[0].length, META_DUP));
+    /* count characters before the match */
+    s = lhstr;
+    remaining_len = matches[0].data - lhstr;
+    offs = 0;
+    MB_CHARINIT();
+    while (remaining_len) {
+	offs++;
+	charlen = MB_CHARLEN(s, remaining_len);
+	s += charlen;
+	remaining_len -= charlen;
+    }
+    setiparam("MBEGIN", offs + indexing_base);
+    /* then the characters within the match */
+    remaining_len = matches[0].length;
+    while (remaining_len) {
+	offs++;
+	charlen = MB_CHARLEN(s, remaining_len);
+	s += charlen;
+	remaining_len -= charlen;
+    }
+    /* zsh ${foo[a,b]} is inclusive of end-points, [a,b] not [a,b) */
+    setiparam("MEND", offs + indexing_base - 1);
+    if (!nelem) {
+	goto CLEANUP;
+    }
+
+    bptr = mbegin = (char **)zalloc(sizeof(char *)*(nelem+1));
+    eptr = mend = (char **)zalloc(sizeof(char *)*(nelem+1));
+    for (m = matches + start, n = 0;
+	 n < nelem;
+	 ++n, ++m, ++bptr, ++eptr)
+    {
+	char buf[DIGBUFSIZE];
+	if (m->data == NULL) {
+	    /* FIXME: have assumed this is the API for non-matching substrings; confirm! */
+	    *bptr = ztrdup("-1");
+	    *eptr = ztrdup("-1");
+	    continue;
+	}
+	s = lhstr;
+	remaining_len = m->data - lhstr;
+	offs = 0;
+	/* Find the start offset */
+	MB_CHARINIT();
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base, 10);
+	*bptr = ztrdup(buf);
+	/* Continue to the end offset */
+	remaining_len = m->length;
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base - 1, 10);
+	*eptr = ztrdup(buf);
+    }
+    *bptr = *eptr = NULL;
+
+    setaparam("match", result_array);
+    setaparam("mbegin", mbegin);
+    setaparam("mend", mend);
+
+CLEANUP:
+    if (matches)
+	zfree(matches, matchessz);
+    cre2_delete(rex);
+CLEANUP_OPT:
+    cre2_opt_delete(opt);
+CLEANUP_UNMETAONLY:
+    free(lhstr);
+    free(rhre);
+    return return_value;
+}
+
+
+static struct conddef cotab[] = {
+    CONDDEF("re2-match", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_RE2),
+    CONDDEF("re2-match-posix", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIX),
+    CONDDEF("re2-match-posixperl", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIXPERL),
+    CONDDEF("re2-match-longest", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_LONGEST),
+};
+
+
+static struct features module_features = {
+    NULL, 0,
+    cotab, sizeof(cotab)/sizeof(*cotab),
+    NULL, 0,
+    NULL, 0,
+    0
+};
+
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+    *features = featuresarray(m, &module_features);
+    return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+    return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}
diff --git a/Src/Modules/re2.mdd b/Src/Modules/re2.mdd
new file mode 100644
index 0000000..b20838c
--- /dev/null
+++ b/Src/Modules/re2.mdd
@@ -0,0 +1,5 @@
+name=zsh/re2
+link='if test "x$enable_re2" = xyes && test "x$ac_cv_lib_cre2_cre2_version_string" = xyes; then echo dynamic; else echo no; fi'
+load=no
+
+objects="re2.o"
diff --git a/Test/V11re2.ztst b/Test/V11re2.ztst
new file mode 100644
index 0000000..d6e327c
--- /dev/null
+++ b/Test/V11re2.ztst
@@ -0,0 +1,170 @@
+%prep
+
+  if ! zmodload -F zsh/re2 C:re2-match 2>/dev/null
+  then
+    ZTST_unimplemented="the zsh/re2 module is not available"
+    return 0
+  fi
+# Load the rest of the builtins
+  zmodload zsh/re2
+  ##FIXME#setopt rematch_pcre
+# Find a UTF-8 locale.
+  setopt multibyte
+# Don't let LC_* override our choice of locale.
+  unset -m LC_\*
+  mb_ok=
+  langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+	 $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+  for LANG in $langs; do
+    if [[ é = ? ]]; then
+      mb_ok=1
+      break;
+    fi
+  done
+  if [[ -z $mb_ok ]]; then
+    ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
+  else
+    print -u $ZTST_fd Testing RE2 multibyte with locale $LANG
+    mkdir multibyte.tmp && cd multibyte.tmp
+  fi
+
+%test
+
+  [[ 'foo→bar' -re2-match .([^[:ascii:]]). ]]
+  print $MATCH
+  print $match[1]
+0:Basic non-ASCII regexp matching
+>o→b
+>→
+
+  [[ alphabeta -re2-match a([^a]+)a ]]
+  echo "$? basic"
+  print $MATCH
+  print $match[1]
+  [[ ! alphabeta -re2-match a(.+)a ]]
+  echo "$? negated op"
+  [[ alphabeta -re2-match ^b ]]
+  echo "$? failed match"
+# default matches on first, then takes longest substring
+# -longest keeps looking
+  [[ abb -re2-match a(b|bb) ]]
+  echo "$? first .${MATCH}.${match[1]}."
+  [[ abb -re2-match-longest a(b|bb) ]]
+  echo "$? longest .${MATCH}.${match[1]}."
+  [[ alphabeta -re2-match ab ]]; echo "$? unanchored"
+  [[ alphabeta -re2-match ^ab ]]; echo "$? anchored"
+  [[ alphabeta -re2-match '^a(\w+)a$' ]]
+  echo "$? perl class used"
+  echo ".${MATCH}. .${match[1]}."
+  [[ alphabeta -re2-match-posix '^a(\w+)a$' ]]
+  echo "$? POSIX-mode, should inhibit Perl class"
+  [[ alphabeta -re2-match-posixperl '^a(\w+)a$' ]]
+  echo "$? POSIX-mode with Perl classes enabled .${match[1]}."
+  unset MATCH match
+  [[ alphabeta -re2-match ^a([^a]+)a([^a]+)a$ ]]
+  echo "$? matched, set vars"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+  unset MATCH match
+  [[ alphabeta -re2-match fr(.+)d ]]
+  echo "$? unmatched, not setting MATCH/match"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+0:Basic matching & result codes
+>0 basic
+>alpha
+>lph
+>1 negated op
+>1 failed match
+>0 first .ab.b.
+>0 longest .abb.bb.
+>0 unanchored
+>1 anchored
+>0 perl class used
+>.alphabeta. .lphabet.
+>1 POSIX-mode, should inhibit Perl class
+>0 POSIX-mode with Perl classes enabled .lphabet.
+>0 matched, set vars
+>.alphabeta. 9
+>.lph|bet.
+>1 unmatched, not setting MATCH/match
+>.. 0
+>..
+
+  m() {
+    unset MATCH MBEGIN MEND match mbegin mend
+    [[ $2 -re2-match $3 ]]
+    print $? $1: m:${MATCH}: ma:${(j:|:)match}: MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  }
+  data='alpha beta gamma delta'
+  m uncapturing $data '\b\w+\b'
+  m capturing $data '\b(\w+)\b'
+  m 'capture 2' $data '\b(\w+)\s+(\w+)\b'
+  m 'capture repeat' $data '\b(?:(\w+)\s+)+(\w+)\b'
+0:Beginning and end testing
+>0 uncapturing: m:alpha: ma:: MBEGIN=1 MEND=5 mbegin=() mend=()
+>0 capturing: m:alpha: ma:alpha: MBEGIN=1 MEND=5 mbegin=(1) mend=(5)
+>0 capture 2: m:alpha beta: ma:alpha|beta: MBEGIN=1 MEND=10 mbegin=(1 7) mend=(5 10)
+>0 capture repeat: m:alpha beta gamma delta: ma:gamma|delta: MBEGIN=1 MEND=22 mbegin=(12 18) mend=(16 22)
+
+
+  unset match mend
+  s=$'\u00a0'
+  [[ $s -re2-match '^.$' ]] && print OK
+  [[ A${s}B -re2-match .(.). && $match[1] == $s ]] && print OK
+  [[ A${s}${s}B -re2-match A([^[:ascii:]]*)B && $mend[1] == 3 ]] && print OK
+  unset s
+0:Raw IMETA characters in input string
+>OK
+>OK
+>OK
+
+  [[ foo -re2-match f.+ ]] ; print $?
+  [[ foo -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ ]] ; print $?
+  [[ ! foo -re2-match x.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match f.+ && bar -re2-match b.+ ) ]] ; print $?
+  [[ ! foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match x.+ && bar -re2-match b.+ ) ]] ; print $?
+0:Regex result inversion detection
+>0
+>1
+>1
+>0
+>0
+>1
+>1
+>1
+>1
+>1
+>0
+>1
+>0
+
+# Subshell because crash on failure
+  ( [[ test.txt -re2-match '^(.*_)?(test)' ]]
+    echo $match[2] )
+0:regression for segmentation fault (pcre, dup for re2), workers/38307
+>test
+
+  setopt BASH_REMATCH KSH_ARRAYS
+  unset MATCH MBEGIN MEND match mbegin mend BASH_REMATCH
+  [[ alphabeta -re2-match '^a([^a]+)(a)([^a]+)a$' ]]
+  echo "$? bash_rematch"
+  echo "m:${MATCH}: ma:${(j:|:)match}:"
+  echo MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  echo "BASH_REMATCH=[${(j:, :)BASH_REMATCH[@]}]"
+  echo "[0]=${BASH_REMATCH[0]} [1]=${BASH_REMATCH[1]}"
+0:bash_rematch works
+>0 bash_rematch
+>m:: ma::
+>MBEGIN= MEND= mbegin=() mend=()
+>BASH_REMATCH=[alphabeta, lph, a, bet]
+>[0]=alphabeta [1]=lph
+
diff --git a/configure.ac b/configure.ac
index 0e0bd53..9c23691 100644
--- a/configure.ac
+++ b/configure.ac
@@ -442,6 +442,11 @@ AC_ARG_ENABLE(pcre,
 AC_HELP_STRING([--enable-pcre],
 [enable the search for the pcre library (may create run-time library dependencies)]))
 
+dnl Do you want to look for re2 support?
+AC_ARG_ENABLE(re2,
+AC_HELP_STRING([--enable-re2],
+[enable the search for cre2 C-language bindings and re2 library]))
+
 dnl Do you want to look for capability support?
 AC_ARG_ENABLE(cap,
 AC_HELP_STRING([--enable-cap],
@@ -683,6 +688,15 @@ if test "x$ac_cv_prog_PCRECONF" = xpcre-config; then
 fi
 fi
 
+if test x$enable_re2 = xyes; then
+AC_CHECK_LIB([re2],[main],,
+  [AC_MSG_FAILURE([test for RE2 library failed])])
+AC_CHECK_LIB([cre2],[cre2_version_string],,
+  [AC_MSG_FAILURE([test for CRE2 library failed])])
+AC_CHECK_HEADERS([cre2.h],,
+  [AC_MSG_ERROR([test for RE2 header failed])])
+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 \
-- 
2.10.0


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[relevance 8%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-08 14:31  3%     ` Stephane Chazelas
  2016-09-08 15:06  3%       ` Stephane Chazelas
@ 2016-09-08 15:14  0%       ` Peter Stephenson
  2016-09-08 16:39  3%         ` Mikael Magnusson
  2016-09-09  8:52  3%       ` Stephane Chazelas
  2 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-09-08 15:14 UTC (permalink / raw)
  To: zsh-workers

On Thu, 08 Sep 2016 15:31:28 +0100
Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> 2016-09-08 12:16:28 +0100, Peter Stephenson:
> [...]
> > diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo
> > index 3d369fb..6fcf3bd 100644
> > --- a/Doc/Zsh/cond.yo
> > +++ b/Doc/Zsh/cond.yo
> > @@ -103,8 +103,8 @@ true if var(file1) and var(file2) exist and refer to the same file.
> >  xitem(var(string) tt(=) var(pattern))
> >  item(var(string) tt(==) var(pattern))(
> >  true if var(string) matches var(pattern).
> > -The `tt(==)' form is the preferred one.  The `tt(=)' form is for
> > -backward compatibility and should be considered obsolete.
> > +The `tt(==)' form is the preferred one for clarity in new shell code
> > +as it more closely resembles other languages.
> [...]
> 
> ksh93 also makes "==" obsolete in [[...]]. "==" is still not
> POSIX (and likely not going to be soon as requests to add it
> have been rejected (IIRC)) for the "test"/"[" utility (or expr).

So possibly even saying == is preferred is going a bit far, though
obviously there's no reason ever to remove it...

pws


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-08 15:14  0%       ` Peter Stephenson
@ 2016-09-08 16:39  3%         ` Mikael Magnusson
  2016-09-08 18:47  4%           ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Mikael Magnusson @ 2016-09-08 16:39 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh workers

On Thu, Sep 8, 2016 at 5:14 PM, Peter Stephenson
<p.stephenson@samsung.com> wrote:
> On Thu, 08 Sep 2016 15:31:28 +0100
> Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
>> 2016-09-08 12:16:28 +0100, Peter Stephenson:
>> [...]
>> > diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo
>> > index 3d369fb..6fcf3bd 100644
>> > --- a/Doc/Zsh/cond.yo
>> > +++ b/Doc/Zsh/cond.yo
>> > @@ -103,8 +103,8 @@ true if var(file1) and var(file2) exist and refer to the same file.
>> >  xitem(var(string) tt(=) var(pattern))
>> >  item(var(string) tt(==) var(pattern))(
>> >  true if var(string) matches var(pattern).
>> > -The `tt(==)' form is the preferred one.  The `tt(=)' form is for
>> > -backward compatibility and should be considered obsolete.
>> > +The `tt(==)' form is the preferred one for clarity in new shell code
>> > +as it more closely resembles other languages.
>> [...]
>>
>> ksh93 also makes "==" obsolete in [[...]]. "==" is still not
>> POSIX (and likely not going to be soon as requests to add it
>> have been rejected (IIRC)) for the "test"/"[" utility (or expr).

POSIX doesn't have [[...]] so what it says isn't really relevant. [ a
== b ] doesn't work in zsh by default either, you have to use either [
a = b ] or [ a \== b ] and obviously the latter is pretty ridiculous.
:)

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-08 16:39  3%         ` Mikael Magnusson
@ 2016-09-08 18:47  4%           ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2016-09-08 18:47 UTC (permalink / raw)
  To: zsh-workers

2016-09-08 18:39:55 +0200, Mikael Magnusson:
[...]
> >> ksh93 also makes "==" obsolete in [[...]]. "==" is still not
> >> POSIX (and likely not going to be soon as requests to add it
> >> have been rejected (IIRC)) for the "test"/"[" utility (or expr).
> 
> POSIX doesn't have [[...]] so what it says isn't really relevant. [ a
> == b ] doesn't work in zsh by default either, you have to use either [
> a = b ] or [ a \== b ] and obviously the latter is pretty ridiculous.
> :)
[...]

I only said "==" was not POSIX *for the "test"/"[" utility (or
expr)*.

It's not relevant to [[...]] except that [[..]] was more or less
the "[" utility moved to a new shell construct to avoid some of
the issues with the interpretation of the arguments of the "["
command (most of which have later been fixed by POSIX).

Now, I agree, given that [ a == b ] doesn't work in zsh when not
in sh emulation, that's one more reason zsh maybe shouldn't
consider [[ a = b ]] as obsolete.

AFAICT, none of mksh, pdksh, yash, bash consider [[ = ]]
obsolete ([ = ] for yash which doesn't have [[ ]]).

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* [PATCH] Add zsh/re2 module with commands & conditions
@ 2016-09-09  1:12  9% Phil Pennock
  0 siblings, 0 replies; 200+ results
From: Phil Pennock @ 2016-09-09  1:12 UTC (permalink / raw)
  To: zsh-workers

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

The below is believed to be solid, guarding hard against the previous
problems and should be good to go.

This is also at:
  <https://github.com/philpennock/zsh-code/tree/re2_cmds>
(and the `re2_raw_wip` branch is the unsquashed progress towards this
 single commit).

----------------------------8< git patch >8-----------------------------

Add support for Google's BSD-licensed RE2 library, via the cre
C-language bindings (also BSD-licensed).

Guard with --enable-re2 for now.

Adds 4 infix conditions and two commands, but not yet any support for
changing how =~ binds.

Includes docs and many many tests.

Includes guard against a cre2 library unusable in practice, which bit
with hard errors (C++ linkage problems with different compilers).

The commands are re2_compile and re2_match; they're feature-complete in
what they have, but there's a TODO to add named-regexps instead of just
one anonymous regexp preserved between them.  (That functionality would
be well suited for the other regexp engines too).  I left the framework
in, so that people can see where it would go and either say "sure, go
for it" or "er, no".  (Includes Yodl comments in the docs).

There's no "multiline" support for changing the ^...$ matching on
newlines vs start/end of text, as I couldn't get it working (and the
cre2 docs describe the opposite of every other regexp engine and the RE2
docs).
---
 Doc/Makefile.in     |   2 +-
 Doc/Zsh/mod_re2.yo  | 126 +++++++++++
 INSTALL             |  13 ++
 Src/Modules/re2.c   | 585 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 Src/Modules/re2.mdd |   7 +
 Test/V11re2.ztst    | 317 ++++++++++++++++++++++++++++
 configure.ac        |  42 ++++
 7 files changed, 1091 insertions(+), 1 deletion(-)
 create mode 100644 Doc/Zsh/mod_re2.yo
 create mode 100644 Src/Modules/re2.c
 create mode 100644 Src/Modules/re2.mdd
 create mode 100644 Test/V11re2.ztst

diff --git a/Doc/Makefile.in b/Doc/Makefile.in
index 2752096..8c00876 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -65,7 +65,7 @@ Zsh/mod_datetime.yo Zsh/mod_db_gdbm.yo Zsh/mod_deltochar.yo \
 Zsh/mod_example.yo Zsh/mod_files.yo Zsh/mod_langinfo.yo \
 Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_newuser.yo \
 Zsh/mod_parameter.yo Zsh/mod_pcre.yo Zsh/mod_private.yo \
-Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
+Zsh/mod_re2.yo Zsh/mod_regex.yo Zsh/mod_sched.yo Zsh/mod_socket.yo \
 Zsh/mod_stat.yo  Zsh/mod_system.yo Zsh/mod_tcp.yo \
 Zsh/mod_termcap.yo Zsh/mod_terminfo.yo \
 Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/mod_zleparameter.yo \
diff --git a/Doc/Zsh/mod_re2.yo b/Doc/Zsh/mod_re2.yo
new file mode 100644
index 0000000..bfabfd1
--- /dev/null
+++ b/Doc/Zsh/mod_re2.yo
@@ -0,0 +1,126 @@
+COMMENT(!MOD!zsh/re2
+Interface to the RE2 regular expression library.
+!MOD!)
+cindex(regular expressions)
+cindex(re2)
+The tt(zsh/re2) module provides regular expression handling using the
+RE2 library.
+This engine assumes UTF-8 strings by default and zsh never disables this.
+Canonical documentation for this syntax accepted by this regular expression
+engine can be found at:
+uref(https://github.com/google/re2/wiki/Syntax)
+
+The tt(zsh/re2) module makes available some commands and test conditions.
+
+Regular expressions can be pre-compiled and given explicit names; these
+are not shell variables and do not share a namespace with them.  There
+is currently no mechanism to enumerate them.
+
+The supported commands are:
+
+startitem()
+findex(re2_compile)
+item(tt(re2_compile) COMMENT(TODO: [ tt(-R) var(NAME) ]) [ tt(-acilwLP) ] var(REGEX))(
+Compiles an RE2-syntax regular expression, defaulting to case-sensitive.
+
+COMMENT(TODO: Option tt(-R) stores the regular expression with the given name,
+instead of in anonymous global state.)
+Option tt(-L) will interpret the pattern as a literal, not a regex.
+Option tt(-P) will enable POSIX syntax instead of the full language.
+Option tt(-a) will force the pattern to be anchored.
+Option tt(-c) will re-enable Perl class support in POSIX mode.
+Option tt(-i) will compile a case-insensitive pattern.
+Option tt(-l) will use a longest-match not first-match algorithm for
+selecting which branch matches.
+Option tt(-w) will re-enable Perl word-boundary support in POSIX mode.
+)
+enditem()
+
+startitem()
+findex(re2_match)
+item(tt(re2_match) [ tt(-v) var(var) ] [ tt(-a) var(arr) ] \
+COMMENT(TODO:[ tt(-R) var(REGNAME) ]|)[ tt(-P) var(PATTERN) ] var(string))(
+Matches a regular expression against the supplied string, storing matches in
+variables.
+Returns success if var(string) matches the tested regular expression.
+
+Without option+COMMENT(TODO: s tt(-R) or) tt(-P) will match against an implicit current regular
+expression object, which must have been compiled with tt(re2_compile).
+COMMENT(TODO: Option tt(-R) will use the regular expression with the given name.)
+Option tt(-P) will take a regular expression as a parameter and compile and
+use it, without changing the implicit current regular expression object as
+set by calling tt(re2_compile).
+
+Without a successful match, no variables are modified, even those explicitly
+specified.
+
+Upon successful match: the entire matched portion of var(string) is stored in
+the var(var) of option tt(-v) if given, else in tt(MATCH); any captured
+sub-expressions are stored in the array var(arr) of option tt(-a) if given,
+else in tt(match).
+
+No offset variables are currently mutated; this may change in a future release
+of Zsh.
+)
+enditem()
+
+The supported test conditions are:
+
+startitem()
+findex(re2-match)
+item(var(expr) tt(-re2-match) var(regex))(
+Matches a string against an RE2 regular expression.
+Upon successful match, the
+matched portion of the string will normally be placed in the tt(MATCH)
+variable.  If there are any capturing parentheses within the regex, then
+the tt(match) array variable will contain those.
+If the match is not successful, then the variables will not be altered.
+
+In addition, the tt(MBEGIN) and tt(MEND) variables are updated to point
+to the offsets within var(expr) for the beginning and end of the matched
+text, with the tt(mbegin) and tt(mend) arrays holding the beginning and
+end of each substring matched.
+
+If tt(BASH_REMATCH) is set, then the array tt(BASH_REMATCH) will be set
+instead of all of the other variables.
+
+The tt(NO_CASE_MATCH) option may be used to make matching case-sensitive.
+
+For finer-grained control, use the tt(re2_match) builtin.
+)
+enditem()
+
+startitem()
+findex(re2-match-posix)
+item(var(expr) tt(-re2-match-posix) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax.
+)
+enditem()
+
+startitem()
+findex(re2-match-posixperl)
+item(var(expr) tt(-re2-match-posixperl) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to use
+POSIX syntax, with the Perl classes and word-boundary extensions re-enabled
+too.
+
+This thus adds support for:
+tt(\d), tt(\s), tt(\w), tt(\D), tt(\S), tt(\W), tt(\b), and tt(\B).
+)
+enditem()
+
+startitem()
+findex(re2-match-longest)
+item(var(expr) tt(-re2-match-longest) var(regex))(
+Matches as per tt(-re2-match) but configuring the RE2 engine to find
+the longest match, instead of the left-most.
+
+For example, given
+
+example([[ abb -re2-match-longest ^a+LPAR()b|bb+RPAR() ]])
+
+This will match the right-branch, thus tt(abb), where tt(-re2-match) would
+instead match only tt(ab).
+)
+enditem()
diff --git a/INSTALL b/INSTALL
index 99895bd..e7f7782 100644
--- a/INSTALL
+++ b/INSTALL
@@ -558,6 +558,19 @@ only be searched for if the option --enable-pcre is passed to configure.
 
 (Future versions of the shell may have a better fix for this problem.)
 
+--enable-re2:
+
+The RE2 library is written in C++, so a C-library shim layer is needed for
+use by Zsh.  We use https://github.com/marcomaggi/cre2 for this, which is
+currently at version 0.3.1.  Both re2 and cre2 need to be installed for
+this option to successfully enable the zsh/re2 module.  The Zsh
+functionality is currently experimental.
+
+Warning: compile cre2 with the same C++ compiler as is used for re2; the
+Zsh developer who wrote this module finds that clang++ for both works
+on MacOS, while g++ runs into various problems.  Once cre2 is built and
+installed, any C compiler can use the shim.
+
 --enable-cap:
 
 This searches for POSIX capabilities; if found, the `cap' library
diff --git a/Src/Modules/re2.c b/Src/Modules/re2.c
new file mode 100644
index 0000000..1d04040
--- /dev/null
+++ b/Src/Modules/re2.c
@@ -0,0 +1,585 @@
+/*
+ * re2.c
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 2016 Phil Pennock
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Phil Pennock or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Phil Pennock and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Phil Pennock and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose.  The software
+ * provided hereunder is on an "as is" basis, and Phil Pennock and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+/* This is heavily based upon my earlier regex module, with Peter's fixes
+ * for the tougher stuff I had skipped / gotten wrong. */
+
+#include "re2.mdh"
+#include "re2.pro"
+
+/*
+ * re2 itself is a C++ library; zsh needs C language bindings.
+ * These come from <https://github.com/marcomaggi/cre2>.
+ */
+#include <cre2.h>
+
+/* the conditions we support */
+#define ZRE2_COND_RE2		0
+#define ZRE2_COND_POSIX		1
+#define ZRE2_COND_POSIXPERL	2
+#define ZRE2_COND_LONGEST	3
+
+struct zcre2_regexp_wrapper {
+    cre2_regexp_t *rex;
+    cre2_anchor_t anchoring;
+
+/* We don't need to keep the cre_options_t* around while the cre2_regexp_t* exists;
+ * from the CRE documentation for the cre2_new() initializer:
+ *
+ * "The options object opt is duplicated in the internal state of the regular
+ * expression instance, so opt can be safely mutated or finalised after this
+ * call. If opt is NULL: the regular expression object is built with the
+ * default set of options." */
+};
+
+/* collect names all the variables which we might set as side-effects;
+ * if name is NULL, do not set it. Inline comments give 'typical' vars */
+struct match_varset {
+    /* bash non-NULL inhibits use of all others */
+    const char *bash; /* BASH_REMATCH */
+    const char *total; /* MATCH */
+    const char *substrings; /* match */
+    const char *offset_start; /* MBEGIN */
+    const char *offset_end; /* MEND */
+    const char *subs_offset_starts; /* mbegin */
+    const char *subs_offset_ends; /* mend */
+};
+
+/* The implicit anonymous regular expression object carried between compile & match */
+static struct zcre2_regexp_wrapper anonymous;
+
+/* TODO: tree of zcre2_regexp_wrapper, for named regexps */
+
+/* returns 1 if matched, 0 if did not match; sets vars as side-effect */
+static int zre2_match_capture(cre2_regexp_t *, cre2_anchor_t,
+			      const char *, size_t, struct match_varset *);
+
+/**/
+static int
+bin_re2_compile(char *nam, char **args, Options ops, UNUSED(int func))
+{
+    struct zcre2_regexp_wrapper *target;
+    cre2_options_t *zre2_opt;
+    cre2_anchor_t anchoring;
+    char *pattern;
+    int return_value = 1;
+
+    zre2_opt = cre2_opt_new();
+    if (!zre2_opt) {
+	zwarnnam(nam, "re2 opt memory allocation failure");
+	return 1;
+    }
+    /* nb: we can set encoding here; re2 assumes UTF-8 by default */
+    cre2_opt_set_log_errors(zre2_opt, 0); /* don't hit stderr by default */
+
+    anchoring = OPT_ISSET(ops,'a') ? CRE2_ANCHOR_BOTH : CRE2_UNANCHORED;
+    if(OPT_ISSET(ops,'L')) cre2_opt_set_literal(zre2_opt, 1);
+    if(OPT_ISSET(ops,'P')) cre2_opt_set_posix_syntax(zre2_opt, 1);
+    if(OPT_ISSET(ops,'c')) cre2_opt_set_perl_classes(zre2_opt, 1);
+    if(OPT_ISSET(ops,'i')) cre2_opt_set_case_sensitive(zre2_opt, 0);
+    if(OPT_ISSET(ops,'l')) cre2_opt_set_longest_match(zre2_opt, 1);
+    if(OPT_ISSET(ops,'w')) cre2_opt_set_word_boundary(zre2_opt, 1);
+
+    /* The cre docs on cre2_opt_set_one_line are misleading led me to believe
+     * that RE2 is doing the opposite of every other regexp engine when it
+     * comes to multiline; the Syntax docs  make clear that RE2's defaults
+     * match every other regexp engine.
+     * I couldn't get cre2_opt_set_one_line() to do anything sane, so for now
+     * we're dropping support for -m/multiline.  A feature for the future. */
+
+    if(OPT_ISSET(ops,'R')) {
+	/* we don't enable R as an option below. */
+	target = /*TODO*/NULL;
+	zwarnnam(nam, "-R unimplemented, TODO");
+	goto CLEANUP_OPT;
+    } else {
+	target = &anonymous;
+    }
+
+    if (target->rex != NULL) {
+	cre2_delete(target->rex);
+	target->rex = NULL;
+    }
+
+    pattern = ztrdup(*args);
+    unmetafy(pattern, NULL);
+
+    target->anchoring = anchoring;
+    target->rex = cre2_new(pattern, strlen(pattern), zre2_opt);
+    if (!target->rex) {
+	zwarnnam(nam, "re2 regexp memory allocation failure");
+	goto CLEANUP_OPT;
+    }
+    if (cre2_error_code(target->rex)) {
+	zwarnnam(nam, "re2 rexexp compilation failed: %s", cre2_error_string(target->rex));
+	cre2_delete(target->rex);
+	target->rex = NULL;
+	goto CLEANUP_OPT;
+    }
+
+    return_value = 0;
+
+CLEANUP_OPT:
+    cre2_opt_delete(zre2_opt);
+    return return_value;
+}
+
+/**/
+static int
+bin_re2_match(char *nam, char **args, Options ops, UNUSED(int func))
+{
+    struct match_varset varnames;
+    struct zcre2_regexp_wrapper short_lived;
+    struct zcre2_regexp_wrapper *zrex;
+    cre2_options_t *zre2_opt;
+    char *pattern, *plaintext;
+    int c, return_value;
+
+    return_value = 1;
+    memset((void *)&varnames, 0, sizeof(varnames));
+    varnames.total = OPT_HASARG(ops,c='v') ? OPT_ARG(ops,c) : "MATCH";
+    varnames.substrings = OPT_HASARG(ops,c='a') ? OPT_ARG(ops,c) : "match";
+
+    short_lived.rex = NULL;
+    if (OPT_HASARG(ops,c='P')) {
+	zrex = &short_lived;
+	zrex->anchoring = CRE2_UNANCHORED;
+	zre2_opt = cre2_opt_new();
+	if (!zre2_opt) {
+	    zwarnnam(nam, "re2 opt memory allocation failure");
+	    return 1;
+	}
+	cre2_opt_set_log_errors(zre2_opt, 0); /* don't hit stderr by default */
+	pattern = ztrdup(OPT_ARG(ops,c));
+	unmetafy(pattern, NULL);
+	zrex->rex = cre2_new(pattern, strlen(pattern), zre2_opt);
+	cre2_opt_delete(zre2_opt);
+	if (!zrex->rex) {
+	    zwarnnam(nam, "re2 regexp memory allocation failure");
+	    return 1;
+	}
+	if (cre2_error_code(zrex->rex)) {
+	    zwarnnam(nam, "re2 rexexp compilation failed: %s", cre2_error_string(zrex->rex));
+	    cre2_delete(zrex->rex);
+	    return 1;
+	}
+    } else if (OPT_HASARG(ops,c='R')) {
+	/*TODO: get the target from the regexp named*/
+	zwarnnam(nam, "-R unimplemented, BUG FIXME XXX");
+	return 1;
+    } else {
+	zrex = &anonymous;
+
+	if (zrex->rex == NULL) {
+	    zwarnnam(nam, "no anonymous re2 object; did you call re2_compile?");
+	    return 1;
+	}
+    }
+
+    plaintext = ztrdup(*args);
+    unmetafy(plaintext, NULL);
+
+    /* beware bool sense */
+    return_value = zre2_match_capture(zrex->rex, zrex->anchoring,
+				      plaintext, strlen(plaintext),
+				      &varnames) ? 0 : 1;
+
+    if (short_lived.rex != NULL) {
+	cre2_delete(short_lived.rex);
+    }
+    return return_value;
+}
+
+/**/
+static int
+zcond_re2_match(char **a, int id)
+{
+    struct match_varset varnames;
+    cre2_regexp_t *rex;
+    cre2_options_t *opt;
+    char *lhstr, *lhstr_zshmeta, *rhre, *rhre_zshmeta;
+    int return_value;
+
+    return_value = 0; /* 1 => matched successfully */
+
+    lhstr_zshmeta = cond_str(a,0,0);
+    rhre_zshmeta = cond_str(a,1,0);
+    lhstr = ztrdup(lhstr_zshmeta);
+    unmetafy(lhstr, NULL);
+    rhre = ztrdup(rhre_zshmeta);
+    unmetafy(rhre, NULL);
+
+    opt = cre2_opt_new();
+    if (!opt) {
+	zwarn("re2 opt memory allocation failure");
+	goto CLEANUP_UNMETAONLY;
+    }
+    /* nb: we can set encoding here; re2 assumes UTF-8 by default */
+    cre2_opt_set_log_errors(opt, 0); /* don't hit stderr by default */
+    if (!isset(CASEMATCH)) {
+	cre2_opt_set_case_sensitive(opt, 0);
+    }
+
+    /* "The following options are only consulted when POSIX syntax is enabled;
+     * when POSIX syntax is disabled: these features are always enabled and
+     * cannot be turned off."
+     * Seems hard to mis-parse, but I did.  Okay, Perl classes \d,\w and friends
+     * always on normally, can _also_ be enabled in POSIX mode. */
+
+    switch (id) {
+    case ZRE2_COND_RE2:
+	/* nothing to do, this is default */
+	break;
+    case ZRE2_COND_POSIX:
+	cre2_opt_set_posix_syntax(opt, 1);
+	break;
+    case ZRE2_COND_POSIXPERL:
+	cre2_opt_set_posix_syntax(opt, 1);
+	/* we enable Perl classes (\d, \s, \w, \D, \S, \W)
+	 * and boundaries/not (\b \B) */
+	cre2_opt_set_perl_classes(opt, 1);
+	cre2_opt_set_word_boundary(opt, 1);
+	break;
+    case ZRE2_COND_LONGEST:
+	cre2_opt_set_longest_match(opt, 1);
+	break;
+    default:
+	DPUTS(1, "bad re2 option");
+	goto CLEANUP_OPT;
+    }
+
+    rex = cre2_new(rhre, strlen(rhre), opt);
+    if (!rex) {
+	zwarn("re2 regular expression memory allocation failure");
+	goto CLEANUP_OPT;
+    }
+    if (cre2_error_code(rex)) {
+	zwarn("re2 rexexp compilation failed: %s", cre2_error_string(rex));
+	goto CLEANUP;
+    }
+
+    memset((void *)&varnames, 0, sizeof(varnames));
+    varnames.bash = isset(BASHREMATCH) ? "BASH_REMATCH" : NULL;
+    varnames.total = "MATCH";
+    varnames.substrings = "match";
+    varnames.offset_start = "MBEGIN";
+    varnames.offset_end = "MEND";
+    varnames.subs_offset_starts = "mbegin";
+    varnames.subs_offset_ends = "mend";
+
+    return_value = zre2_match_capture(rex, CRE2_UNANCHORED,
+				      lhstr, strlen(lhstr),
+				      &varnames);
+
+CLEANUP:
+    cre2_delete(rex);
+CLEANUP_OPT:
+    cre2_opt_delete(opt);
+CLEANUP_UNMETAONLY:
+    free(lhstr);
+    free(rhre);
+    return return_value;
+}
+
+/* This does the matching and capturing logic.
+ * Returns 1 if matched, 0 if did not match; sets vars as side-effect.
+ * Should guard against _any_ varname being NULL, let callers decide
+ * what they want.
+ * If .bash varname non-NULL, _only_ that varname set (because that's the
+ * logic used by the infix-operator; if you need something else, change this
+ * constraint). */
+static int
+zre2_match_capture(
+    cre2_regexp_t *rex,
+    cre2_anchor_t anchoring,
+    const char *plaintext,
+    size_t plain_size,
+    struct match_varset *varnames
+) {
+    cre2_string_t *m, *matches = NULL;
+    char **result_array, **x;
+    const char *s;
+    char **mbegin, **mend, **bptr, **eptr;
+    size_t matchessz = 0;
+    int return_value, ncaptures, matched, nelem, start, n, indexing_base;
+    int remaining_len, charlen;
+    zlong offs;
+
+    if (rex == NULL) {
+	zwarn("BUG: got NULL re2 regexp");
+	return 0;
+    }
+
+    return_value = 0;
+
+    ncaptures = cre2_num_capturing_groups(rex);
+    /* the nmatch for cre2_match follows the usual pattern of index 0 holding
+     * the entire matched substring, index 1 holding the first capturing
+     * sub-expression, etc.  So we need ncaptures+1 elements. */
+    matchessz = (ncaptures + 1) * sizeof(cre2_string_t);
+    matches = zalloc(matchessz);
+
+    matched = cre2_match(rex,
+			 plaintext, plain_size, /* text to match against */
+			 0, plain_size, /* substring of text to consider */
+			 anchoring,
+			 matches, (ncaptures+1));
+    if (!matched)
+	goto CLEANUP;
+    return_value = 1;
+
+    /* We have a match, we will return success, we have array of cre2_string_t
+     * items, each with .data and .length fields pointing into the matched text,
+     * all in unmetafied format.
+     *
+     * We need to collect the results, put together various arrays and offset
+     * variables, while respecting options to change the array set, the indexing
+     * of that array and everything else that 26 years of history has endowed
+     * upon us. */
+    /* For the condition case:
+     * option BASHREMATCH set:
+     *    set $BASH_REMATCH instead of $MATCH/$match
+     *    entire matched portion in index 0 (useful with option KSH_ARRAYS)
+     * option _not_ set:
+     *    $MATCH scalar gets entire string
+     *    $match array gets substrings
+     *    $MBEGIN $MEND scalars get offsets of entire match
+     *    $mbegin $mend arrays get offsets of substrings
+     *    all of the offsets depend upon KSHARRAYS to determine indexing!
+     *
+     * Our caller sets up the varnames bundle, sets ->bash non-NULL only
+     * if option BASHREMATCH set, and we use non-NULL string pointers to
+     * decide whether to set data.
+     */
+
+    if (varnames->bash != NULL) {
+	start = 0;
+	nelem = ncaptures + 1;
+    } else {
+	start = 1;
+	nelem = ncaptures;
+    }
+    result_array = NULL;
+    if (nelem) {
+	result_array = x = (char **) zalloc(sizeof(char *) * (nelem + 1));
+	for (m = matches + start, n = start; n <= ncaptures; ++n, ++m, ++x) {
+	    /* .data is (const char *), metafy can modify in-place so takes
+	     * (char *) but doesn't modify given META_DUP, so safe to drop
+	     * the const. */
+	    *x = metafy((char *)m->data, m->length, META_DUP);
+	}
+	*x = NULL;
+    }
+
+    if (varnames->bash != NULL) {
+	setaparam((char *)varnames->bash, result_array);
+	goto CLEANUP;
+    }
+
+    indexing_base = isset(KSHARRAYS) ? 0 : 1;
+
+    if (varnames->total != NULL) {
+	setsparam((char *)varnames->total /* typically: MATCH */,
+		  metafy((char *)matches[0].data, matches[0].length, META_DUP));
+    }
+
+    if ((varnames->offset_start != NULL) || (varnames->offset_end != NULL)) {
+	/* count characters before the match */
+	s = plaintext;
+	remaining_len = matches[0].data - plaintext;
+	offs = 0;
+	MB_CHARINIT();
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	if (varnames->offset_start != NULL) {
+	    setiparam((char *)varnames->offset_start, /* typically: MBEGIN */
+		      offs + indexing_base);
+	}
+	/* then the characters within the match */
+	remaining_len = matches[0].length;
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	if (varnames->offset_end != NULL) {
+	    /* zsh ${foo[a,b]} is inclusive of end-points, [a,b] not [a,b) */
+	    setiparam((char *)varnames->offset_end, /* typically: MEND */
+		      offs + indexing_base - 1);
+	}
+    }
+
+    if (!ncaptures) {
+	goto CLEANUP;
+    }
+
+    if (varnames->substrings != NULL) {
+	setaparam((char *)varnames->substrings, /* typically: match */
+		  result_array);
+    }
+
+    if ((varnames->subs_offset_starts == NULL) && (varnames->subs_offset_ends == NULL)) {
+	goto CLEANUP;
+    }
+
+    bptr = mbegin = (char **)zalloc(sizeof(char *)*(ncaptures+1));
+    eptr = mend = (char **)zalloc(sizeof(char *)*(ncaptures+1));
+    for (m = matches + start, n = 0;
+	 n < ncaptures;
+	 ++n, ++m, ++bptr, ++eptr)
+    {
+	char buf[DIGBUFSIZE];
+	if (m->data == NULL) {
+	    /* FIXME: have assumed this is the API for non-matching substrings; confirm! */
+	    *bptr = ztrdup("-1");
+	    *eptr = ztrdup("-1");
+	    continue;
+	}
+	s = plaintext;
+	remaining_len = m->data - plaintext;
+	offs = 0;
+	/* Find the start offset */
+	MB_CHARINIT();
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base, 10);
+	*bptr = ztrdup(buf);
+	/* Continue to the end offset */
+	remaining_len = m->length;
+	while (remaining_len) {
+	    offs++;
+	    charlen = MB_CHARLEN(s, remaining_len);
+	    s += charlen;
+	    remaining_len -= charlen;
+	}
+	convbase(buf, offs + indexing_base - 1, 10);
+	*eptr = ztrdup(buf);
+    }
+    *bptr = *eptr = NULL;
+
+    if (varnames->subs_offset_starts != NULL) {
+	setaparam((char *)varnames->subs_offset_starts, /* typically: mbegin */
+		  mbegin);
+    }
+    if (varnames->subs_offset_ends != NULL) {
+	setaparam((char *)varnames->subs_offset_ends, /* typically: mend */
+		  mend);
+    }
+
+CLEANUP:
+    if (matches)
+	zfree(matches, matchessz);
+    return return_value;
+}
+
+static struct builtin bintab[] = {
+    /* TODO: add "R:" in here for named regexps: */
+    BUILTIN("re2_compile", 0, bin_re2_compile, 1, 1, 0, "acilwLP",  NULL),
+    BUILTIN("re2_match",   0, bin_re2_match,   1, 1, 0, "a:v:P:",    NULL),
+};
+
+
+static struct conddef cotab[] = {
+    CONDDEF("re2-match", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_RE2),
+    CONDDEF("re2-match-posix", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIX),
+    CONDDEF("re2-match-posixperl", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_POSIXPERL),
+    CONDDEF("re2-match-longest", CONDF_INFIX, zcond_re2_match, 0, 0, ZRE2_COND_LONGEST),
+};
+
+
+static struct features module_features = {
+    bintab, sizeof(bintab)/sizeof(*bintab),
+    cotab, sizeof(cotab)/sizeof(*cotab),
+    NULL, 0,
+    NULL, 0,
+    0
+};
+
+
+/**/
+int
+setup_(UNUSED(Module m))
+{
+    return 0;
+}
+
+/**/
+int
+features_(Module m, char ***features)
+{
+    *features = featuresarray(m, &module_features);
+    return 0;
+}
+
+/**/
+int
+enables_(Module m, int **enables)
+{
+    return handlefeatures(m, &module_features, enables);
+}
+
+/**/
+int
+boot_(UNUSED(Module m))
+{
+    anonymous.rex = NULL;
+    return 0;
+}
+
+/**/
+int
+cleanup_(Module m)
+{
+    if (anonymous.rex != NULL) {
+	cre2_delete(anonymous.rex);
+	anonymous.rex = NULL;
+    }
+    /* TODO:
+     * when implement -R named variables, also clean those up.
+     * (isolating them, to allow for clean module unloading, is why I moved
+     * away from storing regexps in named variables and think we should use
+     * a separate tree instead. */
+    return setfeatureenables(m, &module_features, NULL);
+}
+
+/**/
+int
+finish_(UNUSED(Module m))
+{
+    return 0;
+}
diff --git a/Src/Modules/re2.mdd b/Src/Modules/re2.mdd
new file mode 100644
index 0000000..5b23699
--- /dev/null
+++ b/Src/Modules/re2.mdd
@@ -0,0 +1,7 @@
+name=zsh/re2
+link='if test "x$enable_re2" = xyes && test "x$ac_cv_lib_cre2_cre2_version_string" = xyes; then echo dynamic; else echo no; fi'
+load=no
+
+autofeatures="b:re2_compile b:re2_match C:re2-match"
+
+objects="re2.o"
diff --git a/Test/V11re2.ztst b/Test/V11re2.ztst
new file mode 100644
index 0000000..860233e
--- /dev/null
+++ b/Test/V11re2.ztst
@@ -0,0 +1,317 @@
+%prep
+
+  if ! zmodload -F zsh/re2 C:re2-match 2>/dev/null
+  then
+    ZTST_unimplemented="the zsh/re2 module is not available"
+    return 0
+  fi
+# Load the rest of the builtins
+  zmodload zsh/re2
+  # TODO: use future mechanism to switch =~ to use re2 and test =~ too
+# Find a UTF-8 locale.
+  setopt multibyte
+# Don't let LC_* override our choice of locale.
+  unset -m LC_\*
+  mb_ok=
+  langs=(en_{US,GB}.{UTF-,utf}8 en.UTF-8
+	 $(locale -a 2>/dev/null | egrep 'utf8|UTF-8'))
+  for LANG in $langs; do
+    if [[ é = ? ]]; then
+      mb_ok=1
+      break;
+    fi
+  done
+  if [[ -z $mb_ok ]]; then
+    ZTST_unimplemented="no UTF-8 locale or multibyte mode is not implemented"
+  else
+    print -u $ZTST_fd Testing RE2 multibyte with locale $LANG
+    mkdir multibyte.tmp && cd multibyte.tmp
+  fi
+
+%test
+
+  [[ 'foo→bar' -re2-match .([^[:ascii:]]). ]]
+  print $MATCH
+  print $match[1]
+0:Basic non-ASCII regexp matching
+>o→b
+>→
+
+  MATCH=''
+  [[ ÷x -re2-match '^(\p{Sm})(\p{Latin})$' ]]
+  print "$? <$MATCH> .${match[1]}|${match[2]}."
+0:Unicode character class names & extracting correct widths
+>0 <÷x> .÷|x.
+
+  [[ alphabeta -re2-match a([^a]+)a ]]
+  echo "$? basic"
+  print $MATCH
+  print $match[1]
+  [[ ! alphabeta -re2-match a(.+)a ]]
+  echo "$? negated op"
+  [[ alphabeta -re2-match ^b ]]
+  echo "$? failed match"
+# default matches on first, then takes longest substring
+# -longest keeps looking
+  [[ abb -re2-match a(b|bb) ]]
+  echo "$? first .${MATCH}.${match[1]}."
+  [[ abb -re2-match-longest a(b|bb) ]]
+  echo "$? longest .${MATCH}.${match[1]}."
+  [[ alphabeta -re2-match ab ]]; echo "$? unanchored"
+  [[ alphabeta -re2-match ^ab ]]; echo "$? anchored"
+  [[ alphabeta -re2-match '^a(\w+)a$' ]]
+  echo "$? perl class used"
+  echo ".${MATCH}. .${match[1]}."
+  [[ alphabeta -re2-match-posix '^a(\w+)a$' ]]
+  echo "$? POSIX-mode, should inhibit Perl class"
+  [[ alphabeta -re2-match-posixperl '^a(\w+)a$' ]]
+  echo "$? POSIX-mode with Perl classes enabled .${match[1]}."
+  unset MATCH match
+  [[ alphabeta -re2-match ^a([^a]+)a([^a]+)a$ ]]
+  echo "$? matched, set vars"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+  unset MATCH match
+  [[ alphabeta -re2-match fr(.+)d ]]
+  echo "$? unmatched, not setting MATCH/match"
+  echo ".$MATCH. ${#MATCH}"
+  echo ".${(j:|:)match[*]}."
+0:Basic matching & result codes
+>0 basic
+>alpha
+>lph
+>1 negated op
+>1 failed match
+>0 first .ab.b.
+>0 longest .abb.bb.
+>0 unanchored
+>1 anchored
+>0 perl class used
+>.alphabeta. .lphabet.
+*?\(eval\):*: re2 rexexp compilation failed: invalid escape sequence: \w
+>1 POSIX-mode, should inhibit Perl class
+>0 POSIX-mode with Perl classes enabled .lphabet.
+>0 matched, set vars
+>.alphabeta. 9
+>.lph|bet.
+>1 unmatched, not setting MATCH/match
+>.. 0
+>..
+
+  m() {
+    unset MATCH MBEGIN MEND match mbegin mend
+    [[ $2 -re2-match $3 ]]
+    print $? $1: m:${MATCH}: ma:${(j:|:)match}: MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  }
+  data='alpha beta gamma delta'
+  m uncapturing $data '\b\w+\b'
+  m capturing $data '\b(\w+)\b'
+  m 'capture 2' $data '\b(\w+)\s+(\w+)\b'
+  m 'capture repeat' $data '\b(?:(\w+)\s+)+(\w+)\b'
+0:Beginning and end testing
+>0 uncapturing: m:alpha: ma:: MBEGIN=1 MEND=5 mbegin=() mend=()
+>0 capturing: m:alpha: ma:alpha: MBEGIN=1 MEND=5 mbegin=(1) mend=(5)
+>0 capture 2: m:alpha beta: ma:alpha|beta: MBEGIN=1 MEND=10 mbegin=(1 7) mend=(5 10)
+>0 capture repeat: m:alpha beta gamma delta: ma:gamma|delta: MBEGIN=1 MEND=22 mbegin=(12 18) mend=(16 22)
+
+
+  unset match mend
+  s=$'\u00a0'
+  [[ $s -re2-match '^.$' ]] && print OK
+  [[ A${s}B -re2-match .(.). && $match[1] == $s ]] && print OK
+  [[ A${s}${s}B -re2-match A([^[:ascii:]]*)B && $mend[1] == 3 ]] && print OK
+  unset s
+0:Raw IMETA characters in input string
+>OK
+>OK
+>OK
+
+  [[ foo -re2-match f.+ ]] ; print $?
+  [[ foo -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ ]] ; print $?
+  [[ ! foo -re2-match x.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && bar -re2-match x.+ ]] ; print $?
+  [[ ! foo -re2-match f.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match f.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match f.+ && bar -re2-match b.+ ) ]] ; print $?
+  [[ ! foo -re2-match x.+ && bar -re2-match b.+ ]] ; print $?
+  [[ foo -re2-match x.+ && ! bar -re2-match b.+ ]] ; print $?
+  [[ ! ( foo -re2-match x.+ && bar -re2-match b.+ ) ]] ; print $?
+0:Regex result inversion detection
+>0
+>1
+>1
+>0
+>0
+>1
+>1
+>1
+>1
+>1
+>0
+>1
+>0
+
+# Subshell because crash on failure
+  ( [[ test.txt -re2-match '^(.*_)?(test)' ]]
+    echo $match[2] )
+0:regression for segmentation fault (pcre, dup for re2), workers/38307
+>test
+
+  setopt BASH_REMATCH KSH_ARRAYS
+  unset MATCH MBEGIN MEND match mbegin mend BASH_REMATCH
+  [[ alphabeta -re2-match '^a([^a]+)(a)([^a]+)a$' ]]
+  print "$? bash_rematch"
+  print "m:${MATCH}: ma:${(j:|:)match}:"
+  print MBEGIN=$MBEGIN MEND=$MEND mbegin="(${mbegin[*]})" mend="(${mend[*]})"
+  print "BASH_REMATCH=[${(j:, :)BASH_REMATCH[@]}]"
+  print "[0]=${BASH_REMATCH[0]} [1]=${BASH_REMATCH[1]}"
+0:bash_rematch works
+>0 bash_rematch
+>m:: ma::
+>MBEGIN= MEND= mbegin=() mend=()
+>BASH_REMATCH=[alphabeta, lph, a, bet]
+>[0]=alphabeta [1]=lph
+
+  unsetopt BASH_REMATCH KSH_ARRAYS
+  m() {
+    local label="$1" text="$2" rc out
+    shift 2
+    unset MATCH match
+    # can't capture stderr sanely for amalgamation, need compile to happen in parent
+    re2_compile "$@"
+    rc=$?
+    if (( rc )); then print "${rc}-NoCompile $label"; return 1; fi
+    print -n "$rc:"
+    re2_match "$text"
+    print $? $label: m:${MATCH}: ma:${(j:|:)match}:
+  }
+  #
+  m cmd-clean                 alphabeta  lph
+  m cmd-anchored-nomatch      alphabeta  -a lph.+
+  m cmd-anchored-match        alphabeta  -a alp.+
+  m case-mismatch             alphabeta  'A\w+'
+  m case-insensitive-pattern  alphabeta  -i 'A\w+'
+  m case-insensitive-text     Alphabeta  -i 'a\w+'
+  m case-sensitive-text       Alphabeta  'a\w+'
+  m non-posix-okay-normal     ÷1   '^(\p{Sm})\d$'
+  m non-posix-reject-normal   ÷x   '^(\p{Sm})\d$'
+  print -u2 'stderr start non-posix-posixmode'
+  m non-posix-posixmode       ÷1   -P '^(\p{Sm})\d$'
+  print -u2 'stderr end non-posix-posixmode'
+  m literal-match             x1   -L  x1
+  m literal-nomatch           x1   -L  .1
+  m literal-match-substr      abcd -L  bc
+  m literal-nomatch-anchored  abcd -aL bc
+  m not-longest               abb      'a(b|bb)'
+  m longest                   abb  -l  'a(b|bb)'
+0:re2 compile/match testing with anonymous var
+>0:0 cmd-clean: m:lph: ma::
+>0:1 cmd-anchored-nomatch: m:: ma::
+>0:0 cmd-anchored-match: m:alphabeta: ma::
+>0:1 case-mismatch: m:: ma::
+>0:0 case-insensitive-pattern: m:alphabeta: ma::
+>0:0 case-insensitive-text: m:Alphabeta: ma::
+>0:0 case-sensitive-text: m:abeta: ma::
+>0:0 non-posix-okay-normal: m:÷1: ma:÷:
+>0:1 non-posix-reject-normal: m:: ma::
+>1-NoCompile non-posix-posixmode
+?stderr start non-posix-posixmode
+*?m:re2_compile:*: re2 rexexp compilation failed: invalid escape sequence: \p
+?stderr end non-posix-posixmode
+>0:0 literal-match: m:x1: ma::
+>0:1 literal-nomatch: m:: ma::
+>0:0 literal-match-substr: m:bc: ma::
+>0:1 literal-nomatch-anchored: m:: ma::
+>0:0 not-longest: m:ab: ma:b:
+>0:0 longest: m:abb: ma:bb:
+
+### We've dropped multi-line support for now, rather than debug RE2/cre2
+### interactions and figure out how I (pdp) am mis-reading docs.  Should
+### we add it, this is the test which exposed the presence of problems:
+#  m multiline-reject-nom      $'ab\ncd'      '^cd'
+#  set -x
+#  m multiline-okay            $'ab\ncd'   -m '^cd'
+#  set +x
+#0:re2 multiline matching
+#>0:1 multiline-reject-nom: m:: ma::
+#>0:0 multiline-okay: m:cd: ma::
+
+  m posix-simple       a1d  -Pa   '([[:alpha:]])([[:digit:]])([[:alpha:]])'
+  #
+  print -u2 'stderr start posix-reject-perlclass'
+  m posix-reject-perlclass      a1d  -Pa   '(\w)(\d)(\w)'
+  print -u2 'stderr end posix-reject-perlclass'
+  m posix-perlclass-enabled     a1d  -Pac  '(\w)(\d)(\w)'
+  m boundaries-normal           'def  efg'   '\be(.)'
+  print -u2 'stderr start posix-reject-boundaries'
+  m posix-reject-boundaries     'def  efg'   -P   '\be(.)'
+  print -u2 'stderr end posix-reject-boundaries'
+  m posix-boundaries-enabled    'def  efg'   -Pw  '\be(.)'
+  m posix-perlclass-boundaries  'de1g e2h' -Pcw '\be(\d)(\w)'
+  m posix-pcb-mattered          'de1g e2h' -Pcw   'e(\d)(\w)'
+0:re2 POSIX mode with various features added back
+>0:0 posix-simple: m:a1d: ma:a|1|d:
+?stderr start posix-reject-perlclass
+*?m:re2_compile:*: re2 rexexp compilation failed: invalid escape sequence: \\w
+?stderr end posix-reject-perlclass
+>1-NoCompile posix-reject-perlclass
+>0:0 posix-perlclass-enabled: m:a1d: ma:a|1|d:
+>0:0 boundaries-normal: m:ef: ma:f:
+?stderr start posix-reject-boundaries
+*?m:re2_compile:*: re2 rexexp compilation failed: invalid escape sequence: \\b
+?stderr end posix-reject-boundaries
+>1-NoCompile posix-reject-boundaries
+>0:0 posix-boundaries-enabled: m:ef: ma:f:
+>0:0 posix-perlclass-boundaries: m:e2h: ma:2|h:
+>0:0 posix-pcb-mattered: m:e1g: ma:1|g:
+
+  re2_compile -i '^([aeiou])(\w{2})'
+  mintov() {
+    local label="$1"; shift
+    unset MATCH match T1 t1
+    re2_match "$@"
+    print "$? $label MATCH=<$MATCH> match=<${(j:|:)match}> T1=<$T1> t1=<${(j:|:)t1}>"
+  }
+  mintov  not-first     not_first
+  mintov  simple        orange
+  mintov  redir-arr     -a t1 orange
+  mintov  redir-var     -v T1 orange
+  mintov  redir-both    -v T1 -a t1 orange
+  mintov  normal-after  orange
+0:re2_match capturing to named vars
+>1 not-first MATCH=<> match=<> T1=<> t1=<>
+>0 simple MATCH=<ora> match=<o|ra> T1=<> t1=<>
+>0 redir-arr MATCH=<ora> match=<> T1=<> t1=<o|ra>
+>0 redir-var MATCH=<> match=<o|ra> T1=<ora> t1=<>
+>0 redir-both MATCH=<> match=<> T1=<ora> t1=<o|ra>
+>0 normal-after MATCH=<ora> match=<o|ra> T1=<> t1=<>
+
+
+  re2_compile '^([aeiou])(\w{2})'
+  re2_match orange  && echo "yes-1"
+  re2_match -P '^t.{3}' orange || echo "no-2"
+  re2_match -P '^t.{3}' tangerine && echo "yes-3"
+  re2_match tangerine || echo "no-4"
+  re2_match orange && echo "yes-5 ${match[2]}"
+0:re2_match -P pattern works & doesn't mess with anonymous
+>yes-1
+>no-2
+>yes-3
+>no-4
+>yes-5 ra
+
+
+  re2_compile '^(\p{Sm})(?!\d+)(?:.)$'
+1:re2 check no crash on unsupported syntax
+?(eval):re2_compile:1: re2 rexexp compilation failed: invalid perl operator: (?!
+
+  re2_compile '(fred'
+1:re2 complain parens not closed
+?(eval):re2_compile:1: re2 rexexp compilation failed: missing ): (fred
+
+
+%clean
+  unfunction -m 'm*'
diff --git a/configure.ac b/configure.ac
index 0e0bd53..c000d6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -442,6 +442,11 @@ AC_ARG_ENABLE(pcre,
 AC_HELP_STRING([--enable-pcre],
 [enable the search for the pcre library (may create run-time library dependencies)]))
 
+dnl Do you want to look for re2 support?
+AC_ARG_ENABLE(re2,
+AC_HELP_STRING([--enable-re2],
+[enable the search for cre2 C-language bindings and re2 library]))
+
 dnl Do you want to look for capability support?
 AC_ARG_ENABLE(cap,
 AC_HELP_STRING([--enable-cap],
@@ -683,6 +688,43 @@ if test "x$ac_cv_prog_PCRECONF" = xpcre-config; then
 fi
 fi
 
+if test x$enable_re2 = xyes; then
+AC_CHECK_LIB([re2],[main],,
+  [AC_MSG_FAILURE([test for RE2 library failed])])
+AC_CHECK_LIB([cre2],[cre2_version_string],,
+  [AC_MSG_FAILURE([test for CRE2 library failed])])
+AC_CHECK_HEADERS([cre2.h],,
+  [AC_MSG_ERROR([test for RE2 header failed])])
+dnl The C++ libraries cre2 & re2 need to be built with the same compiler
+dnl to avoid chaotic failures; in testing, a mismatch was sufficient to
+dnl cause this to either error or segfault during cre2_pattern().
+AC_CACHE_CHECK([whether cre2 is broken at runtime],
+  [zsh_cv_cre2_runtime_broken],
+  AC_TRY_RUN([
+#include <stdint.h>
+#include <string.h>
+#include <cre2.h>
+#define Pattern "a.{2}(c|d)$"
+int main(int argc, char **argv) {
+	cre2_options_t *opts; cre2_regexp_t *rex;
+	opts = cre2_opt_new();
+	if (!opts) { return 1; }
+	rex = cre2_new(Pattern, strlen(Pattern), opts);
+	if (!rex) { return 2; }
+	if (cre2_error_code(rex)) { return 3; }
+	if (strcmp(cre2_pattern(rex), Pattern) != 0) { return 4; }
+	cre2_delete(rex);
+	cre2_opt_delete(opts);
+	return 0;
+}],
+  zsh_cv_cre2_runtime_broken=no,
+  zsh_cv_cre2_runtime_broken=yes
+  zsh_cv_cre2_runtime_broken=yes))
+  if test x$zsh_cv_cre2_runtime_broken = xyes; then
+    AC_MSG_ERROR([cre2 library hard-unusable, rebuild with same compiler as for RE2])
+  fi
+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 \
-- 
2.10.0


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

^ permalink raw reply	[relevance 9%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  @ 2016-09-08 14:31  3%     ` Stephane Chazelas
  2016-09-08 15:06  3%       ` Stephane Chazelas
                         ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Stephane Chazelas @ 2016-09-08 14:31 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

2016-09-08 12:16:28 +0100, Peter Stephenson:
[...]
> diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo
> index 3d369fb..6fcf3bd 100644
> --- a/Doc/Zsh/cond.yo
> +++ b/Doc/Zsh/cond.yo
> @@ -103,8 +103,8 @@ true if var(file1) and var(file2) exist and refer to the same file.
>  xitem(var(string) tt(=) var(pattern))
>  item(var(string) tt(==) var(pattern))(
>  true if var(string) matches var(pattern).
> -The `tt(==)' form is the preferred one.  The `tt(=)' form is for
> -backward compatibility and should be considered obsolete.
> +The `tt(==)' form is the preferred one for clarity in new shell code
> +as it more closely resembles other languages.
[...]

ksh93 also makes "==" obsolete in [[...]]. "==" is still not
POSIX (and likely not going to be soon as requests to add it
have been rejected (IIRC)) for the "test"/"[" utility (or expr).

I suspect the reason David Korn obsoleted "==" is mainly for
consistency with the ((...)) "==" operator. There, "==" is
comparison and "=" is assignment like in C/awk (and other
languages that don't do the disambiguation via some other mean
like :=/= or <-/=).

However inside [[...]], there is no possible confusion between
assignment and comparison as [[...]] is only a construct for
doing tests, so no point in having a "==" there.

I personally use "=" (even for [[...]]), as that's what's
standard for "test"/"[".

The risk with stating that "==" is obsolete is that people are
going to start using [ "$a" == "$b" ] (as many do already)
thinking it's the right thing to do and get bitten when "sh"
changes from bash/zsh/ksh/yash to another sh implementation
whose "test" builtin doesn't support "=="

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-09  8:52  3%       ` Stephane Chazelas
@ 2016-09-09  9:31  3%         ` Peter Stephenson
  2016-09-09 16:00  0%           ` Stephane Chazelas
    1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2016-09-09  9:31 UTC (permalink / raw)
  To: zsh-workers

On Fri, 09 Sep 2016 09:52:31 +0100
Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> It's still possible that the next major POSIX spec will have
> [ == ] and maybe even [[ ]].
> 
> You guys may want to comment on the latest proposal there:
> http://austingroupbugs.net/file_download.php?file_id=31&type=bug
> 
> as it would make zsh non-conformant.
> 
> In particular, it  proposes specifying [[ =~ ]] the ksh/bash
> way, that is where quoting escapes regexp operators (
> [[ a =~ "." ]] returns false) and [[ < ]] required to use
> collation.

If POSIX-like shells already do it that way, the best we could offer
would probably be another kludge-up option anyway.  Not specifying it,
the only other option, isn't really doing anyone any favours in the end.

pws


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-08 14:31  3%     ` Stephane Chazelas
  2016-09-08 15:06  3%       ` Stephane Chazelas
  2016-09-08 15:14  0%       ` Peter Stephenson
@ 2016-09-09  8:52  3%       ` Stephane Chazelas
  2016-09-09  9:31  3%         ` Peter Stephenson
    2 siblings, 2 replies; 200+ results
From: Stephane Chazelas @ 2016-09-09  8:52 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers

2016-09-08 15:31:28 +0100, Stephane Chazelas:
[...]
> ksh93 also makes "==" obsolete in [[...]]. "==" is still not
> POSIX (and likely not going to be soon as requests to add it
> have been rejected (IIRC)) for the "test"/"[" utility (or expr).
[...]

Sorry, bad memory. Though there was some opposition, the "=="
proposal was not rejected:
http://austingroupbugs.net/view.php?id=375 was what I was
vaguely recalling.

It's still possible that the next major POSIX spec will have
[ == ] and maybe even [[ ]].

You guys may want to comment on the latest proposal there:
http://austingroupbugs.net/file_download.php?file_id=31&type=bug

as it would make zsh non-conformant.

In particular, it  proposes specifying [[ =~ ]] the ksh/bash
way, that is where quoting escapes regexp operators (
[[ a =~ "." ]] returns false) and [[ < ]] required to use
collation.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-09  9:31  3%         ` Peter Stephenson
@ 2016-09-09 16:00  0%           ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2016-09-09 16:00 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

2016-09-09 10:31:55 +0100, Peter Stephenson:
> On Fri, 09 Sep 2016 09:52:31 +0100
> Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> > It's still possible that the next major POSIX spec will have
> > [ == ] and maybe even [[ ]].
> > 
> > You guys may want to comment on the latest proposal there:
> > http://austingroupbugs.net/file_download.php?file_id=31&type=bug
> > 
> > as it would make zsh non-conformant.
> > 
> > In particular, it  proposes specifying [[ =~ ]] the ksh/bash
> > way, that is where quoting escapes regexp operators (
> > [[ a =~ "." ]] returns false) and [[ < ]] required to use
> > collation.
> 
> If POSIX-like shells already do it that way, the best we could offer
> would probably be another kludge-up option anyway.  Not specifying it,
> the only other option, isn't really doing anyone any favours in the end.
[...]

Note that doing it properly is tricky. bash has had a number
of bugs before it eventually settled to something reliable
enough.

bash -c '[[ "\\" =~ [^]"."] ]]'

Still return false though.

With zsh supporting both ERE and PCRE, it's going to be even
more pain I would say.

Specifying it (which the current proposal doesn't really
address) is also going to be difficult.

The problem is that the shell needs to know the syntax of the
regular expressions in order to be able to quote the RE
operators properly for the regexp engine.

for instance in [[ x =~ "." ]], the shell has to call
regcomp("\\."), but in [[ x =~ ["."] ]], it must call
regcomp("[.]"), as otherwise a regcomp("[\.]") would also match
on backslash. bash now does that properly in most cases (after I
raised the bug some time ago), but misses the [^]...] case as
I've just realised.

And in [[ x =~ "<" ]], you don't want to do a regcomp("\\<"), as
\< has a special meaning in some regexp engines. So bash does a
regcomp("<") (for both [[ x =~ "<" ]] and [[ x =~ \< ]])
instead. What that means is that you can't use the extensions of
your local regexp library unless you use a variable as in:

var='\<foo\>'
[[ $x =~ $var ]]

because then bash does a regcomp("\\<foo\\>") (just like zsh).

See also:

a='foo\'
[[ 'foo\bar' =~ $a"." ]]

That returns true in bash. (as it does a regcomp("foo\\\\.")),
though here we are asking for trouble in the first place with
that trailing backslash.

In effect at the moment to use =~ portably between ksh, bash,
bash31, zsh, you have to use:

regex=...
[[ $string =~ $regex ]]

And in between yash and zsh:

[ "$string" "=~" "$regex" ]

In PCRE, you have things like (?x) that affect the parsing and
would make things more complicated, but you might be able to
leverage \Q \E.

-- 
Stephane


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] Use == in expressions instead of the deprecated =
  2016-09-08 14:31  3%     ` Stephane Chazelas
@ 2016-09-08 15:06  3%       ` Stephane Chazelas
  2016-09-08 15:14  0%       ` Peter Stephenson
  2016-09-09  8:52  3%       ` Stephane Chazelas
  2 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2016-09-08 15:06 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers

2016-09-08 15:31:28 +0100, Stephane Chazelas:
[...]
> ksh93 also makes "==" obsolete in [[...]]. "==" is still not
> POSIX (and likely not going to be soon as requests to add it
> have been rejected (IIRC)) for the "test"/"[" utility (or expr).
[...]

Appart from bash 2.02, I don't know of a shell implementation
that treats [[ = ]] differently from [[ == ]] (or [ = ] vs [ ==
] for those "[" implementations that support ==) however note
that yash has a 3rd operator: [ === ] that is short for [ '<=' ]
&& [ '>=' ] or [ ! '<' ] && [ ! '>' ].

As in yash like in bash or ksh93 (but not zsh), < and > for
string comparison use strcoll() (like sort/expr or awk's </> for
strings) while == uses strcmp. And in some locales, there are
strings that sort the same even though they are different.

yash's === is a test to check that two strings sort the same,
like the "=" operator of expr (or the == operator of some awk
implementations as currently required by POSIX (though that's
going to change)).

For instance in a en_GB.UTF-8 locale on a GNU system, \u2461
sorts the same as \u2462 (in that case, a bug).

expr $'\u2461' = $'\u2462'
and
yash -c '[ \u2461 === \u2462 ]'

return true while

[[ \u2461 < \u2462 ]] and [[ \u2461 > \u2462 ]]
both return false in bash and ksh93.

zsh's behaviour is more consistent here but means that for
instance

[[ Stéphane < Stuff ]]

returns false (while bash and ksh93 return true) even though
I'd exect é to sort before u.

See also
https://unix.stackexchange.com/questions/56655/what-is-the-difference-between-a-z-and-a-z/56674#56674

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: PATCH: [[ -v varname ]]
  @ 2016-09-15 11:08  3%           ` Stephane Chazelas
  2016-09-15 11:22  4%             ` wrong "export -p" output for exported but not set variables (Was: PATCH: [[ -v varname ]]) Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2016-09-15 11:08 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: zsh-workers

2016-09-15 00:01:50 +0200, Oliver Kiddle:
> On 9 Sep, Stephane Chazelas wrote:
> > You guys may want to comment on the latest proposal there:
> > http://austingroupbugs.net/file_download.php?file_id=31&type=bug
> > as it would make zsh non-conformant.
> 
> One thing it also includes is the bash/ksh [[ -v ... ]] condition for
> checking if a particular variable is set. Zsh has the ${+varname} syntax
> which provides the same functionality in a different form. The following
> patch adds the ksh form for compatibility.
[...]

Note that there's a lot of variation between the ksh93 and bash
implementation of [[ -v ]] (though maybe not so much on the part
covered by POSIX), for instance on variables that have been
declared (or exported or marked readonly) with different types
but not assigned to (at least in zsh, declared/exported
variables are always given a default value), on arrays or hashs
that have no element (or no element of indice 0 or "0"; for a
hash in bash [[ -v h ]] returns true iff h[0] is set and in ksh
never ([[ -v h[@] ]] doesn't work either)).

Also note that in ksh/bash, it's only for variables, not other
types of parameters ([[ -v 0 ]], [[ -v "#" ]] return false).

See also:

$ a='b[0`uname>&2`]' bash -c '[[ -v $a ]]'
Linux

$ bash -c 'typeset -n a=b; [[ -v a ]]'; echo $?
1
$ b= bash -c 'typeset -n a=b; [[ -v a ]]'; echo $?
0

Spurious error message:

$ ksh -c 'typeset -T A=(a=a); A a; [[ -v a.x ]]'
ksh: x: is not an element of a

a.x returns false if $a has a x but that's a discipline (or
array/hash with 0 element not set).


In any case, it looks like your patch does the sensible thing in
all the cases I've tried except that [[ -v @ ]] returns false
(while [[ -v * ]] return true). No big deal as nobody would ever
want to do that.

What to do in zsh (where scalar and arrays are distinct types) for 

zsh -c 'a=1234; [[ -v a[1] ]]

is up to debate (currently returns false).

See also
https://unix.stackexchange.com/questions/212183/how-do-i-check-if-a-variable-exists-in-an-if-statement/246703#246703

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* wrong "export -p" output for exported but not set variables (Was: PATCH: [[ -v varname ]])
  2016-09-15 11:08  3%           ` Stephane Chazelas
@ 2016-09-15 11:22  4%             ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2016-09-15 11:22 UTC (permalink / raw)
  To: Oliver Kiddle, zsh-workers

2016-09-15 12:08:54 +0100, Stephane Chazelas:
[...]
> declared (or exported or marked readonly) with different types
> but not assigned to (at least in zsh, declared/exported
> variables are always given a default value)
[...]

Actually, I was wrong about that and was basing it on the output
of typeset -p.

$ zsh -c 'export a; export -p a'
typeset -x a=''

(BTW, it would be nice to have sh-compatible (POSIX at least) output in:
$ ARGV0=sh zsh -c 'export a; export -p a'
typeset -x a=''
)

$ zsh -c 'export a; printenv a'
$ zsh -c 'export a=; printenv a'

$

$a was not given a default empty value there. It's considered as set though:

$ zsh -c 'export a; echo ${a+foo}'
foo

Which I think breaks POSIX compliance (and no other shell
outputs foo there)..

It's different for "readonly":

$ zsh -c 'readonly a; echo ${a+foo}'
foo
$ ARGV0=sh zsh -c 'readonly a; echo ${a+foo}'

$

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: Is "command" working right, yet?
  2016-02-07 15:24  4% ` Martijn Dekker
@ 2016-09-25 23:31  3%   ` Martijn Dekker
  2016-09-26  3:13  3%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-09-25 23:31 UTC (permalink / raw)
  To: zsh-workers

Op 07-02-16 om 15:24 schreef Martijn Dekker:
> Bart Schaefer schreef op 03-02-16 om 00:37:
> [...]
>> > burner% setopt posixbuiltins
>> > burner% command -p -V true
>> > zsh: command not found: -V
>> > burner% command -V -p true  
>> > command: bad option: -p
>> > 
>> > I think this is pretty clearly a bug.
> Agreed, these options should combine without a problem.

Resuming this old thread, it would be nice to get this fixed before zsh
5.3 is released. It's the only clear POSIX issue left on zsh that I know
of, and I've found a few in the past...

The culprit seems to be the simplistic option parsing code starting at
line 2664 in Src/exec.c (current git, e35dcae):

|            if ((cflags & BINF_COMMAND) && nextnode(firstnode(args))) {
|                 /* check for options to command builtin */
|                 char *next = (char *) getdata(nextnode(firstnode(args)));
|                 char *cmdopt;
|                 if (next && *next == '-' && strlen(next) == 2 &&
|                         (cmdopt = strchr("pvV", next[1])))
|                 {
|                     if (*cmdopt == 'p') {
|                         uremnode(args, firstnode(args));
|                         use_defpath = 1;
|                         if (nextnode(firstnode(args)))
|                             next = (char *)
getdata(nextnode(firstnode(args)));
|                     } else {
|                         hn = &commandbn.node;
|                         is_builtin = 1;
|                         break;
|                     }
|                 }
|                 if (!strcmp(next, "--"))
|                      uremnode(args, firstnode(args));
|             }

Sure enough, it looks if there's one option and if there is, it happily
ignores the rest. Combined options like -pV also aren't supported.

I don't understand nearly enough about the zsh codebase to know why this
routine does its own option parsing rather than calling some common
option parsing function, so I can't offer suggestions for improvement
here that aren't likely to be completely stupid.

Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* Re: Is "command" working right, yet?
  2016-09-25 23:31  3%   ` Martijn Dekker
@ 2016-09-26  3:13  3%     ` Bart Schaefer
    0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-09-26  3:13 UTC (permalink / raw)
  To: zsh-workers

On Sep 26, 12:31am, Martijn Dekker wrote:
}
} The culprit seems to be the simplistic option parsing code starting at
} line 2664 in Src/exec.c (current git, e35dcae):
} 
} Sure enough, it looks if there's one option and if there is, it happily
} ignores the rest. Combined options like -pV also aren't supported.

Not exactly.  That whole thing is in a "while" loop, so as long as -p
and -v and/or -V are in separate words I think the expectation was
that it would loop around and discover the next one .. but if -p is
first, it doesn't loop, and if -v or -V is first then -p is rejected
because it's not [and can't be, see below] listed in the value of
"commandbn" [exec.c 209].

} I don't understand nearly enough about the zsh codebase to know why this
} routine does its own option parsing rather than calling some common
} option parsing function, so I can't offer suggestions for improvement

It's because "command" is a sort-of keyword instead of a builtin, so it
doesn't go through the regular builtin dispatch where the common option
parsing lives.  Originally zsh's "command" prefix didn't accept any
options, so this parsing was bolted on bit by bit as POSIX defined them.

A complication is that "command -v" is defined in terms of bin_whence(),
and "whence" has a -p option that means something different.


^ permalink raw reply	[relevance 3%]

* Re: Is "command" working right, yet?
  @ 2016-09-27 12:15  3%         ` Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2016-09-27 12:15 UTC (permalink / raw)
  To: Zsh hackers list

Op 27-09-16 om 11:08 schreef Peter Stephenson:
> On Sun, 25 Sep 2016 20:13:28 -0700
> Bart Schaefer <schaefer@brasslantern.com> wrote:
>> A complication is that "command -v" is defined in terms of bin_whence(),
>> and "whence" has a -p option that means something different.
> 
> That also means path search.

Nope.

'command -p' means: ignore the PATH environment variable and do the
search as normal, but (if it's a path search) use the system default
path as output by the 'getconf PATH' command. That means the -p option
has no effect for builtins.

POSIX provides this as one way to make shell scripts a bit more robust;
'command -p grep' guarantees you get either the system's external 'grep'
or a builtin version provided by the shell, and not some other 'grep'
that the user (or someone who hacked them) may have installed in some
location that comes before the real 'grep' in $PATH and that may, for
all anyone knows, delete all their files.

Reference:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/command.html#tag_20_22_04

This is why it's important that '-p' should combine properly with '-v'
and '-V'. The command 'command -pv grep', provided there is no builtin
for it, should output the location of the system default 'grep' as
opposed to whatever 'grep' may take precedence over it in $PATH.

By the way, 'command -p' *nearly* works properly (i.e. as described
above) in zsh, apart from combining with other options. See line 664 and
on in exec.c, line 2030 and on in configure.ac, and line 77 in config.h.in.

The problem is configure.ac only tries non-standard 'getconf' commands
(i.e. 'getconf _CS_PATH' and 'getconf CS_PATH'); the command to use on
BSD/OSX is 'getconf PATH', which works on Linux as well. I don't know if
the other two should be kept, but 'getconf PATH' should at least be added.

diff --git a/configure.ac b/configure.ac
index 0e0bd53..e0eb320 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2035,6 +2035,8 @@ AC_CACHE_VAL(zsh_cv_cs_path,
   zsh_cv_cs_path=`getconf _CS_PATH`
 elif getconf CS_PATH >/dev/null 2>&1; then
   zsh_cv_cs_path=`getconf CS_PATH`
+elif getconf PATH >/dev/null 2>&1; then
+  zsh_cv_cs_path=`getconf PATH`
 else
   zsh_cv_cs_path="/bin:/usr/bin"
 fi])


Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* 'set -e' with '!' POSIX issue
@ 2016-10-02 10:01 10% Martijn Dekker
  2016-10-02 17:55  4% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-10-02 10:01 UTC (permalink / raw)
  To: Zsh hackers list

'set -e' ('set -o errexit') is not POSIX compliant on zsh because it
doesn't ignore a command beginning with "!".

The script:

    set -e
    ! true
    echo good

should output "good", and does, on every shell except zsh.

Ref.:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25
| 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.

(Note that in POSIX terms the definition of "pipeline" includes a simple
command.)

Thanks,

- Martijn


^ permalink raw reply	[relevance 10%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-02 10:01 10% 'set -e' with '!' POSIX issue Martijn Dekker
@ 2016-10-02 17:55  4% ` Peter Stephenson
  2016-10-04  7:45  5%   ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-10-02 17:55 UTC (permalink / raw)
  To: Zsh hackers list

On Sun, 2 Oct 2016 11:01:18 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> 'set -e' ('set -o errexit') is not POSIX compliant on zsh because it
> doesn't ignore a command beginning with "!".

I don't really like the errexit logic as there are too many horrible
cases, since the place we need to test is different from where the code
is being executed (look at the particularly horrible oldnoeerrexit
logic).  This was not entirely trivial but we might get away with it.

The tests are for ERR_RETURN because that's easier to write; most of the
logic is shared with ERR_EXIT.

pws

diff --git a/Src/exec.c b/Src/exec.c
index 349414c..a429428 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1226,6 +1226,7 @@ execlist(Estate state, int dont_change_job, int exiting)
     }
     while (wc_code(code) == WC_LIST && !breaks && !retflag && !errflag) {
 	int donedebug;
+	int this_noerrexit = 0;
 
 	ltype = WC_LIST_TYPE(code);
 	csp = cmdsp;
@@ -1309,9 +1310,12 @@ execlist(Estate state, int dont_change_job, int exiting)
 	    goto sublist_done;
 	}
 	while (wc_code(code) == WC_SUBLIST) {
+	    int isend = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END);
 	    next = state->pc + WC_SUBLIST_SKIP(code);
 	    if (!oldnoerrexit)
-		noerrexit = (WC_SUBLIST_TYPE(code) != WC_SUBLIST_END);
+		noerrexit = !isend;
+	    if ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) && isend)
+		this_noerrexit = 1;
 	    switch (WC_SUBLIST_TYPE(code)) {
 	    case WC_SUBLIST_END:
 		/* End of sublist; just execute, ignoring status. */
@@ -1427,7 +1431,7 @@ sublist_done:
 	/* Check whether we are suppressing traps/errexit *
 	 * (typically in init scripts) and if we haven't  *
 	 * already performed them for this sublist.       */
-	if (!noerrexit && !donetrap) {
+	if (!noerrexit && !this_noerrexit && !donetrap) {
 	    if (sigtrapped[SIGZERR] && lastval) {
 		dotrap(SIGZERR);
 		donetrap = 1;
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 83c05aa..3a65b28 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -519,6 +519,43 @@
 >Yes
 F:Must be tested with a top-level script rather than source or function
 
+  fn() {
+      emulate -L zsh
+      setopt errreturn
+      print before
+      false
+      print after
+  }
+  fn
+1:ERRRETURN, basic case
+>before
+
+  fn() {
+      emulate -L zsh
+      setopt errreturn
+      print before
+      ! true
+      ! false
+      print after
+  }
+  fn
+0:ERRETURN with "!"
+>before
+>after
+
+  fn() {
+      emulate -L zsh
+      setopt errreturn
+      print before
+      ! true
+      ! false
+      false
+      print after
+  }
+  fn
+1:ERRETURN with "!" and a following false
+>before
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 4%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-02 17:55  4% ` Peter Stephenson
@ 2016-10-04  7:45  5%   ` Vincent Lefevre
  2016-10-04  8:30  5%     ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2016-10-04  7:45 UTC (permalink / raw)
  To: zsh-workers

On 2016-10-02 18:55:30 +0100, Peter Stephenson wrote:
> On Sun, 2 Oct 2016 11:01:18 +0100
> Martijn Dekker <martijn@inlv.org> wrote:
> > 'set -e' ('set -o errexit') is not POSIX compliant on zsh because it
> > doesn't ignore a command beginning with "!".
> 
> I don't really like the errexit logic as there are too many horrible
> cases, since the place we need to test is different from where the code
> is being executed (look at the particularly horrible oldnoeerrexit
> logic).  This was not entirely trivial but we might get away with it.
> 
> The tests are for ERR_RETURN because that's easier to write; most of the
> logic is shared with ERR_EXIT.

I thought that this was not supposed to change:

  http://www.zsh.org/mla/workers/2009/msg00572.html
  http://www.zsh.org/mla/workers/2009/msg00574.html

I haven't checked the current status for the other 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 5%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-04  7:45  5%   ` Vincent Lefevre
@ 2016-10-04  8:30  5%     ` Peter Stephenson
  2016-10-05 10:18  5%       ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2016-10-04  8:30 UTC (permalink / raw)
  To: zsh-workers

On Tue, 4 Oct 2016 09:45:38 +0200
Vincent Lefevre <vincent@vinc17.net> wrote:
> On 2016-10-02 18:55:30 +0100, Peter Stephenson wrote:
> > On Sun, 2 Oct 2016 11:01:18 +0100
> > Martijn Dekker <martijn@inlv.org> wrote:
> > > 'set -e' ('set -o errexit') is not POSIX compliant on zsh because it
> > > doesn't ignore a command beginning with "!".
> > 
> > I don't really like the errexit logic as there are too many horrible
> > cases, since the place we need to test is different from where the code
> > is being executed (look at the particularly horrible oldnoeerrexit
> > logic).  This was not entirely trivial but we might get away with it.
> > 
> > The tests are for ERR_RETURN because that's easier to write; most of the
> > logic is shared with ERR_EXIT.
> 
> I thought that this was not supposed to change:
> 
>   http://www.zsh.org/mla/workers/2009/msg00572.html
>   http://www.zsh.org/mla/workers/2009/msg00574.html
> 
> I haven't checked the current status for the other two cases.

The point I made there was I was waiting for things to clear up.  That
was 7 years ago.  I'm not going to wait any longer for things to clear
up...

pws


^ permalink raw reply	[relevance 5%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-04  8:30  5%     ` Peter Stephenson
@ 2016-10-05 10:18  5%       ` Martijn Dekker
  2016-10-05 11:37  5%         ` Peter Stephenson
  2016-10-05 13:47  3%         ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2016-10-05 10:18 UTC (permalink / raw)
  To: Zsh hackers list

Op 04-10-16 om 10:30 schreef Peter Stephenson:
> On Tue, 4 Oct 2016 09:45:38 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
>> I thought that this was not supposed to change:
>>
>>   http://www.zsh.org/mla/workers/2009/msg00572.html
>>   http://www.zsh.org/mla/workers/2009/msg00574.html
>>
>> I haven't checked the current status for the other two cases.
> 
> The point I made there was I was waiting for things to clear up.  That
> was 7 years ago.  I'm not going to wait any longer for things to clear
> up...

FYI, your patch fixes the simple case ('! true'), but not the two more
complex cases mentioned back then:

On Fri, Mar 13, 2009 at 03:51:34PM +0100, Vincent Lefevre wrote:
> According to the new "set -e" proposal
>
>   http://www.opengroup.org/austin/mailarchives/ag/msg18258.html
>
> zsh -c 'set -e; ! if true; then false; fi; echo $?'
>
> should output 0, i.e. "false" should not make the shell exit, because
> it is under a "!" context (even though "!" doesn't apply on the "false"
> command directly).
>
> Note that every other shell (bash, ksh93, pdksh, dash, posh) output 0.

On Tue, Mar 17, 2009 at 12:46:20PM +0100, Vincent Lefevre wrote:
> POSIX shells (bash, dash, ksh93, pdksh, posh) return with no output
> and an exit status equal to 1 on:
>
>   sh -c 'set -e; foo() { false && false; }; foo; echo $?'
>
> but zsh doesn't, even with "emulate sh":
>
> $ zsh -fc 'emulate sh; set -e; foo() { false && false; }; foo; echo $?'
> 1
>
> zsh should match the existing practice (perhaps even without
> "emulate sh", unless this can break too many zsh scripts).

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-05 10:18  5%       ` Martijn Dekker
@ 2016-10-05 11:37  5%         ` Peter Stephenson
  2016-10-05 13:47  3%         ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2016-10-05 11:37 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 5 Oct 2016 12:18:26 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> On Fri, Mar 13, 2009 at 03:51:34PM +0100, Vincent Lefevre wrote:
> > According to the new "set -e" proposal
> >
> >   http://www.opengroup.org/austin/mailarchives/ag/msg18258.html
> >
> > zsh -c 'set -e; ! if true; then false; fi; echo $?'
> >
> > should output 0, i.e. "false" should not make the shell exit, because
> > it is under a "!" context (even though "!" doesn't apply on the "false"
> > command directly).

This one appears to be a straightforward extension.

diff --git a/Src/exec.c b/Src/exec.c
index f248ca2..741c80e 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1317,8 +1317,13 @@ execlist(Estate state, int dont_change_job, int exiting)
 	    next = state->pc + WC_SUBLIST_SKIP(code);
 	    if (!oldnoerrexit)
 		noerrexit = !isend;
-	    if ((WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT) && isend)
-		this_noerrexit = 1;
+	    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> */
+		noerrexit = 1;
+	    }
 	    switch (WC_SUBLIST_TYPE(code)) {
 	    case WC_SUBLIST_END:
 		/* End of sublist; just execute, ignoring status. */
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 3a65b28..0faec02 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -556,6 +556,33 @@ F:Must be tested with a top-level script rather than source or function
 1:ERRETURN with "!" and a following false
 >before
 
+  fn() {
+      emulate -L zsh
+      setopt errreturn
+      print before
+      ! if true; then
+        false
+      fi
+      print after
+  }
+  fn
+0:ERRETURN with "!" suppressed inside complex structure
+>before
+>after
+
+  fn() {
+      emulate -L zsh
+      setopt errreturn
+      print before
+      if true; then
+        false
+      fi
+      print after
+  }
+  fn
+1:ERRETURN with no "!" suppression (control case)
+>before
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 5%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-05 10:18  5%       ` Martijn Dekker
  2016-10-05 11:37  5%         ` Peter Stephenson
@ 2016-10-05 13:47  3%         ` Peter Stephenson
  2016-10-06  8:36  5%           ` Peter Stephenson
  2016-10-06 11:22  9%           ` Martijn Dekker
  1 sibling, 2 replies; 200+ results
From: Peter Stephenson @ 2016-10-05 13:47 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 5 Oct 2016 12:18:26 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> On Tue, Mar 17, 2009 at 12:46:20PM +0100, Vincent Lefevre wrote:
> > POSIX shells (bash, dash, ksh93, pdksh, posh) return with no output
> > and an exit status equal to 1 on:
> >
> >   sh -c 'set -e; foo() { false && false; }; foo; echo $?'
> >
> > but zsh doesn't, even with "emulate sh":
> >
> > $ zsh -fc 'emulate sh; set -e; foo() { false && false; }; foo; echo $?'
> > 1

I think this is a bug, regardless of the standard.  The "&&" within the
function shouldn't have anything to do with what happens outside, and it
works without that.

The fix appears to be similar to the one for "!".

Please reassure me that this is correct:

% ./zsh -fc 'set -e; foo() { false && false; echo OK; }; foo; echo $?'
OK
0

We hit the first "false" in the &&, which doesn't trigger ERR_EXIT so
the second "false" that would is never executed; therefore we proceed to
"echo OK"; therefore the status of the function is 0.  If there's no
controversy I may add this as a test case for future reference, together
with the "true & false" case that causes the function to be aborted.

pws

diff --git a/Src/exec.c b/Src/exec.c
index 741c80e..c0ed2c4 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1229,7 +1229,7 @@ execlist(Estate state, int dont_change_job, int exiting)
     }
     while (wc_code(code) == WC_LIST && !breaks && !retflag && !errflag) {
 	int donedebug;
-	int this_noerrexit = 0;
+	int this_noerrexit = 0, this_donetrap = 0;
 
 	ltype = WC_LIST_TYPE(code);
 	csp = cmdsp;
@@ -1353,10 +1353,10 @@ execlist(Estate state, int dont_change_job, int exiting)
 			/* We've skipped to the end of the list, not executing *
 			 * the final pipeline, so don't perform error handling *
 			 * for this sublist.                                   */
-			donetrap = 1;
+			this_donetrap = 1;
 			goto sublist_done;
 		    } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) {
-			donetrap = 1;
+			this_donetrap = 1;
 			/*
 			 * Treat this in the same way as if we reached
 			 * the end of the sublist normally.
@@ -1386,10 +1386,10 @@ execlist(Estate state, int dont_change_job, int exiting)
 			/* We've skipped to the end of the list, not executing *
 			 * the final pipeline, so don't perform error handling *
 			 * for this sublist.                                   */
-			donetrap = 1;
+			this_donetrap = 1;
 			goto sublist_done;
 		    } else if (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END) {
-			donetrap = 1;
+			this_donetrap = 1;
 			/*
 			 * Treat this in the same way as if we reached
 			 * the end of the sublist normally.
@@ -1439,7 +1439,7 @@ sublist_done:
 	/* Check whether we are suppressing traps/errexit *
 	 * (typically in init scripts) and if we haven't  *
 	 * already performed them for this sublist.       */
-	if (!noerrexit && !this_noerrexit && !donetrap) {
+	if (!noerrexit && !this_noerrexit && !donetrap && !this_donetrap) {
 	    if (sigtrapped[SIGZERR] && lastval) {
 		dotrap(SIGZERR);
 		donetrap = 1;
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 0faec02..5057dcf 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -476,7 +476,7 @@
     fi
   }
   fn
-0:ERRRETURN not triggered in if condition
+0:ERR_RETURN not triggered in if condition
 >Oh, yes
 
   fn() {
@@ -490,7 +490,7 @@
     fi
   }
   fn
-1:ERRRETURN in "if"
+1:ERR_RETURN in "if"
 
   fn() {
     emulate -L zsh
@@ -503,7 +503,7 @@
     fi
   }
   fn
-1:ERRRETURN in "else" branch (regression test)
+1:ERR_RETURN in "else" branch (regression test)
 
   $ZTST_testdir/../Src/zsh -f =(<<<"
   if false; then
@@ -515,7 +515,7 @@
     print Yes
   fi
   ")
-0:ERRRETURN when false "if" is the first statement in an "else" (regression)
+0:ERR_RETURN when false "if" is the first statement in an "else" (regression)
 >Yes
 F:Must be tested with a top-level script rather than source or function
 
@@ -527,7 +527,7 @@ F:Must be tested with a top-level script rather than source or function
       print after
   }
   fn
-1:ERRRETURN, basic case
+1:ERR_RETURN, basic case
 >before
 
   fn() {
@@ -539,7 +539,7 @@ F:Must be tested with a top-level script rather than source or function
       print after
   }
   fn
-0:ERRETURN with "!"
+0:ERR_RETURN with "!"
 >before
 >after
 
@@ -553,7 +553,7 @@ F:Must be tested with a top-level script rather than source or function
       print after
   }
   fn
-1:ERRETURN with "!" and a following false
+1:ERR_RETURN with "!" and a following false
 >before
 
   fn() {
@@ -566,7 +566,7 @@ F:Must be tested with a top-level script rather than source or function
       print after
   }
   fn
-0:ERRETURN with "!" suppressed inside complex structure
+0:ERR_RETURN with "!" suppressed inside complex structure
 >before
 >after
 
@@ -580,9 +580,22 @@ F:Must be tested with a top-level script rather than source or function
       print after
   }
   fn
-1:ERRETURN with no "!" suppression (control case)
+1:ERR_RETURN with no "!" suppression (control case)
 >before
 
+  (setopt err_return
+    fn() {
+      print before-in
+      false && false
+    }
+    print before-out
+    fn
+    print after-out
+  )
+1:ERR_RETURN with "&&" in function (regression test)
+>before-out
+>before-in
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 3%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-05 13:47  3%         ` Peter Stephenson
@ 2016-10-06  8:36  5%           ` Peter Stephenson
  2016-10-06 11:22  9%           ` Martijn Dekker
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2016-10-06  8:36 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 5 Oct 2016 14:47:03 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> Please reassure me that this is correct:
> 
> % ./zsh -fc 'set -e; foo() { false && false; echo OK; }; foo; echo $?'
> OK
> 0
> 
> We hit the first "false" in the &&, which doesn't trigger ERR_EXIT so
> the second "false" that would is never executed; therefore we proceed to
> "echo OK"; therefore the status of the function is 0.  If there's no
> controversy I may add this as a test case for future reference, together
> with the "true & false" case that causes the function to be aborted.

Here are corresponding tests.  Nothing fundamentally new compared with
previous tests, it's just a bit more complicated.

pws

diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 5057dcf..74b83f3 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -596,6 +596,36 @@ F:Must be tested with a top-level script rather than source or function
 >before-out
 >before-in
 
+  (setopt err_return
+    fn() {
+      print before-in
+      false && false
+      print after-in
+    }
+    print before-out
+    fn
+    print after-out
+  )
+0:ERR_RETURN not triggered on LHS of "&&" in function
+>before-out
+>before-in
+>after-in
+>after-out
+
+  (setopt err_return
+    fn() {
+      print before-in
+      true && false
+      print after-in
+    }
+    print before-out
+    fn
+    print after-out
+  )
+1:ERR_RETURN triggered on RHS of "&&" in function
+>before-out
+>before-in
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 5%]

* Re: 'set -e' with '!' POSIX issue
  2016-10-05 13:47  3%         ` Peter Stephenson
  2016-10-06  8:36  5%           ` Peter Stephenson
@ 2016-10-06 11:22  9%           ` Martijn Dekker
  1 sibling, 0 replies; 200+ results
From: Martijn Dekker @ 2016-10-06 11:22 UTC (permalink / raw)
  To: Zsh hackers list

Op 05-10-16 om 15:47 schreef Peter Stephenson:
> Please reassure me that this is correct:
> 
> % ./zsh -fc 'set -e; foo() { false && false; echo OK; }; foo; echo $?'
> OK
> 0

Looks correct to me. It's consistent with the POSIX description and
bash, (d)ash, yash, ksh93, mksh/pdksh all behave the same.

- M.


^ permalink raw reply	[relevance 9%]

* 'export -p' lacks POSIX output
@ 2016-10-22  3:02  5% Martijn Dekker
  2016-10-22 18:24  9% ` Bart Schaefer
  2016-10-28 21:00  9% ` exported unset variables [was: 'export -p' lacks POSIX output] Martijn Dekker
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2016-10-22  3:02 UTC (permalink / raw)
  To: Zsh hackers list

The command 'export -p' always outputs 'typeset' commands. If
POSIXBUILTINS is active, it should output 'export' commands.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_22_03
| When -p is specified, export shall write to the standard output the
| names and values of all exported variables, in the following format:
|
| "export %s=%s\n", <name>, <value>
|
| if name is set, and:
|
| "export %s\n", <name>
|
| if name is unset.

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: 'export -p' lacks POSIX output
  2016-10-22  3:02  5% 'export -p' lacks POSIX output Martijn Dekker
@ 2016-10-22 18:24  9% ` Bart Schaefer
  2016-10-23 12:00 11%   ` Martijn Dekker
  2016-10-24  8:33  5%   ` Peter Stephenson
  2016-10-28 21:00  9% ` exported unset variables [was: 'export -p' lacks POSIX output] Martijn Dekker
  1 sibling, 2 replies; 200+ results
From: Bart Schaefer @ 2016-10-22 18:24 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 22,  5:02am, Martijn Dekker wrote:
} Subject: 'export -p' lacks POSIX output
}
} The command 'export -p' always outputs 'typeset' commands. If
} POSIXBUILTINS is active, it should output 'export' commands.

Would anyone object if this just happened all the time, rather than
depending on POSIXBUILTINS + "export"?

The decision of what command name to print is buried way down in the
depths of hash table scanning callbacks, which although it could test
for POSIXBUILTINS, has no knowledge of the original command name used
to invoke the scan.  (This is a bugaboo for the zsh/param/private
module, so I'm pretty intimately familiar with it at this point.)

More explicitly,

    typeset -x foo=bar
    typeset -p foo

would print

    export foo=bar

even if POSIXBUILTINS were not set.


^ permalink raw reply	[relevance 9%]

* Re: 'export -p' lacks POSIX output
  2016-10-22 18:24  9% ` Bart Schaefer
@ 2016-10-23 12:00 11%   ` Martijn Dekker
  2016-10-23 16:47  9%     ` Bart Schaefer
  2016-10-24  8:33  5%   ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2016-10-23 12:00 UTC (permalink / raw)
  To: Zsh hackers list

Op 22-10-16 om 20:24 schreef Bart Schaefer:
> Would anyone object if this just happened all the time, rather than
> depending on POSIXBUILTINS + "export"?

After the patch, variables with a non-scalar type get output such as:

export -i10 SHLVL=2

Option flags to 'export' other than -p are not POSIX, and POSIX
specifies output without any flags for 'export -p'.

Maybe that implies that commands like 'export -p' and 'trap' should
generate commands suitable for any POSIX shell. This would mean the
$'...' quoting method should also be deactivated. It may become POSIX at
some point, but it's anyone's guess how long that will take, and then
shells have to implement it. Then again, POSIX says the input should be
"suitable for reinput to the shell", not "suitable for reinput to any
POSIX shell".[*]

In any case, if the output needs to be conditional upon POSIXBUILTINS
anyway, I reckon you might as well not change the behaviour at all if
POSIXBUILTINS is not active.

- M.

[*]
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_22_04


^ permalink raw reply	[relevance 11%]

* Re: 'export -p' lacks POSIX output
  2016-10-23 12:00 11%   ` Martijn Dekker
@ 2016-10-23 16:47  9%     ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-10-23 16:47 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 23,  2:00pm, Martijn Dekker wrote:
} Subject: Re: 'export -p' lacks POSIX output
}
} Op 22-10-16 om 20:24 schreef Bart Schaefer:
} > Would anyone object if this just happened all the time, rather than
} > depending on POSIXBUILTINS + "export"?
} 
} After the patch, variables with a non-scalar type get output such as:
} 
} export -i10 SHLVL=2
} 
} Option flags to 'export' other than -p are not POSIX, and POSIX
} specifies output without any flags for 'export -p'.

We may have to settle for incompatibility here.  As I mentioned, there
is no way (without either a large code change or introducing yet another
global variable [*]) for the code that prints the command name to know
whether "typeset -p", "declare -p", "export -p", etc. were used.  If the
non-string (note, integer is not non-scalar) flags are eliminated, the
state won't be properly reflected if the commands are re-input.

If you're writing a POSIX-compatible script you shouldn't declare anything
integer in the first place, should you?

} In any case, if the output needs to be conditional upon POSIXBUILTINS
} anyway, I reckon you might as well not change the behaviour at all if
} POSIXBUILTINS is not active.

The selection of the command name to print and the output of the type
dinstinction flags are in separate sections of the code, so that's not
really a concern.  I think the addition of -g for typeset of non-local
parameters in function scope is useful (waiting to hear if anyone has
objections) and that doesn't depend on POSIXBUILTINS.

[*] Of course if such a variable WERE introduced I could take advantage
of it in zsh/param/private.  I was trying to avoid invasive changes for
that module but if it's needed for other reasons I'd be less shy.


^ permalink raw reply	[relevance 9%]

* Re: 'export -p' lacks POSIX output
  2016-10-22 18:24  9% ` Bart Schaefer
  2016-10-23 12:00 11%   ` Martijn Dekker
@ 2016-10-24  8:33  5%   ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2016-10-24  8:33 UTC (permalink / raw)
  To: Zsh hackers list

On Sat, 22 Oct 2016 11:24:23 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Oct 22,  5:02am, Martijn Dekker wrote:
> } Subject: 'export -p' lacks POSIX output
> }
> } The command 'export -p' always outputs 'typeset' commands. If
> } POSIXBUILTINS is active, it should output 'export' commands.
> 
> Would anyone object if this just happened all the time, rather than
> depending on POSIXBUILTINS + "export"?

That sounds reasonable and probably clearer; the one thing to be careful
about is that "export" is actually equivalent to "typeset -gx".

pws


^ permalink raw reply	[relevance 5%]

* [PATCH] _awk: support gawk ver.3 and 4
@ 2016-10-26 14:07 16% Jun T.
  2016-11-03 12:53  6% ` Oliver Kiddle
  0 siblings, 1 reply; 200+ results
From: Jun T. @ 2016-10-26 14:07 UTC (permalink / raw)
  To: zsh-workers

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

Add support for gawk ver.3 and 4 in _awk.
The new _awk is also attached just for convenience.
Any comments are welcome.

Jun


diff --git a/Completion/Unix/Command/_awk b/Completion/Unix/Command/_awk
index c493c3b..a3b2422 100644
--- a/Completion/Unix/Command/_awk
+++ b/Completion/Unix/Command/_awk
@@ -1,21 +1,119 @@
-#compdef awk
-
-# completions for awk
-# This only aims to complete POSIX awk options, as described in
-# awk(P). Most awk implementations, such as gawk and mawk, will have
-# additional options that this does not complete. Also, currently
-# this completion does not allow everything that POSIX allows. For
-# example, awk(P) states that the user may specify assignments
-# without using the -v option; this does not support that.
+#compdef awk gawk
+
+# For gawk ver.3 and 4, in addition to POSIX.
+#
+# gawk's options '-W ...' (such as '-W help') are not supported.
+# gawk3 has some synomyms for long options (e.g., --compat is a synomym
+# for --traditional). These are not supported either.
 #
-# In addition, the "program text" completion is not perfect. For
-# instance, type "awk -" and then hit tab. You will be presented
-# both with the dashed options and with the "program text" option.
-# Fixing this is beyond my current _arguments expertise--help
-# appreciated.
-
-_arguments -S -s '-F+[define input field separator to be an extended regular expression]:extended regular expression:' \
-    '*-v+[assign values to variables]:assignment:' \
-    '(1)-f+[program file]:program file:_files' \
-    '1:program text:' \
-    '*:input files:_files'
+# 'gawk -f<TAB>' will complete files in AWKPATH in addition to those in
+# the current directory. If this is annoying, you may try
+#   zstyle ':completion:*:*:gawk:option-f-1:*' tag-order program-files
+
+local variant curcontext="$curcontext" state state_descr line ret=1
+local -A opt_args
+local -a args
+
+_pick_variant -r variant gawk4='GNU Awk 4' gawk3='GNU Awk 3' posix --version
+
+args=(
+  {-F+,--field-separator}'[define input field separator by extended regex]:extended regular expression:'
+  '*'{-v+,--assign}'[assign values to variables]:assignment:'
+  '(1)*'{-f+,--file}'[read program file]:program file:->script'
+  '1: :_guard "^-*" "program text"'
+  '*:input files:_files'
+)
+
+case $variant in
+  (gawk*)
+    args+=(
+      {-c,--traditional}'[run in compatibility mode]'
+      '(- : *)'{-C,--copyright}'[print copyright info and exit]'
+      {-d-,--dump-variables=-}'[print a sorted list of global variables]::output file:_files'
+      {-e,--source}'[pass program text in arg]:program text:'
+      '(1)'{-E+,--exec}'[like -f, but safer for CGI]:program file:->script'
+      '(- : *)'{-h,--help}'[print usage message and exit]'
+      {-L-,--lint=-}'[warn about dubious or non-portable constructs]::flag:((fatal\:"treat warnings as fatal error" invalid\:"warn only about thigs that are actually invalid"))'
+      {-n,--non-decimal-data}'[auto-detect octal/hexadecimal values in input]'
+      {-N,--use-lc-numeric}"[force use of locale's decimal point character]"
+      {-O,--optimize}'[enable optimization]'
+      {-p-,--profile=-}'[output profiling data to file]::output file:_files'
+      {-P,--posix}'[run in strict POSIX mode]'
+      {-r,--re-interval}'[enable interval expressions in regex matching]'
+      {-t,--lint-old}'[warn about non-portable constructs]'
+      '(- : *)'{-V,--version}'[print version info and exit]'
+    )
+    ;|
+  (gawk4)
+    args+=(
+      {-b,--characters-as-bytes}'[treat all input data as single-byte characters]'
+      {-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'
+      '*'{-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'
+      {-S,--sandbox}'[disable system(), redirections and dynamic extensions]'
+    )
+    ;;
+  (gawk3)
+    # one letter options are new in gawk4
+    args=( ${args:#(|\*)(|\(*\))-[cCdEhLnNtOpPreV]*} )
+    args+=(
+      '--gen-po[scan awk program and generate .po file on stdout]'
+    )
+    ;;
+  (*)
+    # remove long options
+    args=( ${args:#*--*} )
+esac
+
+_arguments -S -s -C : $args && ret=0
+
+# Complete files in . (current directory) and AWKPATH/AWKLIBPATH.
+# Use different tag/description for files in . even if . is in AWKPATH.
+_files_in_curdir_or_path() {
+  local expl pat1 pat2
+  if [[ -n $6 ]]; then  # $6 = 'so', 'dll' or ''
+    pat1="-g *.$6"
+    pat2="-g *.$6"
+  fi
+  if [[ $words[CURRENT] == */* || $variant != gawk* || \
+	-n $opt_args[(I)(-c|--traditional|-P|--posix)] ]]; then
+    _wanted $2 expl $3 _files $pat1 && ret=0
+  else
+    local prog='BEGIN {print ENVIRON["'$1'"]}'
+    local -aU paths
+    # split AWKPATH into paths, and replace null element by '.'.
+    paths=( "${(@)${(@s.:.)$(_call_program get-awk-env \
+			    $words[1] ${(q)prog})}:/#%/.}" )
+    if (( $paths[(I).] )); then
+      # If '.' is in paths, remove it; we will handle it separately
+      paths=( ${(@)paths:#.} )
+    else
+      # If '.' is not in paths, we should not complete files in '.'
+      pat1='-g *(-/)'
+    fi
+    if (( $#paths )); then
+      _alternative "${2}:${3}:_files ${(b)pat1}" \
+		  "${4}:${5}:_files -W paths ${(b)pat2}" && ret=0
+    else
+      _wanted $2 expl $3 _files $pat1 && ret=0
+    fi
+  fi
+}
+
+case $state in
+  (script)
+    _files_in_curdir_or_path AWKPATH program-files 'program file' \
+			    library-files 'library in AWKPATH'
+    ;;
+  (extension)
+    local ext=so
+    [[ $OSTYPE == cygwin* ]] && ext=dll
+    _files_in_curdir_or_path AWKLIBPATH extensions 'extension' \
+			    library-files 'extension in AWKLIBPATH' $ext
+    ;;
+esac
+
+return ret






[-- Attachment #2: _awk --]
[-- Type: application/octet-stream, Size: 4505 bytes --]

#compdef awk gawk

# For gawk ver.3 and 4, in addition to POSIX.
#
# gawk's options '-W ...' (such as '-W help') are not supported.
# gawk3 has some synomyms for long options (e.g., --compat is a synomym
# for --traditional). These are not supported either.
#
# 'gawk -f<TAB>' will complete files in AWKPATH in addition to those in
# the current directory. If this is annoying, you may try
#   zstyle ':completion:*:*:gawk:option-f-1:*' tag-order program-files

local variant curcontext="$curcontext" state state_descr line ret=1
local -A opt_args
local -a args

_pick_variant -r variant gawk4='GNU Awk 4' gawk3='GNU Awk 3' posix --version

args=(
  {-F+,--field-separator}'[define input field separator by extended regex]:extended regular expression:'
  '*'{-v+,--assign}'[assign values to variables]:assignment:'
  '(1)*'{-f+,--file}'[read program file]:program file:->script'
  '1: :_guard "^-*" "program text"'
  '*:input files:_files'
)

case $variant in
  (gawk*)
    args+=(
      {-c,--traditional}'[run in compatibility mode]'
      '(- : *)'{-C,--copyright}'[print copyright info and exit]'
      {-d-,--dump-variables=-}'[print a sorted list of global variables]::output file:_files'
      {-e,--source}'[pass program text in arg]:program text:'
      '(1)'{-E+,--exec}'[like -f, but safer for CGI]:program file:->script'
      '(- : *)'{-h,--help}'[print usage message and exit]'
      {-L-,--lint=-}'[warn about dubious or non-portable constructs]::flag:((fatal\:"treat warnings as fatal error" invalid\:"warn only about thigs that are actually invalid"))'
      {-n,--non-decimal-data}'[auto-detect octal/hexadecimal values in input]'
      {-N,--use-lc-numeric}"[force use of locale's decimal point character]"
      {-O,--optimize}'[enable optimization]'
      {-p-,--profile=-}'[output profiling data to file]::output file:_files'
      {-P,--posix}'[run in strict POSIX mode]'
      {-r,--re-interval}'[enable interval expressions in regex matching]'
      {-t,--lint-old}'[warn about non-portable constructs]'
      '(- : *)'{-V,--version}'[print version info and exit]'
    )
    ;|
  (gawk4)
    args+=(
      {-b,--characters-as-bytes}'[treat all input data as single-byte characters]'
      {-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'
      '*'{-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'
      {-S,--sandbox}'[disable system(), redirections and dynamic extensions]'
    )
    ;;
  (gawk3)
    # one letter options are new in gawk4
    args=( ${args:#(|\*)(|\(*\))-[cCdEhLnNtOpPreV]*} )
    args+=(
      '--gen-po[scan awk program and generate .po file on stdout]'
    )
    ;;
  (*)
    # remove long options
    args=( ${args:#*--*} )
esac

_arguments -S -s -C : $args && ret=0

# Complete files in . (current directory) and AWKPATH/AWKLIBPATH.
# Use different tag/description for files in . even if . is in AWKPATH.
_files_in_curdir_or_path() {
  local expl pat1 pat2
  if [[ -n $6 ]]; then  # $6 = 'so', 'dll' or ''
    pat1="-g *.$6"
    pat2="-g *.$6"
  fi
  if [[ $words[CURRENT] == */* || $variant != gawk* || \
	-n $opt_args[(I)(-c|--traditional|-P|--posix)] ]]; then
    _wanted $2 expl $3 _files $pat1 && ret=0
  else
    local prog='BEGIN {print ENVIRON["'$1'"]}'
    local -aU paths
    # split AWKPATH into paths, and replace null element by '.'.
    paths=( "${(@)${(@s.:.)$(_call_program get-awk-env \
			    $words[1] ${(q)prog})}:/#%/.}" )
    if (( $paths[(I).] )); then
      # If '.' is in paths, remove it; we will handle it separately
      paths=( ${(@)paths:#.} )
    else
      # If '.' is not in paths, we should not complete files in '.'
      pat1='-g *(-/)'
    fi
    if (( $#paths )); then
      _alternative "${2}:${3}:_files ${(b)pat1}" \
		  "${4}:${5}:_files -W paths ${(b)pat2}" && ret=0
    else
      _wanted $2 expl $3 _files $pat1 && ret=0
    fi
  fi
}

case $state in
  (script)
    _files_in_curdir_or_path AWKPATH program-files 'program file' \
			    library-files 'library in AWKPATH'
    ;;
  (extension)
    local ext=so
    [[ $OSTYPE == cygwin* ]] && ext=dll
    _files_in_curdir_or_path AWKLIBPATH extensions 'extension' \
			    library-files 'extension in AWKLIBPATH' $ext
    ;;
esac

return ret

^ permalink raw reply	[relevance 16%]

* zsh silently abandons compound command on trying to write to a closed file descriptor
@ 2016-10-27 17:21  3% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2016-10-27 17:21 UTC (permalink / raw)
  To: Zsh hackers list

zsh misbehaves if a redirection produces an error due to writing to a
closed file descriptor. For instance,

    echo hi >&- || echo oops

doesn't output "oops" as expected. But the shell is not exited, only the
current compound command is apparently abandoned -- silently, without an
error message or even a non-zero exit status.

Test script:

	echo hi >&- || ! echo oops
	echo $?

'zsh test.sh' and 'zsh -o posixbuiltins test.sh' both output 0 (and
nothing else). Expected output is an error message followed by "oops"
followed by 1.

Relevant POSIX text is at:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_08_01

Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-22  3:02  5% 'export -p' lacks POSIX output Martijn Dekker
  2016-10-22 18:24  9% ` Bart Schaefer
@ 2016-10-28 21:00  9% ` Martijn Dekker
  2016-10-28 21:31  5%   ` Bart Schaefer
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2016-10-28 21:00 UTC (permalink / raw)
  To: Zsh hackers list

Op 22-10-16 om 04:02 schreef Martijn Dekker:
> The command 'export -p' always outputs 'typeset' commands. If
> POSIXBUILTINS is active, it should output 'export' commands.
> 
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_22_03
> | When -p is specified, export shall write to the standard output the
> | names and values of all exported variables, in the following format:
> |
> | "export %s=%s\n", <name>, <value>
> |
> | if name is set, and:
> |
> | "export %s\n", <name>
> |
> | if name is unset.

That reminds me that, in POSIX, there is such a thing as a variable that
is both exported and unset; the variable name gets the 'exported' flag
and will retain it if/when it is set later. Ref. as above.

In zsh, however, variables are automatically set to the empty value upon
being exported.

Back in April 2015, in zsh-workers/34991, I reported a similar issue for
readonly variables, which Peter fixed in the following three commits:

bf258a1c07a9cf1119f83d1d15310b02b94f4d67
60c6bcdeae6d132c0ab770cc8491055b24f7670e
f855801fb9ed82d2596f52f5b64dd66c42255c5f

zsh needs a similar fix for exported unset variables, presumably also
subject to the POSIXBUILTINS option.

Thanks,

- M.



^ permalink raw reply	[relevance 9%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-28 21:31  5%   ` Bart Schaefer
@ 2016-10-28 21:48  5%     ` Martijn Dekker
  2016-10-29  0:18  7%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-10-28 21:48 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

Op 28-10-16 om 22:31 schreef Bart Schaefer:
> On Oct 28, 10:00pm, Martijn Dekker wrote:
> }
> } In zsh, however, variables are automatically set to the empty value upon
> } being exported.
> 
> That's no longer true subsequent to my "export -p" patch:
> 
> torch% export XYZPDQ
> torch% export -p | grep XYZPDQ
> export XYZPDQ
> torch% printenv | grep XYZPDQ
> torch% 
> 
> Unless there's some other nuance here that I'm missing?

Hmm... With current git version:

$ PS1='%% ' Src/zsh -f -o posixbuiltins
% unset -v var
% export var
% echo ${var+s}  # this shows it as set (should be unset)
s
% export -p var  # but this shows it as unset
export var
% var=''
% export -p var  # 'export' knows if it's set or not, ${var+s} doesn't?
export var=''

So, currently, ${var+s} doesn't correctly represent that an exported
'var' is unset.

(Also, is it correct/expected behaviour that zsh doesn't parse comments
on the interactive command line? Blindly copying/pasting the above won't
work for that reason.)

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-28 21:48  5%     ` Martijn Dekker
@ 2016-10-29  0:18  7%       ` Bart Schaefer
  2016-10-29  8:11  5%         ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-10-29  0:18 UTC (permalink / raw)
  To: Zsh hackers list; +Cc: Martijn Dekker

[It's once again taking a long time for some messages to reach the
mailing list.  My first message on this thread hasn't even shown up
there yet.]

On Oct 28, 10:48pm, Martijn Dekker wrote:
}
} $ PS1='%% ' Src/zsh -f -o posixbuiltins
} % unset -v var
} % export var
} % echo ${var+s}  # this shows it as set (should be unset)
} s
} % export -p var  # but this shows it as unset
} export var

Ah, I see.  Yes, I mentioned this in the email about the patch.  The
shell variable named "var" becomes set upon being exported, but the
environment copy remains unset until explicitly assigned.  Zsh has
always distinguished the shell variable from the exported variable,
even though the value of the exported variable (if any) is stored in
the data structure for the shell variable.

All my patch did was cause "export -p" to output the state of the
environment variable instead of the state of the shell variable.

See if the patch below will help.

} (Also, is it correct/expected behaviour that zsh doesn't parse comments
} on the interactive command line? Blindly copying/pasting the above won't
} work for that reason.)

Yes, the option INTERACTIVE_COMMENTS has to be set to recognize comments
at the command line.  Should this be on in POSIX mode?


diff --git a/Src/builtin.c b/Src/builtin.c
index 2db739f..183ed45 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2008,11 +2008,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      * handled in createparam().  Here we just avoid using it for the
      * present tests if it's unset.
      *
-     * POSIXBUILTINS horror: we need to retain the 'readonly' flag
-     * of an unset parameter.
+     * POSIXBUILTINS horror: we need to retain the 'readonly' or 'export'
+     * flags of an unset parameter.
      */
     usepm = pm && (!(pm->node.flags & PM_UNSET) ||
-		   (isset(POSIXBUILTINS) && (pm->node.flags & PM_READONLY)));
+		   (isset(POSIXBUILTINS) &&
+		    (pm->node.flags & (PM_READONLY|PM_EXPORTED))));
 
     /*
      * We need to compare types with an existing pm if special,
@@ -2135,7 +2136,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	/*
 	 * Stricter rules about retaining readonly attribute in this case.
 	 */
-	if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) &&
+	if ((on & (PM_READONLY|PM_EXPORTED)) &&
+	    (!usepm || (pm->node.flags & PM_UNSET)) &&
 	    !ASG_VALUEP(asg))
 	    on |= PM_UNSET;
 	else if (usepm && (pm->node.flags & PM_READONLY) &&


^ permalink raw reply	[relevance 7%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-28 21:00  9% ` exported unset variables [was: 'export -p' lacks POSIX output] Martijn Dekker
@ 2016-10-28 21:31  5%   ` Bart Schaefer
  2016-10-28 21:48  5%     ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-10-28 21:31 UTC (permalink / raw)
  To: Martijn Dekker, Zsh hackers list

On Oct 28, 10:00pm, Martijn Dekker wrote:
}
} In zsh, however, variables are automatically set to the empty value upon
} being exported.

That's no longer true subsequent to my "export -p" patch:

torch% export XYZPDQ
torch% export -p | grep XYZPDQ
export XYZPDQ
torch% printenv | grep XYZPDQ
torch% 

Unless there's some other nuance here that I'm missing?

Even before this patch "typeset" would report that the exported variable
was set to the empty string, but zsh did not modify the environment unless
an empty string were actually assigned.


^ permalink raw reply	[relevance 5%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-29  0:18  7%       ` Bart Schaefer
@ 2016-10-29  8:11  5%         ` Martijn Dekker
  2016-10-29 18:09  6%           ` Bart Schaefer
  2016-10-29 19:05  9%           ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2016-10-29  8:11 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

Op 29-10-16 om 01:18 schreef Bart Schaefer:
[...]
> All my patch did was cause "export -p" to output the state of the
> environment variable instead of the state of the shell variable.

Understood.

> See if the patch below will help.

Seems like it's about halfway there:

$ PS1='%% ' Src/zsh -f -o posixbuiltins
% export var; echo ${var+set} ${var-unset}; typeset -p var
unset
export var
% var=; echo ${var+set} ${var-unset}; typeset -p var
set
typeset var=''

The variable name loses its export attribute upon assignment; it should
retain it.

> } (Also, is it correct/expected behaviour that zsh doesn't parse comments
> } on the interactive command line? Blindly copying/pasting the above won't
> } work for that reason.)
> 
> Yes, the option INTERACTIVE_COMMENTS has to be set to recognize comments
> at the command line.  Should this be on in POSIX mode?

I think so. All the other shells recognise comments in interactive mode
by default. The spec for comments at
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_03
(#9) does not distinguish between interactive and non-interactive shells.

Thanks,

- M.


^ permalink raw reply	[relevance 5%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-29  8:11  5%         ` Martijn Dekker
@ 2016-10-29 18:09  6%           ` Bart Schaefer
  2016-10-29 18:43  9%             ` Peter Stephenson
  2016-10-29 19:05  9%           ` Bart Schaefer
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2016-10-29 18:09 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 29,  9:11am, Martijn Dekker wrote:
} Subject: Re: exported unset variables [was: 'export -p' lacks POSIX output
}
} % var=; echo ${var+set} ${var-unset}; typeset -p var
} set
} typeset var=''
} 
} The variable name loses its export attribute upon assignment; it should
} retain it.

That one potentially gets rather ugly; consider:

% setopt POSIXBUILTINS
% export var
% var=()
zsh: var: attempt to assign array value to non-array

Is that OK with everyone?

As an aside, zsh currently allows the export flag to be applied to array
variables, but then will not put them in the environment.  Patch below
revises 39704 to use "typeset -xa ary" rather than "export -a ary".

Replaces 39754.


diff --git a/Src/builtin.c b/Src/builtin.c
index 2db739f..986ace2 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -2008,11 +2008,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      * handled in createparam().  Here we just avoid using it for the
      * present tests if it's unset.
      *
-     * POSIXBUILTINS horror: we need to retain the 'readonly' flag
-     * of an unset parameter.
+     * POSIXBUILTINS horror: we need to retain the 'readonly' or 'export'
+     * flags of an unset parameter.
      */
     usepm = pm && (!(pm->node.flags & PM_UNSET) ||
-		   (isset(POSIXBUILTINS) && (pm->node.flags & PM_READONLY)));
+		   (isset(POSIXBUILTINS) &&
+		    (pm->node.flags & (PM_READONLY|PM_EXPORTED))));
 
     /*
      * We need to compare types with an existing pm if special,
@@ -2135,7 +2136,8 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	/*
 	 * Stricter rules about retaining readonly attribute in this case.
 	 */
-	if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) &&
+	if ((on & (PM_READONLY|PM_EXPORTED)) &&
+	    (!usepm || (pm->node.flags & PM_UNSET)) &&
 	    !ASG_VALUEP(asg))
 	    on |= PM_UNSET;
 	else if (usepm && (pm->node.flags & PM_READONLY) &&
@@ -2143,6 +2145,10 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	    zerr("read-only variable: %s", pm->node.nam);
 	    return NULL;
 	}
+	/* This is handled by createparam():
+	if (usepm && (pm->node.flags & PM_EXPORTED) && !(off & PM_EXPORTED))
+	    on |= PM_EXPORTED;
+	*/
     }
 
     /*
diff --git a/Src/params.c b/Src/params.c
index 3084b1f..330f22b 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -940,7 +940,10 @@ createparam(char *name, int flags)
 		zerr("%s: restricted", name);
 		return NULL;
 	    }
-	    if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL)) {
+	    if (!(oldpm->node.flags & PM_UNSET) ||
+		(oldpm->node.flags & PM_SPECIAL) ||
+		/* POSIXBUILTINS horror: we need to retain 'export' flags */
+		(isset(POSIXBUILTINS) && (oldpm->node.flags & PM_EXPORTED))) {
 		oldpm->node.flags &= ~PM_UNSET;
 		if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) {
 		    Param altpm =
@@ -5225,10 +5228,6 @@ printparamvalue(Param p, int printflags)
 {
     char *t, **u;
 
-    if ((p->node.flags & PM_EXPORTED) && !p->env) {
-	putchar('\n');
-	return;
-    }
     if (printflags & PRINT_KV_PAIR)
 	putchar(' ');
     else
@@ -5332,7 +5331,8 @@ printparamnode(HashNode hn, int printflags)
 	}
 	if (locallevel && p->level >= locallevel) {
 	    printf("typeset ");	    /* printf("local "); */
-	} else if (p->node.flags & PM_EXPORTED) {
+	} else if ((p->node.flags & PM_EXPORTED) &&
+		   !(p->node.flags & (PM_ARRAY|PM_HASHED))) {
 	    printf("export ");
 	} else if (locallevel) {
 	    printf("typeset -g ");
@@ -5350,8 +5350,8 @@ printparamnode(HashNode hn, int printflags)
 	    if (pmptr->flags & PMTF_TEST_LEVEL) {
 		if (p->level)
 		    doprint = 1;
-	    } else if ((pmptr->binflag != PM_EXPORTED ||
-			((p->node.flags & PM_LOCAL) || p->level)) &&
+	    } else if ((pmptr->binflag != PM_EXPORTED || p->level ||
+			(p->node.flags & (PM_LOCAL|PM_ARRAY|PM_HASHED))) &&
 		       (p->node.flags & pmptr->binflag))
 		doprint = 1;
 


^ permalink raw reply	[relevance 6%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-29 18:09  6%           ` Bart Schaefer
@ 2016-10-29 18:43  9%             ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-10-29 18:43 UTC (permalink / raw)
  To: Zsh hackers list

On Sat, 29 Oct 2016 11:09:04 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> That one potentially gets rather ugly; consider:
> 
> % setopt POSIXBUILTINS
> % export var
> % var=()
> zsh: var: attempt to assign array value to non-array
> 
> Is that OK with everyone?

We've generally taken the attitude that POSIX copmliance settings aren't
intended to be useful to native zsh users, just compatible for everyone
else, so what it used to do isn't a big issue.  I think this fits in
that category.

I don't think exporting arrays would be that hard, but if you want to do
it, the right way is probably to use "typeset -T" and specify which
character you want the elements to be joined with.

pws


^ permalink raw reply	[relevance 9%]

* Re: exported unset variables [was: 'export -p' lacks POSIX output]
  2016-10-29  8:11  5%         ` Martijn Dekker
  2016-10-29 18:09  6%           ` Bart Schaefer
@ 2016-10-29 19:05  9%           ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2016-10-29 19:05 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 29,  9:11am, Martijn Dekker wrote:
}
} > } (Also, is it correct/expected behaviour that zsh doesn't parse comments
} > } on the interactive command line? Blindly copying/pasting the above won't
} > } work for that reason.)
} > 
} > Yes, the option INTERACTIVE_COMMENTS has to be set to recognize comments
} > at the command line.  Should this be on in POSIX mode?
} 
} I think so. All the other shells recognise comments in interactive mode
} by default.

Hmm, it looks like this is already the case; if I invoke zsh as "ksh":

$ setopt | grep comment
nointeractivecomments off

And indeed the source gives interactivecomments the OPT_BOURNE flag.

The only other thing might be to also give it the OPT_EMULATE flag, but
I'm uncertain about that.  In what circumstances are you encountering
difficulty with this?


^ permalink raw reply	[relevance 9%]

* Re: [PATCH] _awk: support gawk ver.3 and 4
  2016-10-26 14:07 16% [PATCH] _awk: support gawk ver.3 and 4 Jun T.
@ 2016-11-03 12:53  6% ` Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2016-11-03 12:53 UTC (permalink / raw)
  To: zsh-workers

On 26 Oct, "Jun T." wrote:
> Add support for gawk ver.3 and 4 in _awk.
> Any comments are welcome.

All looks good.

Only thing that came to mind is that we should use the function for nawk
too.

Oliver

diff --git a/Completion/Unix/Command/_awk b/Completion/Unix/Command/_awk
index a3b2422..cdae8c7 100644
--- a/Completion/Unix/Command/_awk
+++ b/Completion/Unix/Command/_awk
@@ -1,4 +1,4 @@
-#compdef awk gawk
+#compdef awk gawk nawk
 
 # For gawk ver.3 and 4, in addition to POSIX.
 #


^ permalink raw reply	[relevance 6%]

* Re: "invalid arguments" in cpio completion
  @ 2016-11-05 21:52  3%   ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-11-05 21:52 UTC (permalink / raw)
  To: zsh-workers

On Nov 5,  8:39pm, Daniel Shahaf wrote:
}
} Danek Duvall wrote on Thu, Nov 03, 2016 at 13:32:56 -0700:
} > 
} >     $ local args
} >     $ args+=(a b c)
} >     $ print -l -- "$args[@]"
} > 
} >     a
} >     b
} >     c
} > 
} 
} This behaviour is the same in HEAD.

That's not new behavior; using array-append on a scalar converts the
scalar into a 1-element array before appending to it.

The question is whether an empty scalar should be converted into a
1-element array or an empty array.  This goes back to the fact that
in zsh without posixbuiltins, a declared variable is implicitly set,
and therefore its value is the empty string.

BTW, in the current HEAD zsh *with* posixbuiltins, attempting to
assign an array to an exported scalar will result in an error message
*but also* causes the scalar to become set (to empty).  I'm not sure
what if anything posix compatibility would say about this.


^ permalink raw reply	[relevance 3%]

* 'exit' in trap handler does not execute EXIT trap
@ 2016-11-07 18:18  3% ` Martijn Dekker
  2016-11-08 12:47  0%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2016-11-07 18:18 UTC (permalink / raw)
  To: Zsh hackers list

zsh does not execute the EXIT trap if the trap handler for another trap
exits the shell. I cannot find anything about this in the POSIX spec,
but this is different from all the other shells, which do execute the
EXIT trap.

Test script:

trap 'echo TERM; exit' TERM
trap 'echo EXIT' EXIT
kill -s TERM "$$"
echo 'FATAL: we should never get here!' 1>&2
exit 1

Actual output: TERM
Expected output: TERM\nEXIT

Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* Re: 'exit' in trap handler does not execute EXIT trap
  2016-11-07 18:18  3% ` 'exit' in trap handler does not execute EXIT trap Martijn Dekker
@ 2016-11-08 12:47  0%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-11-08 12:47 UTC (permalink / raw)
  To: Zsh hackers list

On Mon, 7 Nov 2016 18:18:47 +0000
Martijn Dekker <martijn@inlv.org> wrote:
> zsh does not execute the EXIT trap if the trap handler for another trap
> exits the shell. I cannot find anything about this in the POSIX spec,
> but this is different from all the other shells, which do execute the
> EXIT trap.

diff --git a/Src/builtin.c b/Src/builtin.c
index 6c9d058..6969719 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5435,6 +5435,11 @@ zexit(int val, int from_where)
 	}
     }
     lastval = val;
+    /*
+     * Now we are committed to exiting any previous state
+     * is irrelevant.  Ensure trap can run.
+     */
+    errflag = intrap = 0;
     if (sigtrapped[SIGEXIT])
 	dotrap(SIGEXIT);
     callhookfunc("zshexit", NULL, 1, NULL);
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 74b83f3..828a3d1 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -626,6 +626,21 @@ F:Must be tested with a top-level script rather than source or function
 >before-out
 >before-in
 
+  if zmodload zsh/system 2>/dev/null; then
+  (
+    trap 'echo TERM; exit 2' TERM
+    trap 'echo EXIT' EXIT
+    kill -s TERM "$sysparams[pid]"
+    echo 'FATAL: we should never get here!' 1>&2
+    exit 1
+  )
+  else
+    ZTST_skip="zsh/system library not found."
+  fi
+2:EXIT trap from TERM trap
+>TERM
+>EXIT
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 0%]

* PATCH: typo corrections in completion functions
@ 2016-11-09 14:52  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2016-11-09 14:52 UTC (permalink / raw)
  To: Zsh workers

The _tmux typos reminded me that I haven't run a check for spelling and
typo errors in a few years.

Oliver

diff --git a/Completion/Debian/Command/_dcut b/Completion/Debian/Command/_dcut
index 210d544..fb1ac7e 100644
--- a/Completion/Debian/Command/_dcut
+++ b/Completion/Debian/Command/_dcut
@@ -106,7 +106,7 @@ function _dcut() {
     (rm)
       # dcut rm arguments
       opts=(
-        '--searchdirs[search in all directores for the given files]'
+        '--searchdirs[search in all directories for the given files]'
         '1::file to be deleted:_files'
       )
       ;;
@@ -128,7 +128,7 @@ function _dcut() {
       opts=(
         '--uid[full name and address or GPG fingerprint of the Debian Maintainer]'
         '*--allow[grant permission to upload a source package]:source package'
-        '*--deny[remove permission to upload a source pckage]:source package'
+        '*--deny[remove permission to upload a source package]:source package'
       )
       ;;
     (reschedule)
@@ -142,7 +142,7 @@ function _dcut() {
       # dcut rm arguments
       opts=(
         '*'{-f,--filename}'[file name to be removed]:file name:_files'
-        '--searchdirs[search in all directores for the given files]'
+        '--searchdirs[search in all directories for the given files]'
       )
       ;;
     (upload)
diff --git a/Completion/Debian/Command/_git-buildpackage b/Completion/Debian/Command/_git-buildpackage
index a2dc656..c38edc1 100644
--- a/Completion/Debian/Command/_git-buildpackage
+++ b/Completion/Debian/Command/_git-buildpackage
@@ -4,7 +4,7 @@
 _arguments \
   '--version[show program version number and exit]' \
   '--help[show help message and exit]' \
-  '--git-ignore-new[build with uncommited changes in the source tree]' \
+  '--git-ignore-new[build with uncommitted changes in the source tree]' \
   '--git-no-ignore-new[negates --git-ignore-new]' \
   '--git-verbose[verbose command execution]' \
   '--git-tag[create a tag after a successful build]' \
@@ -40,4 +40,4 @@ _arguments \
   '--git-dont-purge[retain exported package build directory]' \
   '--git-overlay[extract orig tarball when using export-dir option]' \
   '--git-no-overlay[negates --git-overlay]' \
-  '*:Other options:_dpkg-buildpackage'
+  '*:other options:_dpkg-buildpackage'
diff --git a/Completion/Debian/Command/_lintian b/Completion/Debian/Command/_lintian
index 773e7a1..16af508 100644
--- a/Completion/Debian/Command/_lintian
+++ b/Completion/Debian/Command/_lintian
@@ -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 informations]:infos:_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 , "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' \
       '(-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/_make-kpkg b/Completion/Debian/Command/_make-kpkg
index 55adf88..252627a 100644
--- a/Completion/Debian/Command/_make-kpkg
+++ b/Completion/Debian/Command/_make-kpkg
@@ -40,7 +40,7 @@ _arguments -C \
         build\:"compiles the kernel" \
         modules\:"build all add-on modules" \
         modules-config\:"configure all add-on modules" \
-        modules-image\:"build all add-on modules, but wirhou source and diff files" \
+        modules-image\:"build all add-on modules, but without source and diff files" \
         modules-clean\:"clean add-on modules" \
         configure\:"configure the kernel" \
         debian\:"creates the debian/ directory" \
diff --git a/Completion/Linux/Command/_iwconfig b/Completion/Linux/Command/_iwconfig
index 30892fb..07c028b 100644
--- a/Completion/Linux/Command/_iwconfig
+++ b/Completion/Linux/Command/_iwconfig
@@ -50,7 +50,7 @@ if [[ -n "$state" ]]; then
       	'essid[set the network name]' \
 	'(nwid domain)'{nwid,domain}'[set the network ID]' \
 	'(freq channel)'{freq,channel}'[set the operating frequency or channel]' \
-	'sens[set the sensitivity threhold]' \
+	'sens[set the sensitivity threshold]' \
       	'mode[set operating mode]' \
 	'ap[register with given access point]' \
 	'(nick nickname)'nick{,name}'[set the nickname]' \
@@ -62,7 +62,7 @@ if [[ -n "$state" ]]; then
 	'txpower[set transmit power]' \
 	'retry[set number of retries]' \
 	'modu[force a specific set of modulations]' \
-	'commit[apply changes imediately]' && ret=0
+	'commit[apply changes immediately]' && ret=0
     ;;
   esac
 fi
diff --git a/Completion/Linux/Command/_mdadm b/Completion/Linux/Command/_mdadm
index 940eb68..b2af326 100644
--- a/Completion/Linux/Command/_mdadm
+++ b/Completion/Linux/Command/_mdadm
@@ -56,15 +56,15 @@ _layouts () {
         	                'f9[far copies]'
 			;;
 		faulty)
-			_values -S \  "Failure mode" \
+			_values -S \  "failure mode" \
 				{write-transient,wt}'[write-transient]' \
 				{read-transient,rt}'[read-transient]' \
-				{write-presistent,wp}'[write-presistent]' \
-				{read-presistent,rp}'[read-presistent]' \
+				{write-persistent,wp}'[write-persistent]' \
+				{read-persistent,rp}'[read-persistent]' \
 				write-all'[write-all]' \
 				{read-fixable,rf}'[read-fixable]' \
 				{clear,none}'[remove any pending or periodic failure modes]' \
-				flush'[clear any persistant faults]'
+				flush'[clear any persistent faults]'
 	esac
 }
 
diff --git a/Completion/Solaris/Command/_dladm b/Completion/Solaris/Command/_dladm
index 036c179..cb598de 100644
--- a/Completion/Solaris/Command/_dladm
+++ b/Completion/Solaris/Command/_dladm
@@ -682,7 +682,7 @@ _dladm() {
       '(-f --force)'{-f,--force}'[force partition creation]' \
       '(-l --link)'{-l,--link}'[IP-over-IB physical link name]:IB link:_dladm_iblinks' \
       '(-p --prop)'{-p,--prop}'[set link properties]:link property:_values -s , "property" ${(M)linkprops_nonvlanvnic\:#*\:*} ${(M)linkprops_general\:#*\:*}' \
-      '(-P --pkey)'{-P,--pkey}'[set parition key]:hex number:' \
+      '(-P --pkey)'{-P,--pkey}'[set partition key]:hex number' \
       ':partition link name:'
   ;;
 
diff --git a/Completion/Unix/Command/_adb b/Completion/Unix/Command/_adb
index 879e260..6b56d17 100644
--- a/Completion/Unix/Command/_adb
+++ b/Completion/Unix/Command/_adb
@@ -217,7 +217,7 @@ _adb_pm_list () {
     (permissions)
       _arguments -s '-g[organize by group]' \
       		    '-f[print all information]' \
-      		    '-d[only list dangerous pemissions]' \
+		    '-d[only list dangerous permissions]' \
       		    '-u[only list user visible permissions]' \
       		    '-s[short summary]' \
       		    ':'
@@ -282,7 +282,7 @@ _adb_activity_manager_handler () {
       _arguments -s '-r[print raw results]' \
       		    '-e[set argument NAME to VALUE]:<NAME> <VALUE>:' \
       		    '-p[write profiling data to FILE]:<FILE>:' \
-      		    '-w[wait for instrumenation to finish]' \
+		    '-w[wait for instrumentation to finish]' \
       		    ':'
       ;;
     (profile)
@@ -307,7 +307,7 @@ _adb_package_manager_handler () {
       (( $+functions[_adb_installed_packages] )) && _adb_installed_packages
       ;;
     (setInstallLocation)
-      _wanted set_installlcation expl 'install location' compadd -d "(0:auto 1:internal 2:external)" 0 1 2
+      _wanted install-locations expl 'install location' compadd -d "(0:auto 1:internal 2:external)" 0 1 2
       ;;
     (getInstallLocation)
       ;;
diff --git a/Completion/Unix/Command/_attr b/Completion/Unix/Command/_attr
index c7ca1b8..df1fb7d 100644
--- a/Completion/Unix/Command/_attr
+++ b/Completion/Unix/Command/_attr
@@ -21,11 +21,11 @@ case $service in
       '(-d --dump -n --name)'{-n+,--name=}'[dump the value of the named extended attribute]' \
       '(-n --name -d --dump)'{-d,--dump}'[dump the values of all extended attributes]' \
       '(-e --encoding)'{-e+,--encoding=}'[encode values after retrieving them]:encoding:(text hex base64)' \
-      '(-h --no-derference)'{-h,--no-dereference}'[do not follow symbolic links]' \
+      '(-h --no-dereference)'{-h,--no-dereference}"[don't follow symbolic links]" \
       '(-m --match)'{-m+,--match=}'[only include attributes with names matching regex]:regular expression' \
-      '--absolute-names[do not string leasing slash characters]' \
+      "--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 recurively]' \
+      '(-R --recursive)'{-R,--recursive}'[list attributes of all files and directories recursively]' \
       '(-P --physical -L --logical)'{-L,--logical}'[follow all symbolic links]' \
       '(-L --logical -P --physical)'{-P,--physical}'[skip all symbolic links]' \
       '(* -)--version[display version information]' \
@@ -39,7 +39,7 @@ case $service in
       '(-v --value)'{-v+,--value=}'[specify value for the attribute]' \
       '(-x --remove)'{-x+,--remove=}'[remove specified extended attribute]' \
       '(-n --name -v --value)--restore[restore extended attributes from dump file]:dump file:_files' \
-      '(-h --no-derference)'{-h,--no-dereference}'[do not follow symbolic links]' \
+      '(-h --no-dereference)'{-h,--no-dereference}"[don't follow symbolic links]" \
       '(* -)--version[display version information]' \
       '(* -)--help[display help information]' \
       '*:file:_files'
diff --git a/Completion/Unix/Command/_awk b/Completion/Unix/Command/_awk
index cdae8c7..9050c2f 100644
--- a/Completion/Unix/Command/_awk
+++ b/Completion/Unix/Command/_awk
@@ -3,7 +3,7 @@
 # For gawk ver.3 and 4, in addition to POSIX.
 #
 # gawk's options '-W ...' (such as '-W help') are not supported.
-# gawk3 has some synomyms for long options (e.g., --compat is a synomym
+# gawk3 has some synonyms for long options (e.g., --compat is a synonym
 # for --traditional). These are not supported either.
 #
 # 'gawk -f<TAB>' will complete files in AWKPATH in addition to those in
@@ -33,7 +33,7 @@ case $variant in
       {-e,--source}'[pass program text in arg]:program text:'
       '(1)'{-E+,--exec}'[like -f, but safer for CGI]:program file:->script'
       '(- : *)'{-h,--help}'[print usage message and exit]'
-      {-L-,--lint=-}'[warn about dubious or non-portable constructs]::flag:((fatal\:"treat warnings as fatal error" invalid\:"warn only about thigs that are actually invalid"))'
+      {-L-,--lint=-}'[warn about dubious or non-portable constructs]::flag:((fatal\:"treat warnings as fatal error" invalid\:"warn only about things that are actually invalid"))'
       {-n,--non-decimal-data}'[auto-detect octal/hexadecimal values in input]'
       {-N,--use-lc-numeric}"[force use of locale's decimal point character]"
       {-O,--optimize}'[enable optimization]'
diff --git a/Completion/Unix/Command/_bzr b/Completion/Unix/Command/_bzr
index 28ebd14..1b755b4 100644
--- a/Completion/Unix/Command/_bzr
+++ b/Completion/Unix/Command/_bzr
@@ -375,7 +375,7 @@ case $cmd in
 (gannotate|gblame|gpraise)
     args+=(
 	'--all[show annotations on all lines]'
-	'--plain[do not hightlight annotation lines]'
+	"--plain[don't highlight annotation lines]"
 	'*:files:_bzr_versionedFiles'
 	)
     ;;
diff --git a/Completion/Unix/Command/_cdrdao b/Completion/Unix/Command/_cdrdao
index ad1bf40..0c3cfb8 100644
--- a/Completion/Unix/Command/_cdrdao
+++ b/Completion/Unix/Command/_cdrdao
@@ -211,7 +211,7 @@ __cdrdao-simulate-or-write () {
     $_cdrdao_common_toc_device_args \
     $_cdrdao_speed_arg \
     '--multi[do not close the session after successful write]' \
-    '--overburn[allow overburing of medium]' \
+    '--overburn[allow overburning of medium]' \
     '--full-burn[force burning to the outer disk edge]' \
     $_cdrdao_capacity_arg \
     $_cdrdao_eject_arg \
diff --git a/Completion/Unix/Command/_devtodo b/Completion/Unix/Command/_devtodo
index dbc64f8..2380399 100644
--- a/Completion/Unix/Command/_devtodo
+++ b/Completion/Unix/Command/_devtodo
@@ -32,11 +32,11 @@ arg_generic=(
 	'--help[display help]'
 	'--version[display version]'
 	'--title[todo title]:string: '
-	'--date-format[strftime time formet]:time string: '
+	'--date-format[strftime time format]:time string:_date_formats'
 	'*--format[define format]:format:_todo_format'
 	'*--use-format[output format]:format:_todo_format'
 	'--sort[sort database]:sort expression:_todo_sort'
-	'--paranoid[paranoid parmissions etc]'
+	'--paranoid[paranoid permissions etc]'
 	'--database-loaders[loader order]:database loader: '
 	'--backup[backup database]:count: '
 	'--timeout[display timeout]:seconds: '
diff --git a/Completion/Unix/Command/_feh b/Completion/Unix/Command/_feh
index 322b1a3..a094e33 100644
--- a/Completion/Unix/Command/_feh
+++ b/Completion/Unix/Command/_feh
@@ -77,7 +77,7 @@ argument_postfix=(
 	'recursive'   '[recurse into subdirectories]'
 	'randomize'   '[randomize file list before displaying]'
 	'filelist'    '[read file list from this file]:file:_files'
-	'preload'     '[eliminate unlaodable images before displaying]'
+	'preload'     '[eliminate unloadable images before displaying]'
 	'full-screen' '[make the window fullscreen]'
 	'geometry'    '[limit window size]:geometry: '
 	'auto-zoom'   '[zoom picture to screen size]'
@@ -114,7 +114,7 @@ argument_postfix=(
 	'thumb-width' '[montage mode: Thumbnail width]:pixels: '
 	'thumb-height' '[montage mode: Thumbnail height]:pixels: '
 	'limit-width' '[montage mode: Limit montage width]:pixels: '
-	'limit-height' '[montage mode: Limit montage heihgt]:pixels: '
+	'limit-height' '[montage mode: Limit montage height]:pixels: '
 	'bg'          '[montage mode: Background image]:file:_files'
 	'alpha'       '[montage mode: Thumbnail transparency level]:integer: '
 	'font'        '[index mode: Thumbnail info font]:font: '
diff --git a/Completion/Unix/Command/_global b/Completion/Unix/Command/_global
index c4714cb..ffd8c0d 100644
--- a/Completion/Unix/Command/_global
+++ b/Completion/Unix/Command/_global
@@ -14,7 +14,7 @@ _arguments \
   '(--color)--color=-[color matches]::color:(always auto never)' \
   '(-d --definition)'{-d,--definition}'[print locations of definitions]' \
   '(-e --regexp :)'{-e,--regexp}'[specify pattern]:pattern:_global_tags' \
-  '(--encode-path)--encode-path=-[encode path charcters in hexadecimal representation]:format' \
+  '(--encode-path)--encode-path=-[encode path characters in hexadecimal representation]:format' \
   '(-F --first-match)'{-f,--first-match}'[stop searching if tag is found in current tag file]' \
   '(--from-here)--from-here=-[decide tag type by context]:line_path:' \
   '(-G --basic-regexp :)'{-G,--basic-regexp}'[specify basic regexp to use]:word:_global_tags' \
@@ -23,9 +23,9 @@ _arguments \
   '(-i --ignore-case)'{-i,--ignore-case}'[ignore case in patterns]' \
   '(-L --file-list)'{-L,--file-list}'[obtain files from file in addition to the arguments]:file:_files' \
   '(-l --local)'{-l,--local}'[print just objects which exist under the current directory]' \
-  '(--literal)--literal[use leteral search instead of regexp search]' \
+  '(--literal)--literal[use literal search instead of regexp search]' \
   '(-M --match-case)'{-m,--match-case}'[enable case sensitive search]' \
-  '(--match-part)--match-part=-[speficy how path name completion should match]::part:(first last all)' \
+  '(--match-part)--match-part=-[specify how path name completion should match]::part:(first last all)' \
   '(-n --nofilter)'{-n,--nofilter}'[suppress sort filter and path conversion filter]' \
   '(-O --only-other)'{-O,--only-other}'[search only text files]' \
   '(-o --other)'{-o,--other}'[search in other files, not just source files (with -g)]' \
diff --git a/Completion/Unix/Command/_groff b/Completion/Unix/Command/_groff
index 4f3b8c6..d78d654 100644
--- a/Completion/Unix/Command/_groff
+++ b/Completion/Unix/Command/_groff
@@ -27,7 +27,7 @@ _arguments \
 	'-I[add search dir for soelim]:directory:_files -/' \
 	'-l[send output to spooler program for printing]' \
 	'*-L[pass arg to spooler program]:spooler argument:' \
-	'-N[do not allow newlines within eqn delimeters]' \
+	"-N[don't allow newlines within eqn delimiters]" \
 	'-p[preprocess with pic]' \
 	'*-P[pass option to postprocessor]:option:' \
         '-R[preprocess with refer]' \
diff --git a/Completion/Unix/Command/_growisofs b/Completion/Unix/Command/_growisofs
index f67961f..741a751 100644
--- a/Completion/Unix/Command/_growisofs
+++ b/Completion/Unix/Command/_growisofs
@@ -218,7 +218,7 @@ else
     '-check-session[check old session for compliance against current rules]' \
     '-copyright[specify the path and file-name of the copyright file]' \
     '-d[omit trailing period from files that do not have a period]' \
-    '-D[do not use deep directory-realocation]' \
+    "-D[don't use deep directory-reallocation]" \
     '-dir-mode[specify the mode of directories]' \
     '-dvd-video[generate a DVD-Video compliant UDF file-system]' \
     '-f[follow symbolic links when generating the file system]' \
@@ -250,7 +250,7 @@ else
     {-nobak,-no-bak}'[do not include backup files on the ISO9660 file-system]' \
     '-force-rr[do not use the automatic Rock Ridge attribute-recognition for previous sessions]' \
     '-no-rr[do not use use the Rock Ridge attributes from previous sessions]' \
-    '-no-split-symlink-components[do not split the symbolic-link compontents]' \
+    "-no-split-symlink-components[don't split the symbolic-link components]" \
     '-no-split-symlink-fields[do not split the symbolic-link fields]' \
     '-o[output the ISO9660-file-system image to the given file]:ISO9660 image:_files' \
     '-pad[pad the end of the image by 150 sectors]' \
diff --git a/Completion/Unix/Command/_initctl b/Completion/Unix/Command/_initctl
index 6505e42..9d444c6 100644
--- a/Completion/Unix/Command/_initctl
+++ b/Completion/Unix/Command/_initctl
@@ -4,7 +4,7 @@
 
 typeset -g -a -U _initctl_events_list _initctl_eventargs_list
 
-# run show-config -e and if possible parse out all events and KEY= argumnts
+# run show-config -e and if possible parse out all events and KEY= arguments
 # otherwise provide some common values
 _initctl_fillarray_events_args ()
 {
@@ -169,7 +169,7 @@ _initctl()
   # define fallback completion function
   local cmd_completion_default=basic
 
-  # depending on which command was used, call different completion funtions
+  # depending on which command was used, call different completion functions
   case $service in
     initctl)
       _arguments "${common_args[@]}" '*::Initctl Commands:_initctl_command'
diff --git a/Completion/Unix/Command/_iostat b/Completion/Unix/Command/_iostat
index 6653a5d..88fc6a1 100644
--- a/Completion/Unix/Command/_iostat
+++ b/Completion/Unix/Command/_iostat
@@ -70,7 +70,7 @@ case $OSTYPE:l in
     args=(
       '-c[report percentage of time the system spent in user/system mode, dtrace probes and idling]'
       '-C[report extended disk statistics aggregated by controller id, when used with -x]'
-      '-d[report the number of kilobytes tranferred per second, tranfers per second and average service time]'
+      '-d[report kilobytes transferred per second, transfers per second and average service time]'
       '-D[report reads/writes per second and percentage disk utilization]'
       '-e[display device error summary statistics]'
       '-E[display all device error statistics]'
@@ -78,7 +78,7 @@ case $OSTYPE:l in
       '-I[report counts in each interval]'
       '-l[limit the number of disks included in the report]:number of disks'
       '-m[report file system mount points]'
-      '-M[display data throughtput in MB/sec instead of KB/sec]'
+      '-M[display data throughput in MB/sec instead of KB/sec]'
       '-n[display names in descriptive format]'
       '-p[report per-partition statistics]'
       '-P[report per-partition statistics only]'
@@ -98,7 +98,7 @@ case $OSTYPE:l in
       '-C[display CPU statistics]'
       '-c[number of times to display statistics]'
       '-d[display only device statistics]'
-      '-l[total statstics for a given time period]'
+      '-l[total statistics for a given time period]'
       '-K[display block count in kilobytes]'
       '-n[limit the number of disks included in the report]:number of disks'
       '-o[display old-style iostat device statistics]'
diff --git a/Completion/Unix/Command/_ip b/Completion/Unix/Command/_ip
index d9dd924..1ca3f1a 100644
--- a/Completion/Unix/Command/_ip
+++ b/Completion/Unix/Command/_ip
@@ -98,7 +98,7 @@ subcmd_lockmtu=("(" /$'lock\0'/ ":lock:lock:(lock)" "|" ")" $subcmd_number )
 local -a subcmd_nexthop
 _regex_words nexthop 'nexthop route keyword' \
     'via:specify nexthop router:$subcmd_ipaddr' \
-    'dev:sepcify output device:$subcmd_dev' \
+    'dev:specify output device:$subcmd_dev' \
     'weight:specify relative quality of route:$subcmd_number'
 subcmd_nexthop=("$reply[@]" "#")
 
@@ -107,7 +107,7 @@ _regex_words rtprotocol 'route protocol' \
   'redirect:installed from ICMP redirect' \
   'kernel:installed automatically by kernel' \
   'boot:installed during boot sequence' \
-  'static:installed by adminstrator' \
+  'static:installed by administrator' \
   'ra:installed by Router Discovery protocol'
 subcmd_rtprotocol=("$reply[@]")
 
@@ -175,7 +175,7 @@ _regex_words \
   'do*wn:change state do down' \
   'ar*p:change ARP flag on device:$subcmd_onoff' \
   'mu*lticast:change MULTICAST flag on device:$subcmd_onoff' \
-  'pr*omisc:set promiscious mode:$subcmd_onoff' \
+  'pr*omisc:set promiscuous mode:$subcmd_onoff' \
   'dy*namic:change DYNAMIC flag on device:$subcmd_onoff' \
   'n*ame:change name of device:$subcmd_string' \
   'txq*ueuelen:specify length of transmit queue:$subcmd_number' \
@@ -490,7 +490,7 @@ maddr_cmds=("$reply[@]")
 # mroute
 #
 local -a mroute_show_cmds
-_regex_words mroute-show-comnands "mroute show command" \
+_regex_words mroute-show-commands "mroute show command" \
   'to:select destination prefix:$subcmd_ipaddr' \
   'iif:select input interface (device):$subcmd_dev' \
   'from:select source prefix:$subcmd_ipaddr'
diff --git a/Completion/Unix/Command/_java b/Completion/Unix/Command/_java
index 7d5bd42..7a12246 100644
--- a/Completion/Unix/Command/_java
+++ b/Completion/Unix/Command/_java
@@ -71,7 +71,7 @@ java)
     '-verbose\:gc[print gc information]' \
     '-verbose\:jni[print JNI information]' \
     '(- 1)-version[print version]' \
-    '-showversion[print version and contrinue]' \
+    '-showversion[print version and continue]' \
     '(- 1)-'{\?,help}'[print help message]' \
     '(- 1)-X-[non-standard java option]:option' \
     '(- 1)-jar[specify a program encapsulated as jar]:jar:_files -g \*.jar\(-.\)' \
diff --git a/Completion/Unix/Command/_localedef b/Completion/Unix/Command/_localedef
index 78d2319..4d4b4bb 100644
--- a/Completion/Unix/Command/_localedef
+++ b/Completion/Unix/Command/_localedef
@@ -62,7 +62,7 @@ else
   [[ $OSTYPE == (freebsd*|dragonfly*) ]] && bsd_opts=(
       '-D[create BSD-style output]' \
       '-U[ignore undefined character symbols]' \
-      '-v[verbose deguggin output]' \
+      '-v[verbose debug output]' \
       '-w+[specify width file]:width file:_files' \
     )
 
diff --git a/Completion/Unix/Command/_make b/Completion/Unix/Command/_make
index 35a892c..a2ee9ec 100644
--- a/Completion/Unix/Command/_make
+++ b/Completion/Unix/Command/_make
@@ -184,7 +184,7 @@ _make() {
       '(-j --jobs)'{-j,--jobs=}'[allow N jobs at once; infinite jobs with no arg]:number of jobs'
       '(-k --keep-going)'{-k,--keep-going}"[keep going when some targets can't be made]"
       '(-l --load-average --max-load)'{-l,--load-average=,--max-load}"[don't start multiple jobs unless load is below N]:load"
-      '(-L --check-symlik-times)'{-L,--check-symlink-times}'[use the latest mtime between symlinks and target]'
+      '(-L --check-symlink-times)'{-L,--check-symlink-times}'[use the latest mtime between symlinks and target]'
       '(-n --just-print --dry-run --recon)'{-n,--just-print,--dry-run,--recon}"[don't actually run any recipe; just print them]"
       '*'{-o,--old-file=,--assume-old=}"[consider specified file to be old and don't remake it]:file not to remake:->file"
       '(-O --output-sync)'{-O-,--output-sync=-}'[synchronize output of parallel jobs]::granularity for grouping output:compadd -E 0 none line target recurse'
diff --git a/Completion/Unix/Command/_mencal b/Completion/Unix/Command/_mencal
index ca56c60..4286b94 100644
--- a/Completion/Unix/Command/_mencal
+++ b/Completion/Unix/Command/_mencal
@@ -10,7 +10,7 @@ _arguments -C \
   '(--quiet -q)'{-q,--quiet}'[no top information]' \
   '(--nocolor -n)'{-n,--nocolor}'[noncolored output]' \
   '(--icolor -i)'{-i,--icolor}'[intersection color]:color:(red green blue yellow violet cyan shiny bold)' \
-  '(-)'{-h,--help}'[display help informaiton]' \
+  '(-)'{-h,--help}'[display help information]' \
   '(-)'{-V,--version}'[print version information]' \
   \*{-c,--config}'[config]:options:->option' && ret=0
 
diff --git a/Completion/Unix/Command/_module b/Completion/Unix/Command/_module
index 060f05b..1872c3e 100644
--- a/Completion/Unix/Command/_module
+++ b/Completion/Unix/Command/_module
@@ -41,7 +41,7 @@ _module()
     "purge:unload all loaded modules"
     "refresh:refresh all non-persistent components of loaded modules"
     "whatis:display module information"
-    "appropos:search for a given keyword in modules"
+    "apropos:search for a given keyword in modules"
     "keyword:search for a given keyword in modules"
     "initadd:add or append a module to the user's shell init file"
     "initprepend:add or prepend a module to the user's shell init files"
diff --git a/Completion/Unix/Command/_nkf b/Completion/Unix/Command/_nkf
index 4d54127..04977e4 100644
--- a/Completion/Unix/Command/_nkf
+++ b/Completion/Unix/Command/_nkf
@@ -35,7 +35,7 @@ _arguments -s \
   '(-m)-M-[MIME encode]:mime encode:((\:header B\:base64 Q\:quoted))' \
   '-h-[hirakana<->katakana]:hirakata:((1\:hirakana-\>katakana 2\:katakana-\>hirakana 3\:both))' \
   '-L-[line mode]:line mode:((u\:LF w\:CRLF m\:CR))' \
-  '-I[Convert non ISO-2022-JP charactor to GETA]' \
+  '-I[convert non ISO-2022-JP character to GETA]' \
   '(--cap-input --url-input)'{--cap-input,--url-input}'[Convert hex after \: or \%]' \
   '--overwrite[Overwrite original listed files by filtered result]' \
   '(-v --help)'{-v,--help}'[display help message]' \
diff --git a/Completion/Unix/Command/_nmap b/Completion/Unix/Command/_nmap
index 437e68b..b3d3d48 100644
--- a/Completion/Unix/Command/_nmap
+++ b/Completion/Unix/Command/_nmap
@@ -5,7 +5,7 @@ local curcontext="$curcontext" state line suf ret=1
 _arguments -C \
   '!-sI:zombie host:_hosts' \
   '!-P'{T,S,U}'+:port list' \
-  '*-s-[specify scan type]:scan type:((S\:TCP\ SYN\ scan T\:TCP\ connect\(\)\ scan F\:stealth\ FIN\ scan X\:stealth\ Xmas\ tree\ scan N\:stealth\ null\ scan P\:ping\ scanning U\:UDP\ scan O\:IP\ prototocol\ scan I\:idle\ scan A\:ACK\ scan W\:window\ scan R\:RPC\ scan L\:list\ scan V\:version\ detection))' \
+  '*-s-[specify scan type]:scan type:((S\:TCP\ SYN\ scan T\:TCP\ connect\(\)\ scan F\:stealth\ FIN\ scan X\:stealth\ Xmas\ tree\ scan N\:stealth\ null\ scan P\:ping\ scanning U\:UDP\ scan O\:IP\ protocol\ scan I\:idle\ scan A\:ACK\ scan W\:window\ scan R\:RPC\ scan L\:list\ scan V\:version\ detection))' \
   '-b[specify ftp relay host]:ftp relay host:_hosts' \
   '*-P-[specify probe types and options]:probe type/options:->probe-opts' \
   '-A[enable OS detection and version scanning]' \
@@ -29,7 +29,7 @@ _arguments -C \
   '--data_length[add random data to packets]:data length' \
   '(-R)-n[skip reverse DNS to speed things up]' \
   '(-n)-R[always do reverse DNS on targets]' \
-  '-r[do not ramdomize order in which ports are scanned]' \
+  "-r[don't randomize order in which ports are scanned]" \
   '-ttl[specify IPv4 time to live for sent packets]' \
   '--randomize_hosts[scan hosts in random order]' \
   '-M[specify maximum number of parallel TCP connects]:maximum TCP connects' \
diff --git a/Completion/Unix/Command/_pbm b/Completion/Unix/Command/_pbm
index 747aed3..62004f7 100644
--- a/Completion/Unix/Command/_pbm
+++ b/Completion/Unix/Command/_pbm
@@ -698,7 +698,7 @@ ppmtoacad)
 ppmtobmp)
   _arguments \
     '(-windows)-os2' '(-os2)-windows' \
-    '-bpp[secify bits per pixel for BMP file]:bits per pixel:(1 4 8 24)' \
+    '-bpp[specify bits per pixel for BMP file]:bits per pixel:(1 4 8 24)' \
     ':file:_pbm'
   ;;
 
diff --git a/Completion/Unix/Command/_rar b/Completion/Unix/Command/_rar
index e2081f6..906e236 100644
--- a/Completion/Unix/Command/_rar
+++ b/Completion/Unix/Command/_rar
@@ -22,7 +22,7 @@ common=(
   '-ow[save or restore file owner and group]'
   '-p+:password'
   '-p\-[do not query password]'
-  '-r[recurse subdirectorie]'
+  '-r[recurse subdirectories]'
   '-ta+[process files modified after a date]:date (YYYYMMDDHHMMSS)'
   '-tb+[process files modified before a date]:date (YYYYMMDDHHMMSS)'
   '-tn+[process files newer than a specified time]:time'
diff --git a/Completion/Unix/Command/_sisu b/Completion/Unix/Command/_sisu
index 6ca2abf..0250581 100644
--- a/Completion/Unix/Command/_sisu
+++ b/Completion/Unix/Command/_sisu
@@ -23,7 +23,7 @@ _arguments -s -C -M 'r:|[_-]=* r:|=*' \
   '(--convert --to -C)-I[texinfo output, not maintained]' \
   '(--convert --to -C)-L[print license info]' \
   '(--convert --to -C)-M[maintenance mode, retain intermediate processing files]' \
-  '(--convert --to -C)-m[create intermediate markup file, metaverse, assumed for most output instuctions]' \
+  '(--convert --to -C)-m[create intermediate markup file, metaverse, assumed for most output instructions]' \
   '(--convert --to -C)-N[document content certificate, output document digests]' \
   '(--convert --to -C)-n[skip intermediate markup, skip -m]' \
   '(--convert --to -C)-o[Open Document text format output]' \
diff --git a/Completion/Unix/Command/_sqsh b/Completion/Unix/Command/_sqsh
index f41ab5b..5caf7f9 100644
--- a/Completion/Unix/Command/_sqsh
+++ b/Completion/Unix/Command/_sqsh
@@ -17,7 +17,7 @@ _sybase_server() {
 _arguments : \
     '-A[adjust TDS packet size (512)]:packet size (bytes):(512 1024 1536 2048)' \
     '-B[turn off file buffering on startup]' \
-    '-C[send sql statment to server]:sql' \
+    '-C[send sql statement to server]:sql' \
     '-D[change database context on startup]:database' \
     '-E[replace default editor (vi)]:editor' \
     '-H[set the client hostname]:reported hostname' \
diff --git a/Completion/Unix/Command/_surfraw b/Completion/Unix/Command/_surfraw
index 0307555..d9df417 100644
--- a/Completion/Unix/Command/_surfraw
+++ b/Completion/Unix/Command/_surfraw
@@ -118,7 +118,7 @@ case $state in
       deblists)
         _arguments $args \
           '-shelp[go to search help page]' \
-          '-results=-[specifiy number of results to return]:number' \
+          '-results=-[specify number of results to return]:number' \
           '-dates=-[quarters to search]:date' \
           '-case[use case sensitive search]' \
           '-errors=-[specify errors allowed]:errors:(0 1 2 best)' \
diff --git a/Completion/Unix/Command/_units b/Completion/Unix/Command/_units
index 7fcb078..d049d22 100644
--- a/Completion/Unix/Command/_units
+++ b/Completion/Unix/Command/_units
@@ -13,12 +13,12 @@ typeset -A opt_args
 _arguments -C -s -S \
   '(-c --check --check-verbose)'{-c,--check}'[check units are reducible]' \
   '(-c --check)--check-verbose[verbosely check units are reducible]' \
-  '(-o --output-format)'{-o,--output-format}'[specify output format]:printf formt: ' \
+  '(-o --output-format)'{-o,--output-format}'[specify output format]:printf format' \
   '(-f --file)'{-f,--file}'[specify file with units]:units file:_files' \
   '(-m --minus)'{-m,--minus}'[- is subtraction]' \
   '(-p --product)'{-p,--product}'[binary - is product]' \
   '(-q --quiet --silent)'{-q,--quiet,--silent}'[suppress prompts and statistics]' \
-  '(-s --strict)'{-s,--strict}'[suppress conversion to reciprocals units]' \
+  '(-s --strict)'{-s,--strict}'[suppress conversion to reciprocal units]' \
   '(-t --terse)'{-t,--terse}'[make conversion output briefer]' \
   '(-v --verbose)'{-v,--verbose}'[make output more verbose]' \
   '(- *)'{-h,--help}'[show help information and exit]' \
diff --git a/Completion/Unix/Command/_wiggle b/Completion/Unix/Command/_wiggle
index ec71fdc..0a2f0c0 100644
--- a/Completion/Unix/Command/_wiggle
+++ b/Completion/Unix/Command/_wiggle
@@ -9,7 +9,7 @@ _arguments \
   '(-w --words -l --lines)'{-w,--words}'[make operations and display word based]' \
   '(-l --lines -w --words)'{-l,--lines}'[make operations and display line based]' \
   '(-p --patch)'{-p,--patch}'[treat last named file as a patch]' \
-  '(-r --replace)'{-r,--replace}'[replace orginal file with merged output]' \
+  '(-r --replace)'{-r,--replace}'[replace original file with merged output]' \
   '(-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]' \


^ permalink raw reply	[relevance 1%]

* Re: Test failure on OpenBSD
  @ 2016-12-09  8:24  3%       ` Bart Schaefer
  2016-12-09  9:49  0%         ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2016-12-09  8:24 UTC (permalink / raw)
  To: zsh-workers

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

On Thu, Dec 8, 2016 at 9:13 PM, Matthew Martin <phy1729@gmail.com> wrote:
>
> That's why I tested 5.2 as well. Any tips on where to look or what is
> the C equivalent of    [[ $'\ua0' =~ '^.$' ]] ?

According to http://man.openbsd.org/regex.3 --

 There is one known functionality bug. The implementation of
internationalization
 is incomplete: the locale is always assumed to be the default one of IEEE
Std
 1003.2 (“POSIX.2”), and only the collating elements etc. of that locale
are available.

Wouldn't that mean this test should be expected to fail on openbsd?

^ permalink raw reply	[relevance 3%]

* Re: Test failure on OpenBSD
  2016-12-09  8:24  3%       ` Bart Schaefer
@ 2016-12-09  9:49  0%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2016-12-09  9:49 UTC (permalink / raw)
  To: zsh-workers

On Fri, 9 Dec 2016 00:24:33 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> According to http://man.openbsd.org/regex.3 --
> 
>  There is one known functionality bug. The implementation of
> internationalization
>  is incomplete: the locale is always assumed to be the default one of IEEE
> Std
>  1003.2 (“POSIX.2”), and only the collating elements etc. of that locale
> are available.
> 
> Wouldn't that mean this test should be expected to fail on openbsd?

diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index 3a6e955..9a246ca 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -511,6 +511,8 @@
 >OK
 >OK
 >OK
+F:A failure here may indicate the system regex library does not
+F:support character sets outside the portable 7-bit range.
 
   () {
      emulate -L zsh

pws


^ permalink raw reply	[relevance 0%]

* Re: zsh-5.2-test-3
  @ 2016-12-11  8:58  3%                 ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2016-12-11  8:58 UTC (permalink / raw)
  To: zsh-workers

On Dec 11,  4:11am, Daniel Shahaf wrote:
} Subject: Re: zsh-5.2-test-3
}
} Bart Schaefer wrote on Sat, Dec 10, 2016 at 19:44:21 -0800:
} > Actually -- why is that test in B02 in the first place, rather than in
} > say D04parameter.ztst ?
} 
} Because it's about assignment, as opposed to substitution?

Then why isn't in it A06assign ?  (Because it's not really about
assignment, either -- it's about a special-parameter side-effect.)

} If there's a better home for the test I don't mind moving it.

It probably ought to be in A05execution, or maybe we need a new test
file just for behavior of assorted special parameters.  C06specials ?

Incidentally, assigning to USERNAME attempts to change both UID and
GID and is still only a warning, not an error.  Further, if setuid()
and setgid() aren't available, assignments to UID et al. silently
do nothing, which is probably why failure of set?id() when available
was never a hard error before.

Passing thought, mostly unrelated:  There should be tests of "getopts"
in B08shift.  I believe we still have some incompatibility with POSIX
in OPTIND/OPTARG handling it would be nice to have an example of the
current behavior with some mention of the difference in case we get
around to fixing it.


^ permalink raw reply	[relevance 3%]

* Re: PATCH Re: 5.3: printf -
  @ 2016-12-15  0:50  3%             ` Daniel Shahaf
  2016-12-15  1:14  4%               ` Chet Ramey
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2016-12-15  0:50 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer wrote on Wed, Dec 14, 2016 at 10:44:50 -0800:
> On Dec 14,  4:51pm, Daniel Shahaf wrote:
> }
> } The grandparent patch fixes all the cases given so far in this thread,
> } except that "printf --" and "printf -- -" yield an error and "-",
> } respectively - whereas in sh mode they should both print "--".
> 
> Bash prints an error and "-" respectively in those two cases as well,
> so I think it's unclear what should happen for that in sh mode.

I was aiming for POSIX-compliance, not bash-compliance, for sh mode.


^ permalink raw reply	[relevance 3%]

* Re: PATCH Re: 5.3: printf -
  2016-12-15  0:50  3%             ` Daniel Shahaf
@ 2016-12-15  1:14  4%               ` Chet Ramey
  2016-12-15 22:45  3%                 ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Chet Ramey @ 2016-12-15  1:14 UTC (permalink / raw)
  To: Daniel Shahaf, zsh-workers; +Cc: chet.ramey

On 12/14/16 7:50 PM, Daniel Shahaf wrote:
> Bart Schaefer wrote on Wed, Dec 14, 2016 at 10:44:50 -0800:
>> On Dec 14,  4:51pm, Daniel Shahaf wrote:
>> }
>> } The grandparent patch fixes all the cases given so far in this thread,
>> } except that "printf --" and "printf -- -" yield an error and "-",
>> } respectively - whereas in sh mode they should both print "--".
>>
>> Bash prints an error and "-" respectively in those two cases as well,
>> so I think it's unclear what should happen for that in sh mode.
> 
> I was aiming for POSIX-compliance, not bash-compliance, for sh mode.

The format is not optional, according to Posix.  All shells aiming for
Posix conformance throw an error on `printf --'.

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet@case.edu    http://cnswww.cns.cwru.edu/~chet/


^ permalink raw reply	[relevance 4%]

* Re: PATCH Re: 5.3: printf -
  2016-12-15  1:14  4%               ` Chet Ramey
@ 2016-12-15 22:45  3%                 ` Daniel Shahaf
  2016-12-15 23:48  0%                   ` Chet Ramey
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2016-12-15 22:45 UTC (permalink / raw)
  To: Chet Ramey; +Cc: zsh-workers

Chet Ramey wrote on Wed, Dec 14, 2016 at 20:14:31 -0500:
> On 12/14/16 7:50 PM, Daniel Shahaf wrote:
> > Bart Schaefer wrote on Wed, Dec 14, 2016 at 10:44:50 -0800:
> >> On Dec 14,  4:51pm, Daniel Shahaf wrote:
> >> }
> >> } The grandparent patch fixes all the cases given so far in this thread,
> >> } except that "printf --" and "printf -- -" yield an error and "-",
> >> } respectively - whereas in sh mode they should both print "--".
> >>
> >> Bash prints an error and "-" respectively in those two cases as well,
> >> so I think it's unclear what should happen for that in sh mode.
> > 
> > I was aiming for POSIX-compliance, not bash-compliance, for sh mode.
> 
> The format is not optional, according to Posix.

Sure.

> All shells aiming for Posix conformance throw an error on `printf --'.

This surprises me; it doesn't match my understanding of the spec.
(I thought POSIX would take "--" to be the format string.)

Cheers,

Daniel
(trying not to repeat myself _too_ much..)


^ permalink raw reply	[relevance 3%]

* Re: PATCH Re: 5.3: printf -
  2016-12-15 22:45  3%                 ` Daniel Shahaf
@ 2016-12-15 23:48  0%                   ` Chet Ramey
  2016-12-16  0:56  0%                     ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Chet Ramey @ 2016-12-15 23:48 UTC (permalink / raw)
  To: Daniel Shahaf; +Cc: chet.ramey, zsh-workers

On 12/15/16 5:45 PM, Daniel Shahaf wrote:

> This surprises me; it doesn't match my understanding of the spec.
> (I thought POSIX would take "--" to be the format string.)

"Standard utilities that do not accept options, but that do accept
operands, shall recognize "--" as a first argument to be discarded."

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_04

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://cnswww.cns.cwru.edu/~chet/


^ permalink raw reply	[relevance 0%]

* Re: PATCH Re: 5.3: printf -
  2016-12-15 23:48  0%                   ` Chet Ramey
@ 2016-12-16  0:56  0%                     ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2016-12-16  0:56 UTC (permalink / raw)
  To: Chet Ramey; +Cc: zsh-workers

Chet Ramey wrote on Thu, Dec 15, 2016 at 18:48:13 -0500:
> On 12/15/16 5:45 PM, Daniel Shahaf wrote:
> 
> > This surprises me; it doesn't match my understanding of the spec.
> > (I thought POSIX would take "--" to be the format string.)
> 
> "Standard utilities that do not accept options, but that do accept
> operands, shall recognize "--" as a first argument to be discarded."
> 
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_04

Thank you for the reference.

diff --git a/Test/B03print.ztst b/Test/B03print.ztst
index 7a43f9c..c65568a 100644
--- a/Test/B03print.ztst
+++ b/Test/B03print.ztst
@@ -334,5 +334,3 @@
 0:regression test of printf with assorted ambiguous options or formats
 >------x
 ?(eval):printf:3: not enough arguments
-F:There is some question whether "printf --" should be an error as above,
-F:or should treat "--" as the format string.  Bash agrees on the error.


^ permalink raw reply	[relevance 0%]

* [PATCH] Document echo \c behaviour
@ 2017-01-09 20:32  8% Phil Pennock
  0 siblings, 0 replies; 200+ results
From: Phil Pennock @ 2017-01-09 20:32 UTC (permalink / raw)
  To: zsh-workers

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

Report on IRC asking about a behaviour difference between bash and zsh
led me down a rabbit hole.  While bash does the same thing as zsh when
given "echo -e", the behaviour was not documented in our man-pages and
was counter-intuitive.

    echo "foo\cbar" baz bat

Only the "foo" is output, with no final newline.

Commit logs show revision b77b51c in 2005 made this explicit, to "handle
\c escapes as per POSIX (truncating the output at the \c)".

SUSv4 XCU at <http://pubs.opengroup.org/onlinepubs/9699919799/> states:

 > \c
 > Suppress the <newline> that otherwise follows the final argument in
 > the output. All characters following the '\c' in the arguments shall
 > be ignored.

I think that this is worth documenting.  Patch tested with "make" in
Doc/ and results look fine.
---
 Doc/Zsh/builtins.yo | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 7b04d0648..4caefd5ba 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -453,7 +453,7 @@ tt(echo) recognizes the following escape sequences:
 startsitem()
 sitem(tt(\a))(bell character)
 sitem(tt(\b))(backspace)
-sitem(tt(\c))(suppress final newline)
+sitem(tt(\c))(suppress subsequent characters and final newline)
 sitem(tt(\e))(escape)
 sitem(tt(\f))(form feed)
 sitem(tt(\n))(linefeed (newline))
@@ -467,6 +467,9 @@ sitem(tt(\u)var(NNNN))(unicode character code in hexadecimal)
 sitem(tt(\U)var(NNNNNNNN))(unicode character code in hexadecimal)
 endsitem()
 
+POSIX requires for tt(echo) that "All characters following the tt(\c) in the
+arguments shall be ignored".
+
 pindex(BSD_ECHO, use of)
 The tt(-E) flag, or the tt(BSD_ECHO) option, can be used to disable
 these escape sequences.  In the latter case, tt(-e) flag can be used to
-- 
2.11.0


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[relevance 8%]

* fix watch implementation
@ 2017-01-12  6:46  2% Jens Elkner
  0 siblings, 0 replies; 200+ results
From: Jens Elkner @ 2017-01-12  6:46 UTC (permalink / raw)
  To: zsh-workers

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

Hi,

when evaluating zsh as the new default shell for interactive use it was
discovered, that the 'watch' feature doesn't work on Solaris 11.3 and
Ubuntu 14.04, 15.04 and probably other modern platforms: 'log' never
shows anything and logins/logouts never show up.

The root cause is, that the current implementation uses a rather
discouraged way to obtain utmp[x] records, i.e. it reads binary records
instead of using the POSIX/recommended way, i.e. {set,get,end}ut[x]ent() -
similar to getpwent(). To check I just inserted a printf: 1st record
seems to be ok but is always of ut_type != USER_PROCESS and all following
records read contain really garbage with ut_type = 0 (probably by
accident). So no wonder, why it doesn't work as expected.

The attached patch fixes the implementation, has been successfully
tested on the platforms mentioned above (was developed against 5.0.7,
which is, what the vendors of the mentioned OS ship, however, someone on
irc reported, that it applies cleanly to the current master version as
well).

Would be nice if it could be merged ASAP. IIRC, we started to evaluate
zsh as default shell 5+ years ago. First test was, whether watch works:
it didn't, but had no time to dig deeper, so we stopped and postponed
the eval ...

have fun,
jel.
-- 
Otto-von-Guericke University     http://www.cs.uni-magdeburg.de/
Department of Computer Science   Geb. 29 R 027, Universitaetsplatz 2
39106 Magdeburg, Germany         Tel: +49 391 67 52768

[-- Attachment #2: watch.patch --]
[-- Type: text/plain, Size: 3971 bytes --]

--- zsh-5.0.7/Src/watch.c.orig	Thu Jul 31 20:41:49 2014
+++ zsh-5.0.7/Src/watch.c	Wed Jan 11 16:37:49 2017
@@ -87,6 +87,9 @@
 
 #if !defined(WATCH_STRUCT_UTMP) && defined(HAVE_STRUCT_UTMPX) && defined(REAL_UTMPX_FILE)
 # define WATCH_STRUCT_UTMP struct utmpx
+# define setutent setutxent
+# define getutent getutxent
+# define endutent endutxent 
 /*
  * In utmpx, the ut_name field is replaced by ut_user.
  * Howver, on some systems ut_name may already be defined this
@@ -141,9 +144,9 @@
 #  define WATCH_WTMP_FILE "/dev/null"
 # endif
 
-static int wtabsz;
-static WATCH_STRUCT_UTMP *wtab;
-static time_t lastutmpcheck;
+static int wtabsz = 0;
+static WATCH_STRUCT_UTMP *wtab = NULL;
+static time_t lastutmpcheck = 0;
 
 /* get the time of login/logout for WATCH */
 
@@ -449,34 +452,44 @@
 /* initialize the user List */
 
 /**/
-static void
-readwtab(void)
+static int
+readwtab(WATCH_STRUCT_UTMP **head, int initial_sz)
 {
-    WATCH_STRUCT_UTMP *uptr;
-    int wtabmax = 32;
-    FILE *in;
+    WATCH_STRUCT_UTMP *uptr, *tmp;
+    int wtabmax = initial_sz < 2 ? 32 : initial_sz;
+    int sz = 0;
 
-    wtabsz = 0;
-    if (!(in = fopen(WATCH_UTMP_FILE, "r")))
-	return;
-    uptr = wtab = (WATCH_STRUCT_UTMP *)zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP));
-    while (fread(uptr, sizeof(WATCH_STRUCT_UTMP), 1, in))
+
+    uptr = *head = (WATCH_STRUCT_UTMP *)zalloc(wtabmax * sizeof(WATCH_STRUCT_UTMP));
+	setutent();
+    while ((tmp = getutent()) != NULL)
 # ifdef USER_PROCESS
-	if   (uptr->ut_type == USER_PROCESS)
+	if   (tmp->ut_type == USER_PROCESS)
 # else /* !USER_PROCESS */
-	if   (uptr->ut_name[0])
+	if   (tmp->ut_name[0])
 # endif /* !USER_PROCESS */
 	{
+		memcpy(uptr, tmp, sizeof (WATCH_STRUCT_UTMP));
 	    uptr++;
-	    if (++wtabsz == wtabmax)
-		uptr = (wtab = (WATCH_STRUCT_UTMP *)realloc((void *) wtab, (wtabmax *= 2) *
-						      sizeof(WATCH_STRUCT_UTMP))) + wtabsz;
+	    if (++sz == wtabmax) {
+			uptr = (WATCH_STRUCT_UTMP *)
+				realloc(*head, (wtabmax *= 2) * sizeof(WATCH_STRUCT_UTMP));
+			if (uptr == NULL) {
+				/* memory pressure - so stop consuming and use, what we have
+				 * Other option is to exit() here, as zmalloc does on error */
+				sz--;
+				break;
+			}
+			*head = uptr;
+			uptr += sz;
+		}
 	}
-    fclose(in);
+    endutent();
 
-    if (wtabsz)
-	qsort((void *) wtab, wtabsz, sizeof(WATCH_STRUCT_UTMP),
+    if (sz)
+	qsort((void *) *head, sz, sizeof(WATCH_STRUCT_UTMP),
 	           (int (*) _((const void *, const void *)))ucmp);
+	return sz;
 }
 
 /* Check for login/logout events; executed before *
@@ -486,55 +499,28 @@
 void
 dowatch(void)
 {
-    FILE *in;
     WATCH_STRUCT_UTMP *utab, *uptr, *wptr;
     struct stat st;
     char **s;
     char *fmt;
-    int utabsz = 0, utabmax = wtabsz + 4;
-    int uct, wct;
+    int utabsz, uct, wct;
 
     s = watch;
 
     holdintr();
-    if (!wtab) {
-	readwtab();
-	noholdintr();
-	return;
-    }
+    if (!wtab)
+	wtabsz = readwtab(&wtab, 32);
     if ((stat(WATCH_UTMP_FILE, &st) == -1) || (st.st_mtime <= lastutmpcheck)) {
 	noholdintr();
 	return;
     }
     lastutmpcheck = st.st_mtime;
-    uptr = utab = (WATCH_STRUCT_UTMP *) zalloc(utabmax * sizeof(WATCH_STRUCT_UTMP));
-
-    if (!(in = fopen(WATCH_UTMP_FILE, "r"))) {
-	free(utab);
-	noholdintr();
-	return;
-    }
-    while (fread(uptr, sizeof *uptr, 1, in))
-# ifdef USER_PROCESS
-	if (uptr->ut_type == USER_PROCESS)
-# else /* !USER_PROCESS */
-	if (uptr->ut_name[0])
-# endif /* !USER_PROCESS */
-	{
-	    uptr++;
-	    if (++utabsz == utabmax)
-		uptr = (utab = (WATCH_STRUCT_UTMP *)realloc((void *) utab, (utabmax *= 2) *
-						      sizeof(WATCH_STRUCT_UTMP))) + utabsz;
-	}
-    fclose(in);
+    utabsz = readwtab(&utab, wtabsz + 4);
     noholdintr();
     if (errflag) {
 	free(utab);
 	return;
     }
-    if (utabsz)
-	qsort((void *) utab, utabsz, sizeof(WATCH_STRUCT_UTMP),
-	           (int (*) _((const void *, const void *)))ucmp);
 
     wct = wtabsz;
     uct = utabsz;

^ permalink raw reply	[relevance 2%]

* Re: `exec env -i OLDPWD=$OLDPWD zsh` doesn't work
  @ 2017-01-14  5:09  3%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2017-01-14  5:09 UTC (permalink / raw)
  To: Zsh Hackers' List

On Fri, 13 Jan 2017, Peter Stephenson wrote:

> OLDPWD seems to be slightly weirdly implemented at the moment.  There's
> an internal variable storing it, but that's not explicitly tied to a
> shell variable; instead when the internal variable gets changed
> the shell variable also gets changed.  So the internal variable isn't
> changed if you change the shell variable

This is actually semantically necessary, as I recall.  There's no
prohibition on using OLDPWD and PWD as ordinary variables, as long as
you don't "cd" along the way.

And assigning to them is not supposed to behave like a "cd" or to
change the way "cd -" works, as far as I can tell.

Please don't make them into specials, we'll just have to find a way to
un-special them again for POSIX compatibility or something.


^ permalink raw reply	[relevance 3%]

* traps not reset in pipe component subshells
@ 2017-02-10 14:57  4% Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2017-02-10 14:57 UTC (permalink / raw)
  To: zsh-workers

Hello,

$ zsh -c 'trap "print -u2 out" EXIT; exit | exit | exit'
out
out
out


That's the only case I could find where the traps are not reset
in a subshell (tried coproc, zpty, $(...), <(...), exit&)

Another POSIX non-conformance:

$ bash -c 'trap uname EXIT; echo "$(trap)"'
trap -- 'uname' EXIT
Linux
$ zsh -c 'trap uname EXIT; echo "$(trap)"'

Linux

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap

POSIX requires $(trap) be treated as a special case so one can do:

traps=$(trap)
...
eval "$traps" # restore earlier traps

dash and mksh have the same problem. In zsh, thanks to the
first /bug/ above, one can do:

trap | IFS= read -rd '' traps

It may make sense to have a $trap[NAL] zsh/parameter hash for
that (where an empty value means ignored, while "-" means
default, not sure what to do if there's a TRAPNAL() but an
application can always check $+functions[TRAPNAL] first).

See also:
https://unix.stackexchange.com/questions/343990/dash-how-to-capture-output-of-trap-invoked-w-o-arguments/343999#343999

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: Multithreading support in pluggable module, but with problems
  @ 2017-02-11 19:46  3% ` Bart Schaefer
  2017-02-11 20:14  0%   ` Sebastian Gniazdowski
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2017-02-11 19:46 UTC (permalink / raw)
  To: zsh-workers

On Feb 11,  4:58am, Sebastian Gniazdowski wrote:
} Subject: Multithreading support in pluggable module, but with problems
}
} # zpin 'print -rl "a:b" "c:d"' | zpopulator -A my_hash
} 
} This is done entirely in background. zpin does fork() and this way makes
} Zsh think it's finished - main process exits. zpopulator starts a thread
} and makes main thread exit - this is also sufficient to make Zsh think
} that there is no background job.

So if I understand this correctly, you're attempting to use POSIX threads
to share the my_hash variable between the main shell and a 2nd thread of
which the main shell is not aware, so that the 2nd thread can stuff a
value into my_hash while the main thread goes on about its business?

I can almost promise you there is no way to make that work, at least not
in a crash-proof manner.  Even making my_hash PM_READONLY -- which is I
presume what yesterday's question was about -- what is there to stop
the thread-unaware main shell from accessing it at a time when the 2nd
thread is changing it in some way that will send the main thread off
into uncharted memory?

Aside from that, you're running directly afoul of the presecribed
behavior of file descriptor management for shells, which amounts
to a prohibition on passing unexpected file descriptors down to any
forked children.  If you want to keep a descriptor around, you have
to manipulate it with the routines in Src/utils.c that manage the
fdtable array.

In particular you *might* need to call either movefd() or redup()
rather than call dup2() directly, and you should otherwise be using
addmodulefd() to protect the fd from exec.c:closeallelse().  Examples
in Src/Modules/tcp.c.


^ permalink raw reply	[relevance 3%]

* Re: Multithreading support in pluggable module, but with problems
  2017-02-11 19:46  3% ` Bart Schaefer
@ 2017-02-11 20:14  0%   ` Sebastian Gniazdowski
  0 siblings, 0 replies; 200+ results
From: Sebastian Gniazdowski @ 2017-02-11 20:14 UTC (permalink / raw)
  To: zsh-workers; +Cc: Bart Schaefer

On Sat, Feb 11, 2017, at 11:46 AM, Bart Schaefer wrote:
> So if I understand this correctly, you're attempting to use POSIX threads
> to share the my_hash variable between the main shell and a 2nd thread of
> which the main shell is not aware, so that the 2nd thread can stuff a
> value into my_hash while the main thread goes on about its business?

Yes. 2nd thread has it's forked pipe data provider – "zpin" command that
does eval – and can eval freely because it's forked – Zsh forks first
components of pipeline, last one isn't forked – that's the tight window
for this solution.

> I can almost promise you there is no way to make that work, at least not
> in a crash-proof manner.  Even making my_hash PM_READONLY -- which is I
> presume what yesterday's question was about -- what is there to stop
> the thread-unaware main shell from accessing it at a time when the 2nd
> thread is changing it in some way that will send the main thread off
> into uncharted memory?

I know it might seem dirty, but what if it's rock-solid done. Also, for
me it might be interesting, for someone outside it might be repelling –
I think I can tell from my own reactions to creativity of others,
plugins created by others – sadly I'm miles away from trying them. But
maybe they're just not interesting, it's possible.

I think I got code close to working state. Can consecutively spawn 32
threads one hundred times. Have functions without queue_signals() etc.
copied from Zsh. What is to stop conflicts are helper variables. Got two
of them casually added, readonly:

– $workers_count – holds number of active threads. User is to wait for
0.
– $worker_finished – array of 32 ones. If a thread is active, there is
"0" for him.

If in syntax highlighting I would spawn "check_path()" with worker
number "X", output to variable "output_X", then I would check for
$worker_finished[X] to become "1" at main loop one or few times, join
the thread (TODO), use the variable. This might seem complex and maybe
it is, I will verify.

> In particular you *might* need to call either movefd() or redup()
> rather than call dup2() directly, and you should otherwise be using
> addmodulefd() to protect the fd from exec.c:closeallelse().  Examples
> in Src/Modules/tcp.c.

Good to know, thanks. I might reserve 32 file descriptors.

Also I think I found some very real proof. In my message I wrote I
guarded fclose() with fcntl() that is checking if FD is valid:

            if ( -1 != fcntl( fileno( oconf->stream ), F_GETFD ) ) {
                if ( 0 != fclose( oconf->stream ) ) {

This summoned away almost all FD problems, literaly 99.5%. Once in a
while fclose() would however fail. I thought: "It's a race condition,
between fcntl() and fclose() something closes the FD". So I modified:

            if ( -1 != fcntl( fileno( oconf->stream ), F_GETFD ) ) {
                sleep( 1 );
                if ( 0 != fclose( oconf->stream ) ) {

And now I get many "Bad descriptor" errors each time. So something is
really managing the FD behind the curtains, either is like I originally
suspected that closing on one end invalidates on other (there are
problems in this thinking..), or it's Zsh that does the management,
which might be a good thing. It seems I can just forget about fclose(),
it's not needed apparently. Will check for any memory leak tomorrow to
be sure.

-- 
Sebastian Gniazdowski


^ permalink raw reply	[relevance 0%]

* Re: signal mask bug?
  @ 2017-02-16  9:48  3%     ` Peter Stephenson
  2017-02-16 20:18  0%       ` Danek Duvall
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-02-16  9:48 UTC (permalink / raw)
  To: zsh-workers

On Wed, 15 Feb 2017 20:10:44 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> But then when we reach prinjob() from the "jobs" command, pn->status of
> that job has changed from -1 to 65535.
> 
> This happens at signals.c:525 in wait_for_processes(), when the status
> returned from wait3(&status) [line 457] is assigned to it.

Or somewhere or other it's going through a cast to unsigned short, but
that doesn't seem all that likely in the signal code, particularly POSIX
style on a 32- or 64-bit architecture.

If it's Solaris *and* Linux it seems unlikely the status itself is
doing anything funny, though, and that's passed back as int *...

pws


^ permalink raw reply	[relevance 3%]

* Re: signal mask bug?
  2017-02-16  9:48  3%     ` Peter Stephenson
@ 2017-02-16 20:18  0%       ` Danek Duvall
  0 siblings, 0 replies; 200+ results
From: Danek Duvall @ 2017-02-16 20:18 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Thu, Feb 16, 2017 at 09:48:36AM +0000, Peter Stephenson wrote:

> On Wed, 15 Feb 2017 20:10:44 -0800
> Bart Schaefer <schaefer@brasslantern.com> wrote:
> > But then when we reach prinjob() from the "jobs" command, pn->status of
> > that job has changed from -1 to 65535.
> > 
> > This happens at signals.c:525 in wait_for_processes(), when the status
> > returned from wait3(&status) [line 457] is assigned to it.
> 
> Or somewhere or other it's going through a cast to unsigned short, but
> that doesn't seem all that likely in the signal code, particularly POSIX
> style on a 32- or 64-bit architecture.
> 
> If it's Solaris *and* Linux it seems unlikely the status itself is
> doing anything funny, though, and that's passed back as int *...

So my colleague did some digging and found that the process is marked with
WCONTFLG, and that once that happens, you have to check WIFCONTINUED()
before anything else, because WCONTFLG overwrites all the bits.  He found
that the following patch worked for him:

    --- a/Src/signals.c   2015-09-04 13:38:13.000000000 -0700
    +++ b/Src/signals.c   2017-02-16 11:37:26.714503575 -0800
    @@ -510,6 +510,11 @@
                    struct timezone dummy_tz;
                    gettimeofday(&pn->endtime, &dummy_tz);
                    pn->status = status;
    +#ifdef WIFCONTINUED
    +               if (WIFCONTINUED(status))
    +                       pn->status = SP_RUNNING;
    +#endif
    +
                    pn->ti = ru;
     #else
                    update_process(pn, status);

though it occurred to me that it might be better placed in the loop in
printjob(), which already has an override for pn->status.

Thanks,
Danek


^ permalink raw reply	[relevance 0%]

* Re: [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS
  @ 2017-02-20 22:13  4%       ` Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2017-02-20 22:13 UTC (permalink / raw)
  To: Zsh hackers list

Op 20-02-17 om 22:20 schreef Bart Schaefer:
> Thanks to Chet Ramey for pointing me at
> http://austingroupbugs.net/view.php?id=888
> 
> Which says (very last block of examples) that var=$@ and var="$@" and
> a whole slew of their variations, have unspecified behavior.

True. I should not have included that in the test case.

It makes sense for var=$@ and var="$@" to be unspecified. In a pure
POSIX context these does not make sense, because POSIX does not have
arrays, and we've already got $* to combine the PPs into a scalar. But
for zsh or bash, which do have arrays, it could actually make sense to
make var=$@ and var="$@" properly equivalent to var=("$@"). It's just
that no shell currently does this, at least not intentionally; zsh's
current behaviour as reported was clearly not consistent.

> Consequently I'm going to take the position that zsh is allowed to join
> these with empty string rather than pulling a field separator out of
> its proverbial hat, and I will tweak 40565 appropriately and commit.

Thanks.

- M.


^ permalink raw reply	[relevance 4%]

* [BUG] Solaris-specific program flow corruption after subshell error exit
@ 2017-02-26  5:36  2% Martijn Dekker
  2017-02-26 20:29  3% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2017-02-26  5:36 UTC (permalink / raw)
  To: Zsh hackers list

Modernish (cross-platform POSIX shell library with ambitions to become
modernizr/jQuery for the shell) is finally getting near a first testing
release, so I'm doing testing on all shell/OS combinations I can get my
hands on.

In the course of that testing I've come across a zsh bug that *only*
manifests on Solaris, at least version 11.3. (A free VirtualBox VM for
evaluation purposes is available from Oracle.)

If a subshell exits due to an error in a special builtin or redirection,
execution flow is corrupted in such a manner that, when end of file is
reached without an explicit 'return' or 'exit' being encountered,
execution of the file does not end but restarts at the point exactly
after the subshell was exited. The second time around, if program
specifics allow it, execution ends normally.

The bug only manifests if POSIXBUILTINS is active, and only on Solaris.
I confirmed the bug on zsh 5.0.7 (as shipped by default), zsh 5.2
(package available from Oracle), *and* today's current git version
(compiled myself, obviously). So it appears to be long-standing.

Test script:

# Bug only occurs with POSIXBUILTINS active.
setopt POSIXBUILTINS
# Execution counter.
count=0
# Exiting from a subshell due to an error triggers the bug.
(set -o nonexistent_@_option) 2>/dev/null
# With the bug, this will be executed twice so 'let' returns true.
let "(count += 1) > 1" && echo "BUG DETECTED"
# EOF. To trigger the bug, don't explicitly exit or return.

Save and run with "zsh test.zsh". On Solaris, it outputs "BUG DETECTED".
On any other OS, it outputs nothing.

Interestingly, a sourced dot script will trigger the bug just as cleanly
as a standalone script, so it is possible to test for the bug from
another program without affecting that program.

Actually, things get *really* interesting if you add "return" to the end
of the test script and source it from another script as a dot script. In
that case, the bug appears to "move up" in the calling hierarchy; that
is, if the file sourcing this test script (with the extra "return") ends
execution due to end of file (i.e. no "return" or "exit"), its execution
resumes to just after the command that sourced this file.

(This is how I initially encountered the bug: when I tried 'modernish
--test', zsh 5.0.7 on Solaris would mysteriously try to run the test
suite twice. Which was "interesting" to track down, to say the least.)

Good luck with this one. Let me know if you need me to do anything
specific to help track it down.

- M.


^ permalink raw reply	[relevance 2%]

* Re: [BUG] Solaris-specific program flow corruption after subshell error exit
  2017-02-26  5:36  2% [BUG] Solaris-specific program flow corruption after subshell error exit Martijn Dekker
@ 2017-02-26 20:29  3% ` Bart Schaefer
  2017-02-26 22:55  3%   ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2017-02-26 20:29 UTC (permalink / raw)
  To: Martijn Dekker, Zsh hackers list

On Feb 26,  6:36am, Martijn Dekker wrote:
}
} In the course of that testing I've come across a zsh bug that *only*
} manifests on Solaris, at least version 11.3. (A free VirtualBox VM for
} evaluation purposes is available from Oracle.)
} 
} If a subshell exits due to an error in a special builtin or redirection,
} execution flow is corrupted in such a manner that, when end of file is
} reached without an explicit 'return' or 'exit' being encountered,
} execution of the file does not end but restarts at the point exactly
} after the subshell was exited. The second time around, if program
} specifics allow it, execution ends normally.

Given that this is specific to Solaris and has to do with execution of
script files, I'm going to guess that it's related to file descriptor
management and buffering within STREAMS modules.

In particular I'm guessing that the POSIX-compatible behavior referenced
at the "fatal:" label in exec.c near line 4000 is leaving some kind of
shared stdin state between the parent and the subshell, because "set"
is a special builtin so will invoke the exit at that point.  Without
actually running the code, I'd expect we're going through the _exit()
branch rather than the exit() branch which under normal circumstances is
deliberately to avoid having such shared state mess up the parent file
descriptor positions, but maybe that's not sufficient.

Whether this is revealing a bug in zsh or a bug in Solaris 11.3 I can't
say.


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Solaris-specific program flow corruption after subshell error exit
  2017-02-26 20:29  3% ` Bart Schaefer
@ 2017-02-26 22:55  3%   ` Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2017-02-26 22:55 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

Op 26-02-17 om 21:29 schreef Bart Schaefer:
> In particular I'm guessing that the POSIX-compatible behavior referenced
> at the "fatal:" label in exec.c near line 4000 is leaving some kind of
> shared stdin state between the parent and the subshell, because "set"
> is a special builtin so will invoke the exit at that point.  Without
> actually running the code, I'd expect we're going through the _exit()
> branch rather than the exit() branch which under normal circumstances is
> deliberately to avoid having such shared state mess up the parent file
> descriptor positions, but maybe that's not sufficient.

I can't comment on that, but I did a little uninformed experimenting.

>From line 4002:

    if (forked)
        _exit(1);
    else
        exit(1);

if I change the second "exit(1)" to "_exit(1)", the bug disappears and
the shell *appears* to act normally, at least with all the POSIX options
active. It passes the modernish test suite and runs all the example
programs without a hitch.

So that appears to suggest that the problem is something to do with
invoking exit() and not _exit() upon exiting a subshell on error. Could
it be that the 'forked' flag contains the wrong value?

- M.


^ permalink raw reply	[relevance 3%]

* Re: patch for ssh completion
  @ 2017-03-02 12:12  3% ` Daniel Shahaf
  2017-03-05  8:27  0%   ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2017-03-02 12:12 UTC (permalink / raw)
  To: Jeremy Cantrell; +Cc: zsh-workers

Jeremy Cantrell wrote on Tue, Feb 28, 2017 at 11:17:29 -0800:
> Hello!
> 
> I've found a tiny problem with the ssh completion script where any host
> entries defined in included configuration files do not appear as choices
> when completing. I've attached a patch that fixes it for me. Below is an
> example that illustrates the problem:
> 
> ~/.ssh/config:
> Include hosts
> 
> ~/.ssh/hosts:
> Host example
> HostName example.local

>From ssh_config(5):

     Include
             Include the specified configuration file(s).  Multiple pathnames
             may be specified and each pathname may contain glob(3) wildcards
             and, for user configurations, shell-like ‘~’ references to user
             home directories.  Files without absolute paths are assumed to be
             in ~/.ssh if included in a user configuration file or /etc/ssh if
             included from the system configuration file.  Include directive
             may appear inside a Match or Host block to perform conditional
             inclusion.

> Thanks,
> Jeremy

> --- /usr/share/zsh/functions/Completion/Unix/_ssh	2016-12-22 11:27:00.000000000 -0800
> +++ packages/base/.local/share/zsh/functions/_ssh	2017-02-26 22:37:47.513422235 -0800
> @@ -681,16 +681,21 @@
>    fi
>    if [[ -r $config ]]; then
>      local key hosts host
> +    local filename configs=($config)
> +    grep '^Include\b' "$config" | sed 's/\s\+/ /g' | cut -d' ' -f2 |
> +    while read -r filename; do
> +        config=$HOME/.ssh/$filename

This handles your example, but not the other possibilities documented in
the man page, e.g., absolute paths.  I expect using those would cause
errors on stderr.  (I can't test this since my ssh isn't new enough.)

The «\b» in grep is not in POSIX.  It could be changed to match
whitespace explicitly.  I assume we'll also want to use builtin
functionality such as ${(M)…:#Include*} instead of external executables.

Can filenames be quoted?  I.e., does «Include "foo"» include ~/.ssh/foo
or ~/.ssh/\"foo\"?

Can Include directives be nested?  If they can, it'd be nice to handle
that.  (But I don't think that's a blocker to accepting the patch)

>          while IFS=$'=\t ' read -r key hosts; do
>          if [[ "$key" == (#i)host ]]; then
>              for host in ${(z)hosts}; do
>                  case $host in
>                  (*[*?]*) ;;
>                  (*) config_hosts+=("$host") ;;
>                  esac
>              done
>          fi
>          done < "$config"
> +    done

Thanks for the patch.

Cheers,

Daniel


^ permalink raw reply	[relevance 3%]

* Re: patch for ssh completion
  2017-03-02 12:12  3% ` Daniel Shahaf
@ 2017-03-05  8:27  0%   ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2017-03-05  8:27 UTC (permalink / raw)
  To: Jeremy Cantrell; +Cc: zsh-workers

Jeremy — have you seen my review (quoted below)?  Would you be able to
revise the patch to address these points, at least the first two?

Process-wise, patches that apply to latest master are preferred, but
_ssh hasn't been changed since 5.3.1 so that's okay.

Cheers,

Daniel

Daniel Shahaf wrote on Thu, Mar 02, 2017 at 12:12:29 +0000:
> Jeremy Cantrell wrote on Tue, Feb 28, 2017 at 11:17:29 -0800:
> > Hello!
> > 
> > I've found a tiny problem with the ssh completion script where any host
> > entries defined in included configuration files do not appear as choices
> > when completing. I've attached a patch that fixes it for me. Below is an
> > example that illustrates the problem:
> > 
> > ~/.ssh/config:
> > Include hosts
> > 
> > ~/.ssh/hosts:
> > Host example
> > HostName example.local
> 
> From ssh_config(5):
> 
>      Include
>              Include the specified configuration file(s).  Multiple pathnames
>              may be specified and each pathname may contain glob(3) wildcards
>              and, for user configurations, shell-like ‘~’ references to user
>              home directories.  Files without absolute paths are assumed to be
>              in ~/.ssh if included in a user configuration file or /etc/ssh if
>              included from the system configuration file.  Include directive
>              may appear inside a Match or Host block to perform conditional
>              inclusion.
> 
> > Thanks,
> > Jeremy
> 
> > --- /usr/share/zsh/functions/Completion/Unix/_ssh	2016-12-22 11:27:00.000000000 -0800
> > +++ packages/base/.local/share/zsh/functions/_ssh	2017-02-26 22:37:47.513422235 -0800
> > @@ -681,16 +681,21 @@
> >    fi
> >    if [[ -r $config ]]; then
> >      local key hosts host
> > +    local filename configs=($config)
> > +    grep '^Include\b' "$config" | sed 's/\s\+/ /g' | cut -d' ' -f2 |
> > +    while read -r filename; do
> > +        config=$HOME/.ssh/$filename
> 
> This handles your example, but not the other possibilities documented in
> the man page, e.g., absolute paths.  I expect using those would cause
> errors on stderr.  (I can't test this since my ssh isn't new enough.)
> 
> The «\b» in grep is not in POSIX.  It could be changed to match
> whitespace explicitly.  I assume we'll also want to use builtin
> functionality such as ${(M)…:#Include*} instead of external executables.
> 
> Can filenames be quoted?  I.e., does «Include "foo"» include ~/.ssh/foo
> or ~/.ssh/\"foo\"?
> 
> Can Include directives be nested?  If they can, it'd be nice to handle
> that.  (But I don't think that's a blocker to accepting the patch)
> 
> >          while IFS=$'=\t ' read -r key hosts; do
> >          if [[ "$key" == (#i)host ]]; then
> >              for host in ${(z)hosts}; do
> >                  case $host in
> >                  (*[*?]*) ;;
> >                  (*) config_hosts+=("$host") ;;
> >                  esac
> >              done
> >          fi
> >          done < "$config"
> > +    done
> 
> Thanks for the patch.
> 
> Cheers,
> 
> Daniel


^ permalink raw reply	[relevance 0%]

* Re: export "a=b"=~
  @ 2017-03-08 13:23  3% ` Daniel Shahaf
  2017-03-08 15:44  0%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Daniel Shahaf @ 2017-03-08 13:23 UTC (permalink / raw)
  To: Zsh hackers list

Stephane Chazelas wrote on Wed, Mar 08, 2017 at 08:50:00 +0000:
> Not that it's likely to ever be a concern, but I just noticed:
> 
> $ zsh -c 'export "a"=a=~; echo $a'
> a=~
> $ zsh -c 'export "a=a"=~; echo $a'
> a=/home/chazelas
> $ zsh -c 'export a=a=~; echo $a'
> a=~
> 
> (5.1.1)

[ I assume the point is that tilde expansion wasn't expected in the
second case. ]

Same behaviour in latest master.  This is because the MAGIC_EQUAL_SUBST
option, even when unset, implicitly applies to "export".  (The
declaration of "export" in builtins.c has the BINF_MAGICEQUALS flag
since before CVS.)

Should the behaviour be changed in 'emulate sh' / 'setopt posix*' mode?


^ permalink raw reply	[relevance 3%]

* Re: export "a=b"=~
  2017-03-08 13:23  3% ` Daniel Shahaf
@ 2017-03-08 15:44  0%   ` Peter Stephenson
  2017-03-08 22:30  3%     ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-03-08 15:44 UTC (permalink / raw)
  To: Zsh hackers list

On Wed, 8 Mar 2017 13:23:45 +0000
Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> Stephane Chazelas wrote on Wed, Mar 08, 2017 at 08:50:00 +0000:
> > Not that it's likely to ever be a concern, but I just noticed:
> > 
> > $ zsh -c 'export "a"=a=~; echo $a'
> > a=~
> > $ zsh -c 'export "a=a"=~; echo $a'
> > a=/home/chazelas
> > $ zsh -c 'export a=a=~; echo $a'
> > a=~
> > 
> > (5.1.1)
> 
> [ I assume the point is that tilde expansion wasn't expected in the
> second case. ]
> 
> Same behaviour in latest master.  This is because the MAGIC_EQUAL_SUBST
> option, even when unset, implicitly applies to "export".  (The
> declaration of "export" in builtins.c has the BINF_MAGICEQUALS flag
> since before CVS.)
> 
> Should the behaviour be changed in 'emulate sh' / 'setopt posix*' mode?

I think that flag is now largely redundant since these days the "~"
expansion is normally triggered by parsing the variable and argument
separately, in which case the older "magic" behaviour isn't useful.

Hence, regardless of compatibility mode, we should probably suppress
that flag in this case, leaving the fix-up magic behaviour for when we
encounter a builtin without recognising it as a keyword in the parser
(an unusual case where it's OK to make reasonable guesses and
compatibility with older zsh is probably the right answer).

So I think the following ought to work without any significant side
effects.  I've renamed the controlling variable for clarity; the older,
more general, name is now purely historical.

One extra thing: it seems likely that you don't want MAGIC_EQUAL_SUBST
behaviour *at all* in the case where you recognised the keyword,
i.e. even if the option is explicitly set, right?  So I've changed that,
too.  In other words,

setopt magicequalsubst
typeset "a=a"=~

*still* only assigns the value 'a=~'.  See comment I've added for the full
logic.

It would certainly be possible not to set magic_assign if the
POSIX_BUILTINS option is on, too, but that's now a very minor effect.

pws

diff --git a/Src/exec.c b/Src/exec.c
index 8b32246..ec415cf 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2658,7 +2658,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
     char *text;
     int save[10];
     int fil, dfil, is_cursh, do_exec = 0, redir_err = 0, i;
-    int nullexec = 0, assign = 0, forked = 0;
+    int nullexec = 0, magic_assign = 0, forked = 0;
     int is_shfunc = 0, is_builtin = 0, is_exec = 0, use_defpath = 0;
     /* Various flags to the command. */
     int cflags = 0, orig_cflags = 0, checked = 0, oautocont = -1;
@@ -2761,7 +2761,8 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 		/* autoload the builtin if necessary */
 		if (!(hn = resolvebuiltin(cmdarg, hn)))
 		    return;
-		assign = (hn->flags & BINF_MAGICEQUALS);
+		if (type != WC_TYPESET)
+		    magic_assign = (hn->flags & BINF_MAGICEQUALS);
 		break;
 	    }
 	    checked = 0;
@@ -2929,8 +2930,22 @@ execcmd_exec(Estate state, Execcmd_params eparams,
     if (noerrexit == 2 && !is_shfunc)
 	noerrexit = 0;
 
-    /* Do prefork substitutions */
-    esprefork = (assign || isset(MAGICEQUALSUBST)) ? PREFORK_TYPESET : 0;
+    /* Do prefork substitutions.
+     *
+     * Decide if we need "magic" handling of ~'s etc. in
+     * assignment-like arguments.
+     * - If magic_assign is set, we are using a builtin of the
+     *   tyepset family, but did not recognise this as a keyword,
+     *   so need guess-o-matic behaviour.
+     * - Otherwise, if we did recognise the keyword, we never need
+     *   guess-o-matic behaviour as the argument was properly parsed
+     *   as such.
+     * - Otherwise, use the behaviour specified by the MAGIC_EQUAL_SUBST
+     *   option.
+     */
+    esprefork = (magic_assign ||
+		 (isset(MAGICEQUALSUBST) && type != WC_TYPESET)) ?
+		 PREFORK_TYPESET : 0;
     if (args && eparams->htok)
 	prefork(args, esprefork, NULL);
 
@@ -3710,7 +3725,7 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 		     * Save if it's got "command" in front or it's
 		     * not a magic-equals assignment.
 		     */
-		    if ((cflags & (BINF_COMMAND|BINF_ASSIGN)) || !assign)
+		    if ((cflags & (BINF_COMMAND|BINF_ASSIGN)) || !magic_assign)
 			do_save = 1;
 		}
 		if (do_save && varspc)


^ permalink raw reply	[relevance 0%]

* Re: export "a=b"=~
  2017-03-08 15:44  0%   ` Peter Stephenson
@ 2017-03-08 22:30  3%     ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2017-03-08 22:30 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

2017-03-08 15:44:28 +0000, Peter Stephenson:
[...]
> > Same behaviour in latest master.  This is because the MAGIC_EQUAL_SUBST
> > option, even when unset, implicitly applies to "export".  (The
> > declaration of "export" in builtins.c has the BINF_MAGICEQUALS flag
> > since before CVS.)
[...]
> So I think the following ought to work without any significant side
> effects.  I've renamed the controlling variable for clarity; the older,
> more general, name is now purely historical.
[...]

Some variations between shells:

$ ksh93 -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
~
/home/chazelas
~
$ bash -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
~
/home/chazelas
~
$ ARGV0=sh bash -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
~
~
~
$ mksh -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
/home/chazelas
/home/chazelas
~
$ dash -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
~
~
~
~
$ yash -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
~
~
~
~
$ zsh -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
/home/chazelas
~
~
$ zsh -o magicequalsubst  -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
/home/chazelas
/home/chazelas
~



After your patch:

$ ./Src/zsh -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
~
~
~
$ ./Src/zsh -o magicequalsubst -c 'export a=~; echo $a; export "a"=~; echo $a; "export" a=~; echo $a; export a\=~; echo $a'
/home/chazelas
~
/home/chazelas
~


I can't say I have a strong opinion on what is best. I like
magic_equal_subst myself and I'm annoyed when ./configure
--prefix=~ doesn't work or sudo JAVA_HOME=~/jre... And I tend to
quote ~ when in doubt and don't want it to be expanded.

Note that in bash (when not in posix mode)

echo a=~

expands (so covers my sudo case above) but

echo --prefix=~

does not. What's on the left of the = has to look like a valid
literal unquoted bash variable name.

Started from:
https://askubuntu.com/questions/890415/why-couldnt-i-use-instead-of-home-username-when-giving-the-file-pat/890472#890472

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* PATCH: update completions for some coreutils commands
@ 2017-03-13 22:24 15% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2017-03-13 22:24 UTC (permalink / raw)
  To: Zsh workers

This updates a few completions up to coreutils 8.27, binutils 2.28. New
completions for basename, fmt and paste. _cat is mostly better support
for Solaris and the BSDs.

Oliver

diff --git a/Completion/Unix/Command/_basename b/Completion/Unix/Command/_basename
new file mode 100644
index 000000000..a826b56b0
--- /dev/null
+++ b/Completion/Unix/Command/_basename
@@ -0,0 +1,27 @@
+#compdef basename gbasename
+
+local args variant
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+
+case $variant in
+  gnu)
+    args=( -s -S -A "-*"
+      '(2 -a --multiple)'{-a,--multiple}'[support multiple arguments, handling each]'
+      '(2 -a --multiple -s --suffix)'{-s+,--suffix=}'[remove a trailing suffix]:suffix'
+      '(-z --zero)'{-z,--zero}'[separate output with NUL rather than newline]'
+      '(- *)--version[display version information]'
+      '(- *)--help[display help information]'
+    )
+  ;;
+  darwin*|dragonfly*|freebsd*)
+    args=( -s -S -A "-*"
+      '(2)-a[support multiple arguments, handling each]'
+      '(-a 2)-s+[remove a trailing suffix]:suffix'
+    )
+  ;;
+esac
+
+_arguments $args \
+  '1:file:_files' \
+  '(*)2:suffix' \
+  '*:file:_files'
diff --git a/Completion/Unix/Command/_cat b/Completion/Unix/Command/_cat
index 57b197038..46180f2c8 100644
--- a/Completion/Unix/Command/_cat
+++ b/Completion/Unix/Command/_cat
@@ -19,8 +19,9 @@ if _pick_variant gnu=GNU unix --version; then
     '*:files:_files'
   )
 
-elif [[ "$OSTYPE" == (freebsd|dragonfly|darwin)* ]]; then
+elif [[ "$OSTYPE" == (*bsd|dragonfly|darwin)* ]]; then
   args=(
+    -A "-*"
     '(-n)-b[number non-blank output lines]'
     '(-v)-e[display $ at the end of each line (implies -v)]'
     '-n[number all output lines]'
@@ -28,12 +29,27 @@ elif [[ "$OSTYPE" == (freebsd|dragonfly|darwin)* ]]; then
     '(-v)-t[display tab as ^I (implies -v)]'
     '-u[do not buffer output]'
     '-v[display non-printing chars as ^X or M-a]'
-    '(-)*:files:_files'
+    '*:files:_files'
   )
-  [[ $OSTYPE = freebsd* ]] && args+=(
+  [[ $OSTYPE = (free|net)bsd* ]] && args+=(
     '-l[set a lock on the stdout file descriptor]'
   )
-
+  [[ $OSTYPE = netbsd* ]] && args+=(
+    '-B+[read with buffer of specified size]:size (bytes)'
+    '-f[only attempt to display regular files]'
+  )
+elif [[ $OSTYPE = solaris* ]]; then
+  args=(
+    -A "-*"
+    '(-b)-n[number all output lines]'
+    '(-n)-b[number non-blank output lines]'
+    "-u[don't buffer output]"
+    '-s[be silent about non-existent files]'
+    '-v[display non-printing chars as ^X or M-a]'
+    '-e[display $ at the end of each line (requires -v)]'
+    '-t[display tab as ^I and formfeeds and ^L (requires -v)]'
+    '*:files:_files'
+  )
 else
   # POSIX reqires '-u', and most OSes may support '-n'
   args=(
@@ -43,4 +59,4 @@ else
   )
 fi
 
-_arguments -s -S : $args
+_arguments -s -S $args
diff --git a/Completion/Unix/Command/_date b/Completion/Unix/Command/_date
index 731f6963b..a3e933710 100644
--- a/Completion/Unix/Command/_date
+++ b/Completion/Unix/Command/_date
@@ -8,14 +8,15 @@ opts=( -s -w -C )
 
 if _pick_variant gnu="Free Software Foundation" unix --version; then
   local d='(-d --date -f --file -r --reference -s --set)'
-  local f='(-I --iso-8601 -R --rfc-2822 --rfc-3339)'
+  local f='(-I --iso-8601 -R --rfc-email --rfc-3339)'
   args=(
     $d{-d+,--date=}'[output date specified by string]:time string'
+    '--debug[annotate parsed date and warn about questionable usage]'
     $d{-f+,--file=}'[output dates specified in file]:file:_files'
     $d{-r+,--reference=}'[output last modification time of specified file]:file:_files'
     $d{-s+,--set=}'[set time]:time string'
     $f{-I-,--iso-8601=-}'[display in ISO 8601 format]::precision:(date hours minutes seconds ns)'
-    $f{-R,--rfc-2822}'[display in RFC2822 format]'
+    $f{-R,--rfc-email}'[display in RFC5322 format]'
     $f'--rfc-3339=-[display in RFC 3339 format]:precision:(date seconds ns)'
     '(-u --utc --universal)'{-u,--utc,--universal}'[display or set time in UTC]'
     '(- :)--help[output help and exit]'
diff --git a/Completion/Unix/Command/_df b/Completion/Unix/Command/_df
index a98180a2c..677b8c727 100644
--- a/Completion/Unix/Command/_df
+++ b/Completion/Unix/Command/_df
@@ -5,12 +5,6 @@ local -A opt_args
 
 if _pick_variant gnu=GNU unix --version; then
   args=(
-    '(-B --block-size -k)'{-B+,--block-size=}'[specify block size]:size (bytes)'
-    '(-B --block-size -k)-k[like --block-size=1K]'
-    '(-P --portability)'{-P,--portability}'[use the POSIX output format]'
-    '(-h --human-readable -H --si)'{-h,--human-readable}'[print sizes in human readable format]'
-    '(-h --human-readable -H --si)'{-H,--si}'[human readable fomat, but use powers of 1000 not 1024]'
-    '(-i --inodes)'{-i,--inodes}'[list inode information instead of block usage]'
     '--total[produce a grand total]'
     '(-T --print-type)'{-T,--print-type}'[print file system type]'
     '(-a --all)'{-a,--all}'[include dummy file systems]'
@@ -23,6 +17,13 @@ if _pick_variant gnu=GNU unix --version; then
     '(- : *)--help[display help and exit]'
     '(- : *)--version[output version information and exit]'
     '*:files:_files'
+    - '(format)'
+    {-B+,--block-size=}'[specify block size]:size (bytes)'
+    '-k[like --block-size=1K]'
+    {-P,--portability}'[use the POSIX output format]'
+    {-h,--human-readable}'[print sizes in human readable format]'
+    {-H,--si}'[human readable format, but use powers of 1000 not 1024]'
+    {-i,--inodes}'[list inode information instead of block usage]'
   )
 elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then
   args=(
diff --git a/Completion/Unix/Command/_fmt b/Completion/Unix/Command/_fmt
new file mode 100644
index 000000000..759396637
--- /dev/null
+++ b/Completion/Unix/Command/_fmt
@@ -0,0 +1,60 @@
+#compdef fmt
+
+local variant
+local -a args
+local copt="[preserve indentation of first two lines]"
+local wopt="[specify maximum line width]:width [75]"
+local sopt="[don't join short lines\: split only]"
+
+args=( -A "-*" "(1 2)-w+$wopt" '*:file:_files' )
+_pick_variant -r variant gnu=GNU unix --version
+case $variant in
+  gnu)
+    args=(
+      '(-c --crown-margin)'{-c,--crown-margin}$copt
+      '(-w --width)'{-w+,--width=}$wopt
+      '(-p --prefix)'{-p+,--prefix=}'[only reformat lines with specified prefix]:prefix'
+      '(-s --split-only)'{-s,--split-only}$sopt
+      '(-t --tagged-paragraph)'{-t,--tagged-paragraph}'[indentation of first line different from second]'
+      '(-u --uniform-spacing)'{-u,--uniform-spacing}'[use one space between words, two after sentences]'
+      '(-g --goal)'{-g,--goal=}'[specify goal width]:goal width [93% of width]'
+      '(- *)--help[display help information]'
+      '(- *)--version[display version information]'
+      '*:file:_files'
+    )
+  ;;
+  solaris*)
+    args=(
+      "-c$copt"
+      "-s$sopt"
+    )
+  ;;
+  netbsd*)
+    args+=(
+      '-C[center the text]'
+      '(1 2)-g+[specify goal width]:goal width'
+      '(1 2)-m+[specify maximum width]:maximum width'
+      '-r[format all lines]'
+    )
+  ;|
+  darwin*|dragonfly*|freebsd*|openbsd*)
+    args+=(
+      '-c[center the text line by line]'
+      '-m[sensible formatting of mail header lines]'
+      '-n[format lines beginning with a . (dot) character]'
+      "-p[change in indentation doesn't start new paragraph]"
+      '-s[collapse whitespace inside lines]'
+      '-d+[specify sentence-ending characters]:sentence ends [.?!]'
+      '-l+[replace initial spaces with tabs]:tab width [8]'
+      '-t+[specify tab width of input files]:tab width [8]'
+    )
+  ;& # fall-through
+  netbsd*)
+    args+=( ':: :_guard "[0-9]#" goal width' )
+    (( ${(M)#words[1,CURRENT-1]:#[0-9]##} )) && args+=(
+      ':: :_guard "[0-9]#" maximum width'
+    )
+  ;;
+esac
+
+_arguments -s -S $args
diff --git a/Completion/Unix/Command/_locate b/Completion/Unix/Command/_locate
index e2d475e27..23305f798 100644
--- a/Completion/Unix/Command/_locate
+++ b/Completion/Unix/Command/_locate
@@ -1,132 +1,96 @@
-#compdef locate mlocate slocate
+#compdef locate mlocate slocate glocate
 
-# Decide if we are using mlocate or slocate.
-local ltype basename=${words[1]:t} input
-# If we can't, use this guess.
-local best_guess=mlocate
+local variant=$service
+local -a args
+[[ $service = locate ]] &&
+  _pick_variant -r variant glocate=findutils mlocate=mlocate slocate=secure $OSTYPE -V
+args=( '(-)'{-V,--version}'[display version information]' )
 
-case $basename in
-  ([ms]locate)
-  ltype=$basename
-  ;;
+case $variant in
+  [mg]locate)
+    args+=(
+      '(-A --all)'{-A,--all}'[only print entries that match all patterns]'
+      '(-E --non-existing -e --existing)'{-e,--existing}'[restrict display to existing files]'
+      '(-c --count)'{-c,--count}'[output the number of matching entries]'
+      '(-i --ignore-case)'{-i,--ignore-case}'[ignore case distinctions in patterns]'
+      '(-w --wholename -b --basename)'{-w,--wholename}'[match entire file path (default)]'
+      '(-w --wholename -b --basename)'{-b,--basename}'[match only the basename of files in the database]'
+      '(-P -H --no-follow -L --follow)'{-P,-H,--nofollow}"[don't follow symbolic links]"
+      '(-P -H --no-follow -L --follow)'{-L,--follow}'[follow symbolic links to find existing files (default)]'
+      '(-0 --null)'{-0,--null}'[output separated by NUL characters]'
+      '(-S --statistics)'{-S,--statistics}'[show database statistics]'
+    )
+  ;|
 
-  (locate)
-  input="$(_call_program locate $words[1] -V 2>&1)"
-  case $input in
-    (*mlocate*)
-    ltype=mlocate
-    ;;
-
-    (*(#i)secure locate*)
-    ltype=slocate
-    ;;
-
-    (*(#i)gnu locate*|*findutils*gnu*)
-    ltype=gnu
-    ;;
-
-    (*"illegal option"*)
-    if [[ $OSTYPE == (freebsd|openbsd|dragonfly|darwin)* ]]; then
-      ltype=bsd
-    else
-      ltype=$best_guess
-    fi
-    ;;
-
-    # guess
-    (*)
-    ltype=$best_guess
-    ;;
-  esac
-  ;;
-
-  (*)
-  # too dangerous to run: guess
-  ltype=$best_guess
-esac
-
-case $ltype in
   (mlocate)
   # -r/--regexp mean no normal arguments, so shouldn't complete
   # -m and --mmap are ignored, so don't bother
   # -s and --stdio likewise
-  _arguments -s -S : \
-    '(-A --all)'{-A,--all}'[only print entries that match all patterns]' \
-    {-b,--basename}'[match only the basename of files in the database]' \
-    {-c,--count}'[output the number of matching entries]' \
-    {-d,--database=}'[use alternative database]:database:_sequence -s \: _files' \
-    {-e,--existing}'[restrict display to existing files]' \
-    {-L,--follow}'[follow symbolic links to find existing files (default)]' \
-    '(-)'{-h,--help}'[display help information]' \
-    {-i,--ignore-case}'[ignore case distinctions in patterns]' \
-    {-l,-n,--limit=}'[limit search results]:file limit: ' \
-    {-P,-H,--nofollow}'[don'\''t follow symbolic links]' \
-    {-0,--null}'[output separated by NUL characters]' \
-    {-S,--statistics}'[show database statistics]' \
-    {-q,--quiet}'[don'\''t report errors]' \
-    {-r,--regexp=}'[search for given basic regexp]:basic regexp: ' \
-    --regex'[patterns are extended regexps]' \
-    '(-)'{-V,--version}'[display version information]' \
-    {-w,--wholename}'[match entire file path (default)]' \
-    '*:pattern: '
+    args=( -s -S : $args
+      \*{-d,--database=}'[use alternative database]:database:_sequence -s \: _files'
+      '(-)'{-h,--help}'[display help information]'
+      '(-l -n --limit)'{-l,-n,--limit=}'[limit search results]:file limit'
+      '(-q --quiet)'{-q,--quiet}"[don't report errors]"
+      '(:)*'{-r,--regexp=}'[search for given basic regexp]:basic regexp'
+      '--regex[patterns are extended regexps]'
+    )
   ;;
 
   (slocate)
   # -d can take path
   # -e can take a comma-separated list of directories.
   # -f should complete list of file system types like mount
-  _arguments -s -S : \
-    -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 -/' \
-    -f'[exclude file system types from db with -u, -U]:file system:_file_systems' \
-    -l'[security level]:level:(0 1)' \
-    -q'[quiet mode]' \
-    -n'[limit search results]:file limit: ' \
-    -i'[case insensitive search]' \
-    {-r,--regexp=}'[use basic regular expression]:regexp: ' \
-    {-o,--output=}'[specify database to create]:database:_files' \
-    {-d,--database=}'[specify database to search]:database:_files' \
-    {-h,--help}'[display help]' \
-    {-v,--verbose}'[display files when creating database]' \
-    {-V,--version}'[display version]' \
-    '*:pattern: '
+    args=( -s -S : $args
+      -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 -/'
+      -f'[exclude file system types from db with -u, -U]:file system:_file_systems'
+      -l'[security level]:level:(0 1)'
+      -q'[quiet mode]'
+      -n'[limit search results]:file limit '
+      -i'[case insensitive search]'
+      {-r,--regexp=}'[use basic regular expression]:regexp'
+      {-o,--output=}'[specify database to create]:database:_files'
+      {-d,--database=}'[specify database to search]:database:_files'
+      '(-)'{-h,--help}'[display help information]'
+      {-v,--verbose}'[display files when creating database]'
+    )
   ;;
 
-  (gnu)
-  _arguments -s : \
-    {-d,--database=}'[use alternative database]:database:_files' \
-    {-e,--existing}'[restrict display to existing files]' \
-    {-E,--non-existing}'[allow display of nonexistent files (default)]' \
-    {-i,--ignore-case}'[ignore case distinctions in patterns]' \
-    {-w,--wholename}'[match entire file path (default)]' \
-    {-b,--basename}'[match only the basename of files in the database]' \
-    {-l,-n,--limit=}'[limit search results]:file limit: ' \
-    {-S,--statistics}'[show database statistics]' \
-    {-0,--null}'[output separated by NUL characters]' \
-    {-c,--count}'[output the number of matching entries]' \
-    {-P,-H,--nofollow}'[don'\''t follow symbolic links]' \
-    {-L,--follow}'[follow symbolic links to find existing files (default)]' \
-    {-A,-all}'[match all arguments instead of at least one]' \
-    {-p,--print}'[include search results with statistics or count]' \
-    {-r,--regex=}'[patterns are regular expressions]:basic regexp: ' \
-    --regextype='[select type of regular expression]:regex type:(findutils-default awk egrep ed emacs gnu-awk grep posix-awk posix-basic posix-egrep posix-extended posix-minimal-basic sed)' \
-    {-V,--version}'[show version]' \
-    --help'[show help]' \
-    '*:pattern: '
+  (glocate)
+    args=( -s : $args
+      \*{-d,--database=}'[use alternative database]:database:_files'
+      '(-E --non-existing -e --existing)'{-E,--non-existing}'[restrict display to nonexistent files]'
+      '(-l --limit)'{-l,--limit=}'[limit search results]:file limit: '
+      '--max-database-age[specify database age at which warning should be issued]:age (days) [8]'
+      '(-p --print)'{-p,--print}'[include search results with statistics or count]'
+      \*{-r,--regex=}'[patterns are regular expressions]:regexp'
+      --regextype='[select type of regular expression]:regex type [basic]:(findutils-default awk egrep ed emacs gnu-awk grep posix-awk posix-basic posix-egrep posix-extended posix-minimal-basic sed)'
+      '(-)'--help'[display help information]'
+    )
   ;;
 
-  (bsd)
-  _arguments -s -S -A '-*' \
-    '(-S)-0[separate file names by NUL characters]' \
-    '(- *)-S[show database statistics and exit]' \
-    '(-S)-c[output the number of matching file names]' \
-    '(-S)*-d[specify database to search]:database:_files' \
-    '(-S)-i[ignore case distinctions in pattern and database]' \
-    '(-S)-l[limit output to specified number of file names]:file limit: ' \
-    '(-S)-m[use mmap(2) instead of stdio(3) (default)]' \
-    '(-S)-s[use stdio(3) instead of mmap(2)]' \
-    '*:pattern: '
-  ;;
+  (freebsd|openbsd|dragonfly|darwin)*)
+    args=( -s -S -A '-*'
+      '(-S)-c[output the number of matching file names]'
+      '(-S)-i[ignore case distinctions in pattern and database]'
+      '(-S)-l[limit output to specified number of file names]:file limit '
+      '(- *)-S[show database statistics and exit]'
+    )
+  ;|
+  openbsd*)
+    args+=( '(-S)-b[match only the basename of files in the database]' )
+  ;|
+  (freebsd|dragonfly|darwin)*)
+    args+=(
+      '(-S)-0[separate file names by NUL characters]'
+      '(-S)-m[use mmap(2) instead of stdio(3) (default)]'
+      '(-S)-s[use stdio(3) instead of mmap(2)]'
+    )
+  ;|
+  (*) args+=( '(-S)*-d[specify database to search]:database:_files' ) ;;
+
 esac
+
+_arguments $args '*: :_guard "^-*" pattern'
diff --git a/Completion/Unix/Command/_ls b/Completion/Unix/Command/_ls
index 2ca59423d..ca20107c2 100644
--- a/Completion/Unix/Command/_ls
+++ b/Completion/Unix/Command/_ls
@@ -131,7 +131,7 @@ else
     '(--width -w)'{--width=,-w+}'[specify screen width]:screen width'
 
     '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--escape,-b}'[print octal escapes for control characters]'
-    '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--literal,-N}'[print raw characters]'
+    '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--literal,-N}'[print entry names without quoting]'
     '(--quoting-style -b --escape -N --literal -Q --quote-name)'{--quote-name,-Q}'[quote names]'
     '(-b --escape -N --literal -Q --quote-name)--quoting-style=:quoting style:(literal shell shell-always c escape clocale locale)'
 
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 73d7508b4..963b43f27 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -58,6 +58,7 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
 	'--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:*}##*: })"
+	'--with-symbol-versions[display version strings after symbol names]'
       )
     ;;
   esac
diff --git a/Completion/Unix/Command/_paste b/Completion/Unix/Command/_paste
new file mode 100644
index 000000000..6efe8eacb
--- /dev/null
+++ b/Completion/Unix/Command/_paste
@@ -0,0 +1,19 @@
+#compdef paste
+
+local -a args
+local dopt='[specify delimiter list]:delimiter list [tab]'
+local sopt='[paste one file at a time instead of in parallel]'
+
+if _pick_variant gnu=GNU unix --version; then
+  args=(
+    '(-z --zero-terminated)'{-z,--zero-terminated}'[use NUL as line delimiter instead of newline]'
+    "(-d)--delimiters=$dopt"
+    "(-s)--serial$sopt"
+    '(- *)--help[display help information]'
+    '(- *)--version[display version information]'
+  )
+else
+  args=( -A "-?*" )
+fi
+
+_arguments -s $args "(--delimiters)-d+$dopt" "(--serial)-s$sopt" '*:file:_files'
diff --git a/Completion/Unix/Command/_readelf b/Completion/Unix/Command/_readelf
index 15d5145c5..46da00cc4 100644
--- a/Completion/Unix/Command/_readelf
+++ b/Completion/Unix/Command/_readelf
@@ -34,6 +34,7 @@ case $variant in
       '(-g --section-groups)'{-g,--section-groups}'[show section groups]'
       '(-t --section-details)'{-t,--section-details}'[show section details]'
       '(-e --headers)'{-e,--headers}'[show file, program and sections headers]'
+      '(-s --syms --symbols)'{-s,--syms,--symbols}'[show symbol table]'
       '(-u --unwind)'{-u,--unwind}'[show unwind info (if present)]'
       '(-D --use-dynamic)'{-D,--use-dynamic}'[use dynamic section info when showing symbols]'
     )
@@ -52,6 +53,8 @@ case $variant in
       '(-e --exception)'{-e,--exception}'[show sections for exception handling]'
       '(-N --numeric-addresses)'{-N,--numeric-addresses}"[don't find symbol names for addresses in DWARF data]"
       '(-z --decompress)'{-z,--decompress}'[show compression information; decompress before dumping data]'
+      '(--symbols)-s[show symbol table]'
+      '(-s)--symbols=-[show symbol table]::section:(.dynsym .symtab)'
     )
   ;;
 esac
diff --git a/Completion/Unix/Command/_sed b/Completion/Unix/Command/_sed
index 259477f93..222798b8a 100644
--- a/Completion/Unix/Command/_sed
+++ b/Completion/Unix/Command/_sed
@@ -23,8 +23,9 @@ elif _pick_variant gnu=GNU unix --version; then
     '(-i --in-place)'{-i-,--in-place=-}$inplace
     '(-l --line-length)'{-l,--line-length=-}'[specify line-wrap length for the l command]'
     '(-r)--posix[disable GNU extensions]'
-    '(-r --regexp-extended)'{-r,--regexp-extended}$extended
+    '(-E -r --regexp-extended)'{-E,-r,--regexp-extended}$extended
     '(-s --separate)'{-s,--separate}'[consider files separately instead of as a combined stream]'
+    '--sandbox[block commands that can affect the system (r/w/W/e)]'
     '(-u --unbuffered)'{-u,--unbuffered}'[disable data buffering]'
     '(-z --null-data)'{-z,--null-data}'[separate lines by NUL characters]'
     '(- 1 :)--help[print program usage]'
diff --git a/Completion/Unix/Command/_strip b/Completion/Unix/Command/_strip
index 726d87c2b..f244b0ace 100644
--- a/Completion/Unix/Command/_strip
+++ b/Completion/Unix/Command/_strip
@@ -16,11 +16,12 @@ if _pick_variant gnu=GNU solaris --version; then
   fi
   args=(
     '(-F --target)'{-F+,--target=}'[object code format to use]:bfd name:->bfdnames'
-    '--help[display usage information and exit]'
-    '--info[display list of architectures and object formats]'
+    '(-)--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)'{-I+,--output-target=}'[object code format of output]:bfd name:->bfdnames'
     '*'{-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-unneeded[remove symbols not needed for relocation processing]'
@@ -33,7 +34,7 @@ if _pick_variant gnu=GNU solaris --version; then
     '(-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)'{-V,--version}'[display version information and exit]'
+    '(-)'{-V,--version}'[display version information and exit]'
     '(-v --verbose)'{-v,--verbose}'[list all object files modified or members of archives]')
 else
   args=(


^ permalink raw reply	[relevance 15%]

* Alias expansion inconsistency in $(command substitutions) with IGNORE_CLOSE_BRACES
@ 2017-04-16 16:07  4% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2017-04-16 16:07 UTC (permalink / raw)
  To: zsh-workers

If either the IGNORE_CLOSE_BRACES or IGNORE_BRACES option is active,
there is an inconsistency in alias expansion within command
substitutions, specifically those of the form $(command).

Given:

% set -o ignoreclosebraces
% alias OPEN='{' CLOSE='};'

These work fine:

% { OPEN echo hi; CLOSE }
hi
% var=`{ OPEN echo hi; CLOSE }` && echo "$var"
hi

But this does not:

% var=$({ OPEN echo hi; CLOSE }) && echo "$var"
zsh: parse error near `)'
zsh: parse error near `var=$({ OPEN echo hi...'

This inconsistency seems to have been introduced around zsh 5.2; it's
not present in zsh 5.1.1 and earlier.

Thanks,

- M.

In case anyone wonders about an actual use case for aliases like these,
it's the var/setlocal module of modernish, my cross platform POSIX shell
library:
https://github.com/modernish/modernish#user-content-use-varsetlocal
This basically brings the functionality of zsh anonymous functions to
plain POSIX shells. Of course this would be redundant on scripts written
for zsh, but it would be nice if cross-shell scripts run consistently.


^ permalink raw reply	[relevance 4%]

* Re: Call stack issues when running trap handler
  @ 2017-04-26 19:27  5% ` Peter Stephenson
  2017-04-26 19:52  4%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-04-26 19:27 UTC (permalink / raw)
  To: zsh-workers

On Fri, 21 Apr 2017 22:32:46 +0200
Sebastian Reuße <seb@wirrsal.net> wrote:
> I’ve noticed that under certain conditions, shell functions called from
> inside an exit trap handler appear to never return. E.g., running the
> following code will only yield «a» as output, indicating that callee
> «echoa» never returns control to the caller «handler».

I've just re-read this and compared with the evidence and obviously I've
misinterpreted it.  When you said "never return", you meant it exited
from that point (so never printed "b" but did leave the shell
nonetheless).  I interpreted this as saying it got stuck in that
function, but that obviously isn't what you mean.

This I can fix.

If anyone knows whether I need to distinguish in any of the following
between EXIT traps for functions and the shell as a whole, feel free to
tell me.  I'm assuming it's going to be too arcane to worry about.

pws

diff --git a/Src/builtin.c b/Src/builtin.c
index b2e552d..ff07b04 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5509,8 +5509,11 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
 	     *
 	     * If we are forked, we exit the shell at the function depth
 	     * at which we became a subshell, hence the comparison.
+	     *
+	     * If we *are* in an EXIT trap... give this all up as
+	     * a bad job.
 	     */
-	    if (stopmsg || (zexit(0,2), !stopmsg)) {
+	    if ((stopmsg || (zexit(0,2), !stopmsg)) && !in_exit_trap) {
 		retflag = 1;
 		breaks = loops;
 		exit_pending = (num << 1) | 1;
diff --git a/Src/exec.c b/Src/exec.c
index 978a32d..e0fc544 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5688,8 +5688,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
      * the only likely case where we need that second test is
      * when we have an "always" block.  The endparamscope() has
      * already happened, hence the "+1" here.
+     *
+     * If we are in an exit trap, finish it first... we wouldn't set
+     * exit_pending if we were already in one.
      */
-    if (exit_pending && exit_level >= locallevel+1) {
+    if (exit_pending && exit_level >= locallevel+1 && !in_exit_trap) {
 	if (locallevel > forklevel) {
 	    /* Still functions to return: force them to do so. */
 	    retflag = 1;
diff --git a/Src/signals.c b/Src/signals.c
index 68a7ae3..cad40f4 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -55,6 +55,11 @@ mod_export Eprog siglists[VSIGCOUNT];
 /**/
 mod_export int nsigtrapped;
 
+/* Running an exit trap? */
+
+/**/
+int in_exit_trap;
+
 /*
  * Flag that exit trap has been set in POSIX mode.
  * The setter's expectation is therefore that it is run
@@ -1435,7 +1440,13 @@ dotrap(int sig)
 
     dont_queue_signals();
 
+    if (sig == SIGEXIT)
+	++in_exit_trap;
+
     dotrapargs(sig, sigtrapped+sig, funcprog);
 
+    if (sig == SIGEXIT)
+	--in_exit_trap;
+
     restore_queue_signals(q);
 }


^ permalink raw reply	[relevance 5%]

* Re: Call stack issues when running trap handler
  2017-04-26 19:27  5% ` Peter Stephenson
@ 2017-04-26 19:52  4%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-04-26 19:52 UTC (permalink / raw)
  To: zsh-workers

On Wed, 26 Apr 2017 20:27:29 +0100
Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> This I can fix.

I think I like this better.

shell_exiting looks like a good way of ensuring we don't tie ourselves
in knots with exits, independent of in_exit_trap which we still need for
the original fix.  The interaction is that when we commit to exiting
shell_exiting goes to -1; then we won't set exit_pending in zexit();
that means we don't hit the case that caused us to exit early.  Or
something.

pws

diff --git a/Src/builtin.c b/Src/builtin.c
index b2e552d..063644e 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5500,7 +5500,7 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
 	}
 	/*FALLTHROUGH*/
     case BIN_EXIT:
-	if (locallevel > forklevel) {
+	if (locallevel > forklevel && shell_exiting != -1) {
 	    /*
 	     * We don't exit directly from functions to allow tidying
 	     * up, in particular EXIT traps.  We still need to perform
@@ -5509,6 +5509,9 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
 	     *
 	     * If we are forked, we exit the shell at the function depth
 	     * at which we became a subshell, hence the comparison.
+	     *
+	     * If we are already exiting... give this all up as
+	     * a bad job.
 	     */
 	    if (stopmsg || (zexit(0,2), !stopmsg)) {
 		retflag = 1;
@@ -5555,6 +5558,14 @@ checkjobs(void)
     }
 }
 
+/*
+ * -1 if the shell is already committed to exit.
+ * positive if zexit() was already called.
+ */
+
+/**/
+int shell_exiting;
+
 /* exit the shell.  val is the return value of the shell.  *
  * from_where is
  *   1   if zexit is called because of a signal
@@ -5566,10 +5577,8 @@ checkjobs(void)
 mod_export void
 zexit(int val, int from_where)
 {
-    static int in_exit;
-
     /* Don't do anything recursively:  see below */
-    if (in_exit == -1)
+    if (shell_exiting == -1)
 	return;
 
     if (isset(MONITOR) && !stopmsg && from_where != 1) {
@@ -5582,14 +5591,14 @@ zexit(int val, int from_where)
 	}
     }
     /* Positive in_exit means we have been here before */
-    if (from_where == 2 || (in_exit++ && from_where))
+    if (from_where == 2 || (shell_exiting++ && from_where))
 	return;
 
     /*
-     * We're now committed to exiting.  Set in_exit to -1 to
+     * We're now committed to exiting.  Set shell_exiting to -1 to
      * indicate we shouldn't do any recursive processing.
      */
-    in_exit = -1;
+    shell_exiting = -1;
     /*
      * We want to do all remaining processing regardless of preceding
      * errors, even user interrupts.
diff --git a/Src/exec.c b/Src/exec.c
index 978a32d..e0fc544 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5688,8 +5688,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
      * the only likely case where we need that second test is
      * when we have an "always" block.  The endparamscope() has
      * already happened, hence the "+1" here.
+     *
+     * If we are in an exit trap, finish it first... we wouldn't set
+     * exit_pending if we were already in one.
      */
-    if (exit_pending && exit_level >= locallevel+1) {
+    if (exit_pending && exit_level >= locallevel+1 && !in_exit_trap) {
 	if (locallevel > forklevel) {
 	    /* Still functions to return: force them to do so. */
 	    retflag = 1;
diff --git a/Src/signals.c b/Src/signals.c
index 68a7ae3..cad40f4 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -55,6 +55,11 @@ mod_export Eprog siglists[VSIGCOUNT];
 /**/
 mod_export int nsigtrapped;
 
+/* Running an exit trap? */
+
+/**/
+int in_exit_trap;
+
 /*
  * Flag that exit trap has been set in POSIX mode.
  * The setter's expectation is therefore that it is run
@@ -1435,7 +1440,13 @@ dotrap(int sig)
 
     dont_queue_signals();
 
+    if (sig == SIGEXIT)
+	++in_exit_trap;
+
     dotrapargs(sig, sigtrapped+sig, funcprog);
 
+    if (sig == SIGEXIT)
+	--in_exit_trap;
+
     restore_queue_signals(q);
 }
diff --git a/Test/C03traps.ztst b/Test/C03traps.ztst
index 7bc0b48..7594012 100644
--- a/Test/C03traps.ztst
+++ b/Test/C03traps.ztst
@@ -756,6 +756,27 @@ F:Must be tested with a top-level script rather than source or function
 >''
 >hello
 
+  $ZTST_testdir/../Src/zsh -f =(<<<"
+    trap handler EXIT
+    handler() {
+      echoa
+      echo b
+    }
+    echoa() {
+      echo a
+    }
+    exit0() {
+      exit
+    }
+    main() {
+      exit0
+    }
+    main
+  ")
+0:No early exit from nested function in EXIT trap.
+>a
+>b
+
 %clean
 
   rm -f TRAPEXIT


^ permalink raw reply	[relevance 4%]

* Zsh parser malloc corruption
@ 2017-05-08 13:53  1% Eduardo Bustamante
  0 siblings, 0 replies; 200+ results
From: Eduardo Bustamante @ 2017-05-08 13:53 UTC (permalink / raw)
  To: zsh-workers; +Cc: Eduardo A. Bustamante López

dualbus@debian:~/bash-fuzzing/zsh-parser$ cat -v malloc-corruption
0000000000000000000000000000000000000000${0#0000000000000000^@000000000000000000000000000000000000000000000000000^@^@000M-^GM-^O0000000$000000#000000000000$$$0}000000000000&0000000000000000000000000000000000000000000000000000000000000000&00000000

dualbus@debian:~/bash-fuzzing/zsh-parser$ base64 malloc-corruption
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMCR7MCMwMDAwMDAwMDAwMDAw
MDAwADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAA
MDAwh48wMDAwMDAwJDAwMDAwMCMwMDAwMDAwMDAwMDAkJCQwfTAwMDAwMDAwMDAwMCYwMDAwMDAw
MDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAw
JjAwMDAwMDAwCg==

dualbus@debian:~/bash-fuzzing/zsh-parser$ ~/src/zsh/zsh/Src/zsh -n
malloc-corruption
*** Error in `/home/dualbus/src/zsh/zsh/Src/zsh': malloc(): memory
corruption: 0x0000000000aca090 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x70bcb)[0x7f47ad245bcb]
/lib/x86_64-linux-gnu/libc.so.6(+0x76f96)[0x7f47ad24bf96]
/lib/x86_64-linux-gnu/libc.so.6(+0x78f69)[0x7f47ad24df69]
/lib/x86_64-linux-gnu/libc.so.6(__libc_malloc+0x54)[0x7f47ad24fd84]
/home/dualbus/src/zsh/zsh/Src/zsh(zalloc+0x3c)[0x4798dc]
/home/dualbus/src/zsh/zsh/Src/zsh(setunderscore+0xa2)[0x435892]
/home/dualbus/src/zsh/zsh/Src/zsh[0x43d6b5]
/home/dualbus/src/zsh/zsh/Src/zsh[0x43b804]
/home/dualbus/src/zsh/zsh/Src/zsh[0x433f6e]
/home/dualbus/src/zsh/zsh/Src/zsh(execlist+0x64e)[0x432dfe]
/home/dualbus/src/zsh/zsh/Src/zsh(execode+0x11e)[0x43277e]
/home/dualbus/src/zsh/zsh/Src/zsh(loop+0x416)[0x45e366]
/home/dualbus/src/zsh/zsh/Src/zsh(zsh_main+0x366)[0x4627d6]
/home/dualbus/src/zsh/zsh/Src/zsh(main+0x22)[0x411a32]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f47ad1f52b1]
/home/dualbus/src/zsh/zsh/Src/zsh(_start+0x2a)[0x41193a]
======= Memory map: ========
00400000-004e9000 r-xp 00000000 fe:01 18487233
  /home/dualbus/src/zsh/zsh/Src/zsh
006e9000-006ea000 r--p 000e9000 fe:01 18487233
  /home/dualbus/src/zsh/zsh/Src/zsh
006ea000-006f1000 rw-p 000ea000 fe:01 18487233
  /home/dualbus/src/zsh/zsh/Src/zsh
006f1000-00704000 rw-p 00000000 00:00 0
00ab3000-00ad4000 rw-p 00000000 00:00 0                                  [heap]
7f47a8000000-7f47a8021000 rw-p 00000000 00:00 0
7f47a8021000-7f47ac000000 ---p 00000000 00:00 0
7f47ac563000-7f47ac579000 r-xp 00000000 fe:01 1310769
  /lib/x86_64-linux-gnu/libgcc_s.so.1
7f47ac579000-7f47ac778000 ---p 00016000 fe:01 1310769
  /lib/x86_64-linux-gnu/libgcc_s.so.1
7f47ac778000-7f47ac779000 r--p 00015000 fe:01 1310769
  /lib/x86_64-linux-gnu/libgcc_s.so.1
7f47ac779000-7f47ac77a000 rw-p 00016000 fe:01 1310769
  /lib/x86_64-linux-gnu/libgcc_s.so.1
7f47ac77a000-7f47ac784000 r-xp 00000000 fe:01 1311265
  /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f47ac784000-7f47ac984000 ---p 0000a000 fe:01 1311265
  /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f47ac984000-7f47ac985000 r--p 0000a000 fe:01 1311265
  /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f47ac985000-7f47ac986000 rw-p 0000b000 fe:01 1311265
  /lib/x86_64-linux-gnu/libnss_files-2.24.so
7f47ac986000-7f47ac98c000 rw-p 00000000 00:00 0
7f47ac98c000-7f47ac997000 r-xp 00000000 fe:01 1311269
  /lib/x86_64-linux-gnu/libnss_nis-2.24.so
7f47ac997000-7f47acb96000 ---p 0000b000 fe:01 1311269
  /lib/x86_64-linux-gnu/libnss_nis-2.24.so
7f47acb96000-7f47acb97000 r--p 0000a000 fe:01 1311269
  /lib/x86_64-linux-gnu/libnss_nis-2.24.so
7f47acb97000-7f47acb98000 rw-p 0000b000 fe:01 1311269
  /lib/x86_64-linux-gnu/libnss_nis-2.24.so
7f47acb98000-7f47acbac000 r-xp 00000000 fe:01 1311178
  /lib/x86_64-linux-gnu/libnsl-2.24.so
7f47acbac000-7f47acdac000 ---p 00014000 fe:01 1311178
  /lib/x86_64-linux-gnu/libnsl-2.24.so
7f47acdac000-7f47acdad000 r--p 00014000 fe:01 1311178
  /lib/x86_64-linux-gnu/libnsl-2.24.so
7f47acdad000-7f47acdae000 rw-p 00015000 fe:01 1311178
  /lib/x86_64-linux-gnu/libnsl-2.24.so
7f47acdae000-7f47acdb0000 rw-p 00000000 00:00 0
7f47acdb0000-7f47acdb7000 r-xp 00000000 fe:01 1311180
  /lib/x86_64-linux-gnu/libnss_compat-2.24.so
7f47acdb7000-7f47acfb6000 ---p 00007000 fe:01 1311180
  /lib/x86_64-linux-gnu/libnss_compat-2.24.so
7f47acfb6000-7f47acfb7000 r--p 00006000 fe:01 1311180
  /lib/x86_64-linux-gnu/libnss_compat-2.24.so
7f47acfb7000-7f47acfb8000 rw-p 00007000 fe:01 1311180
  /lib/x86_64-linux-gnu/libnss_compat-2.24.so
7f47acfb8000-7f47acfd0000 r-xp 00000000 fe:01 1311335
  /lib/x86_64-linux-gnu/libpthread-2.24.so
7f47acfd0000-7f47ad1cf000 ---p 00018000 fe:01 1311335
  /lib/x86_64-linux-gnu/libpthread-2.24.so
7f47ad1cf000-7f47ad1d0000 r--p 00017000 fe:01 1311335
  /lib/x86_64-linux-gnu/libpthread-2.24.so
7f47ad1d0000-7f47ad1d1000 rw-p 00018000 fe:01 1311335
  /lib/x86_64-linux-gnu/libpthread-2.24.so
7f47ad1d1000-7f47ad1d5000 rw-p 00000000 00:00 0
7f47ad1d5000-7f47ad36a000 r-xp 00000000 fe:01 1311151
  /lib/x86_64-linux-gnu/libc-2.24.so
7f47ad36a000-7f47ad569000 ---p 00195000 fe:01 1311151
  /lib/x86_64-linux-gnu/libc-2.24.so
7f47ad569000-7f47ad56d000 r--p 00194000 fe:01 1311151
  /lib/x86_64-linux-gnu/libc-2.24.so
7f47ad56d000-7f47ad56f000 rw-p 00198000 fe:01 1311151
  /lib/x86_64-linux-gnu/libc-2.24.so
7f47ad56f000-7f47ad573000 rw-p 00000000 00:00 0
7f47ad573000-7f47ad676000 r-xp 00000000 fe:01 1311172
  /lib/x86_64-linux-gnu/libm-2.24.so
7f47ad676000-7f47ad875000 ---p 00103000 fe:01 1311172
  /lib/x86_64-linux-gnu/libm-2.24.so
7f47ad875000-7f47ad876000 r--p 00102000 fe:01 1311172
  /lib/x86_64-linux-gnu/libm-2.24.so
7f47ad876000-7f47ad877000 rw-p 00103000 fe:01 1311172
  /lib/x86_64-linux-gnu/libm-2.24.so
7f47ad877000-7f47ad87e000 r-xp 00000000 fe:01 1313974
  /lib/x86_64-linux-gnu/librt-2.24.so
7f47ad87e000-7f47ada7d000 ---p 00007000 fe:01 1313974
  /lib/x86_64-linux-gnu/librt-2.24.so
7f47ada7d000-7f47ada7e000 r--p 00006000 fe:01 1313974
  /lib/x86_64-linux-gnu/librt-2.24.so
7f47ada7e000-7f47ada7f000 rw-p 00007000 fe:01 1313974
  /lib/x86_64-linux-gnu/librt-2.24.so
7f47ada7f000-7f47adaa4000 r-xp 00000000 fe:01 1310814
  /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f47adaa4000-7f47adca4000 ---p 00025000 fe:01 1310814
  /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f47adca4000-7f47adca8000 r--p 00025000 fe:01 1310814
  /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f47adca8000-7f47adca9000 rw-p 00029000 fe:01 1310814
  /lib/x86_64-linux-gnu/libtinfo.so.5.9
7f47adca9000-7f47adcac000 r-xp 00000000 fe:01 1311170
  /lib/x86_64-linux-gnu/libdl-2.24.so
7f47adcac000-7f47adeab000 ---p 00003000 fe:01 1311170
  /lib/x86_64-linux-gnu/libdl-2.24.so
7f47adeab000-7f47adeac000 r--p 00002000 fe:01 1311170
  /lib/x86_64-linux-gnu/libdl-2.24.so
7f47adeac000-7f47adead000 rw-p 00003000 fe:01 1311170
  /lib/x86_64-linux-gnu/libdl-2.24.so
7f47adead000-7f47aded0000 r-xp 00000000 fe:01 1310733
  /lib/x86_64-linux-gnu/ld-2.24.so
7f47adf32000-7f47adf37000 rw-p 00000000 00:00 0
7f47adf37000-7f47adf88000 r--p 00000000 fe:01 26351510
  /usr/lib/locale/aa_DJ.utf8/LC_CTYPE
7f47adf88000-7f47ae0b8000 r--p 00000000 fe:01 26351509
  /usr/lib/locale/aa_DJ.utf8/LC_COLLATE
7f47ae0b8000-7f47ae0bc000 rw-p 00000000 00:00 0
7f47ae0bc000-7f47ae0bd000 r--p 00000000 fe:01 26351533
  /usr/lib/locale/aa_ET/LC_NUMERIC
7f47ae0bd000-7f47ae0be000 r--p 00000000 fe:01 26480725
  /usr/lib/locale/en_US.utf8/LC_TIME
7f47ae0be000-7f47ae0bf000 r--p 00000000 fe:01 26355066
  /usr/lib/locale/chr_US/LC_MONETARY
7f47ae0bf000-7f47ae0c0000 r--p 00000000 fe:01 26355282
  /usr/lib/locale/en_AG/LC_MESSAGES/SYS_LC_MESSAGES
7f47ae0c0000-7f47ae0c1000 r--p 00000000 fe:01 26355068
  /usr/lib/locale/chr_US/LC_PAPER
7f47ae0c1000-7f47ae0c2000 r--p 00000000 fe:01 26355067
  /usr/lib/locale/chr_US/LC_NAME
7f47ae0c2000-7f47ae0c3000 r--p 00000000 fe:01 26480723
  /usr/lib/locale/en_US.utf8/LC_ADDRESS
7f47ae0c3000-7f47ae0c4000 r--p 00000000 fe:01 26355069
  /usr/lib/locale/chr_US/LC_TELEPHONE
7f47ae0c4000-7f47ae0c5000 r--p 00000000 fe:01 26355064
  /usr/lib/locale/chr_US/LC_MEASUREMENT
7f47ae0c5000-7f47ae0cc000 r--s 00000000 fe:01 25449459
  /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7f47ae0cc000-7f47ae0cd000 r--p 00000000 fe:01 26480724
  /usr/lib/locale/en_US.utf8/LC_IDENTIFICATION
7f47ae0cd000-7f47ae0d0000 rw-p 00000000 00:00 0
7f47ae0d0000-7f47ae0d1000 r--p 00023000 fe:01 1310733
  /lib/x86_64-linux-gnu/ld-2.24.so
7f47ae0d1000-7f47ae0d2000 rw-p 00024000 fe:01 1310733
  /lib/x86_64-linux-gnu/ld-2.24.so
7f47ae0d2000-7f47ae0d3000 rw-p 00000000 00:00 0
7ffd82d8d000-7ffd82dae000 rw-p 00000000 00:00 0                          [stack]
7ffd82de7000-7ffd82de9000 r--p 00000000 00:00 0                          [vvar]
7ffd82de9000-7ffd82deb000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0
  [vsyscall]
Aborted

(gdb) bt
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007ffff71353fa in __GI_abort () at abort.c:89
#2  0x00007ffff7171bd0 in __libc_message (do_abort=do_abort@entry=2,
    fmt=fmt@entry=0x7ffff7266bd0 "*** Error in `%s': %s: 0x%s ***\n")
at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7177f96 in malloc_printerr (action=3,
str=0x7ffff72637cb "malloc(): memory corruption", ptr=<optimized out>,
    ar_ptr=<optimized out>) at malloc.c:5046
#4  0x00007ffff7179f69 in _int_malloc (av=av@entry=0x7ffff7499b00
<main_arena>, bytes=bytes@entry=96) at malloc.c:3509
#5  0x00007ffff717bd84 in __GI___libc_malloc (bytes=96) at malloc.c:2925
#6  0x00000000004798dc in zalloc (size=96) at mem.c:966
#7  0x0000000000435892 in setunderscore (str=0x7ffff7e5bc18 '0'
<repeats 40 times>, "malloc-corruption", '0' <repeats 12 times>)
    at exec.c:2518
#8  0x000000000043d6b5 in execcmd_exec (state=0x7fffffffde20,
eparams=0x7fffffffcce0, input=0, output=0, how=4, last1=2)
    at exec.c:3183
#9  0x000000000043b804 in execpline2 (state=0x7fffffffde20, pcode=131,
how=4, input=0, output=0, last1=0) at exec.c:1873
#10 0x0000000000433f6e in execpline (state=0x7fffffffde20,
slcode=3074, how=4, last1=0) at exec.c:1602
#11 0x0000000000432dfe in execlist (state=0x7fffffffde20,
dont_change_job=0, exiting=0) at exec.c:1360
#12 0x000000000043277e in execode (p=0x7ffff7e5b5c0,
dont_change_job=0, exiting=0, context=0x4d90c4 "toplevel") at
exec.c:1141
#13 0x000000000045e366 in loop (toplevel=1, justonce=0) at init.c:208
#14 0x00000000004627d6 in zsh_main (argc=3, argv=0x7fffffffe448) at init.c:1692
#15 0x0000000000411a32 in main (argc=3, argv=0x7fffffffe448) at ./main.c:93


^ permalink raw reply	[relevance 1%]

* [PATCH] _nm: support macOS and OpenBSD
@ 2017-05-29  4:28 12% Jun T.
  0 siblings, 0 replies; 200+ results
From: Jun T. @ 2017-05-29  4:28 UTC (permalink / raw)
  To: zsh-workers

Added support for darwin and openbsd.
(FreeBSD is now using elftoolchain. NetBSD and dragonfly are
still using binutils.)
Also included a few updates for elftoolchain/elfutils.


diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 963b43f..146a69e 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -5,55 +5,62 @@ local args files variant
 files="*:object file:_object_files"
 args=(
   '(-A -o --print-file-name)'{-A,-o,--print-file-name}'[print name of input file on each line]'
-  '(--demangle)-C[decode symbol names]'
+  '(--demangle --no-demangle)-C[decode symbol names]'
   '(-D --dynamic)'{-D,--dynamic}'[display dynamic symbols instead of normal ones]'
   '(-g --extern-only)'{-g,--extern-only}'[display only global symbols]'
   '(-t --radix -o -x)'{-t,--radix}'[specify radix for numeric values]:radix:((d\:decimal o\:octal x\:hexadecimal))'
 )
 
 if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfutils unix -V; then
-  compset -P '@' && files='*:options file:_files'
   args+=(
     '(- *)--help[display help information]'
-    '(- *)--version[display version information]'
+    '(- *)'{-V,--version}'[display version information]'
     '(-f --format -P --portability)-B[same as --format=bsd]'
-    '(-C --no-demangle)--demangle=-[decode symbol names]::style:(auto gnu lucid arm hp edg gnu-v3 java gnat)'
-    "(-C --demangle)--no-demangle[don't decode symbol names]"
     '(-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 --numeric-sort -r -P --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}'[do not sort symbols]'
     '(-P --portability -B -f --format)'{-P,--portability}'[same as --format=posix]'
-    '(-r --reverse-sort -p --no-sort --size-sort -v)'{-r,--reverse-sort}'[reverse sort order]'
+    '(-r --reverse-sort -p --no-sort)'{-r,--reverse-sort}'[reverse sort order]'
     '(-u --undefined-only --defined-only)'{-u,--undefined-only}'[display only undefined symbols]'
     '(-a --debug-syms)'{-a,--debug-syms}'[display debugger-only symbols]'
     '(-S --print-size)'{-S,--print-size}'[print size of defined symbols]'
     '(-s --print-armap)'{-s,--print-armap}'[include index for symbols from archive members]'
-    '(-p --no-sort -n --numeric-sort -r -v)--size-sort[sort symbols by size]'
   )
   case $variant in
     elftoolchain|binutils)
       args+=(
 	'(-l --line-numbers)'{-l,--line-numbers}'[display source file and line numbers from debug information]'
+	"(-C --demangle)--no-demangle[don't decode symbol names]"
+	'(-p --no-sort -n -v --numeric-sort)--size-sort[sort symbols by size]'
+	'(-n --numeric-sort -p --no-sort --size-sort)-v[sort symbols numerically by address]'
+	'(- *)-h[display help information]'
       )
     ;|
     elftoolchain)
-      args=( ${args:#*--(portability|extern-only)\[*}
-        '(- *)-h[display help information]'
-	'(-t -x)-o[print values in octal]'
-	'(-t -o)-x[print values in hexadecimal]'
-	'(--size-sort)-v[sort output by value]'
+      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)'
+	'-o[with -P, same as -t o; otherwise same as -A]'
+	'(-t --radix)-x[print values in hexadecimal]'
       )
     ;;
     elfutils)
       args+=(
         '--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)'
+	'(- *)--usage[give a short usage message]'
+	'(- *)-\\?[display help information]'
       )
     ;;
     binutils)
+      compset -P '@' && files='*:options file:_files'
       args+=(
 	'(-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)'
 	'--plugin[load specified plugin]:plugin'
 	'--special-syms[include special symbols in the output]'
 	'--synthetic[display synthetic symbols as well]'
@@ -63,22 +70,65 @@ if _pick_variant -r variant binutils=GNU elftoolchain=elftoolchain elfutils=elfu
     ;;
   esac
 else
-  # following flags are accurate for Solaris
-  args=( ${args:#(|*\)(\*|))-[o-]*}
-    "-h[don't display column headers]"
-    '-l[distinguish WEAK symbols with * character]'
-    '(-t -x)-o[print values in octal]'
-    '(-v)-n[sort symbols by name]'
-    '(-P)-p[produce parsable output]'
-    '(-p)-P[portable output format]'
-    '(-r)-R[print archive name, object file and symbol name]'
-    '-r[prepend name of input file to each symbol name]'
-    '-s[print section name instead of index]'
-    '-u[print undefined symbols only]'
-    '(-n)-v[sort external symbols by value]'
-    '-V[display version of the nm command]'
-    '(-o -t)-x[print values in hexadecimal]'
-  )
+  case $OSTYPE in
+    (darwin*|openbsd*)
+      args=(
+	'(-A -o)'{-A,-o}'[prepend file name to each output line]'
+	'(-g)-a[display all symbols including those for debuggers]'
+	'(-a)-g[display only global symbols]'
+	'(-U)-u[display only undefined symbols]'
+	'(-p)-n[sort numerically rather than alphabetically]'
+	"(-n -r)-p[don't sort; display in symbol-table order]"
+	'(-p)-r[sort in reverse order]'
+	'(-j)-P[print information in a portable format]'
+	'(-j)-t[specify radix for numeric values (used with -P)]:radix:((d\:decimal o\:octal x\:hexadecimal))'
+      );|
+    (darwin*)
+      args+=(
+	"(-u)-U[don't display undefined symbols]"
+	'-f[display symbol table of dynamic library flat]'
+	'(-P -t -m)-j[just display symbol names (no value or type)]'
+	'-l[display .section_start if no symbol is in the section (used with -s)]'
+	'(-j)-m[use verbose format for Mach-O symbols]'
+	'-s[list only symbols in the specified section]:segment name: :section name: '
+	"-x[display symbol table entry's fields in hexadecimal]"
+	'*-arch[select architecture from universal file]:architecture:(all i386 x86_64)'
+      );;
+    (openbsd*)
+      args+=(
+	'-C[decode low-level symbol names]'
+	'-D[display dynamic symbol table instead of normal symbol table]'
+	'-e[output extended information]'
+	'-s[show archive index]'
+	'-w[warn about non-object archive members]'
+      );;
+    (solaris*)
+      args=( ${args:#(|*\)(\*|))-[o-]*}
+	"-h[don't display column headers]"
+	'-l[distinguish WEAK symbols with * character]'
+	'(-t -x)-o[print values in octal]'
+	'(-v)-n[sort symbols by name]'
+	'(-P)-p[produce parsable output]'
+	'(-p)-P[portable output format]'
+	'(-r)-R[print archive name, object file and symbol name]'
+	'-r[prepend name of input file to each symbol name]'
+	'-s[print section name instead of index]'
+	'-u[print undefined symbols only]'
+	'(-n)-v[sort external symbols by value]'
+	'-V[display version of the nm command]'
+	'(-o -t)-x[print values in hexadecimal]'
+      );;
+    (*)
+      # minimal POSIX
+      args=(
+	'-A[print name of input file on each line]'
+	'(-u)-g[display only global symbols]'
+	'-P[print information in a portable format]'
+	'-t[specify radix for numeric values]:radix:((d\:decimal o\:octal x\:hexadecimal))'
+	'(-g)-u[display only undefined symbols]'
+	'-v[sort symbols by value instead of by name]'
+      );;
+  esac
 fi
 
-_arguments -s "$args[@]" $files
+_arguments -s -S : "$args[@]" $files



^ permalink raw reply	[relevance 12%]

* Re: Surprising behaviour with numeric glob sort
  @ 2017-06-05 11:54  3%               ` Stephane Chazelas
  2017-06-05 19:15  3%                 ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2017-06-05 11:54 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2017-06-04 15:01:35 -0700, Bart Schaefer:
> On Jun 4,  6:31pm, Stephane Chazelas wrote:
> }
> } "Slow" (though probably quite negligible compared to strcoll()
> } which already does things like in addition to a lot more hard
> } wark) but working.
> 
> According to one strcoll man page I have, the right thing to do is
> convert all the strings with strxfrm and then strcmp those.
> 
> It provides no advice on how to order the original array to match the
> sorted result of the xfrm'd array (the transform is not reversible),
> nor how to determine how much space to allocate for each transform.
> 
> Zsh has the additional complication of needing to deal with strings
> having embedded '\0' bytes, which neither strcoll nor strxfrm is able
> to deal with.  I'm not 100% confident that zsh's current algorithm
> deals correct with this either.

>From what I can see (by using ltrace -e strcoll), zsh removes
the NUL bytes before calling strcoll, so $'\0\0x' sorts the same
as $'\0x' or 'x'.

That's as if $'\0' had IGNORE for all weights in the collation
order which I suppose is as valid as any. Per POSIX, such input
would not be text, so "sorting" them may not be very meaningful.
Same for strings that contain byte sequences that don't form
valid characters where there's no saying what strcoll() may do
with them.

Having NUL sort before any other character would be preferable
in the C locale that sorts by code point though (like to sort
UTF-16 text based on codepoint).

> A possible approach would be to pre-allocate a hash table and fill
> it on the fly with keys the original strings and values the strxfrm
> results.  An additional strxfrm could be called on the trailing bits
> after any embedded nul.  Then sort the original array by comparing
> the values in the hash.  Doesn't solve the question of how much space
> to reserve, but it would allow the current algorithm for picking out
> numeric substrings to be used.

You mean a Schwartzian transform
(https://en.wikipedia.org/wiki/Schwartzian_transform) that sorts
on (here using $'\0zsh\0-1.2\0x' as an example):

{
  original <= $'\0zsh\0-1.2\0x'
  parts <= [{string: $'\0' . strxfrm("zsh") . $'\0' . strxfrm("-")},
            {num: 1},
	    {string: strxfrm(".")},
	    {num: 2},
	    {string: $'\0' . strxfrm("x")}]
}, ...

With a comparison function that does memcmp() on the "string"
parts and a number comparison on the "num" parts?

Yes, that sounds like a good idea that trades memory for
efficiency (by doing the strxfrm() hard work up front and only
once), but if we're going to transform upfront anyway, the
memory is traded off already.

Or same using zero-padding

{
  original <= $'\0zsh\0-1.2\0x'
  transformed <= $'\0' . strxfrm("zsh") . $'\0' . strxfrm("-") .
                 "001" .  strxfrm(".") . "002" . $'\0' . strxfrm("x")}]
}, ...

(and using memcmp() in the comparison function)

With same benefits (a-1 a+2 a-3 sorted in that order where "-"
and "+" are ignored in the first pass like without
numericglobsort) and same drawback (need to find out the right
padding width).

> For parameter array sorting we could extend the (m) flag to indicate
> that this transformation is required [it already means to count byte
> widths for (l), (r), etc.] so as to avoid the overhead when it is not
> needed.  For globbing, we'd have to rely on something else such as
> whether MULTIBYTE is set.

Note that for globbing, the "numeric" sort applies after the
"o+myfunc" or "oe:...:" transformation, so the strings to sort
on may still contain all sorts of things like NUL bytes and byte
sequences that don't form valid characters even if they were not
in the file names in the first place.

Like in a

by_content() REPLY=$mapfile[$REPLY]
echo *(no+by_content)

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: Surprising behaviour with numeric glob sort
  2017-06-05 11:54  3%               ` Stephane Chazelas
@ 2017-06-05 19:15  3%                 ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2017-06-05 19:15 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

2017-06-05 12:54:39 +0100, Stephane Chazelas:
[...]
> Having NUL sort before any other character would be preferable
> in the C locale that sorts by code point though (like to sort
> UTF-16 text based on codepoint).
[...]

Well, only for UTF-16BE. Given that UTF-16 is mostly used only
on Microsoft and as little endian, that would rarely be useful.

Still, it would be more consistent to have 0 < 1 < ... < 255
and would make sure the order is deterministic which is generally
expected of the C locale. It should be only a matter of calling
memcmp() when we detect the locale (LC_COLLATE) to be C or
POSIX.

GNU sort seems to be treating the NUL byte as the character that
sorts first and seems to be doing it using several calls to
strcoll() in non-C locales:

$ printf '%b\n' 'X\0\0A\0B' 'X\0\0A\0\0C' | ltrace -e strcoll sort
sort->strcoll("X", "X")        = 0
sort->strcoll("", "")          = 0
sort->strcoll("A", "A")        = 0
sort->strcoll("B", "")         = 1
XAC
XAB

(I'd say there's scope for optimisation there).

In the C locale, it just calls memcmp().

Cheers,
Stephane


^ permalink raw reply	[relevance 3%]

* Re: =~ doesn't work with NUL characters
  @ 2017-06-14 20:49  3% ` Phil Pennock
  2017-06-15  9:50  3%   ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Phil Pennock @ 2017-06-14 20:49 UTC (permalink / raw)
  To: Zsh hackers list

On 2017-06-13 at 11:02 +0100, Stephane Chazelas wrote:
> [[ $'a\0b' =~ 'a$' ]]
> 
> returns true both with and without rematchpcre

Let's break this down, non-PCRE and PCRE, and consider appropriate
behaviour for each separately.

Without rematchpcre, this is ERE per POSIX APIs, which don't portably
support size-supplied strings, relying instead upon C-string
null-termination.

Current macOS has regnexec() but this is not in the system regexp
library I see on Ubuntu Trusty or FreeBSD 10.3.  It appears to be an
extension from when they switched to the TRE implementation in macOS
10.8.  <https://laurikari.net/tre/>

Trying to support this would result in variations in behaviour across
systems in a way which I think might be undesirable.  The whole point of
adding the non-PCRE implementation was to match Bash behaviour by
default, and Bash does the same thing.

So for non-PCRE, I think this current behaviour is the only sane choice.

For PCRE, I'm inclined to agree that we should be able to portably
supply the length and there would not be any cross-platform behavioural
variances.  I think it's also reasonable that PCRE matching could
diverge from ERE matching even more.  Others might disagree?

We've "always" used strlen here; the most recent change was to handle
meta/unmeta (by me), but the strlen usage has been present since the
pcre module was introduced in commit bff61cf9e1 in 2001.

Thus: do we want to change behaviour, after 16 years, to allow embedded
NUL for the PCRE case, being different from the ERE case?

There's enough room for disagreement here that I'm not rushing to write
a patch, but instead deferring to those with commit-bit.  My personal
inclination is to handle NULL in the PCRE case.  It should just be a
case of passing an int* instead of NULL as the second parameter to
unmetafy().

-Phil


^ permalink raw reply	[relevance 3%]

* Re: =~ doesn't work with NUL characters
  2017-06-14 20:49  3% ` Phil Pennock
@ 2017-06-15  9:50  3%   ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2017-06-15  9:50 UTC (permalink / raw)
  To: Phil Pennock; +Cc: Zsh hackers list

2017-06-14 16:49:38 -0400, Phil Pennock:
[...]
> Without rematchpcre, this is ERE per POSIX APIs, which don't portably
> support size-supplied strings, relying instead upon C-string
> null-termination.
> 
> Current macOS has regnexec() but this is not in the system regexp
> library I see on Ubuntu Trusty or FreeBSD 10.3.  It appears to be an
> extension from when they switched to the TRE implementation in macOS
> 10.8.  <https://laurikari.net/tre/>
> 
> Trying to support this would result in variations in behaviour across
> systems in a way which I think might be undesirable.  The whole point of
> adding the non-PCRE implementation was to match Bash behaviour by
> default, and Bash does the same thing.
[...]

A dirty trick in UTF-8 locales (the norm these days) may be to
encode NUL as U+7FFFFF00 (and bytes 0x80 -> 0xff that don't
form part  of valid characters as U_7FFFFF{80..FF}) (in both the
string and regexp).

That wouldn't work with every regexp implementation though as
some would treat those as invalid characters if they go by
the newer definition where valid characters are only
0000->D7FF, E000->10FFFF.

But with those that do, that would also make the behaviour more
consistent in cases like:

[[ $'\x80' = ? ]] vs [[ $'\x80' =~ '^.$' ]]

That wouldn't help in things like [[ x =~ $'[\0-\177]' ]] (which
anyway doesn't make sense in locales other than C/POSIX) though.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] PCRE/NUL: pass NUL in for text, handle NUL out
  @ 2017-06-16  6:41  3% ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2017-06-16  6:41 UTC (permalink / raw)
  To: Phil Pennock; +Cc: zsh-workers

2017-06-15 16:40:50 -0400, Phil Pennock:
> The regexp itself is always NUL-terminated, so detect embedded NULs and
> zwarn on their presence.
[...]

Thanks Phil.

Maybe an improvement could be to replace those NULs with a
litteral \0. Though that would not be valid if the NUL is
preceded by a backslash or within \Q...\E. So it's probably
just as well to use the warning to let the user do the escaping
himself.



Having a way to use \Q...\E reliably would be nice by the way

As in a variant of:

    [[ $x =~ "...\Q$y\E" ]]

That still works if $y contains \E. (I can't think of a
reasonable way though).

bash32+/ksh93 support:

    [[ $x =~ ..."$y"...]]

as in quoting $y prevents interpretation of RE operators in
them. It's quite buggy in ksh93, and in bash, that means the
syntax is limited to POSIX ERE even on systems where EREs have
many extensions like  \<, back-references... (except if you
store the regex in a variable which you then leave unquoted:
ws='\<' we='\>'; [[ $var = $ws"$word"$we ]], not [[ $var =
\<"$word"\> ]]) so I'm not sure we want to go there.

Solution for now in zsh is to escape like:

   [[ $x =~ "\b\Q${word//\\E/\\E\\\\E\\Q}\E" ]]

(possibly still doesn't work in locales that have characters
whose encoding ends in 0x5c bytes (same as \), but nobody should
use those really in this day and age).

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* [BUG] 'exec' runs shell functions and builtins
@ 2017-07-25 21:49  5% ` Martijn Dekker
  2017-07-26  9:23 16%   ` Peter Stephenson
  2017-07-26 17:46  4%   ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2017-07-25 21:49 UTC (permalink / raw)
  To: Zsh hackers list

In zsh, 'exec' looks up shell functions and builtins before external
commands, and if it finds one it appears to do the equivalent of running
the function or builtin followed by 'exit'. This is different from most
other shells and turns out[1] to be a bug in POSIX terms; 'exec' is
supposed to launch a program that overlays the current shell[2],
implying the program launched by 'exec' is always external to the shell.

This means that
    (exec commandname arguments ...)
is a POSIXly correct way of guaranteeing the execution of an external
command without specifying the path (something the "command" command
doesn't do in POSIX mode). This was confirmed the other day by Geoff
Clare and Chet Ramey on austin-group-l. (I seem to recall Bart asked on
this list quite some time ago if POSIX provides for a way to do this.)

This behaviour also appears to be contrary to the documentation in
zshbuiltins(1) ("Replace the current shell with an external command
rather than forking").

Test script:

testFn() {
        exec :
}
if (PATH=/dev/null exec testFn) 2>/dev/null; then
        echo "this shell execs both functions and builtins"
fi

(The only other POSIX-ish shell that zsh has this in common with is
pdksh/mksh. In pdksh this is definitely a bug as this behaviour differs
from ksh88 which pdksh is supposed to be a clone of. The POSIX spec is
also based on ksh88 behaviour.)

Confirmed down to 4.3.17 (I didn't check older versions).

- M.

[1] https://www.mail-archive.com/austin-group-l@opengroup.org/msg01469.html

[2]
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_20_14


^ permalink raw reply	[relevance 5%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-07-25 21:49  5% ` [BUG] 'exec' runs shell functions and builtins Martijn Dekker
@ 2017-07-26  9:23 16%   ` Peter Stephenson
  2017-07-26 17:46  4%   ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2017-07-26  9:23 UTC (permalink / raw)
  To: Zsh hackers list

On Tue, 25 Jul 2017 22:49:33 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> In zsh, 'exec' looks up shell functions and builtins before external
> commands, and if it finds one it appears to do the equivalent of running
> the function or builtin followed by 'exit'. This is different from most
> other shells and turns out[1] to be a bug in POSIX terms; 'exec' is
> supposed to launch a program that overlays the current shell[2],
> implying the program launched by 'exec' is always external to the shell.

Prior art suggests we can get away with adding this behaviour to the
POSIX_BUILTINS option.  (I'd like to hope people don't actually
set the POSIX options separately anyway, but feel free not to tell me.)

pws

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index cc6ae2a..edf43d4 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2140,6 +2140,10 @@ In addition, various error conditions associated with the above builtins
 or tt(exec) cause a non-interactive shell to exit and an interactive
 shell to return to its top-level processing.
 
+Furthermore, functions ahd shell builtins are not executed after
+an tt(exec) prefix; the command to be executed must be an external
+command found in the path.
+
 Furthermore, the tt(getopts) builtin behaves in a POSIX-compatible
 fashion in that the associated variable tt(OPTIND) is not made
 local to functions.
diff --git a/Src/exec.c b/Src/exec.c
index 0a96879..f339dd6 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2778,6 +2778,12 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 		 * Reserved words take precedence over shell functions.
 		 */
 		checked = 1;
+	    } else if (isset(POSIXBUILTINS) && (cflags & BINF_EXEC)) {
+		/*
+		 * POSIX doesn't allow "exec" to operate on builtins
+		 * or shell functions.
+		 */
+		break;
 	    } else {
 		if (!(cflags & (BINF_BUILTIN | BINF_COMMAND)) &&
 		    (hn = shfunctab->getnode(shfunctab, cmdarg))) {
@@ -3123,10 +3129,14 @@ execcmd_exec(Estate state, Execcmd_params eparams,
 	     *   - we have determined there are options which would
 	     *     require us to use the "command" builtin); or
 	     * - we aren't using POSIX and so BINF_COMMAND indicates a zsh
-	     *   precommand modifier is being used in place of the builtin
+	     *   precommand modifier is being used in place of the
+	     *   builtin
+	     * - we are using POSIX and this is an EXEC, so we can't
+	     *   execute a builtin or function.
 	     */
 	    if (errflag || checked || is_builtin ||
-		(unset(POSIXBUILTINS) && (cflags & BINF_COMMAND)))
+		(isset(POSIXBUILTINS) ?
+		 (cflags & BINF_EXEC) : (cflags & BINF_COMMAND)))
 		break;
 
 	    cmdarg = (char *) peekfirst(args);
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index dac9430..f01d835 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -831,6 +831,20 @@
 >val2
 >val2
 
+  print "Contents of file" >cat_arg
+  (
+     cat() { print Function with argument $1 }
+     print Without
+     (exec cat cat_arg; print Not reached)
+     print With
+     (setopt posixbuiltins; exec cat cat_arg; print Not reached)
+  )
+0:POSIX_BUILTINS and exec
+>Without
+>Function with argument cat_arg
+>With
+>Contents of file
+
 # PRINTEXITVALUE only works if shell input is coming from standard input.
 # Goodness only knows why.
   $ZTST_testdir/../Src/zsh -f <<<'


^ permalink raw reply	[relevance 16%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-07-25 21:49  5% ` [BUG] 'exec' runs shell functions and builtins Martijn Dekker
  2017-07-26  9:23 16%   ` Peter Stephenson
@ 2017-07-26 17:46  4%   ` Bart Schaefer
  2017-07-27  9:02  0%     ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2017-07-26 17:46 UTC (permalink / raw)
  To: Martijn Dekker; +Cc: Zsh hackers list

AFAIK zsh has always had this behavior.  It also allows for example
"exec builtin echo" as well as "builtin exec echo" etc.  What would
POSIX say that
    exec command echo foo
should do?  It's relatively easy to stop "exec" from finding functions
and builtin commands, but I think fairly painful to get it to ignore
other "precommand modifier" tokens.  Even after PWS's 41464 the above
example runs /bin/echo whereas I think the POSIX expectation would be
to report "command: command not found".

> This behaviour also appears to be contrary to the documentation in
> zshbuiltins(1) ("Replace the current shell with an external command
> rather than forking").

The documentation under "precommand modifiers" (which is
cross-referenced from zshbuiltins) says:

     The following command together with any arguments is run in place
     of the current process, rather than as a sub-process.  The shell
     does not fork and is replaced.

I think this is a case of the zshbuiltins doc being ancient and
imprecise rather than intentionally indicative of anything, but:


^ permalink raw reply	[relevance 4%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-07-26 17:46  4%   ` Bart Schaefer
@ 2017-07-27  9:02  0%     ` Peter Stephenson
  2017-07-28 17:58  3%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-07-27  9:02 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list

On Wed, 26 Jul 2017 10:46:06 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> AFAIK zsh has always had this behavior.  It also allows for example
> "exec builtin echo" as well as "builtin exec echo" etc.  What would
> POSIX say that
>     exec command echo foo
> should do?  It's relatively easy to stop "exec" from finding functions
> and builtin commands, but I think fairly painful to get it to ignore
> other "precommand modifier" tokens.  Even after PWS's 41464 the above
> example runs /bin/echo whereas I think the POSIX expectation would be
> to report "command: command not found".

This isn't what I get:

% (setopt posixbuiltins; exec command echo foo)
zsh: command not found: command
% cat ~/bin/builtin
#!/bin/sh
echo External command named $0
% (setopt posixbuiltins; exec builtin echo)
External command named /export/home/pws/bin/builtin

There's no further processing of the arguments when we find an exec
with posixbuiltins set, so the above is what I'd expect.

pws

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 99b1dd4..0e8580d 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -679,7 +679,10 @@ See ifzman(the section `Precommand Modifiers' in zmanref(zshmisc))\
 ifnzman(noderef(Precommand Modifiers)).
 
 If the option tt(POSIX_BUILTINS) is set, var(command) is never
-interpreted as a shell builtin command or shell function.
+interpreted as a shell builtin command or shell function.  This
+means further precommand modifiers such as tt(builtin) and
+tt(noglob) are also not interpreted within the shell.  Hence
+var(command) is always found by searching the command path.
 
 cindex(redirection, current shell's I/O)
 If var(command) is omitted but any redirections are specified,


^ permalink raw reply	[relevance 0%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-07-27  9:02  0%     ` Peter Stephenson
@ 2017-07-28 17:58  3%       ` Bart Schaefer
  2017-08-11 15:10  4%         ` Kamil Dudka
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2017-07-28 17:58 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, Jul 27, 2017 at 2:02 AM, Peter Stephenson
<p.stephenson@samsung.com> wrote:
>
> % (setopt posixbuiltins; exec command echo foo)
> zsh: command not found: command

Chet Ramey emailed me:
=====
"However, all of the standard utilities, including the regular built-ins in
the table, but not the special built-ins described in Special Built-In
Utilities, shall be implemented in a manner so that they can be accessed
via the exec family of functions as defined in the System Interfaces volume
of POSIX.1-2008 and can be invoked directly by those standard utilities
that require it (env, find, nice, nohup, time, xargs)."

`command' is explicitly listed in the table in

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag_17_06
=====

So "exec command ..." is actually supposed to work, as is "exec read",
"exec getopts", etc.  Urk.


^ permalink raw reply	[relevance 3%]

* [PATCH] _df: Complete mounted device and mount points.
@ 2017-08-02 15:10  4% Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2017-08-02 15:10 UTC (permalink / raw)
  To: zsh-workers

This splits umount's "udevordir" completion from _mount to a new file,
without changing it.
---
I tested this on linux, but both _df and _umountable have different codepaths
for each of linux / BSD / other, so some testing on those would be appreciated.

Cheers,

Daniel

 Completion/Unix/Command/_df      |  6 +++---
 Completion/Unix/Command/_mount   | 43 +--------------------------------------
 Completion/Unix/Type/_umountable | 44 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 48 insertions(+), 45 deletions(-)
 create mode 100644 Completion/Unix/Type/_umountable

diff --git a/Completion/Unix/Command/_df b/Completion/Unix/Command/_df
index 677b8c727..d20ddea7e 100644
--- a/Completion/Unix/Command/_df
+++ b/Completion/Unix/Command/_df
@@ -16,7 +16,7 @@ if _pick_variant gnu=GNU unix --version; then
     '-v[(ignored)]'
     '(- : *)--help[display help and exit]'
     '(- : *)--version[output version information and exit]'
-    '*:files:_files'
+    '*:files:_umountable'
     - '(format)'
     {-B+,--block-size=}'[specify block size]:size (bytes)'
     '-k[like --block-size=1K]'
@@ -39,7 +39,7 @@ elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then
     '-i[include inode usage statistics (default)]'
     '-l[only display locally-mounted file systems]'
     '-n[use previously obtained statistics]'
-    '*:files:_files'
+    '*:files:_umountable'
   )
   spec='[only display file systems of specified types]:file system type:->fslist'
   case "$OSTYPE" in
@@ -59,7 +59,7 @@ else
     '-k[use 1024-byte blocks]'
     '-P[POSIX compliant output]'
     '-t[include total allocated-space figures in the output]'
-    '*:files:_files'
+    '*:files:_umountable'
   )
 fi
 
diff --git a/Completion/Unix/Command/_mount b/Completion/Unix/Command/_mount
index 9a7041dee..03cc01f8d 100644
--- a/Completion/Unix/Command/_mount
+++ b/Completion/Unix/Command/_mount
@@ -931,48 +931,7 @@ devordir)
   esac
   ;;
 udevordir)
-  local dev_tmp dpath_tmp mp_tmp mline
-
-  case "$OSTYPE" in
-  linux*|irix*)
-    tmp=( "${(@f)$(< /etc/mtab)}" )
-    dev_tmp=( "${(@)${(@)tmp%% *}:#none}" )
-    mp_tmp=( "${(@)${(@)tmp#* }%% *}" )
-    ;;
-  freebsd*|dragonfly*)
-    /sbin/mount | while read mline; do
-      dev_tmp+=( $mline[(w)1] )
-      mp_tmp+=( $mline[(w)3] )
-    done
-  ;;
-  darwin*)
-    tmp=( "${(@f)$(/sbin/mount)}" )
-    dev_tmp=( "${(@)${(@)tmp%% *}:#map}" )
-    mp_tmp=( "${(@)${(@)tmp#* on }%% \(*}" )
-    ;;
-  *)
-    /sbin/mount | while read mline; do
-      mp_tmp+=( $mline[(w)1] )
-      dev_tmp+=( $mline[(w)3] )
-    done
-    ;;
-  esac
-
-  local MATCH MBEGIN MEND
-  # The complicated substitution for mount point names is required because
-  # characters in /etc/mtab that might confuse programs reading the names
-  # are encoded as exactly 3 octal digits, like for example \040 for space.
-  # The cleaner-looking ${(g::)mp_tmp} might consume too many digits.
-  # Both mp_tmp and dev_tmp are derived from /etc/mtab or "mount" output.
-  mp_tmp=("${(@)mp_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}")
-  dev_tmp=("${(@)dev_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}")
-  dpath_tmp=( "${(@M)dev_tmp:#/*}" )
-  dev_tmp=( "${(@)dev_tmp:#/*}" )
-
-  _alternative \
-    'device-labels:device label:compadd -a dev_tmp' \
-    'device-paths: device path:_canonical_paths -A dpath_tmp -N -M "r:|/=* r:|=*" device-paths device\ path' \
-    'directories:mount point:_canonical_paths -A mp_tmp -N -M "r:|/=* r:|=*" directories mount\ point' && ret=0
+  _umountable
   ;;
 labels)
   _wanted labels expl 'disk label' compadd /dev/disk/by-label/*(:t) && ret=0
diff --git a/Completion/Unix/Type/_umountable b/Completion/Unix/Type/_umountable
new file mode 100644
index 000000000..2b2567478
--- /dev/null
+++ b/Completion/Unix/Type/_umountable
@@ -0,0 +1,44 @@
+#autoload
+local tmp
+local dev_tmp dpath_tmp mp_tmp mline
+
+case "$OSTYPE" in
+linux*|irix*)
+  tmp=( "${(@f)$(< /etc/mtab)}" )
+  dev_tmp=( "${(@)${(@)tmp%% *}:#none}" )
+  mp_tmp=( "${(@)${(@)tmp#* }%% *}" )
+  ;;
+freebsd*|dragonfly*)
+  /sbin/mount | while read mline; do
+    dev_tmp+=( $mline[(w)1] )
+    mp_tmp+=( $mline[(w)3] )
+  done
+;;
+darwin*)
+  tmp=( "${(@f)$(/sbin/mount)}" )
+  dev_tmp=( "${(@)${(@)tmp%% *}:#map}" )
+  mp_tmp=( "${(@)${(@)tmp#* on }%% \(*}" )
+  ;;
+*)
+  /sbin/mount | while read mline; do
+    mp_tmp+=( $mline[(w)1] )
+    dev_tmp+=( $mline[(w)3] )
+  done
+  ;;
+esac
+
+local MATCH MBEGIN MEND
+# The complicated substitution for mount point names is required because
+# characters in /etc/mtab that might confuse programs reading the names
+# are encoded as exactly 3 octal digits, like for example \040 for space.
+# The cleaner-looking ${(g::)mp_tmp} might consume too many digits.
+# Both mp_tmp and dev_tmp are derived from /etc/mtab or "mount" output.
+mp_tmp=("${(@)mp_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}")
+dev_tmp=("${(@)dev_tmp//(#m)\\[0-7](#c3)/${(#)$(( 8#${MATCH[2,-1]} ))}}")
+dpath_tmp=( "${(@M)dev_tmp:#/*}" )
+dev_tmp=( "${(@)dev_tmp:#/*}" )
+
+_alternative \
+  'device-labels:device label:compadd -a dev_tmp' \
+  'device-paths: device path:_canonical_paths -A dpath_tmp -N -M "r:|/=* r:|=*" device-paths device\ path' \
+  'directories:mount point:_canonical_paths -A mp_tmp -N -M "r:|/=* r:|=*" directories mount\ point' && ret=0


^ permalink raw reply	[relevance 4%]

* shwordsplit: final non-whitespace IFS character problem
@ 2017-08-04  2:03  4% Martijn Dekker
  2017-08-04 10:56  5% ` Stephane Chazelas
  2017-08-06 18:08  3% ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2017-08-04  2:03 UTC (permalink / raw)
  To: Zsh hackers list

In field/word splitting, a final non-whitespace IFS delimiter character
is counted as an empty field. This is unlike every other current shell
(including current versions of pdksh, i.e. mksh and OpenBSD ksh).

Test script:

setopt shwordsplit
IFS=:
x=a:b:
set -- $x
echo $#

Expected output: 2
Actual output: 3

The POSIX standard appears pretty ambiguous on this:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05

https://osdn.jp/ticket/browse.php?group_id=3863&tid=35283#comment:3863:35283:1435293070
[click on "Show all old Histories" for complete discussion]

However, it turns out that the intention of the standard was clarified
back in 1995 (!) in:
http://www.open-std.org/JTC1/SC22/WG15/docs/rr/9945-2/9945-2-98.html

IOW, the intention of the POSIX standard is for IFS characters to be
field terminators rather than separators (in spite of the S in IFS).

Sorry if the timing of this is awkward (shortly before an upcoming release).

Thanks,

- M.


^ permalink raw reply	[relevance 4%]

* Re: shwordsplit: final non-whitespace IFS character problem
  2017-08-04  2:03  4% shwordsplit: final non-whitespace IFS character problem Martijn Dekker
@ 2017-08-04 10:56  5% ` Stephane Chazelas
  2017-08-04 11:13  3%   ` Peter Stephenson
  2017-08-06 18:08  3% ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Stephane Chazelas @ 2017-08-04 10:56 UTC (permalink / raw)
  To: Martijn Dekker; +Cc: Zsh hackers list

2017-08-04 04:03:19 +0200, Martijn Dekker:
> In field/word splitting, a final non-whitespace IFS delimiter character
> is counted as an empty field. This is unlike every other current shell
> (including current versions of pdksh, i.e. mksh and OpenBSD ksh).
> 
> Test script:
> 
> setopt shwordsplit
> IFS=:
> x=a:b:
> set -- $x
> echo $#
[...]

IIRC, it was discussed before, and the concensus at the time was
that it would be silly as the S in IFS stands for *S*eparator, not
terminator nor delimiter. At the time though, a number of shells
(pdksh and ash based ones) still behaved like zsh and not ksh88
and POSIX was even less clear about it.

Note that, it also affects "read", where "IFS=: read var" on an
output that contains "word:" should (as per POSIX) store "word"
into "var" (while it "should" store "word1:word2:" on a line
with "word1:word2:").

I can't imagine changing the behaviour in the sh/ksh emulations
would be a problem (though I still think it's silly).

Note that with that semantic, you can no longer do things like:

IFS=:
set -o noglob
for dir in $PATH; do
  ...
done

You need to use some kludge like the "which" POSIX script does
on Debian to account for PATHs like "/bin:/usr/bin:".

-- 
Stephane


^ permalink raw reply	[relevance 5%]

* Re: shwordsplit: final non-whitespace IFS character problem
  2017-08-04 10:56  5% ` Stephane Chazelas
@ 2017-08-04 11:13  3%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-08-04 11:13 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 4 Aug 2017 11:56:01 +0100
Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> 2017-08-04 04:03:19 +0200, Martijn Dekker:
> > In field/word splitting, a final non-whitespace IFS delimiter character
> > is counted as an empty field. This is unlike every other current shell
> > (including current versions of pdksh, i.e. mksh and OpenBSD ksh).
> > 
> > Test script:
> > 
> > setopt shwordsplit
> > IFS=:
> > x=a:b:
> > set -- $x
> > echo $#
> [...]
> 
> IIRC, it was discussed before, and the concensus at the time was
> that it would be silly as the S in IFS stands for *S*eparator, not
> terminator nor delimiter.

Clearly it's not a good idea to change this in native mode.

> I can't imagine changing the behaviour in the sh/ksh emulations
> would be a problem (though I still think it's silly).

If everyone else does it, we should follow there.  I guess POSIX_STRINGS
is as sensible an option to use as anything (though previous disclaimers
on partial use of POSIX options apply).

Not sure this is going to get done before the release.

pws


^ permalink raw reply	[relevance 3%]

* PATCH: update to a few more completions
@ 2017-08-04 15:58  6% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2017-08-04 15:58 UTC (permalink / raw)
  To: Zsh workers

This is a further update to completion of options. Updates are up to the
following versions:

  flex - 2.6.4, this was very outdated before
  gstat - FreeBSD 11.1
  sudo - 1.8.20p2
  sqlite - 3.20.0

Not too much has changed in terms of options for FreeBSD 11.1 unless we
want to somehow handle libxo stuff.

Oliver

diff --git a/Completion/BSD/Command/_gstat b/Completion/BSD/Command/_gstat
index 7baaf0d62..c60e54422 100644
--- a/Completion/BSD/Command/_gstat
+++ b/Completion/BSD/Command/_gstat
@@ -2,10 +2,12 @@
 
 _arguments -s : \
   '-a[only display providers that are at least 0.1% busy]' \
-  '-b[batch mode]' \
+  '(-B)-b[batch mode]' \
+  '(-b)-B[endless batch mode]' \
   '-c[enable the display geom(4) consumers]' \
   '-d[enable the display delete operations]' \
   '-f+[filter by regex]:regex' \
   '-o[enable the display for other operations]' \
+  "-s[enable blocks' size statistics]" \
   '-I+[display refresh rate]:interval (ms)' \
   '-p[only display physical providers]'
diff --git a/Completion/Unix/Command/_flex b/Completion/Unix/Command/_flex
index 7ca5b0f83..80b0cd7fc 100644
--- a/Completion/Unix/Command/_flex
+++ b/Completion/Unix/Command/_flex
@@ -1,35 +1,52 @@
-#compdef flex
+#compdef flex flex++
 
 local curcontext="$curcontext" state line ret=1
 typeset -A opt_args
 
-_arguments -C -s \
-  --help --version \
-  '-b[generate backing-up information]' \
-  '-d[make scanner running in debug mode]' \
-  '-f[generate fast scanner (full table)]' \
-  '-h[show help]' \
-  '-i[generate case-insensitive scanner]' \
-  '-l[maximum compatibility with lex]' \
-  '-p[generate performance report]' \
-  '-s[suppress default rule]' \
-  '-t[write scanner to stdout]' \
-  '-v[show summary of statistics about scanner]' \
-  '-w[suppress warnings]' \
-  '-B[generate batch scanner]' \
-  '-F[use fast scanner table representation]' \
-  '-I[generate interactive scanner]' \
-  '-L[don'"'"'t generate #line directives]' \
-  '-T[trace mode]' \
-  '-V[show version]' \
-  '-7[generate 7-bit scanner]' \
-  '-8[generate 8-bit scanner]' \
-  '-\+[generate C++ scanner class]' \
+_arguments -C -s -S \
   '-C-[specify degree of table compression]:table compression:->tabcomp' \
-  '-o-[specify output file]:output file:_files' \
-  '-P-[change yy prefix]:prefix string:' \
-  '-S-[override skeleton file]:skeleton file:_files' \
-  '*:input files:_files -g "*.(#i)(f|)lex(-.)"' && ret=0
+  '--align[trade off larger tables for better memory alignment]' \
+  '--ecs[construct equivalence classes]' \
+  '--meta-ecs[construct meta-equivalence classes]' \
+  '--read[use read() instead of stdio for scanner input]' \
+  '(-f --full)'{-f,--full}'[generate fast scanner (full table)]' \
+  '(-F --fast)'{-F,--fast}'[use fast scanner table representation]' \
+  '(-d --debug)'{-d,--debug}'[enable debug mode in scanner]' \
+  '(-b --backup)'{-b,--backup}'[write backup information to lex.backup]' \
+  '(-p --perf-report)'{-p,--perf-report}'[generate performance report]' \
+  '(-s --nodefault)'{-s,--nodefault}'[suppress default rule to ECHO unmatched text]' \
+  '(-T --trace)'{-T,--trace}'[trace mode]' \
+  '(-w --nowarn)'{-w,--nowarn}'[suppress warnings]' \
+  '(-v --verbose)'{-v,--verbose}'[show summary of statistics about scanner]' \
+  '--hex[use hexadecimal numbers instead of octal in debug outputs]' \
+  '(-o --outfile)'{-o+,--outfile=}'[specify output file]:output file:_files' \
+  '(-S --skel)'{-S+,--skel=}'-[override skeleton file]:skeleton file:_files' \
+  '(-t --stdout)'{-t,--stdout}'[write scanner to stdout]' \
+  '--yyclass=[specify name of C++ class]:class name' \
+  '--header-file=-[create a C header file in addition to the scanner]:file:_files' \
+  '--tables-file=-[write tables to file]::tables file:_files' \
+  '(-7 -8 --7bit --8bit)'{-7,--7bit}'[generate 7-bit scanner]' \
+  '(-7 -8 --7bit --8bit)'{-8,--8bit}'[generate 8-bit scanner]' \
+  '(-B --batch -I --interactive)'{-B,--batch}'[generate batch scanner]' \
+  '(-i --case-insensitive)'{-i,--case-insensitive}'[generate case-insensitive scanner]' \
+  '(-l --lex-compat)'{-l,--lex-compat}'[maximum compatibility with original lex]' \
+  '(-X --posix-compat)'{-l,--posix-compat}'[maximum compatibility with POSIX lex]' \
+  '(-B --batch -I --interactive)'{-I,--interactive}'[generate interactive scanner]' \
+  '--yylineno[track line count in yylineno]' \
+  '-\+[generate C++ scanner class]' \
+  '-D-[define macro]:macro' \
+  '(-L --noline)'{-L,--noline}"[don't generate #line directives]" \
+  '(-P --prefix)'{-P+,--prefix=}'[change yy prefix]:prefix string' \
+  '(-R --reentrant)'{-R,--reentrant}'[generate a reentrant C scanner]' \
+  '--bison-bridge[scanner for bison pure parser]' \
+  '--bison-locations[include yylloc support]' \
+  '--stdinit[initialize yyin/yyout to stdin/stdout]' \
+  "--nounistd[don't include <unistd.h>]" \
+  "--no-[don't generate a particular function]:function" \
+  '(-c -n)'{-c,-n}'[do nothing]' \
+  '(- *)'{-h,--help}'[display help information]' \
+  '( *)'{-V,--version}'[display version information]' \
+  '*:input file:_files -g "*.(#i)(f|)lex(-.)"' && ret=0
 
 if [[ -n "$state" ]]; then
   _values -s '' 'table compression' \
@@ -38,7 +55,7 @@ if [[ -n "$state" ]]; then
     '(m)f[generate full tables]' \
     '(m)F[generate fast tables]' \
     '(f F)m[construct meta-equivalence classes]' \
-    'r[don'"'"'t use stdio library]' && ret=0
+    "r[don't use stdio library]" && ret=0
 fi
 
 return ret
diff --git a/Completion/Unix/Command/_sqlite b/Completion/Unix/Command/_sqlite
index 05027c603..df673894c 100644
--- a/Completion/Unix/Command/_sqlite
+++ b/Completion/Unix/Command/_sqlite
@@ -22,7 +22,7 @@ options+=(
 )
 
 output_modes=( column HTML line list )
-(( $+sqlite3 )) && output_modes+=( csv )
+(( $+sqlite3 )) && output_modes+=( csv quote )
 exclusive=( $^dashes-${^output_modes:l} )
 for display_opt in $output_modes ; do
   # finagle the description to match the way SQLite's -help formats them
@@ -32,8 +32,8 @@ for display_opt in $output_modes ; do
 done
 
 options+=(
-  $^dashes'-separator[set output field separator]:string to separate output fields:'
-  $^dashes'-nullvalue[set null value string]:string for NULL values:'
+  $^dashes'-separator[set output field separator]:output field separator [|]'
+  $^dashes'-nullvalue[set text string for null values]:string'
   '(- :)'$^dashes'-version[show SQLite version]'
   '(- :)'$^dashes'-help[show help]'
   '1:SQLite database file:_files'
@@ -42,9 +42,12 @@ options+=(
 
 (( $+sqlite3 )) && options+=(
   $^dashes'-bail[stop after hitting an error]'
+  $^dashes'-cmd[run specified command before reading stdin]:sqlite meta-command'
   '(-*batch -*interactive)'$^dashes'-batch[force batch I/O]'
   '(-*batch -*interactive)'$^dashes'-interactive[force interactive I/O]'
+  $^dashes'-mmap[set default mmap size]:size'
   $^dashes'-stats[print memory stats before each finalize]'
+  $^dashes'-vfs[use specified default VFS]:vfs:(unix-dotfile unix-excl unix-none unix-namedsem)'
 )
 
 _arguments $options
diff --git a/Completion/Unix/Command/_sudo b/Completion/Unix/Command/_sudo
index aa7a1a498..ec293d469 100644
--- a/Completion/Unix/Command/_sudo
+++ b/Completion/Unix/Command/_sudo
@@ -26,6 +26,7 @@ args=(
   '(-r --role)'{-r+,--role=}'[create SELinux security context with specified role]:role'
   '(-S --stdin)'{-S,--stdin}'[read password from standard input]'
   '(-t --type)'{-t+,--type=}'[create SELinux security context with specified type]:type'
+  '(-T --command-timeout)'{-T+,--command-timeout=}'[terminate command after specified time limit]:timeout'
   '(-U --other-user)'{-U+,--other-user=}'[in list mode, display privileges for user]:user:_users'
   '(-u --user)'{-u+,--user=}'[run command (or edit file) as specified user]:user:_users'
   '(-)'{-V,--version}'[display version information and exit]'


^ permalink raw reply	[relevance 6%]

* Re: shwordsplit: final non-whitespace IFS character problem
  2017-08-04  2:03  4% shwordsplit: final non-whitespace IFS character problem Martijn Dekker
  2017-08-04 10:56  5% ` Stephane Chazelas
@ 2017-08-06 18:08  3% ` Peter Stephenson
  2017-08-06 20:01  3%   ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2017-08-06 18:08 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 4 Aug 2017 04:03:19 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> In field/word splitting, a final non-whitespace IFS delimiter character
> is counted as an empty field.

Hope this is good enough.  I've taken account of the fact that when
splitting "foo:bar::" one empty string is kept as it's not final.

As far as I can see from bash, in the case of white space, terminating
white space is also stripped (all of it, since the main difference here
is it combines to make a single delimiter), but it's quite hard to
generate a case to be sure with other shells making it pretty difficult
to get the effect of splitting without removing empty words.  So now

% foo="one    two   three   "
% print -l "${=foo}"
one
two
three

% (setopt posixstrings; print -l "${=foo}"; )
one
two
three
% 

which seems to agree with the following in bash:

$ var="one   two   three    "
$ fn() { typeset f; for f in "$@"; do echo $f; done; }
$ fn $var
one
two
three
$ 

but it's possible the space is being removed for some completely
different reason.

It would obviously be insane to make this the default behaviour.  I hope
the description of the option is suitably off-putting.

pws

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 70092d6..c0f07d7 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2193,16 +2193,16 @@ cindex(discarding embedded nulls in $'...')
 cindex(embedded nulls, in $'...')
 cindex(nulls, embedded in $'...')
 item(tt(POSIX_STRINGS) <K> <S>)(
-This option affects processing of quoted strings.  Currently it only
-affects the behaviour of null characters, i.e. character 0 in the
-portable character set corresponding to US ASCII.
+This option affects processing of quoted strings, and also
+splitting of strngs.
 
-When this option is not set, null characters embedded within strings
-of the form tt($')var(...)tt(') are treated as ordinary characters. The
-entire string is maintained within the shell and output to files where
-necessary, although owing to restrictions of the library interface
-the string is truncated at the null character in file names, environment
-variables, or in arguments to external programs.
+When this option is not set, null characters (character 0 in the
+portable character set coresponding to US ASCII) that are embedded
+within strings of the form tt($')var(...)tt(') are treated as ordinary
+characters. The entire string is maintained within the shell and output
+to files where necessary, although owing to restrictions of the libplary
+interface the string is truncated at the null character in file name s,
+environment variables, or in arguments to external programs.
 
 When this option is set, the tt($')var(...)tt(') expression is truncated at
 the null character.  Note that remaining parts of the same string
@@ -2211,6 +2211,19 @@ beyond the termination of the quotes are not truncated.
 For example, the command line argument tt(a$'b\0c'd) is treated with
 the option off as the characters tt(a), tt(b), null, tt(c), tt(d),
 and with the option on as the characters tt(a), tt(b), tt(d).
+
+Furthermore, when the option is set, a trailing separator followed by an
+empty strins does not cause extra fields to be output when the string
+is split.  For example,
+
+example(var="foo bar "
+print -l "${=var}")
+
+outputs a blank line at the end if tt(POSIXSTRINGS) is not set, but
+no blank line if the option is set.  Note the quotation marks as
+empty elements would in any case be removed without their presence.
+If the separator is not white space, only the final separator is
+ignored in this fashion.
 )
 pindex(POSIX_TRAPS)
 pindex(NO_POSIX_TRAPS)
diff --git a/Src/utils.c b/Src/utils.c
index 5055d69..5493317 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3500,12 +3500,12 @@ skipwsep(char **s)
 mod_export char **
 spacesplit(char *s, int allownull, int heap, int quote)
 {
-    char *t, **ret, **ptr;
+    char *t, **ret, **ptr, **eptr;
     int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1);
     char *(*dup)(const char *) = (heap ? dupstring : ztrdup);
 
     /* ### TODO: s/calloc/alloc/ */
-    ptr = ret = (char **) (heap ? hcalloc(l) : zshcalloc(l));
+    eptr = ptr = ret = (char **) (heap ? hcalloc(l) : zshcalloc(l));
 
     if (quote) {
 	/*
@@ -3537,6 +3537,7 @@ spacesplit(char *s, int allownull, int heap, int quote)
 	if (s > t || allownull) {
 	    *ptr = (char *) (heap ? zhalloc((s - t) + 1) :
 		                     zalloc((s - t) + 1));
+	    eptr = ptr;
 	    ztrncpy(*ptr++, t, s - t);
 	} else
 	    *ptr++ = dup(nulstring);
@@ -3545,6 +3546,20 @@ spacesplit(char *s, int allownull, int heap, int quote)
     }
     if (!allownull && t != s)
 	*ptr++ = dup("");
+    if (isset(POSIXSTRINGS) && ptr != eptr + 1) {
+	/*
+	 * Trailing separators do not generate extra fields in POSIX.
+	 * Note this is only the final separator --- if the
+	 * immediately preceding field was null it is still counted.
+	 * So just back up one.
+	 */
+	--ptr;
+	if (!heap) {
+	    char **ret2 = realloc(ret, sizeof(*ret) * (ptr+1-ret));
+	    ptr -= ret-ret2;
+	    ret = ret2;
+	}
+    }
     *ptr = NULL;
     return ret;
 }
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index f01d835..b394e7c 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1339,3 +1339,44 @@
 ?(anon):4: `break' active at end of function scope
 ?(anon):4: `break' active at end of function scope
 ?(anon):4: `break' active at end of function scope
+
+  for opt in POSIX_STRINGS NO_POSIX_STRINGS; do
+    var="foo bar "
+    (setopt $opt; print -l X "${=var}" Y)
+    var="foo2::bar2:"
+    (setopt $opt; IFS=:; print -l X "${=var}" Y)
+    var="foo3:bar3::"
+    (setopt $opt; IFS=:; print -l X "${=var}" Y)
+  done
+0:POSIX_STRINGS effect on final delimiters
+>X
+>foo
+>bar
+>Y
+>X
+>foo2
+>
+>bar2
+>Y
+>X
+>foo3
+>bar3
+>
+>Y
+>X
+>foo
+>bar
+>
+>Y
+>X
+>foo2
+>
+>bar2
+>
+>Y
+>X
+>foo3
+>bar3
+>
+>
+>Y


^ permalink raw reply	[relevance 3%]

* Re: shwordsplit: final non-whitespace IFS character problem
  2017-08-06 18:08  3% ` Peter Stephenson
@ 2017-08-06 20:01  3%   ` Peter Stephenson
  2017-08-08 10:56  0%     ` Kamil Dudka
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-08-06 20:01 UTC (permalink / raw)
  To: Zsh hackers list

This uses some rephrasings from Daniel and also fails to leak in the
case of non-heap allocation.

pws

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 70092d6..36bd939 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2193,16 +2193,16 @@ cindex(discarding embedded nulls in $'...')
 cindex(embedded nulls, in $'...')
 cindex(nulls, embedded in $'...')
 item(tt(POSIX_STRINGS) <K> <S>)(
-This option affects processing of quoted strings.  Currently it only
-affects the behaviour of null characters, i.e. character 0 in the
-portable character set corresponding to US ASCII.
+This option affects processing of quoted strings, and also
+splitting of strngs.
 
-When this option is not set, null characters embedded within strings
-of the form tt($')var(...)tt(') are treated as ordinary characters. The
-entire string is maintained within the shell and output to files where
-necessary, although owing to restrictions of the library interface
-the string is truncated at the null character in file names, environment
-variables, or in arguments to external programs.
+When this option is not set, null characters (character 0 in the
+portable character set coresponding to US ASCII) that are embedded
+within strings of the form tt($')var(...)tt(') are treated as ordinary
+characters. The entire string is maintained within the shell and output
+to files where necessary, although owing to restrictions of the library
+interface the string is truncated at the null character in file names,
+environment variables, or in arguments to external programs.
 
 When this option is set, the tt($')var(...)tt(') expression is truncated at
 the null character.  Note that remaining parts of the same string
@@ -2211,6 +2211,18 @@ beyond the termination of the quotes are not truncated.
 For example, the command line argument tt(a$'b\0c'd) is treated with
 the option off as the characters tt(a), tt(b), null, tt(c), tt(d),
 and with the option on as the characters tt(a), tt(b), tt(d).
+
+Furthermore, when the option is set, a trailing separator followed by an
+empty strings does not cause extra fields to be produced when the string
+is split.  For example,
+
+example(var="foo bar "
+print -l "${=var}")
+
+outputs a blank line at the end if tt(POSIXSTRINGS) is not set, but
+no blank line if the option is set.  Note that empty elements would in
+any case be removed if quotation marks were not used.  If the separator
+is not white space, only the final separator is ignored in this fashion.
 )
 pindex(POSIX_TRAPS)
 pindex(NO_POSIX_TRAPS)
diff --git a/Src/utils.c b/Src/utils.c
index 5055d69..7d8e98c 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -3500,12 +3500,12 @@ skipwsep(char **s)
 mod_export char **
 spacesplit(char *s, int allownull, int heap, int quote)
 {
-    char *t, **ret, **ptr;
+    char *t, **ret, **ptr, **eptr;
     int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1);
     char *(*dup)(const char *) = (heap ? dupstring : ztrdup);
 
     /* ### TODO: s/calloc/alloc/ */
-    ptr = ret = (char **) (heap ? hcalloc(l) : zshcalloc(l));
+    eptr = ptr = ret = (char **) (heap ? hcalloc(l) : zshcalloc(l));
 
     if (quote) {
 	/*
@@ -3537,6 +3537,7 @@ spacesplit(char *s, int allownull, int heap, int quote)
 	if (s > t || allownull) {
 	    *ptr = (char *) (heap ? zhalloc((s - t) + 1) :
 		                     zalloc((s - t) + 1));
+	    eptr = ptr;
 	    ztrncpy(*ptr++, t, s - t);
 	} else
 	    *ptr++ = dup(nulstring);
@@ -3545,6 +3546,21 @@ spacesplit(char *s, int allownull, int heap, int quote)
     }
     if (!allownull && t != s)
 	*ptr++ = dup("");
+    if (isset(POSIXSTRINGS) && ptr != eptr + 1) {
+	/*
+	 * Trailing separators do not generate extra fields in POSIX.
+	 * Note this is only the final separator --- if the
+	 * immediately preceding field was null it is still counted.
+	 * So just back up one.
+	 */
+	--ptr;
+	if (!heap) {
+	    char **ret2 = realloc(ret, sizeof(*ret) * (ptr+1-ret));
+	    ptr -= ret-ret2;
+	    free(ret);
+	    ret = ret2;
+	}
+    }
     *ptr = NULL;
     return ret;
 }
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index f01d835..b394e7c 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1339,3 +1339,44 @@
 ?(anon):4: `break' active at end of function scope
 ?(anon):4: `break' active at end of function scope
 ?(anon):4: `break' active at end of function scope
+
+  for opt in POSIX_STRINGS NO_POSIX_STRINGS; do
+    var="foo bar "
+    (setopt $opt; print -l X "${=var}" Y)
+    var="foo2::bar2:"
+    (setopt $opt; IFS=:; print -l X "${=var}" Y)
+    var="foo3:bar3::"
+    (setopt $opt; IFS=:; print -l X "${=var}" Y)
+  done
+0:POSIX_STRINGS effect on final delimiters
+>X
+>foo
+>bar
+>Y
+>X
+>foo2
+>
+>bar2
+>Y
+>X
+>foo3
+>bar3
+>
+>Y
+>X
+>foo
+>bar
+>
+>Y
+>X
+>foo2
+>
+>bar2
+>
+>Y
+>X
+>foo3
+>bar3
+>
+>
+>Y


^ permalink raw reply	[relevance 3%]

* Re: 5.4 almost released
  @ 2017-08-08 11:00  3%                 ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-08-08 11:00 UTC (permalink / raw)
  To: Martijn Dekker, Zsh hackers list

On Tue, 8 Aug 2017 11:26:47 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> The recent POSIX_STRINGS-related change (41499, 2eacbef) introduced at
> least one serious bug. I think you should probably revert that commit
> before the 5.4 release so it can have more testing before 5.4.1 or
> whatever the release after this one is.

I'll probably back it off and make a 5.4.1 this evening as 5.4 is
already tagged.  Any fix will therefore be delayed until at least the
next full release (presumably 5.5).

> $* concatenated, IFS is space:
> 
>         emulate sh
>         set " abc " " def ghi " " jkl "
>         IFS=' '
>         set xx$*yy
> 	echo "$#,$1|$2|$3|$4|$5|$6"
> 
> Actual output: 5,xx|abc|def|ghi|jklyy|
> Expected output: 6,xx|abc|def|ghi|jkl|yy
> 
> The 'yy' is joined to the final 'jkl' instead of becoming a separate
> argument.

In other words, we are splitting on $* because that's the parameter we
are substituting, and performing any further processing on the result of
that, whereas in effect the rules want us to think of xx$1 ... ${N}yy as
arguments to be split (and the yy might itself be a further substitution).

I'm not sure we have a suitable level of expansion at which to fix this
up neatly, and cases like $*$x where $x is empty but we haven't expanded
it yet when we encounter $* are likely to be horrible.  I will therefore
probably leave the fix to someone who has more interest in POSIX tweaks.

pws


^ permalink raw reply	[relevance 3%]

* Re: shwordsplit: final non-whitespace IFS character problem
  2017-08-06 20:01  3%   ` Peter Stephenson
@ 2017-08-08 10:56  0%     ` Kamil Dudka
  0 siblings, 0 replies; 200+ results
From: Kamil Dudka @ 2017-08-08 10:56 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Sunday, August 06, 2017 21:01:10 Peter Stephenson wrote:
> @@ -3545,6 +3546,21 @@ spacesplit(char *s, int allownull, int heap, int quote) }
>      if (!allownull && t != s)
>  	*ptr++ = dup("");
> +    if (isset(POSIXSTRINGS) && ptr != eptr + 1) {
> +	/*
> +	 * Trailing separators do not generate extra fields in POSIX.
> +	 * Note this is only the final separator --- if the
> +	 * immediately preceding field was null it is still counted.
> +	 * So just back up one.
> +	 */
> +	--ptr;
> +	if (!heap) {
> +	    char **ret2 = realloc(ret, sizeof(*ret) * (ptr+1-ret));
> +	    ptr -= ret-ret2;
> +	    free(ret);
> +	    ret = ret2;
> +	}
> +    }
>      *ptr = NULL;
>      return ret;
>  }

Is it correct when you free() the pointer that you previously gave to
realloc()?  Could not it cause a double free()?

Kamil


^ permalink raw reply	[relevance 0%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-07-28 17:58  3%       ` Bart Schaefer
@ 2017-08-11 15:10  4%         ` Kamil Dudka
  2017-08-11 15:25  0%           ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Kamil Dudka @ 2017-08-11 15:10 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

On Friday, July 28, 2017 10:58:59 Bart Schaefer wrote:
> On Thu, Jul 27, 2017 at 2:02 AM, Peter Stephenson
> 
> <p.stephenson@samsung.com> wrote:
> > % (setopt posixbuiltins; exec command echo foo)
> > zsh: command not found: command
> 
> Chet Ramey emailed me:
> =====
> "However, all of the standard utilities, including the regular built-ins in
> the table, but not the special built-ins described in Special Built-In
> Utilities, shall be implemented in a manner so that they can be accessed
> via the exec family of functions as defined in the System Interfaces volume
> of POSIX.1-2008 and can be invoked directly by those standard utilities
> that require it (env, find, nice, nohup, time, xargs)."
> 
> `command' is explicitly listed in the table in
> 
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tag
> _17_06 =====
> 
> So "exec command ..." is actually supposed to work, as is "exec read",
> "exec getopts", etc.  Urk.

Today I discovered that bash in Fedora installs /usr/bin/cd and the like
as external commands to make 'exec' work on those built-ins (primarily
in bash):

https://bugzilla.redhat.com/820192

I am really not happy about this solution because the external commands
only confuse people for no good reason (other than satisfying the POSIX 
requirement).

It is good that zsh does not need this in its native configuration but
how is it supposed to work in the POSIX emulation mode now?

% (exec cd)
% emulate sh
% (exec cd) 
zsh: command not found: cd

If I understand http://www.zsh.org/mla/workers/2017/msg01138.html correctly,
then the above command should work?

Kamil


^ permalink raw reply	[relevance 4%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-08-11 15:10  4%         ` Kamil Dudka
@ 2017-08-11 15:25  0%           ` Peter Stephenson
  2017-08-14  7:19  3%             ` Kamil Dudka
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-08-11 15:25 UTC (permalink / raw)
  To: zsh-workers

On Fri, 11 Aug 2017 17:10:12 +0200
Kamil Dudka <kdudka@redhat.com> wrote:
> It is good that zsh does not need this in its native configuration but
> how is it supposed to work in the POSIX emulation mode now?
> 
> % (exec cd)
> % emulate sh
> % (exec cd) 
> zsh: command not found: cd
> 
> If I understand http://www.zsh.org/mla/workers/2017/msg01138.html correctly,
> then the above command should work?

I can't actually think of a useful application of the above that would
make "work" meaningful.  What's the "exec" supposed to be doing?  Who
would even try to exec a builtin, even if they discover that for some
bizarre reason the standard says you can?  The one possible use of
"exec" in that case might be to ensure you're *not* using a builtin ---
but apparently you are?  What?

pws


^ permalink raw reply	[relevance 0%]

* Re: [BUG] 'exec' runs shell functions and builtins
  2017-08-11 15:25  0%           ` Peter Stephenson
@ 2017-08-14  7:19  3%             ` Kamil Dudka
  0 siblings, 0 replies; 200+ results
From: Kamil Dudka @ 2017-08-14  7:19 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Friday, August 11, 2017 16:25:01 Peter Stephenson wrote:
> On Fri, 11 Aug 2017 17:10:12 +0200
> 
> Kamil Dudka <kdudka@redhat.com> wrote:
> > It is good that zsh does not need this in its native configuration but
> > how is it supposed to work in the POSIX emulation mode now?
> > 
> > % (exec cd)
> > % emulate sh
> > % (exec cd)
> > zsh: command not found: cd
> > 
> > If I understand http://www.zsh.org/mla/workers/2017/msg01138.html
> > correctly, then the above command should work?
> 
> I can't actually think of a useful application of the above that would
> make "work" meaningful.  What's the "exec" supposed to be doing?  Who
> would even try to exec a builtin, even if they discover that for some
> bizarre reason the standard says you can?  The one possible use of
> "exec" in that case might be to ensure you're *not* using a builtin ---
> but apparently you are?  What?
> 
> pws

Thanks for the reply!  It did not make much sense to me either but I am by
no means expert in this area.  In fact I hoped to hear some explanation on 
this list because the topic had been raised here recently.  Given the lack
of information about the reasoning behind the strange POSIX requirement, I 
agree to keep the behavior of zsh as it is now.

Kamil


^ permalink raw reply	[relevance 3%]

* Re: Modify sort ordering for `ls`
  @ 2017-08-18 20:44  3% ` Phil Pennock
  2017-08-18 22:24  0%   ` Daniel Li
  0 siblings, 1 reply; 200+ results
From: Phil Pennock @ 2017-08-18 20:44 UTC (permalink / raw)
  To: Daniel Li; +Cc: zsh-workers

On 2017-08-18 at 13:32 -0700, Daniel Li wrote:
> Whereas on Ubuntu, ls -l gives the reverse:
> 
> -rw-rw-r-- 1 ubuntu ubuntu 0 Aug 18 13:22 VeryLongFileNameHelper.scala
> -rw-rw-r-- 1 ubuntu ubuntu 0 Aug 18 13:22 VeryLongFileName.scala

export LC_COLLATE=POSIX

1. The default sort ordering is driven by locale.
2. Zsh can do things about results of stuff driven by zsh, including
   glob expansion.
3. The above is not using zsh glob expansion.
4. How ls(1) works should be documented in its man-page and other than
   via the environment, Zsh can't do anything here.  There's no
   environment variables _we_ can add to _your_ system ls.

Ultimately, if you can't find a locale collation which works for your
purposes, you can dive deep and write your own collation specification.
If your OS allows use of private locale definitions, then these should
work in _all_ locale-aware applications, not just ls(1).

http://pubs.opengroup.org/onlinepubs/009696699/utilities/localedef.html
http://pubs.opengroup.org/onlinepubs/009696699/basedefs/xbd_chap07.html


^ permalink raw reply	[relevance 3%]

* Re: Modify sort ordering for `ls`
  2017-08-18 20:44  3% ` Phil Pennock
@ 2017-08-18 22:24  0%   ` Daniel Li
  0 siblings, 0 replies; 200+ results
From: Daniel Li @ 2017-08-18 22:24 UTC (permalink / raw)
  To: Phil Pennock; +Cc: zsh-workers

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

That's just what I'm looking for.  Thanks!

Daniel Li


*Daniel Li*
Senior Backend Engineer at Tubi TV

560 Mission St, Suite 1301

San Francisco, CA 94105

On Fri, Aug 18, 2017 at 1:44 PM, Phil Pennock <
zsh-workers+phil.pennock@spodhuis.org> wrote:

> On 2017-08-18 at 13:32 -0700, Daniel Li wrote:
> > Whereas on Ubuntu, ls -l gives the reverse:
> >
> > -rw-rw-r-- 1 ubuntu ubuntu 0 Aug 18 13:22 VeryLongFileNameHelper.scala
> > -rw-rw-r-- 1 ubuntu ubuntu 0 Aug 18 13:22 VeryLongFileName.scala
>
> export LC_COLLATE=POSIX
>
> 1. The default sort ordering is driven by locale.
> 2. Zsh can do things about results of stuff driven by zsh, including
>    glob expansion.
> 3. The above is not using zsh glob expansion.
> 4. How ls(1) works should be documented in its man-page and other than
>    via the environment, Zsh can't do anything here.  There's no
>    environment variables _we_ can add to _your_ system ls.
>
> Ultimately, if you can't find a locale collation which works for your
> purposes, you can dive deep and write your own collation specification.
> If your OS allows use of private locale definitions, then these should
> work in _all_ locale-aware applications, not just ls(1).
>
> http://pubs.opengroup.org/onlinepubs/009696699/utilities/localedef.html
> http://pubs.opengroup.org/onlinepubs/009696699/basedefs/xbd_chap07.html
>

^ permalink raw reply	[relevance 0%]

* "set -e" handling is broken with zsh 5.3.1 and 5.4.1
@ 2017-08-27  0:50  3% Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2017-08-27  0:50 UTC (permalink / raw)
  To: zsh-workers

Consider:

----------------------------------------
#!/usr/bin/env zsh

set -e

f()
{
  [[ -z 1 ]] && false
}

if false; then
  :
else
  f
  echo Fail 1
  echo Fail 2
  f
  echo Fail 3
fi
----------------------------------------

With
  zsh 5.3.1-4+b1 under Debian/stretch
  zsh 5.4.1-1 under Debian/unstable

I get:

% ./cond2-e; echo $?
Fail 1
Fail 2
1

I suppose that cond2-e should die just after f is called, before
outputting anything. At least, the behavior is not consistent.

zsh 5.0.7 was outputting:

Fail 1
Fail 2
Fail 3

but I suppose that this was incorrect (different from what other
shells give on similar POSIX code).

-- 
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%]

* Running "unset path" breaks PATH despite emulation being enabled
@ 2017-09-08  8:29  3% Eric Pruitt
  2017-09-08 11:30  0% ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Eric Pruitt @ 2017-09-08  8:29 UTC (permalink / raw)
  To: zsh-workers

According and <http://www.zsh.org/mla/users/2015/msg00180.html> and the
manual, Z shell should become roughly POSIX compatible when using
"emulate sh". When using emulation, running 'path=""' does not break
PATH command execution, but running 'unset path' still does which seems
like a bug to me:

    $ zsh -c 'emulate -L sh; path=""; ls /dev/null'
    /dev/null
    $ zsh -c 'emulate -L sh; unset path; ls /dev/null'
    zsh:1: command not found: ls

Eric


^ permalink raw reply	[relevance 3%]

* Re: Running "unset path" breaks PATH despite emulation being enabled
  2017-09-08  8:29  3% Running "unset path" breaks PATH despite emulation being enabled Eric Pruitt
@ 2017-09-08 11:30  0% ` Mikael Magnusson
    2017-09-09  4:24  3%   ` Eric Pruitt
  0 siblings, 2 replies; 200+ results
From: Mikael Magnusson @ 2017-09-08 11:30 UTC (permalink / raw)
  To: Eric Pruitt; +Cc: zsh workers

On Fri, Sep 8, 2017 at 10:29 AM, Eric Pruitt <eric.pruitt@gmail.com> wrote:
> According and <http://www.zsh.org/mla/users/2015/msg00180.html> and the
> manual, Z shell should become roughly POSIX compatible when using
> "emulate sh". When using emulation, running 'path=""' does not break
> PATH command execution, but running 'unset path' still does which seems
> like a bug to me:
>
>     $ zsh -c 'emulate -L sh; path=""; ls /dev/null'
>     /dev/null
>     $ zsh -c 'emulate -L sh; unset path; ls /dev/null'
>     zsh:1: command not found: ls

This works fine if you start zsh as sh though, ie either make a
symlink ln -s =zsh sh; ./sh or do ARGV0=sh zsh
It can't really work in the 'emulate sh' case since the parameter
$path is then already created and it would be quite controversial for
emulate to remove parameters from the shell environment.

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* Re: Running "unset path" breaks PATH despite emulation being enabled
  2017-09-08 11:30  0% ` Mikael Magnusson
  @ 2017-09-09  4:24  3%   ` Eric Pruitt
  1 sibling, 0 replies; 200+ results
From: Eric Pruitt @ 2017-09-09  4:24 UTC (permalink / raw)
  To: zsh workers

On Fri, Sep 08, 2017 at 01:30:05PM +0200, Mikael Magnusson wrote:
> This works fine if you start zsh as sh though, ie [...] ARGV0=sh zsh

For the benefit of other people who like myself, don't use actually Z
shell, this is NOT the equivalent of "ARGV0=sh zsh" in many (most?)
other shells, it's describing execve("sh", ["zsh", ...]):

    # For POSIX shells, you can use Z shell itself assuming there's not
    # a standardized built-in way I overlooked:
    $ zsh -c "ARGV0=sh zsh ..."

    # For Bash (and some others):
    $ (exec -a sh zsh ...)

Eric


^ permalink raw reply	[relevance 3%]

* Re: Running "unset path" breaks PATH despite emulation being enabled
  @ 2017-09-11  8:58  2%     ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-09-11  8:58 UTC (permalink / raw)
  To: Zsh Hackers' List

On Fri, 8 Sep 2017 17:17:03 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> All this is entirely correct.  I wonder if it would be helpful for us to
> make it easier to set an emulation at invocation, i.e. "zsh --emulate sh
> ..."?

I've slightly reordered to try to ensure the maximum compatibility with
the previous code, and also added an extra sentence about the usefulness
of --emulate compared with the emulate builtin.  I'll commit this.

pws

diff --git a/Doc/Zsh/invoke.yo b/Doc/Zsh/invoke.yo
index e03c1e2..a184bc8 100644
--- a/Doc/Zsh/invoke.yo
+++ b/Doc/Zsh/invoke.yo
@@ -46,6 +46,20 @@ ifzman(zmanref(zshoptions))\
 ifnzman(noderef(Options))\
 .
 
+The long option `tt(--emulate)' followed (in a separate word) by an
+emulation mode may be passed to the shell.
+The emulation modes are those described for the tt(emulate) builtin,
+see
+ifzman(zmanref(zshbuiltins))\
+ifnzman(noderef(Shell Builtin Commands)).
+The `tt(--emulate)' option must precede any other options (which might
+otherwise be overridden), but following options are honoured, so
+may be used to modify the requested emulation mode.  Note that certain
+extra steps are taken to ensure a smooth emulation when this option
+is used compared with the tt(emulate) command within the shell: for
+example, variables that conflict with POSIX usage such as tt(path) are
+not defined within the shell.
+
 Options may be specified by name using the tt(-o) option.  tt(-o) acts like
 a single-letter option, but takes a following string as the option name.
 For example,
diff --git a/Src/builtin.c b/Src/builtin.c
index 2e72ba2..0c2a62a 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5905,7 +5905,7 @@ bin_emulate(char *nam, char **argv, Options ops, UNUSED(int func))
     savehackchar = keyboardhackchar;
     emulate(shname, opt_R, &new_emulation, new_opts);
     optlist = newlinklist();
-    if (parseopts(nam, &argv, new_opts, &cmd, optlist)) {
+    if (parseopts(nam, &argv, new_opts, &cmd, optlist, 0)) {
 	ret = 1;
 	goto restore;
     }
diff --git a/Src/init.c b/Src/init.c
index 87dd2e2..c537266 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -244,33 +244,24 @@ static int restricted;
 
 /**/
 static void
-parseargs(char **argv, char **runscript, char **cmdptr)
+parseargs(char *zsh_name, char **argv, char **runscript, char **cmdptr)
 {
     char **x;
     LinkList paramlist;
+    int flags = PARSEARGS_TOPLEVEL;
+    if (**argv == '-')
+	flags |= PARSEARGS_LOGIN;
 
     argzero = posixzero = *argv++;
     SHIN = 0;
 
-    /* There's a bit of trickery with opts[INTERACTIVE] here.  It starts *
-     * at a value of 2 (instead of 1) or 0.  If it is explicitly set on  *
-     * the command line, it goes to 1 or 0.  If input is coming from     *
-     * somewhere that normally makes the shell non-interactive, we do    *
-     * "opts[INTERACTIVE] &= 1", so that only a *default* on state will  *
-     * be changed.  At the end of the function, a value of 2 gets        *
-     * changed to 1.                                                     */
-    opts[INTERACTIVE] = isatty(0) ? 2 : 0;
     /*
-     * MONITOR is similar:  we initialise it to 2, and if it's
-     * still 2 at the end, we set it to the value of INTERACTIVE.
+     * parseopts sets up some options after we deal with emulation in
+     * order to be consistent --- the code in parseopts_setemulate() is
+     * matched by code at the end of the present function.
      */
-    opts[MONITOR] = 2;   /* may be unset in init_io() */
-    opts[HASHDIRS] = 2;  /* same relationship to INTERACTIVE */
-    opts[USEZLE] = 1;    /* see below, related to SHINSTDIN */
-    opts[SHINSTDIN] = 0;
-    opts[SINGLECOMMAND] = 0;
 
-    if (parseopts(NULL, &argv, opts, cmdptr, NULL))
+    if (parseopts(zsh_name, &argv, opts, cmdptr, NULL, flags))
 	exit(1);
 
     /*
@@ -334,9 +325,45 @@ parseopts_insert(LinkList optlist, char *base, int optno)
 }
 
 /*
+ * This sets the global emulation plus the options we traditionally
+ * set immediately after that.  This is just for historical consistency
+ * --- I don't think those options actually need to be set here.
+ */
+static void parseopts_setemulate(char *nam, int flags)
+{
+    emulate(nam, 1, &emulation, opts);   /* initialises most options */
+    opts[LOGINSHELL] = ((flags & PARSEARGS_LOGIN) != 0);
+    opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
+
+    /* There's a bit of trickery with opts[INTERACTIVE] here.  It starts *
+     * at a value of 2 (instead of 1) or 0.  If it is explicitly set on  *
+     * the command line, it goes to 1 or 0.  If input is coming from     *
+     * somewhere that normally makes the shell non-interactive, we do    *
+     * "opts[INTERACTIVE] &= 1", so that only a *default* on state will  *
+     * be changed.  At the end of the function, a value of 2 gets        *
+     * changed to 1.                                                     */
+    opts[INTERACTIVE] = isatty(0) ? 2 : 0;
+    /*
+     * MONITOR is similar:  we initialise it to 2, and if it's
+     * still 2 at the end, we set it to the value of INTERACTIVE.
+     */
+    opts[MONITOR] = 2;   /* may be unset in init_io() */
+    opts[HASHDIRS] = 2;  /* same relationship to INTERACTIVE */
+    opts[USEZLE] = 1;    /* see below, related to SHINSTDIN */
+    opts[SHINSTDIN] = 0;
+    opts[SINGLECOMMAND] = 0;
+}
+
+/*
  * Parse shell options.
- * If nam is not NULL, this is called from a command; don't
- * exit on failure.
+ *
+ * If (flags & PARSEARGS_TOPLEVEL):
+ * - we are doing shell initilisation
+ * - nam is the name under which the shell was started
+ * - set up emulation and standard options based on that.
+ * Otherwise:
+ * - nam is a command name
+ * - don't exit on failure.
  *
  * If optlist is not NULL, it used to form a list of pointers
  * into new_opts indicating which options have been changed.
@@ -345,23 +372,26 @@ parseopts_insert(LinkList optlist, char *base, int optno)
 /**/
 mod_export int
 parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
-	  LinkList optlist)
+	  LinkList optlist, int flags)
 {
     int optionbreak = 0;
     int action, optno;
     char **argv = *argvp;
+    int toplevel = ((flags & PARSEARGS_TOPLEVEL) != 0u);
+    int emulate_required = toplevel;
+    char *top_emulation = nam;
 
     *cmdp = 0;
 #define WARN_OPTION(F, S)						\
     do {								\
-	if (nam)							\
+	if (!toplevel)							\
 	    zwarnnam(nam, F, S);					\
 	else								\
 	    zerr(F, S);							\
     } while (0)
 #define LAST_OPTION(N)	       \
     do {		       \
-	if (nam) {	       \
+	if (!toplevel) {       \
 	    if (*argv)	       \
 		argv++;	       \
 	    goto doneargv;     \
@@ -381,7 +411,7 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
 		    argv++;
 		    goto doneoptions;
 		}
-		if (nam || *argv != args+1 || **argv != '-')
+		if (!toplevel || *argv != args+1 || **argv != '-')
 		    goto badoptionstring;
 		/* GNU-style long options */
 		++*argv;
@@ -394,6 +424,19 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
 		    printhelp();
 		    LAST_OPTION(0);
 		}
+		if (!strcmp(*argv, "emulate")) {
+		    ++argv;
+		    if (!*argv) {
+			zerr("--emulate: argument required");
+			exit(1);
+		    }
+		    if (!emulate_required) {
+			zerr("--emulate: must precede other options");
+			exit(1);
+		    }
+		    top_emulation = *argv;
+		    break;
+		}
 		/* `-' characters are allowed in long options */
 		for(args = *argv; *args; args++)
 		    if(*args == '-')
@@ -402,9 +445,17 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
 	    }
 
 	    if (unset(SHOPTIONLETTERS) && **argv == 'b') {
+		if (emulate_required) {
+		    parseopts_setemulate(top_emulation, flags);
+		    emulate_required = 0;
+		}
 		/* -b ends options at the end of this argument */
 		optionbreak = 1;
 	    } else if (**argv == 'c') {
+		if (emulate_required) {
+		    parseopts_setemulate(top_emulation, flags);
+		    emulate_required = 0;
+		}
 		/* -c command */
 		*cmdp = *argv;
 		new_opts[INTERACTIVE] &= 1;
@@ -417,15 +468,20 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
 		    return 1;
 		}
 	    longoptions:
+		if (emulate_required) {
+		    parseopts_setemulate(top_emulation, flags);
+		    emulate_required = 0;
+		}
 		if (!(optno = optlookup(*argv))) {
 		    WARN_OPTION("no such option: %s", *argv);
 		    return 1;
-		} else if (optno == RESTRICTED && !nam) {
+		} else if (optno == RESTRICTED && toplevel) {
 		    restricted = action;
-		} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
+		} else if ((optno == EMACSMODE || optno == VIMODE) && !toplevel) {
 		    WARN_OPTION("can't change option: %s", *argv);
 		} else {
-		    if (dosetopt(optno, action, !nam, new_opts) && nam) {
+		    if (dosetopt(optno, action, toplevel, new_opts) &&
+			!toplevel) {
 			WARN_OPTION("can't change option: %s", *argv);
 		    } else if (optlist) {
 			parseopts_insert(optlist, new_opts, optno);
@@ -442,15 +498,21 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
 		    }
 		break;
 	    } else {
+		if (emulate_required) {
+		    parseopts_setemulate(top_emulation, flags);
+		    emulate_required = 0;
+		}
 	    	if (!(optno = optlookupc(**argv))) {
 		    WARN_OPTION("bad option: -%c", **argv);
 		    return 1;
-		} else if (optno == RESTRICTED && !nam) {
+		} else if (optno == RESTRICTED && toplevel) {
 		    restricted = action;
-		} else if ((optno == EMACSMODE || optno == VIMODE) && nam) {
+		} else if ((optno == EMACSMODE || optno == VIMODE) &&
+			   !toplevel) {
 		    WARN_OPTION("can't change option: %s", *argv);
 		} else {
-		    if (dosetopt(optno, action, !nam, new_opts) && nam) {
+		    if (dosetopt(optno, action, toplevel, new_opts) &&
+			!toplevel) {
 			WARN_OPTION("can't change option: -%c", **argv);
 		    } else if (optlist) {
 			parseopts_insert(optlist, new_opts, optno);
@@ -470,6 +532,10 @@ parseopts(char *nam, char ***argvp, char *new_opts, char **cmdp,
     }
  doneargv:
     *argvp = argv;
+    if (emulate_required) {
+	parseopts_setemulate(top_emulation, flags);
+	emulate_required = 0;
+    }
     return 0;
 }
 
@@ -1660,11 +1726,9 @@ zsh_main(UNUSED(int argc), char **argv)
     fdtable[0] = fdtable[1] = fdtable[2] = FDT_EXTERNAL;
 
     createoptiontable();
-    emulate(zsh_name, 1, &emulation, opts);   /* initialises most options */
-    opts[LOGINSHELL] = (**argv == '-');
-    opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid());
-    /* sets ZLE, INTERACTIVE, SHINSTDIN and SINGLECOMMAND */
-    parseargs(argv, &runscript, &cmd);
+    /* sets emulation, LOGINSHELL, PRIVILEGED, ZLE, INTERACTIVE,
+     * SHINSTDIN and SINGLECOMMAND */ 
+    parseargs(zsh_name, argv, &runscript, &cmd);
 
     SHTTY = -1;
     init_io(cmd);
diff --git a/Src/zsh.h b/Src/zsh.h
index abe9a9c..1e982a6 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1361,6 +1361,14 @@ struct options {
     int argscount, argsalloc;
 };
 
+/* Flags to parseargs() */
+
+enum {
+    PARSEARGS_TOPLEVEL = 0x1,	/* Call to initialise shell */
+    PARSEARGS_LOGIN    = 0x2	/* Shell is login shell */
+};
+
+
 /*
  * Handler arguments are: builtin name, null-terminated argument
  * list excluding command name, option structure, the funcid element from the
diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst
index 2de097e..7b1592f 100644
--- a/Test/B07emulate.ztst
+++ b/Test/B07emulate.ztst
@@ -251,3 +251,28 @@
  emulate sh -c '[[ a == a ]]'
 0:regression test for POSIX_ALIASES reserved words
 F:Some reserved tokens are handled in alias expansion
+
+ for mode in ksh bash zsh; do
+   $ZTST_testdir/../Src/zsh --emulate $mode -f -c 'emulate'
+ done
+0:--emulate option
+>ksh
+>sh
+>zsh
+
+ $ZTST_testdir/../Src/zsh -f --emulate sh
+1:--emulate must be first
+*?*: --emulate: must precede other options
+
+ $ZTST_testdir/../Src/zsh --emulate
+1:--emulate needs an argument
+*?*: --emulate: argument required
+
+ for opt in shwordsplit noshwordsplit; do
+   $ZTST_testdir/../Src/zsh --emulate sh -f -o $opt -c '
+     [[ -o shwordsplit ]] && echo yes || echo no
+   '
+ done
+0:--emulate followed by other options
+>yes
+>no


^ permalink raw reply	[relevance 2%]

* Re: [BUG] exec + builtin and traps
  @ 2017-09-12 11:42  3%         ` Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2017-09-12 11:42 UTC (permalink / raw)
  To: zsh-workers

On 2017-09-12 11:50:06 +0100, Peter Stephenson wrote:
> On Tue, 12 Sep 2017 12:39:19 +0200
> Vincent Lefevre <vincent@vinc17.net> wrote:
> > No, by default (with TRAPS_ASYNC unset), traps are run *after* the
> > child process has exited:
> 
> True, but the *builtin* is an eval list, that only terminates when it
> has executed an arbitrary set of other commands.  The trap is executed
> at the end of this list, before control returns back to eval.  We are
> not exec'ing sleep here, we are exec'ing eval, so there is time after
> the *child* process is executed, as in the TRAPS_ASYNC doc you quote.
> 
> eval, unlike exec, is not an permanent handoff of control to the
> following command.

OK, this was a bit confusing from the description of "eval" by POSIX,
which describes it as a way to construct a command:

  The eval utility shall construct a command by concatenating
  arguments together, separating each with a <space> character.
  The constructed command shall be read and executed by the shell.

BTW, the way zsh handles "eval" is still strange:

----------------------------------------
trap 'echo foo' USR1
( sleep 1; kill -USR1 $$; ) &
eval "wait && echo bar"
echo OK
----------------------------------------

outputs

foo
bar
OK

----------------------------------------
trap 'echo foo' USR1
( sleep 1; kill -USR1 $$; ) &
wait && echo bar
echo OK
----------------------------------------

outputs

foo
OK

All the other shells output

foo
OK

in both 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%]

* Re: Memory leak when working with undefined associative array keys & problems with unset
       [not found]       ` <1505690609.1747008.1109155032.651AC839@webmail.messagingengine.com>
@ 2017-09-18  0:22  3%     ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2017-09-18  0:22 UTC (permalink / raw)
  To: zsh-workers

[Replying to an off-list message w/Daniel's permission]

On Sep 17, 11:23pm, Daniel Shahaf wrote:
} 
} Bart Schaefer wrote on Sun, 17 Sep 2017 16:15 -0700:
} > On Sep 16,  8:57pm, Anssi Palin wrote:
} > } $ key='hello * [ world'
} > } $ typeset -A a=("$key" val)
} > } $ unset "a[$key]"
} > } unset: a[hello * [ world]: invalid parameter name
} > 
} > Hmm, when examining ${a[$key]} we enter parse_subscript() with $key
} > tokenized, but there's no way to get the tokenized string to reach
} > the same point in the unset builtin

Incidentally ksh93 has this same problem, at least as of 2012:

$ echo $KSH_VERSION
Version AJM 93u+ 2012-08-01
$ unset a["$key"]
ksh: unset: a[hello * [ world]: invalid variable name
$ unset "a[$key]"
ksh: unset: a[hello * [ world]: invalid variable name
$ unset "a['$key']"
ksh: unset: a['hello * [ world']: invalid variable name

This is probably why we've ignored this issue, to date.

} Couldn't we just change the interface and keep it a builtin?
} The point being to pass the subscript separately.

I don't know whether e.g. POSIX would squawk about more options to unset.

There's also this, now that we've added the [key]=val syntax:

torch% a=( ['hello * [ world']=(x y z) )
torch% typeset -p a                     
typeset -A a=( ['hello * [ world']='(x y z)' )
torch% a=( ['hello * [ world']=() )     
zsh: parse error near `()'

Since the empty parens there are currently a parse error, we could make
that work the way it does for plain arrays and unset the key.  However,
in ksh note there are no quotes around the parenthesized value (is that
because ksh allows hash elements to be arrays?) and the empty parens
version is permitted:

$ a=(['hello * [ world']=(x y z))
$ typeset -p a
typeset -A a=(['hello * [ world']=(x y z) )
$ a=(['hello * [ world']=() )    
$ typeset -p a
typeset -A a=(['hello * [ world']=())

So we may prefer to go with [increased] ksh compatibility here.


^ permalink raw reply	[relevance 3%]

* POSIX and PROMPT_BANG
@ 2017-09-27 23:56 10% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2017-09-27 23:56 UTC (permalink / raw)
  To: Zsh hackers list

By a coincidence I won't bother to explain, it has just come to my
attention that the POSIX spec says (reprhrased in zsh terminology)
that PS1 shall be interpreted as if PROMPT_BANG is set, which we do
not do by default in sh emulation (but do in ksh emulation).

However, it appears PROMPT_BANG is *not* supposed to apply to PS2 or
PS4 (PS3 is unspecified because "select" is not a POSIX feature).  Zsh
applies it the same to all prompts.

I'm not advocating doing anything about this, merely making note.


^ permalink raw reply	[relevance 10%]

* [bug] sh: tilde expansion after field splitting
@ 2017-10-04 22:20  3% Martijn Dekker
  2017-10-05  5:24  3% ` Bart Schaefer
  2017-10-08  7:53  2% ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2017-10-04 22:20 UTC (permalink / raw)
  To: Zsh hackers list

POSIX says tilde expansion should be done before parameter expansion and
certainly before field spplitting (shwordsplit):
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06

zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
tilde expansion *after* field splitting, and only from the second field on.

Test script:

emulate sh
v='~/one ~/two ~/three'
printf '[%s]\n' $v

Actual output:

[~/one]
[/Users/martijn/two]
[/Users/martijn/three]

Expected output:

[~/one]
[~/two]
[~/three]

Thanks,

- M.


^ permalink raw reply	[relevance 3%]

* Re: [bug] sh: tilde expansion after field splitting
  2017-10-04 22:20  3% [bug] sh: tilde expansion after field splitting Martijn Dekker
@ 2017-10-05  5:24  3% ` Bart Schaefer
  2017-10-08  7:53  2% ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2017-10-05  5:24 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 5, 12:20am, Martijn Dekker wrote:
}
} POSIX says tilde expansion should be done before parameter expansion [...]
} zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
} tilde expansion *after* field splitting, and only from the second field on.

This is a change in the effects of SH_FILE_EXPANSION when an array is
synthesized by word splitting.

Traced this to here:

diff --git a/Src/subst.c b/Src/subst.c
index 81d34d2..021d234 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -3834,8 +3834,14 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
                y = dupstring(nulstring);
            insertlinknode(l, n, (void *) y), incnode(n);
        }
-       if (eval)
-           n = on;
+       /* This used to omit restoring of *str and instead test
+        *   if (eval)
+        *       n = on;
+        * but that causes strange behavior of history modifiers when
+        * applied across all values of an array.  What is magic about
+        * eval here that *str seemed not to need restoring?
+        */
+       *str = getdata(n = on);
     } else {
        /*
         * Scalar value.  Handle last minute transformations

Apparently the answer to the question in that comment has something to
do with shfileexpansion.  Anyone have additional clues?


^ permalink raw reply	[relevance 3%]

* Re: [bug] sh: tilde expansion after field splitting
  2017-10-04 22:20  3% [bug] sh: tilde expansion after field splitting Martijn Dekker
  2017-10-05  5:24  3% ` Bart Schaefer
@ 2017-10-08  7:53  2% ` Bart Schaefer
  2017-10-08 19:20  0%   ` Peter Stephenson
  2017-10-13  9:43  0%   ` Martijn Dekker
  1 sibling, 2 replies; 200+ results
From: Bart Schaefer @ 2017-10-08  7:53 UTC (permalink / raw)
  To: Zsh hackers list

On Oct 5, 12:20am, Martijn Dekker wrote:
} Subject: [bug] sh: tilde expansion after field splitting
}
} POSIX says tilde expansion should be done before parameter expansion [...]
} zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
} tilde expansion *after* field splitting, and only from the second field on.

The patch below fixes this, I believe.  Several comments:

- There either isn't a Test/ for the keyvalpairelement() case in the
  first hunk below, or it isn't rigorous enough, because I initially
  forgot the incnode(node) in that hunk, yet the shell did *not* go
  into an infinite loop during "make check", nor did any test fail.

- The patch covers two bugs for the price of one: unqueue_signals()
  near the end of the first hunk was missed when keyvalpairelement()
  was added (that's the only place at which errflag could become set
  at that point in the loop, and only when keyvalpairelemnt() also
  returns false).  I'm guessing a test for that failure is needed?

- Should we be testing isset(SHFILEEXPANSION) directly here, or ought
  it instead be [for example] passed in the flags?  Is it possible
  that stringsubst() [second hunk] could toggle the setopt so that
  the isset() in the third hunk inverts sense?  Of course if that IS
  possible, then the ultimate effect might be the expected one, and
  this point is moot.

- Grepping Test/* doesn't find anything for SH_FILE_EXPANSION (in
  upper/lower, with/without underscores, etc.).  Did I miss it?
  Does the test for the case in this thread belong in D04parameter
  or E01options?


diff --git a/Src/subst.c b/Src/subst.c
index 2d3eeb2..8c290cc 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -106,15 +106,20 @@ prefork(LinkList list, int flags, int *ret_flags)
 	ret_flags = &ret_flags_local; /* will be discarded */
 
     queue_signals();
-    for (node = firstnode(list); node; incnode(node)) {
+    node = firstnode(list);
+    while (node) {
+	LinkNode nextnode = 0;
 	if ((flags & (PREFORK_SINGLE|PREFORK_ASSIGN)) == PREFORK_ASSIGN &&
 	    (insnode = keyvalpairelement(list, node))) {
 	    node = insnode;
+	    incnode(node);
 	    *ret_flags |= PREFORK_KEY_VALUE;
 	    continue;
 	}
-	if (errflag)
+	if (errflag) {
+	    unqueue_signals();
 	    return;
+	}
 	if (isset(SHFILEEXPANSION)) {
 	    /*
 	     * Here and below we avoid taking the address
@@ -132,6 +137,12 @@ prefork(LinkList list, int flags, int *ret_flags)
 	     * testing if cptr changed...
 	     */
 	    setdata(node, cptr);
+	    /*
+	     * Advance now because we must not expand filenames again
+	     * after string substitution (which may insert new nodes).
+	     */
+	    nextnode = node;
+	    incnode(nextnode);
 	}
 	if (!(node = stringsubst(list, node,
 				 flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
@@ -139,6 +150,10 @@ prefork(LinkList list, int flags, int *ret_flags)
 	    unqueue_signals();
 	    return;
 	}
+	if (isset(SHFILEEXPANSION))
+	    node = nextnode;
+	else
+	    incnode(node);
     }
     for (node = firstnode(list); node; incnode(node)) {
 	if (node == stop)


^ permalink raw reply	[relevance 2%]

* Re: [bug] sh: tilde expansion after field splitting
  2017-10-08  7:53  2% ` Bart Schaefer
@ 2017-10-08 19:20  0%   ` Peter Stephenson
  2017-10-13  9:43  0%   ` Martijn Dekker
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2017-10-08 19:20 UTC (permalink / raw)
  To: Zsh hackers list

On Sun, 8 Oct 2017 00:53:46 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Oct 5, 12:20am, Martijn Dekker wrote:
> } Subject: [bug] sh: tilde expansion after field splitting
> }
> } POSIX says tilde expansion should be done before parameter expansion [...]
> } zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
> } tilde expansion *after* field splitting, and only from the second field on.
> 
> The patch below fixes this, I believe.

Good, it sounds like the effect of the chunk you previous identified as
related was simply moving the linked list node on as a side effect, or
something like that.

> - There either isn't a Test/ for the keyvalpairelement() case in the
>   first hunk below, or it isn't rigorous enough, because I initially
>   forgot the incnode(node) in that hunk, yet the shell did *not* go
>   into an infinite loop during "make check", nor did any test
>   fail

That doesn't make sense.  This is the only place where key / value pairs
are handled and they require some sort of loop increment to work at all.
You're basically claiming they only work by magic.

> - Should we be testing isset(SHFILEEXPANSION) directly here, or ought
>   it instead be [for example] passed in the flags?  Is it possible
>   that stringsubst() [second hunk] could toggle the setopt so that
>   the isset() in the third hunk inverts sense?  Of course if that IS
>   possible, then the ultimate effect might be the expected one, and
>   this point is moot.

I can't believe this is a big deal.

> - Grepping Test/* doesn't find anything for SH_FILE_EXPANSION (in
>   upper/lower, with/without underscores, etc.).  Did I miss it?
>   Does the test for the case in this thread belong in D04parameter
>   or E01options?

Assuming SH_FILE_EXPANSION predates the test suite, I wouldn't be
surprised if it's missing.

pws


^ permalink raw reply	[relevance 0%]

* [PATCH] POSIXBUILTINS: quieten 'unset -f nonexistentfunc'
@ 2017-10-11 18:44  8% Martijn Dekker
  2017-11-02 19:04  0% ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2017-10-11 18:44 UTC (permalink / raw)
  To: Zsh hackers list

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

Doing 'unset -f' on an unset function outputs an error message and
causes an unsuccessful exit status. All other shells quietly ignore it.
POSIX specifies for 'unset' that "Unsetting a variable or function that
was not previously set shall not be considered an error [...]".
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_29_03

If I have figured this out correctly, then the attached patch causes
'unset -f nonexistent_function' to be quiet and return status 0 if
POSIXBUILTINS is active, without changing the behaviour of 'unfunction'
and 'unhash -f'.

- Martijn


[-- Attachment #2: unset-f-quieten.patch --]
[-- Type: text/plain, Size: 1553 bytes --]

diff --git a/Src/builtin.c b/Src/builtin.c
index 84a2bee..0ff9e4f 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -125,7 +125,7 @@ static struct builtin builtins[] =
     BUILTIN("unalias", 0, bin_unhash, 0, -1, BIN_UNALIAS, "ams", NULL),
     BUILTIN("unfunction", 0, bin_unhash, 1, -1, BIN_UNFUNCTION, "m", "f"),
     BUILTIN("unhash", 0, bin_unhash, 1, -1, BIN_UNHASH, "adfms", NULL),
-    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, 0, "fmv", NULL),
+    BUILTIN("unset", BINF_PSPECIAL, bin_unset, 1, -1, BIN_UNSET, "fmv", NULL),
     BUILTIN("unsetopt", 0, bin_setopt, 0, -1, BIN_UNSETOPT, NULL, NULL),
     BUILTIN("wait", 0, bin_fg, 0, -1, BIN_WAIT, NULL, NULL),
     BUILTIN("whence", 0, bin_whence, 0, -1, 0, "acmpvfsSwx:", NULL),
@@ -4158,6 +4158,10 @@ bin_unhash(char *name, char **argv, Options ops, int func)
     for (; *argv; argv++) {
 	if ((hn = ht->removenode(ht, *argv))) {
 	    ht->freenode(hn);
+	} else if (func == BIN_UNSET && isset(POSIXBUILTINS)) {
+	    /* POSIX: unset: "Unsetting a variable or function that was *
+	     * not previously set shall not be considered an error."    */
+	    returnval = 0;
 	} else {
 	    zwarnnam(name, "no such hash table element: %s", *argv);
 	    returnval = 1;
diff --git a/Src/hashtable.h b/Src/hashtable.h
index 3606e97..21398e1 100644
--- a/Src/hashtable.h
+++ b/Src/hashtable.h
@@ -62,6 +62,7 @@
 #define BIN_UNHASH   28
 #define BIN_UNALIAS  29
 #define BIN_UNFUNCTION  30
+#define BIN_UNSET    31
 
 /* These currently depend on being 0 and 1. */
 #define BIN_SETOPT    0

^ permalink raw reply	[relevance 8%]

* Re: [bug] sh: tilde expansion after field splitting
  2017-10-08  7:53  2% ` Bart Schaefer
  2017-10-08 19:20  0%   ` Peter Stephenson
@ 2017-10-13  9:43  0%   ` Martijn Dekker
  2017-10-13 12:55  0%     ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2017-10-13  9:43 UTC (permalink / raw)
  To: Zsh hackers list

Op 08-10-17 om 09:53 schreef Bart Schaefer:
> On Oct 5, 12:20am, Martijn Dekker wrote:
> } Subject: [bug] sh: tilde expansion after field splitting
> }
> } POSIX says tilde expansion should be done before parameter expansion [...]
> } zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
> } tilde expansion *after* field splitting, and only from the second field on.
> 
> The patch below fixes this, I believe.  Several comments:

This introduces a bug with "$@", $@ and $* expansion:

$ Src/zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" "$@$@"'
[a]
[b$@]

$ Src/zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" $@$@'
[a]
[b$@]

$ zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" $*$*'
zsh:1: no matches found: b$*

Expected output for all three:
[a]
[ba]
[b]

Thanks,

- M.


^ permalink raw reply	[relevance 0%]

* Re: [bug] sh: tilde expansion after field splitting
  2017-10-13  9:43  0%   ` Martijn Dekker
@ 2017-10-13 12:55  0%     ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-10-13 12:55 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 13 Oct 2017 11:43:17 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> Op 08-10-17 om 09:53 schreef Bart Schaefer:
> > On Oct 5, 12:20am, Martijn Dekker wrote:
> > } Subject: [bug] sh: tilde expansion after field splitting
> > }
> > } POSIX says tilde expansion should be done before parameter expansion [...]
> > } zsh did this correctly up to version 5.0.8; as of 5.1, it appears to do
> > } tilde expansion *after* field splitting, and only from the second field on.
> > 
> > The patch below fixes this, I believe.  Several comments:
> 
> This introduces a bug with "$@", $@ and $* expansion:
> 
> $ Src/zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" "$@$@"'
> [a]
> [b$@]
> 
> $ Src/zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" $@$@'
> [a]
> [b$@]
> 
> $ zsh -o SHFILEEXPANSION -c 'set "a" "b"; printf "[%s]\n" $*$*'
> zsh:1: no matches found: b$*

Would it be easier to do something like this?  I don't think efficiency
is much of an issue here.

pws

diff --git a/Src/subst.c b/Src/subst.c
index 8c290cc..d027e3d 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -108,7 +108,6 @@ prefork(LinkList list, int flags, int *ret_flags)
     queue_signals();
     node = firstnode(list);
     while (node) {
-	LinkNode nextnode = 0;
 	if ((flags & (PREFORK_SINGLE|PREFORK_ASSIGN)) == PREFORK_ASSIGN &&
 	    (insnode = keyvalpairelement(list, node))) {
 	    node = insnode;
@@ -137,23 +136,31 @@ prefork(LinkList list, int flags, int *ret_flags)
 	     * testing if cptr changed...
 	     */
 	    setdata(node, cptr);
-	    /*
-	     * Advance now because we must not expand filenames again
-	     * after string substitution (which may insert new nodes).
-	     */
-	    nextnode = node;
-	    incnode(nextnode);
-	}
-	if (!(node = stringsubst(list, node,
-				 flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
-				 ret_flags, asssub))) {
-	    unqueue_signals();
-	    return;
 	}
-	if (isset(SHFILEEXPANSION))
-	    node = nextnode;
 	else
-	    incnode(node);
+	{
+	    if (!(node = stringsubst(list, node,
+				     flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
+				     ret_flags, asssub))) {
+		unqueue_signals();
+		return;
+	    }
+	}
+	incnode(node);
+    }
+    if (isset(SHFILEEXPANSION)) {
+	/*
+	 * stringsubst() may insert new nodes, so doesn't work
+	 * well in the same loop as file expansion.
+	 */
+	for (node = firstnode(list); node; incnode(node)) {
+	    if (!(node = stringsubst(list, node,
+				     flags & ~(PREFORK_TYPESET|PREFORK_ASSIGN),
+				     ret_flags, asssub))) {
+		unqueue_signals();
+		return;
+	    }
+	}
     }
     for (node = firstnode(list); node; incnode(node)) {
 	if (node == stop)
diff --git a/Test/E01options.ztst b/Test/E01options.ztst
index 6929f51..0f6bb34 100644
--- a/Test/E01options.ztst
+++ b/Test/E01options.ztst
@@ -1038,6 +1038,16 @@ F:Regression test for workers/41811
 >~/one
 >~/two
 
+  (
+    setopt shfileexpansion
+    set -- also appearing
+    print -l $*$*
+  )
+0:SH_FILE_EXPANSION interaction with inserting nodes from parameters
+>also
+>appearingalso
+>appearing
+
   testpat() {
     if [[ $1 = ${~2} ]]; then print $1 $2 yes; else print $1 $2 no; fi
   }


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] POSIXBUILTINS: quieten 'unset -f nonexistentfunc'
  2017-10-11 18:44  8% [PATCH] POSIXBUILTINS: quieten 'unset -f nonexistentfunc' Martijn Dekker
@ 2017-11-02 19:04  0% ` Martijn Dekker
  2017-11-02 20:04  0%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2017-11-02 19:04 UTC (permalink / raw)
  To: Zsh hackers list

Op 11-10-17 om 19:44 schreef Martijn Dekker:
> Doing 'unset -f' on an unset function outputs an error message and
> causes an unsuccessful exit status. All other shells quietly ignore it.
> POSIX specifies for 'unset' that "Unsetting a variable or function that
> was not previously set shall not be considered an error [...]".
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_29_03
> 
> If I have figured this out correctly, then the attached patch causes
> 'unset -f nonexistent_function' to be quiet and return status 0 if
> POSIXBUILTINS is active, without changing the behaviour of 'unfunction'
> and 'unhash -f'.

Was this overlooked, or rejected?

Thanks,

- M.


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] POSIXBUILTINS: quieten 'unset -f nonexistentfunc'
  2017-11-02 19:04  0% ` Martijn Dekker
@ 2017-11-02 20:04  0%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-11-02 20:04 UTC (permalink / raw)
  To: Martijn Dekker; +Cc: Zsh hackers list

On Thu, 2 Nov 2017 19:04:40 +0000
Martijn Dekker <martijn@inlv.org> wrote:
> Op 11-10-17 om 19:44 schreef Martijn Dekker:
> > Doing 'unset -f' on an unset function outputs an error message and
> > causes an unsuccessful exit status. All other shells quietly ignore it.
> > POSIX specifies for 'unset' that "Unsetting a variable or function that
> > was not previously set shall not be considered an error [...]".
> > http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_29_03
> > 
> > If I have figured this out correctly, then the attached patch causes
> > 'unset -f nonexistent_function' to be quiet and return status 0 if
> > POSIXBUILTINS is active, without changing the behaviour of 'unfunction'
> > and 'unhash -f'.
> 
> Was this overlooked, or rejected?

Just got missed; I've committed it.

pws


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] don't exit shell on [[ -o invalid@option ]]
  @ 2017-11-11 19:01  3%     ` Martijn Dekker
  2017-11-11 23:19  3%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2017-11-11 19:01 UTC (permalink / raw)
  To: zsh-workers

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

Op 11-11-17 om 12:45 schreef Peter Stephenson:
> On Fri, 10 Nov 2017 14:37:17 -0800
> Bart Schaefer <schaefer@brasslantern.com> wrote:
>> We could certainly suppress the error in emulation modes given that's
>> what other shells do.  Further, I'm not strongly invested in the current
>> behavior even for native mode, but we should consider the ramifications.
> 
> It's not clear if it matters in practice rather than theory, no.  The
> test failing is probably usually good enough.
> 
> We could attach it to POSIXBUILTINS as that does control some aspects of
> reutrn / exit behaviour, and [[ ... ]] behaves like a specially parsed
> builtin.

Something like this?

Seems a bit wrong as this is not POSIX at all. Also, POSIXBUILTINS makes
'set -o' exit the shell on an invalid option, which is the opposite
effect. But I can't find a better shell option either.

- M.

[-- Attachment #2: dont-exit-on-testing-invalid-option.patch --]
[-- Type: text/plain, Size: 898 bytes --]

diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo
index e08fc0d..0ea5fc1 100644
--- a/Doc/Zsh/cond.yo
+++ b/Doc/Zsh/cond.yo
@@ -45,6 +45,8 @@ item(tt(-o) var(option))(
 true if option named var(option) is on.  var(option)
 may be a single character, in which case it is a single letter option name.
 (See noderef(Specifying Options).)
+If the var(option) does not exist, the shell exits with an error message,
+unless the shell option tt(POSIX_BUILTINS) is set.
 )
 item(tt(-p) var(file))(
 true if var(file) exists and is a FIFO special file (named pipe).
diff --git a/Src/cond.c b/Src/cond.c
index b9a47ce..814f4b0 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -506,6 +506,8 @@ optison(char *name, char *s)
     else
 	i = optlookup(s);
     if (!i) {
+	if (isset(POSIXBUILTINS))
+	   return 1; /* act like bash and *ksh */
 	zwarnnam(name, "no such option: %s", s);
 	return 2;
     } else if(i < 0)

^ permalink raw reply	[relevance 3%]

* Re: [PATCH] don't exit shell on [[ -o invalid@option ]]
  2017-11-11 19:01  3%     ` Martijn Dekker
@ 2017-11-11 23:19  3%       ` Bart Schaefer
  2017-11-12 19:56  0%         ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2017-11-11 23:19 UTC (permalink / raw)
  To: zsh-workers

On Nov 11,  7:01pm, Martijn Dekker wrote:
}
} Op 11-11-17 om 12:45 schreef Peter Stephenson:
} > On Fri, 10 Nov 2017 14:37:17 -0800
} > Bart Schaefer <schaefer@brasslantern.com> wrote:
} >> We could certainly suppress the error in emulation modes
} > 
} > We could attach it to POSIXBUILTINS as that does control some aspects
} 
} Seems a bit wrong as this is not POSIX at all.

I was thinking more along the lines of tying it to EMULATION(EMULATE_SH)
rather directly to a given option bit.  So you get it if the shell is
started as sh/ksh/etc., but you can't switch it on if started as zsh.


^ permalink raw reply	[relevance 3%]

* Re: [PATCH] don't exit shell on [[ -o invalid@option ]]
  2017-11-11 23:19  3%       ` Bart Schaefer
@ 2017-11-12 19:56  0%         ` Peter Stephenson
    0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-11-12 19:56 UTC (permalink / raw)
  To: zsh-workers

On Sat, 11 Nov 2017 15:19:05 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Nov 11,  7:01pm, Martijn Dekker wrote:
> }
> } Op 11-11-17 om 12:45 schreef Peter Stephenson:
> } > On Fri, 10 Nov 2017 14:37:17 -0800
> } > Bart Schaefer <schaefer@brasslantern.com> wrote:
> } >> We could certainly suppress the error in emulation modes
> } > 
> } > We could attach it to POSIXBUILTINS as that does control some aspects
> } 
> } Seems a bit wrong as this is not POSIX at all.
> 
> I was thinking more along the lines of tying it to EMULATION(EMULATE_SH)
> rather directly to a given option bit.  So you get it if the shell is
> started as sh/ksh/etc., but you can't switch it on if started as zsh.

This is tending to hide the knob under the sticky out bit at the top where
the logo is attached (as it were).

Maybe we should just accept the original patch and note the
incimpatibility.  It's a non-issue for properly written shell code
anyway.

pws


^ permalink raw reply	[relevance 0%]

* Re: [PATCH] don't exit shell on [[ -o invalid@option ]]
  @ 2017-11-18 18:22  4%                   ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2017-11-18 18:22 UTC (permalink / raw)
  To: zsh-workers

Martijn Dekker wrote on Thu, 16 Nov 2017 02:52 +0200:
> Op 15-11-17 om 01:52 schreef Daniel Shahaf:
> > Okay, so how about if we demoted the fatal error to a warning?  Like
> > this:
> > 
> >     % [[ -o not_an_option ]] || echo This gets run
> >     zsh: [[: no such option: not_an_option
> >     This gets run
> >     % 
> 
> I think that would be fine, as well as returning status 2 along with it.
> 
> I do think the warning (and the status 2) should be suppressed if
> POSIX_IDENTIFIERS or some other emulation-relevant shell option is
> active, so that 'emulate ksh' and 'emulate sh' reproduce ksh behaviour.

How about the following.

It uses status 3 because status 2 currently means "syntax error in [["
and I didn't want to overload that; and it uses POSIX_BUILTINS because
that seemed more closely related than POSIX_IDENTIFIERS.

Consider it a work in progress, i.e., particulars are still malleable.
There are good arguments in favour of all sides here… (incumbent
behaviour, Martijn's patch, this patch)

Cheers,

Daniel

diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo
index e08fc0d36..4ca132a26 100644
--- a/Doc/Zsh/cond.yo
+++ b/Doc/Zsh/cond.yo
@@ -45,6 +45,10 @@ item(tt(-o) var(option))(
 true if option named var(option) is on.  var(option)
 may be a single character, in which case it is a single letter option name.
 (See noderef(Specifying Options).)
+
+When no option named var(option) exists, and the tt(POSIX_BUILTINS) option
+hasn't been set, return 3 with a warning.  If that option is set, return 1
+with no warning.
 )
 item(tt(-p) var(file))(
 true if var(file) exists and is a FIFO special file (named pipe).
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 28155d796..d043cf398 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2169,6 +2169,9 @@ command found in the path.
 Furthermore, the tt(getopts) builtin behaves in a POSIX-compatible
 fashion in that the associated variable tt(OPTIND) is not made
 local to functions.
+
+Moreover, the warning and special exit code from
+tt([[ -o )var(non_existent_option)tt( ]]) are suppressed.
 )
 pindex(POSIX_IDENTIFIERS)
 pindex(NO_POSIX_IDENTIFIERS)
diff --git a/Src/cond.c b/Src/cond.c
index b9a47cea5..9f13e07d7 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -61,7 +61,8 @@ static void cond_subst(char **strp, int glob_ok)
  * of functionality.
  *
  * Return status is the final shell status, i.e. 0 for true,
- * 1 for false and 2 for error.
+ * 1 for false, 2 for syntax error, 3 for "option in tested in
+ * -o does not exist".
  */
 
 /**/
@@ -86,10 +87,10 @@ case COND_NOT:
 	if (tracingcond)
 	    fprintf(xtrerr, " %s", condstr[ctype]);
 	ret = evalcond(state, fromtest);
-	if (ret == 2)
-	    return ret;
-	else
+	if (ret == 0 || ret == 1)
 	    return !ret;
+	else
+	    return ret;
     case COND_AND:
 	if (!(ret = evalcond(state, fromtest))) {
 	    if (tracingcond)
@@ -100,7 +101,8 @@ case COND_AND:
 	    return ret;
 	}
     case COND_OR:
-	if ((ret = evalcond(state, fromtest)) == 1) {
+	ret = evalcond(state, fromtest);
+	if (ret == 1 || ret == 3) {
 	    if (tracingcond)
 		fprintf(xtrerr, " %s", condstr[ctype]);
 	    goto rec;
@@ -506,8 +508,12 @@ optison(char *name, char *s)
     else
 	i = optlookup(s);
     if (!i) {
-	zwarnnam(name, "no such option: %s", s);
-	return 2;
+	if (isset(POSIXBUILTINS))
+	    return 1;
+	else {
+	    zwarnnam(name, "no such option: %s", s);
+	    return 3;
+	}
     } else if(i < 0)
 	return !unset(-i);
     else
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 38525016c..04e1ca8f2 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -440,6 +440,23 @@ F:Failures in these cases do not indicate a problem in the shell.
 >  [[ 'a' == 'b' || 'b' = 'c' || 'c' != 'd' ]]
 >}
 
+  (setopt posixbuiltins; eval '[[ -o invalidoption ]]; echo set: $?'; echo "no warning" >&2)
+  (unsetopt posixbuiltins; [[ -o invalidoption ]]; echo unset: $?)
+  [[ -o invalidoption || -n nonempty ]]; echo "in disjunction, true: $?"
+  [[ -o invalidoption || -z nonempty ]]; echo "in disjunction, false: $?"
+  [[ ! -o invalidoption ]]; echo "negated: $?"
+0:-o invalidoption
+>set: 1
+?no warning
+>unset: 3
+?(eval):2: no such option: invalidoption
+>in disjunction, true: 0
+?(eval):3: no such option: invalidoption
+>in disjunction, false: 1
+?(eval):4: no such option: invalidoption
+>negated: 3
+?(eval):5: no such option: invalidoption
+
 %clean
   # This works around a bug in rm -f in some versions of Cygwin
   chmod 644 unmodish


^ permalink raw reply	[relevance 4%]

* Re: $userdirs empty in non-interactive shells
  @ 2017-12-08 12:23  3% ` Stephane Chazelas
  2017-12-08 12:31  3%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2017-12-08 12:23 UTC (permalink / raw)
  To: Zsh hackers list

2017-12-07 11:29:50 +0000, Stephane Chazelas:
[...]
> >     /* We don't maintain a hash table in non-interactive shells. */
> >     if (!interact)
> >         return;
[...]

If I remove that code, that breaks one of the tests:

> --- /tmp/zsh.ztst.2996/ztst.out 2017-12-07 21:31:18.051388484 +0000
> +++ /tmp/zsh.ztst.2996/ztst.tout        2017-12-07 21:31:18.047388673 +0000
> @@ -1,4 +1,4 @@
>  ~/install/cvs/zsh/Test/options.tmp
> -~/install/cvs/zsh/Test/options.tmp/tmpcd ~/install/cvs/zsh/Test/options.tmp
> -~/install/cvs/zsh/Test/options.tmp/tmpcd ~/install/cvs/zsh/Test/options.tmp/tmpcd ~/install/cvs/zsh/Test/options.tmp
> -~/install/cvs/zsh/Test/options.tmp/tmpcd ~/install/cvs/zsh/Test/options.tmp/tmpcd ~/install/cvs/zsh/Test/options.tmp
> +~cdablevar2 ~/install/cvs/zsh/Test/options.tmp
> +~cdablevar2 ~cdablevar2 ~/install/cvs/zsh/Test/options.tmp
> +~cdablevar2 ~cdablevar2 ~/install/cvs/zsh/Test/options.tmp
> Test ./E01options.ztst failed: output differs from expected as shown above for:
>   dirs
>   pushd $mydir/tmpcd
>   dirs
>   pushd $mydir/tmpcd
>   dirs
>   setopt pushdignoredups
>   pushd $mydir/tmpcd
>   dirs
>   unsetopt pushdignoredups
>   popd >/dev/null
>   popd >/dev/null
> Was testing: PUSHD_IGNOREDUPS option
> ./E01options.ztst: test failed.

That's because an earlier test does a cd a:

cd cdablevar2

under setopt cdablevars with cdablevar2 containing that same
tmpcd directory, and so an entry is added in that hash.

That's one case where an earlier test has side effects on later
tests.

While the documentation doesn't mentions that that "hashing" only
happens in interactve shells, the test code acknowleges it to
some extent:

># Test various shell options.
># Interactive options not tested here:
[...]
>#    AUTO_NAME_DIRS  (named directory table not maintained)

That also means:

$ zsh -fc 'cd ~bin; dirs'
/bin
$ zsh -fic 'cd ~bin; dirs'
~bin

BTW, I just realised that named dirs in variables took precedence
over user home dirs:

$ zsh -fc 'cd -P -- ~bin && pwd'
/bin
$ bin=/tmp zsh -fc 'cd -P -- ~bin && pwd'
/tmp

Is that intentional? I can't say I like the  idea. It would need
to be disabled in "sh" emulation if we wanted to be POSIX
compliant in that regard (but then there are a few other
namespace clashes that would need to be addressed like for
keywords, special variables if we wanted to go all the way
there).

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: $userdirs empty in non-interactive shells
  2017-12-08 12:23  3% ` Stephane Chazelas
@ 2017-12-08 12:31  3%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-12-08 12:31 UTC (permalink / raw)
  To: Zsh hackers list

On Fri, 8 Dec 2017 12:23:46 +0000
Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> BTW, I just realised that named dirs in variables took precedence
> over user home dirs:
> 
> $ zsh -fc 'cd -P -- ~bin && pwd'
> /bin
> $ bin=/tmp zsh -fc 'cd -P -- ~bin && pwd'
> /tmp
> 
> Is that intentional?

Yes, it allows you to override locations associated with users without
jumping through lots of hoops.

Strictly you probably need to be able to turn off variable hashing as
directories entirely in POSIX mode.

pws


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Strange auto-load behaviour when function name contains hyphen
  @ 2017-12-14 10:01  3%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2017-12-14 10:01 UTC (permalink / raw)
  To: zsh-workers

On Thu, 14 Dec 2017 00:46:29 -0600
dana <dana@dana.is> wrote:
> The documentation states that function files intended for zsh-style
> auto-loading are allowed to contain a 'simple definition' (`foo() {
> ... }`) if that's the only thing in the file. This seems to work
> fine... except when the function name contains a hyphen.

A while back we had to turn "-" into a token to fix a compatibility
issue with pattern matching in POSIX shells.  This has caused problems
to come out of the wardrobe ever since.  ("Woodwork" implies a level
of solid material without the appropriate magical connotations.)

This has got line offsets including the function line numbering change as it
currently stands but I won't commit that.

pws

diff --git a/Src/exec.c b/Src/exec.c
index fc6d02d..5149349 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5932,6 +5934,7 @@ stripkshdef(Eprog prog, char *name)
 {
     Wordcode pc;
     wordcode code;
+    char *ptr1, *ptr2;
 
     if (!prog)
 	return NULL;
@@ -5942,8 +5945,23 @@ stripkshdef(Eprog prog, char *name)
 	return prog;
     pc++;
     code = *pc++;
-    if (wc_code(code) != WC_FUNCDEF ||
-	*pc != 1 || strcmp(name, ecrawstr(prog, pc + 1, NULL)))
+    if (wc_code(code) != WC_FUNCDEF ||	*pc != 1)
+	return prog;
+
+    /*
+     * See if name of function requested (name) is same as
+     * name of function in word code.  name may still have "-"
+     * tokenised.
+     */
+    ptr1 = name;
+    ptr2 = ecrawstr(prog, pc + 1, NULL);
+    while (*ptr1 && *ptr2) {
+	if (*ptr1 != *ptr2 && *ptr1 != Dash && *ptr1 != '-')
+	    break;
+	ptr1++;
+	ptr2++;
+    }
+    if (*ptr1 || *ptr2)
 	return prog;
 
     {


^ permalink raw reply	[relevance 3%]

* `jobs -p` does not behave as documented and required by POSIX
@ 2017-12-20  7:56  5% ` Matthias Richerzhagen
  2017-12-20  9:45  5%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Matthias Richerzhagen @ 2017-12-20  7:56 UTC (permalink / raw)
  To: zsh-workers

Hello,

the manpage for the `jobs` buildin function states:

>       −p        Display only the process IDs for the process group
>       leaders of the selected jobs.

> STDOUT
>        If the −p option is specified, the output shall consist of one
> line for each process ID:
> 
>            "%d\n", <process ID>

From the command:

    ( sleep 5; echo 1 ) & ( sleep 10; echo 2 ) &; jobs -p

one can see, that the output does NOT only display the process IDs:

    [1]  - 9282 running    ( sleep 5; echo 1; )
    [2]  + 9283 running    ( sleep 10; echo 2; )

making the usage in commands like

    kill `jobs -p`

generate a lot of error messages.

This is with 

    $ zsh --version 
    zsh 5.4.2 (x86_64-unknown-linux-gnu)

on Arch Linux.

Greetings,
Matthias


^ permalink raw reply	[relevance 5%]

* Re: `jobs -p` does not behave as documented and required by POSIX
  2017-12-20  7:56  5% ` `jobs -p` does not behave as documented and required by POSIX Matthias Richerzhagen
@ 2017-12-20  9:45  5%   ` Peter Stephenson
  2017-12-20 10:42 10%     ` Eric Pruitt
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2017-12-20  9:45 UTC (permalink / raw)
  To: Matthias Richerzhagen, zsh-workers

On Wed, 20 Dec 2017 08:56:20 +0100
Matthias Richerzhagen <matthias.richerzhagen@alumni.fh-aachen.de> wrote:
> Hello,
> 
> the manpage for the `jobs` buildin function states:
> 
> >       −p        Display only the process IDs for the process group
> >       leaders of the selected jobs.
> 
> > STDOUT
> >        If the −p option is specified, the output shall consist of one
> > line for each process ID:
> > 
> >            "%d\n", <process ID>

Erm, I don't think you're looking at the right manual...

       jobs [ -dlprs ] [ job ... ]
       jobs -Z string
              Lists information about each given job, or all jobs  if  job  is
              omitted.   The  -l flag lists process IDs, and the -p flag lists
              process groups.  If the -r flag is specified only  running  jobs
              will be listed and if the -s flag is given only stopped jobs are
              shown.  If the -d flag is given, the directory  from  which  the
              job  was  started (which may not be the current directory of the
              job) will also be shown.

              The -Z option replaces  the  shell's  argument  and  environment
              space  with  the  given  string,  truncated if necessary to fit.
              This will normally be visible in ps (ps(1)) listings.  This fea‐
              ture is typically used by daemons, to indicate their state.

There's no mention of *only* listing process groups.

pws



^ permalink raw reply	[relevance 5%]

* Re: `jobs -p` does not behave as documented and required by POSIX
  2017-12-20  9:45  5%   ` Peter Stephenson
@ 2017-12-20 10:42 10%     ` Eric Pruitt
  2017-12-20 11:49  5%       ` dana
  0 siblings, 1 reply; 200+ results
From: Eric Pruitt @ 2017-12-20 10:42 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Matthias Richerzhagen, zsh-workers

On Wed, Dec 20, 2017 at 09:45:49AM +0000, Peter Stephenson wrote:
> On Wed, 20 Dec 2017 08:56:20 +0100
> Matthias Richerzhagen <matthias.richerzhagen@alumni.fh-aachen.de> wrote:
> > Hello,
> >
> > the manpage for the `jobs` buildin function states:
> >
> > >       −p        Display only the process IDs for the process group
> > >       leaders of the selected jobs.
> >
> > > STDOUT
> > >        If the −p option is specified, the output shall consist of one
> > > line for each process ID:
> > >
> > >            "%d\n", <process ID>
>
> Erm, I don't think you're looking at the right manual...

The text Matthias is quoting is from the POSIX specification
(http://pubs.opengroup.org/onlinepubs/009695399/utilities/jobs.html). I
think their point is moot though because Z-shell does not claim to be
POSIX compliant in its default mode. That said, when running Z-shell as
"sh", the output of `jobs -p` still includes the "extra" information:

    ~$ (exec -a sh zsh -c 'sleep 1 & sleep 2 & jobs -p')
    [1]  - 1022 running    sleep 1
    [2]  + 1023 running    sleep 2

Eric


^ permalink raw reply	[relevance 10%]

* Re: `jobs -p` does not behave as documented and required by POSIX
  2017-12-20 10:42 10%     ` Eric Pruitt
@ 2017-12-20 11:49  5%       ` dana
  0 siblings, 0 replies; 200+ results
From: dana @ 2017-12-20 11:49 UTC (permalink / raw)
  To: Eric Pruitt; +Cc: Peter Stephenson, Matthias Richerzhagen, zsh-workers

On 20 Dec 2017, at 04:42, Eric Pruitt <eric.pruitt@gmail.com> wrote:
>think their point is moot though because Z-shell does not claim to be
>POSIX compliant in its default mode. That said, when running Z-shell as
>"sh", the output of `jobs -p` still includes the "extra" information:

Seems this was brought up before (linked from workers/22180); Bart had some
thoughts about it but no action was taken:

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=346162

Anyway, as a work-around one can do this:

  kill ${${jobstates#*:*:}%=*}

Or in a script it's probably sufficient most of the time to kill the shell's
entire process group (maybe `-HUP` would be a little nicer):

  kill 0

dana



^ permalink raw reply	[relevance 5%]

Results 1201-1400 of ~2400   |  | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2015-12-10  1:52     expr length "$val" returns the wrong length for values containing NULL (\\0) D Gowers
2015-12-10  3:56     ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-10  4:18  0%   ` D Gowers
2015-12-10  4:29  0%     ` Nikolay Aleksandrovich Pavlov (ZyX)
2015-12-10  5:00  0%       ` D Gowers
2015-12-23 11:53  3% [BUG] 'command' + special built-in exits shell on error Martijn Dekker
2016-01-01 20:03  3% [BUG] emulate sh: arith assignment assigns variable type Martijn Dekker
2016-01-02 18:11     ` Peter Stephenson
2016-01-02 20:46       ` Bart Schaefer
2016-01-02 21:12  4%     ` Peter Stephenson
2016-01-02  3:27  3% [BUG] functions can't create global readonly variables Martijn Dekker
2016-01-02  4:27  4% ` Bart Schaefer
2016-01-02 18:18  3%   ` Peter Stephenson
2016-01-02 20:36  6%     ` Bart Schaefer
2016-01-02 19:39  5%   ` Martijn Dekker
2016-01-18  4:23  3% [BUG] quoting within bracket patterns has no effect Martijn Dekker
2016-01-18 17:24     ` Peter Stephenson
2016-01-23  0:17       ` Martijn Dekker
2016-01-23  1:49  3%     ` Bart Schaefer
2016-01-26  4:03  0%       ` Martijn Dekker
2016-01-26  4:48  4%         ` Bart Schaefer
2016-01-26 14:07  0%           ` Martijn Dekker
2016-01-27  3:05  4%             ` Bart Schaefer
2016-01-20 21:06  9% test is not posix Trek
2016-01-20 21:38  5% ` Bart Schaefer
2016-01-20 21:44  5%   ` Trek
2016-01-20 23:46 10% ` Martijn Dekker
2016-01-21 12:41  5%   ` Peter Stephenson
2016-01-21 13:06  9%     ` [BUG] 'test' returns 1 (not >1) on error [was: test is not posix] Martijn Dekker
2016-01-21 16:20  4%       ` Peter Stephenson
2016-01-23 17:07     Amusing (?) behavior of zsh/parameter specials Bart Schaefer
2016-01-24 18:26  3% ` Peter Stephenson
2016-01-26  5:11  3%   ` Bart Schaefer
2016-01-23 23:53     [PATCH] typeset: set $? on incidental error Daniel Shahaf
2016-01-24  3:32  3% ` Eric Cook
2016-02-03  0:37  4% Is "command" working right, yet? Bart Schaefer
2016-02-07 15:24  4% ` Martijn Dekker
2016-09-25 23:31  3%   ` Martijn Dekker
2016-09-26  3:13  3%     ` Bart Schaefer
2016-09-27 10:08           ` Peter Stephenson
2016-09-27 12:15  3%         ` Martijn Dekker
2016-02-05 13:45     Should (t)path = array-unique-special work this way Sebastian Gniazdowski
2016-02-05 17:15  3% ` Bart Schaefer
2016-02-14 10:04  0%   ` Sebastian Gniazdowski
2016-02-14 14:34  0%     ` Daniel Shahaf
2016-02-14 23:05  4% minor 'select' snag Martijn Dekker
2016-02-15  5:11     [BUG] Sticky-sh POSIX_TRAPS are function-local Martijn Dekker
2016-02-16  9:57  5% ` Peter Stephenson
2016-02-16 12:46 11%   ` Peter Stephenson
2016-02-16 23:38  5%   ` Martijn Dekker
2016-02-17  4:25  5%     ` Bart Schaefer
2016-02-17  5:24  5%       ` Martijn Dekker
2016-02-19 18:59  5%         ` Bart Schaefer
2016-02-17 10:36  0%     ` Peter Stephenson
2016-02-25 11:53 11%     ` Peter Stephenson
2016-02-25 13:52  5%       ` Martijn Dekker
2016-03-04 18:02 16%         ` Peter Stephenson
2016-02-24 17:34     ZSH_SCRIPT Greg Klanderman
2016-02-24 22:31     ` ZSH_SCRIPT Bart Schaefer
2016-02-25  9:33  3%   ` ZSH_SCRIPT Peter Stephenson
2016-02-25 17:59  0%     ` ZSH_SCRIPT Greg Klanderman
2016-02-25 23:04           ` ZSH_SCRIPT Bart Schaefer
2016-02-29 23:36             ` ZSH_SCRIPT Greg Klanderman
2016-03-01  9:27  3%           ` ZSH_SCRIPT Peter Stephenson
2016-03-01 14:39  0%             ` ZSH_SCRIPT Greg Klanderman
2016-02-26  1:02  3% Why zsh chose to be non-compliant in pattern matching Cuong Manh Le
2016-02-27  3:11  4% [PATCH] make 'set +o' useful and POSIX compatible Martijn Dekker
2016-02-27 13:47  5% ` Martijn Dekker
2016-02-28  5:27  5% ` Bart Schaefer
2016-05-09 12:55     [PATCH] zsh locale completion Marko Myllynen
2016-05-09 22:14     ` Daniel Shahaf
2016-05-10 15:32       ` Marko Myllynen
2016-05-28 14:38  3%     ` Eric Cook
2016-05-30 17:36  4% [PATCH v2] " Marko Myllynen
2016-05-30 17:36  2% [PATCH v2] zsh localedef completion Marko Myllynen
2016-05-31 16:44  0% ` Baptiste Daroussin
2016-06-10 17:36     [PATCH 1/3] Tests: Add tests for the ':a' and ':A' modifiers Daniel Shahaf
2016-06-10 17:36  6% ` [PATCH 2/3] Fix the ':A' word modifier on paths with '..' components Daniel Shahaf
2016-06-12 20:32     Regression: broken completion on modification time Dima Kogan
2016-06-13  0:47     ` Bart Schaefer
2016-06-13 22:00       ` Oliver Kiddle
2016-06-14 16:14         ` Bart Schaefer
2016-06-15 16:32           ` Oliver Kiddle
2016-06-15 23:24             ` Daniel Shahaf
2016-06-17 16:19               ` Oliver Kiddle
2016-06-21  1:41                 ` Daniel Shahaf
2016-06-21 14:31 17%               ` Oliver Kiddle
2016-06-13  1:44     [PATCH] add-zle-hook-widget Bart Schaefer
2016-06-13  8:52     ` Daniel Shahaf
2016-06-14 18:10       ` Bart Schaefer
2016-06-15 23:24         ` Daniel Shahaf
2016-06-17  5:20           ` Bart Schaefer
2016-06-21  1:41  2%         ` Daniel Shahaf
2016-07-01 20:11  2%           ` Bart Schaefer
2016-07-05  4:57  0%             ` Daniel Shahaf
2016-06-13  8:52     [PATCH 2/3] Fix the ':A' word modifier on paths with '..' components Daniel Shahaf
2016-06-21  1:53     ` [PATCH v2 1/3] Tests: Add tests for the ':a' and ':A' modifiers Daniel Shahaf
2016-06-21  1:53  5%   ` [PATCH v2 2/3] Fix the ':A' word modifier on paths with '..' components Daniel Shahaf
2016-07-04 21:12  3% [PATCH] improve iostat completion Eric Cook
2016-07-12  1:51  3% ` [PATCH v2] " Eric Cook
2016-07-17 10:01  1% PATCH: update BSD completions Oliver Kiddle
2016-08-10 18:41     Script interpreter path length limit (POUNDBANGLIMIT) Dennis Sperlich
2016-08-11  2:20  3% ` Bart Schaefer
2016-08-16 23:54     [PATCH] New :P history modifier Daniel Shahaf
2016-08-17  7:02  3% ` Bart Schaefer
2016-08-17 16:31  0%   ` Daniel Shahaf
2016-08-22  6:17     [bug] $SHLVL decremented for the last command of a subshell Stephane Chazelas
2016-08-29 15:51     ` [PATCH] " Stephane Chazelas
2016-08-30  1:55       ` Bart Schaefer
2016-08-30 12:44         ` [PATCHv2] " Stephane Chazelas
2016-08-30 13:04           ` Peter Stephenson
2016-08-30 16:46             ` Stephane Chazelas
2016-08-30 17:00               ` Peter Stephenson
2016-08-30 19:54  3%             ` Stephane Chazelas
2016-08-30 20:10  0%               ` Stephane Chazelas
2016-08-30 23:23     buggy configure completion Vincent Lefevre
2016-08-31  3:00     ` buggy configure completion - when both --enable-foo and --disable-foo are listed Daniel Shahaf
2016-08-31  6:15       ` Vincent Lefevre
2016-08-31  9:09  3%     ` Daniel Shahaf
2016-08-31 20:27       ` m0viefreak
2016-09-02  1:27         ` Bart Schaefer
2016-09-02 21:02  2%       ` m0viefreak
2016-09-03  8:41  8% PATCH: completion updates for new options Oliver Kiddle
2016-09-03 21:06  3% [PATCH] Fix ENV handling in sh/ksh emulation Teubel György
2016-09-05 21:27     [PATCH] Use == in expressions instead of the deprecated = Teubel György
2016-09-08  8:35     ` Peter Stephenson
2016-09-08 11:16       ` Peter Stephenson
2016-09-08 14:31  3%     ` Stephane Chazelas
2016-09-08 15:06  3%       ` Stephane Chazelas
2016-09-08 15:14  0%       ` Peter Stephenson
2016-09-08 16:39  3%         ` Mikael Magnusson
2016-09-08 18:47  4%           ` Stephane Chazelas
2016-09-09  8:52  3%       ` Stephane Chazelas
2016-09-09  9:31  3%         ` Peter Stephenson
2016-09-09 16:00  0%           ` Stephane Chazelas
2016-09-14 22:01             ` PATCH: [[ -v varname ]] Oliver Kiddle
2016-09-15 11:08  3%           ` Stephane Chazelas
2016-09-15 11:22  4%             ` wrong "export -p" output for exported but not set variables (Was: PATCH: [[ -v varname ]]) Stephane Chazelas
2016-09-08  4:15  8% [PATCH] Add zsh/re2 module with conditions Phil Pennock
2016-09-09  1:12  9% [PATCH] Add zsh/re2 module with commands & conditions Phil Pennock
2016-10-02 10:01 10% 'set -e' with '!' POSIX issue Martijn Dekker
2016-10-02 17:55  4% ` Peter Stephenson
2016-10-04  7:45  5%   ` Vincent Lefevre
2016-10-04  8:30  5%     ` Peter Stephenson
2016-10-05 10:18  5%       ` Martijn Dekker
2016-10-05 11:37  5%         ` Peter Stephenson
2016-10-05 13:47  3%         ` Peter Stephenson
2016-10-06  8:36  5%           ` Peter Stephenson
2016-10-06 11:22  9%           ` Martijn Dekker
2016-10-22  3:02  5% 'export -p' lacks POSIX output Martijn Dekker
2016-10-22 18:24  9% ` Bart Schaefer
2016-10-23 12:00 11%   ` Martijn Dekker
2016-10-23 16:47  9%     ` Bart Schaefer
2016-10-24  8:33  5%   ` Peter Stephenson
2016-10-28 21:00  9% ` exported unset variables [was: 'export -p' lacks POSIX output] Martijn Dekker
2016-10-28 21:31  5%   ` Bart Schaefer
2016-10-28 21:48  5%     ` Martijn Dekker
2016-10-29  0:18  7%       ` Bart Schaefer
2016-10-29  8:11  5%         ` Martijn Dekker
2016-10-29 18:09  6%           ` Bart Schaefer
2016-10-29 18:43  9%             ` Peter Stephenson
2016-10-29 19:05  9%           ` Bart Schaefer
2016-10-26 14:07 16% [PATCH] _awk: support gawk ver.3 and 4 Jun T.
2016-11-03 12:53  6% ` Oliver Kiddle
2016-10-27 17:21  3% zsh silently abandons compound command on trying to write to a closed file descriptor Martijn Dekker
2016-11-03 20:32     "invalid arguments" in cpio completion Danek Duvall
2016-11-05 20:39     ` Daniel Shahaf
2016-11-05 21:52  3%   ` Bart Schaefer
     [not found]     <CGME20161107184855epcas2p40d3b5bf0dbe89e79bcc94c501a4d1562@epcas2p4.samsung.com>
2016-11-07 18:18  3% ` 'exit' in trap handler does not execute EXIT trap Martijn Dekker
2016-11-08 12:47  0%   ` Peter Stephenson
2016-11-09 14:52  1% PATCH: typo corrections in completion functions Oliver Kiddle
     [not found]     <CGME20161208033159epcas3p47d871ed70505af5cb760591e5cff6a00@epcas3p4.samsung.com>
2016-12-08  3:26     ` Test failure on OpenBSD Matthew Martin
2016-12-08  9:44       ` Peter Stephenson
2016-12-09  5:13         ` Matthew Martin
2016-12-09  8:24  3%       ` Bart Schaefer
2016-12-09  9:49  0%         ` Peter Stephenson
     [not found]     <CGME20161206195028epcas2p3c53119ab37952571be3238cdf228d88f@epcas2p3.samsung.com>
     [not found]     ` <20161206194916.10448440@ntlworld.com>
     [not found]       ` <20161209095729.2033b5be@pwslap01u.europe.root.pri>
     [not found]         ` <20161209195457.27e43234@ntlworld.com>
     [not found]           ` <584CB4EF.6070904@eastlink.ca>
2016-12-11  3:07             ` zsh-5.2-test-3 Bart Schaefer
2016-12-11  3:26               ` zsh-5.2-test-3 Ray Andrews
2016-12-11  3:44                 ` zsh-5.2-test-3 Bart Schaefer
2016-12-11  4:11                   ` zsh-5.2-test-3 Daniel Shahaf
2016-12-11  8:58  3%                 ` zsh-5.2-test-3 Bart Schaefer
2016-12-12 23:41     5.3: printf - Daniel Shahaf
2016-12-13  4:21     ` Bart Schaefer
     [not found]       ` <CGME20161214044835epcas1p363f68aa2155487af59907b878d702464@epcas1p3.samsung.com>
2016-12-14  4:48         ` PATCH " Bart Schaefer
2016-12-14  9:39           ` Peter Stephenson
2016-12-14 16:51             ` Daniel Shahaf
2016-12-14 18:44               ` Bart Schaefer
2016-12-15  0:50  3%             ` Daniel Shahaf
2016-12-15  1:14  4%               ` Chet Ramey
2016-12-15 22:45  3%                 ` Daniel Shahaf
2016-12-15 23:48  0%                   ` Chet Ramey
2016-12-16  0:56  0%                     ` Daniel Shahaf
2017-01-09 20:32  8% [PATCH] Document echo \c behaviour Phil Pennock
2017-01-12  6:46  2% fix watch implementation Jens Elkner
     [not found]     <CAM4j=kO9MSg-72LWog0N3OPumh8jy_xt4_T_fXEXAKQEk3eoXg__31721.773549407$1484300384$gmane$org@mail.gmail.com>
     [not found]     ` <CGME20170113150404epcas4p2b15a4b2d8af580d4b38d8c69e13737a7@epcas4p2.samsung.com>
     [not found]       ` <20170113145919.GB4363@fujitsu.shahaf.local2>
2017-01-13 15:19         ` `exec env -i OLDPWD=$OLDPWD zsh` doesn't work Peter Stephenson
2017-01-13 15:24           ` Peter Stephenson
2017-01-14  5:09  3%         ` Bart Schaefer
2017-02-10 14:57  4% traps not reset in pipe component subshells Stephane Chazelas
2017-02-11 12:58     Multithreading support in pluggable module, but with problems Sebastian Gniazdowski
2017-02-11 19:46  3% ` Bart Schaefer
2017-02-11 20:14  0%   ` Sebastian Gniazdowski
2017-02-15 22:17     signal mask bug? Danek Duvall
     [not found]     ` <CGME20170216041124epcas3p2d347268b66b542ebe695c6a2766eed55@epcas3p2.samsung.com>
2017-02-16  4:10       ` Bart Schaefer
2017-02-16  9:48  3%     ` Peter Stephenson
2017-02-16 20:18  0%       ` Danek Duvall
2017-02-16 23:05     [BUG] var=$* and var=$@ create array with SHWORDSPLIT and null or unset IFS Martijn Dekker
2017-02-17  5:14     ` Bart Schaefer
2017-02-20 18:58       ` Bart Schaefer
2017-02-20 21:20         ` Bart Schaefer
2017-02-20 22:13  4%       ` Martijn Dekker
2017-02-26  5:36  2% [BUG] Solaris-specific program flow corruption after subshell error exit Martijn Dekker
2017-02-26 20:29  3% ` Bart Schaefer
2017-02-26 22:55  3%   ` Martijn Dekker
2017-02-28 19:17     patch for ssh completion Jeremy Cantrell
2017-03-02 12:12  3% ` Daniel Shahaf
2017-03-05  8:27  0%   ` Daniel Shahaf
2017-03-08  8:50     export "a=b"=~ Stephane Chazelas
2017-03-08 13:23  3% ` Daniel Shahaf
2017-03-08 15:44  0%   ` Peter Stephenson
2017-03-08 22:30  3%     ` Stephane Chazelas
2017-03-13 22:24 15% PATCH: update completions for some coreutils commands Oliver Kiddle
2017-04-16 16:07  4% Alias expansion inconsistency in $(command substitutions) with IGNORE_CLOSE_BRACES Martijn Dekker
2017-04-21 20:32     Call stack issues when running trap handler Sebastian Reuße
2017-04-26 19:27  5% ` Peter Stephenson
2017-04-26 19:52  4%   ` Peter Stephenson
2017-05-08 13:53  1% Zsh parser malloc corruption Eduardo Bustamante
2017-05-29  4:28 12% [PATCH] _nm: support macOS and OpenBSD Jun T.
2017-05-31 21:24     Surprising behaviour with numeric glob sort Stephane Chazelas
2017-06-01 22:29     ` Bart Schaefer
2017-06-02  9:03       ` Stephane Chazelas
2017-06-02 23:19         ` Bart Schaefer
2017-06-03 21:16           ` Stephane Chazelas
2017-06-04  0:07             ` Bart Schaefer
2017-06-04 17:31               ` Stephane Chazelas
2017-06-04 22:01                 ` Bart Schaefer
2017-06-05 11:54  3%               ` Stephane Chazelas
2017-06-05 19:15  3%                 ` Stephane Chazelas
2017-06-13 10:02     =~ doesn't work with NUL characters Stephane Chazelas
2017-06-14 20:49  3% ` Phil Pennock
2017-06-15  9:50  3%   ` Stephane Chazelas
2017-06-15 20:40     [PATCH] PCRE/NUL: pass NUL in for text, handle NUL out Phil Pennock
2017-06-16  6:41  3% ` Stephane Chazelas
     [not found]     <CGME20170725221050epcas4p131de822f47289e279c7de12de0d6c127@epcas4p1.samsung.com>
2017-07-25 21:49  5% ` [BUG] 'exec' runs shell functions and builtins Martijn Dekker
2017-07-26  9:23 16%   ` Peter Stephenson
2017-07-26 17:46  4%   ` Bart Schaefer
2017-07-27  9:02  0%     ` Peter Stephenson
2017-07-28 17:58  3%       ` Bart Schaefer
2017-08-11 15:10  4%         ` Kamil Dudka
2017-08-11 15:25  0%           ` Peter Stephenson
2017-08-14  7:19  3%             ` Kamil Dudka
2017-08-02 15:10  4% [PATCH] _df: Complete mounted device and mount points Daniel Shahaf
2017-08-04  2:03  4% shwordsplit: final non-whitespace IFS character problem Martijn Dekker
2017-08-04 10:56  5% ` Stephane Chazelas
2017-08-04 11:13  3%   ` Peter Stephenson
2017-08-06 18:08  3% ` Peter Stephenson
2017-08-06 20:01  3%   ` Peter Stephenson
2017-08-08 10:56  0%     ` Kamil Dudka
2017-08-04 15:58  6% PATCH: update to a few more completions Oliver Kiddle
     [not found]     <CGME20170807135641epcas3p4bc0a64f832ae7fcd76051ac198722045@epcas3p4.samsung.com>
2017-08-07 13:55     ` parsing empty alternatives: case foo|) :;; Daniel Shahaf
2017-08-07 14:26       ` Peter Stephenson
2017-08-07 14:44         ` Bart Schaefer
2017-08-07 14:58           ` Peter Stephenson
2017-08-07 18:03             ` 5.4 almost released Peter Stephenson
2017-08-07 18:25               ` Eric Cook
2017-08-07 18:34                 ` Peter Stephenson
2017-08-08 10:26                   ` Martijn Dekker
2017-08-08 11:00  3%                 ` Peter Stephenson
2017-08-18 20:32     Modify sort ordering for `ls` Daniel Li
2017-08-18 20:44  3% ` Phil Pennock
2017-08-18 22:24  0%   ` Daniel Li
2017-08-27  0:50  3% "set -e" handling is broken with zsh 5.3.1 and 5.4.1 Vincent Lefevre
2017-09-08  8:29  3% Running "unset path" breaks PATH despite emulation being enabled Eric Pruitt
2017-09-08 11:30  0% ` Mikael Magnusson
2017-09-08 16:17       ` Peter Stephenson
2017-09-11  8:58  2%     ` Peter Stephenson
2017-09-09  4:24  3%   ` Eric Pruitt
     [not found]     <CGME20170912101045epcas2p4cae7e7df78ef035900f9c6099dc054fb@epcas2p4.samsung.com>
2017-09-12 10:02     ` [BUG] exec + builtin and traps Vincent Lefevre
2017-09-12 10:19       ` Peter Stephenson
2017-09-12 10:39         ` Vincent Lefevre
2017-09-12 10:50           ` Peter Stephenson
2017-09-12 11:42  3%         ` Vincent Lefevre
2017-09-16 20:57     Memory leak when working with undefined associative array keys & problems with unset Anssi Palin
2017-09-17 23:15     ` Bart Schaefer
     [not found]       ` <1505690609.1747008.1109155032.651AC839@webmail.messagingengine.com>
2017-09-18  0:22  3%     ` Bart Schaefer
2017-09-27 23:56 10% POSIX and PROMPT_BANG Bart Schaefer
2017-10-04 22:20  3% [bug] sh: tilde expansion after field splitting Martijn Dekker
2017-10-05  5:24  3% ` Bart Schaefer
2017-10-08  7:53  2% ` Bart Schaefer
2017-10-08 19:20  0%   ` Peter Stephenson
2017-10-13  9:43  0%   ` Martijn Dekker
2017-10-13 12:55  0%     ` Peter Stephenson
2017-10-11 18:44  8% [PATCH] POSIXBUILTINS: quieten 'unset -f nonexistentfunc' Martijn Dekker
2017-11-02 19:04  0% ` Martijn Dekker
2017-11-02 20:04  0%   ` Peter Stephenson
2017-11-10 18:24     [PATCH] don't exit shell on [[ -o invalid@option ]] Martijn Dekker
2017-11-10 22:37     ` Bart Schaefer
2017-11-11 12:45       ` Peter Stephenson
2017-11-11 19:01  3%     ` Martijn Dekker
2017-11-11 23:19  3%       ` Bart Schaefer
2017-11-12 19:56  0%         ` Peter Stephenson
2017-11-14 12:26               ` Daniel Shahaf
2017-11-14 13:22                 ` Martijn Dekker
2017-11-14 23:52                   ` Daniel Shahaf
2017-11-16  0:52                     ` Martijn Dekker
2017-11-18 18:22  4%                   ` Daniel Shahaf
2017-12-07 11:29     $userdirs empty in non-interactive shells Stephane Chazelas
2017-12-08 12:23  3% ` Stephane Chazelas
2017-12-08 12:31  3%   ` Peter Stephenson
     [not found]     <CGME20171214064805epcas2p196a185a6c3c5e66640833d8dfa15d593@epcas2p1.samsung.com>
2017-12-14  6:46     ` [BUG] Strange auto-load behaviour when function name contains hyphen dana
2017-12-14 10:01  3%   ` Peter Stephenson
     [not found]     <CGME20171220080716epcas1p14317a75dd17abfa9d127ef341bcc383b@epcas1p1.samsung.com>
2017-12-20  7:56  5% ` `jobs -p` does not behave as documented and required by POSIX Matthias Richerzhagen
2017-12-20  9:45  5%   ` Peter Stephenson
2017-12-20 10:42 10%     ` Eric Pruitt
2017-12-20 11:49  5%       ` dana

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).