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: PATCH: Util/helpfiles failing on old-fashioned unix
  @ 2013-12-13  9:08  4%                     ` Martin Vaeth
  0 siblings, 0 replies; 200+ results
From: Martin Vaeth @ 2013-12-13  9:08 UTC (permalink / raw)
  To: zsh-workers

pda@sdf.org <pda@sdf.org> wrote:
> This pipeline looks like
> it could have an undetected error where man fails, but colcrt doesn't.

This is right, but I do not know a clean way how to solve this
problem in the lack of PIPESTATUS in posix - using known posix
tricks like piping error status to >&3 also has compatbility issues
(IIRC on cygwin).

A natural way is to start the man/nroff and colcrt/col processes
separately. Unfortunately, I do not know a way in perl to redirect
stdin *and* stdout of a subprocess simultaneously.
Perhaps the only clean way is to use a temporary file first for the
man/nroff output and then for the colcrc/col output.

Anyway, your patch only breaks usage on other systems:
The semantics of your patch is just a changed second open call and
that the error status of the first call to open is negated which
is certainly not intended:

> +unless( undef == open(MANPAGE, '-|', "man $manfile | colcrt -")) {
> +      ( undef == open(MANPAGE, '-|', "nroff -man $manfile | col -bx"))

The second open is executed if (and only if) the first open *succeeeds*.
This is certainly not intended.

Moreover, a clean patch should somehow attempt all 4 possible combinations
of the tools.


^ permalink raw reply	[relevance 4%]

* Read-only variables in emulation mode
@ 2013-12-16 19:10  3% Øystein Walle
  2013-12-16 19:40  3% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Øystein Walle @ 2013-12-16 19:10 UTC (permalink / raw)
  To: zsh-workers

Hi,

Consider the following:

    emulate sh -c '
    some_name() {
        status=world
        echo "hello $status"
    }
    some_name
    '

Running it gives:

    some_name:1: read-only variable: status

This is a problem if you source a "library" meant to be used by
different versions of different shells:

    $ cat =git-example
    #!/bin/zsh
    emulate sh -c '
    . git-sh-setup
    '
    ...
    require_work_tree
    ...
    $ git example
    die_with_status:1: read-only variable: status

A common idiom in (ba)sh scripting is to use _ as a throwaway in a
while-read loop:

    while read -r col1 _ col2; do
        echo "col1 = $col1 and col2 = $col2"
    done < three-columns.txt

This also fails with an equivalent message when used in sh emulation.

Is it fixable? (Is the general opinion that it needs fixing?). I
assume status and _ are meant to be writable in POSIX shells.

I suppose an idea would be for various variables to be writable within
emulate -c '...' and later in the functions defined therein. How this
would affect the rest of the shell is hard to say for me.

In the mean time, is there any way around it?

Thanks
Øsse


^ permalink raw reply	[relevance 3%]

* Re: Read-only variables in emulation mode
  2013-12-16 19:10  3% Read-only variables in emulation mode Øystein Walle
@ 2013-12-16 19:40  3% ` Bart Schaefer
  2013-12-18  6:36  5%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2013-12-16 19:40 UTC (permalink / raw)
  To: Oystein Walle, zsh-workers

On Dec 16,  8:10pm, Oystein Walle wrote:
} Subject: Read-only variables in emulation mode
}
} I assume status and _ are meant to be writable in POSIX shells.

Hmm.  According to the doc, "status" should be writable but "_" not.

    status <S> <Z>

    _ <S>

(The <S> means "special", the <Z> means "but only in native zsh mode".)

} A common idiom in (ba)sh scripting is to use _ as a throwaway in a
} while-read loop:
} 
}     while read -r col1 _ col2; do
}         echo "col1 = $col1 and col2 = $col2"
}     done < three-columns.txt

Well, that's one I'd never seen before.  Certainly that's about the only
place it's "safe" to use "_" because it's always immediately going to be
clobbered.
 
} In the mean time, is there any way around it?

Only by using a function scope and declaring "local -h _ status" to hide
the special variables.


^ permalink raw reply	[relevance 3%]

* Re: Read-only variables in emulation mode
  2013-12-16 19:40  3% ` Bart Schaefer
@ 2013-12-18  6:36  5%   ` Bart Schaefer
  2013-12-18 19:28  0%     ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2013-12-18  6:36 UTC (permalink / raw)
  To: zsh-workers

On Dec 16, 11:40am, Bart Schaefer wrote:
} Subject: Re: Read-only variables in emulation mode
}
} On Dec 16,  8:10pm, Oystein Walle wrote:
} } Subject: Read-only variables in emulation mode
} }
} } I assume status and _ are meant to be writable in POSIX shells.
} 
} Hmm.  According to the doc, "status" should be writable but "_" not.

I looked a bit more closely at this and found that when zsh is *started*
in POSIX shell mode (e.g., the executable name is sh or ksh), then the
"status" variable is non-special, as expected.

It's a known limitation that invoking "emulate ..." after the shell is
already running does completely re-instantiate POSIX mode.  This is not
likely to change.

However, I don't think there's any particular reason we couldn't remove
the readonly property from $_ if that would improve compatibility.


^ permalink raw reply	[relevance 5%]

* Re: Read-only variables in emulation mode
  2013-12-18  6:36  5%   ` Bart Schaefer
@ 2013-12-18 19:28  0%     ` Peter Stephenson
  2013-12-19  7:57  3%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2013-12-18 19:28 UTC (permalink / raw)
  To: zsh-workers

On Tue, 17 Dec 2013 22:36:51 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> It's a known limitation that invoking "emulate ..." after the shell is
> already running does completely re-instantiate POSIX mode.  This is not
> likely to change.

I don't expect I'll get round to it myself, but in the case of
variables, I don't think this should be that difficult.  The variables
need saving and hiding on entry to emulation and restoring afterwards.
Most of the significant chunks of code for that are already in place.

pws


^ permalink raw reply	[relevance 0%]

* Re: Read-only variables in emulation mode
  2013-12-18 19:28  0%     ` Peter Stephenson
@ 2013-12-19  7:57  3%       ` Bart Schaefer
  2015-06-16  0:10  0%         ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2013-12-19  7:57 UTC (permalink / raw)
  To: zsh-workers

On Dec 18,  7:28pm, Peter Stephenson wrote:
} Subject: Re: Read-only variables in emulation mode
}
} On Tue, 17 Dec 2013 22:36:51 -0800
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > It's a known limitation that invoking "emulate ..." after the shell is
} > already running does [not] completely re-instantiate POSIX mode.
} 
} I don't expect I'll get round to it myself, but in the case of
} variables, I don't think this should be that difficult.

The part about "_" is easy, though:

diff --git a/Src/params.c b/Src/params.c
index 26ad6b2..cadf268 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -283,7 +283,7 @@ IPDEF2("TERM", term_gsu, 0),
 IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET),
 IPDEF2("WORDCHARS", wordchars_gsu, 0),
 IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
-IPDEF2("_", underscore_gsu, PM_READONLY),
+IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
 IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
 
 #ifdef USE_LOCALE


Feel free to commit that for me if you want it to go into 5.0.4, I'm
going to be asleep for the next several hours ...


^ permalink raw reply	[relevance 3%]

* Fwd (potential regression in 5.0.3): Bug#732726: zsh function freeze
@ 2013-12-20 19:24  2% Axel Beckert
  0 siblings, 0 replies; 200+ results
From: Axel Beckert @ 2013-12-20 19:24 UTC (permalink / raw)
  To: zsh-workers

Hi,

this has been reported[1] against zsh 5.0.3 in Debian today. Looks like
some regression in 5.0.3 on a first glance. Maybe related to the
test-suite freezes which have been reported on a few architectures.

[1] http://bugs.debian.org/732726

Since 5.0.4 seems close, I thought I'd better forward it soon despite
I haven't looked at it closer yet.

----- Forwarded message from Vincent Lefevre <vincent@vinc17.net> -----
Date: Fri, 20 Dec 2013 19:14:36 +0100
From: Vincent Lefevre <vincent@vinc17.net>
Subject: [Pkg-zsh-devel] Bug#732726: zsh function freeze
Reply-To: Vincent Lefevre <vincent@vinc17.net>, 732726@bugs.debian.org

Package: zsh
Version: 5.0.3-1
Severity: important

This is an important regression (no problems after downgrading to
5.0.2-6), always reproducible.

With a private SVN repository, "svncdiff -c65935 ~/wd | head" freezes, where
svncdiff is the following zsh function (I have "autoload -U svncdiff"):

------------------------------------------------------------------------
#!/usr/bin/env zsh

# Wrapper to "svn diff", written by Vincent Lefevre <vincent@vinc17.org>

# Needs my tdiff utility to process the diff output; otherwise you need
# to remove the "| tdiff" at the end.

# Example of svncdiff usage:
#   svncdiff -5 -x -p file
# for 5 lines of unified context and function information.

emulate -LR zsh
local -a args xopt
setopt EXTENDED_GLOB

while [[ $# -ge 1 ]]
do
  if [[ "x$1" == x-[0-9]# ]] then
    args=($args --diff-cmd diff)
    xopt=($xopt -U${1[2,-1]})
  elif [[ $# -ge 2 && "x$1" == x-x ]] then
    shift
    xopt=($xopt $1)
  else
    args=($args $1)
  fi
  shift
done

[[ $#xopt -ge 1 ]] && args=(-x "$xopt" $args)
svnwrapper diff "$args[@]" | tdiff

# $Id: svncdiff 38442 2010-08-05 11:41:16Z vinc17/ypig $
------------------------------------------------------------------------

The dependencies can be found on <https://www.vinc17.net/unix/>.

When svncdiff is called as a script, this is no such problem.

With my tps utility, I can observe:

10987  sshd: vlefevre@pts/2
└─> 10988  -zsh
  └─> 11262  -zsh
    ├─> 11264  zsh -f -- /home/vlefevre/bin/svnwrapper diff -c65935 /home/vlefevre/wd
    │ └─> 11269  svn diff -c65935 /home/vlefevre/wd
    │   ├─> 11273  zsh /home/vlefevre/scripts/ssh mysvn svnserve -t
    │   │ ├─> 11295  cat
    │   │ └─> 11298  ssh -F /home/vlefevre/.ssh/config -C mysvn svnserve -t
    │   └─> 11299  zsh /home/vlefevre/scripts/ssh mysvn svnserve -t
    │     ├─> 11317  cat
    │     └─> 11320  ssh -F /home/vlefevre/.ssh/config -C mysvn svnserve -t
    └─> 11265  perl /home/vlefevre/bin/tdiff

I think that this occurs on big changesets.

$ svncdiff -c65935 ~/wd | wc
   2166   14746  212680

I'll try to investigate, but any idea about which zsh change could
trigger the problem?

-- System Information:
Debian Release: jessie/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.11-2-amd64 (SMP w/8 CPU cores)
Locale: LANG=POSIX, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages zsh depends on:
ii  libc6       2.17-97
ii  libcap2     1:2.22-1.2
ii  libtinfo5   5.9+20130608-1
ii  zsh-common  5.0.3-1

Versions of packages zsh recommends:
ii  libncursesw5  5.9+20130608-1
ii  libpcre3      1:8.31-2

Versions of packages zsh suggests:
ii  zsh-doc  5.0.3-1

-- no debconf information
----- End forwarded message -----

----- Forwarded message from Vincent Lefevre <vincent@vinc17.net> -----
Date: Fri, 20 Dec 2013 19:19:18 +0100
From: Vincent Lefevre <vincent@vinc17.net>
To: 732726@bugs.debian.org
Subject: [Pkg-zsh-devel] Bug#732726: zsh function freeze
Reply-To: Vincent Lefevre <vincent@vinc17.net>, 732726@bugs.debian.org

On 2013-12-20 19:14:36 +0100, Vincent Lefevre wrote:
> I think that this occurs on big changesets.

Indeed I can reproduce it with:

  svncdiff -c 8540 svn://scm.gforge.inria.fr/svn/mpfr/trunk | head
----- End forwarded message -----

		Kind regards, Axel
-- 
/~\  Plain Text Ribbon Campaign                   | Axel Beckert
\ /  Say No to HTML in E-Mail and News            | abe@deuxchevaux.org  (Mail)
 X   See http://www.asciiribbon.org/              | abe@noone.org (Mail+Jabber)
/ \  I love long mails: http://email.is-not-s.ms/ | http://noone.org/abe/ (Web)


^ permalink raw reply	[relevance 2%]

* PATCH: shift -p
@ 2014-01-10 22:37  6% Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-01-10 22:37 UTC (permalink / raw)
  To: Zsh Hackers' List

I've discovered I'm too lazy to write

array="${(@)array[1,-2]}"

any more, so I made "shift -p array" do it instead.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 8c7bc85..ea2f68d 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1500,12 +1500,15 @@ POSIX standard, but tt(setopt) is not.
 )
 findex(shift)
 cindex(parameters, positional)
-item(tt(shift) [ var(n) ] [ var(name) ... ])(
+item(tt(shift) [ tt(-p) ] [ var(n) ] [ var(name) ... ])(
 The positional parameters tt(${)var(n)PLUS()1tt(}) ... are renamed
 to tt($1) ..., where var(n) is an arithmetic expression that
 defaults to 1.
 If any var(name)s are given then the arrays with these names are
 shifted instead of the positional parameters.
+
+If the option tt(-p) is given arguments are instead removed (popped)
+from the end rather than the start of the array.
 )
 findex(source)
 item(tt(source) var(file) [ var(arg) ... ])(
diff --git a/Src/builtin.c b/Src/builtin.c
index c3f0169..9bcbcf7 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -111,7 +111,7 @@ static struct builtin builtins[] =
     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),
     BUILTIN("setopt", 0, bin_setopt, 0, -1, BIN_SETOPT, NULL, NULL),
-    BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, NULL, NULL),
+    BUILTIN("shift", BINF_PSPECIAL, bin_shift, 0, -1, 0, "p", NULL),
     BUILTIN("source", BINF_PSPECIAL, bin_dot, 1, -1, 0, NULL, NULL),
     BUILTIN("suspend", 0, bin_suspend, 0, 0, 0, "f", NULL),
     BUILTIN("test", BINF_HANDLES_OPTS, bin_test, 0, -1, BIN_TEST, NULL, NULL),
@@ -4509,7 +4509,7 @@ bin_print(char *name, char **args, Options ops, int func)
 
 /**/
 int
-bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
+bin_shift(char *name, char **argv, Options ops, UNUSED(int func))
 {
     int num = 1, l, ret = 0;
     char **s;
@@ -4533,7 +4533,19 @@ bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 		    ret++;
 		    continue;
 		}
-		s = zarrdup(s + num);
+		if (OPT_ISSET(ops,'p')) {
+		    char **s2, **src, **dst;
+		    int count;
+		    l = arrlen(s);
+		    src = s;
+		    dst = s2 = (char **)zalloc((l - num + 1) * sizeof(char *));
+		    for (count = l - num; count; count--)
+			*dst++ = ztrdup(*src++);
+		    *dst = NULL;
+		    s = s2;
+		} else {
+		    s = zarrdup(s + num);
+		}
                 setaparam(*argv, s);
             }
     } else {
@@ -4542,9 +4554,16 @@ bin_shift(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 	    ret = 1;
 	} else {
 	    s = zalloc((l - num + 1) * sizeof(char *));
-	    memcpy(s, pparams + num, (l - num + 1) * sizeof(char *));
-	    while (num--)
-		zsfree(pparams[num]);
+	    if (OPT_ISSET(ops,'p')) {
+		memcpy(s, pparams, (l - num) * sizeof(char *));
+		s[l-num] = NULL;
+		while (num--)
+		    zsfree(pparams[l-1-num]);
+	    } else {
+		memcpy(s, pparams + num, (l - num + 1) * sizeof(char *));
+		while (num--)
+		    zsfree(pparams[num]);
+	    }
 	    zfree(pparams, (l + 1) * sizeof(char *));
 	    pparams = s;
 	}
diff --git a/Test/.distfiles b/Test/.distfiles
index 1c01028..5826e75 100644
--- a/Test/.distfiles
+++ b/Test/.distfiles
@@ -15,6 +15,7 @@ B04read.ztst
 B05eval.ztst
 B06fc.ztst
 B07emulate.ztst
+B08shift.ztst
 C01arith.ztst
 C02cond.ztst
 C03traps.ztst
diff --git a/Test/B08shift.ztst b/Test/B08shift.ztst
index e69de29..0aa9226 100644
--- a/Test/B08shift.ztst
+++ b/Test/B08shift.ztst
@@ -0,0 +1,33 @@
+# Test the shift builtin.
+
+%test
+
+  set -- one two three four five six seven eight nine ten
+  shift
+  print $*
+  shift 2
+  print $*
+  shift -p 3
+  print $*
+  shift -p
+  print $*
+0:shifting positional parameters
+>two three four five six seven eight nine ten
+>four five six seven eight nine ten
+>four five six seven
+>four five six
+
+  array=(yan tan tether mether pip azer sezar akker conter dick)
+  shift 2 array
+  print $array
+  shift array
+  print $array
+  shift -p 3 array
+  print $array
+  shift -p array
+  print $array
+0:shifting array
+>tether mether pip azer sezar akker conter dick
+>mether pip azer sezar akker conter dick
+>mether pip azer sezar
+>mether pip azer

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[relevance 6%]

* [PATCH] new completion function for od
@ 2014-01-22 15:59  4% Jun T.
  0 siblings, 0 replies; 200+ results
From: Jun T. @ 2014-01-22 15:59 UTC (permalink / raw)
  To: zsh-workers


---

This is a new completion function for the od (octal dump) command


 Completion/Unix/Command/_od | 71 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)
 create mode 100644 Completion/Unix/Command/_od

diff --git a/Completion/Unix/Command/_od b/Completion/Unix/Command/_od
new file mode 100644
index 0000000..d542597
--- /dev/null
+++ b/Completion/Unix/Command/_od
@@ -0,0 +1,71 @@
+#compdef od
+
+local context state state_descr line args ret=1
+local -A opt_args
+
+args=(
+  '(-A --address-radix)'{-A+,--address-radix=}'[file offset base]:base:((d\:decimal o\:octal x\:hexadecimal n\:none))'
+  '(-j --skip-bytes)'{-j+,--skip-bytes=}'[skip specified bytes]:bytes'
+  '(-N --read-bytes)'{-N+,--read-bytes=}'[dump at most specified bytes]:bytes'
+  '*'{-t+,--format=}'[specify output format]:format string:->format'
+  '(-v --output-duplicates)'{-v,--output-duplicates}'[do not use * to mark line suppression]'
+  '-a[output named characters (-t a)]'
+  '-b[output octal bytes (-t o1)]'
+  '-c[output characters with C-style escape (-t c)]'
+  '-d[output unsigned decimal shorts (-t u2)]'
+  '-f[output single-precision floats (-t fF)]'
+  {-h,-x}'[output hexadecimal shorts (-t x2)]'
+  '-i[output decimal integers (-t dI)]'
+  {-l,-I,-L}'[output decimal longs (-t dL)]'
+  {-o,-B}'[output octal shorts (-t o2)]'
+  '-s[output decimal shorts (-t d2)]'
+  '*:files:_files'
+)
+
+if _pick_variant gnu=GNU unix --version; then
+  # -h -B -I and -L are obsolescent and undocumented
+  args=( ${(R)args:#(|\*)(|\(*\))-[hBIL]*} )
+  args+=(
+    {-S+,--strings=-}'[output strings of at least specfied bytes long]:length'
+    {-w-,--width=-}'[output specified bytes per line]:bytes'
+    '(- : *)--help[display help and exit]'
+    '(- : *)--version[output version information and exit]'
+  )
+else
+  args=( ${(R)args:#(|\*)(|\(*\))--*} )    # remove long options
+  case "$OSTYPE" in
+    (darwin*|freebsd*|dragonfly*|openbsd*)
+      args+=(
+        '-D[output unsigned decimal ints (-t u4)]'
+        {-e,-F}'[output double-precision floats (-t fD)]'
+        {-H,-X}'[output hexadecimal ints (-t x4)]'
+        '-O[output octal ints (-t o4)]'
+      )
+      ;;
+    (*)
+      # POSIX options only
+      args=( ${(M)args:#(|\*)(|\(*\))-[AjNtvbcdosx]*} )
+      ;;
+  esac
+fi
+
+_arguments -s -S : "$args[@]" && return 0
+
+case "$state" in
+  (format)
+    compset -P '*[acCSIL1248FDL]'
+    if compset -P '*[doux]'; then
+      args=( 'C:char' 'S:short' 'I:int' 'L:long' 1 2 4 8 )
+      _describe -t integer-size 'size of integer' args && ret=0
+    elif compset -P '*f'; then
+      args=( 'F:float' 'D:double' 'L:long double' )
+      _describe -t float-size 'size of float' args && ret=0
+    fi
+    args=( 'a:named character' 'c:character (C-style escape)'
+           'd:decimal' 'o:octal' 'u:unsigned decimal'
+           'x:hexadecimal' 'f:floating-point number' )
+    _describe -t type-specifier 'type specifier' args && ret=0
+  ;;
+esac
+
+return ret
-- 
1.8.3.4 (Apple Git-47)



^ permalink raw reply	[relevance 4%]

* Following up from before 5.0.5:  Change initialization of parameters
@ 2014-02-02 20:48  3% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-02-02 20:48 UTC (permalink / raw)
  To: zsh-workers

Some weeks ago, before the several rounds of finding critcal bugs shortly
after each release and therefore making PWS repeat himself, there was a
discussion about the handling of various parameters that are "special" to
zsh but not to a POSIX shell.

Here's a first pass at initializing several of these parameters as unset
(rather than e.g. set to empty string).  There are probably others that
could get similar treatment.  I fiddled with a few more that overlap with
various emulation modes but found problems; e.g. having OPTND/OPTARG unset
actually breaks the getopts command: that's probably a bug.

Possibly the most interesting one here is $_ which changes from READONLY
to DONTIMPORT.  This is what started the previous thread: $_ is said to
be commonly used as a throwaway in some scripting idioms.  The only
reason I can see why it was ever read-only is because it's going to be
overwritten at regular intervals, so one cannot rely on it keeping any
value one might assign to it.


diff --git a/Src/params.c b/Src/params.c
index dc41c6c..59d503c 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -263,7 +263,7 @@ static initparam special_params[] ={
 #define NULL_GSU BR((GsuScalar)(void *)NULL)
 #define IPDEF1(A,B,C) {{NULL,A,PM_INTEGER|PM_SPECIAL|C},BR(NULL),GSU(B),10,0,NULL,NULL,NULL,0}
 IPDEF1("#", pound_gsu, PM_READONLY),
-IPDEF1("ERRNO", errno_gsu, 0),
+IPDEF1("ERRNO", errno_gsu, PM_UNSET),
 IPDEF1("GID", gid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("EGID", egid_gsu, PM_DONTIMPORT | PM_RESTRICTED),
 IPDEF1("HISTSIZE", histsize_gsu, PM_RESTRICTED),
@@ -279,11 +279,11 @@ IPDEF2("USERNAME", username_gsu, PM_DONTIMPORT|PM_RESTRICTED),
 IPDEF2("-", dash_gsu, PM_READONLY),
 IPDEF2("histchars", histchars_gsu, PM_DONTIMPORT),
 IPDEF2("HOME", home_gsu, PM_UNSET),
-IPDEF2("TERM", term_gsu, 0),
+IPDEF2("TERM", term_gsu, PM_UNSET),
 IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET),
 IPDEF2("WORDCHARS", wordchars_gsu, 0),
 IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
-IPDEF2("_", underscore_gsu, PM_READONLY),
+IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
 IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
 
 #ifdef USE_LOCALE
@@ -326,16 +326,17 @@ IPDEF5("SHLVL", &shlvl, varinteger_gsu),
 IPDEF5("TRY_BLOCK_ERROR", &try_errflag, varinteger_gsu),
 
 #define IPDEF7(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
+#define IPDEF7U(A,B) {{NULL,A,PM_SCALAR|PM_SPECIAL|PM_UNSET},BR((void *)B),GSU(varscalar_gsu),0,0,NULL,NULL,NULL,0}
 IPDEF7("OPTARG", &zoptarg),
 IPDEF7("NULLCMD", &nullcmd),
-IPDEF7("POSTEDIT", &postedit),
+IPDEF7U("POSTEDIT", &postedit),
 IPDEF7("READNULLCMD", &readnullcmd),
 IPDEF7("PS1", &prompt),
-IPDEF7("RPS1", &rprompt),
-IPDEF7("RPROMPT", &rprompt),
+IPDEF7U("RPS1", &rprompt),
+IPDEF7U("RPROMPT", &rprompt),
 IPDEF7("PS2", &prompt2),
-IPDEF7("RPS2", &rprompt2),
-IPDEF7("RPROMPT2", &rprompt2),
+IPDEF7U("RPS2", &rprompt2),
+IPDEF7U("RPROMPT2", &rprompt2),
 IPDEF7("PS3", &prompt3),
 IPDEF7("PS4", &prompt4),
 IPDEF7("SPROMPT", &sprompt),


^ permalink raw reply	[relevance 3%]

* Re: It seems that I find a zle -F full CPU bug
  @ 2014-02-20 20:04  3%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-02-20 20:04 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, 20 Feb 2014 11:36:26 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> This is going to require more #ifdef's to examine fds[] in the poll() case
> and the bits in errfds in the select() case.

Yes, they're annoyingly different.  It's quite possible we don't
actually need select() --- certainly it will only be needed for some
pokey old non-POSIX thing.
 
> Aside:  Am I misreading the code, or is it the case that the (HAVE_TIO &&
> sun) #ifdef branch does not support zle -F ?

It should prefer poll or failing that select.  If we don't have any such feature
we can't support zle -F.

pws


^ permalink raw reply	[relevance 3%]

* Zsh does not follow POSIX when return is called during the action of a trap
@ 2014-03-12 15:36  8% Eduardo A. Bustamante López
  2014-03-12 16:52  9% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Eduardo A. Bustamante López @ 2014-03-12 15:36 UTC (permalink / raw)
  To: zsh-workers

Hi! I first reported this bug to bug-bash, but since it also applies
to zsh, I wanted you to know about it. I'll use the same report I
sent, since it's the same problem:



According to POSIX:

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

Source (EXIT STATUS section):
  
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#return


So, what I understand from this:

(1) When return is called without a numeric argument, the code
returned is that of the `last command'.

(2) The `last command' is defined as: ``[...] the command that
executed immediately preceding the trap action''.


Taking the SYNOPSIS for the trap builtin:

| trap n [condition...] 
| trap [action condition...]

and from DESCRIPTION:

| Each time trap is invoked, the action argument shall be processed in
| a manner equivalent to:
| 
| eval action

Source:
  http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap


So as I read it, `action' refers to the whole string.



Now, this means, taking the following pseudo-code:

|  trap '(exit BEFORE-RETURN); return' SIGNAL
|
|  fn() {
|    (exit BEFORE-ACTION); -block here waiting for signal-
|  }

If that script receives SIGNAL, it should return the BEFORE-ACTION
exit code, and not the BEFORE-RETURN exit code.



Testing this is a bit tricky, because there's no simple way of
blocking to wait for a signal in a way that it doesn't affect our
testing, so the bes I could come up with is this:


### begin test script
code='trap "(exit 2); return" USR1
f() {
    { echo; kill -USR1 $$; } | exit 3
    return 5
}

(exit 7); f
'

shells=(
    bash
    'bash --posix'
    ksh
    mksh
    dash
   'busybox sh'
    zsh
    jsh
)

for attempt in {1..1000}; do
    for shell in "address@hidden"; do
        printf '%s: %s\n' "$shell" "$($shell -c "$code"; echo $?)"
    done
done | sort | uniq -c
### end test script



And sample output from this script:

    969 bash: 2
     31 bash: 5
    979 bash --posix: 2
     21 bash --posix: 5
   1000 busybox sh: 5
    971 dash: 3
     29 dash: 5
    118 jsh: 3
    882 jsh: 5
      1 ksh: 0
    999 ksh: 3
    970 mksh: 3
     30 mksh: 5
      6 zsh: 2
    994 zsh: 3


Most of the time, zsh returns the correct code (3, BEFORE-ACTION),
but sometimes it returns 2, which is BEFORE-RETURN (and it should not).


The versions tested are:


bash --version|head -n1: 
  GNU bash, version 4.3.0(2)-release (x86_64-unknown-linux-gnu)
zsh --version|head -n1: 
  zsh 4.3.17 (x86_64-unknown-linux-gnu)
ksh --version|head -n1: 
    version         sh (AT&T Research) 93u+ 2012-02-29
mksh -c 'echo "$KSH_VERSION"': 
  @(#)MIRBSD KSH R40 2012/07/20 Debian-7
apt-cache policy dash|grep Installed: 
    Installed: 0.5.7-3
apt-cache policy busybox|grep Installed: 
    Installed: 1:1.20.0-7
head -n3 ~/local/src/heirloom-sh/CHANGES: 
  Release ...
* A bug in the supplied realloc() replacement could result in heap
  corruption. (No resulting failures have been observed with sh so far.)



Original bug report:
  http://lists.gnu.org/archive/html/bug-bash/2014-03/msg00053.html

-- 
Eduardo Alan Bustamante López


^ permalink raw reply	[relevance 8%]

* Re: Zsh does not follow POSIX when return is called during the action of a trap
  2014-03-12 15:36  8% Zsh does not follow POSIX when return is called during the action of a trap Eduardo A. Bustamante López
@ 2014-03-12 16:52  9% ` Bart Schaefer
  2014-03-12 17:03  5%   ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-03-12 16:52 UTC (permalink / raw)
  To: Eduardo A. Bustamante Lopez, zsh-workers

On Mar 12,  8:36am, Eduardo A. Bustamante Lopez wrote:
}
} Hi! I first reported this bug to bug-bash, but since it also applies
} to zsh, I wanted you to know about it.

Have you tried this with the POSIX_TRAPS option set?

Zsh does not in general conform to POSIX at all unless you run it with
the appropriate compatibility settings.


^ permalink raw reply	[relevance 9%]

* Re: Zsh does not follow POSIX when return is called during the action of a trap
  2014-03-12 16:52  9% ` Bart Schaefer
@ 2014-03-12 17:03  5%   ` Peter Stephenson
  2014-03-12 17:47  7%     ` Eduardo A. Bustamante López
  2014-03-12 17:49  5%     ` Chet Ramey
  0 siblings, 2 replies; 200+ results
From: Peter Stephenson @ 2014-03-12 17:03 UTC (permalink / raw)
  To: zsh-workers; +Cc: Eduardo A. Bustamante Lopez

On Wed, 12 Mar 2014 09:52:10 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Mar 12,  8:36am, Eduardo A. Bustamante Lopez wrote:
> }
> } Hi! I first reported this bug to bug-bash, but since it also applies
> } to zsh, I wanted you to know about it.
> 
> Have you tried this with the POSIX_TRAPS option set?
> 
> Zsh does not in general conform to POSIX at all unless you run it with
> the appropriate compatibility settings.

I was going to mention that.  I think it still needs some work --- which
I know how to do in this case.  N.B. you can test this with the line

[ x$ZSH_VERSION != x ] && emulate sh

at the top of the "code" variable.

However, I'm trying to work out what happens with the case

|  trap '(exit BEFORE-RETURN); return EXPLICIT-RETURN-VALUE' SIGNAL
|
|  fn() {
|    (exit BEFORE-ACTION); -block here waiting for signal-
|  }

Should this exit with EXPLICIT-RETURN_VALUE or BEFORE-ACTION?  The
latter is easier to implement but my guess (without ploughing through
the standard) is EXPLICIT-RETURN-VALUE is right here.

pws


^ permalink raw reply	[relevance 5%]

* Re: Zsh does not follow POSIX when return is called during the action of a trap
  2014-03-12 17:03  5%   ` Peter Stephenson
@ 2014-03-12 17:47  7%     ` Eduardo A. Bustamante López
  2014-03-12 17:49  5%     ` Chet Ramey
  1 sibling, 0 replies; 200+ results
From: Eduardo A. Bustamante López @ 2014-03-12 17:47 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Wed, Mar 12, 2014 at 05:03:09PM +0000, Peter Stephenson wrote:
> On Wed, 12 Mar 2014 09:52:10 -0700
> Bart Schaefer <schaefer@brasslantern.com> wrote:
> > Have you tried this with the POSIX_TRAPS option set?
> > 
> > Zsh does not in general conform to POSIX at all unless you run it with
> > the appropriate compatibility settings.
I see. Well, I now ran the code with 'emulate sh' (thanks Peter, for
the suggestion).

These are the results:

|      12 zsh: 2
|     988 zsh: 3
| zsh 5.0.5-dev-0 (x86_64-unknown-linux-gnu)

For this new code:

| code='
| emulate sh
| 
| trap "(exit 2); return" USR1
| f() {
|     { echo; kill -USR1 $$; } | exit 3
|     return 5
| }
| 
| (exit 7); f
| '
| 
| shells=(
|     zsh
| )
| 
| for attempt in {1..1000}; do
|     for shell in "${shells[@]}"; do
| 	printf '%s: %s\n' "$shell" "$($shell -c "$code"; echo $?)"
|     done
| done | sort | uniq -c
| 
| zsh --version



> However, I'm trying to work out what happens with the case
> 
> |  trap '(exit BEFORE-RETURN); return EXPLICIT-RETURN-VALUE' SIGNAL
> |
> |  fn() {
> |    (exit BEFORE-ACTION); -block here waiting for signal-
> |  }
> 
> Should this exit with EXPLICIT-RETURN_VALUE or BEFORE-ACTION?  The
> latter is easier to implement but my guess (without ploughing through
> the standard) is EXPLICIT-RETURN-VALUE is right here.
> 
> pws
> 
Ah, I see. I tested with this:

| code='
| emulate sh
| 
| trap "(exit 2); return 9" USR1
| f() {
|     { echo; kill -USR1 $$; } | exit 3
|     return 5
| }
| 
| (exit 7); f
| '
| 
| shells=(
|     zsh
| )
| 
| for attempt in {1..1000}; do
|     for shell in "${shells[@]}"; do
|   printf '%s: %s\n' "$shell" "$($shell -c "$code"; echo $?)"
|     done
| done | sort | uniq -c
| 
| zsh --version

And got:

|     991 zsh: 3
|       9 zsh: 9
| zsh 5.0.5-dev-0 (x86_64-unknown-linux-gnu)

Which is kind of wrong, since it should always be 9, but according to
the results, it's mostly 3. POSIX states:

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

So, the result should be 9 ("'?' shall be set to n [...] or the exit
status of the last command [...]"). Because in this case 'n' is set.

-- 
Eduardo Alan Bustamante López


^ permalink raw reply	[relevance 7%]

* Re: Zsh does not follow POSIX when return is called during the action of a trap
  2014-03-12 17:03  5%   ` Peter Stephenson
  2014-03-12 17:47  7%     ` Eduardo A. Bustamante López
@ 2014-03-12 17:49  5%     ` Chet Ramey
  2014-03-12 18:23 10%       ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Chet Ramey @ 2014-03-12 17:49 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers; +Cc: chet.ramey, Eduardo A. Bustamante Lopez

On 3/12/14 1:03 PM, Peter Stephenson wrote:

> However, I'm trying to work out what happens with the case
> 
> |  trap '(exit BEFORE-RETURN); return EXPLICIT-RETURN-VALUE' SIGNAL
> |
> |  fn() {
> |    (exit BEFORE-ACTION); -block here waiting for signal-
> |  }
> 
> Should this exit with EXPLICIT-RETURN_VALUE or BEFORE-ACTION?  The
> latter is easier to implement but my guess (without ploughing through
> the standard) is EXPLICIT-RETURN-VALUE is right here.

The correct exit value is EXPLICIT-RETURN-VALUE.

The standards text that Eduardo quoted only applies to the case where
`return' is not given an argument.

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


^ permalink raw reply	[relevance 5%]

* Re: Zsh does not follow POSIX when return is called during the action of a trap
  2014-03-12 17:49  5%     ` Chet Ramey
@ 2014-03-12 18:23 10%       ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-03-12 18:23 UTC (permalink / raw)
  To: zsh-workers; +Cc: Eduardo A. Bustamante Lopez

On Wed, 12 Mar 2014 13:49:18 -0400
Chet Ramey <chet.ramey@case.edu> wrote:
> On 3/12/14 1:03 PM, Peter Stephenson wrote:
> 
> > However, I'm trying to work out what happens with the case
> > 
> > |  trap '(exit BEFORE-RETURN); return EXPLICIT-RETURN-VALUE' SIGNAL
> > |
> > |  fn() {
> > |    (exit BEFORE-ACTION); -block here waiting for signal-
> > |  }
> > 
> > Should this exit with EXPLICIT-RETURN_VALUE or BEFORE-ACTION?  The
> > latter is easier to implement but my guess (without ploughing through
> > the standard) is EXPLICIT-RETURN-VALUE is right here.
> 
> The correct exit value is EXPLICIT-RETURN-VALUE.

OK, so I think the answer is as follows...  I'm out of time, I'll give
it a check with explicit return values tomorrow.

I'll also add some additional documentation for POSIX_TRAPS.

diff --git a/Src/builtin.c b/Src/builtin.c
index 9bcbcf7..0419c39 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -4688,9 +4688,10 @@ exit_pending;
 int
 bin_break(char *name, char **argv, UNUSED(Options ops), int func)
 {
-    int num = lastval, nump = 0;
+    int num = lastval, nump = 0, implicit;
 
     /* handle one optional numeric argument */
+    implicit = !*argv;
     if (*argv) {
 	num = mathevali(*argv++);
 	nump = 1;
@@ -4721,7 +4722,12 @@ bin_break(char *name, char **argv, UNUSED(Options ops), int func)
 	    retflag = 1;
 	    breaks = loops;
 	    lastval = num;
-	    if (trap_state == TRAP_STATE_PRIMED && trap_return == -2) {
+	    if (trap_state == TRAP_STATE_PRIMED && trap_return == -2 &&
+		/*
+		 * With POSIX, "return" on its own in a trap doesn't
+		 * update $? --- we keep the status from before the trap.
+		 */
+		!(isset(POSIXTRAPS) && implicit)) {
 		trap_state = TRAP_STATE_FORCE_RETURN;
 		trap_return = lastval;
 	    }
diff --git a/Src/signals.c b/Src/signals.c
index c8f5fbc..a6eb803 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -1155,6 +1155,7 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
     char *name, num[4];
     int obreaks = breaks;
     int oretflag = retflag;
+    int olastval = lastval;
     int isfunc;
     int traperr, new_trap_state, new_trap_return;
 
@@ -1261,6 +1262,13 @@ dotrapargs(int sig, int *sigtr, void *sigfn)
     } else {
 	if (traperr && !EMULATION(EMULATE_SH))
 	    lastval = 1;
+	else {
+	    /*
+	     * With no explicit forced return, we keep the
+	     * lastval from before the trap ran.
+	     */
+	    lastval = olastval;
+	}
 	if (try_tryflag)
 	    errflag = traperr;
 	breaks += obreaks;

pws


^ permalink raw reply	[relevance 10%]

* [PATCH] A few cleanups in manpages
@ 2014-03-17 15:01  7% Jun T.
  0 siblings, 0 replies; 200+ results
From: Jun T. @ 2014-03-17 15:01 UTC (permalink / raw)
  To: zsh-workers

Remove extra ')' in contrib.yo, and a few cleanups
in mod_{pcre,regex,sched}.yo.
---
 Doc/Zsh/contrib.yo   | 2 +-
 Doc/Zsh/mod_pcre.yo  | 1 +
 Doc/Zsh/mod_regex.yo | 1 +
 Doc/Zsh/mod_sched.yo | 2 +-
 4 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo
index 11d596d..c446471 100644
--- a/Doc/Zsh/contrib.yo
+++ b/Doc/Zsh/contrib.yo
@@ -2904,7 +2904,7 @@ file name is matched against the pattern, regardless of how the file
 was passed to the handler.  The file is resolved to a full path using
 the tt(:A) modifier described in
 ifzman(the subsection Modifers in zmanref(zshexpn))\
-ifnzman(noderef(Modifiers)));
+ifnzman(noderef(Modifiers));
 this means that symbolic links are resolved where possible, so that
 links into other file systems behave in the correct fashion.
 )
diff --git a/Doc/Zsh/mod_pcre.yo b/Doc/Zsh/mod_pcre.yo
index 9b8d9d6..6ab5a19 100644
--- a/Doc/Zsh/mod_pcre.yo
+++ b/Doc/Zsh/mod_pcre.yo
@@ -72,6 +72,7 @@ print -l $accum
 enditem()
 
 The tt(zsh/pcre) module makes available the following test condition:
+
 startitem()
 findex(pcre-match)
 item(expr tt(-pcre-match) pcre)(
diff --git a/Doc/Zsh/mod_regex.yo b/Doc/Zsh/mod_regex.yo
index 4081810..f204516 100644
--- a/Doc/Zsh/mod_regex.yo
+++ b/Doc/Zsh/mod_regex.yo
@@ -4,6 +4,7 @@ Interface to the POSIX regex library.
 cindex(regular expressions)
 cindex(regex)
 The tt(zsh/regex) module makes available the following test condition:
+
 startitem()
 findex(regex-match)
 item(var(expr) tt(-regex-match) var(regex))(
diff --git a/Doc/Zsh/mod_sched.yo b/Doc/Zsh/mod_sched.yo
index 948001b..2d8d77c 100644
--- a/Doc/Zsh/mod_sched.yo
+++ b/Doc/Zsh/mod_sched.yo
@@ -48,7 +48,7 @@ enditem()
 
 startitem()
 vindex(zsh_scheduled_events)
-item(zsh_scheduled_events)(
+item(tt(zsh_scheduled_events))(
 A readonly array corresponding to the events scheduled by the
 tt(sched) builtin.  The indices of the array correspond to the numbers
 shown when tt(sched) is run with no arguments (provided that the
-- 
1.8.3.4 (Apple Git-47)



^ permalink raw reply	[relevance 7%]

* Re: LOGNAME not properly set on FreeBSD
  @ 2014-04-02 20:54  3%     ` Phil Pennock
  2014-04-02 21:11  0%       ` Erik Johnson
  0 siblings, 1 reply; 200+ results
From: Phil Pennock @ 2014-04-02 20:54 UTC (permalink / raw)
  To: Erik Johnson; +Cc: zsh-workers

On 2014-04-01 at 19:50 -0500, Erik Johnson wrote:
> The whole point of "su -" (and "su -l", which are equivalent), is to
> make the session a login session.

Then it's su's responsibility to clear/reset/set environment variables
associated with the login.

In fact, SUSv4 is pretty clear on this:
----------------------------8< cut here >8------------------------------
LOGNAME
  The system shall initialize this variable at the time of login to be
  the user's login name. See <pwd.h> . For a value of LOGNAME to be
  portable across implementations of POSIX.1-2008, the value should be
  composed of characters from the portable filename character set.
----------------------------8< cut here >8------------------------------

Note "at the time of login".  The fact that zsh will fix up a _missing_
LOGNAME variable is a shell convenience, for a broken system which
didn't do what it should have done at login time.

So either su is leaving LOGNAME set across the security boundary, or
libc's getlogin() continues to report the old value after the su.

In another sub-thread, you perform a bunch of tests with python2's
getpass.getuser() function, but please note that this function
preferentially uses environment variables and doesn't report which
variable it sourced from, so is problematic for tracing the source of a
problem.  That function will try, in turn: LOGNAME USER LNAME USERNAME;
after that, it uses a passwd lookup of the current uid, _not_
getlogin().  Thus the evidence purporting to show that it "just works"
in other shells isn't actually showing that.

Running >> env - bash --login << I see that I have a login shell and
that LOGNAME is not set, thus bash is not performing any such fixup and
if you see correct values in your tests, what you're seeing is likely
Python's getpass.getuser() reaching the pwd.getpwuid(os.getuid())[0]
step.

So yes, in such a scenario you'll get a different result from zsh which
fixes up the missing LOGNAME from the libc getlogin(), thus returns
whatever the OS's concept of "the user's login name" is.

-Phil


^ permalink raw reply	[relevance 3%]

* Re: LOGNAME not properly set on FreeBSD
  @ 2014-04-02 20:58  4%     ` Peter Stephenson
  2014-04-02 21:14  0%       ` Erik Johnson
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-04-02 20:58 UTC (permalink / raw)
  To: Erik Johnson, zsh-workers

On Wed, 2 Apr 2014 14:06:21 -0500
Erik Johnson <palehose@gmail.com> wrote:
> Python os.getlogin() does indeed show "erik" instead of "root". So this
> may just be a difference between glibc and BSD libc. Either way, it
> "just works" in bash, sh, csh, tcsh, and ksh, as can be seen below, so
> I believe there is an argument for making it work properly in FreeBSD as
> well, or at the very least adding some wording to the zshparam manpage
> which makes this difference in behavior clear.

Hmm...  to me, having LOGNAME *not* report the same as getlogin() is
"just not working".  Presumably there's some reason why getlogin() does
what it does and it doesn't seem to me to be the shell's job to second
guess system calls.  POSIX seems to agree with me --- to be fair, this
isn't for the variable, it's for the command "logname", but it would be
confusing if they were different.

  The logname utility shall write the user's login name to standard
  output. The login name shall be the string that would be returned by
  the getlogin() function defined in the System Interfaces volume of
  POSIX.1-2008. Under the conditions where the getlogin() function would
  fail, the logname utility shall write a diagnostic message to standard
  error and exit with a non-zero exit status.

However, there may be some documented prior art for LOGNAME that I'm
missing --- the history of shell development isn't necessarily particularly
rational.

It certainly makes sense to document it in any case.

diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index cf2ad34..8d95355 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -621,7 +621,9 @@ item(tt(LOGNAME))(
 If the corresponding variable is not set in the environment of the
 shell, it is initialized to the login name corresponding to the
 current login session. This parameter is exported by default but
-this can be disabled using the tt(typeset) builtin.
+this can be disabled using the tt(typeset) builtin.  The value
+is set to the string returned by the manref(getlogin)(3) system call
+if that is available.
 )
 vindex(MACHTYPE)
 item(tt(MACHTYPE))(


-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[relevance 4%]

* Re: LOGNAME not properly set on FreeBSD
  2014-04-02 20:54  3%     ` Phil Pennock
@ 2014-04-02 21:11  0%       ` Erik Johnson
  0 siblings, 0 replies; 200+ results
From: Erik Johnson @ 2014-04-02 21:11 UTC (permalink / raw)
  To: zsh-workers

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

On Wed, Apr 02, 2014 at 04:54:13PM -0400, Phil Pennock wrote:
>On 2014-04-01 at 19:50 -0500, Erik Johnson wrote:
>> The whole point of "su -" (and "su -l", which are equivalent), is to
>> make the session a login session.
>
>Then it's su's responsibility to clear/reset/set environment variables
>associated with the login.
>
>In fact, SUSv4 is pretty clear on this:
>----------------------------8< cut here >8------------------------------
>LOGNAME
>  The system shall initialize this variable at the time of login to be
>  the user's login name. See <pwd.h> . For a value of LOGNAME to be
>  portable across implementations of POSIX.1-2008, the value should be
>  composed of characters from the portable filename character set.
>----------------------------8< cut here >8------------------------------
>
>Note "at the time of login".  The fact that zsh will fix up a _missing_
>LOGNAME variable is a shell convenience, for a broken system which
>didn't do what it should have done at login time.
>
>So either su is leaving LOGNAME set across the security boundary, or
>libc's getlogin() continues to report the old value after the su.
>
>In another sub-thread, you perform a bunch of tests with python2's
>getpass.getuser() function, but please note that this function
>preferentially uses environment variables and doesn't report which
>variable it sourced from, so is problematic for tracing the source of a
>problem.  That function will try, in turn: LOGNAME USER LNAME USERNAME;
>after that, it uses a passwd lookup of the current uid, _not_
>getlogin().  Thus the evidence purporting to show that it "just works"
>in other shells isn't actually showing that.
>
>Running >> env - bash --login << I see that I have a login shell and
>that LOGNAME is not set, thus bash is not performing any such fixup and
>if you see correct values in your tests, what you're seeing is likely
>Python's getpass.getuser() reaching the pwd.getpwuid(os.getuid())[0]
>step.
>

Good point:

erik@virtubsd:~% sudo chpass -s /bin/csh root
Password:
chpass: user information updated
erik@virtubsd:~%  su -
Password:
virtubsd# echo $LOGNAME
root
virtubsd# logout
erik@virtubsd:~% sudo chpass -s /bin/tcsh root
chpass: user information updated
erik@virtubsd:~% su -
Password:
virtubsd# echo $LOGNAME
root
virtubsd# logout
erik@virtubsd:~% sudo chpass -s /usr/local/bin/bash root
chpass: user information updated
erik@virtubsd:~% su -
Password:
[root@virtubsd ~]# echo $LOGNAME

[root@virtubsd ~]# logout
erik@virtubsd:~% sudo chpass -s /usr/local/bin/ksh93 root
chpass: user information updated
erik@virtubsd:~% su -
Password:
# echo $LOGNAME

# ^D
erik@virtubsd:~% sudo chpass -s /usr/local/bin/zsh root
chpass: user information updated
erik@virtubsd:~% su -
Password:
virtubsd# echo $LOGNAME
erik
virtubsd#

>So yes, in such a scenario you'll get a different result from zsh which
>fixes up the missing LOGNAME from the libc getlogin(), thus returns
>whatever the OS's concept of "the user's login name" is.
>
>-Phil

-- 

-Erik

"For me, it is far better to grasp the universe as it really is than to
persist in delusion, however satisfying and reassuring."  --Carl Sagan


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

^ permalink raw reply	[relevance 0%]

* Re: LOGNAME not properly set on FreeBSD
  2014-04-02 20:58  4%     ` Peter Stephenson
@ 2014-04-02 21:14  0%       ` Erik Johnson
  0 siblings, 0 replies; 200+ results
From: Erik Johnson @ 2014-04-02 21:14 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

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

On Wed, Apr 02, 2014 at 09:58:54PM +0100, Peter Stephenson wrote:
>On Wed, 2 Apr 2014 14:06:21 -0500
>Erik Johnson <palehose@gmail.com> wrote:
>> Python os.getlogin() does indeed show "erik" instead of "root". So this
>> may just be a difference between glibc and BSD libc. Either way, it
>> "just works" in bash, sh, csh, tcsh, and ksh, as can be seen below, so
>> I believe there is an argument for making it work properly in FreeBSD as
>> well, or at the very least adding some wording to the zshparam manpage
>> which makes this difference in behavior clear.
>
>Hmm...  to me, having LOGNAME *not* report the same as getlogin() is
>"just not working".  Presumably there's some reason why getlogin() does
>what it does and it doesn't seem to me to be the shell's job to second
>guess system calls.  POSIX seems to agree with me --- to be fair, this
>isn't for the variable, it's for the command "logname", but it would be
>confusing if they were different.
>
>  The logname utility shall write the user's login name to standard
>  output. The login name shall be the string that would be returned by
>  the getlogin() function defined in the System Interfaces volume of
>  POSIX.1-2008. Under the conditions where the getlogin() function would
>  fail, the logname utility shall write a diagnostic message to standard
>  error and exit with a non-zero exit status.
>
>However, there may be some documented prior art for LOGNAME that I'm
>missing --- the history of shell development isn't necessarily particularly
>rational.
>
>It certainly makes sense to document it in any case.
>

Yeah, and for what it's worth it seems that not all of the shells are
exporting LOGNAME. But the ones that do are apparently doing so
differently than zsh does it. So, documentation is probably the best
route to go here. Thanks!


-- 

-Erik

"For me, it is far better to grasp the universe as it really is than to
persist in delusion, however satisfying and reassuring."  --Carl Sagan


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

^ permalink raw reply	[relevance 0%]

* Parser issues and and [[ $var ]]
       [not found]                       ` <slrnlln1bj.a9l.martin@epidot.math.uni-rostock.de>
@ 2014-04-26 20:30  3%                     ` Bart Schaefer
  2014-05-10 21:09  2%                       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-04-26 20:30 UTC (permalink / raw)
  To: zsh-workers

On Apr 26, 10:07am, Martin Vaeth wrote:
}
} BTW: "emulate -L bash" would be useful to read some distribution's
} or user's bash setup files. Main difference to emulate -L sh would be
}   setopt ksh_glob no_sh_glob brace_expand
} and that [[ $var ]] is treated equivalent to [[ -n $var ]]:
} I experienced that the latter is the main issue with bash compatibility
} (besides shopt and PS1, of course, which are not reasonable to emulate).

Hmm.  Looks like both bash and ksh93 accept [[ $foo ]] as valid syntax.
This turns out to be surprisingly difficult to fix, and poking at it,
I think we may have broken some things in parse.c.

For example, [ -t ] is supposed to be equivalent to [ -t 1 ] and there
is code late in par_cond_2() that handles this, but that code is never
reached because the /* POSIX 1003.2 */ code at the top of par_cond_2()
preemptively turns it into [ -n -t ].

The same unreached code for [ -t ] also tries to handle [ $var ] but is
not usable for [[ $var ]] because of the different lexing conventions
for "test"/"[" vs. [[ ... ]].  Also [[ -t ]] is NOT supposed to behave
like either of [[ -t 1 ]] or [[ -n -t ]], so that part of the code in
question must be avoided.

Also, if you compare the later code to the earlier code, sometimes we
call dupstring() on the first argument to par_cond_double() and other
times we do not.  Either we don't need dupstring(), or not using it is
a bug waiting to happen.

So it looks like par_cond_2() needs some more overhauling.


^ permalink raw reply	[relevance 3%]

* Re: Parser issues and and [[ $var ]]
  2014-04-26 20:30  3%                     ` Parser issues and and [[ $var ]] Bart Schaefer
@ 2014-05-10 21:09  2%                       ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-05-10 21:09 UTC (permalink / raw)
  To: zsh-workers

Looking at this a bit further ...

On Apr 26,  1:30pm, Bart Schaefer wrote:
} Subject: Parser issues and and [[ $var ]]
}
} Hmm.  Looks like both bash and ksh93 accept [[ $foo ]] as valid syntax.
} This turns out to be surprisingly difficult to fix, and poking at it,
} I think we may have broken some things in parse.c.
} 
} For example, [ -t ] is supposed to be equivalent to [ -t 1 ] and there
} is code late in par_cond_2() that handles this, but that code is never
} reached because the /* POSIX 1003.2 */ code at the top of par_cond_2()
} preemptively turns it into [ -n -t ].

Further prodding seems to indicate that bash and ksh disagree on this
point.  [ -t ] in bash (and in the "test" external command) is treated
like [ "-t" ], so

    [ -t ] >/dev/null

is true in bash3.2 but false in ksh93 (including builtin test).  As far
as I can tell, this is the only operator that behaves this way, both
bash and ksh treat all other binary operators as strings when they
have no argument.

Zsh has traditionally had the ksh behavior here, though as noted this
was probably unintentionally changed a couple of revisions ago.

Ksh93 has one other interesting feature that I wasn't able to make work
in zsh:

    ksh$ [ -t ] >/dev/null || print tested FD 1 not a terminal
    tested FD 1 not a terminal

    ksh$ x=t
    ksh$ [ -$x ] >/dev/null && print tested as a string
    tested as a string

So it appears ksh is tokenizing the arguments of "[" (and builtin test),
whereas zsh will expand $x first in that case.  This is similar to ksh
treating "typeset" as special in command position.

} The same unreached code for [ -t ] also tries to handle [ $var ] but is
} not usable for [[ $var ]] because of the different lexing conventions
} for "test"/"[" vs. [[ ... ]].  Also [[ -t ]] is NOT supposed to behave
} like either of [[ -t 1 ]] or [[ -n -t ]], so that part of the code in
} question must be avoided.

That code turns out to be reachable after all if the expression is more
complex than just [ -a ], e.g. [ -a -a -a ].  This plus examination of
ecadd() leads me to belive that ...

} Also, if you compare the later code to the earlier code, sometimes we
} call dupstring() on the first argument to par_cond_double() and other
} times we do not.  Either we don't need dupstring(), or not using it is
} a bug waiting to happen.

... calling dupstring() on literals before passing to par_cond_double()
is the right thing to do.

I think the following produces syntax errors in all the places it should
and works in the rest of the cases, but I have not yet tested it with
new conditionals added by modules -- e.g., the recomputation of dble
for s2 (last hunk) may need knowledge of added conditions.  So I won't
commit until others have a chance to play with this.


diff --git a/Src/parse.c b/Src/parse.c
index 530a070..6ea997d 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2068,6 +2068,9 @@ par_cond_2(void)
 	    /* one argument: [ foo ] is equivalent to [ -n foo ] */
 	    s1 = tokstr;
 	    condlex();
+	    /* ksh behavior: [ -t ] means [ -t 1 ]; bash disagrees */
+	    if (unset(POSIXBUILTINS) && !strcmp(s1, "-t"))
+		return par_cond_double(s1, dupstring("1"));
 	    return par_cond_double(dupstring("-n"), s1);
 	}
 	if (testargs[1]) {
@@ -2086,6 +2089,9 @@ par_cond_2(void)
 		return par_cond_triple(s1, s2, s3);
 	    }
 	}
+	/*
+	 * We may fall through here in oddball cases like [ = -a ! ]
+	 */
     }
     if (tok == BANG) {
 	/*
@@ -2114,18 +2120,17 @@ par_cond_2(void)
 	condlex();
 	return r;
     }
+    if ((s1 = tokstr) != 0)
+	dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1
+		&& !s1[2]);
     if (tok != STRING) {
-	if (tok && tok != LEXERR && condlex == testlex) {
-	    s1 = tokstr;
+	/* Check first argument for [[ string ]] re-interpretation */
+	if (tokstr && tok != LEXERR && (!dble || condlex == testlex)) {
 	    condlex();
-	    return par_cond_double("-n", s1);
+	    return par_cond_double(dupstring("-n"), s1);
 	} else
 	    YYERROR(ecused);
     }
-    s1 = tokstr;
-    if (condlex == testlex)
-	dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1
-		  && !s1[2]);
     condlex();
     if (tok == INANG || tok == OUTANG) {
 	enum lextok xtok = tok;
@@ -2140,15 +2145,19 @@ par_cond_2(void)
 	return 1;
     }
     if (tok != STRING) {
-	if (tok != LEXERR && condlex == testlex) {
-	    if (!dble)
-		return par_cond_double("-n", s1);
-	    else if (!strcmp(s1, "-t"))
-		return par_cond_double(s1, "1");
+	/*
+	 * Check second argument in case semantics e.g. [ = -a = ]
+	 * mean we have to go back and fix up the first one
+	 */
+	if (tok != LEXERR) {
+	    if (!dble || condlex == testlex)
+		return par_cond_double(dupstring("-n"), s1);
 	} else
 	    YYERROR(ecused);
     }
-    s2 = tokstr;
+    if ((s2 = tokstr) != 0 && condlex != testlex)
+	dble = (*s2 == '-' && strspn(s2+1, "abcdefghknoprstuwxzLONGS") == 1
+		&& !s2[2]);
     incond++;			/* parentheses do globbing */
     condlex();
     incond--;			/* parentheses do grouping */


^ permalink raw reply	[relevance 2%]

* 'emulate sh -c' and $0
@ 2014-05-29 23:04  3% Richard Hansen
  2014-05-30  3:45  3% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Richard Hansen @ 2014-05-29 23:04 UTC (permalink / raw)
  To: zsh-workers

Hi all,

I just encountered what I think is a bug in Zsh 5.0.5.  The following
command:

    zsh -c '
        emulate sh -c "echo \"\$0\""
        bar() { emulate sh -c "echo \"\$0\""; }
        bar
    ' foo arg1

produces the following output:

    foo
    bar

I expected it to produce:

    foo
    foo

This is relevant when sourcing a file containing (POSIX) sh code that
might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after
exporting/unsetting environment variables).

Perhaps Zsh should save the original value of $0 somewhere and restore
it when entering sh emulation mode.

Thanks,
Richard


^ permalink raw reply	[relevance 3%]

* Re: 'emulate sh -c' and $0
  2014-05-29 23:04  3% 'emulate sh -c' and $0 Richard Hansen
@ 2014-05-30  3:45  3% ` Bart Schaefer
  2014-05-30  8:49  3%   ` Richard Hansen
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-05-30  3:45 UTC (permalink / raw)
  To: zsh-workers

On May 29,  7:04pm, Richard Hansen wrote:
}
} I just encountered what I think is a bug in Zsh 5.0.5.

To the extent that it's working exactly as documented, it's not a bug ...

}     zsh -c '
}         emulate sh -c "echo \"\$0\""
}         bar() { emulate sh -c "echo \"\$0\""; }
}         bar
}     ' foo arg1
} 
} I expected it to produce:
} 
}     foo
}     foo

If you throw in "unsetopt functionargzero" any time before calling "bar" 
then it does produce that output.

If you rewrite your example as

    zsh -c '
        emulate sh -c "echo \"\$0\""
        emulate sh -c "bar() { echo \"\$0\"; }"
        bar
    ' foo arg1

then it also produces your expected output; you just need to define the
function in the right scope.

} This is relevant when sourcing a file containing (POSIX) sh code that
} might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after
} exporting/unsetting environment variables).
} 
} Perhaps Zsh should save the original value of $0 somewhere and restore
} it when entering sh emulation mode.

I don't find those examples particularly compelling, but the original
value of $0 is already stashed; what would need to change is that the
*local* value of $0 gets temporarily replaced by the global one.  (The
[un]setting of functionargzero controls whether a local value is ever
created in the first place.)


^ permalink raw reply	[relevance 3%]

* Re: 'emulate sh -c' and $0
  2014-05-30  3:45  3% ` Bart Schaefer
@ 2014-05-30  8:49  3%   ` Richard Hansen
    0 siblings, 1 reply; 200+ results
From: Richard Hansen @ 2014-05-30  8:49 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

(please cc me in replies as I am not subscribed to the list)

On 2014-05-29 23:45, Bart Schaefer wrote:
> On May 29,  7:04pm, Richard Hansen wrote:
>>
>> I just encountered what I think is a bug in Zsh 5.0.5.
> 
> To the extent that it's working exactly as documented, it's not a bug ...

Would you mind pointing me to where this specific behavior is
documented?  It was non-obvious to me when I was digging around.

(I am aware of the documentation for the FUNCTION_ARGZERO option.  I'm
more interested in what it really means to be running in sh emulation
mode, as that's where I think the bug is.)

>>     zsh -c '
>>         emulate sh -c "echo \"\$0\""
>>         bar() { emulate sh -c "echo \"\$0\""; }
>>         bar
>>     ' foo arg1
>> 
>> I expected it to produce:
>> 
>>     foo
>>     foo
> 
> If you throw in "unsetopt functionargzero" any time before calling "bar" 
> then it does produce that output.
> 
> If you rewrite your example as
> 
>     zsh -c '
>         emulate sh -c "echo \"\$0\""
>         emulate sh -c "bar() { echo \"\$0\"; }"
>         bar
>     ' foo arg1
> 
> then it also produces your expected output; you just need to define the
> function in the right scope.

It is not always possible to unset that option in a meaningful way --
the code that sources the file with POSIX shell code may itself be in a
file that has been sourced.  By that time, $0 has already been
overridden.  Moving the unsetopt up another level may not be
desirable/feasible.

For example:

cat <<\EOF >foo.zsh
# zsh-specific code goes here
unsetopt FUNCTION_ARGZERO
. ./bar.sh
# zsh-specific code goes here
EOF
cat <<\EOF >bar.sh
printf %s\\n "$0"
EOF
zsh -c '. ./foo.zsh' baz

>> This is relevant when sourcing a file containing (POSIX) sh code that
>> might examine $0 (e.g., for logging or to 'exec "$0" "$@"' after
>> exporting/unsetting environment variables).
>> 
>> Perhaps Zsh should save the original value of $0 somewhere and restore
>> it when entering sh emulation mode.
> 
> I don't find those examples particularly compelling,

Here's the real-world problem that motivated my bug report; perhaps it
is a more compelling example (or perhaps you'll think of a better way to
solve the problem I was addressing):

http://article.gmane.org/gmane.comp.version-control.git/250409

> but the original
> value of $0 is already stashed; what would need to change is that the
> *local* value of $0 gets temporarily replaced by the global one.

That's good news; that should make it easier to write a patch that
temporarily replaces the local value with the global value.

Would you (or anyone else in the community) be opposed to such a patch?
 If not, can you point me to the relevant bits of code to help me get
started?

Thanks,
Richard


^ permalink raw reply	[relevance 3%]

* Re: 'emulate sh -c' and $0
  @ 2014-05-30 21:14  4%       ` Richard Hansen
  2014-05-31  5:13  2%         ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Richard Hansen @ 2014-05-30 21:14 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

On 2014-05-30 13:00, Bart Schaefer wrote:
> Finally the entry for the emulate builtin says:
> 
>      With single argument set up zsh options to emulate the specified
>      shell as much as possible.  `csh' will never be fully emulated.
>      If the argument is not one of the shells listed above, zsh will be
>      used as a default; more precisely, the tests performed on the
>      argument are the same as those used to determine the emulation at
>      startup based on the shell name, see Compatibility.

Thanks for the documentation references.  I had read "to emulate the
specified shell as much as possible" without paying enough attention to
the qualifying "set up zsh options".  So you are right:  The
documentation says that emulate only toggles options, and the behavior
of $0 with FUNCTION_ARGZERO is clear, so there's no reason to expect Zsh
to reset $0 to the original $0 when in sh emulation mode.

That being said, I still think there's value in changing Zsh's behavior.

> 
>> (I am aware of the documentation for the FUNCTION_ARGZERO option.  I'm
>> more interested in what it really means to be running in sh emulation
>> mode, as that's where I think the bug is.)
> 
> In general, emulation is at its most complete if and only if the shell
> is actually started as an emulator (e.g., the path name to the shell
> binary itself is not zsh, or ARGV0 is set in the environment).  The
> "emulate" builtin only changes setopts to the closest possible.

Would it add too much complexity to the code or documentation if the
emulate builtin did more than just toggle options (specifically:
temporarily change the binding of $0 to the original value)?

Perhaps the behavior of FUNCTION_ARGZERO could be altered so that $0
expands as follows:

    If option FUNCTION_ARGZERO is enabled and $0 is expanded inside the
    body of a function, $0 expands to the name of the enclosing
    function.

    Otherwise, if option FUNCTION_ARGZERO is enabled and $0 is expanded
    inside a sourced file, $0 expands to the pathname given to the
    'source' or '.' builtin command.

    Otherwise, if the shell was invoked with an argument naming a
    script containing shell commands to be executed, $0 expands to the
    value of that argument.

    Otherwise, if the shell was invoked with the '-c' flag and at least
    one non-option non-flag argument was given, $0 expands to the value
    of the first non-option non-flag argument.

    Otherwise, $0 expands to the value of the first argument passed to
    zsh from its parent (argv[0] in C).

This modification would make it possible to toggle the setting back and
forth to examine the local or original value as desired, even within the
same function.  I wouldn't expect this change to break many scripts, but
maybe any backward incompatibility is unacceptable.

>>> I don't find those examples particularly compelling,
>> 
>> Here's the real-world problem that motivated my bug report; perhaps it
>> is a more compelling example (or perhaps you'll think of a better way to
>> solve the problem I was addressing):
>> 
>> http://article.gmane.org/gmane.comp.version-control.git/250409
> 
> Instead of "compelling" I perhaps should have said "likely to come up
> in common usage."  You have a fairly rare special case there.

Good point.  :)

> In that example,
> 
>     ARGV0=sh exec zsh "$0" "$@"
> 
> might do what you want, but I'm not entirely following from the diff
> context what's intended.

Some more context if you're curious:  The Git distribution comes with
t/test-lib.sh, a file containing POSIX shell code implementing common
test infrastructure (print error messages, declare and run test cases,
etc.).  The test scripts are POSIX shell scripts that source this shared
file, with two exceptions:

  * t/t9903-bash-prompt.sh starts off running under /bin/sh, but it
    does the following early on:

        exec bash "$0" "$@"

    so that it can run and test Bash-specific shell code.  After
    reinvoking itself under Bash, the code sources test-lib.sh in order
    to reuse the shared test infrastructure code.  (The code in
    test-lib.sh is interpreted as Bash code, not POSIX shell code, but
    that doesn't really matter because the code is compatible with both
    shells.)

  * t/t9904-zsh-prompt.sh (new in that linked patch series) is similar
    to t9903, except it restarts itself under Zsh instead of Bash.
    Like t9903, it sources test-lib.sh, but because the code in
    test-lib.sh is incompatible with Zsh, it uses Zsh's sh emulation to
    source test-lib.sh.

The point of these two test scripts is to run Bash and Zsh in their
native modes as much as possible -- emulation is explicitly avoided
except as necessary to run the shared test infrastructure.

So 'ARGV0=sh exec zsh "$0" "$@"' doesn't work for two reasons:

  * at the time that line is executed, the script is being interpreted
    by /bin/sh and not Zsh, so the ARGV0 assignment won't have the
    desired effect

  * we want as little as possible to run in sh emulation mode so that
    we can test Zsh-specific code

>  
>>> but the original
>>> value of $0 is already stashed; what would need to change is that the
>>> *local* value of $0 gets temporarily replaced by the global one.
>> 
>> That's good news; that should make it easier to write a patch that
>> temporarily replaces the local value with the global value.
> 
> Unfortunately the way the local value is implemented is usually to use
> C local variable scoping to stash and restore the contents of a C global
> pointer, so this would mean at least one additional C global.
> 
>> Would you (or anyone else in the community) be opposed to such a patch?
> 
> The use cases in both directions seem pretty unusual to me.  Losing the
> ability to "localize" $0 for scripts feels almost as likely to create
> questions as does your situation.

I'm not sure what you mean by losing the ability to localize $0.

I see a few OK options:

  * Option #1:
    1. Add a new global variable 'orig_argzero' to hold the original
       value of $0.  This variable is never modified once set.
    2. The existing global variable 'argzero' continues to serve its
       current role of holding the "localized" value of $0 (it is
       updated when executing functions or sourcing files if
       FUNCTION_ARGZERO is enabled).
    3. When 'emulate sh' starts, temporarily set argzero to
       orig_argzero.  Restore argzero when 'emulate sh' returns.

This would result in behavior that is identical to the current behavior
except $0 would match the POSIX spec when in sh emulation mode (and only
in sh emulation mode).

  * Option #2:
    1. Add a new global variable 'orig_argzero' to hold the original
       value of $0.  This variable is never modified once set.
    2. The existing global variable 'argzero' continues to serve its
       current role of holding the "localized" value of $0 (it is
       updated when executing functions or sourcing files if
       FUNCTION_ARGZERO is enabled).
    3. Add a new option; let's call it LOCALIZE_ARGZERO for now.  If
       LOCALIZE_ARGZERO is enabled, use argzero to expand $0.  If
       LOCALIZE_ARGZERO is disabled, use orig_argzero to expand $0.
    4. Enable LOCALIZE_ARGZERO by default, but disable it in sh
       emulation mode.
    5. Stop disabling FUNCTION_ARGZERO by default in sh emulation mode.

  * Option #3:
    1. Add a new global variable 'orig_argzero' to hold the original
       value of $0.  This variable is never modified once set.
    2. Whenever a function is called or a file sourced, update the
       global variable holding the "localized" $0 ('argzero'), even if
       FUNCTION_ARGZERO is disabled.
    3. Modify the expansion rules for $0 as follows:  If
       FUNCTION_ARGZERO is enabled, use argzero to expand $0.  If
       FUNCTION_ARGZERO is disabled, use orig_argzero to expand $0.

Pros and cons:

Option #1 is simplest to implement, simple for users, and (mostly)
backward compatible, but less powerful than options #2 and #3 and
'emulate' no longer just sets options.

Option #2 is complex but powerful (scripts can read both the original $0
and the localized $0 in the same chunk of code) and (mostly) backward
compatible.  Note that option #1 can be used as a stepping stone to
option #2.

Option #3 is simple for users but not backward compatible.

I think my preference is to go with option #1 with a possible future
step to option #2 (at which time FUNCTION_ARGZERO can be deprecated in
favor of LOCALIZE_ARGZERO).

> I suppose if both values were in the
> C global state, it would be possible to have the "correct" one appear
> at the instant functionargzero changes, instead of being determined by
> the setting at the time the function is entered.  OTOH that would be a
> larger behavior difference / lack of backward compatibilty.

Oops, I should have thoroughly read your email before proposing the same
thing but with more words.  :)

> 
>> If not, can you point me to the relevant bits of code to help me get
>> started?
> 
> Search Src/*.c for references to "argzero", with particular attention to
> builtin.c:bin_emulate.

Thanks.  No promises that I'll have the time to submit a patch soon (or
even at all), but I plan on taking a crack at it this weekend.

-Richard


^ permalink raw reply	[relevance 4%]

* Re: 'emulate sh -c' and $0
  2014-05-30 21:14  4%       ` Richard Hansen
@ 2014-05-31  5:13  2%         ` Bart Schaefer
  2014-06-03 20:15  0%           ` Richard Hansen
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-05-31  5:13 UTC (permalink / raw)
  To: Richard Hansen; +Cc: zsh-workers

On May 30,  5:14pm, Richard Hansen wrote:
}
} Would it add too much complexity to the code or documentation if the
} emulate builtin did more than just toggle options (specifically:
} temporarily change the binding of $0 to the original value)?

No, probably not.  We could certainly get away with making the change
to $0 be an additional effect of the (relatively new) -c option, i.e.,

    emulate sh

changes only the options, but 

    emulate sh -c 'some command'

changes both options and $0 in the scope of 'some command'.  In fact I
like that idea a lot, now that I've written it down ... but it'd be a
bit complicated to add that to "sticky emulation" so a simpler plan is
probably better.

} > The use cases in both directions seem pretty unusual to me.  Losing the
} > ability to "localize" $0 for scripts feels almost as likely to create
} > questions as does your situation.
} 
} I'm not sure what you mean by losing the ability to localize $0.

You gave two examples in your original message on this thread: the current
behavior and the behavior you expected.  Someone else might be expecting
the current behavior, and I don't see any clear criteria for deciding
which one is "best."  If we make any of the suggested changes here, the
current behavior is lost.

} I see a few OK options:
} 
}   * Option #1:
}     3. When 'emulate sh' starts, temporarily set argzero to
}        orig_argzero.  Restore argzero when 'emulate sh' returns.
} 
}   * Option #2:
}     3. Add a new option; let's call it LOCALIZE_ARGZERO for now.  If
}        LOCALIZE_ARGZERO is enabled, use argzero to expand $0.  If
}        LOCALIZE_ARGZERO is disabled, use orig_argzero to expand $0.
}     4. Enable LOCALIZE_ARGZERO by default, but disable it in sh
}        emulation mode.
}     5. Stop disabling FUNCTION_ARGZERO by default in sh emulation mode.
} 
}   * Option #3:
}     3. Modify the expansion rules for $0 as follows:  If
}        FUNCTION_ARGZERO is enabled, use argzero to expand $0.  If
}        FUNCTION_ARGZERO is disabled, use orig_argzero to expand $0.

I was initially leaning toward #3, because #1 takes away the current
behavior and because I'd rather not add yet another option as in #2 ...
but then I had a different idea ...

It seems to me that the ideal situation would be that

    emulate sh

works exactly as it does now ("With SINGLE ARGUMENT set up zsh options"
says the doc, emphasis mine) but that

    emulate sh -c 'some command'

alters the behavior of $0 as well.  The advantage of this is that the -c
option to emulate is relatively new; any scripts relying on the current
$0 behavior are likely old and won't use -c.  The drawback to this is
"sticky emulation" for functions, which is based entirely on option
settings; but that can be made to work if we add an option.  Hence:

If we leave FUNCTION_ARGZERO as it is (that is, off by default for sh
emulation) and add an option POSIX_ARGZERO which exposes the global
argzero when set (inverting your Option #2) but which is never on by
default, then bin_emulate can set POSIX_ARGZERO in the -c scope when
emulating sh/ksh, and it will be sticky for functions defined there.

We wouldn't even have to build those smarts into bin_emulate; a user
who wanted the POSIX semantics could explicitly do

    emulate sh -o POSIX_ARGZERO -c '...'

The only "magic" necessary is that POSIX_ARGZERO exposes the original
value of $0 in spite of the current FUNCTION_ARGZERO setting.

Here are the bits outside bin_emulate, and not yet with doc.  I suppose
there may be some places where posixzero needs to be saved / changed /
restored, which this hasn't covered.


diff --git a/Src/init.c b/Src/init.c
index fd12412..5e92f59 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -226,7 +226,7 @@ parseargs(char **argv, char **runscript)
     char **x;
     LinkList paramlist;
 
-    argzero = *argv++;
+    argzero = posixzero = *argv++;
     SHIN = 0;
 
     /* There's a bit of trickery with opts[INTERACTIVE] here.  It starts *
@@ -253,7 +253,7 @@ parseargs(char **argv, char **runscript)
     if (*argv) {
 	if (unset(SHINSTDIN)) {
 	    if (cmd)
-		argzero = *argv;
+		argzero = posixzero = *argv;
 	    else
 		*runscript = *argv;
 	    opts[INTERACTIVE] &= 1;
@@ -275,6 +275,7 @@ parseargs(char **argv, char **runscript)
     while ((*x++ = (char *)getlinknode(paramlist)));
     free(paramlist);
     argzero = ztrdup(argzero);
+    posixzero = ztrdup(posixzero);
 }
 
 /* Insert into list in order of pointer value */
diff --git a/Src/options.c b/Src/options.c
index ce73d99..e83dc58 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -207,6 +207,7 @@ static struct optname optns[] = {
 {{NULL, "pathscript",	      OPT_EMULATE|OPT_BOURNE},	 PATHSCRIPT},
 {{NULL, "pipefail",           OPT_EMULATE},              PIPEFAIL},
 {{NULL, "posixaliases",       OPT_EMULATE|OPT_BOURNE},	 POSIXALIASES},
+{{NULL, "posixargzero",       OPT_EMULATE},              POSIXARGZERO},
 {{NULL, "posixbuiltins",      OPT_EMULATE|OPT_BOURNE},	 POSIXBUILTINS},
 {{NULL, "posixcd",            OPT_EMULATE|OPT_BOURNE},	 POSIXCD},
 {{NULL, "posixidentifiers",   OPT_EMULATE|OPT_BOURNE},	 POSIXIDENTIFIERS},
diff --git a/Src/params.c b/Src/params.c
index 7901029..0699ead 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -67,6 +67,7 @@ char **path,		/* $path        */
 /**/
 mod_export
 char *argzero,		/* $0           */
+     *posixzero,	/* $0           */
      *home,		/* $HOME        */
      *nullcmd,		/* $NULLCMD     */
      *oldpwd,		/* $OLDPWD      */
@@ -194,6 +195,8 @@ static const struct gsu_integer euid_gsu =
 static const struct gsu_integer ttyidle_gsu =
 { ttyidlegetfn, nullintsetfn, stdunsetfn };
 
+static const struct gsu_scalar argzero_gsu =
+{ argzerogetfn, nullstrsetfn, nullunsetfn };
 static const struct gsu_scalar username_gsu =
 { usernamegetfn, usernamesetfn, stdunsetfn };
 static const struct gsu_scalar dash_gsu =
@@ -285,6 +288,7 @@ IPDEF2("WORDCHARS", wordchars_gsu, 0),
 IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
 IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
 IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
+IPDEF2("0", argzero_gsu, 0),
 
 #ifdef USE_LOCALE
 # define LCIPDEF(name) IPDEF2(name, lc_blah_gsu, PM_UNSET)
@@ -340,7 +344,6 @@ IPDEF7U("RPROMPT2", &rprompt2),
 IPDEF7("PS3", &prompt3),
 IPDEF7("PS4", &prompt4),
 IPDEF7("SPROMPT", &sprompt),
-IPDEF7("0", &argzero),
 
 #define IPDEF8(A,B,C,D) {{NULL,A,D|PM_SCALAR|PM_SPECIAL},BR((void *)B),GSU(colonarr_gsu),0,0,NULL,C,NULL,0}
 IPDEF8("CDPATH", &cdpath, "cdpath", 0),
@@ -3981,6 +3984,17 @@ lcsetfn(Param pm, char *x)
 }
 #endif /* USE_LOCALE */
 
+/* Function to get value for special parameter `0' */
+
+/**/
+static char *
+argzerogetfn(UNUSED(Param pm))
+{
+    if (isset(POSIXARGZERO))
+	return posixzero;
+    return argzero;
+}
+
 /* Function to get value for special parameter `HISTSIZE' */
 
 /**/
diff --git a/Src/zsh.h b/Src/zsh.h
index 5fbff57..620883b 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2151,6 +2151,7 @@ enum {
     PATHSCRIPT,
     PIPEFAIL,
     POSIXALIASES,
+    POSIXARGZERO,
     POSIXBUILTINS,
     POSIXCD,
     POSIXIDENTIFIERS,


^ permalink raw reply	[relevance 2%]

* Re: 'emulate sh -c' and $0
  2014-05-31  5:13  2%         ` Bart Schaefer
@ 2014-06-03 20:15  0%           ` Richard Hansen
  2014-06-03 20:26  3%             ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Richard Hansen @ 2014-06-03 20:15 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

On 2014-05-31 01:13, Bart Schaefer wrote:
> If we leave FUNCTION_ARGZERO as it is (that is, off by default for sh
> emulation) and add an option POSIX_ARGZERO which exposes the global
> argzero when set (inverting your Option #2) but which is never on by
> default, then bin_emulate can set POSIX_ARGZERO in the -c scope when
> emulating sh/ksh, and it will be sticky for functions defined there.
> 
> We wouldn't even have to build those smarts into bin_emulate; a user
> who wanted the POSIX semantics could explicitly do
> 
>     emulate sh -o POSIX_ARGZERO -c '...'
> 
> The only "magic" necessary is that POSIX_ARGZERO exposes the original
> value of $0 in spite of the current FUNCTION_ARGZERO setting.
> 
> Here are the bits outside bin_emulate, and not yet with doc.  I suppose
> there may be some places where posixzero needs to be saved / changed /
> restored, which this hasn't covered.

Wow, thank you for committing this change to master!  It works well in
my limited testing, except for the documented limitation that
POSIX_ARGZERO stays enabled when calling a non-emulated function from a
function defined in 'emulate <shell> -c'.  I'm not sure how much this
will matter in practice, but if backward compatibility wasn't a concern
it'd be nice if zsh temporarily restored options when invoking a
function outside the 'emulate <shell> -c' boundary.

Although it would be a behavior change, I think it would be best if both
'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default:  I
suspect that someone who runs 'emulate sh' cares more about accurate sh
emulation than compatibility with previous sh emulation behavior.  :)

Thanks,
Richard


^ permalink raw reply	[relevance 0%]

* Re: 'emulate sh -c' and $0
  2014-06-03 20:15  0%           ` Richard Hansen
@ 2014-06-03 20:26  3%             ` Peter Stephenson
  2014-06-03 21:10  0%               ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-06-03 20:26 UTC (permalink / raw)
  To: zsh-workers

On Tue, 03 Jun 2014 16:15:25 -0400
Richard Hansen <rhansen@bbn.com> wrote:
> Although it would be a behavior change, I think it would be best if both
> 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default:  I
> suspect that someone who runs 'emulate sh' cares more about accurate sh
> emulation than compatibility with previous sh emulation behavior.  :)

Yes, that's the policy --- backward compatibility is for native mode, sh
compatibility can be improved without worrying about that.

I'm not sure why we missed this one.  Most of the POSIX options are on
in sh emulations.

pws


^ permalink raw reply	[relevance 3%]

* Re: 'emulate sh -c' and $0
  2014-06-03 20:26  3%             ` Peter Stephenson
@ 2014-06-03 21:10  0%               ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-06-03 21:10 UTC (permalink / raw)
  To: zsh-workers

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

On Jun 3, 2014 1:27 PM, "Peter Stephenson" <p.w.stephenson@ntlworld.com>
wrote:
>
> On Tue, 03 Jun 2014 16:15:25 -0400
> Richard Hansen <rhansen@bbn.com> wrote:
> > Although it would be a behavior change, I think it would be best if both
> > 'emulate sh' and 'emulate sh -c' set POSIX_ARGZERO by default
>
> Yes, that's the policy --- backward compatibility is for native mode, sh
> compatibility can be improved without worrying about that.

The complexity here is that we're not just dealing with a particular
emulation, we're dealing with switching from one emulation to another (and
possibly back again) in the middle of a running shell session, and the
effect that has on a dynamically scoped variable that crosses the emulation
boundaries.

If I start in zsh mode and change $0, or $PATH, or any other parameter, and
then enter  a different emulation, the values of those parameters don't
normally change.

> I'm not sure why we missed this one.  Most of the POSIX options are on
> in sh emulations.

We didn't really miss it -- FUNCTION_ARGZERO is correctly turned off when
in sh emulation.  The complication is that it affects $0 only upon entry to
the scope, so although $0 doesn't change *again*, it also doesn't revert if
it was changed previously.

^ permalink raw reply	[relevance 0%]

* Oddball output from zerrmsg()
@ 2014-06-04  2:12  3% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-06-04  2:12 UTC (permalink / raw)
  To: zsh-workers

There's a discussion on the POSIX mailing list about "break"/"continue" RE
whether they should affect only loops "visible" to the statement (can be
thought of as "local" scope) or also those in calling scope.  Shells differ
on this point.

That is, currently, given:

    foo() { print FOO; break 2 }
    bar() { repeat 2 foo; print BAR }
    baz() { repeat 2 bar }

The zsh behavior is:

    % foo
    FOO
    foo:break: not in while, until, select, or repeat loop
    % bar
    FOO
    BAR
    % baz
    FOO
    % 

Note that "break 2" has interupted the loops in both bar and baz, even
though neither of them was in the scope of foo, and has thereby short-
circuited the "print" in bar.

With the proposed semantics:

    % baz
    FOO
    foo:break: not in while, until, select, or repeat loop
    % 

If we edit foo just a little:

    foo() { repeat 2; do print FOO; break 3; done }

Then (with the proposed "break" semantics):

    % baz
    FOO
    FOO
    BAR
    FOO
    FOO
    BAR
    % 

Thus "break 3" has interrupted only the innermost loop, the other two
in bar and baz are considered out of scope and proceed normally.

I don't have an opinion on which of these is preferable, this is all
just background material.

Now for the strange part.  I applied a small patch to doshfunc() to
implement the proposed behavior and ran "make check".  I got exactly
one failure, and it's a false positive:

============
./A07control.ztst: starting.
*** /tmp/zsh.ztst.err.64460     Tue Jun  3 18:57:24 2014
--- /tmp/zsh.ztst.terr.64460    Tue Jun  3 18:57:24 2014
***************
*** 1 ****
! fn:continue:1 not in while, until, select, or repeat loop
--- 1 ----
! fn:continue:1: not in while, until, select, or repeat loop
Test ./A07control.ztst failed: error output differs from expected as shown
above for:
  fn() {
    continue
  }
  fn
Was testing: continue outside loop
./A07control.ztst: test failed.
============

What?  Where did the colon after the line number in the error message go?
Why has it not been there all along?  I don't see the code path by which
that colon would ever have been omitted, yet A07control.ztst clearly was
not prepared for it to be there.  Any ideas?


^ permalink raw reply	[relevance 3%]

* [PATCH] A few more format fix in docs
@ 2014-06-05 14:56  2% Jun T
  0 siblings, 0 replies; 200+ results
From: Jun T @ 2014-06-05 14:56 UTC (permalink / raw)
  To: zsh-workers; +Cc: Jun T

---
 Doc/Zsh/calsys.yo  | 21 +++++++++++----------
 Doc/Zsh/grammar.yo | 51 ++++++++++++++++++++++++++-------------------------
 Doc/Zsh/zle.yo     | 20 ++++++++++----------
 3 files changed, 47 insertions(+), 45 deletions(-)

diff --git a/Doc/Zsh/calsys.yo b/Doc/Zsh/calsys.yo
index 7dc51ab..0d7abbf 100644
--- a/Doc/Zsh/calsys.yo
+++ b/Doc/Zsh/calsys.yo
@@ -547,35 +547,36 @@ and status 2 if the wrong number of arguments were passed; it also sets the
 parameter tt(reply) to an empty associative array.  Otherwise,
 it returns status 0 and sets elements of the associative
 array tt(reply) as follows:
+
 startsitem()
-sitem(time)(The time as a string of digits in the same units as
+sitem(tt(time))(The time as a string of digits in the same units as
 tt($EPOCHSECONDS))
-sitem(schedtime)(The regularly scheduled time.  This may differ from
+sitem(tt(schedtime))(The regularly scheduled time.  This may differ from
 the actual event time tt(time) if this is a recurring event and the next
 occurrence has been rescheduled.  Then tt(time) gives the actual time
 and tt(schedtime) the time of the regular recurrence before modification.)
-sitem(text1)(The text from the line not including the date and time of the
+sitem(tt(text1))(The text from the line not including the date and time of the
 event, but including any tt(WARN) or tt(RPT) keywords and values.)
-sitem(warntime)(Any warning time given by the tt(WARN) keyword as a string
+sitem(tt(warntime))(Any warning time given by the tt(WARN) keyword as a string
 of digits containing the time at which to warn in the same units as
 tt($EPOCHSECONDS).  (Note this is an absolute time, not the relative time
 passed down.)  Not set no tt(WARN) keyword and value were
 matched.)
-sitem(warnstr)(The raw string matched after the tt(WARN) keyword, else unset.)
-sitem(rpttime)(Any recurrence time given by the tt(RPT) keyword as a string
+sitem(tt(warnstr))(The raw string matched after the tt(WARN) keyword, else unset.)
+sitem(tt(rpttime))(Any recurrence time given by the tt(RPT) keyword as a string
 of digits containing the time of the recurrence in the same units
 as tt($EPOCHSECONDS).  (Note this is an absolute time.)  Not set if
 no tt(RPT) keyword and value were matched.)
-sitem(schedrpttime)(The next regularly scheduled occurrence of a recurring
+sitem(tt(schedrpttime))(The next regularly scheduled occurrence of a recurring
 event before modification.  This may differ from tt(rpttime), which is the
 actual time of the event that may have been rescheduled from the regular
 time.)
-sitem(rptstr)(The raw string matched after the tt(RPT) keyword, else unset.)
-sitem(text2)(The text from the line after removal of the date and any
+sitem(tt(rptstr))(The raw string matched after the tt(RPT) keyword, else unset.)
+sitem(tt(text2))(The text from the line after removal of the date and any
 keywords and values.)
 )
 endsitem()
-)
+
 findex(calendar_showdate)
 item(tt(calendar_showdate) [ tt(-r) ] [ tt(-f) var(fmt) ] var(date-spec ...))(
 The given var(date-spec) is interpreted and the corresponding date and
diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index dde67eb..9a1e261 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -465,37 +465,38 @@ shell constructs such as loops or conditions; this somewhat illogical
 behaviour can be recovered by setting the option tt(CONTINUE_ON_ERROR).
 
 Fatal errors found in non-interactive shells include:
-startlist()
-list(Failure to parse shell options passed when invoking the shell)
-list(Failure to change options with the tt(set) builtin)
-list(Parse errors of all sorts, including failures to parse
+
+startitemize()
+itemiz(Failure to parse shell options passed when invoking the shell)
+itemiz(Failure to change options with the tt(set) builtin)
+itemiz(Parse errors of all sorts, including failures to parse
 mathematical expressions)
-list(Failures to set or modify variable behaviour with tt(typeset),
+itemiz(Failures to set or modify variable behaviour with tt(typeset),
 tt(local), tt(declare), tt(export), tt(integer), tt(float))
-list(Execution of incorrectly positioned loop control structures
+itemiz(Execution of incorrectly positioned loop control structures
 (tt(continue), tt(break)))
-list(Attempts to use regular expression with no regular expression
+itemiz(Attempts to use regular expression with no regular expression
 module available)
-list(Disallowed operations when the tt(RESTRICTED) options is set)
-list(Failure to create a pipe needed for a pipeline)
-list(Failure to create a multio)
-list(Failure to autoload a module needed for a declared shell feature)
-list(Errors creating command or process substitutions)
-list(Syntax errors in glob qualifiers)
-list(File generation errors where not caught by the option tt(BAD_PATTERN))
-list(All bad patterns used for matching within case statements)
-list(File generation failures where not caused by tt(NO_MATCH) or
-list(All file generation errors where the pattern was used to create a
+itemiz(Disallowed operations when the tt(RESTRICTED) options is set)
+itemiz(Failure to create a pipe needed for a pipeline)
+itemiz(Failure to create a multio)
+itemiz(Failure to autoload a module needed for a declared shell feature)
+itemiz(Errors creating command or process substitutions)
+itemiz(Syntax errors in glob qualifiers)
+itemiz(File generation errors where not caught by the option tt(BAD_PATTERN))
+itemiz(All bad patterns used for matching within case statements)
+itemiz(File generation failures where not caused by tt(NO_MATCH) or
+itemiz(All file generation errors where the pattern was used to create a
 multio)
-list(Memory errors where detected by the shell)
-list(Invalid subscripts to shell variables)
-list(Attempts to assign read-only variables)
-list(Logical errors with variables such as assignment to the wrong type)
-list(Use of invalid variable names)
-list(Errors in variable substitution syntax)
-list(Failure to convert characters in tt($')...tt(') expressions)
+itemiz(Memory errors where detected by the shell)
+itemiz(Invalid subscripts to shell variables)
+itemiz(Attempts to assign read-only variables)
+itemiz(Logical errors with variables such as assignment to the wrong type)
+itemiz(Use of invalid variable names)
+itemiz(Errors in variable substitution syntax)
+itemiz(Failure to convert characters in tt($')...tt(') expressions)
 similar options)
-endlist()
+enditemize()
 
 If the tt(POSIX_BUILTINS) option is set, more errors associated with
 shell builtin commands are treated as fatal, as specified by the POSIX
diff --git a/Doc/Zsh/zle.yo b/Doc/Zsh/zle.yo
index 4b10226..2a907c5 100644
--- a/Doc/Zsh/zle.yo
+++ b/Doc/Zsh/zle.yo
@@ -732,16 +732,16 @@ The context in which zle was called to read a line; read-only.  One of
 the values:
 
 startitem()
-item(start)(
+item(tt(start))(
 The start of a command line (at prompt tt(PS1)).
 )
-item(cont)(
+item(tt(cont))(
 A continuation to a command line (at prompt tt(PS2)).
 )
-item(select)(
+item(tt(select))(
 In a tt(select) loop.
 )
-item(vared)(
+item(tt(vared))(
 Editing a variable in tt(vared).
 )
 enditem()
@@ -878,21 +878,21 @@ is needed for character indexing to include tt(PREDISPLAY).
 
 Each string consists of the following parts:
 
-startlist()
-list(Optionally, a `tt(P)' to signify that the start and end offset that
+startitemize()
+itemiz(Optionally, a `tt(P)' to signify that the start and end offset that
 follow include any string set by the tt(PREDISPLAY) special parameter;
 this is needed if the predisplay string itself is to be highlighted.
 Whitespace may follow the `tt(P)'.)
-list(A start offset in the same units as tt(CURSOR), terminated by
+itemiz(A start offset in the same units as tt(CURSOR), terminated by
 whitespace.)
-list(An end offset in the same units as tt(CURSOR), terminated by
+itemiz(An end offset in the same units as tt(CURSOR), terminated by
 whitespace.)
-list(A highlight specification in the same format as
+itemiz(A highlight specification in the same format as
 used for contexts in the parameter tt(zle_highlight),
 ifnzman(noderef(Character Highlighting))\
 ifzman(see Character Highlighting below);
 for example, tt(standout) or tt(fg=red,bold)).
-endlist()
+enditemize()
 
 For example, 
 
-- 
1.8.5.2 (Apple Git-48)


^ permalink raw reply	[relevance 2%]

* Re: ulimit -a: -r vs -N [was Re: pkgsrc patches for zsh]
  @ 2014-06-25 10:33  4%                     ` Peter Stephenson
    0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-06-25 10:33 UTC (permalink / raw)
  To: Thomas Klausner, zsh-workers

On Wed, 25 Jun 2014 10:36:55 +0200
Thomas Klausner <tk@giga.or.at> wrote:
> The description for -T is not correct for NetBSD though. (I don't know
> how this limit works on other operating systems.)
> From NetBSD's sh(1)'s ulimit section:
> 
>  -r          show or set the limit on the number of threads this
>              user can have at one time
> 
> So the limit is not per-process, but for the user in total.

That's basically how -T is documented in the zsh manual, so it may be
the description of -T from ulimit that's wrong.  If anyone can confirm
(Linux doesn't have either, it looks like NPROC is the nearest), I will
change this globally, but for now it's just for NetBSD.

I've added compatibility with sh when NTHR is present and RTPRIO isn't
--- which should be just about specific enough that the additional
compatibility more than offsets any confusion.

> The check for RLIMIT_NTHR is already in that file, about 10 lines
> higher.

Thanks, should have spotted that.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 9905ab5..dd090d6 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1940,6 +1940,9 @@ sitem(tt(-m))(Kilobytes on the size of physical memory.)
 sitem(tt(-n))(open file descriptors.)
 sitem(tt(-p))(The number of pseudo-terminals.)
 sitem(tt(-q))(Bytes in POSIX message queues.)
+sitem(tt(-r))(Maximum real time priority.  On some systems where this
+is not available, such as NetBSD, this has the same effect as tt(-T)
+for compatibility with tt(sh).)
 sitem(tt(-s))(Kilobytes on the size of the stack.)
 sitem(tt(-T))(The number of simultaneous threads available to the user.)
 sitem(tt(-t))(CPU seconds to be used.)
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 0bcafda..bcf9ad8 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -32,12 +32,17 @@
 
 #if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY)
 
-#ifdef RLIMIT_POSIXLOCKS
+#if defined(HAVE_RLIMIT_POSIXLOCKS) && !defined(HAVE_RLIMIT_LOCKS)
 #  define RLIMIT_LOCKS		RLIMIT_POSIXLOCKS
+#  define HAVE_RLIMIT_LOCKS     1
 #endif
 
-#ifdef RLIMIT_NTHR
+#if defined(HAVE_RLIMIT_NTHR) && !defined(HAVE_RLIMIT_PTHREAD)
 #  define RLIMIT_PTHREAD	RLIMIT_NTHR
+#  define HAVE_RLIMIT_PTHREAD   1
+#  define THREAD_FMT            "-T: threads                         "
+#else
+#  define THREAD_FMT            "-T: threads per process             "
 #endif
 
 enum {
@@ -373,7 +378,7 @@ printulimit(char *nam, int lim, int hard, int head)
 # ifdef HAVE_RLIMIT_PTHREAD
     case RLIMIT_PTHREAD:
 	if (head)
-	    printf("-T: threads per process             ");
+	    printf(THREAD_FMT);
 	break;
 # endif /* HAVE_RLIMIT_PTHREAD */
 # ifdef HAVE_RLIMIT_NICE
@@ -387,6 +392,14 @@ printulimit(char *nam, int lim, int hard, int head)
 	if (head)
 	    printf("-r: max rt priority                 ");
 	break;
+# else
+#  ifdef HAVE_RLIMIT_NTHR
+	/* For compatibility with sh on NetBSD */
+    case RLIMIT_NTHR:
+	if (head)
+	    printf("-r: threads                         ");
+	break;
+#  endif /* HAVE_RLIMIT_NTHR */
 # endif /* HAVE_RLIMIT_RTPRIO */
 # ifdef HAVE_RLIMIT_NPTS
     case RLIMIT_NPTS:
@@ -860,6 +873,13 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 		case 'r':
 		    res = RLIMIT_RTPRIO;
 		    break;
+# else
+#  ifdef HAVE_RLIMIT_NTHR
+		    /* For compatibility with sh on NetBSD */
+		case 'r':
+		    res = RLIMIT_NTHR;
+		    break;
+#  endif /* HAVE_RLIMIT_NTHR */
 # endif
 # ifdef HAVE_RLIMIT_NPTS
 		case 'p':
@@ -876,6 +896,11 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 		    res = RLIMIT_KQUEUES;
 		    break;
 # endif
+# ifdef HAVE_RLIMIT_PTHREAD
+		case 'T':
+		    res = RLIMIT_PTHREAD;
+		    break;
+# endif
 		default:
 		    /* unrecognised limit */
 		    zwarnnam(name, "bad option: -%c", *options);


-- 
Peter Stephenson <p.stephenson@samsung.com>  Principal Software Engineer
Tel: +44 (0)1223 434724                Samsung Cambridge Solution Centre
St John's House, St John's Innovation Park, Cowley Road,
Cambridge, CB4 0DS, UK


^ permalink raw reply	[relevance 4%]

* Re: ulimit -a: -r vs -N [was Re: pkgsrc patches for zsh]
  @ 2014-06-25 11:11  5%                         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-06-25 11:11 UTC (permalink / raw)
  To: Thomas Klausner, zsh-workers

On Wed, 25 Jun 2014 13:00:11 +0200
Thomas Klausner <tk@giga.or.at> wrote:
> On Wed, Jun 25, 2014 at 11:33:35AM +0100, Peter Stephenson wrote:
> > I've added compatibility with sh when NTHR is present and RTPRIO isn't
> > --- which should be just about specific enough that the additional
> > compatibility more than offsets any confusion.
> 
> Thanks, but this version doesn't compile since:
> rlimits.c: In function 'printulimit':
> rlimits.c:398:5: error: duplicate case value
>      case RLIMIT_NTHR:
>      ^
> rlimits.c:379:5: error: previously used here
>      case RLIMIT_PTHREAD:
>      ^
> *** Error code 1

Right, we'll just have to output for -T only, not -r.  As -r's for
compatibility with sh and the zsh documentation mentions -T that's
probably not a problem.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 9905ab5..dd090d6 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1940,6 +1940,9 @@ sitem(tt(-m))(Kilobytes on the size of physical memory.)
 sitem(tt(-n))(open file descriptors.)
 sitem(tt(-p))(The number of pseudo-terminals.)
 sitem(tt(-q))(Bytes in POSIX message queues.)
+sitem(tt(-r))(Maximum real time priority.  On some systems where this
+is not available, such as NetBSD, this has the same effect as tt(-T)
+for compatibility with tt(sh).)
 sitem(tt(-s))(Kilobytes on the size of the stack.)
 sitem(tt(-T))(The number of simultaneous threads available to the user.)
 sitem(tt(-t))(CPU seconds to be used.)
diff --git a/Src/Builtins/rlimits.c b/Src/Builtins/rlimits.c
index 0bcafda..1ab8710 100644
--- a/Src/Builtins/rlimits.c
+++ b/Src/Builtins/rlimits.c
@@ -32,12 +32,17 @@
 
 #if defined(HAVE_GETRLIMIT) && defined(RLIM_INFINITY)
 
-#ifdef RLIMIT_POSIXLOCKS
+#if defined(HAVE_RLIMIT_POSIXLOCKS) && !defined(HAVE_RLIMIT_LOCKS)
 #  define RLIMIT_LOCKS		RLIMIT_POSIXLOCKS
+#  define HAVE_RLIMIT_LOCKS     1
 #endif
 
-#ifdef RLIMIT_NTHR
+#if defined(HAVE_RLIMIT_NTHR) && !defined(HAVE_RLIMIT_PTHREAD)
 #  define RLIMIT_PTHREAD	RLIMIT_NTHR
+#  define HAVE_RLIMIT_PTHREAD   1
+#  define THREAD_FMT            "-T: threads                         "
+#else
+#  define THREAD_FMT            "-T: threads per process             "
 #endif
 
 enum {
@@ -373,7 +378,7 @@ printulimit(char *nam, int lim, int hard, int head)
 # ifdef HAVE_RLIMIT_PTHREAD
     case RLIMIT_PTHREAD:
 	if (head)
-	    printf("-T: threads per process             ");
+	    printf(THREAD_FMT);
 	break;
 # endif /* HAVE_RLIMIT_PTHREAD */
 # ifdef HAVE_RLIMIT_NICE
@@ -860,6 +865,13 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 		case 'r':
 		    res = RLIMIT_RTPRIO;
 		    break;
+# else
+#  ifdef HAVE_RLIMIT_NTHR
+		    /* For compatibility with sh on NetBSD */
+		case 'r':
+		    res = RLIMIT_NTHR;
+		    break;
+#  endif /* HAVE_RLIMIT_NTHR */
 # endif
 # ifdef HAVE_RLIMIT_NPTS
 		case 'p':
@@ -876,6 +888,11 @@ bin_ulimit(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
 		    res = RLIMIT_KQUEUES;
 		    break;
 # endif
+# ifdef HAVE_RLIMIT_PTHREAD
+		case 'T':
+		    res = RLIMIT_PTHREAD;
+		    break;
+# endif
 		default:
 		    /* unrecognised limit */
 		    zwarnnam(name, "bad option: -%c", *options);


^ permalink raw reply	[relevance 5%]

* Fwd: [Pkg-zsh-devel] Bug#702760: zsh: aptitude completion missing resolver options [origin: dbbcode@gmail.com]
@ 2014-06-28 12:34  2% Axel Beckert
  0 siblings, 0 replies; 200+ results
From: Axel Beckert @ 2014-06-28 12:34 UTC (permalink / raw)
  To: zsh-workers

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

Hi,

the patch in the attached mail expands zsh's aptitude completion by
two boolean options.

It applies to current zsh git HEAD without fuzz, but with an offset of
33 lines.

Initially reported in Debian at https://bugs.debian.org/702760

		Kind regards, Axel
-- 
/~\  Plain Text Ribbon Campaign                   | Axel Beckert
\ /  Say No to HTML in E-Mail and News            | abe@deuxchevaux.org  (Mail)
 X   See http://www.nonhtmlmail.org/campaign.html | abe@noone.org (Mail+Jabber)
/ \  I love long mails: http://email.is-not-s.ms/ | http://noone.org/abe/ (Web)

[-- Attachment #2: Type: message/rfc822, Size: 6711 bytes --]

[-- Attachment #2.1.1: Type: text/plain, Size: 1189 bytes --]

Package: zsh
Version: 4.3.10-14
Severity: normal

The _aptitude zsh completion file is missing --full-resolver and
--safe-resolver. Since these options are used frequently, I think it fitting
that they be added to the completion system. I have made a simple patch to add
them.

-- System Information:
Debian Release: 6.0.7
  APT prefers stable-updates
  APT policy: (500, 'stable-updates'), (500, 'stable')
Architecture: i386 (i686)

Kernel: Linux 2.6.32-5-686 (SMP w/1 CPU core)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages zsh depends on:
ii  libc6                     2.11.3-4       Embedded GNU C Library: Shared lib
ii  libcap2                   1:2.19-3       support for getting/setting POSIX.
ii  libncursesw5              5.7+20100313-5 shared libraries for terminal hand

Versions of packages zsh recommends:
ii  libc6                         2.11.3-4   Embedded GNU C Library: Shared lib
ii  libpcre3                      8.02-1.1   Perl 5 Compatible Regular Expressi

Versions of packages zsh suggests:
pn  zsh-doc                       <none>     (no description available)

-- no debconf information

[-- Attachment #2.1.2: zsh_apti.patch --]
[-- Type: text/plain, Size: 814 bytes --]

--- /usr/share/zsh/functions/Completion/Debian/_aptitude	2010-06-30 12:25:11.000000000 -0400
+++ ./Completion/Debian/Command/_aptitude	2013-03-10 23:27:58.000000000 -0400
@@ -37,6 +37,8 @@
   '--schedule-only[schedule operations to be performed in the future]' \
   '--purge-unused[purge unused packages instead of removing]' \
   '--visual-preview[start up the visual interface and display its preview screen]' \
+  '--full-resolver[attempts to resolve conflicts with a higher risk of breakage]' \
+  '--safe-resolver[attempts to resolve conflicts with a lower risk of breakage]' \
   '-S[load the extended state information from non-standard state file]:state file:_files' \
   '-u[begin updating the package lists as soon as the program starts]' \
   '-i[displays a download preview when the program starts]' \

[-- Attachment #2.1.3: Type: text/plain, Size: 182 bytes --]

_______________________________________________
Pkg-zsh-devel mailing list
Pkg-zsh-devel@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-zsh-devel

^ permalink raw reply	[relevance 2%]

* Fwd: [Pkg-zsh-devel] Bug#702000: zsh: gzip completion: --rsyncable option is missing [origin: vincent@vinc17.net]
@ 2014-06-28 13:50  3% Axel Beckert
  0 siblings, 0 replies; 200+ results
From: Axel Beckert @ 2014-06-28 13:50 UTC (permalink / raw)
  To: zsh-workers

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

Hi,

the attached mail contains a patch to add the --rsyncable option to
zsh's gzip completion.

The patch applies cleanly against Completion/Unix/Command/_gzip in
current zsh git HEAD.

Initially reported in Debian at https://bugs.debian.org/702000

		Kind regards, Axel
-- 
/~\  Plain Text Ribbon Campaign                   | Axel Beckert
\ /  Say No to HTML in E-Mail and News            | abe@deuxchevaux.org  (Mail)
 X   See http://www.nonhtmlmail.org/campaign.html | abe@noone.org (Mail+Jabber)
/ \  I love long mails: http://email.is-not-s.ms/ | http://noone.org/abe/ (Web)

[-- Attachment #2: Type: message/rfc822, Size: 6306 bytes --]

[-- Attachment #2.1.1: Type: text/plain, Size: 988 bytes --]

Package: zsh
Version: 5.0.2-2
Severity: minor
Tags: patch

Debian's gzip version has a --rsyncable option (see "gzip --help"
output, the man page not being currently up to date). It should
be supported by "/usr/share/zsh/functions/Completion/Unix/_gzip".

See attached patch.

-- System Information:
Debian Release: 7.0
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.2.0-4-amd64 (SMP w/8 CPU cores)
Locale: LANG=POSIX, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages zsh depends on:
ii  dpkg        1.16.9
ii  libc6       2.13-38
ii  libcap2     1:2.22-1.2
ii  libtinfo5   5.9-10
ii  zsh-common  5.0.2-2

Versions of packages zsh recommends:
ii  libc6         2.13-38
ii  libncursesw5  5.9-10
ii  libpcre3      1:8.31-2

Versions of packages zsh suggests:
ii  zsh-doc  5.0.2-2

-- no debconf information

[-- Attachment #2.1.2: _gzip.patch --]
[-- Type: text/plain, Size: 589 bytes --]

--- /usr/share/zsh/functions/Completion/Unix/_gzip	2012-12-28 14:38:19.000000000 +0100
+++ share/zsh/site-functions/_gzip	2013-03-01 15:42:50.000000000 +0100
@@ -39,6 +39,7 @@
     '(-q --quiet)--silent[suppress all warnings]' \
     '(--recursive)-r[operate recursively on directories]' \
     '(-r)--recursive[operate recursively on directories]' \
+    '--rsyncable[make rsync-friendly archive]' \
     '(--suffix)-S+[specify suffix for compressed files]:suffix:' \
     '(-S)--suffix=[specify suffix for compressed files]:suffix:' \
     '(--test)-t[test compressed file integrity]' \

[-- Attachment #2.1.3: Type: text/plain, Size: 182 bytes --]

_______________________________________________
Pkg-zsh-devel mailing list
Pkg-zsh-devel@lists.alioth.debian.org
http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-zsh-devel

^ permalink raw reply	[relevance 3%]

* Discussion of path search for builtin utilities
@ 2014-07-03 18:14  4% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-07-03 18:14 UTC (permalink / raw)
  To: zsh-workers


---------- Forwarded message ----------
Date: Wed, 2 Jul 2014 23:29:29 +0200
From: Jilles Tjoelker <jilles@stack.nl>
To: Philip Guenther <guenther@gmail.com>
Cc: austin-group-l@opengroup.org
Subject: Re: what does XCU 2.9.1.1 part 1.d.i.a. mean?  Does anyone follow it?
Resent-Date: 2 Jul 2014 21:35:13 -0000
Resent-From: austin-group-l@opengroup.org
Resent-To: austin-group-l@opengroup.org

On Tue, Jul 01, 2014 at 12:54:32AM -0700, Philip Guenther wrote:
> XCU 2.9.1.1 describes how the shell does command seach and execution.  To
> quote:
> ------
> 1. If the command name does not contain any <slash> characters, the first
>    successful step in the following sequence shall occur:
>     a.  If the command name matches the name of a special built-in
>         utility, that special built-in utility shall be invoked.
>     b.  If the command name matches the name of a function known to
>         this shell, the function shall be invoked as described in
>         Section 2.9.5. If the implementation has provided a standard
>         utility in the form of a function, it shall not be recognized
>         at this point. It shall be invoked in conjunction with the path
>         search in step 1.d.
>     c.  If the command name matches the name of a utility listed in the
>         following table, that utility shall be invoked.
>                 alias        false       jobs       read         wait
>                 bg           fc          kill       true
>                 cd           fg          newgrp     umask
>                 command      getopts     pwd        unalias
>     d.  Otherwise, the command shall be searched for using the PATH
>         environment variable as described in XBD Chapter 8:
>      i. If the search is successful:
>         a. If the system has implemented the utility as a regular
>            built-in or as a shell function, it shall be invoked at this
>            point in the path search.
>         b. Otherwise, the shell executes the utility in a separate utility
>            environment (see Section 2.12) with actions equivalent to
>            calling the execl() function as defined in <...>
> ...
>      ii. If the search is unsuccessful, the command shall fail with an
>          exit status of 127 and the shell shall write an error message.
> ------

> Okay, so consider a shell which has 'test' as a built-in.  It's not
> special, let's assume there's no function definition, and its not in the
> list in 1.c, so the shell has to do a search of $PATH per 1.d.

> Question 1)
>    Part 1.d.i.a. *doesn't* refer to the search finding the utility in any
>    particular directory, such as a directory in the PATH required for
>    standards compliance.  So it doesn't matter if it found a completely
>    different version of the utility; it can/should still invoke the
>    (standard-behaving) built-in version.  Is that correct?

> Question 2)
>    Part 1.d.ii says that if you override PATH with one that doesn't
>    include (versions of) the standard utilties, then built-ins not listed
>    in part 1c must not be invoked by the shell.  For example, assuming
>    $HOME/empty doesn't exist and can be created, then this:
> 	mkdir $HOME/empty
> 	( unset -f test; PATH=$HOME/empty; test -d $HOME/empty )
> 	echo $?
>    must output "127".  Is that correct?

> Checking of a few systems (linux, solaris 10, Mac OSX) find they seem to
> answer my questions 1 and 2 with "yes" and "no", respectively.  That is,
> they treat all built-ins like the list in 1c, skipping the $PATH search
> completely and rendering part 1.d.i.a. superfluous.

> (If it matter neither whether the path search is successful, nor what it
> finds when it is successful, then the search is pointless.)

> Can we delete part 1.d.i.a ?

ksh93 implements 1.d.i.a for some builtins, although it also has some
builtins (POSIX and other) that are not found via PATH.

For example, ksh93 Version AJM 93u+ 2012-08-01 from FreeBSD ports can do
things like (after creating an executable named /opt/ast/bin/cat):

$ command -V cat
cat is a tracked alias for /bin/cat
$ (PATH=/opt/ast/bin:$PATH; command -V cat)
cat is a shell builtin version of /opt/ast/bin/cat
$ (PATH=/opt/ast/bin:$PATH; cat -\?)
Usage: cat [-bdenstuvABDERST] [file ...]
$ cat -\?
cat: illegal option -- ?
usage: cat [-belnstuv] [file ...]
$ PATH=/var/empty cat -\?
ksh93: cat: not found [No such file or directory]

I think this is what is meant by 1.d.i.a.

This ksh93 feature allows scripts to opt-in to builtins that may not be
compatible with the utilities provided with the system (for example, the
builtin version does not support FreeBSD's -l option). For a shell that
is more tightly coupled with the rest of the system, this seems less
useful.

The apparent goal of allowing applications to be certain of invoking
their own executables is not achieved by almost all shells, and may not
be desirable either (how about calling utilities implemented as shell
scripts using a non-standard PATH?).

-- 
Jilles Tjoelker

---------- Forwarded message ----------
Date: Tue, 1 Jul 2014 12:37:56 -0700
From: Nick Stoughton <nickstoughton@gmail.com>
To: Philip Guenther <guenther@gmail.com>
Cc: "austin-group-l@opengroup.org" <austin-group-l@opengroup.org>
Subject: Re: what does XCU 2.9.1.1 part 1.d.i.a. mean? Does anyone follow it?
Resent-Date: 1 Jul 2014 19:38:08 -0000
Resent-From: austin-group-l@opengroup.org
Resent-To: austin-group-l@opengroup.org

As far as I can see all of the following shells fail to conform as you
describe:

ksh
bash
dash
tcsh
zsh

(some of these fail for lots of other reasons too!)

The only shell I have been able to find that *does* implement the standard
as required is "yash" (and then only in posixly-correct mode).

However, XRAT (page 3693, line 126346 onwards) has this to say:
--------------
The command search shown here does not match all historical
implementations. A more typical
sequence has been:
 ?  Any built-in (special or regular)
 ? Functions
 ? Path search for executable files
But there are problems with this sequence. Since the programmer has no idea
in advance which
utilities might have been built into the shell, a function cannot be used
to override portably a
utility of the same name. (For example, a function named cd cannot be
written for many
historical systems.) Furthermore, the PATH variable is partially
ineffective in this case, and only
a pathname with a <slash> can be used to ensure a specific executable file
is invoked.

After the execve( ) failure described, the shell normally executes the file
as a shell script. Some
implementations, however, attempt to detect whether the file is actually a
script and not an
executable from some other architecture. The method used by the KornShell
is allowed by the
text that indicates non-text files may be bypassed.

The sequence selected for the Shell and Utilities volume of POSIX.1-2008
acknowledges that
special built-ins cannot be overridden, but gives the programmer full
control over which
versions of other utilities are executed. It provides a means of
suppressing function lookup (via
the command utility) for the user?s own functions and ensures that any
regular built-ins or
functions provided by the implementation are under the control of the path
search. The
mechanisms for associating built-ins or functions with executable files in
the path are not
specified by the Shell and Utilities volume of POSIX.1-2008, but the
wording requires that if
either is implemented, the application is not able to distinguish a
function or built-in from an
executable (other than in terms of performance, presumably). The
implementation ensures that
all effects specified by the Shell and Utilities volume of POSIX.1-2008
resulting from the
invocation of the regular built-in or function (interaction with the
environment, variables, traps,
and so on) are identical to those resulting from the invocation of an
executable file.

------------
So it appears that this is deliberate, if largely un-implemented. I would
encourage you to file a bug at http://austingroupbugs.net for further
deliberation.


^ permalink raw reply	[relevance 4%]

* aliases+=(foo 'echo bar') crash
@ 2014-07-23 16:09  3% Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2014-07-23 16:09 UTC (permalink / raw)
  To: zsh-workers

$ zsh --version
zsh 5.0.5 (x86_64-pc-linux-gnu)
$ zsh -c 'aliases+=(a b)'
*** Error in `zsh': double free or corruption (out): 0x00007f55e838f7e0 ***
zsh: abort      zsh -c 'aliases+=(a b)'

(gdb) bt
#0  0x00007ffff7135407 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff71367e8 in __GI_abort () at abort.c:89
#2  0x00007ffff7173394 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7ffff7266010 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7178b6e in malloc_printerr (action=1, str=0x7ffff7266160 "double free or corruption (out)", ptr=<optimized out>) at malloc.c:4996
#4  0x00007ffff7179876 in _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
#5  0x0000000000455305 in strsetfn ()
#6  0x000000000045a2f2 in ?? ()
#7  0x000000000045a7cc in arrhashsetfn ()
#8  0x000000000045b263 in assignaparam ()
#9  0x00000000004226cc in ?? ()
#10 0x00000000004272a5 in ?? ()
#11 0x0000000000428896 in ?? ()
#12 0x0000000000428c0e in ?? ()
#13 0x0000000000429db1 in execlist ()
#14 0x000000000042a030 in execode ()
#15 0x000000000042a102 in execstring ()
#16 0x000000000043bde2 in init_misc ()
#17 0x000000000043d29e in zsh_main ()
#18 0x00007ffff7121b45 in __libc_start_main (main=0x40f010 <main>, argc=3, argv=0x7fffffffdd98, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7fffffffdd88) at libc-start.c:287
#19 0x000000000040f03e in _start ()



^ permalink raw reply	[relevance 3%]

* PATCH: ztrftime %. for fractions of a second in prompts
@ 2014-07-30 10:46  6% Peter Stephenson
  2014-07-30 13:16  0% ` Vin Shelton
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-07-30 10:46 UTC (permalink / raw)
  To: Zsh Hackers' List

I was trying to get some timings in prompts to better than a second ---
not particularly useful in a regular shell prompt, but very useful in
the prompts provided by e.g. the TCP functions.

I was shocked! shocked! to find this appears not to be possible.

I've used %. for this as it's definitely not POSIX and is very easy to
remember.  You can specify 1 to 6 digits between the '%' and the '.'.

This doesn't appear to be useful in non-prompt calls to ztrftime() since
the fractions of a second aren't available.

pws


diff --git a/Doc/Zsh/prompt.yo b/Doc/Zsh/prompt.yo
index eab15d2..36f351b 100644
--- a/Doc/Zsh/prompt.yo
+++ b/Doc/Zsh/prompt.yo
@@ -185,6 +185,13 @@ sitem(tt(%K))(the hour of the day on the 24-hour clock)
 sitem(tt(%L))(the hour of the day on the 12-hour clock)
 endsitem()
 
+In addition, if the system supports the POSIX tt(gettimeofday) system
+call, tt(%.) provides decimal fractions of a second since the epoch with
+leading zeroes.  By default three decimal places are provided, but a
+number of digits up to 6 may be given following the tt(%); hence tt(%6.)
+outputs microseconds.  A typical example of this is the format
+`tt(%D{%H:%M:%S.%.})'.
+
 The GNU extension that a `tt(-)' between the tt(%) and the
 format character causes a leading zero or space to be stripped
 is handled directly by the shell for the format characters tt(d), tt(f),
diff --git a/Src/builtin.c b/Src/builtin.c
index 34a5296..a2a3ad7 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1731,7 +1731,7 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
 	    if (tdfmt != NULL) {
 		struct tm *ltm;
 		ltm = localtime(&ent->stim);
-		if (ztrftime(timebuf, 256, tdfmt, ltm))
+		if (ztrftime(timebuf, 256, tdfmt, ltm, 0L))
 		    fprintf(f, "%s  ", timebuf);
 	    }
 	    /* display the time taken by the command, if required */
diff --git a/Src/prompt.c b/Src/prompt.c
index 95a7d49..c16d781 100644
--- a/Src/prompt.c
+++ b/Src/prompt.c
@@ -270,6 +270,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
     char *ss, *hostnam;
     int t0, arg, test, sep, j, numjobs;
     struct tm *tm;
+    struct timezone dummy_tz;
+    struct timeval tv;
     time_t timet;
     Nameddir nd;
 
@@ -636,8 +638,8 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 			tmfmt = "%l:%M%p";
 			break;
 		    }
-		    timet = time(NULL);
-		    tm = localtime(&timet);
+		    gettimeofday(&tv, &dummy_tz);
+		    tm = localtime(&tv.tv_sec);
 		    /*
 		     * Hack because strftime won't say how
 		     * much space it actually needs.  Try to add it
@@ -647,7 +649,7 @@ putpromptchar(int doprint, int endchar, unsigned int *txtchangep)
 		     */
 		    for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) {
 			addbufspc(t0);
-			if (ztrftime(bv->bp, t0, tmfmt, tm) >= 0)
+			if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >= 0)
 			    break;
 		    }
 		    /* There is enough room for this because addbufspc(t0)
diff --git a/Src/utils.c b/Src/utils.c
index cef2abe..aa978e6 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -2710,7 +2710,7 @@ ztrftimebuf(int *bufsizeptr, int decr)
 
 /**/
 mod_export int
-ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
+ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec)
 {
     int hr12;
 #ifdef HAVE_STRFTIME
@@ -2729,6 +2729,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
     while (*fmt)
 	if (*fmt == '%') {
 	    int strip;
+	    int digs = 3;
 
 	    fmt++;
 	    if (*fmt == '-') {
@@ -2736,6 +2737,17 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
 		fmt++;
 	    } else
 		strip = 0;
+	    if (idigit(*fmt)) {
+		/* Digit --- only useful with . */
+		char *dstart = fmt;
+		char *dend = fmt+1;
+		while (idigit(*dend))
+		    dend++;
+		if (*dend == '.') {
+		    fmt = dend;
+		    digs = atoi(dstart);
+		}
+	    }
 	    /*
 	     * Assume this format will take up at least two
 	     * characters.  Not always true, but if that matters
@@ -2745,6 +2757,20 @@ ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
 	    if (ztrftimebuf(&bufsize, 2))
 		return -1;
 	    switch (*fmt++) {
+	    case '.':
+		if (ztrftimebuf(&bufsize, digs))
+		    return -1;
+		if (digs > 6)
+		    digs = 6;
+		if (digs < 6) {
+		    int trunc;
+		    for (trunc = 5 - digs; trunc; trunc--)
+			usec /= 10;
+		    usec  = (usec + 5) / 10;
+		}
+		sprintf(buf, "%0*ld", digs, usec);
+		buf += digs;
+		break;
 	    case 'd':
 		if (tm->tm_mday > 9 || !strip)
 		    *buf++ = '0' + tm->tm_mday / 10;
diff --git a/Src/watch.c b/Src/watch.c
index 5231579..8dea0b4 100644
--- a/Src/watch.c
+++ b/Src/watch.c
@@ -330,7 +330,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt, int prnt, int fini)
 		    }
 		    timet = getlogtime(u, inout);
 		    tm = localtime(&timet);
-		    ztrftime(buf, 40, fm2, tm);
+		    ztrftime(buf, 40, fm2, tm, 0L);
 		    printf("%s", (*buf == ' ') ? buf + 1 : buf);
 		    break;
 		case '%':


^ permalink raw reply	[relevance 6%]

* Re: PATCH: ztrftime %. for fractions of a second in prompts
  2014-07-30 10:46  6% PATCH: ztrftime %. for fractions of a second in prompts Peter Stephenson
@ 2014-07-30 13:16  0% ` Vin Shelton
  0 siblings, 0 replies; 200+ results
From: Vin Shelton @ 2014-07-30 13:16 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh Hackers' List

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

Dear Peter,

On my Mint 17 system, the latest code fails to compile with gcc 4.8.2:

gcc -c -I. -I../../Src -I/opt/src/zsh-2014-07-30/Src
-I/opt/src/zsh-2014-07-30/Src/Zle -I/opt/src/zsh-2014-07-30/Src/Builtins
 -DHAVE_CONFIG_H -DMODULE -Wall -Wmissing-prototypes -O2 -fPIC -o sched..o
/opt/src/zsh-2014-07-30/Src/Builtins/sched.c
/opt/src/zsh-2014-07-30/Src/Builtins/sched.c: In function ‘bin_sched’:
/opt/src/zsh-2014-07-30/Src/Builtins/sched.c:214:6: error: too few
arguments to function ‘ztrftime’
      ztrftime(tbuf, 40, "%a %b %e %k:%M:%S", tmp);
      ^
In file included from ./../../Src/zsh.mdh:62:0,
                 from ./sched.mdh:17,
                 from /opt/src/zsh-2014-07-30/Src/Builtins/sched.c:30:
./../../Src/utils.epro:80:32: note: declared here
 extern mod_import_function int ztrftime _((char*buf,int
bufsize,char*fmt,struct tm*tm,long usec));
                                ^
make[3]: *** [sched..o] Error 1
make[3]: Leaving directory `/opt/build/zsh-2014-07-30/Src/Builtins'
make[2]: *** [modules] Error 1
make[2]: Leaving directory `/opt/build/zsh-2014-07-30/Src'
make[1]: *** [modules] Error 2
make[1]: Leaving directory `/opt/build/zsh-2014-07-30/Src'
make: *** [all] Error 1

Please let me know if you need more info.

  - Vin


On Wed, Jul 30, 2014 at 3:46 AM, Peter Stephenson <p.stephenson@samsung.com>
wrote:

> I was trying to get some timings in prompts to better than a second ---
> not particularly useful in a regular shell prompt, but very useful in
> the prompts provided by e.g. the TCP functions.
>
> I was shocked! shocked! to find this appears not to be possible.
>
> I've used %. for this as it's definitely not POSIX and is very easy to
> remember.  You can specify 1 to 6 digits between the '%' and the '.'.
>
> This doesn't appear to be useful in non-prompt calls to ztrftime() since
> the fractions of a second aren't available.
>
> pws
>
>
> diff --git a/Doc/Zsh/prompt.yo b/Doc/Zsh/prompt.yo
> index eab15d2..36f351b 100644
> --- a/Doc/Zsh/prompt.yo
> +++ b/Doc/Zsh/prompt.yo
> @@ -185,6 +185,13 @@ sitem(tt(%K))(the hour of the day on the 24-hour
> clock)
>  sitem(tt(%L))(the hour of the day on the 12-hour clock)
>  endsitem()
>
> +In addition, if the system supports the POSIX tt(gettimeofday) system
> +call, tt(%.) provides decimal fractions of a second since the epoch with
> +leading zeroes.  By default three decimal places are provided, but a
> +number of digits up to 6 may be given following the tt(%); hence tt(%6.)
> +outputs microseconds.  A typical example of this is the format
> +`tt(%D{%H:%M:%S.%.})'.
> +
>  The GNU extension that a `tt(-)' between the tt(%) and the
>  format character causes a leading zero or space to be stripped
>  is handled directly by the shell for the format characters tt(d), tt(f),
> diff --git a/Src/builtin.c b/Src/builtin.c
> index 34a5296..a2a3ad7 100644
> --- a/Src/builtin.c
> +++ b/Src/builtin.c
> @@ -1731,7 +1731,7 @@ fclist(FILE *f, Options ops, zlong first, zlong last,
>             if (tdfmt != NULL) {
>                 struct tm *ltm;
>                 ltm = localtime(&ent->stim);
> -               if (ztrftime(timebuf, 256, tdfmt, ltm))
> +               if (ztrftime(timebuf, 256, tdfmt, ltm, 0L))
>                     fprintf(f, "%s  ", timebuf);
>             }
>             /* display the time taken by the command, if required */
> diff --git a/Src/prompt.c b/Src/prompt.c
> index 95a7d49..c16d781 100644
> --- a/Src/prompt.c
> +++ b/Src/prompt.c
> @@ -270,6 +270,8 @@ putpromptchar(int doprint, int endchar, unsigned int
> *txtchangep)
>      char *ss, *hostnam;
>      int t0, arg, test, sep, j, numjobs;
>      struct tm *tm;
> +    struct timezone dummy_tz;
> +    struct timeval tv;
>      time_t timet;
>      Nameddir nd;
>
> @@ -636,8 +638,8 @@ putpromptchar(int doprint, int endchar, unsigned int
> *txtchangep)
>                         tmfmt = "%l:%M%p";
>                         break;
>                     }
> -                   timet = time(NULL);
> -                   tm = localtime(&timet);
> +                   gettimeofday(&tv, &dummy_tz);
> +                   tm = localtime(&tv.tv_sec);
>                     /*
>                      * Hack because strftime won't say how
>                      * much space it actually needs.  Try to add it
> @@ -647,7 +649,7 @@ putpromptchar(int doprint, int endchar, unsigned int
> *txtchangep)
>                      */
>                     for(j = 0, t0 = strlen(tmfmt)*8; j < 3; j++, t0*=2) {
>                         addbufspc(t0);
> -                       if (ztrftime(bv->bp, t0, tmfmt, tm) >= 0)
> +                       if (ztrftime(bv->bp, t0, tmfmt, tm, tv.tv_usec) >=
> 0)
>                             break;
>                     }
>                     /* There is enough room for this because addbufspc(t0)
> diff --git a/Src/utils.c b/Src/utils.c
> index cef2abe..aa978e6 100644
> --- a/Src/utils.c
> +++ b/Src/utils.c
> @@ -2710,7 +2710,7 @@ ztrftimebuf(int *bufsizeptr, int decr)
>
>  /**/
>  mod_export int
> -ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm)
> +ztrftime(char *buf, int bufsize, char *fmt, struct tm *tm, long usec)
>  {
>      int hr12;
>  #ifdef HAVE_STRFTIME
> @@ -2729,6 +2729,7 @@ ztrftime(char *buf, int bufsize, char *fmt, struct
> tm *tm)
>      while (*fmt)
>         if (*fmt == '%') {
>             int strip;
> +           int digs = 3;
>
>             fmt++;
>             if (*fmt == '-') {
> @@ -2736,6 +2737,17 @@ ztrftime(char *buf, int bufsize, char *fmt, struct
> tm *tm)
>                 fmt++;
>             } else
>                 strip = 0;
> +           if (idigit(*fmt)) {
> +               /* Digit --- only useful with . */
> +               char *dstart = fmt;
> +               char *dend = fmt+1;
> +               while (idigit(*dend))
> +                   dend++;
> +               if (*dend == '.') {
> +                   fmt = dend;
> +                   digs = atoi(dstart);
> +               }
> +           }
>             /*
>              * Assume this format will take up at least two
>              * characters.  Not always true, but if that matters
> @@ -2745,6 +2757,20 @@ ztrftime(char *buf, int bufsize, char *fmt, struct
> tm *tm)
>             if (ztrftimebuf(&bufsize, 2))
>                 return -1;
>             switch (*fmt++) {
> +           case '.':
> +               if (ztrftimebuf(&bufsize, digs))
> +                   return -1;
> +               if (digs > 6)
> +                   digs = 6;
> +               if (digs < 6) {
> +                   int trunc;
> +                   for (trunc = 5 - digs; trunc; trunc--)
> +                       usec /= 10;
> +                   usec  = (usec + 5) / 10;
> +               }
> +               sprintf(buf, "%0*ld", digs, usec);
> +               buf += digs;
> +               break;
>             case 'd':
>                 if (tm->tm_mday > 9 || !strip)
>                     *buf++ = '0' + tm->tm_mday / 10;
> diff --git a/Src/watch.c b/Src/watch.c
> index 5231579..8dea0b4 100644
> --- a/Src/watch.c
> +++ b/Src/watch.c
> @@ -330,7 +330,7 @@ watchlog2(int inout, WATCH_STRUCT_UTMP *u, char *fmt,
> int prnt, int fini)
>                     }
>                     timet = getlogtime(u, inout);
>                     tm = localtime(&timet);
> -                   ztrftime(buf, 40, fm2, tm);
> +                   ztrftime(buf, 40, fm2, tm, 0L);
>                     printf("%s", (*buf == ' ') ? buf + 1 : buf);
>                     break;
>                 case '%':
>

^ permalink raw reply	[relevance 0%]

* PATCH: assorted completion function updates
@ 2014-08-13 22:30  4% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2014-08-13 22:30 UTC (permalink / raw)
  To: Zsh workers

This adds a new function for dsh. The mosh and nm functions are not
really patches to the existing functions: I've had them in unfinished
form for some time. nm handles options for GNU and Solaris variants
(FreeBSD uses GNU nm). _rsync and _wget is just updates to the list of
options.

Oliver

diff --git a/Completion/Unix/Command/_dsh b/Completion/Unix/Command/_dsh
new file mode 100644
index 0000000..688e024
--- /dev/null
+++ b/Completion/Unix/Command/_dsh
@@ -0,0 +1,33 @@
+#compdef dsh
+
+local curcontext="$curcontext" state line expl
+typeset -A opt_args
+
+_arguments -s -C -S \
+  '(-v --verbose -q --quiet)'{-v,--verbose}'[verbose output]' \
+  '(-q --quiet -v --verbose)'{-q,--quiet}'[quieter output]' \
+  '(-M --show-machine-names)'{-M,--show-machine-names}'[prepend the host name on output]' \
+  '(-i --duplicate-input)'{-i,--duplicate-input}'[duplicate input given to dsh]' \
+  '(-b --bufsize)'{-b,--bufsize}'[change buffer size used in input duplication]:buffer size for -i (bytes)' \
+  '(-m --machine)'{-m,--machine}'[execute on machine]:machine:{_hosts || _user_at_host}' \
+  '(-n --num-topology)'{-n,--num-topology}'[how to divide the machines]:number' \
+  '(-a --all)'{-a,--all}'[execute on all machines]' \
+  '(-g --group)'{-g,--group}'[execute on group member]:groupname:->groups' \
+  '(-f --file)'{-f,--file}'[use the file as list of machines]:file:_files' \
+  '(-r --remoteshell)'{-r,--remoteshell}'[execute using shell]:remote shell:(rsh ssh)' \
+  '(-o --remoteshellopt)'{-o,--remoteshellopt}'[option to give to remote shell ]:option' \
+  '(-)'{-h,--help}'[display help information]' \
+  '(-w --wait-shell -c --concurrent-shell)'{-w,--wait-shell}'[sequentially execute shell]' \
+  '(-c --concurrent-shell -w --wait-shell)'{-c,--concurrent-shell}'[execute shell concurrently]' \
+  '(-F --forklimit)'{-F,--forklimit}'[concurrent with limit on number]:fork limit' \
+  '(-)'{-V,--version}'[display version information]' \
+  '*::args: _normal' && return
+
+if [[ $state = groups ]]; then
+  if ! zstyle -s ":completion:$curcontext:dsh-groups" dsh-groups grp; then
+    [[ -e ~/.dsh/group ]] && grp="~/.dsh/group" || return 1
+  fi
+  _path_files -W ~/.dsh/group && return
+fi
+
+return 1
diff --git a/Completion/Unix/Command/_mosh b/Completion/Unix/Command/_mosh
index c940f90..dacbd10 100644
--- a/Completion/Unix/Command/_mosh
+++ b/Completion/Unix/Command/_mosh
@@ -1,12 +1,26 @@
 #compdef mosh
 
+local curcontext="$curcontext" state line
+local -a suf
+
 _arguments \
-  '--client=:client helper:_command_names -e' \
-  '--server=:server helper:_files' \
-  '--ssh=:ssh command to run:_files' \
-  '(-a -n)--predict=:when:(adaptive always never)' \
-  '(--predict -n)-a[predict always]' \
-  '(--predict -a)-n[predict never]' \
-  {-p,--port=}':port:_ports' \
-  ':remote:_hosts' \
-  ':remote command:_command_names -e'
+  '(-)--help[display help information]' \
+  '(-)--version[display version information]' \
+  "--no-init[don't set terminal init string]" \
+  '--ssh=[specify ssh command to setup session]:ssh command:_normal' \
+  '--port=[specify server-side port range]:port:_sequence -n 2 -s \: _ports' \
+  '(-a -n)--predict=[control speculative local echo]:mode:(adaptive always never)' \
+  '(--predict -n)-a[synonym for --predict=always]' \
+  '(--predict -a)-n[synonym for --predict=never]' \
+  '--server[specify command to run server helper]:remote file:_files' \
+  '--client[specify command to run client helper]:_command_names -e' \
+  '1:remote host name:->userhost' \
+  '*:::args:_normal' && return
+
+case $state in
+  userhost)
+    _hosts || _user_at_host && return
+  ;;
+esac
+
+return 1
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 3ceb8c9..6c95a0d 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -1,30 +1,62 @@
 #compdef nm
 
-# This is a stub.  It's main reason for existence is to offer
-# object files with nm.  Feel free to extend it.  If you do, remove
-# this comment.
+local args files
 
-local state context line expl
-local -A opt_args
-local -a args
-integer ret=1
+_nm_object_file() {
+  [[ -x $REPLY || $REPLY = *.([ao]|so) ]]
+}
 
-if _pick_variant gnu='Free Soft' unix --version; then
-  args+=(-s --)
-fi
-args+=('*:file:->file')
-
-_arguments "$args[@]" && ret=0
+files="*:object file:_path_files -g '*(-.e:_nm_object_file:)'"
+args=(
+  '(-A -o --print-file-name)'{-A,-o,--print-file-name}'[print name of input file on each line]'
+  '(--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))'
+)
 
-case $state in
-  (file)
-  _alternative \
-    "object-files:object file:_path_files -g '*.o'" \
-    "executable-files:executable file:_path_files -g '*(*)'" \
-    "dynamic-libraries:dynamic library:_path_files -g '*.so(.*)#'" \
-    "static-libraries:static library:_path_files -g '*.a'" \
-    "directories:directory:_path_files -g '*(/)'" && ret=0
-  ;;
-esac
+if _pick_variant gnu=GNU unix -V; then
+  compset -P '@' && files='*:options file:_files'
+  args+=(
+    '(- *)--help[display help information]'
+    '(- *)--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)'{-f+,--format=}'[specify output format]:format:(bsd sysv posix)'
+    '(-l --line-numbers)'{-l,--line-numbers}'[display source file and line numbers from debug information]'
+    '(-n --numeric-sort -p --no-sort --size-sort)'{-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 --portability -B -f --format)'{-P,--portability}'[same as --format=posix]'
+    '(-r --reverse-sort -p --no-sort --size-sort)'{-r,--reverse-sort}'[reverse sort order]'
+    '--plugin[load specified plugin]:plugin'
+    '(-u --undefined-only --defined-only)'{-u,--undefined-only}'[display only undefined symbols]'
+    "--target=[target object format]:targets:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
+    '(-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)--size-sort[sort symbols by size]'
+    '--special-syms[include special symbols in the output]'
+    '--synthetic[display synthetic symbols as well]'
+  )
+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]'
+  )
+fi
 
-return ret
+_arguments -s "$args[@]" $files
diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync
index a531d7d..7bad03a 100644
--- a/Completion/Unix/Command/_rsync
+++ b/Completion/Unix/Command/_rsync
@@ -74,7 +74,8 @@ _rsync() {
   _arguments -s \
     '*'{-v,--verbose}'[increase verbosity]' \
     {--no-v,--no-verbose}'[turn off --verbose]' \
-    '--bwlimit=[limit I/O bandwidth]:KBytes (etc.) per second' \
+    '--bwlimit=[limit I/O bandwidth]:limit (KiB per second)' \
+    '--outbuf=[set output buffering]:buffering:(none line block)' \
     '--port=[specify alternate port number]:port:(873)' \
     '--address=[bind to the specified address]:bind address:_bind_addresses' \
     '(-T --temp-dir)'{-T,--temp-dir=}'[create temporary files in specified directory]:directory:_directories' \
@@ -213,6 +214,7 @@ _rsync() {
     '--protocol=[force an older protocol version to be used]:number' \
     '--info=[fine-grained informational verbosity]:comma-separated list' \
     '--debug=[fine-grained debug verbosity]:comma-separated list' \
+    '--msgs2stderr[special output handling for debugging]' \
     '--munge-links[munge symlinks to make them safer, but unusable]' \
     '--ignore-missing-args[ignore missing source args without error]' \
     '--delete-missing-args[delete missing source args from destination]' \
@@ -222,6 +224,7 @@ _rsync() {
     '*'{-M=,--remote-option=}'[send option to the remote side only]:option string' \
     '--preallocate[preallocate the full length of new files]' \
     '--iconv=[request charset conversion of filenames]:number' \
+    '--checksum-seed=:number' \
     '--read-batch=[read a batched update from the specified file]:file:_files'
 }
 
diff --git a/Completion/Unix/Command/_wget b/Completion/Unix/Command/_wget
index f709a08..b8ca2fd 100644
--- a/Completion/Unix/Command/_wget
+++ b/Completion/Unix/Command/_wget
@@ -14,6 +14,7 @@ _arguments -C -s \
   '(--quiet -q --verbose -v --no-verbose -nv)'{--quiet,-q}'[turn off output]' \
   '(--quiet -q --verbose -v --no-verbose -nv)'{--verbose,-v}'[turn on verbose output]' \
   '*-n+[turn off flags]:flags:->noflags' \
+  '--report-speed=:type:(bits)' \
   '(--input-file -i)'{--input-file=,-i+}'[specify input file]:file containing URLs:_files' \
   '(--force-html -F)'{--force-html,-F}'[treat input file as html]' \
   '(--base -B)'{--base=,-B+}'[prepend URL to relative links]:base URL:_urls' \
@@ -47,6 +48,7 @@ _arguments -C -s \
   '--prefer-family[connect first to addresses of specified family]:address family:(IPv6 IPv4 none)' \
   '(--http-user --ftp-user)--user[set both ftp and http user]:user' \
   '(--http-password --ftp-password)--password[set both ftp and http password]:password' \
+  '(--password --http-password --ftp-password)--ask-password:[prompt for passwords]' \
   '--no-iri[turn off IRI support]' \
   '--local-encoding=[specify local encoding for IRIs]:encoding' \
   '--remote-encoding=[specify default remote encoding]:encoding' \
@@ -56,12 +58,13 @@ _arguments -C -s \
   '(--directory-prefix -P)'{--directory-prefix=,-P+}'[specify prefix to save files to]:prefix:_files -/' \
   '--cut-dirs=:number:' \
   '(--user)--http-user=:user' \
-  '(--password)--http-password=:password' \
+  '(--password --ask-password)--http-password=:password' \
   '--no-cache[disallow server-cached data]' \
   '--default-page=[specify default page name, normally index.html]' \
   '(--adjust-extension -E)'{--adjust-extension,-E}'[save all HTML/CSS documents with proper extensions]' \
   "--ignore-length[ignore \`Content-Length' header field]" \
   '*--header=:string' \
+  '--max-redirect=:number' \
   '--proxy-user=:user' \
   '--proxy-password=:password' \
   '--referer=:URL:_urls' \
@@ -74,9 +77,14 @@ _arguments -C -s \
   '--keep-session-cookies[load and save session cookies]' \
   '--post-data=[use the POST method with specified data]:data to send' \
   '--post-file=[use the POST method; sending contents of a file]:file:_files' \
+  '--method=[use specified HTTP method]:method:(GET POST HEAD DELETE)' \
+  '(--body-file)--body-data=[send string as data]:string' \
+  '(--body-data)--body-file=[send contents of file]:file:_files' \
   '--content-disposition[honor the Content-Disposition header when choosing local file names]'  \
+  '--content-on-error[output received content on server errors]' \
   "--auth-no-challenge[send basic HTTP authentication without first waiting for server's challenge]" \
   '--secure-protocol=[choose secure protocol]:protocol:(SSLv2 SSLv3 TLSv1)' \
+  --https-only \
   "--no-check-certificate=[don't check the server certificate]" \
   '--certificate=[specify client certificate]:client certificate file:_files' \
   '--certificate-type=[specify client certificate type]:certificate type:(PEM DER)' \
@@ -87,22 +95,27 @@ _arguments -C -s \
   '--random-file[specify file with random data for seeding generator]:file:_files' \
   '--egd-file=[specify filename of EGD socket]:file:_files' \
   '(--user)--ftp-user=:user' \
-  '(--password)--ftp-password=:password' \
+  '(--password --ask-password)--ftp-password=:password' \
   "--no-remove-listing[don't remove \`.listing' files]" \
   '--no-glob[turn off FTP file name globbing]' \
   '--no-passive-ftp' \
-  '--retr-symlinks' \
   '--preserve-permissions[preserve remote file permissions with ftp]' \
+  '--retr-symlinks' \
+  '--warc-file=:file:_files' --warc-header=:string --warc-max-size=:number \
+  --warc-cdx --warc-dedup=:file:_files --no-warc-compression --no-warc-digests \
+  --no-warc-keep-log --warc-tempdir=:directory:_directories \
   '(--recursive -r)'{--recursive,-r}'[recurse subdirectories]' \
   '(--level -l)'{--level=,-l+}'[specify maximum recursion depth]:level' \
   '--delete-after' \
   '(--convert-links -k)'{--convert-links,-k}'[convert links to be relative]' \
+  '--backups=:max backups' \
   '(--backup-converted -K)'{--backup-converted,-K}'[backup files before conversion]' \
   '(--mirror -m -r -N -l)'{--mirror,-m}'[mirror (-r -N -l inf --no-remove-listing)]' \
   '(--page-requisites -p)'{--page-requisites,-p}'[get all images needed to display page]' \
   '--strict-comments[turn on strict (SGML) handling of HTML comments]' \
   '(--accept -A)'{--accept=,-A+}'[specify accepted extensions]:extensions' \
   '(--reject -R)'{--reject=,-R+}'[specify rejected extensions]:extensions' \
+  --{accept,reject}-regex=:regex '--regex-type=:regex type:(posix pcre)' \
   '(--domains -D)'{--domains=,-D+}'[specify accepted domains]:domains:_domains' \
   '--exclude-domains=:rejected domains:_domains' \
   '--follow-ftp' \


^ permalink raw reply	[relevance 4%]

* Re: zsh got stuck without any message because of history lock file
  @ 2014-09-06 18:51  2%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-09-06 18:51 UTC (permalink / raw)
  To: zsh workers

On Sep 6, 11:03am, Mikael Magnusson wrote:
}
} > I'm not 100% sure it's because of this change, but recently, I've had
} > new terminals stuck forever on startup until I exit all open terminals
} > logged in as that user (or possibly just a specific one of them). It
} > happens very spuriously, maybe a few times per week. I have
} > histfcntllock set. On one occasion I tried moving the .history file
} > instead of exiting, and this also immediately unstuck all new
} > terminals.
} 
} I'm still seeing reports of this every now and then in #zsh (and I
} have the option unset so I'm not sure if it happens to me anymore.) If
} nobody fixed this, it's probably still a problem.

So, a few things.

The unlockhistfile() operation assumes that closing the flock_fd is
enough to release the lock.  I can't quote chapter and verse for this
from e.g. the POSIX spec, but I believe that to be correct.

However, lockhistfile() does not call flockhistfile() when it has
already been locked (flock_fd >= 0), and in that case it falls through
to file-based locking again.  This isn't a problem except when hend()
is deciding whether to call savehistfile(); it only considers whether
the file is already locked in the case of SHARE_HISTORY, but may call
savehistfile() for both SHARE_HISTORY and INC_APPEND_HISTORY et al.,
and savehistfile() calls lockhistfile() again.

Additionally, lockhistfile() only increments the lockhistct counter
when file locking, not when fcntl locking, which leads to an incorrect
answer from histfileIsLocked().

So I think there's a potential problem where INC_APPEND_HISTORY could
apply both locking mechanisms at different times, leading to a race.

These were all assumptions about both kinds of locking being applied
that I missed before.  The "better performance" from HIST_FCNTL_LOCK
I guess just mean that it would fail faster on permission problems or
lock collisions, not that it would improve performance overall.

We can either apply the additional patch below, or back out some of
the last one to restore the "always locks both ways" behavior.


diff --git a/Src/hist.c b/Src/hist.c
index 770d559..d29a65a 100644
--- a/Src/hist.c
+++ b/Src/hist.c
@@ -2490,6 +2490,9 @@ flockhistfile(char *fn, int keep_trying)
     struct flock lck;
     int ctr = keep_trying ? 9 : 0;
 
+    if (flock_fd >= 0)
+	return 0; /* already locked */
+
     if ((flock_fd = open(unmeta(fn), O_RDWR | O_NOCTTY)) < 0)
 	return errno == ENOENT ? 0 : 2; /* "successfully" locked missing file */
 
@@ -2768,12 +2771,6 @@ lockhistfile(char *fn, int keep_trying)
     if (!fn && !(fn = getsparam("HISTFILE")))
 	return 1;
 
-#ifdef HAVE_FCNTL_H
-    if (isset(HISTFCNTLLOCK) && flock_fd < 0) {
-	return flockhistfile(fn, keep_trying);
-    }
-#endif
-
     if (!lockhistct++) {
 	struct stat sb;
 	int fd;
@@ -2786,6 +2783,11 @@ lockhistfile(char *fn, int keep_trying)
 # endif
 #endif
 
+#ifdef HAVE_FCNTL_H
+	if (isset(HISTFCNTLLOCK))
+	    return flockhistfile(fn, keep_trying);
+#endif
+
 	lockfile = bicat(unmeta(fn), ".LOCK");
 	/* NOTE: only use symlink locking on a link()-having host in order to
 	 * avoid a change from open()-based locking to symlink()-based. */


^ permalink raw reply	[relevance 2%]

* POSIX_ARGZERO: not POSIX compliant in sourced script?!
@ 2014-09-11 20:07 10% Daniel Hahler
  2014-09-12  3:59  9% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Daniel Hahler @ 2014-09-11 20:07 UTC (permalink / raw)
  To: Zsh Hackers' List

The option POSIX_ARGZERO (added in 19f3161 for zsh 5.0.5) does not appear to be fully POSIX compliant when being used in a sourced file.

I don't know how POSIX defines it, but at least dash (and bash) behave differently.

Given the following files:

cat > test.sh <<EOF
#!/bin/sh
. ./test_sourced.sh
EOF


cat > test_sourced.sh <<EOF
echo $0

if [ -n "$ZSH_VERSION" ]; then
  setopt posixargzero
  echo $0
fi
EOF


The second $0 with zsh should be "test.sh", and not "zsh":

% zsh test.sh
test_sourced.sh
zsh

% sh test.sh
test.sh
test.sh

% ./test.sh
./test.sh


The same applies when using zsh in the shebang line, and executing the script (I was under the impression that this would work better, but it does not):

cat > test.sh <<EOF
#!/usr/bin/env zsh
. ./test_sourced.sh
EOF

% ./test.sh
test_sourced.sh
zsh


Regards,
Daniel.


^ permalink raw reply	[relevance 10%]

* Re: POSIX_ARGZERO: not POSIX compliant in sourced script?!
  2014-09-11 20:07 10% POSIX_ARGZERO: not POSIX compliant in sourced script?! Daniel Hahler
@ 2014-09-12  3:59  9% ` Bart Schaefer
  2014-09-14  1:03  5%   ` Daniel Hahler
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-09-12  3:59 UTC (permalink / raw)
  To: Daniel Hahler, Zsh Hackers' List

On Sep 11, 10:07pm, Daniel Hahler wrote:
}
} The option POSIX_ARGZERO (added in 19f3161 for zsh 5.0.5) does not
} appear to be fully POSIX compliant when being used in a sourced file.

Hrm.  Well, it was implemented the way it was described to us, but it
seems we need the following instead?


diff --git a/Src/init.c b/Src/init.c
index 5e92f59..d536978 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -252,8 +252,9 @@ parseargs(char **argv, char **runscript)
     paramlist = znewlinklist();
     if (*argv) {
 	if (unset(SHINSTDIN)) {
+	    posixzero = *argv;
 	    if (cmd)
-		argzero = posixzero = *argv;
+		argzero = *argv;
 	    else
 		*runscript = *argv;
 	    opts[INTERACTIVE] &= 1;

-- 
Barton E. Schaefer


^ permalink raw reply	[relevance 9%]

* Re: POSIX_ARGZERO: not POSIX compliant in sourced script?!
  2014-09-12  3:59  9% ` Bart Schaefer
@ 2014-09-14  1:03  5%   ` Daniel Hahler
  0 siblings, 0 replies; 200+ results
From: Daniel Hahler @ 2014-09-14  1:03 UTC (permalink / raw)
  To: Zsh Hackers' List

Thanks for fixing this!

(Reference: Git commit 03e53c8)


Regards,
Daniel.

On 12.09.2014 05:59, Bart Schaefer wrote:
> On Sep 11, 10:07pm, Daniel Hahler wrote:
> }
> } The option POSIX_ARGZERO (added in 19f3161 for zsh 5.0.5) does not
> } appear to be fully POSIX compliant when being used in a sourced file.
> 
> Hrm.  Well, it was implemented the way it was described to us, but it
> seems we need the following instead?
> 
> 
> diff --git a/Src/init.c b/Src/init.c
> index 5e92f59..d536978 100644
> --- a/Src/init.c
> +++ b/Src/init.c
> @@ -252,8 +252,9 @@ parseargs(char **argv, char **runscript)
>      paramlist = znewlinklist();
>      if (*argv) {
>  	if (unset(SHINSTDIN)) {
> +	    posixzero = *argv;
>  	    if (cmd)
> -		argzero = posixzero = *argv;
> +		argzero = *argv;
>  	    else
>  		*runscript = *argv;
>  	    opts[INTERACTIVE] &= 1;
> 


^ permalink raw reply	[relevance 5%]

* Fwd: Surprising parsing result with anonymous functions and for loops
       [not found]     ` <CAKjp4B7Gy9f2RCYzn8G6i+ADh_p7GWZEv1x_Cd0eR3Ggxv+APw@mail.gmail.com>
@ 2014-09-24 19:14  4%   ` Clint Hepner
  0 siblings, 0 replies; 200+ results
From: Clint Hepner @ 2014-09-24 19:14 UTC (permalink / raw)
  To: zsh-workers

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

I meant to reply to the list, but only replied to Mikael instead.

---------- Forwarded message ----------
From: Clint Hepner <clint.hepner@gmail.com>
Date: Wed, Sep 24, 2014 at 3:11 PM
Subject: Re: Surprising parsing result with anonymous functions and for
loops
To: Mikael Magnusson <mikachu@gmail.com>


The POSIX standard defines a function definition as

    <name>  () <compound-statement>

where { ...; } is just one kind of compound statement, along with for
loops, while loops, etc. The following are all valid function definitions:

    foo () { echo bar; }
    foo () while [[ $i != foo ]]; do i=foo; done
    foo () for i in 1 2 3; do echo $i; done
    foo () ( echo bar; )
    foo () (( x=3 ))

The man page is ambiguous about what constitutes a function; it lists three
allowable forms:

       function word ... [ () ] [ term ] { list }
       word ... () [ term ] { list }
       word ... () [ term ] command

where the third is the one that describes the observed behavior.  I thought
the first might imply
special behavior when using the function keyword, but

    function foo (( x = 3))

works as well. The second is would seem to be a special case of the third,
except it does seem to treat the braces as part of the syntax:

    foo () { echo foo }

would in POSIX require a semicolon prior to the closing brace, but works in
zsh.

On Wed, Sep 24, 2014 at 10:07 AM, Mikael Magnusson <mikachu@gmail.com>
wrote:

> The intended command was something along these lines:
> () { for a { echo $a } } some words here
> but I forgot the enclosing { } and wrote the following
> () for a { echo $a } some words here
> surely this doesn't work, right?... wrong:
> % () for a { echo $a } some words here
> some
> words
> here
>
> Perhaps even more surprising is the following:
> % () for a { echo $a } ls
> ls
> --color=auto
> -T
> 0
> -A
> -v
> --quoting-style=shell
>
> I haven't looked at the parsing for the anonymous function stuff, but
> if it's not too hairy to fix, my vote is we drop this easter egg at
> some point.
>
> --
> Mikael Magnusson
>

^ permalink raw reply	[relevance 4%]

* Re: Surprising parsing result with anonymous functions and for loops
  @ 2014-09-25  5:53  3%       ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-09-25  5:53 UTC (permalink / raw)
  To: zsh workers

> The presence of braces around the entire body simply allows the parser
> to distinguish the body from the arguments.  If there are other
> syntactic clues, those also distinguish body from arguments

Incidentally, I think this is related to zsh's non-standard handling
of redirections following a function definition.  POSIX says that

foo() { echo foo; } >/tmp/foo

should behave the same as

foo() { { echo foo; } >/tmp/foo }

but in zsh it behaves like

{ foo() { echo foo; } } >/tmp/foo


^ permalink raw reply	[relevance 3%]

* PATCH: fix return status of completion functions
@ 2014-10-14 20:32  1% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2014-10-14 20:32 UTC (permalink / raw)
  To: Zsh workers

I went through the completion functions looking for cases where the
return status is not correctly being passed on to indicate whether
matches were added. This fixes nearly all the cases I found. An
incorrect return status mostly affects approximate completion.
There are still issues with _arguments when the prefix-needed
style is set to false; I use the following to allow approximate
completion to make corrections to mistakes in the prefix.
  zstyle ':completion::approximate*:*' prefix-needed false

_call_function usage seems to be wrong almost as often as not. It could
perhaps use an option to indicate that it should only set the return
parameter if status was 0 so we don't end up with things like
ret=$(( ret && fret )) following it. Perhaps -o for OR (which is perhaps
confusing given that in math evaluation, it'd be an AND).

We're not that consistent in the fallback handling either.
_call_function is often used for dispatching to functions for
subcommands. Traditionally we handled an unknown subcommand with a
message like:
  _message "unknown cvs command: $words[1]"
Experience has shown that it is perhaps better to call _default. I
rather like the idea in _git of checking a use-fallback style. Perhaps
this logic could go in _call_function itself to get wider use? Something
like:
  _call_function -e "unknown subcommand" _$service-$words[1]
This could check use-fallback and call either _default or _message and
then return a conventional status.

Inevitably these fixes resulted in my getting sidetracked into fixing
other issues in many instances. Bad handling of zstyle contexts
with _arguments/_values is also common.

Oliver

diff --git a/Completion/Debian/Command/_apt-move b/Completion/Debian/Command/_apt-move
index a72378e..6911ef6 100644
--- a/Completion/Debian/Command/_apt-move
+++ b/Completion/Debian/Command/_apt-move
@@ -1,6 +1,6 @@
 #compdef apt-move
 
-local curcontext="$curcontext" state line cmds ret=1
+local curcontext="$curcontext" state line expl cmds ret=1
 typeset -A opt_args
 
 _arguments -C \
@@ -45,7 +45,10 @@ case $state in
         _files -g "*.d(sc|eb)(-.)" && ret=0
       ;;
       listbin)
-        _wanted lists expl list compadd mirror sync repo
+        _wanted lists expl list compadd mirror sync repo && ret=0
+      ;;
+      *)
+	_default && ret=0
       ;;
     esac
   ;;
diff --git a/Completion/Debian/Command/_bts b/Completion/Debian/Command/_bts
index 4907d15..9f1f77b 100644
--- a/Completion/Debian/Command/_bts
+++ b/Completion/Debian/Command/_bts
@@ -40,10 +40,12 @@ case "$words[1]" in
   ;;
   (show|bugs)
     if [[ CURRENT -eq 2 ]]; then
-      _wanted package expl 'package' _deb_packages avail
-      _wanted maintainer expl 'package maintainer' compadd $DEBEMAIL
+      _alternative \
+	'packages:package:_deb_packages avail' \
+        "emails:package maintainer:compadd $DEBEMAIL"
+    else
+      _wanted sep expl 'separator' compadd -S ' ' , .
     fi
-    _wanted sep expl 'separator' compadd -S ' ' , .
   ;;
   reopen)
     if [[ CURRENT -eq 2 ]]; then
diff --git a/Completion/Linux/Command/_sysstat b/Completion/Linux/Command/_sysstat
index 60de9d8..2a7128c 100644
--- a/Completion/Linux/Command/_sysstat
+++ b/Completion/Linux/Command/_sysstat
@@ -4,80 +4,73 @@
 # sysstat-nfsiostat - there seems to be two nfsiostat(1)s. one from oracle and one by redhat.
 
 _mpstat() {
-  local ret=1
   _arguments : \
     '-A[equivalent to -u -I ALL -P ALL]' \
-    '-I[report interrupt statistics]:interrupts:(SUM CPU SCPU ALL)' \
-    '-P[specify processor number]:processor: _values -s "," processor ON ALL' \
+    '-I[report interrupt statistics]:interrupt:(SUM CPU SCPU ALL)' \
+    '-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:_guard "[0-9]#" "interval"' \
-    '2:count:_guard "[0-9]#" "count"' && ret=0
-  return ret
+    '1:interval' \
+    '2:count'
 }
 
 _iostat() {
-  local ret=1
   _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: _message "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]' \
-    '1:interval:_guard "[0-9]#" "interval"' \
-    '2:count:_guard "[0-9]#" "count"' && ret=0
-  return ret
+    '::device:_files -W /dev -g "*(-%)"' \
+    ': :_guard "[0-9]#" "interval"' \
+    ':count'
 }
 
 _cifsiostat() {
-  local ret=1
   _arguments : \
     '-h[human readable]' \
     '(-m)-k[display statistics in kB/s]' \
     '(-k)-m[display statistics in MB/s]' \
     '-t[print timestamp for each report]' \
     '-V[print version number]' \
-    '1:interval:_guard "[0-9]#" "interval"' \
-    '2:count:_guard "[0-9]#" "count"' && ret=0
-  return ret
+    '1:interval' \
+    '2:count'
 }
 
 _isag() {
-  local ret=1 
   _arguments : \
-    '-p[Pathname to daily data files]:data files: _files -/' \
-    '-c[Specify configuration file]:configuration file: _files' \
-    '-ght[Specify height of the chart]:height: _message "height"' \
-    '-gwd[Specify width of the chart]:width: _message "width"' && ret=0
-  return ret
+    '-p[specify path to daily data files]:path:_files -/' \
+    '-c[specify configuration file]:configuration file:_files' \
+    '-ght[specify height of the chart]:height' \
+    '-gwd[specify width of the chart]:width'
 }
 
 _sadf() {
-  local ret=1 line state context expl
-  typeset -A opt_args
+  local ret=1
   # any options after `--' are for sar(1)
   if ! (( CURRENT > $words[(i)--] )); then
     _arguments : \
       '-C[display comments in file]' \
       '(-j -p -x)-d[output file in SQL format]' \
-      '-e[set ending time of report]:ending time: _message "ending time in localtime(HH\:MM\:SS 24-hour format)"' \
+      '-e[set ending time of report]:ending time (HH\:MM\:SS)' \
       '-H[display only the header of the report]' \
       '(-j -p -x)-h[print on a single line when used with -d]' \
       '(-d -p -x)-j[output file in JSON]' \
       '-P[restrict processor dependant statistics]:processor number(zero indexed) or ALL:(ALL)' \
       '(-j -x -d)-p[print in format parsable by tools like awk]' \
-      '-s[set starting time of report]:starting time: _message "starting time in localtime(HH\:MM\:SS 24-hour format)"' \
+      '-s[set starting time of report]:starting time (HH\:MM\:SS)"' \
       '(-t -U)-T[display timestamp in local time]' \
       '(-T -U)-t[display timestamp in file\''s original localtime]' \
-      '(-t -T)-U[display in seconds from epoch(UTC)]' \
+      '(-t -T)-U[display in seconds since epoch (UTC)]' \
       '-V[print version number]' \
       '(-j -d -p)-x[output file in XML]' \
-      '1:interval:_guard "[0-9]#" "interval"' \
-      '2:count:_guard "[0-9]#" "count"' && ret=0 
+      '1:interval' \
+      '2:count' \
+      '3:data file:_files' && ret=0
   else
     _arguments : '*::sar: _sar' && ret=0
   fi
@@ -85,20 +78,19 @@ _sadf() {
 }
 
 _sar() {
-  local ret=1 
   _arguments : \
     '-A[equivalent to -bBdFHqrRSuvwWy -I SUM -I XALL -m ALL -n ALL -u ALL -P ALL]' \
     '-B[report paging statistics]' \
     '-b[report I/O and transfer rate statistics]' \
     '-C[display comments from sadc]' \
     '-d[report activity for each block device]' \
-    '-e[set ending time of report]:ending time: _message "ending time (HH\:MM\:SS 24-hour format)"' \
+    '-e[set ending time of report]:ending time (HH\:MM\:SS)' \
     '-F[display statistics for mounted filesystems]' \
     '-f[extract records from file]:record:_files' \
     '-H[report hugepages utilization]' \
     '-h[display help]' \
     '*-I[report statistics for interrupts]:interrupts: _values -s "," interrupts 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 SUM ALL XALL' \
-    '-i[select records as close as possible to interval]:interval: _message "interval"' \
+    '-i[select records as close as possible to interval]:interval' \
     '-j[display persistent device names]:type:(ID LABEL PATH UUID)' \
     '-m[report power management statistics]:keywords: _values -s "," keywords CPU FAN FREQ IN TEMP USB ALL' \
     '-n[report network statistics]:keywords: _values -s "," keywords DEV EDEV NFS NFSD SOCK IP EIP ICMP EICMP TCP ETCP UDP SOCK6 IP6 EIP6 ICMP6 EICMP6 UDP6 ALL' \
@@ -108,27 +100,25 @@ _sar() {
     '-R[report memory statistics]' \
     '-r[report memory utilization statistics]' \
     '-S[report swap space utilization]' \
-    '-s[set starting time of report]:start time: _message "start time (HH\:MM\:SS 24-hour format)"' \
+    '-s[set starting time of report]:start time (HH\:MM\:SS)' \
     '-u[report CPU utilization]: :(ALL)' \
     '-V[print version number]' \
     '-v[report status of kernel tables]' \
     '-W[report swapping statistics]' \
     '-w[report task creation and system switching activity]' \
     '-y[report TTY device activity]' \
-    '1:interval:_guard "[0-9]#" "interval"' \
-    '2:count:_guard "[0-9]#" "count"' && ret=0
-  return ret
+    '1:interval' \
+    '2:count'
 }
 
 _pidstat() {
-  local ret=1
   _arguments : \
-    '-C[filter tasks by string]:task: _message "string or regex"' \
+    '-C[filter tasks by string]:task filter' \
     '-d[report I/O statistics]' \
     '-h[display on horizontally]' \
     '-I[divide CPU usage by number of processors]' \
     '-l[display process name along with arguments]' \
-    '-p[select pid]:pid: _pids' \
+    '-p[select pid]:pid: _sequence _pids' \
     '-r[report page faults and memory]' \
     '-s[report stack utilization]' \
     '-T[specifies what to monitor]:type:(TASK CHILD ALL)' \
@@ -137,14 +127,13 @@ _pidstat() {
     '-u[report cpu utilization]' \
     '-V[print version number]' \
     '-v[display values from kernel table]' \
-    '-w[report task switching activity]' && ret=0
-  return ret
+    '-w[report task switching activity]' \
+    ':interval' ':count'
 }
 
 _sysstat() {
-  local ret=1                 
-  _call_function ret _$service
-  return ret                  
-}                             
+  local ret
+  _call_function ret _$service && return ret
+}
 
 _sysstat "$@"
diff --git a/Completion/Mandriva/Command/_urpmi b/Completion/Mandriva/Command/_urpmi
index 2468b23..7951e6a 100644
--- a/Completion/Mandriva/Command/_urpmi
+++ b/Completion/Mandriva/Command/_urpmi
@@ -1,24 +1,8 @@
 #compdef urpme urpmi urpmi.addmedia urpmi.removemedia urpmi.update urpmq urpmf parsehdlist
 
 _urpmi_media() {
-  local ret=1  single=0
-  local -a all_sources opts
-
-  if [[ $1 = -s ]]; then
-    single=1
-    shift
-  fi
-
   # TODO should we probe for active media only?
-  all_sources=( ${(f)"$(urpmq --list-media 2> /dev/null)"} )
-  
-  if (( single )); then
-    compadd "$expl[@]" -a all_sources && ret=0
-  else
-    _values -s , 'urpmi media' "$all_sources[@]" && ret=0
-  fi
-
-  return $ret
+  compadd "$@" - ${(f)"$(urpmq --list-media 2> /dev/null)"}
 }
 
 _urpmi_rpms() {
@@ -40,7 +24,7 @@ _urpmi_rpms() {
 
     _requested files expl '(S)RPM file' \
       _files -g '*.(#i)rpm(-.)' && ret=0
-  
+
     (( ret )) || break
   done
 
@@ -65,12 +49,12 @@ _urpmi_media_url() {
     fi
   fi
 
-  return $ret
+  return ret
 }
 
 _urpme_package() {
   local -a _rpms
-  _rpms=( $(_call_program packages rpm -qa 2>/dev/null) )
+  _rpms=( $(_call_program packages rpm -qa) )
   compadd "$@" -a _rpms
 }
 
@@ -80,12 +64,11 @@ _urpmi_parallel_alias() {
 }
 
 _urpmi() {
-  local state context line ret=1 help="--help -h"
-
-  local -a opts_help  opts_net opts_verbose opts_inst_rem opts_search opts_media
+  local ret=1 help="--help -h"
+  local -a opts_help opts_net opts_verbose opts_inst_rem opts_search opts_media
 
   opts_help=(
-    "($help : -)"{--help,-h}"[print usage information]"
+    "(: -)"{--help,-h}"[print usage information]"
   )
 
   opts_net=(
@@ -116,10 +99,10 @@ _urpmi() {
   )
 
   opts_media=(
-    "($help)--excludemedia[do not use the given media]:urpmi media: _urpmi_media"
-    "($help --update --use-distrib)--media[use only the media listed by comma]:urpmi media: _urpmi_media"
-    "($help)--searchmedia[use only the given media to search requested (or updated) packages]:urpmi media: _urpmi_media -s"
-    "($help)--sortmedia[sort media according to substrings separated by comma]:urpmi media: _urpmi_media"
+    "($help)--excludemedia[do not use the given media]:urpmi media:_sequence _urpmi_media"
+    "($help --update --use-distrib)--media[use only the media listed by comma]:urpmi media:_sequence _urpmi_media"
+    "($help)--searchmedia[use only the given media to search requested (or updated) packages]:urpmi media:_urpmi_media"
+    "($help)--sortmedia[sort media according to substrings separated by comma]:urpmi media:_sequence _urpmi_media"
     "($help)--synthesis[use the given synthesis instead of urpmi db]:synthesis file:_url"
     "($help --media --use-distrib)--update[use only update media]"
     "($help --media --update)--use-distrib[configure urpmi on the fly from a distrib tree]:installation media:_urpmi_media_url"
@@ -132,7 +115,7 @@ _urpmi() {
         $opts_inst_rem \
 	"--auto[do not ask any question]" \
 	"-v[verbose]" \
-	": :_urpme_package"
+	": :_urpme_package" && ret=0
     ;;
     urpmi.addmedia )
       _arguments -A '-*' \
@@ -165,7 +148,7 @@ _urpmi() {
 	"($help :)-a[select all media]" \
 	"($help)-c[clean headers cache directory]" \
 	"($help)-y[fuzzy mathing on media names]" \
-	"(-a)"{,\*}": : _urpmi_media" \
+	"(-a)"{,\*}":media:_sequence _urpmi_media" \
        && ret=0
     ;;
     urpmi.update )
@@ -179,7 +162,7 @@ _urpmi() {
 	"($help --update :)-a[select all non-removable media]" \
 	"($help)-c[clean /var/cache/urpmi/headers on exit]" \
 	"($help)*-f[force generation of hdlist files]" \
-	"($help -a)"{,\*}": : _urpmi_media" \
+	"($help -a)"{,\*}":media:_sequence _urpmi_media" \
        && ret=0
     ;;
     urpmi )
@@ -308,7 +291,7 @@ _urpmi() {
     ;;
   esac
 
-  return $ret
+  return ret
 }
 
 _urpmi "$@"
diff --git a/Completion/Redhat/Command/_rpm b/Completion/Redhat/Command/_rpm
index 83922b6..696c12f 100644
--- a/Completion/Redhat/Command/_rpm
+++ b/Completion/Redhat/Command/_rpm
@@ -122,7 +122,7 @@ _rpm () {
     query)
       # --dump requires one of -{l,c,d}
       # --triggers requires --script
-      _arguments -s \
+      _arguments -s -C \
 	\!{-q,--query} "${commonopts[@]}" "${selectopts[@]}" "${pathopts[@]}" \
 	"($sopts)--specfile[query specified spec file as if it were a package]" \
 	'(-i --info)'{-i,--info}'[display package information]' \
@@ -140,10 +140,10 @@ _rpm () {
 	{--triggers,--triggerscripts}'[show trigger scripts]' && ret=0
       ;;
     setattrs)
-      _arguments -s --set{perm,ugids} "${selectopts[@]}" && ret = 0
+      _arguments -s -C --set{perm,ugids} "${selectopts[@]}" && ret=0
       ;;
     verify)
-      _arguments -s \!-{y,V} \
+      _arguments -s -C \!-{y,V} \
 	"${commonopts[@]}" "${selectopts[@]}" "${pathopts[@]}" \
 	--no{deps,files,scripts,digest,signature,linkto,md5,size,user,group,mtime,mode,rdev} && ret=0
       ;;
@@ -151,7 +151,7 @@ _rpm () {
       tmp=( '(--force)--oldpackage' )
       ;&
     install)
-      _arguments -s \!-{i,U} "$tmp[@]" \
+      _arguments -s -C \!-{i,U} "$tmp[@]" \
 	"${commonopts[@]}" "${pathopts[@]}" \
 	'--excludepath:file to exclude:_files -/' \
 	'--relocate:relocate:->relocate' \
@@ -165,7 +165,7 @@ _rpm () {
 	'*:pkg file:->package_file' && ret=0
       ;;
     uninstall)
-      _arguments -s \!-e \
+      _arguments -s -C \!-e \
 	"${commonopts[@]}" "${pathopts[@]}" \
 	--{allmatches,justdb,repackage,test} \
 	--no{deps,scripts,preun,postun,trigger{s,un,postun}} \
@@ -177,7 +177,7 @@ _rpm () {
     build_t)
       (( $#tmp )) || tmp=( '*:tar file:_files -g "*.(#i)tar(.*|)(-.)"' )
 
-      _arguments -s \
+      _arguments -s -C \
 	"${commonopts[@]}" "${pathopts[@]}" \
 	--{short-circuit,clean,nobuild,rmsource,sign,test} \
 	'--target:specify a build target:->target'\
@@ -187,13 +187,13 @@ _rpm () {
 	'--timecheck:time check (seconds):' "$tmp[1]" && ret=0
       ;;
     sigcheck)
-      _arguments -s \!-K \
+      _arguments -s -C \!-K \
 	"${commonopts[@]}" \
 	--no{gpg,pgp,md5,signature,digest} \
 	'*:package file:->package_file' && ret=0
       ;;
     rebuild)
-      _arguments -s \
+      _arguments -s -C \
 	"${commonopts[@]}" "${pathopts[@]}" \
 	'*:source package file:->package_file' && ret=0
       ;;
@@ -286,7 +286,7 @@ _rpm () {
       ;;
     capabilities)
       _wanted capabilities expl capability compadd \
-	  ${(f)"$(_call_program capabilities rpm -qa --queryformat '%\{requirename}\\n' 2>/dev/null)"}
+	  ${(f)"$(_call_program capabilities rpm -qa --queryformat '%\{requirename}\\n' 2>/dev/null)"} && ret=0
       ;;
     relocate)
       if compset -P '*='; then
diff --git a/Completion/Solaris/Command/_ptree b/Completion/Solaris/Command/_ptree
index 035614b..754979c 100644
--- a/Completion/Solaris/Command/_ptree
+++ b/Completion/Solaris/Command/_ptree
@@ -1,23 +1,7 @@
 #compdef ptree
 
-_ptree() {
-	local curcontext="$curcontext" context state line ret=1
-	typeset -A opt_args
-
-	_arguments -s \
-		'-a[all processes]' \
-		'-c[show contract memberships]' \
-		'-z[show processes in zone]:zone:($(zoneadm list))' \
-		'*:pid or user:->pidoruser' && ret=0
-
-	if [[ $ret -ne 0 ]]; then
-		_alternative \
-			'users:logged-in user:compadd ${$(who -q)\:#(users=*|\#)}' \
-			'pids:pid:_pids'
-		ret=$?
-	fi
-
-	return $ret
-}
-
-_ptree "$@"
+_arguments -s \
+  '-a[all processes]' \
+  '-c[show contract memberships]' \
+  '-z[show processes in zone]:zone:_zones' \
+  '*: : _alternative "users:logged-in user:_users_on" "pids:pid:_pids"'
diff --git a/Completion/Unix/Command/_arp b/Completion/Unix/Command/_arp
index 64a8b80..f340e97 100644
--- a/Completion/Unix/Command/_arp
+++ b/Completion/Unix/Command/_arp
@@ -1,6 +1,6 @@
 #compdef arp
 
-local state line expl curcontext="$curcontext"
+local state line expl curcontext="$curcontext" ret=1
 local -a cmds
 
 cmds=(-a --display -d --delete -s --set -f --file)
@@ -15,7 +15,9 @@ _arguments -C \
   '(-H --hw-type -d --delete)'{-H,--hw-type}'[class of entries to check for]:class:(ether arcnet pronet ax25 netrom)' \
   '(-n --numeric -d --delete -s --set -f --file)'{-n,--numeric}'[shows numerical addresses]' \
   '(-v --verbose)'{-v,--verbose}'[be verbose]' \
-  '(-a)1:host:->hostintable'
+  '(-a)1:host:->hostintable' && ret=0
 
 [[ "$state" = hostintable ]] &&
-  _wanted hosts expl 'host' compadd ${${${(f)"$(${words[1]} -an)"}##[ ?(]#}%%[ )]*}
+  _wanted hosts expl 'host' compadd ${${${(f)"$(${words[1]} -an)"}##[ ?(]#}%%[ )]*} && ret=0
+
+return ret
diff --git a/Completion/Unix/Command/_at b/Completion/Unix/Command/_at
index 8734e6b..b225890 100644
--- a/Completion/Unix/Command/_at
+++ b/Completion/Unix/Command/_at
@@ -1,6 +1,6 @@
 #compdef atrm atq at batch
 
-local context state line expl
+local context state line expl ret=1
 typeset -A opt_args
 
 #todo (when extremely bored) make -l and -d do the atq and atrm completions
@@ -8,12 +8,12 @@ case $service in
 atrm)
   _arguments \
     '-V[print version number]' \
-    '*:job number:->jobs'
+    '*:job number:->jobs' && ret=0
   ;;
 atq)
   _arguments \
     '-V[print version number]' \
-    '-q[uses specified queue]:a-z+A-Z'
+    '-q[uses specified queue]:a-z+A-Z' && ret=0
   ;;
 at|batch)
   _arguments \
@@ -29,11 +29,13 @@ at|batch)
     - atrm \
       '-d[alias for atrm]' \
     - show-job \
-      '-c[cat specified jobs to stdout]:*:job number:->jobs'
+      '-c[cat specified jobs to stdout]:*:job number:->jobs' && ret=0
 esac
 
 case $state in
 jobs)
-  _wanted job expl 'job number' compadd ${(M)${(f)"$(_call_program job atq)"}##<->}
+  _wanted -C $context jobs expl 'job number' compadd ${(M)${(f)"$(_call_program job atq)"}##<->} && ret=0
   ;;
 esac
+
+return ret
diff --git a/Completion/Unix/Command/_bittorrent b/Completion/Unix/Command/_bittorrent
index f7da204..1f305a1 100644
--- a/Completion/Unix/Command/_bittorrent
+++ b/Completion/Unix/Command/_bittorrent
@@ -21,7 +21,7 @@ case $service in
    ;&
  btlaunchmanycurses)
   _arguments -s -S \
-      '(--responsefile)--responsefile+[specify file for server response]:file:_files -g "*"'\
+      '(--responsefile)--responsefile+[specify file for server response]:file:_files'\
       "--url+[specify URL of torrent file]:URL:_urls"\
       '(-i --ip)'{-i+,--ip+}'[specify ip address to report as]:ip address'\
       "--bind+[specify ip to bind to instead of default]:ip:_bind_addresses"\
@@ -50,18 +50,18 @@ case $service in
       "--max_initiate+[specify peers needed before stopping initiating new connections]:peers:"\
       "--report_hash_failures+[report hash failures to user]:enable:(0 1)"\
       "--rarest_first_priority_cutoff+[specify peers which need to have a piece before other partials take priority over rarest first]:peers:"\
-      ':torrent file:_files -g "*.torrent(-.)"' \
-      && return 0
+      ':torrent file:_files -g "*.torrent(-.)"'
+    return
   ;;
 
 # Next up are the torrent file manipulation programs.
 
   btshowmetainfo)
-   _files -g "*.torrent(-.)" && return 0
-   ;;
+    _files -g "*.torrent(-.)" && return
+  ;;
 
   btrename)
-   _files -g '*.torrent(-.)' && return 0
+    _files -g '*.torrent(-.)' && return
   ;;
 
   btmakemetafile)
@@ -69,12 +69,12 @@ case $service in
       '--piece_size_pow2+[specify power of 2 to set the piece size to]:power:' \
       "--comment+[specify human-readable comment to put in .torrent]:comment:"\
       "--target+[specify target file for the torrent]:file:_files"\
-      ':file:_files -g "*"' \
-      && return 0;
+      ':file:_files -g "*"'
+    return
   ;;
 
   btreannounce)
-   _files -g '*.torrent(-.)' && return 0
+    _files -g '*.torrent(-.)' && return
   ;;
 
 # Lastly the tracker.
@@ -94,7 +94,7 @@ case $service in
       "--min_time_between_log_flushes+[specify minimum time between log flushes]:time (s):" \
       "--allowed_dir+[specify directory having downloadable torrents]:directory:_files -/" \
       "--parse_allowed_interval+[specify interval between reloading allowed_dir]:time (min):" \
-      "--show_names+[display names from allowed dir]:enable:(0 1)"\
-      && return 0
-    ;;
+      "--show_names+[display names from allowed dir]:enable:(0 1)"
+    return
+  ;;
 esac
diff --git a/Completion/Unix/Command/_bogofilter b/Completion/Unix/Command/_bogofilter
index 44953cc..ff36e83 100644
--- a/Completion/Unix/Command/_bogofilter
+++ b/Completion/Unix/Command/_bogofilter
@@ -1,7 +1,5 @@
 #compdef bogoutil bogotune bogofilter
 
-local expl ret bogotokens
-
 _bogoutil_caching_policy () {
   local -a oldp
 
@@ -14,6 +12,7 @@ _bogoutil_caching_policy () {
 
 _bogoutil() {
 
+  local bogotokens expl ret=1
 	typeset -a _bogoutil_actions
 	_bogoutil_actions=(-h --help -V --version -d --dump -l --load -u
 		--upgrade -m -w -p -H --db-verify -r -R --db-prune --db-recover
@@ -46,30 +45,27 @@ _bogoutil() {
 	"($_bogoutil_actions)"'--db-remove-environment:database:_files -/' \
 	'--db_lk_max_locks[set max lock count]' \
 	'--db_lk_max_objects[set max object count]' \
-  	"($_bogoutil_actions)"'-h[help]' \
-  	"($_bogoutil_actions)"'--help' \
-  	"($_bogoutil_actions)"'-V[version]' \
-  	"($_bogoutil_actions)"'--version' \
+	"($_bogoutil_actions)"{-h,--help}'[help]' \
+	"($_bogoutil_actions)"{-V,--version}'[version]' \
   	'*:tokens:->tokens' && ret=0
 
   zstyle -s ":completion:${curcontext}:" cache-policy update_policy
   if [[ -z "$update_policy" ]]; then
     zstyle ":completion:${curcontext}:" cache-policy _bogoutil_caching_policy
   fi
-  
+
   case $state in
   	(tokens)
   	if ( [[ -z "$bogotokens" ]] || _cache_invalid bogotokens ) &&
   	  ! _retrieve_cache bogotokens; then
-  	  bogotokens=(${${(f)"$(_call_program bogoutil bogoutil -d ~/.bogofilter/wordlist.db -c 50)"}%% *})
+          bogotokens=(${${(f)"$(_call_program bogotokens bogoutil -d ~/.bogofilter/wordlist.db -c 50)"}%% *})
   	  _store_cache bogotokens bogotokens
-  	else
-  	  :
   	fi
-  	  _wanted tokens expl "token" \
-  	     compadd -a bogotokens
+          _wanted tokens expl "token" compadd -a bogotokens && ret=0
   	;;
   esac
+
+  return ret
 }
 
 case $service in
diff --git a/Completion/Unix/Command/_bpython b/Completion/Unix/Command/_bpython
index c51cc8c..233e032 100644
--- a/Completion/Unix/Command/_bpython
+++ b/Completion/Unix/Command/_bpython
@@ -13,10 +13,10 @@ all_opts=(
 )
 
 urwid_opts=(
-  '(-r --reactor)'{-r,--reactor}'[use Twisted reactor instead of the event loop]:reactor:'
+  '(-r --reactor)'{-r,--reactor}'[use twisted reactor instead of the event loop]:reactor'
   '--help-reactors[display list of available Twisted reactors]'
-  '(-p --plugin)'{-p,--plugin}'[exectue a twistd plugin]:plugin:'
-  '(-s --server)'{-s,--server}'[run an eval server on the given port]:port:'
+  '(-p --plugin)'{-p,--plugin}'[execute a twisted plugin]:plugin'
+  '(-s --server)'{-s,--server}'[run an eval server on the given port]:port:_ports'
 )
 
 gtk_opts=(
@@ -26,19 +26,19 @@ gtk_opts=(
 case "$service" in
   bpython|bpython2|bpython3)
     _arguments \
-      "$all_opts[@]" && return 0
+      "$all_opts[@]"
   ;;
 
   bpython-urwid|bpython2-urwid|bpython3-urwid)
     _arguments \
       "$all_opts[@]" \
-      "$urwid_opts[@]" && return 0
+      "$urwid_opts[@]"
   ;;
 
   bpython-gtk|bpython2-gtk|bpython3-gtk)
     _arguments \
       "$all_opts[@]" \
-      "$gtk_opts[@]" && return 0
+      "$gtk_opts[@]"
   ;;
 esac
 
diff --git a/Completion/Unix/Command/_bzr b/Completion/Unix/Command/_bzr
index c28c214..4a4e5ab 100644
--- a/Completion/Unix/Command/_bzr
+++ b/Completion/Unix/Command/_bzr
@@ -11,12 +11,12 @@ _arguments -C \
 
 if (( ! $+_bzr_cmds )); then
     typeset -gH _bzr_cmds
-    _bzr_cmds=(${(f)"$(_call_program bzr bzr shell-complete)"})
+    _bzr_cmds=(${(f)"$(_call_program subcommands bzr shell-complete)"})
 fi
 
 if [[ $state != 'args' ]]; then
-    _describe -t subcommand 'subcommand' _bzr_cmds
-    return 0
+    _describe -t subcommands 'subcommand' _bzr_cmds
+    return
 fi
 
 cmd="$words[1]"
@@ -25,39 +25,35 @@ curcontext="${curcontext%:*:*}:bzr-$cmd:"
 (( $+functions[_bzr_unknownFiles] )) ||
 _bzr_unknownFiles() {
     local fileList
-    fileList=(${(ps:\0:)"$(bzr ls --null --unknown -R)"})
+    fileList=(${(ps:\0:)"$(_call_program files bzr ls --null --unknown -R)"})
     compadd -af fileList
-    return 0
 }
 
 (( $+functions[_bzr_unknownRoot] )) ||
 _bzr_unknownRoot() {
-    local fileList
-    fileList=(${(ps:\0:)"$(bzr ls --null --from-root --unknown)"})
+    local -a fileList
+    fileList=(${(ps:\0:)"$(_call_program files bzr ls --null --from-root --unknown)"})
     compadd -af fileList
-    return 0
 }
 
 (( $+functions[_bzr_versionedFiles] )) ||
 _bzr_versionedFiles() {
     local fileList
-    fileList=(${(ps:\0:)"$(bzr ls --null --versioned -R)"})
+    fileList=(${(ps:\0:)"$(_call_program files bzr ls --null --versioned -R)"})
     compadd -af fileList
-    return 0
 }
 
 (( $+functions[_bzr_modifiedFiles] )) ||
 _bzr_modifiedFiles() {
     local fileList
-    fileList=(${(ps:\0:)"$(bzr status . --versioned --short | cut -b 5- | tr '\n' '\0')"})
+    fileList=(${(ps:\0:)"$(_call_program files bzr status . --versioned --short | cut -b 5- | tr '\n' '\0')"})
     compadd -af fileList
-    return 0
 }
 
 (( $+functions[_bzr_completeParents] )) ||
 _bzr_completeParents() {
-    local parentFile=$(bzr root 2>/dev/null)/.bzr/branch/parent
-    [[ -r $parentFile ]] && compadd -X "Completing parents" $(cat $parentFile)
+    local parentFile=$(_call_program parents bzr root)/.bzr/branch/parent
+    [[ -r $parentFile ]] && _wanted parents expl parent compadd -- $(<$parentFile)
 }
 
 args=( '(-)'{--help,-h}'[show help message]' )
@@ -99,7 +95,7 @@ case $cmd in
 	'--lightweight[perform a lightweight checkout]'
 	'(-r --revision)'{--revision=,-r}'[the revision to get]:rev:'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (rename|move|mv)
@@ -194,7 +190,7 @@ case $cmd in
 	'(-v --verbose)'{--verbose,-v}'[display more information]'
 	'*:local repository:_files -/'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (missing)
@@ -210,7 +206,7 @@ case $cmd in
 	'(-v --verbose)'{--verbose,-v}'[display more information]'
 	'*:local repository:_files -/'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (commit|checkin|ci)
@@ -227,7 +223,7 @@ case $cmd in
     ;;
 
 (bind|break-lock|reconcile)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (register-branch)
@@ -240,7 +236,7 @@ case $cmd in
 	'--link-bug=[the bug this branch fixes]:bug-ID:'
 	'--product=[launchpad product short name to associate with the branch]:product:'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (remerge)
@@ -249,7 +245,7 @@ case $cmd in
 	'--reprocess[reprocess to reduce spurious conflicts]'
 	'--show-base[show base revision text in conflicts]'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (conflicts|added|deleted|modified|unknowns|directories|ignored|unbind|nick|revno|version)
@@ -322,7 +318,7 @@ case $cmd in
 	'--show-base[show base revision text in conflicts]'
 	'*:local repository:_files -/'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (ls)
@@ -346,7 +342,7 @@ case $cmd in
 	'(-v --verbose -q --quiet)'{--verbose,-v}'[display more information]'
 	'*:local repository:_files -/'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (help)
@@ -355,8 +351,8 @@ case $cmd in
 	'*:subcmds:->cmds'
 	)
     _arguments -s "$args[@]" && ret=0
-    _describe -t subcommand 'subcommand' _bzr_cmds
-    return 0
+    _describe -t subcommands 'subcommand' _bzr_cmds && ret=0
+    return ret
     ;;
 
     # Plugins
@@ -380,7 +376,7 @@ case $cmd in
 	'--remember[remember the specified location as a default]'
 	'*:local repository:_files -/'
 	)
-    _bzr_completeParents
+    _bzr_completeParents && ret=0
     ;;
 
 (clean-tree)
@@ -409,10 +405,11 @@ case $cmd in
     ;;
 
 (*)
-    _message "unknown bzr command completion: $cmd"
-    return 1
+    _default
+    return
     ;;
 esac
 
 _arguments -s "$args[@]" && ret=0
-return $ret
+
+return ret
diff --git a/Completion/Unix/Command/_cdrdao b/Completion/Unix/Command/_cdrdao
index 06b47c9..ad1bf40 100644
--- a/Completion/Unix/Command/_cdrdao
+++ b/Completion/Unix/Command/_cdrdao
@@ -4,108 +4,85 @@
 
 # Command completion and main loop {{{1
 
-_cdrdao_commands () {
-  local -a commands
-
-  commands=(
-    'show-toc:print out a summary of a TOC'
-    'read-toc:create a TOC file based on a CD'
-    'read-cd:create a TOC file and image file based on a CD'
-    'read-cddb:add CD-TEXT data from a CDDB server to a TOC'
-    'show-data:print out samples that would be written to CD'
-    'read-test:check if data described in a TOC can be read from a CD'
-    'disk-info:show information about a CD'
-    'msinfo:generate mkisofs command for creating multi-session CD'
-    'unlock:try to unlock a recorder after a failed run'
-    'blank:blank a CD-RW'
-    'simulate:simulate a write'
-    'write:write a CD based on a TOC'
-    'copy:copy a CD'
-  )
-
-  _describe -t commands 'cdrdao command' commands && ret=0
-}
-
 _cdrdao () {
-  local curcontext=$curcontext ret=1
-
-  local context state line
-  typeset -A opt_args
-  _arguments \
-    ':command:->command' \
-    '*::options:->options' && ret=0
-  case $state in
-    (command)
-      _cdrdao_commands
-      ;;
-    (options)
-      curcontext="${curcontext%:*:*}:cdrdao-$words[1]:"
-      _call_function ret _cdrdao-$words[1]
-      ;;
-  esac
+  local ret=1
+  local -a commands
+  if (( CURRENT == 2 )); then
+    commands=( ${${${(M)${(f)"$(_call_program subcommands cdrdao 2>&1)"}:#  *}// #- /:}#??} )
+    _describe -t subcommands 'cdrdao command' commands && ret=0
+  else
+    local cmd="${words[2]}"
+    local curcontext="${curcontext%:*:*}:cdrdao-$cmd:"
+    shift words
+    (( CURRENT-- ))
+    if ! _call_function ret _cdrdao-$cmd; then
+      _default && ret=0
+    fi
+  fi
 
+  return ret
 }
 
 # Common arguments {{{1
 
-declare -ga tmpfile_args
-tmpfile_args=(
+declare -ga _cdrdao_tmpfile_args
+_cdrdao_tmpfile_args=(
   '--tmpdir[directory to store temporary data in]:directory:_directories'
-  '--keep[do not remove temporary data when done]')
-
-declare -ga device_args
-device_args=(
-  '--device[set SCSI address of the CD recorder]:device:__cdrdao-device'
-  '--driver[use given driver for the CD recorder]:driver:__cdrdao-drivers')
+  '--keep[do not remove temporary data when done]'
+)
 
 # TODO: Gah!  Fix a cddb server spec matcher
-declare -ga cddb_args
-cddb_args=(
+declare -ga _cdrdao_cddb_args
+_cdrdao_cddb_args=(
   '--cddb-servers[specify list of CDDB servers to use]:CDDB servers:'
   '--cddb-timeout[specify timeout in seconds for connections to CDDB servers]: :_guard "[[\:digit\:]]" timeout'
-  '--cddb-directory[directory where fetched CDDB records will be stored]:directory:_directories')
+  '--cddb-directory[directory where fetched CDDB records will be stored]:directory:_directories'
+)
 
-declare -g paranoiamode_arg=
-paranoiamode_arg='--paranoia-mode[set correction mode for digital audio extraction]:mode:(("0\:no checking" "1\:perform overlapped reading to avoid jitter" "2\:like 1 but with checks of read audio data" "3\:like 2 but with scratch detection/repair (default)"))'
+declare -g _cdrdao_paranoiamode_arg
+_cdrdao_paranoiamode_arg='--paranoia-mode[set correction mode for digital audio extraction]:mode:(("0\:no checking" "1\:perform overlapped reading to avoid jitter" "2\:like 1 but with checks of read audio data" "3\:like 2 but with scratch detection/repair (default)"))'
 
-declare -g fasttoc_arg=
-fasttoc_arg='--fast-toc[skip pre-gap-length and index-mark extraction]'
+declare -g _cdrdao_fasttoc_arg
+_cdrdao_fasttoc_arg='--fast-toc[skip pre-gap-length and index-mark extraction]'
 
-declare -g swap_arg=
-swap_arg='--swap[swap the byte order of samples]'
+declare -g _cdrdao_swap_arg
+_cdrdao_swap_arg='--swap[swap the byte order of samples]'
 
-declare -g reload_arg=
-reload_arg='--reload[reload the disk if necessary]'
+declare -g _cdrdao_reload_arg
+_cdrdao_reload_arg='--reload[reload the disk if necessary]'
 
-declare -g eject_arg=
-eject_arg='--eject[eject CD after completed operation]'
+declare -g _cdrdao_eject_arg
+_cdrdao_eject_arg='--eject[eject CD after completed operation]'
 
-declare -g speed_arg=
-speed_arg='-speed[set writing speed]: :_guard "[[\:digit\:]]##" speed'
+declare -g _cdrdao_speed_arg
+_cdrdao_speed_arg='-speed[set writing speed]: :_guard "[[\:digit\:]]##" speed'
 
-declare -ga common_args
-common_args=(
+declare -ga _cdrdao_common_args
+_cdrdao_common_args=(
   '(*)'{-h,--help}'[display command/option summary]'
   '-v[set verbosity level]: :_guard "[[\:digit\:]]##" verbosity')
 
-declare -ga common_toc_args
-common_toc_args=(
-  $common_args
+declare -ga _cdrdao_common_toc_args
+_cdrdao_common_toc_args=(
+  $_cdrdao_common_args
   ':TOC file:_files -g "*.toc(-.)"')
 
-declare -ga common_device_args
-common_device_args=(
-  $common_args
-  $device_args)
-
-declare -ga common_toc_device_args
-common_toc_device_args=(
-  $common_toc_args
-  $common_device_args
-  $force_arg)
-
-declare -ga common_read_args
-common_read_args=(
+declare -ga _cdrdao_common_device_args
+_cdrdao_common_device_args=(
+  $_cdrdao_common_args
+  '--device[set SCSI address of the CD recorder]:device:__cdrdao-device'
+  '--driver[use given driver for the CD recorder]:driver:__cdrdao-drivers'
+)
+
+declare -ga _cdrdao_common_toc_device_args
+_cdrdao_common_toc_device_args=(
+  $_cdrdao_common_toc_args
+  $_cdrdao_common_device_args
+  '--force[force execution of operation]'
+)
+
+declare -ga _cdrdao_common_read_args
+_cdrdao_common_read_args=(
   '--rspeed[set reading speed]: :_guard "[[\:digit\:]]##" speed'
   '--session[specify what session to process on multi-session CDs]: :_guard "[[\:digit\:]]##" "session number"'
   '--read-subchan[set sub-channel reading-mode]:mode:(("rw\:de-interleaved and error corrected" "rw_raw\:not de-interleaved, not error-corrected, and L-EC data included"))'
@@ -128,18 +105,18 @@ _cdrdao-toc-size () {
 
 __cdrdao-show-toc-or-toc-info-or-toc-size () {
   _arguments \
-    $common_toc_args \
-    $tmpfile_args && ret=0
+    $_cdrdao_common_toc_args \
+    $_cdrdao_tmpfile_args
 }
 
 _cdrdao-read-toc () {
-  __cdrdao-read-toc-or-read-cd \
-    $fasttoc_arg
+  __cdrdao-read-toc-or-read-cd $_cdrdao_cddb_args
 }
 
 _cdrdao-read-cd () {
   __cdrdao-read-toc-or-read-cd \
-    $paranoiamode_arg
+    $_cdrdao_paranoiamode_arg \
+    $_cdrdao_cddb_args
 }
 
 __cdrdao-read-toc-or-read-cd () {
@@ -148,30 +125,31 @@ __cdrdao-read-toc-or-read-cd () {
   __cdrdao-read-toc-or-read-cd-or-copy-dependent-args
 
   _arguments \
-    $common_toc_device_args \
-    $common_read_args \
-    $dependent_args
+    $_cdrdao_common_toc_device_args \
+    $_cdrdao_common_read_args \
+    $dependent_args \
+    $_cdrdao_fasttoc_arg \
     '--datafile[set name of data file placed in TOC file]:file:_files' \
     '--read-raw[read data in raw format from CD]' \
     '--no-mode2-mixed[if MODE2_FORM1 or MODE2_FORM2, do not extract as MODE2_FORM_MIX]' \
-    $* && ret=0
+    "$@" && ret=0
 }
 
 _cdrdao-read-cddb () {
   _arguments \
-    $common_toc_args \
-    $cddb_args && ret=0
+    $_cdrdao_common_toc_args \
+    $_cdrdao_cddb_args
 }
 
 _cdrdao-show-data () {
   _arguments \
-    $common_toc_args \
-    $swap_arg && ret=0
+    $_cdrdao_common_toc_args \
+    $_cdrdao_swap_arg
 }
 
 _cdrdao-read-test () {
   _arguments \
-    $common_toc_args && ret=0
+    $_cdrdao_common_toc_args
 }
 
 _cdrdao-disk-info () {
@@ -180,13 +158,18 @@ _cdrdao-disk-info () {
 
 __cdrdao-disk-info-or-drive-info () {
   _arguments \
-    $common_device_args && ret=0
+    $_cdrdao_common_device_args
+}
+
+_cdrdao-discid() {
+  _arguments $_cdrdao_common_device_args $_cdrdao_cddb_args \
+    '--query-string[print out CDDB query only]'
 }
 
 _cdrdao-msinfo () {
   _arguments \
-    $common_device_args \
-    $reload_arg && ret=0
+    $_cdrdao_common_device_args \
+    $_cdrdao_reload_arg
 }
 
 _cdrdao-drive-info () {
@@ -195,22 +178,22 @@ _cdrdao-drive-info () {
 
 _cdrdao-unlock () {
   _arguments \
-    $common_device_args \
-    $reload_arg \
-    $eject_arg && ret=0
+    $_cdrdao_common_device_args \
+    $_cdrdao_reload_arg \
+    $_cdrdao_eject_arg
 }
 
 _cdrdao-blank () {
   _arguments \
-    $common_device_args \
-    $speed_arg \
+    $_cdrdao_common_device_args \
+    $_cdrdao_speed_arg \
     '--blank-mode[set the blanking mode]:blanking mode:(("full\:completely erase data" "minimal\:only dereference data"))' \
-    $eject_arg && ret=0
+    $_cdrdao_eject_arg
 }
 
 _cdrdao-scanbus () {
   _arguments \
-    $common_args && ret=0
+    $_cdrdao_common_args
 }
 
 _cdrdao-simulate () {
@@ -218,26 +201,26 @@ _cdrdao-simulate () {
 }
 
 __cdrdao-simulate-or-write () {
-  local capacity_arg=
-  
+  local _cdrdao_capacity_arg=
+
   if (( $words[(I)--full-burn] )); then
-    capacity_arg='--capacity[set disk capacity for --full-burn]: :_guard "[[\:digit\:]]" minutes'
+    _cdrdao_capacity_arg='--capacity[set disk capacity for --full-burn]: :_guard "[[\:digit\:]]" minutes'
   fi
 
   _arguments \
-    $common_toc_device_args \
-    $speed_arg \
+    $_cdrdao_common_toc_device_args \
+    $_cdrdao_speed_arg \
     '--multi[do not close the session after successful write]' \
     '--overburn[allow overburing of medium]' \
     '--full-burn[force burning to the outer disk edge]' \
-    $capacity_arg \
-    $eject_arg \
-    $swap_arg \
+    $_cdrdao_capacity_arg \
+    $_cdrdao_eject_arg \
+    $_cdrdao_swap_arg \
     '--buffers[set fifo buffer size]: :_guard "[[\:digit\:]]" size' \
-    $reload_arg \
-    $tmpfile_args \
+    $_cdrdao_reload_arg \
+    $_cdrdao_tmpfile_args \
     '-n[do not pause before writing]' \
-    $* && ret=0
+    $*
 }
 
 _cdrdao-write () {
@@ -254,24 +237,24 @@ __cdrdao-read-toc-or-read-cd-or-copy-dependent-args () {
   fi
 
   if (( words[(I)--with-cddb] )); then
-    dependent_args+=$cddb_args
+    dependent_args+=$_cdrdao_cddb_args
   fi
 }
 
 _cdrdao-copy () {
-  local -ga dependent_args
+  local -a dependent_args
 
   __cdrdao-read-toc-or-read-cd-or-copy-dependent-args
 
   _cdrdao-write \
-    $dependent_args
-    $common_read_args
+    $dependent_args \
+    $_cdrdao_common_read_args \
     '--source-device[set SCSI address of the CD reader]:device:__cdrdao-device' \
     '--source-driver[use given driver for the CD reader]:driver:__cdrdao-drivers' \
     '--on-the-fly[perform on-the-fly copy of CD (no image created)]' \
-    $fasttoc_arg \
+    $_cdrdao_fasttoc_arg \
     '--keepimage[do not remove generated image when done]' \
-    $paranoiamode_arg && ret=0
+    $_cdrdao_paranoiamode_arg
 }
 
 # Type completion {{{1
@@ -280,24 +263,21 @@ __cdrdao-device () {
   # Use cdrdao scanbus and also check what OS we're running under and provide
   # additional stuff, like devices (/dev/sg0)
   local -a devices
+  devices=(${${(f)"$(_call_program devices cdrdao scanbus -v 0 2>&1)"}%% :*})
 
-  devices=(${(f)"$(_call_program devices cdrdao scanbus -v 0 2>/dev/null)"})
-  if (( ${#pipestatus:#0} > 0 )); then
-    return 1
-  fi
-
-  _wanted devices expl 'device' compadd - $devices
+  _wanted devices expl 'device' compadd -a devices
 }
 
 __cdrdao-drivers () {
-  local -a drivers
-
-  drivers=(${(f)"$(_call_program drivers cut -d'|' -f4 /usr/share/cdrdao/drivers -s 2>/dev/null | sort -u)"})
-  if (( ${#pipestatus:#0} > 0 )); then
-    return 1
+  local suf
+  local -Ua drivers
+  drivers=(${(f)"$(_call_program drivers cut -d'\|' -f4 /usr/share/cdrdao/drivers -s)"})
+  if compset -P \*:; then
+    _message -e options option
+  else
+    compset -S :\* || suf=-qS:
+    _wanted drivers expl 'driver' compadd $suf -a drivers
   fi
-
-  _wanted drivers expl 'driver' compadd -qS: - $drivers
 }
 
 # }}}1
diff --git a/Completion/Unix/Command/_chmod b/Completion/Unix/Command/_chmod
index 5d3cb2c..48ce050 100644
--- a/Completion/Unix/Command/_chmod
+++ b/Completion/Unix/Command/_chmod
@@ -49,7 +49,7 @@ case "$state" in
       compset -P '*'
       _alternative -O suf \
 	'who:who:((u\:user g\:group a\:all o\:others))' \
-	'operators:operator:(+ - =)'
+	'operators:operator:(+ - =)' && ret=0
     fi
   ;;
   files)
diff --git a/Completion/Unix/Command/_cpio b/Completion/Unix/Command/_cpio
index 280a893..6b07a21 100644
--- a/Completion/Unix/Command/_cpio
+++ b/Completion/Unix/Command/_cpio
@@ -1,17 +1,17 @@
 #compdef cpio
 
 local args ig curcontext="$curcontext" state line
-local expl ret
+local expl ret=1
 local fmts='(bar bin odc newc crc tar ustar hpbin hpodc)'
 
 _pick_variant -r ig gnu=GNU unix --version
 
 if (( CURRENT == 2 )); then
-   # Complete arguments 
+   # Complete arguments
    args=('-o[create archive]' '-i[extract from archive]'
    '-p[run as filter on directory tree]')
    [[ $ig = gnu ]] && args=($args '--create[create archive]'
-   '--extract[extract from archive]' 
+   '--extract[extract from archive]'
    '--pass-through[run as filter on directory tree]'
    '--help[show help text]' '--version[show version information]')
 else
@@ -23,13 +23,13 @@ else
 	   "--format=:format type:$fmts"
 	   '--message=:message at end of volume:'
 	   '--null' '--reset-access-time'
-	   '--verbose' '--dot' '--append' 
+	   '--verbose' '--dot' '--append'
 	   '--block-size=:block size in 512 byte units:'
 	   '--dereference'
 	   '--io-size=:block size in bytes'
 	   '--quiet' '--force-local'  '--help'   '--version')
     fi
-    args=($args
+    args+=(
 	  '-A[append files to archive]'
 	  '-B[block size 5120 bytes with special file]'
 	  '-C[set block size per record]:block size in bytes:(8192)'
@@ -44,10 +44,10 @@ else
     if [[ $ig = gnu ]]; then
       args=('--file=:archive file:->afile'
 	    "--format=:format type:$fmts"
-	    '--make-directories' '--nonmatching' 
+	    '--make-directories' '--nonmatching'
             '--preserve-modification-time' '--numeric'
 	    '--rename' '--list' '--swap-bytes' '--swap-halfwords'
-	    '--dot' '--unconditional' '--verbose' 
+	    '--dot' '--unconditional' '--verbose'
 	    '--block-size=:block size in 512 byte units:'
 	    '--swap-halfwords'
 	    '--io-size=:block size in bytes:'
@@ -58,7 +58,7 @@ else
 	    '--no-absolute-filenames' '--sparse' '--only-verify-crc'
 	    '--quiet' '--help' '--version')
     fi
-    args=($args
+    args+=(
 	  '-b[reverse bytes in word]'
 	  '-B[block size 5120 bytes with special file]'
 	  '-d[create directories as needed]'
@@ -87,7 +87,7 @@ else
 	    '--owner=:user (and group) for files:->user'
 	    '--no-preserve-owner' '--sparse'  '--help'  '--version')
     fi
-    args=($args
+    args+=(
 	  '-d[create directories as needed]'
 	  '-l[link files instead of copying]'
 	  '-L[follow symbolic links]'
@@ -98,12 +98,11 @@ else
   else
     return 1
   fi
-  args=($args
+  args+=(
 	'-a[reset access time of input files]'
 	)
-fi 
+fi
 
-ret=1
 _arguments -C -s "$args[@]" && ret=0
 
 if [[ $state = afile ]]; then
@@ -121,12 +120,12 @@ if [[ $state = afile ]]; then
   fi
 elif [[ $state = user ]]; then
   if compset -P '*[:.]'; then
-    _groups
+    _groups && ret=0
   else
     local suf=.
     [[ $OSTYPE = (solaris|hpux)* ]] && suf=:
     compset -S '.*' && unset suf
-    _users -S "$suf" -q
+    _users -S "$suf" -q && ret=0
   fi
 fi
 
diff --git a/Completion/Unix/Command/_df b/Completion/Unix/Command/_df
index 892f91f..a98180a 100644
--- a/Completion/Unix/Command/_df
+++ b/Completion/Unix/Command/_df
@@ -1,6 +1,6 @@
 #compdef df
 
-local context state state_descr line args spec
+local curcontext="$curcontext" state state_descr line args spec ret=1
 local -A opt_args
 
 if _pick_variant gnu=GNU unix --version; then
@@ -34,6 +34,7 @@ elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then
     '(-b -g -H -h -k -m)-m[use 1024*1024-byte blocks]'
     '-P[POSIX compliant output]'
     '-a[show all mount points]'
+    '-c[display a grand total]'
     '-i[include inode usage statistics (default)]'
     '-l[only display locally-mounted file systems]'
     '-n[use previously obtained statistics]'
@@ -44,7 +45,7 @@ elif [[ "$OSTYPE" == (darwin|freebsd|dragonfly)* ]]; then
     (darwin*)
       args+=(
         "-T+$spec"
-#       '-t[same as -T (obsolete)]:file system type:->fslist'
+        "!-t+$spec" # obsolete
       )
       ;;
     (freebsd*|dragonfly*)
@@ -61,19 +62,15 @@ else
   )
 fi
 
-_arguments -s -S : $args && return 0
+_arguments -C -s -S : $args && ret=0
 
 case "$state" in
   (fslist)
-    local -a fsys used pre disp expl
-    _file_systems -U -O fsys
-    pre=$IPREFIX
-    # offer 'no' only if at the beginning of the list
-    if ! compset -P '*,' && ! compset -P 'no'; then
-      disp=( 'no  -- exclude file system types in the list' )
-      _wanted list-prefix expl 'prefix to list' compadd -d disp 'no'
-    fi
-    used=( ${(s:,:)${${IPREFIX#$pre}#no}} )
-    _wanted fsys-types expl "$state_descr" compadd -qS , -F used -a fsys
+    [[ ! -prefix *, ]] && ! compset -P 'no' &&
+        _describe -t list-prefixes 'prefix to list' \
+        '( no:exclude\ file\ system\ types\ in\ the\ list )' && ret=0
+    _sequence -s , _file_systems && ret=0
     ;;
 esac
+
+return ret
diff --git a/Completion/Unix/Command/_django b/Completion/Unix/Command/_django
index ac20409..0296876 100644
--- a/Completion/Unix/Command/_django
+++ b/Completion/Unix/Command/_django
@@ -1,26 +1,23 @@
 #compdef django-admin.py django-admin manage.py
 
-local ret=1 state
+local curcontext="$curcontext" state line expl ret=1
 
-if [ "$service" = "manage.py" ] && [ ! -x ./manage.py ]; then
-  return 0
+if [[ "$service" = "manage.py" && ! -x ./manage.py ]]; then
+  _default
+  return
 fi
 
 declare -ga common_args
 common_args=(
   '--help[display help information]'
   '--version[display version information]'
-  '--pythonpath=[directory to add to the Python path]:directory:_directories'
-  '--settings=[Python path to settings module]:settings'
+  '--pythonpath=[directory to add to the Python path]:directory:_directories -W / -P /'
+  '--settings=[python path to settings module]:settings'
   '--traceback[print traceback on exception]'
 )
 
-_directories () {
-  _wanted directories expl directory _path_files -/ "$@" -
-}
-
 typeset -A opt_args
-_arguments \
+_arguments -C \
   $common_args \
   ':subcommand:->subcommand' \
   '*::options:->options' && ret=0
@@ -66,7 +63,7 @@ case $state in
             subcommands+=($cmd)
         fi
     done
-    
+
     _describe -t subcommands 'django admin subcommand' subcommands && ret=0
     ;;
 
@@ -101,8 +98,8 @@ case $state in
           settings="${DJANGO_SETTINGS_MODULE}"
       else
         return 0
-      fi 
-     
+      fi
+
       _wanted appname expl appname compadd - $(command \
         sed -n "/INSTALLED_APPS\s*=\s*(/,/)/p" ${settings} | \
         sed -n "s/^\s*'\(.*\.\)*\(.*\)'.*$/\2 /pg")
@@ -205,7 +202,7 @@ case $state in
         ;;
     esac
 
-    _arguments $args && ret=0
+    _arguments -C $args && ret=0
     ;;
 esac
 
diff --git a/Completion/Unix/Command/_git b/Completion/Unix/Command/_git
index c4e386b..38bd729 100644
--- a/Completion/Unix/Command/_git
+++ b/Completion/Unix/Command/_git
@@ -5262,12 +5262,10 @@ __git_gpg_secret_keys () {
 (( $+functions[__git_merge_strategies] )) ||
 __git_merge_strategies () {
   local expl
-  local -a merge_strategies
 
-  merge_strategies=(${=${${(M)${(f)"$(_call_program merge-strategies "git merge -s '' 2>&1")"}:#[Aa]vailable (custom )#strategies are: *}#[Aa]vailable (custom )#strategies are: }%.})
-  __git_command_successful $pipestatus || return 1
-
-  _wanted merge-strategies expl 'merge strategy' compadd $* - $merge_strategies
+  _wanted merge-strategies expl 'merge strategy' compadd "$@" - \
+      ${=${${${(M)${(f)"$(_call_program merge-strategies \
+      "git merge -s '' 2>&1")"}:#[Aa]vailable (custom )#strategies are: *}#[Aa]vailable (custom )#strategies are: }%.}:-octopus ours recursive resolve subtree}
 }
 
 (( $+functions[__git_encodings] )) ||
@@ -5299,8 +5297,9 @@ __git_remotes () {
   local remotes expl
 
   remotes=(${(f)"$(_call_program remotes git remote 2>/dev/null)"})
+  __git_command_successful $pipestatus || return 1
 
-  _wanted remotes expl remote compadd $* - $remotes
+  _wanted remotes expl remote compadd "$@" -a - remotes
 }
 
 (( $+functions[__git_ref_specs] )) ||
@@ -5431,13 +5430,7 @@ __git_reflog_entries () {
   reflog_entries=(${${${(f)"$(_call_program reflog-entries git reflog 2>/dev/null)"}#* }%%:*})
   __git_command_successful $pipestatus || return 1
 
-  if compset -P '*@'; then
-    reflog_entries=(${${(M)reflog_entries:#$IPREFIX*}#$IPREFIX})
-    _wanted reflog-entries expl 'reflog entry' compadd $* - $reflog_entries
-  else
-    reflog_entries=(${reflog_entries%@*})
-    _wanted reflog-entries expl 'reflog entry' compadd -qS @ $* - $reflog_entries
-  fi
+  _wanted reflog-entries expl 'reflog entry' _multi_parts @ reflog_entries
 }
 
 (( $+functions[__git_ref_sort_keys] )) ||
@@ -5492,7 +5485,7 @@ __git_stashes () {
   stashes=(${${(f)"$(_call_program stashes git stash list 2>/dev/null)"}/: */})
   __git_command_successful $pipestatus || return 1
 
-  _wanted stashes expl stash compadd $* - $stashes
+  _wanted stashes expl stash compadd "$@" -a - stashes
 }
 
 (( $+functions[__git_svn_revisions] )) ||
@@ -5531,7 +5524,7 @@ __git_branch_names () {
   branch_names=(${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/heads 2>/dev/null)"}#refs/heads/})
   __git_command_successful $pipestatus || return 1
 
-  _wanted branch-names expl branch-name compadd $* - $branch_names
+  _wanted branch-names expl branch-name compadd "$@" -a - branch_names
 }
 
 (( $+functions[__git_remote_branch_names] )) ||
@@ -5542,7 +5535,7 @@ __git_remote_branch_names () {
   branch_names=(${${(f)"$(_call_program remote-branch-refs git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}#refs/remotes/})
   __git_command_successful $pipestatus || return 1
 
-  _wanted remote-branch-names expl 'remote branch name' compadd $* - $branch_names
+  _wanted remote-branch-names expl 'remote branch name' compadd "$@" -a - branch_names
 }
 
 (( $+functions[__git_remote_branch_names_noprefix] )) ||
@@ -5553,7 +5546,7 @@ __git_remote_branch_names_noprefix () {
   branch_names=(${${${(f)"$(_call_program remote-branch-refs-noprefix git for-each-ref --format='"%(refname)"' refs/remotes 2>/dev/null)"}##*/}:#HEAD})
   __git_command_successful $pipestatus || return 1
 
-  _wanted remote-branch-names-noprefix expl 'remote branch name' compadd $* - $branch_names
+  _wanted remote-branch-names-noprefix expl 'remote branch name' compadd "$@" -a - branch_names
 }
 
 (( $+functions[__git_commits] )) ||
@@ -5582,7 +5575,7 @@ __git_heads () {
     done
   fi
 
-  _wanted heads expl head compadd $* - $heads
+  _wanted heads expl head compadd "$@" -a - heads
 }
 
 (( $+functions[__git_commit_objects] )) ||
@@ -5678,7 +5671,7 @@ __git_submodules () {
   submodules=(${${${(f)"$(_call_program submodules git submodule 2>/dev/null)"}#?* }%% *})
   __git_command_successful $pipestatus || return 1
 
-  _wanted submodules expl submodule compadd $* - $submodules
+  _wanted submodules expl submodule compadd "$@" -a - submodules
 }
 
 # Tag Argument Types
@@ -5691,7 +5684,7 @@ __git_tags () {
   tags=(${${(f)"$(_call_program tagrefs git for-each-ref --format='"%(refname)"' refs/tags 2>/dev/null)"}#refs/tags/})
   __git_command_successful $pipestatus || return 1
 
-  _wanted tags expl tag compadd $* - $tags
+  _wanted tags expl tag compadd "$@" -a - tags
 }
 
 (( $+functions[__git_commit_tags] )) ||
@@ -5714,7 +5707,7 @@ __git_tags_of_type () {
   tags=(${${(M)${(f)"$(_call_program $type-tag-refs "git for-each-ref --format='%(*objecttype)%(objecttype) %(refname)' refs/tags 2>/dev/null")"}:#$type(tag|) *}#$type(tag|) refs/tags/})
   __git_command_successful $pipestatus || return 1
 
-  _wanted $type-tags expl "$type tag" compadd $* - $tags
+  _wanted $type-tags expl "$type tag" compadd "$@" -a - tags
 }
 
 # Reference Argument Types
@@ -5737,7 +5730,7 @@ __git_references () {
     _git_refs_cache_pwd=$PWD
   fi
 
-  _wanted references expl 'references' compadd - $_git_refs_cache
+  _wanted references expl 'reference' compadd -a - _git_refs_cache
 }
 
 (( $+functions[__git_local_references] )) ||
@@ -5750,7 +5743,7 @@ __git_local_references () {
     _git_local_refs_cache_pwd=$PWD
   fi
 
-  _wanted references expl 'references' compadd - $_git_local_refs_cache
+  _wanted references expl 'reference' compadd -a - _git_local_refs_cache
 }
 
 (( $+functions[__git_remote_references] )) ||
@@ -5766,7 +5759,7 @@ __git_notes_refs () {
   notes_refs=(${${(f)"$(_call_program notes-refs git for-each-ref --format='"%(refname)"' refs/notes 2>/dev/null)"}#$type refs/notes/})
   __git_command_successful $pipestatus || return 1
 
-  _wanted notes-refs expl 'notes ref' compadd $* - $notes_refs
+  _wanted notes-refs expl 'notes ref' compadd "$@" -a - notes_refs
 }
 
 # File Argument Types
@@ -6406,7 +6399,6 @@ __git_config_values () {
 # Git Config Sections and Types
 (( $+functions[__git_browsers] )) ||
 __git_browsers () {
-  integer ret=1
   local expl
   declare -a userbrowsers builtinbrowsers
 
@@ -6431,16 +6423,9 @@ __git_browsers () {
     cygstart
     xdg-open)
 
-  _tags user-browsers builtin-browsers
-
-  while _tags; do
-    _requested user-browsers expl 'user-defined browser' compadd $* - $userbrowsers && ret=0
-    _requested builtin-browsers expl 'builtin browser' compadd $* - $builtinbrowsers && ret=0
-
-    (( ret )) || break
-  done
-
-  return ret
+  _alternative \
+    'user-browsers:user-defined browser:compadd -a - userbrowsers' \
+    'builtin-browsers:builtin browser:compadd -a - builtinbrowsers'
 }
 
 (( $+functions[__git_difftools] )) ||
@@ -6483,10 +6468,10 @@ __git_diff-or-merge-tools () {
   esac
 
   while _tags; do
-    _requested user-difftools expl 'user-defined difftool' compadd $* - $userdifftools && ret=0
-    _requested user-mergetools expl 'user-defined mergetool' compadd $* - $usermergetools && ret=0
-    _requested builtin-difftools expl 'builtin difftool' compadd $* - $builtindifftools && ret=0
-    _requested builtin-mergetools expl 'builtin mergetool' compadd $* - $builtinmergetools && ret=0
+    _requested user-difftools expl 'user-defined difftool' compadd "$@" -a - userdifftools && ret=0
+    _requested user-mergetools expl 'user-defined mergetool' compadd "$@" -a - usermergetools && ret=0
+    _requested builtin-difftools expl 'builtin difftool' compadd "$@" -a - builtindifftools && ret=0
+    _requested builtin-mergetools expl 'builtin mergetool' compadd "$@" -a - builtinmergetools && ret=0
 
     (( ret )) || break
   done
@@ -6577,20 +6562,18 @@ __git_sendemail_suppresscc_values () {
 
 (( $+functions[__git_colors] )) ||
 __git_colors () {
-  declare -a colors
+  declare -a expl
 
-  colors=(black red green yellow blue magenta cyan white)
-
-  _describe -t colors color colors $*
+  _wanted colors expl color compadd "$@" - \
+      black red green yellow blue magenta cyan white
 }
 
 (( $+functions[__git_color_attributes] )) ||
 __git_color_attributes () {
-  declare -a attributes
-
-  attributes=(bold dim ul blink reverse)
+  declare -a expl
 
-  _describe -t attributes attribute attributes $*
+  _wanted attributes expl attribute compadd "$@" - \
+      bold dim ul blink reverse
 }
 
 # Now, for the main drive...
@@ -6657,12 +6640,12 @@ _git() {
       (option-or-argument)
         curcontext=${curcontext%:*:*}:git-$words[1]:
 
-        if (( $+functions[_git-$words[1]] )); then
-          _call_function ret _git-$words[1]
-        elif zstyle -T :completion:$curcontext: use-fallback; then
-          _files && ret=0
-        else
-          _message 'unknown sub-command'
+	if ! _call_function ret _git-$words[1]; then
+	  if zstyle -T :completion:$curcontext: use-fallback; then
+	    _default && ret=0
+	  else
+	    _message "unknown sub-command: $words[1]"
+	  fi
         fi
         ;;
     esac
diff --git a/Completion/Unix/Command/_less b/Completion/Unix/Command/_less
index ede54a4..a3ba8f6 100644
--- a/Completion/Unix/Command/_less
+++ b/Completion/Unix/Command/_less
@@ -24,8 +24,8 @@ if compset -P '+[-0-9]#'; then
     g:goto\ line
     F:scroll\ to\ end\ and\ keep\ reading\ file
     G:go\ to\ end\ of\ file
-    %:go\ to\ position\ in\ file 
-    p:go\ to\ position\ in\ file 
+    %:go\ to\ position\ in\ file
+    p:go\ to\ position\ in\ file
   )'
   return
 fi
@@ -101,9 +101,9 @@ if [[ -n "$state" ]]; then
     ;;
     tags)
       if (( $+LESSGLOBALTAGS )); then
-        _global_tags
+        _global_tags && ret=0
       else
-        _ctags_tags
+        _ctags_tags && ret=0
       fi
     ;;
   esac
diff --git a/Completion/Unix/Command/_lha b/Completion/Unix/Command/_lha
index 5a238d8..c2d5e7d 100644
--- a/Completion/Unix/Command/_lha
+++ b/Completion/Unix/Command/_lha
@@ -5,16 +5,16 @@ if (( CURRENT == 2 )); then
 
     local lhacmds
     lhacmds=(
-	'(  x l v u d m c p t)a[Add \(Or replace\) to archive]'
-	'(a   l v u d m c p t)x[EXtract from archive]'
-	'(a x   v u d m c p t)l[List]'
-	'(a x l   u d m c p t)v[Verbose List]'
-	'(a x l v   d m c p t)u[Update newer files to archive]'
-	'(a x l v u   m c p t)d[Delete from archive]'
-	'(a x l v u d   c p t)m[Move to archive]'
-	'(a x l v u d m   p t)c[re-Construct new archive]'
-	'(a x l v u d m c   t)p[Print to STDOUT from archive]'
-	'(a x l v u d m c p  )t[Test file CRC in archive]'
+	'(  x l v u d m c p t)a[add \(or replace\) to archive]'
+	'(a   l v u d m c p t)x[extract from archive]'
+	'(a x   v u d m c p t)l[list]'
+	'(a x l   u d m c p t)v[verbose List]'
+	'(a x l v   d m c p t)u[update newer files to archive]'
+	'(a x l v u   m c p t)d[delete from archive]'
+	'(a x l v u d   c p t)m[move to archive]'
+	'(a x l v u d m   p t)c[re-construct new archive]'
+	'(a x l v u d m c   t)p[print to stdout from archive]'
+	'(a x l v u d m c p  )t[test file CRC in archive]'
     )
 
     if [ "${words[2]#-}" != "" ]; then
@@ -23,22 +23,22 @@ if (( CURRENT == 2 )); then
 	    'q[quiet]'
 	    'n[not execute]'
 	    'f[force\(over write at extract\)]'
-	    't[FILES are TEXT file]'
-	    'e[TEXT code convert from/to EUC]'
-	    'g[Generic format \(for compatibility\)]'
+	    't[files are text files]'
+	    'e[text code convert from/to EUC]'
+	    'g[use generic format \(for compatibility\)]'
 	)
 	case ${words[2]#-} in
 	    a*|u*)
 		lhacmds=($lhacmds
-		    'd[delete FILES after]'
-		    'z[files not compress]'
+		    'd[delete files after]'
+		    "z[don't compress files]"
 		    '(  1 2)0[header level 0]'
 		    '(0   2)1[header level 1]'
 		    '(0 1  )2[header level 2]'
 		)
 		;;
 	    c*)
-		lhacmds=($lhacmds 'd[delete FILES after]')
+		lhacmds=($lhacmds 'd[delete files after]')
 		;;
 	    x*)
 		lhacmds=($lhacmds 'i[ignore directory path]')
@@ -46,32 +46,25 @@ if (( CURRENT == 2 )); then
 	esac
     fi
 
-    _values -s '' 'lha command' \
-	$lhacmds \
-	&& return 0
+    _values -s '' 'lha command' $lhacmds
 elif (( CURRENT == 3 )); then
-    _arguments -C \
-	'*:LHA file:_files -g \*.lzh' && return 0
+    _wanted files expl 'lha file' _files -g '*.lzh(-.)'
 else
     case ${words[2]#-} in
 	l*|x*|d*)
 	    if [ -f "$words[3]" ]; then
-		_lzh_cache_list=`$words[1] lq $words[3] | awk '{print $8}'`
+		_lzh_cache_list=`$words[1] lq $words[3] | awk '{print $NF}'`
 		_lzh_cache_list=("${(@f)${_lzh_cache_list}}")
 		
 		_wanted files expl 'file from archive' _multi_parts / _lzh_cache_list
-
-		return 0
 	    else
-		_message -r "Archive file is not found : ${words[3]}"
+		_message -r "archive file is not found : ${words[3]}"
 		return 1
 	    fi
 		
 	    ;;
 	*)
-	    _arguments -C \
-		'*:file:_files' && return 0
+	    _files
+	;;
     esac
 fi
-
-return 0
diff --git a/Completion/Unix/Command/_metaflac b/Completion/Unix/Command/_metaflac
index 14095e9..65b9eb2 100644
--- a/Completion/Unix/Command/_metaflac
+++ b/Completion/Unix/Command/_metaflac
@@ -1,16 +1,13 @@
 #compdef metaflac
 
 local _metaflac_opts _metaflac_shorts _metaflac_opers
-typeset -A opt_args
-function _metaflac_tags () {
-    echo "\n\nBEEP - $line - BEEP\n\n"
-}
-_metaflac_opts=( 
-    '--preserve-modtime' 
-    '--with-filename[prefix output with filename]' 
-    '--no-filename' 
+
+_metaflac_opts=(
+    '--preserve-modtime'
+    '--with-filename[prefix output with filename]'
+    '--no-filename'
     '--no-utf8-convert'
-    '--dont-use-padding[always rewrite the file]' 
+    '--dont-use-padding[always rewrite the file]'
 )
 _metaflac_shorts=(
     '--show-md5sum'
@@ -23,7 +20,7 @@ _metaflac_shorts=(
     '--show-bps'
     '--show-total-samples'
     '--show-vendor-tag'
-    '--show-tag=:FLAC tags:_metaflac_tags'
+    '--show-tag=:FLAC tags'
     '--remove-tag=:FLAC tags: '
     '--remove-first-tag=:FLAC tags: '
     '--remove-all-tags'
@@ -51,9 +48,7 @@ _metaflac_opers=(
 
 _arguments "$_metaflac_opts[@]" \
     "*:FLAC file:_files -g \*.flac\(-.\)" \
-    - "shortcuts" \
+  - "shortcuts" \
     "$_metaflac_shorts[@]" \
-    - "(operations)" \
-    "$_metaflac_opers[@]" \
-    && return 0
-
+  - "(operations)" \
+    "$_metaflac_opers[@]"
diff --git a/Completion/Unix/Command/_module b/Completion/Unix/Command/_module
index c1c9f5c..060f05b 100644
--- a/Completion/Unix/Command/_module
+++ b/Completion/Unix/Command/_module
@@ -52,9 +52,9 @@ _module()
   )
 
   if (( CURRENT == 1 )); then
-    _describe -t commands 'module command' _module_cmds || compadd "$@"
+    _describe -t commands 'module command' _module_cmds
   else
-    local curcontext="$curcontext"
+    local curcontext="$curcontext" ret
 
     cmd="${${_module_cmds[(r)$words[1]:*]%%:*}}"
     # Deal with any aliases
@@ -65,7 +65,7 @@ _module()
       show) cmd="display";;
       keyword) cmd="apropos";;
     esac
-                
+
     if (( $#cmd ));
     then
       local update_policy
@@ -132,7 +132,7 @@ _module_available_modules()
 {
   _arguments -s \
     '(-a --append)'{--append,-a}'[append the directories instead of prepending]' \
-    '*:directory:_files -/'    
+    '*:directory:_files -/'
 }
 
 # Completion function for unuse
diff --git a/Completion/Unix/Command/_monotone b/Completion/Unix/Command/_monotone
index 83e18e3..bcaab87 100644
--- a/Completion/Unix/Command/_monotone
+++ b/Completion/Unix/Command/_monotone
@@ -1,8 +1,22 @@
 #compdef mtn
 
-local context state line ret
-typeset -a cmds
-typeset -A opt_args
+local -a cmds
+cmds=(
+  automate:automation db:database fdiff:debug fload:debug fmerge:debug
+  get_roster:debug identify:debug rcs_import:debug annotate:informative
+  cat:informative complete:informative diff:informative help:informative
+  list:informative log:informative ls:informative show_conflicts:informative
+  status:informative cert:key+cert chkeypass:key+cert dropkey:key+cert
+  genkey:key+cert trusted:key+cert pull:network push:network serve:network
+  sync:network privkey:packet\ i/o pubkey:packet\ i/o read:packet\ i/o
+  cvs_import:rcs approve:review comment:review disapprove:review tag:review
+  testresult:review checkout:tree co:tree explicit_merge:tree heads:tree
+  merge:tree merge_into_dir:tree migrate_workspace:tree propagate:tree
+  refresh_inodeprints:tree setup:tree set:vars unset:vars add:workspace
+  attr:workspace ci:workspace commit:workspace drop:workspace mv:workspace
+  pivot_root:workspace pluck:workspace rename:workspace revert:workspace
+  rm:workspace update:workspace
+)
 
 _arguments \
   '--brief[print a brief version of the normal output]' \
@@ -25,17 +39,5 @@ _arguments \
   '--ticker[set ticker style]:ticker style:(count dot none)' \
   '--version[print version number, then exit]' \
   '(-@ --xargs)'{-@,--xargs}'[insert command line arguments taken from the given file]:file:_files' \
-  '*:command:->cmd' && return 0
-
-case "$state" in
-  (cmd)
-  if (( CURRENT == 2 )); then
-    cmds=(automate:automation db:database fdiff:debug fload:debug fmerge:debug get_roster:debug identify:debug rcs_import:debug annotate:informative cat:informative complete:informative diff:informative help:informative list:informative log:informative ls:informative show_conflicts:informative status:informative cert:key+cert chkeypass:key+cert dropkey:key+cert genkey:key+cert trusted:key+cert pull:network push:network serve:network sync:network privkey:packet\ i/o pubkey:packet\ i/o read:packet\ i/o cvs_import:rcs approve:review comment:review disapprove:review tag:review testresult:review checkout:tree co:tree explicit_merge:tree heads:tree merge:tree merge_into_dir:tree migrate_workspace:tree propagate:tree refresh_inodeprints:tree setup:tree set:vars unset:vars add:workspace attr:workspace ci:workspace commit:workspace drop:workspace mv:workspace pivot_root:workspace pluck:workspace rename:workspace revert:workspace rm:workspace update:workspace)
-    _describe -t commands 'cmds' cmds && ret=0
-  else
-    _files
-  fi
-  ;;
-esac
-
-return ret
+  '1:command: _describe -t commands command cmds' \
+  '*:file:_files'
diff --git a/Completion/Unix/Command/_mpc b/Completion/Unix/Command/_mpc
index 1270767..11eab84 100644
--- a/Completion/Unix/Command/_mpc
+++ b/Completion/Unix/Command/_mpc
@@ -68,21 +68,21 @@ _mpc_command() {
   )
 
   if (( CURRENT == 1 )); then
-    _describe -t command "mpc commands" mpc_cmds
+    _describe -t commands "mpc command" mpc_cmds
   else
-    local curcontext="$curcontext"
+    local cmd=$words[1]
+    local curcontext="${curcontext%:*}:mpc-${cmd}" ret=1
+    if ! _call_function ret _mpc_$cmd; then
+      _default && ret=0
+    fi
+    return ret
   fi
-
-  local cmd=$words[1]
-
-  local curcontext="${curcontext%:*}:mpc-${cmd}"
-  _call_function ret _mpc_$cmd
 }
 
 _mpc_helper_bool() {
   local expl states
   states=(on off yes no 1 0 true false)
-  _wanted states expl boolean compadd $expl -a states
+  _wanted states expl boolean compadd -a states
 }
 
 (( $+functions[_mpc_helper_songnumbers] )) ||
@@ -100,7 +100,7 @@ _mpc_helper_songnumbers() {
     NM="$compstate[nmatches]"
   fi
 
-  out=("${(@f)$(_call_program song-numbers mpc $foo playlist 2>/dev/null)}")
+  out=("${(@f)$(_call_program song-numbers mpc $foo playlist)}")
   out=("${(@M)out[@]:#${~MATCH}}")
 
   sn=("${(@)${(@M)out}//(#b)(#s)(\#|[ >]#)([0-9]#)*/$match[2]}")
diff --git a/Completion/Unix/Command/_netcat b/Completion/Unix/Command/_netcat
index 396fc8e..4e4006b 100644
--- a/Completion/Unix/Command/_netcat
+++ b/Completion/Unix/Command/_netcat
@@ -1,11 +1,10 @@
 #compdef nc netcat
 
-local curcontext="$curcontext" state line expl
-typeset -A opt_args
-
 # handle name clash with the nedit client
-[[ $service = nc ]] && ! _pick_variant netcat=connect nedit -h &&
-    _nedit && return
+if [[ $service = nc ]] && ! _pick_variant netcat=connect nedit -h; then
+  _nedit
+  return
+fi
 
 if (( ! $+_nc_args )); then
   local help="$(_call_program options $words[1] -h < /dev/null 2>&1)"
@@ -14,17 +13,17 @@ if (( ! $+_nc_args )); then
     '*-e prog*' '-e+[program to exec after connect]:prog:_command_names -e'
      '*-g gateway*' '-g+[source-routing hop point]:gateway:_hosts'
      '*-G num*' '-G[source-routing pointer: 4, 8, 12]'
-     '*-i secs*' '-i+[delay interval for lines sent or ports scanned]:secs:'
+     '*-i secs*' '-i+[delay interval for lines sent or ports scanned]:delay (secs)'
      '*-l*' '-l[listen mode]'
      '*-n*' '-n[numeric-only IP addresses, no DNS]'
      '*-o file*' '-o+[hex dump of traffic]:file:_files'
      '*-p port*' '-p+[local port number]:port:_ports'
      '*-r*' '-r[randomize local and remote ports]'
-     '*-q secs*' '-q+[quit after EOF on stdin and delay of secs]:secs:'
+     '*-q secs*' '-q+[quit after EOF on stdin and delay of secs]:delay (secs)'
      '*-t*' '-t[answer TELNET negotiation]'
      '*-u*' '-u[UDP mode]'
      '*-v*' '-v[verbose]'
-     '*-w secs*' '-w+[timeout for connects and final net reads]:secs:'
+     '*-w secs*' '-w+[timeout for connects and final net reads]:timeout (secs)'
      '*-z*' '-z[zero-I/O mode]'
      '*-x*' '-x'
      '*-b*' '-b[allow broadcasts]'
@@ -32,7 +31,7 @@ if (( ! $+_nc_args )); then
   _nc_args=($optionmap[(K)"$help"])
 fi
 
-_arguments -C -s \
+_arguments -s \
   "$_nc_args[@]" \
   ':host:_hosts' \
-  ':port:_ports' && return 0
+  ':port:_ports'
diff --git a/Completion/Unix/Command/_notmuch b/Completion/Unix/Command/_notmuch
index b576d2b..d6cc58d 100644
--- a/Completion/Unix/Command/_notmuch
+++ b/Completion/Unix/Command/_notmuch
@@ -57,12 +57,15 @@ _notmuch_search()
 
 _notmuch()
 {
+  local ret=1
   if (( CURRENT > 2 )) ; then
     local cmd=${words[2]}
     curcontext="${curcontext%:*:*}:notmuch-$cmd"
     (( CURRENT-- ))
     shift words
-    _call_function ret _notmuch_$cmd
+    if ! _call_function ret _notmuch_$cmd; then
+      _default && ret=0
+    fi
     return ret
   else
     _notmuch_commands
diff --git a/Completion/Unix/Command/_pkg-config b/Completion/Unix/Command/_pkg-config
index 48b788a..e44b368 100644
--- a/Completion/Unix/Command/_pkg-config
+++ b/Completion/Unix/Command/_pkg-config
@@ -1,6 +1,6 @@
 #compdef pkg-config
 
-local arguments packages curcontext="$curcontext" stat line
+local arguments packages curcontext="$curcontext" state line ret=1
 declare -A opt_args
 
 arguments=(
@@ -11,31 +11,33 @@ arguments=(
       "--print-errors[cause errors to be printed]"
       "--silence-errors[prevent the printing of errors]"
       "--errors-to-stdout[print errors to stdout rather than stderr]"
-      "--cflags[prints the preprocessor and compile flags]"
+      "--cflags[print the preprocessor and compiler flags]"
       "--cflags-only-I[output -I flags only]"
       "--cflags-only-other[output cflags not covered by the cflags-only-I option]"
       "--debug[show verbose debug information]"
-      "--libs[prints the link flags]"
-      "--libs-only-L[prints the -L and -R parts of \"--libs\"]"
-      "--libs-only-l[prints the -l part of \"--libs\"]"
+      "--libs[print the link flags]"
+      "--libs-only-L[print the -L and -R parts of \"--libs\"]"
+      "--libs-only-l[print the -l part of \"--libs\"]"
       "--libs-only-other[output other libs]"
       "--list-all[list all known packages]"
       "--variable=[return the value of the specified variable]:variable"
       "--define-variable=[set the global value for a variable]:name value pair"
-      "--uninstalled[return successfully if any \"-uninstalled\" packages are being used and fails otherwise]"
-      "--exists[tests whether the package exists or not]"
+      "--uninstalled[return success if any \"-uninstalled\" packages are being used]"
+      "--exists[test whether the package exists or not]"
       "--atleast-version=[test whether the version is at least that of the specified value]:least value"
       "--exact-version=[test whether the version is exactly that of the specified value]:exact value"
       "--max-version=[test whether the version is no greater than some specific value]:max version"
 #      "--msvc-syntax[output linker flags in a form compatible with MSVC++ (Windows only)]"
 #      "--dont-define-prefix[disables automatic overiding of the variable \"prefix\" (Windows only)]"
 #      "--prefix-variable=[set the name of the variable \"prefix\" (Windows only)]:prefix value"
-      "*:package name:->package"
+      "*: :->packages"
 )
 
-_arguments -C $arguments
+_arguments -C $arguments && ret=0
 
 if [[ -n $state ]] ; then
-    packages=( ${(f)"$((pkg-config --list-all | cut -d' ' -f1) 2>/dev/null)"} )
-    compadd -a - packages
+  packages=( ${${(f)"$(_call_program packages pkg-config --list-all)"}%% *} )
+  _wanted packages expl 'package' compadd -a - packages && ret=0
 fi
+
+return ret
diff --git a/Completion/Unix/Command/_prove b/Completion/Unix/Command/_prove
index 75e83c3..1f21423 100644
--- a/Completion/Unix/Command/_prove
+++ b/Completion/Unix/Command/_prove
@@ -45,7 +45,7 @@ _arguments \
   '--source=[load or configure a SourceHandler]:source:' \
   {-a,--archive}'[store output in archive file]:file:_files' \
   {-j,--jobs}'[run N jobs in parallel]:jobs:' \
-  '*--state=[control persistent state]:state:' \
+  '*--state=[control persistent state]: :_values -s , state last failed passed all hot todo slow fast new old fresh save' \
   '--rc=[custom rcfile]:file:_files' \
-  '*:file or directory:_files' \
-  && return 0
+  '*--rules=[limit tests run (or not) in parallel]:rules' \
+  '*:file or directory:_files'
diff --git a/Completion/Unix/Command/_rar b/Completion/Unix/Command/_rar
index 1e3a261..e2081f6 100644
--- a/Completion/Unix/Command/_rar
+++ b/Completion/Unix/Command/_rar
@@ -38,7 +38,7 @@ common=(
 case $service in
   unrar)
     if (( CURRENT == 2 )); then
-       _values 'rar command' \
+      _values 'rar command' \
 	'e[extract files to current directory]' \
 	'l[list archive]' \
 	'lt[list archive (technical format)]' \
@@ -48,7 +48,7 @@ case $service in
 	'v[verbosely list archive]' \
 	'vt[verbosely list archive (technical format)]' \
 	'vb[verbosely list archive (bare format)]' \
-	'x[extract files with full path]' && return
+	'x[extract files with full path]'
     else
       _arguments -S \
 	'-ep3[expand paths to full including the drive letter]' \
@@ -58,7 +58,7 @@ case $service in
 	'-n+:file to include:_files' \
 	'-n@+:file of files to include:_files' \
         "$common[@]" \
-        '*:RAR files:_files -g \*.rar\(-.\)' && return
+        '*:RAR files:_files -g \*.rar\(-.\)'
     fi
   ;;
   rar)
@@ -89,7 +89,7 @@ case $service in
 	'v[verbosely list archive]' \
 	'vt[verbosely list archive (technical format)]' \
 	'vb[verbosely list archive (bare format)]' \
-	'x[extract files with full path]' && return
+	'x[extract files with full path]'
     else
       _arguments -S \
 	'-ag[generate archive name using the current date]' \
@@ -126,7 +126,7 @@ case $service in
 	'-w+[assign work directory]:work directory:_files -/' \
 	"$common[@]" \
 	'-z+[read archive comment from file]:comment file:_files' \
-	'*:files:_files' && return
+	'*:files:_files'
     fi
   ;;
 esac
diff --git a/Completion/Unix/Command/_rsync b/Completion/Unix/Command/_rsync
index 7bad03a..79d8243 100644
--- a/Completion/Unix/Command/_rsync
+++ b/Completion/Unix/Command/_rsync
@@ -35,10 +35,10 @@ if compset -P '*::*/' || compset -P 'rsync://*/*/'; then
   # attrs  size  date  time  name
 
   _wanted files expl 'remote file or directory' \
-      compadd -d remdispf ${${${${remdispf##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}
+      compadd -d remdispf ${${${${remdispf##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}##[^ ]## ##} && ret=0
 
   _wanted files expl 'remote file or directory' \
-      compadd -S/ -d remdispd ${${${${remdispd##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}
+      compadd -S/ -d remdispd ${${${${remdispd##[^ ]## ##}##[^ ]## ##}##[^ ]## ##}##[^ ]## ##} || (( ! ret ))
 
 elif compset -P 1 '*::' || compset -P 1 'rsync://*/'; then
 
diff --git a/Completion/Unix/Command/_rubber b/Completion/Unix/Command/_rubber
index 09e289a..f66540a 100644
--- a/Completion/Unix/Command/_rubber
+++ b/Completion/Unix/Command/_rubber
@@ -15,24 +15,24 @@ else
 fi
 
 _rubber_args=(
-      \*{-c,--command}'=[run the directive CMD before parsing]:command'
-      \*{-e,--epilogue}'=[run the directive CMD after parsing]:command'
-      {-z,--gzip}'[compress the final document]'
-      '(- *)'{-h,--help}'[show help]'
-      '--into=[go to directory DIR before compiling]:directory:_files -/'
-      {-l,--landscape}'[change paper orientation (if relevant)]'
-      {-n,--maxerr}'=[display at most NUM errors]:num'
-      \*{-m,--module}'=[use module]:module:($_rubber_modules)'
-      '--only=[only include the specified SOURCES]:sources'
-      \*{-o,--post}'=[postprocess with module]:postprocessor:($_rubber_modules)'
-      {-d,--pdf}'[produce PDF output instead of DVI]'
-      {-p,--ps}'[produce a PostScript document]'
-      {-q,--quiet}'[suppress messages]'
-      \*{-r,--read}'[read additional directives from a file]:directives files:_files'
-      {-s,--short}'[display errors in a compact form]'
-      \*{-I,--texpath}'=[add DIR to the search path for LaTeX]:tex path:_files -/'
-      \*{-v,--verbose}'[increase verbosity]'
-      '--version[print version information and exit]'
+  \*{-c,--command}'=[run specified directive command before parsing]:command'
+  \*{-e,--epilogue}'=[run specified directive command after parsing]:command'
+  '(-z --gzip)'{-z,--gzip}'[compress the final document]'
+  '(- *)'{-h,--help}'[show help information]'
+  '--into=[go to specified directory before compiling]:directory:_files -/'
+  '(-l --landscape)'{-l,--landscape}'[change paper orientation (if relevant)]'
+  '(-n --maxerr)'{-n,--maxerr}'=[display at most specified number of errors]:number'
+  \*{-m,--module}'=[use module]:module:($_rubber_modules)'
+  '--only=[only include the specified sources]:sources'
+  \*{-o,--post}'=[postprocess with module]:postprocessor:($_rubber_modules)'
+  '(-d --pdf -p -ps)'{-d,--pdf}'[produce PDF output instead of DVI]'
+  '(-p -ps -d --pdf)'{-p,--ps}'[produce a PostScript document]'
+  {-q,--quiet}'[suppress messages]'
+  \*{-r,--read}'[read additional directives from a file]:directives files:_files'
+  {-s,--short}'[display errors in compact form]'
+  \*{-I,--texpath}'=[add directory to the search path for LaTeX]:tex path:_files -/'
+  \*{-v,--verbose}'[increase verbosity]'
+  '--version[print version information and exit]'
 )
 
 case "$service" in
@@ -42,17 +42,15 @@ case "$service" in
       '--clean[remove produced files instead of compiling]' \
       {-f,--force}'[force at least one compilation]' \
       '--inplace[compile the documents from their source directory]' \
-      \*{-W,--warn}'=[report warnings of the given TYPE]:warnings:(all boxes misc refs)' \
+      \*{-W,--warn}'=[report warnings of the given type]:warnings:(all boxes misc refs)' \
       '*:LaTeX files:_files -g "*.(tex|dtx|lhs|w)(-.)"'
-      return 0
 	;;
 	
   rubber-pipe)
     _arguments -s \
       "$_rubber_args[@]" \
       {-k,--keep}'[keep the temporary files after compiling]' \
-      \*{-W,--warn}'=[report warnings of the given TYPE]:warnings:(all boxes misc refs)'
-      return 0
+      \*{-W,--warn}'=[report warnings of the given type]:warnings:(all boxes misc refs)'
 	;;
 	
   rubber-info)
@@ -65,8 +63,5 @@ case "$service" in
       '--refs[show the list of undefined references]' \
       '--warnings[show all LaTeX warnings]' \
       ':LaTeX file:_files -g "*.(tex|dtx|lhs|w)(-.)"'
-      return 0
   ;;
 esac
-
-return 1
diff --git a/Completion/Unix/Command/_screen b/Completion/Unix/Command/_screen
index 931946c..510fd71 100644
--- a/Completion/Unix/Command/_screen
+++ b/Completion/Unix/Command/_screen
@@ -1,20 +1,8 @@
 #compdef screen
 
-local curcontext="$curcontext" state line expl
+local curcontext="$curcontext" state line expl ret=1
 local scr_cmds sessions
 
-function __screen_normal() {
-    if (( CURRENT == 1 )) && [[ $PREFIX == /dev/* ]]; then
-        _path_files -g '*(%)'
-    elif (( CURRENT == 2 )) && [[ ${words[1]} == /dev/* ]]; then
-        _message "baud rate"
-    elif (( CURRENT > 2 )) && [[ ${words[1]} == /dev/* ]]; then
-        _message "no more parameters"
-    else
-        _normal "$@"
-    fi
-}
-
 scr_cmds=(
   acladd            aclchg            acldel            aclgrp
   aclumask          activity          addacl            allpartial
@@ -103,10 +91,21 @@ _arguments -C \
   '-Dx: :->any-sessions' \
   '-dx: :->any-sessions' \
   '-X[execute command as a screen command in the specified session]:screencmd:(${scr_cmds[@]})' \
-  '*::arguments: __screen_normal'
+  '*:: :->normal' && ret=0
 
 if [[ -n $state ]]; then
   case $state in
+    normal)
+      if (( CURRENT == 1 )) && [[ $PREFIX == /dev/* ]]; then
+	  _path_files -g '*(%)'
+      elif (( CURRENT == 2 )) && [[ ${words[1]} == /dev/* ]]; then
+	  _message "baud rate"
+      elif (( CURRENT > 2 )) && [[ ${words[1]} == /dev/* ]]; then
+	  _message "no more parameters"
+      else
+	  _normal
+      fi
+    ;;
     attached-sessions)
       sessions=(
         ${${${(M)${(f)"$(_call_program screen-sessions $words[1] \
@@ -134,4 +133,6 @@ if [[ -n $state ]]; then
     _wanted screen-sessions expl "${state%-*} screen process" \
 	compadd ${sessions#*.}
   fi
-fi
+fi && ret=0
+
+return ret
diff --git a/Completion/Unix/Command/_stgit b/Completion/Unix/Command/_stgit
index 6248267..f313f65 100644
--- a/Completion/Unix/Command/_stgit
+++ b/Completion/Unix/Command/_stgit
@@ -40,11 +40,11 @@ else
 	  compadd ${${(M)${(f)"$(stg series 2> /dev/null)"}##[+>] *}#[+>] } \
 		  && ret=0
       else
-	_files
+	_files && ret=0
       fi
     ;;
     (*)
-      _files
+      _files && ret=0
     ;;
   esac
 fi
diff --git a/Completion/Unix/Command/_strip b/Completion/Unix/Command/_strip
index 06f7243..726d87c 100644
--- a/Completion/Unix/Command/_strip
+++ b/Completion/Unix/Command/_strip
@@ -1,6 +1,6 @@
 #compdef strip
 
-local curcontext=$curcontext state line ret=0
+local curcontext=$curcontext state line ret=1
 declare -A opt_args
 declare -a args
 
@@ -11,8 +11,8 @@ if _pick_variant gnu=GNU solaris --version; then
     local expl
 
     _description files expl 'command-line-options file'
-    _files $expl && ret=0
-    return $ret
+    _files "$expl[@]"
+    return
   fi
   args=(
     '(-F --target)'{-F+,--target=}'[object code format to use]:bfd name:->bfdnames'
@@ -52,9 +52,9 @@ case $state in
     local expl
     declare -a bfdnames
 
-    bfdnames=(${=${(M)${(f)"$(_call_program bfdnames strip --help 2>/dev/null)"}:#strip: supported targets: *}#strip: supported targets: })
+    bfdnames=(${=${(M)${(f)"$(_call_program bfdnames strip --help)"}:#strip: supported targets: *}#strip: supported targets: })
     _describe -t bfdnames 'bfd name' bfdnames && ret=0
     ;;
 esac
 
-return $ret
+return ret
diff --git a/Completion/Unix/Command/_systemd b/Completion/Unix/Command/_systemd
index d2a7895..028ecdd 100644
--- a/Completion/Unix/Command/_systemd
+++ b/Completion/Unix/Command/_systemd
@@ -132,9 +132,9 @@ _hosts_or_user_at_host()
   )
 
   if (( CURRENT == 1 )); then
-    _describe -t commands 'systemctl command' _systemctl_cmds || compadd "$@"
+    _describe -t commands 'systemctl command' _systemctl_cmds
   else
-    local curcontext="$curcontext"
+    local curcontext="$curcontext" ret
 
     cmd="${${_systemctl_cmds[(r)$words[1]:*]%%:*}}"
     # Deal with any aliases
diff --git a/Completion/Unix/Command/_telnet b/Completion/Unix/Command/_telnet
index c7ab34f..1674eed 100644
--- a/Completion/Unix/Command/_telnet
+++ b/Completion/Unix/Command/_telnet
@@ -12,8 +12,8 @@ if (( ! $+_telnet_args )); then
   local help="$(_call_program options 'telnet -\?' < /dev/null 2>&1)"
   local -A optionmap
   optionmap=(
-    '*\[-4\]*' '-4[Force IPv4 address resolution]'
-    '*\[-6\]*' '-6[Force IPv6 address resolution]'
+    '*\[-4\]*' '-4[force IPv4 address resolution]'
+    '*\[-6\]*' '-6[force IPv6 address resolution]'
     '*\[-8\]*' '-8[allow 8-Bit data]'
     '*\[-E\]*' '-E[disable an escape character]'
     '*\[-K\]*' '-K[no automatic login]'
@@ -52,16 +52,16 @@ _arguments -C -s \
 case "$state" in
 ssl)
   _values -w 'SSL parameter' \
-    'debug[Send SSL debugging info to stderr]' \
-    '(nossl)ssl[Negotiate SSL connection]' \
-    '(ssl)nossl[Switch off SSL negotiation]' \
-    'certrequired[Require server certificate]' \
-    'secure[No fallback to unencrypted mode]' \
-    'verbose[Be verbose about certificates, etc.]' \
-    'verify[Set SSL verify flags]:int:' \
-    'cert[Specify certificate file]:certificate file:_path_files' \
-    'key[Specify key file]:key file:_path_files' \
-    'cipher[Set preferred cipher list]:ciphers:'
+    'debug[send SSL debugging info to stderr]' \
+    '(nossl)ssl[negotiate SSL connection]' \
+    '(ssl)nossl[switch off SSL negotiation]' \
+    'certrequired[require server certificate]' \
+    'secure[no fallback to unencrypted mode]' \
+    'verbose[be verbose about certificates, etc.]' \
+    'verify[set SSL verify flags]:int' \
+    'cert[specify certificate file]:certificate file:_path_files' \
+    'key[specify key file]:key file:_path_files' \
+    'cipher[set preferred cipher list]:cipher' && ret=0
   ;;
 
 hosts)
diff --git a/Completion/Unix/Command/_tidy b/Completion/Unix/Command/_tidy
index fce7190..ec2d742 100644
--- a/Completion/Unix/Command/_tidy
+++ b/Completion/Unix/Command/_tidy
@@ -123,6 +123,4 @@ _arguments \
   '--css-prefix:CSS class name:' \
   '--accessibility-check:priority level:(${access[@]})' \
   '--newline:newline character:(LF CRLF CR)' \
-  '*:file:_files' && return
-
-return 1
+  '*:file:_files'
diff --git a/Completion/Unix/Command/_tmux b/Completion/Unix/Command/_tmux
index 5a4a2d7..f0cc4be 100644
--- a/Completion/Unix/Command/_tmux
+++ b/Completion/Unix/Command/_tmux
@@ -1490,7 +1490,7 @@ function __tmux-windows() {
 # And here is the actual _tmux(), that puts it all together:
 function _tmux() {
     local curcontext="${curcontext}"
-    local mode state ret
+    local mode state ret=1
     local -a args
     local -x tmuxcommand
     unset tmux_describe
@@ -1508,22 +1508,22 @@ function _tmux() {
         '-v[request verbose logging]'
         '*:: :->subcommand_or_options'
     )
-    _arguments -C -s -w ${args} && return
+    _arguments -C -s -w ${args} && ret=0
 
     if [[ ${state} == "subcommand_or_options" ]]; then
         if (( CURRENT == 1 )) ; then
             zstyle -s ":completion:${curcontext}:subcommands" mode mode || mode='both'
             if [[ ${mode} == 'commands' ]]; then
-                _describe -t subcommands 'tmux commands' _tmux_commands
+                _describe -t subcommands 'tmux commands' _tmux_commands && ret=0
             elif [[ ${mode} == 'aliases' ]]; then
-                _describe -t subcommands 'tmux aliases' _tmux_aliases
+                _describe -t subcommands 'tmux aliases' _tmux_aliases && ret=0
             else
-                _describe -t subcommands 'tmux commands and aliases' _tmux_commands -- _tmux_aliases
+                _describe -t subcommands 'tmux commands and aliases' _tmux_commands -- _tmux_aliases && ret=0
             fi
         else
             if (( ${+commands[tmux]} == 0 )); then
                 _message '`tmux'\'' not found in $path; sub-cmd completions disabled.'
-                return 0
+                return
             fi
             tmuxcommand="${words[1]}"
             if [[ -n ${_tmux_aliasmap[$tmuxcommand]} ]] ; then
@@ -1545,6 +1545,7 @@ function _tmux() {
             _call_function ret _tmux-${tmuxcommand}
         fi
     fi
+    return ret
 }
 
 # description generation follows; only done on 1st _tmux call.
diff --git a/Completion/Unix/Command/_vcsh b/Completion/Unix/Command/_vcsh
index 47dbd9e..ddce876 100644
--- a/Completion/Unix/Command/_vcsh
+++ b/Completion/Unix/Command/_vcsh
@@ -1,18 +1,13 @@
 #compdef vcsh
 
 function __vcsh_repositories () {
-	local expl
 	local -a repos
-	repos=( ${(f)"$(command vcsh list)"} )
-	_describe -t repos 'repositories' repos
-}
-
-function __vcsh_not_implemented_yet () {
-	_message "Subcommand completion '${1#*-}': not implemented yet"
+	repos=( ${(f)"$(_call_program repositories vcsh list)"} )
+	_describe -t repositories 'repository' repos
 }
 
 function _vcsh-clone () {
-	__vcsh_not_implemented_yet "$0" #TODO
+	_default #TODO
 }
 
 function _vcsh-delete () {
@@ -52,9 +47,11 @@ function _vcsh-push () {
 }
 
 function _vcsh-rename () {
-	(( CURRENT == 2 )) && __vcsh_repositories
-	(( CURRENT == 3 )) && _message "new repository name"
-	(( CURRENT > 3 )) && _nothing
+  case $CURRENT in
+    2) __vcsh_repositories ;;
+    3) _message "new repository name" ;;
+    *) _nothing ;;
+  esac
 }
 
 function _vcsh-run () {
@@ -83,7 +80,7 @@ function _vcsh-write-gitignore () {
 }
 
 function _vcsh () {
-	local curcontext="${curcontext}"
+	local curcontext="${curcontext}" ret=1
 	local state vcshcommand
 	local -a args subcommands
 
@@ -112,24 +109,25 @@ function _vcsh () {
 		'*:: :->subcommand_or_options_or_repo'
 	)
 
-	_arguments -C ${args} && return
+	_arguments -C ${args} && ret=0
 
 	if [[ ${state} == "subcommand_or_options_or_repo" ]]; then
 		if (( CURRENT == 1 )); then
-			_describe -t subcommands 'vcsh sub-commands' subcommands
-			__vcsh_repositories
+			_describe -t subcommands 'vcsh sub-commands' subcommands && ret=0
+			__vcsh_repositories && ret=0
 		else
 			vcshcommand="${words[1]}"
 			if ! (( ${+functions[_vcsh-$vcshcommand]} )); then
 				# There is no handler function, so this is probably the name
 				# of a repository. Act accordingly.
-				_dispatch git git
+				_dispatch git git && ret=0
 			else
 				curcontext="${curcontext%:*:*}:vcsh-${vcshcommand}:"
 				_call_function ret _vcsh-${vcshcommand}
 			fi
 		fi
 	fi
+	return ret
 }
 
 _vcsh "$@"
diff --git a/Completion/Unix/Command/_zpool b/Completion/Unix/Command/_zpool
index 0f18eef..03ebd06 100644
--- a/Completion/Unix/Command/_zpool
+++ b/Completion/Unix/Command/_zpool
@@ -12,7 +12,7 @@ _zpool() {
 	)
 
 	versions=(
-		${${${(M)"${(f)$(zpool upgrade -v)}":#[[:space:]]#<->*}##[[:space:]]}%%[[:space:]]*}
+		${${${(M)"${(f)$(_call_program versions zpool upgrade -v)}":#[[:space:]]#<->*}##[[:space:]]}%%[[:space:]]*}
 	)
 
 	ro_props=(
@@ -87,15 +87,12 @@ _zpool() {
 
 	if [[ $service == "zpool" ]]; then
 		_arguments -C -A "-*" \
-			'-\?[Help]' \
-			'*::command:->subcmd' && return 0
+			'-\?[show help information]' \
+			'1:subcommand:compadd -a subcmds' \
+			'*:: :->subcmd' && return
 
-		if (( CURRENT == 1 )); then
-			_wanted commands expl "zpool subcommand" compadd -a subcmds
-			return
-		fi
 		service="$words[1]"
-		curcontext="${curcontext%:*}=$service:"
+		curcontext="${curcontext%:*}-$service:"
 	fi
 
 	case $service in
diff --git a/Completion/Unix/Type/_users b/Completion/Unix/Type/_users
index 3c8c702..2ea3b14 100644
--- a/Completion/Unix/Type/_users
+++ b/Completion/Unix/Type/_users
@@ -3,8 +3,8 @@
 local expl users
 
 if zstyle -a ":completion:${curcontext}:users" users users; then
-    _wanted users expl user compadd "$@" -a - users
-    return 0
+  _wanted users expl user compadd "$@" -a - users
+  return
 fi
 
 _wanted users expl user compadd "$@" -k - userdirs
diff --git a/Completion/X/Command/_urxvt b/Completion/X/Command/_urxvt
index b7ea06b..661897c 100644
--- a/Completion/X/Command/_urxvt
+++ b/Completion/X/Command/_urxvt
@@ -1,6 +1,6 @@
-#compdef rxvt urxvt urxvtc
+#compdef rxvt urxvt urxvtc urxvt256c urxvt256cc urxvt256c-ml urxvt256c-mlc
 
-local curcontext="$curcontext" state line expl
+local curcontext="$curcontext" state line expl ret=1
 local -a suf long_args
 typeset -A opt_args
 typeset -U extensions
diff --git a/Completion/X/Command/_x_utils b/Completion/X/Command/_x_utils
index 9448fd3..05a899b 100644
--- a/Completion/X/Command/_x_utils
+++ b/Completion/X/Command/_x_utils
@@ -1,12 +1,13 @@
 #compdef xdpyinfo xwininfo xkill xfontsel xfd xev xhost xon xsetroot xwd xwud xrdb xprop xlsatoms
 
-local ret=1 oret expl
+local curcontext="$curcontext" state line expl ret=1
 
 case "$service" in
 xdpyinfo)
   _x_arguments \
     -queryExtensions \
-    '-ext:extension: _x_extension -a'
+    '-ext:extension: _x_extension -a' \
+    -version
   ;;
 xwininfo)
   _x_arguments \
@@ -16,7 +17,7 @@ xwininfo)
     '(-name -root)-id:id: _x_window'
   ;;
 xprop)
-  _x_arguments \
+  _x_arguments -C \
     -{help,frame,notype,spy} \
     '-grammar[show grammar for command line options]' \
     '(-id -name)-root[use the root window as the target window]' \
@@ -28,16 +29,17 @@ xprop)
     '*-remove[specify an atom to remove from the target window]:atoms:->atoms' \
     '*-set[specify an atom and a value to set on the target window]:atoms:->atoms:value' \
     '*-f:atoms:->atoms:format: ::dformat' \
-    '*:atoms:->atoms' && ret=0
+    '*:atoms:->atoms'
   ;;
 xlsatoms)
-  _x_arguments \
+  _x_arguments -C \
     '*-format[printf-style format to use]:format' \
     '*-range[atom values to list]:[num]-[num]' \
     '*-name[name of single atom to print]:atom:->atoms'
   ;;
 xkill)
   _x_arguments \
+    -version \
     -frame \
     '(-id)-all' \
     '(-all)-id:window: _x_window' \
@@ -45,14 +47,16 @@ xkill)
   ;;
 xfontsel)
   _xt_arguments \
-    -{print,noscaled} \
+    -{print,scaled} \
     '-pattern:font pattern:_x_font' \
     '-sample:sample text' \
-    '-sample16:16-bit sample text'
+    '-sample16:16-bit sample text' \
+    '-sampleUCS:ISO10646 sample text'
   ;;
 xfd)
   _xt_arguments \
     '-fn:font: _x_font' \
+    '-fa:font: _xft_fonts' \
     -{box,center} \
     '-start:first character number' \
     '-bc:box border color:_x_color' \
@@ -66,7 +70,8 @@ xev)
     '-id:id:_x_window' \
     '-s[use save-under]' \
     '-name:window name' \
-    '-rv'
+    '-rv' \
+    '*-event:event mask:(keyboard mouse expose visibility structure substructure focus property colormap owner_grab_button randr)'
   ;;
 xhost)
   local type tmp match
@@ -120,8 +125,8 @@ xhost)
           'types:name family:compadd -S: - inet dnet nis krb' \
 	  'hosts:: _hosts' && ret=0
     fi
-    return ret
   fi
+  return ret
   ;;
 xon)
   _arguments \
@@ -165,7 +170,7 @@ xwud)
   ;;
 xrdb)
   _x_arguments \
-    -{help,quiet,symbols,retain} \
+    -{help,quiet,symbols,retain,version} \
     '(-all -screen -screens)-global' \
     '(-global -screen -screens)-all' \
     '(-global -all -screens)-screen' \
@@ -185,12 +190,10 @@ xrdb)
     '*-I-:include directory:_files -/' \
     '*:defaults file:_files'
   ;;
-esac
+esac && ret=0
 
-oret=$?
 if [[ $state == atoms ]]; then
   _wanted atoms expl atoms compadd ${${(f)"$(_call_program atoms xlsatoms 2> /dev/null)"}#*$'\t'} && ret=0
-else
-  ret=$oret
 fi
+
 return ret


^ permalink raw reply	[relevance 1%]

* Re: bug in zsh wait builtin - rhbz#1150541
  @ 2014-10-21 20:02  3% ` Peter Stephenson
  2014-10-22  6:55  4%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-10-21 20:02 UTC (permalink / raw)
  To: zsh-workers

On Tue, 21 Oct 2014 09:53:33 +0200
Tim Speetjens <tim.speetjens@gmail.com> wrote:
> I'ld like to report a bug originally filed in
> https://bugzilla.redhat.com/show_bug.cgi?id=1150541 which is still present
> in the latest version, 5.0.7
> 
> Title:
> zsh wait builtin shows an error and doesn't propagate exit code for a
> finished child process

There's an explanatory note in the latest POSIX standard about this,
quoted below.  It seems that the shell is basically required to remember
all background processes indefinitely (up to not very helpful get out
clauses).  As a baseline, CHILD_MAX here is 1024.  This probably needs
to be a special hash.


On most implementations, wait is a shell built-in. If it is called in a
subshell or separate utility execution environment, such as one of the
following:

    (wait)
    nohup wait ...
    find . -exec wait ... \;

it returns immediately because there are no known process IDs to wait
for in those environments.

Historical implementations of interactive shells have discarded the exit
status of terminated background processes before each shell
prompt. Therefore, the status of background processes was usually lost
unless it terminated while wait was waiting for it. This could be a
serious problem when a job that was expected to run for a long time
actually terminated quickly with a syntax or initialization error
because the exit status returned was usually zero if the requested
process ID was not found. This volume of POSIX.1-2008 requires the
implementation to keep the status of terminated jobs available until the
status is requested, so that scripts like:

    j1&
    p1=$!
    j2&
    wait $p1
    echo Job 1 exited with status $?
    wait $!
    echo Job 2 exited with status $?

work without losing status on any of the jobs. The shell is allowed to
discard the status of any process if it determines that the application
cannot get the process ID for that process from the shell. It is also
required to remember only {CHILD_MAX} number of processes in this
way. Since the only way to get the process ID from the shell is by using
the '!' shell parameter, the shell is allowed to discard the status of
an asynchronous list if "$!" was not referenced before another
asynchronous list was started. (This means that the shell only has to
keep the status of the last asynchronous list started if the application
did not reference "$!". If the implementation of the shell is smart
enough to determine that a reference to "$!" was not saved anywhere that
the application can retrieve it later, it can use this information to
trim the list of saved information. Note also that a successful call to
wait with no operands discards the exit status of all asynchronous
lists.)

If the exit status of wait is greater than 128, there is no way for the
application to know if the waited-for process exited with that value or
was killed by a signal. Since most utilities exit with small values,
there is seldom any ambiguity. Even in the ambiguous cases, most
applications just need to know that the asynchronous job failed; it does
not matter whether it detected an error and failed or was killed and did
not complete its job normally.

pws


^ permalink raw reply	[relevance 3%]

* Re: bug in zsh wait builtin - rhbz#1150541
  2014-10-21 20:02  3% ` Peter Stephenson
@ 2014-10-22  6:55  4%   ` Bart Schaefer
  2014-10-22 18:32  3%     ` Chet Ramey
  2014-10-23  8:32  0%     ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2014-10-22  6:55 UTC (permalink / raw)
  To: zsh-workers

On Oct 21,  9:02pm, Peter Stephenson wrote:
}
} There's an explanatory note in the latest POSIX standard about this,
} quoted below.  It seems that the shell is basically required to remember
} all background processes indefinitely (up to not very helpful get out
} clauses).  As a baseline, CHILD_MAX here is 1024.  This probably needs
} to be a special hash.

Since you've bothered to look this up ... does it go on to say what the
shell is supposed to do if PIDs roll over so that a new background job
gets the same $! as some previous one?  Is "kill" supposed to work the
same way?  (Do we need to send an inquiry to austin-group?  If so, you
will have to do it, my ability to post there has been messed up for a
long time.)

Note also that this is partly handled by the POSIX_JOBS option:

     When the option is set, it becomes possible to use the wait
     builtin to wait for the last job started in the background (as
     given by $!) even if that job has already exited.  This works even
     if the option is turned on temporarily around the use of the wait
     builtin.

I would say that any further change made for this should also be under
the auspices (so to speak) of POSIX_JOBS.

} Historical implementations of interactive shells have discarded the exit
} status of terminated background processes before each shell prompt.

Precisely.  This is not a "bug," as zsh's implementation predates 2008.
It's a POSIX non-conformity, but zsh has quite a few of those remaining,
I think.

-- 
Barton E. Schaefer


^ permalink raw reply	[relevance 4%]

* Re: bug in zsh wait builtin - rhbz#1150541
  2014-10-22  6:55  4%   ` Bart Schaefer
@ 2014-10-22 18:32  3%     ` Chet Ramey
  2014-10-23  8:32  0%     ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Chet Ramey @ 2014-10-22 18:32 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers; +Cc: chet.ramey

On 10/22/14, 2:55 AM, Bart Schaefer wrote:
> On Oct 21,  9:02pm, Peter Stephenson wrote:
> }
> } There's an explanatory note in the latest POSIX standard about this,
> } quoted below.  It seems that the shell is basically required to remember
> } all background processes indefinitely (up to not very helpful get out
> } clauses).  As a baseline, CHILD_MAX here is 1024.  This probably needs
> } to be a special hash.
> 
> Since you've bothered to look this up ... does it go on to say what the
> shell is supposed to do if PIDs roll over so that a new background job
> gets the same $! as some previous one?  Is "kill" supposed to work the
> same way?  (Do we need to send an inquiry to austin-group?  If so, you
> will have to do it, my ability to post there has been messed up for a
> long time.)

The implicit assumption in the Posix spec is that the pid space is large:
large enough that PIDs won't roll over and collide before you've gone
through CHILD_MAX children.  In practice, it happens surprisingly often.

The way I do it is to add the PIDs of exited jobs to a list, and prune it
if the list gets longer than the current child_max.  I check after fork()
and remove pids from the list if they recycle.

`wait' knows how to look through this list for child PID statuses.

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


^ permalink raw reply	[relevance 3%]

* [austin-group] Re: clarification on $*/$@
       [not found]     ` <54480AFD.9010504@case.edu>
@ 2014-10-22 20:52  0%   ` Bart Schaefer
  2014-10-23  9:29  4%     ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2014-10-22 20:52 UTC (permalink / raw)
  To: zsh-workers

Extensive quoting for context.

On Wed, 22 Oct 2014, Chet Ramey wrote:

> On 10/20/14, 5:54 PM, Stephane Chazelas wrote:
>
> > In the Bourne shell, $@ and $* were the same and were variables
> > whose content was the concatenation of the positional
> > parameters.
> >
> > The only thing special was "$@" ($@ quoted) in list contexts
> > (like in arguments to simple commands or in for i in "$@").
> >
> > So in:
> >
> > set a b@c
> > IFS=:,@
> > printf '<%s>\n' $*
> >
> > $* expands to "a:b@c" and undergoes word splitting.
>
> Not really, if you meant how the historical Bourne shell behaved.  The
> Bourne shell expands it to "a b@c" and performs word  splitting, resulting
> in
>
> <a b><c>

Hmm, zsh in sh-emulation behaves as Stephane describes:

$ set a b@c
$ IFS=:,@
$ printf '<%s>\n' $*
<a>
<b>
<c>
$ printf '<%s>\n' "$*"
<a:b@c>

> > set a b@c
> > IFS=
> > printf '<%s>\n' $@
> >
> > $@ expands to one argument only: "a b@c"
>
> Yes, this is what the Bourne shell did/does.

Hmm again, zsh:

$ IFS=
$ printf '<%s>\n' $@
<a>
<b@c>
$ unset IFS
$ printf '<%s>\n' $@
<a>
<b@c>

> > ksh introduced the joining on the joining on the first character
> > of IFS instead of a space character and arrays. $* and $@ still
> > seem to contain the concatenation of the positional parameters
> > with the first character of IFS except that in list contexts,
> > unquoted $* and $@ are also split on the positional parameters
> >
> > set a b
> > IFS=
> > a=$@
> >
> > assigns "ab" to $a, but
>
> That's not true: sh, ksh, bash, and so on assign "a b".  If you meant to
> use $*, you're correct.  Only $* is specified to use the first character
> of $IFS.

Zsh joins all arrays on the first character of IFS in this context.  Note
that assignment is one of the few contexts in which an array is joined
into a scalar.  [[ ]] is another.

$ set a b
$ IFS=
$ a=$@
$ print $a
ab
$ b=(b a)
$ a=${b[@]}
$ print $a
ba
$ [[ $@ = ab ]] && echo joined on IFS
joined on IFS

> If this is central to your argument, you might want to reframe it.

Is this an incompatibility that we should consider fixing?

> > set a b
> > IFS=
> > printf '<%s>\n' $@
> >
> > expands to 2 arguments "a" and "b".
>
> Yes, ksh/mksh and bash do this.  The historical Bourne shell expands it to
> one argument: "a b".

Zsh is as ksh here:

$ set a b
$ IFS=
$ printf '<%s>\n' $@
<a>
<b>

> > So:
> >
> > IFS=
> > set a b
> > printf '<%s>\n' $@
> >
> > would expand to one "ab" argument as you'd expect (as a logical
> > continuation of the Bourne shell and to be consistent with
> > a=$@ and from a shell that doesn't support arrays).
>
> One wouldn't.  Only dash does this.

Command-line arguments are not a context in which arrays are joined in
zsh, either.  Dash surprises me.

> > bash behaviour is rather odd. In some places $@ and $* seem to
> > be the concatenation of arguments with the first character of
> > IFS, sometimes with space.
> >
> > $ bash -c 'set a b; IFS=; a="$@"; echo "$a"'
> > a b
> > $ bash -c 'set a b; IFS=; a=$*; echo "$a"'
> > ab
> > $ bash -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
> > c
>
> Yes, the third case is a problem.  The other two cases are consistent with
> ksh93, mksh, and other Posix shells except dash.

Zsh gives:

% ARGV0=sh zsh -fc 'set a b; IFS=; a="$@"; echo "$a"'
ab
% ARGV0=sh zsh -fc 'set a b; IFS=; a=$*; echo "$a"'
ab
% ARGV0=sh zsh -fc 'set a b; IFS=; a="a bc"; echo ${a#$*}'
a bc


^ permalink raw reply	[relevance 0%]

* Re: bug in zsh wait builtin - rhbz#1150541
  2014-10-22  6:55  4%   ` Bart Schaefer
  2014-10-22 18:32  3%     ` Chet Ramey
@ 2014-10-23  8:32  0%     ` Peter Stephenson
    1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2014-10-23  8:32 UTC (permalink / raw)
  To: zsh-workers

On Tue, 21 Oct 2014 23:55:42 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Oct 21,  9:02pm, Peter Stephenson wrote:
> }
> } There's an explanatory note in the latest POSIX standard about this,
> } quoted below.  It seems that the shell is basically required to remember
> } all background processes indefinitely (up to not very helpful get out
> } clauses).  As a baseline, CHILD_MAX here is 1024.  This probably needs
> } to be a special hash.
> 
> Since you've bothered to look this up ... does it go on to say what the
> shell is supposed to do if PIDs roll over so that a new background job
> gets the same $! as some previous one?

No, and as Chet says this appears to be basically "caveat usator".  The
user needs to be careful / lucky enough to perform their "wait" before
the numbers come round again.

>  Is "kill" supposed to work the same way?

There's no indication kill needs to have this.  Presumably this is
because for kill you don't need to have a sensible exit status, just a
reasonable likelihood the job is dead (or wedged in some state where
that signal doesn't work, but that's an entirely different problem).

> Note also that this is partly handled by the POSIX_JOBS option:
> 
>      When the option is set, it becomes possible to use the wait
>      builtin to wait for the last job started in the background (as
>      given by $!) even if that job has already exited.  This works even
>      if the option is turned on temporarily around the use of the wait
>      builtin.
> 
> I would say that any further change made for this should also be under
> the auspices (so to speak) of POSIX_JOBS.

That would already cover the cases in the "bug" report, in fact.

I'm not really sure why we wouldn't just implement this particular
feature generally, despite the current status.  Is there any reason why
you'd *want* "wait" to give you an error (which isn't a particularly
useful message) owing to a race condition you can't control?  POSIX_JOBS
was originally designed for things where the behaviour was clearly
incompatible.

pws


^ permalink raw reply	[relevance 0%]

* Re: [austin-group] Re: clarification on $*/$@
  2014-10-22 20:52  0%   ` [austin-group] Re: clarification on $*/$@ Bart Schaefer
@ 2014-10-23  9:29  4%     ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2014-10-23  9:29 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

Hi Bart,

the discussion is at
http://thread.gmane.org/gmane.comp.standards.posix.austin.general/9972
where there have been more said about zsh

I'm not sure it's very productive to have a separate discussion
here, but the austin group list is a subscribers only list, so I
suppose CCing zsh-workers wouldn't work well.

In any case, my understanding is that zsh (in sh emulation) is
POSIX compliant by all interpretations of it (as it's quite
unclear) and is the most consistent implementation, so I don't
think zsh should change anything in that regard.

Cheers,
Stephane


^ permalink raw reply	[relevance 4%]

* Re: bug in zsh wait builtin - rhbz#1150541
  @ 2014-10-25 19:08  2%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-10-25 19:08 UTC (permalink / raw)
  To: zsh-workers

On Thu, 23 Oct 2014 21:50:41 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Oct 23,  9:32am, Peter Stephenson wrote:
> }
> } On Tue, 21 Oct 2014 23:55:42 -0700
> } Bart Schaefer <schaefer@brasslantern.com> wrote:
> } >  Is "kill" supposed to work the same way?
> } 
> } There's no indication kill needs to have this.  Presumably this is
> } because for kill you don't need to have a sensible exit status, just a
> } reasonable likelihood the job is dead (or wedged in some state where
> } that signal doesn't work, but that's an entirely different problem).
> 
> My implied point was that both commands accept either job identifiers
> (%3, %?sleep?) or PIDs and presumably should act the same way for the
> same child process regardless of how it was identified; or else PIDs
> are something entirely different than job identifiers and the rules
> are different.  But for "wait" treat PIDs magically while "kill" does
> not, seems inconsistent.

In any case there appears to be no call for kill to do this.

> } > Note also that this is partly handled by the POSIX_JOBS option:
> } > 
> } >      When the option is set, it becomes possible to use the wait
> } >      builtin to wait for the last job started in the background (as
> } >      given by $!) even if that job has already exited.  This works even
> } >      if the option is turned on temporarily around the use of the wait
> } >      builtin.
> } > 
> } > I would say that any further change made for this should also be under
> } > the auspices (so to speak) of POSIX_JOBS.
> } 
> } That would already cover the cases in the "bug" report, in fact.
> 
> I don't think it would, because the report starts two background jobs
> and then waits for the one started first.  The current implementation
> only allows the most recent $! to be waited for after it exits.

I missed that.
 
> } I'm not really sure why we wouldn't just implement this particular
> } feature generally, despite the current status.  Is there any reason why
> } you'd *want* "wait" to give you an error (which isn't a particularly
> } useful message) owing to a race condition you can't control?
> 
> There are a lot of error messages that a script probably doesn't want
> but an interactive user might.  Why do you want "wait %3" to report
> "%3: no such job"?  If nobody wants it, why did it take us 25 years
> to figure that out?

The point I was making wasn't that errors were necessarily bad, if they
could detect something useful, but that the error wasn't detecting
anything particularly useful as there was an intrinsic race, and was
thereby claiming by incorrect guesswork that the PID wasn't a child of
the shell (and trying to claim that's OK because it no longer is is the
sort of argument that will annoy users, who want things to work without
long justifications).  It's incorrect no matter how long it's been
there.

In any case I don't think using wait in this fashion is useful
interactively.  It's replaced by job control.  If you turn off job
control to rely on a system designed for scripts that therefore has no
notifications you are shooting yourself in the foot.  If you use the
scripting-style mechanism you accept the consequences.

(Not sure it's even worth arguing about, but it's Saturday and I'm no
longer on git duty...)

Here's an implementation.  I've given it the obvious finger test, but
there may be some more stressful tests we could apply.  Note I'm only
recording background PIDs, since the user can't explicitly wait for
foreground PIDs; it's possible I've missed a case where something can
be in the background but that would suggest the job is wrongly recorded.

One piece of unfinished business: I think lastpid_status can go, but the
logic associated with it is rather different from what I just
implemented so I'd like some further thoughts over whether there's a
case the latter doesn't cover.  As I've written it lastpid_status is not
an optimisation because you need to remove it from the list anyway ---
you can only wait for a given PID once, after which returning an error
is the correct behaviour.

Note it's not useful to store a job, as opposed to a process, in this
fashion, because we reuse jobs immediately, which is standard shell
behaviour (it would be annoying for job numbers to increment rapidly).
That fits with the fact this isn't really designed for use with job
control.  I've tried to clarify the point in the manual entry for
"wait".

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 46f40cc..edc335e 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -2059,6 +2059,22 @@ then all currently active child processes are waited for.
 Each var(job) can be either a job specification or the process ID
 of a job in the job table.
 The exit status from this command is that of the job waited for.
+
+It is possible to wait for recent processes (specified by process ID,
+not by job) that were running in the background even if the process has
+exited.  Typically the process ID will be recorded by capturing the
+value of the variable tt($!) immediately after the process has been
+started.  There is a limit on the number of process IDs remembered by
+the shell; this is given by the value of the system configuration
+parameter tt(CHILD_MAX).  When this limit is reached, older process IDs
+are discarded, least recently started processes first.
+
+Note there is no protection against the process ID wrapping, i.e. if the
+wait is not executed soon enough there is a chance the process waited
+for is the wrong one.  A conflict implies both process IDs have been
+generated by the shell, as other processes are not recorded, and that
+the user is potentially interested in both, so this problem is intrinsic
+to process IDs.
 )
 findex(whence)
 item(tt(whence) [ tt(-vcwfpams) ] var(name) ...)(
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 068a253..452b258 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1434,10 +1434,10 @@ shell is saved for output within a subshell (for example, within a
 pipeline).  When the option is set, the output of tt(jobs) is empty
 until a job is started within the subshell.
 
-When the option is set, it becomes possible to use the tt(wait) builtin to
-wait for the last job started in the background (as given by tt($!)) even
-if that job has already exited.  This works even if the option is turned
-on temporarily around the use of the tt(wait) builtin.
+In previous versions of the shell, it was necessary to enable
+tt(POSIX_JOBS) in order for the builtin command tt(wait) to return the
+status of background jobs that had already exited.  This is no longer
+the case.
 )
 enditem()
 
diff --git a/Src/jobs.c b/Src/jobs.c
index bd95afb..ec76c4f 100644
--- a/Src/jobs.c
+++ b/Src/jobs.c
@@ -1940,6 +1940,122 @@ maybeshrinkjobtab(void)
     unqueue_signals();
 }
 
+/*
+ * Definitions for the background process stuff recorded below.
+ * This would be more efficient as a hash, but
+ * - that's quite heavyweight for something not needed very often
+ * - we need some kind of ordering as POSIX allows us to limit
+ *   the size of the list to the value of _SC_CHILD_MAX and clearly
+ *   we want to clear the oldest first
+ * - cases with a long list of background jobs where the user doesn't
+ *   wait for a large number, and then does wait for one (the only
+ *   inefficient case) are rare
+ * - in the context of waiting for an external process, looping
+ *   over a list isn't so very inefficient.
+ * Enough excuses already.
+ */
+
+/* Data in the link list, a key (process ID) / value (exit status) pair. */
+struct bgstatus {
+    pid_t pid;
+    int status;
+};
+typedef struct bgstatus *Bgstatus;
+/* The list of those entries */
+LinkList bgstatus_list;
+/* Count of entries.  Reaches value of _SC_CHILD_MAX and stops. */
+long bgstatus_count;
+
+/*
+ * Remove and free a bgstatus entry.
+ */
+static void rembgstatus(LinkNode node)
+{
+    zfree(remnode(bgstatus_list, node), sizeof(struct bgstatus));
+    bgstatus_count--;
+}
+
+/*
+ * Record the status of a background process that exited so we
+ * can execute the builtin wait for it.
+ *
+ * We can't execute the wait builtin for something that exited in the
+ * foreground as it's not visible to the user, so don't bother recording.
+ */
+
+/**/
+void
+addbgstatus(pid_t pid, int status)
+{
+    static long child_max;
+    Bgstatus bgstatus_entry;
+
+    if (!child_max) {
+#ifdef _SC_CHILD_MAX
+	child_max = sysconf(_SC_CHILD_MAX);
+	if (!child_max) /* paranoia */
+#endif
+	{
+	    /* Be inventive */
+	    child_max = 1024L;
+	}
+    }
+
+    if (!bgstatus_list) {
+	bgstatus_list = znewlinklist();
+	/*
+	 * We're not always robust about memory failures, but
+	 * this is pretty deep in the shell basics to be failing owing
+	 * to memory, and a failure to wait is reported loudly, so test
+	 * and fail silently here.
+	 */
+	if (!bgstatus_list)
+	    return;
+    }
+    if (bgstatus_count == child_max) {
+	/* Overflow.  List is in order, remove first */
+	rembgstatus(firstnode(bgstatus_list));
+    }
+    bgstatus_entry = (Bgstatus)zalloc(sizeof(*bgstatus_entry));
+    if (!bgstatus_entry) {
+	/* See note above */
+	return;
+    }
+    bgstatus_entry->pid = pid;
+    bgstatus_entry->status = status;
+    if (!zaddlinknode(bgstatus_list, bgstatus_entry)) {
+	zfree(bgstatus_entry, sizeof(*bgstatus_entry));
+	return;
+    }
+    bgstatus_count++;
+}
+
+/*
+ * See if pid has a recorded exit status.
+ * Note we make no guarantee that the PIDs haven't wrapped, so this
+ * may not be the right process.
+ *
+ * This is only used by wait, which must only work on each
+ * pid once, so we need to remove the entry if we find it.
+ */
+
+static int getbgstatus(pid_t pid)
+{
+    LinkNode node;
+    Bgstatus bgstatus_entry;
+
+    if (!bgstatus_list)
+	return -1;
+    for (node = firstnode(bgstatus_list); node; incnode(node)) {
+	bgstatus_entry = (Bgstatus)getdata(node);
+	if (bgstatus_entry->pid == pid) {
+	    int status = bgstatus_entry->status;
+	    rembgstatus(node);
+	    return status;
+	}
+    }
+    return -1;
+}
 
 /* bg, disown, fg, jobs, wait: most of the job control commands are     *
  * here.  They all take the same type of argument.  Exception: wait can *
@@ -2085,10 +2201,24 @@ bin_fg(char *name, char **argv, Options ops, int func)
 		}
 		if (retval == 0)
 		    retval = lastval2;
-	    } else if (isset(POSIXJOBS) &&
-		       pid == lastpid && lastpid_status >= 0L) {
+	    } else if (pid == lastpid && lastpid_status >= 0L) {
+		/*
+		 * Historical note: this used to be covered by
+		 * isset(POSIXJOBS), but reporting that the last
+		 * PID to exist isn't a child of the shell is not
+		 * obviously useful behaviour.
+		 */
 		retval = (int)lastpid_status;
-	    } else {
+		/*
+		 * We can't wait for a PID twice so ensure it's
+		 * not on the list, either.
+		 *
+		 * TODO: We could optimise this because pid must be at
+		 * the end of the list, if present, but I think we now
+		 * can get rid of lastpid_status anyway.
+ 		 */
+		(void)getbgstatus(pid);
+	    } else if ((retval = getbgstatus(pid)) < 0) {
 		zwarnnam(name, "pid %d is not a child of this shell", pid);
 		/* presumably lastval2 doesn't tell us a heck of a lot? */
 		retval = 1;
diff --git a/Src/linklist.c b/Src/linklist.c
index 1e364fb..3aa8125 100644
--- a/Src/linklist.c
+++ b/Src/linklist.c
@@ -118,6 +118,8 @@ znewlinklist(void)
     LinkList list;
 
     list = (LinkList) zalloc(sizeof *list);
+    if (!list)
+	return NULL;
     list->list.first = NULL;
     list->list.last = &list->node;
     list->list.flags = 0;
@@ -152,6 +154,8 @@ zinsertlinknode(LinkList list, LinkNode node, void *dat)
 
     tmp = node->next;
     node->next = new = (LinkNode) zalloc(sizeof *tmp);
+    if (!new)
+	return NULL;
     new->prev = node;
     new->dat = dat;
     new->next = tmp;
diff --git a/Src/signals.c b/Src/signals.c
index 2df69f9..7b212e6 100644
--- a/Src/signals.c
+++ b/Src/signals.c
@@ -530,6 +530,12 @@ wait_for_processes(void)
 	 */
 	if (pn != NULL && pid == lastpid && lastpid_status != -1L)
 	    lastpid_status = lastval2;
+	/*
+	 * Accumulate a list of older jobs (the above is basically an
+	 * optimisation for the last job.
+	 */
+	if (!(jn->stat & (STAT_CURSH|STAT_BUILTIN)) && jn - jobtab != thisjob)
+	    addbgstatus(pid, (int)lastval2);
     }
 }
 
 
-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[relevance 2%]

* Re: Bug report: Strange behaviour of $SHLVL in subshell.
  @ 2014-11-01 19:15  2% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-11-01 19:15 UTC (permalink / raw)
  To: zsh-workers

On Sat, 1 Nov 2014 15:31:21 +0100
Eliseo Martínez <eliseomarmol@gmail.com> wrote:
> To me, the following is not logical/expected behaviour:
> 
>     $ echo $SHLVL
>     1
>     $ zsh -c 'echo $SHLVL'
>     2
>     $ zsh -c '(echo $SHLVL)'
>     1
> 
> I’d just like to know if it is a bug, or has some kind of explanation.

I think the explanation is it's a bug.  There's a complication owing to
the shell knowing it doesn't actually need to fork, but it certainly
looks like one weirdness too far to expose to the user.

In a bit more detail:  there are optimisations in the shell so that it
knows it doesn't need to fork a new shell when it's about to exit the
parent shell anway.  A quick reading of POSIX (2.12, Shell Execution
Environment, which describes a subshell environment at the end) suggests
this is OK --- it's not tied to what actual process you're in, just how
it affects the environment seen by the command and the parent shell, the
last being academic in this case as you're about to exit.  When it
doesn't fork, it assumes that means it's about to start some command
that now takes over the function of the current shell.  But that's not
true here --- we're actually going to be running code within the current
shell but treating it as a subshell environment.

So currently we don't set the "forked" variable in execcmd() in this
case.  But the other uses of this variable are mostly to do with noting
that if we haven't forked, we need to be able to restore the current
shell environment after the command, which is also irrelevant here.  So
as far as I can see, we can ensure what the user sees is sane by setting
the "forked" flag for an explicit subshell environment even if we
haven't forked.

Decrementing SHLVL to reflect an exec when we're not forked --- i.e. if
we're starting a new shell we note that we're not one level deeper
because in this case the new shell replaced the old one --- was a bit
controversial when it was introduced.  It's the right thing to do if
SHLVL is trying to answer the question "how many levels of shell are
over my head right now in terms of processes", wrong if SHLVL is trying
to answer the question "how many levels of shell execution did I go
through before arriving at this point".

It's possible setting forked = 1 other times when we set is_exec is the
right thing to do.

pws


diff --git a/Src/exec.c b/Src/exec.c
index 5bbd4e1..d2d4e80 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -2995,6 +2995,15 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	 * Note that any form of exec means that the subshell is fake *
 	 * (but we may be in a subshell already).                     */
 	is_exec = 1;
+	/*
+	 * If we are in a subshell environment anyway, say we're forked,
+	 * even if we're actually not forked because we know the
+	 * subshell is exiting.  This ensures SHLVL reflects the current
+	 * shell, and also optimises out any save/restore we'd need to
+	 * do if we were returning to the main shell.
+	 */
+	if (type == WC_SUBSH)
+	    forked = 1;
     }
 
     if ((esglob = !(cflags & BINF_NOGLOB)) && args && htok) {
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index d7f39cb..0cbe6c9 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1548,7 +1548,7 @@
    foo=
    print ${foo:wq}
    print ${:wq}
-0:Empty parameter shouldn't cause modifiers to crash the shell
+0:Empty parameter should not cause modifiers to crash the shell
 >
 >
 
@@ -1656,3 +1656,10 @@
 >h:i
 >j,k
 >l
+
+  SHLVL=1
+  $ZTST_testdir/../Src/zsh -c 'echo $SHLVL'
+  $ZTST_testdir/../Src/zsh -c '(echo $SHLVL)'
+0:SHLVL appears sensible when about to exit shell
+>2
+>2


^ permalink raw reply	[relevance 2%]

* Different behaviour of zsh with two input redirections compared to all other POSIX shells I have installed
@ 2014-12-15 11:33  8% Axel Beckert
  2014-12-15 11:46  5% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Axel Beckert @ 2014-12-15 11:33 UTC (permalink / raw)
  To: zsh-workers

Hi,

while I was debugging some non-zsh related issue with "yes '' |
sometool", I noticed that zsh behaves differently in the following
(possibly neither common nor useful, likely esoteric :-) case:

~ → cat /tmp/bar.txt
bar
~ → zsh -c 'echo foo | cat -v < /tmp/bar.txt'
foo
bar
~ → bash -c 'echo foo | cat -v < /tmp/bar.txt'
bar
~ → dash -c 'echo foo | cat -v < /tmp/bar.txt'
bar
~ → ksh -c 'echo foo | cat -v < /tmp/bar.txt'
bar
~ → mksh -c 'echo foo | cat -v < /tmp/bar.txt'
bar

Interestingly some non-POSIX shells have the probably sanest approach:

~ → tcsh -c 'echo foo | cat -v < /tmp/bar.txt'
Ambiguous input redirect.
~ → csh -c 'echo foo | cat -v < /tmp/bar.txt'
Ambiguous input redirect.

(And yes, csh is _not_ a symlink to tcsh on that system. :-)

Is this expected/wanted zsh behaviour? Is this something we should fix
in zsh? And if so, should it rather behave like bash or like tcsh? :-)

I tend to tcsh's variant although I suspect that this could cause more
breakage than bash's behaviour.

		Kind regards, Axel
-- 
/~\  Plain Text Ribbon Campaign                   | Axel Beckert
\ /  Say No to HTML in E-Mail and News            | abe@deuxchevaux.org  (Mail)
 X   See http://www.nonhtmlmail.org/campaign.html | abe@noone.org (Mail+Jabber)
/ \  I love long mails: http://email.is-not-s.ms/ | http://noone.org/abe/ (Web)


^ permalink raw reply	[relevance 8%]

* Re: Different behaviour of zsh with two input redirections compared to all other POSIX shells I have installed
  2014-12-15 11:33  8% Different behaviour of zsh with two input redirections compared to all other POSIX shells I have installed Axel Beckert
@ 2014-12-15 11:46  5% ` Peter Stephenson
  2014-12-15 11:53  5%   ` Axel Beckert
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2014-12-15 11:46 UTC (permalink / raw)
  To: zsh-workers

On Mon, 15 Dec 2014 12:33:14 +0100
Axel Beckert <abe@deuxchevaux.org> wrote:
> Is this expected/wanted zsh behaviour? Is this something we should fix
> in zsh? And if so, should it rather behave like bash or like tcsh? :-)

You'll need to try with "unsetopt multios" before comparing with other
shells.  (I'm not suggesting that necessarily removes all issues...)

pws


^ permalink raw reply	[relevance 5%]

* Re: Different behaviour of zsh with two input redirections compared to all other POSIX shells I have installed
  2014-12-15 11:46  5% ` Peter Stephenson
@ 2014-12-15 11:53  5%   ` Axel Beckert
  0 siblings, 0 replies; 200+ results
From: Axel Beckert @ 2014-12-15 11:53 UTC (permalink / raw)
  To: zsh-workers

Hi Peter,

On Mon, Dec 15, 2014 at 11:46:57AM +0000, Peter Stephenson wrote:
> On Mon, 15 Dec 2014 12:33:14 +0100
> Axel Beckert <abe@deuxchevaux.org> wrote:
> > Is this expected/wanted zsh behaviour? Is this something we should fix
> > in zsh? And if so, should it rather behave like bash or like tcsh? :-)
> 
> You'll need to try with "unsetopt multios" before comparing with other
> shells.  (I'm not suggesting that necessarily removes all issues...)

Thanks for that hint. I knew about multiple output redirection being a
zsh-only feature, but I didn't expect that this also affects input
redirection in the same way despite it makes sense (now).

And indeed:

~ → zsh -o nomultios -c 'echo foo | cat -v < /tmp/bar.txt'
bar

So it's not a bug, it's a feature! Thanks again. :-)

		Kind regards, Axel
-- 
/~\  Plain Text Ribbon Campaign                   | Axel Beckert
\ /  Say No to HTML in E-Mail and News            | abe@deuxchevaux.org  (Mail)
 X   See http://www.nonhtmlmail.org/campaign.html | abe@noone.org (Mail+Jabber)
/ \  I love long mails: http://email.is-not-s.ms/ | http://noone.org/abe/ (Web)


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  @ 2014-12-18 19:58  3%     ` Bart Schaefer
  2014-12-18 20:09  0%       ` Peter Stephenson
                         ` (3 more replies)
  0 siblings, 4 replies; 200+ results
From: Bart Schaefer @ 2014-12-18 19:58 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

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

On Dec 18, 2014 11:48 AM, "Peter Stephenson" <p.w.stephenson@ntlworld.com>
wrote:
>
> On Thu, 18 Dec 2014 19:29:17 +0000
> Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> > On Thu, 18 Dec 2014 21:19:25 +0300
> > ZyX <kp-pav@yandex.ru> wrote:
> > > but its 0x83 byte which is the last byte of the first unicode
> > > codepoint that forms the variable name represented as UTF-8 is using
> > > zsh `Meta` escape in the `env` output (which clearly is a bug assuming
> > > the fact that unicode variable is exported is not).
> >
> > Yes, indeed.
>
> And on import to the shell.

Are we sure it's even "legal" to export Unicode variable names?  Internally
we can kinda ignore POSIX as we choose, but the environment crosses those
boundaries.

^ permalink raw reply	[relevance 3%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-18 19:58  3%     ` Bart Schaefer
@ 2014-12-18 20:09  0%       ` Peter Stephenson
       [not found]           ` <54933513.6010501@case.edu>
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2014-12-18 20:09 UTC (permalink / raw)
  To: Zsh hackers list

On Thu, 18 Dec 2014 11:58:11 -0800
Bart Schaefer <schaefer@brasslantern.com> wrote:
> Are we sure it's even "legal" to export Unicode variable names?  Internally
> we can kinda ignore POSIX as we choose, but the environment crosses those
> boundaries.

As far as I can see it's described as not portable, which is obviously
correct, but not actually a violation of anything.

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html

However...  AARGH we were already metafying and unmetafying the value, but
not the identifier...  So now we're doing it twice.

I will give it a bit more consideration before posting anything else.

pws


^ permalink raw reply	[relevance 0%]

* Fwd: Re: [BUG] Unicode variables can be exported and are exported metafied
       [not found]           ` <54933513.6010501@case.edu>
@ 2014-12-18 20:20  0%         ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2014-12-18 20:20 UTC (permalink / raw)
  To: Zsh hackers list

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

Assuming it's OK to forward this.
---------- Forwarded message ----------
From: "Chet Ramey" <chet.ramey@case.edu>
Date: Dec 18, 2014 12:12 PM
Subject: Re: [BUG] Unicode variables can be exported and are exported
metafied
To: "Bart Schaefer" <schaefer@brasslantern.com>
Cc: <chet.ramey@case.edu>

On 12/18/14, 2:58 PM, Bart Schaefer wrote:

> Are we sure it's even "legal" to export Unicode variable names?
Internally
> we can kinda ignore POSIX as we choose, but the environment crosses those
> boundaries.

Yes, it is.

"Other characters may be permitted by an implementation; applications
shall tolerate the presence of such names."

http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU    chet@case.edu    http://cnswww.cns.cwru.edu/~chet/

^ permalink raw reply	[relevance 0%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-18 19:58  3%     ` Bart Schaefer
  2014-12-18 20:09  0%       ` Peter Stephenson
       [not found]           ` <54933513.6010501@case.edu>
@ 2014-12-19  9:29  0%       ` Christoph (Stucki) von Stuckrad
  2014-12-19 18:17  0%       ` Christoph (Stucki) von Stuckrad
  3 siblings, 0 replies; 200+ results
From: Christoph (Stucki) von Stuckrad @ 2014-12-19  9:29 UTC (permalink / raw)
  To: zsh-workers

On Thu, 18 Dec 2014, Bart Schaefer wrote:

> Are we sure it's even "legal" to export Unicode variable names?  Internally
> we can kinda ignore POSIX as we choose, but the environment crosses those
> boundaries.

Independend of being 'legal' to me it seems dangerous!

Comparing the 'working as written' example:

~$ M='surprise; : ' MÄRCHEN=story sh -c 'echo $MÄRCHEN'
story

to running it with all the other shells I keep around
(bash, dash, ash, sash - untested ksh and csh)
you always get:

..................................vvvv
~$ M='surprise; : ' MÄRCHEN=story bash -c 'echo $MÄRCHEN'
surprise; : ÄRCHEN

Which gives interesting new ways to introduce security-sensitive
changes into environments by letting a Program check the
UTF8-named-Variable for its contents, but really inserting data
by the broken-part-name, which might be passed unchecked!

So PLEASE DO NOT EXPORT these !

Stucki


-- 
Christoph von Stuckrad      * * |nickname |Mail <stucki@mi.fu-berlin.de> \
Freie Universitaet Berlin   |/_*|'stucki' |Tel(Mo.,Mi.):+49 30 838-75 459|
Mathematik & Informatik EDV |\ *|if online|  (Di,Do,Fr):+49 30 77 39 6600|
Takustr. 9 / 14195 Berlin   * * |on IRCnet|Fax(home):   +49 30 77 39 6601/


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-18 19:58  3%     ` Bart Schaefer
                         ` (2 preceding siblings ...)
  2014-12-19  9:29  0%       ` Christoph (Stucki) von Stuckrad
@ 2014-12-19 18:17  0%       ` Christoph (Stucki) von Stuckrad
  2014-12-19 20:13  0%         ` Павлов Николай Александрович
  2014-12-19 21:21  0%         ` Peter Stephenson
  3 siblings, 2 replies; 200+ results
From: Christoph (Stucki) von Stuckrad @ 2014-12-19 18:17 UTC (permalink / raw)
  To: zsh-workers

On Thu, 18 Dec 2014, Bart Schaefer wrote:

> Are we sure it's even "legal" to export Unicode variable names?  Internally
> we can kinda ignore POSIX as we choose, but the environment crosses those
> boundaries.

Independend of being 'legal' to me it seems dangerous!

Comparing the 'working as written' example:

~$ M='surprise; : ' MÄRCHEN=story sh -c 'echo $MÄRCHEN'
story

to running it with all the other shells I keep around
(bash, dash, ash, sash - untested ksh and csh)
you always get:

..................................vvvv
~$ M='surprise; : ' MÄRCHEN=story bash -c 'echo $MÄRCHEN'
surprise; : ÄRCHEN

Which gives interesting new ways to introduce security-sensitive
changes into environments by letting a Program check the
UTF8-named-Variable for its contents, but really inserting data
by the broken-part-name, which might be passed unchecked!

So PLEASE DO NOT EXPORT these !

Stucki


-- 
Christoph von Stuckrad      * * |nickname |Mail <stucki@mi.fu-berlin.de> \
Freie Universitaet Berlin   |/_*|'stucki' |Tel(Mo.,Mi.):+49 30 838-75 459|
Mathematik & Informatik EDV |\ *|if online|  (Di,Do,Fr):+49 30 77 39 6600|
Takustr. 9 / 14195 Berlin   * * |on IRCnet|Fax(home):   +49 30 77 39 6601/


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-19 18:17  0%       ` Christoph (Stucki) von Stuckrad
@ 2014-12-19 20:13  0%         ` Павлов Николай Александрович
  2014-12-19 21:21  0%         ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Павлов Николай Александрович @ 2014-12-19 20:13 UTC (permalink / raw)
  To: Christoph (Stucki) von Stuckrad, zsh-workers

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

On December 19, 2014 9:17:37 PM EAT, "Christoph (Stucki) von Stuckrad" <stucki@mi.fu-berlin.de> wrote:
>On Thu, 18 Dec 2014, Bart Schaefer wrote:
>
>> Are we sure it's even "legal" to export Unicode variable names?
>Internally
>> we can kinda ignore POSIX as we choose, but the environment crosses
>those
>> boundaries.
>
>Independend of being 'legal' to me it seems dangerous!
>
>Comparing the 'working as written' example:
>
>~$ M='surprise; : ' MÄRCHEN=story sh -c 'echo $MÄRCHEN'
>story
>
>to running it with all the other shells I keep around
>(bash, dash, ash, sash - untested ksh and csh)
>you always get:
>
>..................................vvvv
>~$ M='surprise; : ' MÄRCHEN=story bash -c 'echo $MÄRCHEN'
>surprise; : ÄRCHEN
>
>Which gives interesting new ways to introduce security-sensitive
>changes into environments by letting a Program check the
>UTF8-named-Variable for its contents, but really inserting data
>by the broken-part-name, which might be passed unchecked!
>
>So PLEASE DO NOT EXPORT these !
>
>Stucki

I really do not see any problems here. If one has "surprise" in $M in an environment he runs typed scripts in then he already has much bigger problems.
-----BEGIN PGP SIGNATURE-----
Version: APG v1.1.1

iQJNBAEBCgA3BQJUlIbVMBwfMDI7PjIgHTg6PjswOSAQOzU6QTA9NEA+MjhHIDxr
cC1wYXZAeWFuZGV4LnJ1PgAKCRBu+P2/AXZZIuF9D/4oc9QkX4ziGW34IpiFzPmA
P4w5ZmbGFq8yV8IhYLX+SDukWSKP5j7K7CZgc6UU9Xftpr7RFbSXuRqyjTCWhzRM
mt6od3PeOI6+nEF+hizz+3WwqiHmrB/pagP7qed3gjX6t6y9qV7g+QCXdL7EPOQ/
uUKDoAjF0LPOc0JUtKXVJNZzE6YsCmVL/hwdeGG7pNQ7tOUeKEeS02XwNphAdUw4
5tuwE/UBRxtcPyCE3pVsV9vXa+1cyREuyY50uH/lMRGR8FuyjNmPslvRfDmzWkxw
x5OgxiyukBdxY4YLjiXuVLAVh/JqVmnZvMy2o6uqxESmv3tX8yOIjelFbwo6hZhz
L7RAdsXdw23OFBqxTrHxnSbImQuCn2yS2CrmQmBe3adilj84XIpqlpQCKy/LdXm7
LQyCGrI8gUwKLmpeqvaHrp3SbFfUZIbtMOaccQwPGBfH67JA0CUr+HZv3fJ/Iijm
F0LSsJTiQIgfeXXwk0nxHXUj/0yr5MEJUnVwFNY7C/tgOKRpDpwA5u2jgAvcYpUn
YHJddwyHryeghp2JpiECprUEd1nGRj4ijbGb4uolbs7CxVpR6z+IadEzsSg5bd2y
r499ADpGsuXM0U09unQUTMqsCaxW9y7VOeTqORSv/1jOG7O8vZIRIgLuyi+JYXsU
vMCYECRmzPKvIdYOsbQ7Gg==
=d7xB
-----END PGP SIGNATURE-----


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-19 18:17  0%       ` Christoph (Stucki) von Stuckrad
  2014-12-19 20:13  0%         ` Павлов Николай Александрович
@ 2014-12-19 21:21  0%         ` Peter Stephenson
  2014-12-19 22:44  0%           ` ZyX
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2014-12-19 21:21 UTC (permalink / raw)
  To: zsh-workers

On Fri, 19 Dec 2014 19:17:37 +0100
"Christoph (Stucki) von Stuckrad" <stucki@mi.fu-berlin.de> wrote:
> On Thu, 18 Dec 2014, Bart Schaefer wrote:
> 
> > Are we sure it's even "legal" to export Unicode variable names?
> > Internally we can kinda ignore POSIX as we choose, but the
> > environment crosses those boundaries.
> 
> Independend of being 'legal' to me it seems dangerous!

Well, this seems to be controversial.  But it's not clear how useful such
variables are anyway.

This backs off yesterday's mess and ignores environment variable names
with characters with the top bit set.  We'll see if anyone trips over it.

pws

diff --git a/Src/params.c b/Src/params.c
index 1c51afd..b8e0c42 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -641,9 +641,17 @@ split_env_string(char *env, char **name, char **value)
     if (!env || !name || !value)
 	return 0;
 
-    tenv = metafy(env, strlen(env), META_HEAPDUP);
-    for (str = tenv; *str && *str != '='; str++)
-	;
+    tenv = strcpy(zhalloc(strlen(env) + 1), env);
+    for (str = tenv; *str && *str != '='; str++) {
+	if (STOUC(*str) >= 128) {
+	    /*
+	     * We'll ignore environment variables with names not
+	     * from the portable character set since we don't
+	     * know of a good reason to accept them.
+	     */
+	    return 0;
+	}
+    }
     if (str != tenv && *str == '=') {
 	*str = '\0';
 	*name = tenv;
@@ -4357,18 +4365,7 @@ arrfixenv(char *s, char **t)
 int
 zputenv(char *str)
 {
-    char *ptr;
     DPUTS(!str, "Attempt to put null string into environment.");
-    /*
-     * The environment uses NULL-terminated strings, so just
-     * unmetafy and ignore the length.
-     */
-    for (ptr = str; *ptr && *ptr != Meta; ptr++)
-	;
-    if (*ptr == Meta) {
-	str = dupstring(str);
-	unmetafy(str, NULL);
-    }
 #ifdef USE_SET_UNSET_ENV
     /*
      * If we are using unsetenv() to remove values from the
@@ -4377,11 +4374,21 @@ zputenv(char *str)
      * Unfortunately this is a slightly different interface
      * from what zputenv() assumes.
      */
+    char *ptr;
     int ret;
 
-    for (ptr = str; *ptr && *ptr != '='; ptr++)
+    for (ptr = str; *ptr && STOUC(*ptr) < 128 && *ptr != '='; ptr++)
 	;
-    if (*ptr) {
+    if (STOUC(*ptr) >= 128) {
+	/*
+	 * Environment variables not in the portable character
+	 * set are non-standard and we don't really know of
+	 * a use for them.
+	 *
+	 * We'll disable until someone complains.
+	 */
+	return 1;
+    } else if (*ptr) {
 	*ptr = '\0';
 	ret = setenv(str, ptr+1, 1);
 	*ptr = '=';


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Unicode variables can be exported and are exported metafied
  2014-12-19 21:21  0%         ` Peter Stephenson
@ 2014-12-19 22:44  0%           ` ZyX
  0 siblings, 0 replies; 200+ results
From: ZyX @ 2014-12-19 22:44 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers



20.12.2014, 00:54, "Peter Stephenson" <p.w.stephenson@ntlworld.com>:
> On Fri, 19 Dec 2014 19:17:37 +0100
> "Christoph (Stucki) von Stuckrad" <stucki@mi.fu-berlin.de> wrote:
>>  On Thu, 18 Dec 2014, Bart Schaefer wrote:
>>>  Are we sure it's even "legal" to export Unicode variable names?
>>>  Internally we can kinda ignore POSIX as we choose, but the
>>>  environment crosses those boundaries.
>>  Independend of being 'legal' to me it seems dangerous!
>
> Well, this seems to be controversial.  But it's not clear how useful such
> variables are anyway.
>
> This backs off yesterday's mess and ignores environment variable names
> with characters with the top bit set.  We'll see if anyone trips over it.

According to

> "Other characters may be permitted by an implementation; applications
> shall tolerate the presence of such names."

> … shall tolerate …

such environment variables can be used for testing software for standard conformance.

I think though that for such testing `env` is more likely to be used because zsh support for such environment variables is not only locale-dependent, but also restricted to whatever libc thinks is alphanumeric character:

 zyx  ~  env «»=10 python -c 'import os; print(os.environ["«»"])'
10
 zyx  ~  «»=10 python -c 'import os; print(os.environ["«»"])'
zsh: command not found: «»=10

(something weird like `$'\n'` also works as an “environment variable name” for `env`).

---

By the way, support status for shells found on my system:

code:

    абв=1 $SHELL -c 'echo $абв'

tcsh: Illegal variable name
ksh: echoes 1
mksh: echoes $абв
fish: echoes 1
busybox with ash: echoes $абв
busybox with hush (commit ad0d009e0c1968a14f17189264d3aa8008ea2e3b): echoes $абв
rcsh: syntax error near (decimal -48)
bash: echoes $абв
dash: echoes $абв
zsh: echoes 1

    абв=1 $SHELL /c 'echo %абв%'

wine cmd.exe: echoes ^[[?1h^[=1 followed by CRNL

Summary:

Syntax error: tcsh, rcsh
$абв: mksh, busybox ash, busybox hush, bash, dash
1: ksh, fish, zsh, wine cmd.exe

>
> pws
>
> diff --git a/Src/params.c b/Src/params.c
> index 1c51afd..b8e0c42 100644
> --- a/Src/params.c
> +++ b/Src/params.c
> @@ -641,9 +641,17 @@ split_env_string(char *env, char **name, char **value)
>      if (!env || !name || !value)
>          return 0;
>
> -    tenv = metafy(env, strlen(env), META_HEAPDUP);
> -    for (str = tenv; *str && *str != '='; str++)
> - ;
> +    tenv = strcpy(zhalloc(strlen(env) + 1), env);
> +    for (str = tenv; *str && *str != '='; str++) {
> + if (STOUC(*str) >= 128) {
> +    /*
> +     * We'll ignore environment variables with names not
> +     * from the portable character set since we don't
> +     * know of a good reason to accept them.
> +     */
> +    return 0;
> + }
> +    }
>      if (str != tenv && *str == '=') {
>          *str = '\0';
>          *name = tenv;
> @@ -4357,18 +4365,7 @@ arrfixenv(char *s, char **t)
>  int
>  zputenv(char *str)
>  {
> -    char *ptr;
>      DPUTS(!str, "Attempt to put null string into environment.");
> -    /*
> -     * The environment uses NULL-terminated strings, so just
> -     * unmetafy and ignore the length.
> -     */
> -    for (ptr = str; *ptr && *ptr != Meta; ptr++)
> - ;
> -    if (*ptr == Meta) {
> - str = dupstring(str);
> - unmetafy(str, NULL);
> -    }
>  #ifdef USE_SET_UNSET_ENV
>      /*
>       * If we are using unsetenv() to remove values from the
> @@ -4377,11 +4374,21 @@ zputenv(char *str)
>       * Unfortunately this is a slightly different interface
>       * from what zputenv() assumes.
>       */
> +    char *ptr;
>      int ret;
>
> -    for (ptr = str; *ptr && *ptr != '='; ptr++)
> +    for (ptr = str; *ptr && STOUC(*ptr) < 128 && *ptr != '='; ptr++)
>          ;
> -    if (*ptr) {
> +    if (STOUC(*ptr) >= 128) {
> + /*
> + * Environment variables not in the portable character
> + * set are non-standard and we don't really know of
> + * a use for them.
> + *
> + * We'll disable until someone complains.
> + */
> + return 1;
> +    } else if (*ptr) {
>          *ptr = '\0';
>          ret = setenv(str, ptr+1, 1);
>          *ptr = '=';


^ permalink raw reply	[relevance 0%]

* Re: Math expression evaluation error?
  @ 2015-01-13 16:00  5%                   ` Vincent Lefevre
  2015-01-13 23:03  5%                     ` ZyX
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2015-01-13 16:00 UTC (permalink / raw)
  To: zsh-workers

On 2015-01-12 19:18:22 +0300, ZyX wrote:
> 12.01.2015, 12:18, "Vincent Lefevre" <vincent@vinc17.net>:
> > It's only a notation problem. Unfortunately / was chosen (historically,
> > not by zsh) as the symbol for integer division. The shell expression
> > 1/2 + 1/2 just means:
> >
> >   integer_div(1,2) + integer_div(1,2)
> >
> > where integer_div is the integer division function, which gives 0.
> > This is perfectly correct math.
> 
> It is not integer division.

In POSIX, it is always an integer division.

> 1.0/2 and 1/2.0 will give the same result: 0.5.

because 1.0 and 2.0 don't have an integer type. Therefore the result is
unspecified by POSIX, and zsh chooses to do a floating-point division.

> If you want to see language with operator for integer division check
> out Python-3: it has / for always-floating-point-unless-overridden
> and // for always-integral-unless-overridden

For Python, but not for zsh, unfortunately. But this choice comes
from POSIX historical behavior (and perhaps earlier).

> I would rather call it “type-specific division”.

In zsh. In POSIX, it is *always* an integer division. There is no
floating-point there.

An alternative choice zsh could have done is to return an error
if the / operator is used in a floating-point context, and use a
different operator for the floating-point division. However the
use of / for integer division could still be surprising.

-- 
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%]

* OPTIND set incorrectly by getopts for options without arg
@ 2015-01-13 20:38  3% Simon Chiang
  2015-01-13 21:34  4% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Simon Chiang @ 2015-01-13 20:38 UTC (permalink / raw)
  To: zsh-workers

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

Back in 2007 there was a question posted to the mailing list regarding
OPTIND and getopts (http://www.zsh.org/mla/users/2007/msg01188.html). To
quote, with some notes and one modifcation:

With zsh 4.3.4 the OPTIND incremental bebavior is inconsistent for options
with argument and without argument. For option with argument, OPTIND points
to next argument, while for option without argument it points to current
argument.

func() {
  OPTIND=1        # reset OPTIND each time in to prevent carryover
  getopts a:b optvar
  shift $(( OPTIND -1 ))
  echo "$OPTIND, $1"
}

func -a x y z
output: 3, y      # this is the correct output

func -b x y z
output: 1, -b     # this is the questionable output

Is this a bug? There is no consistent way to do "shift" as such.


Turns out according to the POSIX spec this is a bug (
http://pubs.opengroup.org/onlinepubs/000095399/utilities/getopts.html)

When the end of options is encountered, the getopts utility shall exit with
a return value greater than zero; the shell
variable OPTIND shall be set to the index of the first
non-option-argument.... Any of the following shall identify the end of
options: the special option "--", finding an argument that does not begin
with a '-', or encountering an error.


Unless I'm misreading that means that in the first example "y" indicates
the end of options so the correct output is "3, y".  In the second example
the "x" indicates the end of options so the correct output is "2, x".  For
what it's worth bash and dash set OPTIND in this way.

The original email was regarding zsh 4.3.4.  I can confirm this is still
the behavior at zsh 4.3.9.

Simon

^ permalink raw reply	[relevance 3%]

* Re: OPTIND set incorrectly by getopts for options without arg
  2015-01-13 20:38  3% OPTIND set incorrectly by getopts for options without arg Simon Chiang
@ 2015-01-13 21:34  4% ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-01-13 21:34 UTC (permalink / raw)
  To: Zsh hackers list

Quoting a bit more than I normally would to keep the POSIX text ...
jump to below.

On Tue, Jan 13, 2015 at 12:38 PM, Simon Chiang <simon.a.chiang@gmail.com> wrote:
>
> func() {
>   OPTIND=1        # reset OPTIND each time in to prevent carryover
>   getopts a:b optvar
>   shift $(( OPTIND -1 ))
>   echo "$OPTIND, $1"
> }
>
> func -a x y z
> output: 3, y      # this is the correct output
>
> func -b x y z
> output: 1, -b     # this is the questionable output
>
>
> Turns out according to the POSIX spec this is a bug (
> http://pubs.opengroup.org/onlinepubs/000095399/utilities/getopts.html)
>
> When the end of options is encountered, the getopts utility shall exit with
> a return value greater than zero; the shell
> variable OPTIND shall be set to the index of the first
> non-option-argument.... Any of the following shall identify the end of
> options: the special option "--", finding an argument that does not begin
> with a '-', or encountering an error.
>
>
> Unless I'm misreading that means that in the first example "y" indicates
> the end of options so the correct output is "3, y".  In the second example
> the "x" indicates the end of options so the correct output is "2, x".  For
> what it's worth bash and dash set OPTIND in this way.

If you add an "echo $?" after the call to getopts in the example
function, you will find that bash getopts has NOT "exit[ed] with a
return value greater than zero".  Neither has zsh getopts.

In zsh, if you add a SECOND call to getopts in the example function,
you will find that the second call DOES exit with a value of 1, and
that WHEN zsh getopts exits with a return value greater than zero,
THEN the value of OPTIND is set as POSIX specifies.

The distinction is the definition of "When the end of options is
encountered."  Zsh does not "encounter" the "end of options" until the
getopts call that actually attempts to "read past" the recognized
options.

You can see this better if you invoke the original example as "func -b
-a x y z".

Whether this is actually wrong or the spec is incomplete, I won't try
to argue here.


^ permalink raw reply	[relevance 4%]

* Re: Math expression evaluation error?
  2015-01-13 16:00  5%                   ` Vincent Lefevre
@ 2015-01-13 23:03  5%                     ` ZyX
  2015-01-14 14:47  4%                       ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: ZyX @ 2015-01-13 23:03 UTC (permalink / raw)
  To: Vincent Lefevre, zsh-workers

13.01.2015, 19:01, "Vincent Lefevre" <vincent@vinc17.net>:
> On 2015-01-12 19:18:22 +0300, ZyX wrote:
>>  12.01.2015, 12:18, "Vincent Lefevre" <vincent@vinc17.net>:
>>>  It's only a notation problem. Unfortunately / was chosen (historically,
>>>  not by zsh) as the symbol for integer division. The shell expression
>>>  1/2 + 1/2 just means:
>>>
>>>    integer_div(1,2) + integer_div(1,2)
>>>
>>>  where integer_div is the integer division function, which gives 0.
>>>  This is perfectly correct math.
>>  It is not integer division.
>
> In POSIX, it is always an integer division.

What?!

1. How POSIX is related? Zsh is not a POSIX shell and it is not emulation mode that is being discussed here.
2. If this standard is correct: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tagtcjh_15 then it references ISO C standard. The ISO C standard (C99) says the following for multiplicative operators:

   > 6.5.5 Multiplicative operators
   …
   > 3 The usual arithmetic conversions are performed on the operands.
   > 2 Each of the operands shall have arithmetic type. The operands of the % operator shall
   >   have integer type.
   …
   > 5 The result of the / operator is the quotient from the division of the first operand by the
   >   second; the result of the % operator is the remainder. In both operations, if the value of
   >   the second operand is zero, the behavior is undefined.
   > 6 When integers are divided …

   Where do you see a requirement for `/` to be integer division?
3. POSIX (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04) says that “Only signed long integer arithmetic is required.” And the section referenced there talks about signed long or double. Signed long integer arithmetic is *required* to be in there, but signed long integer arithmetics is *not required* to be the *only* arithmetics present in POSIX shell.

So no, `/` has nothing to do with integer division, except that the referenced C standard expects well-defined integer division in case two integers are divided. If you have another POSIX standard or another interpretation please show it here.

>>  1.0/2 and 1/2.0 will give the same result: 0.5.
>
> because 1.0 and 2.0 don't have an integer type. Therefore the result is
> unspecified by POSIX, and zsh chooses to do a floating-point division.
>>  If you want to see language with operator for integer division check
>>  out Python-3: it has / for always-floating-point-unless-overridden
>>  and // for always-integral-unless-overridden
>
> For Python, but not for zsh, unfortunately. But this choice comes
> from POSIX historical behavior (and perhaps earlier).
>>  I would rather call it “type-specific division”.
>
> In zsh. In POSIX, it is *always* an integer division. There is no
> floating-point there.
>
> An alternative choice zsh could have done is to return an error
> if the / operator is used in a floating-point context, and use a
> different operator for the floating-point division. However the
> use of / for integer division could still be surprising.
>
> --
> 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: Math expression evaluation error?
  2015-01-13 23:03  5%                     ` ZyX
@ 2015-01-14 14:47  4%                       ` Vincent Lefevre
  2015-01-14 21:37  4%                         ` ZyX
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2015-01-14 14:47 UTC (permalink / raw)
  To: zsh-workers

On 2015-01-14 02:03:33 +0300, ZyX wrote:
> 13.01.2015, 19:01, "Vincent Lefevre" <vincent@vinc17.net>:
> > In POSIX, it is always an integer division.
> 
> What?!
> 
> 1. How POSIX is related? Zsh is not a POSIX shell and it is not emulation mode that is being discussed here.

Zsh is partly based on POSIX for compatibility. The big difference
is the lack of word splitting (unless SH_WORD_SPLIT is set). Otherwise
I think that one should expect similar behavior, unless there is a
good reason.

> 2. If this standard is correct: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tagtcjh_15 then it references ISO C standard.
[...]
>    Where do you see a requirement for `/` to be integer division?

The context is an integer arithmetic. Thus / is necessarily an
integer division, like in C with integer types.

> 3. POSIX (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04) says that “Only signed long integer arithmetic is required.” And the section referenced there talks about signed long or double. Signed long integer arithmetic is *required* to be in there, but signed long integer arithmetics is *not required* to be the *only* arithmetics present in POSIX shell.

It says: "as long as it does not affect the results in cases where
there is no overflow"

If $((1/2)) gave 0.5 in some shells, I fear this would break various
scripts.

So, if a real-floating type is used, then for "/", I suppose that
the implementation should do a floor() after the division if the
context has operands recognized as integers, which is here equivalent
to the integer division despite the two roundings (proved in
http://www.vinc17.net/research/papers/rr_intdiv).

But POSIX doesn't specify the arithmetic evaluation on expressions
other than signed long integer arithmetic. An implementation that
decides that $((1.0/2)) gives 17 "as an extension" could still be
conforming.

-- 
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 4%]

* Re: Math expression evaluation error?
  2015-01-14 14:47  4%                       ` Vincent Lefevre
@ 2015-01-14 21:37  4%                         ` ZyX
  2015-01-15 13:34  3%                           ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: ZyX @ 2015-01-14 21:37 UTC (permalink / raw)
  To: Vincent Lefevre, zsh-workers

14.01.2015, 17:48, "Vincent Lefevre" <vincent@vinc17.net>:
> On 2015-01-14 02:03:33 +0300, ZyX wrote:
>>  13.01.2015, 19:01, "Vincent Lefevre" <vincent@vinc17.net>:
>>>  In POSIX, it is always an integer division.
>>  What?!
>>
>>  1. How POSIX is related? Zsh is not a POSIX shell and it is not emulation mode that is being discussed here.
>
> Zsh is partly based on POSIX for compatibility. The big difference
> is the lack of word splitting (unless SH_WORD_SPLIT is set). Otherwise
> I think that one should expect similar behavior, unless there is a
> good reason.
>>  2. If this standard is correct: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tagtcjh_15 then it references ISO C standard.
>
> [...]
>>     Where do you see a requirement for `/` to be integer division?
>
> The context is an integer arithmetic. Thus / is necessarily an
> integer division, like in C with integer types.

No. The context explicitly says that signed long integers or doubles should be used. Context of the ISO C standard obviously does not say anything like this.

>>  3. POSIX (http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_04) says that “Only signed long integer arithmetic is required.” And the section referenced there talks about signed long or double. Signed long integer arithmetic is *required* to be in there, but signed long integer arithmetics is *not required* to be the *only* arithmetics present in POSIX shell.
>
> It says: "as long as it does not affect the results in cases where
> there is no overflow"
>
> If $((1/2)) gave 0.5 in some shells, I fear this would break various
> scripts.

This is as well against the standard because in C division of two integers yields integers and is performed according to integer division rules.

>
> So, if a real-floating type is used, then for "/", I suppose that
> the implementation should do a floor() after the division if the
> context has operands recognized as integers, which is here equivalent
> to the integer division despite the two roundings (proved in
> http://www.vinc17.net/research/papers/rr_intdiv).
>
> But POSIX doesn't specify the arithmetic evaluation on expressions
> other than signed long integer arithmetic. An implementation that
> decides that $((1.0/2)) gives 17 "as an extension" could still be
> conforming.

Nope, it cannot ever be conforming. POSIX does this by saying that semantic of operation is the same as in C, except that only signed long integers and doubles are allowed. In C 1.0/2 gives 0.5 because this is how conversion rules are defined.

If you want to say it does *show me where POSIX explicitly forbids doubles in definition of arithmetic expansion*. I only see it explicitly forbidding the internal shell type (which is allowed to be greater then long or even be floating-point) to affect the results of operation (unless there is an overflow which is in any case not defined for signed integers) which is the case if one tries to divide two integers (effectively requiring shell to keep track on types even if it wants to use double for everything) and also in case doubles are used, effectively meaning that if shell supports doubles it should yield doubles after division involving a double: “The evaluation of arithmetic expressions shall be equivalent to that described in Section 6.5, Expressions, of the ISO C standard.”.

>
> --
> 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 4%]

* Re: Math expression evaluation error?
  2015-01-15 13:34  3%                           ` Vincent Lefevre
@ 2015-01-15 13:41  3%                             ` Vincent Lefevre
  2015-01-15 18:32  4%                             ` ZyX
  1 sibling, 0 replies; 200+ results
From: Vincent Lefevre @ 2015-01-15 13:41 UTC (permalink / raw)
  To: zsh-workers

On 2015-01-15 14:34:21 +0100, Vincent Lefevre wrote:
> > > But POSIX doesn't specify the arithmetic evaluation on expressions
> > > other than signed long integer arithmetic. An implementation that
> > > decides that $((1.0/2)) gives 17 "as an extension" could still be
> > > conforming.
> > 
> > Nope, it cannot ever be conforming. POSIX does this by saying that
> > semantic of operation is the same as in C,
> 
> Only for what it specifies.

BTW, note also that the ISO C standard doesn't specify the accuracy,
unless Annex F (IEEE 754) is supported (which is not required by
POSIX). So, even if the shell claims to implement floating-point
arithmetic, any floating-point number as the result of $((1.0/2))
would be conforming.

-- 
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: Math expression evaluation error?
  2015-01-14 21:37  4%                         ` ZyX
@ 2015-01-15 13:34  3%                           ` Vincent Lefevre
  2015-01-15 13:41  3%                             ` Vincent Lefevre
  2015-01-15 18:32  4%                             ` ZyX
  0 siblings, 2 replies; 200+ results
From: Vincent Lefevre @ 2015-01-15 13:34 UTC (permalink / raw)
  To: zsh-workers

On 2015-01-15 00:37:43 +0300, ZyX wrote:
> 14.01.2015, 17:48, "Vincent Lefevre" <vincent@vinc17.net>:
> > On 2015-01-14 02:03:33 +0300, ZyX wrote:
> >>  13.01.2015, 19:01, "Vincent Lefevre" <vincent@vinc17.net>:
> >>>  In POSIX, it is always an integer division.
> >>  What?!
> >>
> >>  1. How POSIX is related? Zsh is not a POSIX shell and it is not emulation mode that is being discussed here.
> >
> > Zsh is partly based on POSIX for compatibility. The big difference
> > is the lack of word splitting (unless SH_WORD_SPLIT is set). Otherwise
> > I think that one should expect similar behavior, unless there is a
> > good reason.
> >>  2. If this standard is correct: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tagtcjh_15 then it references ISO C standard.
> >
> > [...]
> >>     Where do you see a requirement for `/` to be integer division?
> >
> > The context is an integer arithmetic. Thus / is necessarily an
> > integer division, like in C with integer types.
> 
> No. The context explicitly says that signed long integers or doubles
> should be used. Context of the ISO C standard obviously does not say
> anything like this.

Wrong. The context of $((...)) is signed long arithmetic. If a shell
wants to use double's (such as 1.0), that's only an extension.

> > But POSIX doesn't specify the arithmetic evaluation on expressions
> > other than signed long integer arithmetic. An implementation that
> > decides that $((1.0/2)) gives 17 "as an extension" could still be
> > conforming.
> 
> Nope, it cannot ever be conforming. POSIX does this by saying that
> semantic of operation is the same as in C,

Only for what it specifies.

> except that only signed long integers and doubles are allowed.

No, POSIX says "As an extension, the shell may recognize arithmetic
expressions beyond those listed." and does not specify anything on
such expressions. $((1.0/2)) is such an arithmetic expression beyond
those listed.

In particular, it does *not* say that "only signed long integers and
doubles are allowed". A shell could implement other types (number
fields or whatever), and specific operators. And note that in such
an expression, "/" is not necessarily an operator, but could be part
of a constant.

-- 
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: Math expression evaluation error?
  2015-01-15 13:34  3%                           ` Vincent Lefevre
  2015-01-15 13:41  3%                             ` Vincent Lefevre
@ 2015-01-15 18:32  4%                             ` ZyX
  2015-01-15 21:57  3%                               ` Bart Schaefer
  1 sibling, 1 reply; 200+ results
From: ZyX @ 2015-01-15 18:32 UTC (permalink / raw)
  To: Vincent Lefevre, zsh-workers


15.01.2015, 16:44, "Vincent Lefevre" <vincent@vinc17.net>:
> On 2015-01-15 00:37:43 +0300, ZyX wrote:
>>  14.01.2015, 17:48, "Vincent Lefevre" <vincent@vinc17.net>:
>>>  On 2015-01-14 02:03:33 +0300, ZyX wrote:
>>>>   13.01.2015, 19:01, "Vincent Lefevre" <vincent@vinc17.net>:
>>>>>   In POSIX, it is always an integer division.
>>>>   What?!
>>>>
>>>>   1. How POSIX is related? Zsh is not a POSIX shell and it is not emulation mode that is being discussed here.
>>>  Zsh is partly based on POSIX for compatibility. The big difference
>>>  is the lack of word splitting (unless SH_WORD_SPLIT is set). Otherwise
>>>  I think that one should expect similar behavior, unless there is a
>>>  good reason.
>>>>   2. If this standard is correct: http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap01.html#tagtcjh_15 then it references ISO C standard.
>>>  [...]
>>>>      Where do you see a requirement for `/` to be integer division?
>>>  The context is an integer arithmetic. Thus / is necessarily an
>>>  integer division, like in C with integer types.
>>  No. The context explicitly says that signed long integers or doubles
>>  should be used. Context of the ISO C standard obviously does not say
>>  anything like this.
>
> Wrong. The context of $((...)) is signed long arithmetic. If a shell
> wants to use double's (such as 1.0), that's only an extension.

It is never written in the standard that context is signed long arithmetic. It is only written that signed long integers are the only required types, not the only possible.

>>>  But POSIX doesn't specify the arithmetic evaluation on expressions
>>>  other than signed long integer arithmetic. An implementation that
>>>  decides that $((1.0/2)) gives 17 "as an extension" could still be
>>>  conforming.
>>  Nope, it cannot ever be conforming. POSIX does this by saying that
>>  semantic of operation is the same as in C,
>
> Only for what it specifies.
>>  except that only signed long integers and doubles are allowed.
>
> No, POSIX says "As an extension, the shell may recognize arithmetic
> expressions beyond those listed." and does not specify anything on
> such expressions. $((1.0/2)) is such an arithmetic expression beyond
> those listed.
>
> In particular, it does *not* say that "only signed long integers and
> doubles are allowed". A shell could implement other types (number
> fields or whatever), and specific operators. And note that in such
> an expression, "/" is not necessarily an operator, but could be part
> of a constant.

Standard says that “The arithmetic expression shall be processed according to the rules given in Arithmetic Precision and Operations”. In the referenced section it talks about signed long integers and doubles, neither is forbidden by “the following exceptions”. It as well talks about C rules for arithmetic. So 1.0 is *listed*, but is not *required*. If you want to say POSIX does not list doubles show where it excludes double from the list. Exceptions bullet-list *does not* exclude anything, but selection, iteration and jump statements. All other points are given in a form “feature is not required” or “[of the similar features, I guess] only feature is required” which is not the same as “The arithmetic expression shall be processed according to the rules for signed integers given in …” (in which case doubles indeed were not falling into listed category).

If a shell wants to use double’s it falls into a listed category. But if shell wants to use `//` for always-floating-point division operator then it is what is “beyond those listed”. Zsh math functions are as well, even if they have names from math.h (requirements on such functions are put in the next sub…section (what should something that has lesser then third level called? This whatever is under 1.1.2 subsubsection) which was not referenced in shell standard). This also applies to $(( base#number )) syntax. But not to doubles because they are listed.

The standard *does* say that integer variables and constants shall be implemented as signed long integers and floating-point things should use double (or the equivalent, for both). It is also explicitly said that conversion rules between them are derived from C. So POSIX-compliant $(()) must either not use floating-point values or have double for floating-point values, but it must not have something strange for floating-point values: e.g. lower-precision float or Fraction with two big integers (I mean Fraction class from Python fractions module which basically is a numerator+denominator pair capable of representing any rational number (Python uses big integers for its only integer type)).

>
> --
> 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 4%]

* Re: Math expression evaluation error?
  2015-01-15 18:32  4%                             ` ZyX
@ 2015-01-15 21:57  3%                               ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-01-15 21:57 UTC (permalink / raw)
  To: zsh-workers

Guys, this POSIX argument has gone on way too long and with way too much
context being quoted every time somebody replies.  I haven't seen any
suggestion emerge from this that we should be doing anything different
than we alreay decided to do, so unless you're taking this somewhere that
might end in a concrete proposal of some kind, please wrap it up or stop
copying the list.  Thanks.


^ permalink raw reply	[relevance 3%]

* Attempt to document aliasing more fully
@ 2015-03-14 20:54  2% Bart Schaefer
  2015-03-15 18:35  0% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-03-14 20:54 UTC (permalink / raw)
  To: zsh-workers

So here is what I have (see diff below).  This describes the situation
prior to workers/34641.  To keep 34641, we'd just have to add another
itemiz() calling out command separators as a separate class of "word",
though I still think that if included, those should (a) still exclude
newline and (b) require "alias -g".

Either way I rather suspect that POSIX_ALIASES should prohibit more
than just the reserved words, e.g., I doubt that parameter references
and quoted strings are meant to be allowed in aliases by POSIX.  That
should get fixed, along with the bug(s) mentioned in 34668 and 34682.


diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index 63d90df..ee44841 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -532,12 +532,12 @@ characters up to a newline to be ignored.
 texinode(Aliasing)(Quoting)(Comments)(Shell Grammar)
 sect(Aliasing)
 cindex(aliasing)
-Every token in the shell input is checked to see if there
+Every eligible em(word) in the shell input is checked to see if there
 is an alias defined for it.
 If so, it is replaced by the text of the alias if it is in command
 position (if it could be the first word of a simple command),
 or if the alias is global.
-If the text ends with a space, the next word in the shell input
+If the replacement text ends with a space, the next word in the shell input
 is treated as though it were in command position for purposes of alias
 expansion.
 findex(alias, use of)
@@ -545,6 +545,22 @@ cindex(aliases, global)
 An alias is defined using the tt(alias) builtin; global aliases
 may be defined using the tt(-g) option to that builtin.
 
+A em(word) is defined as:
+
+startitemize()
+itemiz(Any plain string or glob pattern)
+itemiz(Any quoted string, using any quoting method (note that the quotes
+must be part of the alias definition for this to be eligible))
+itemiz(Any parameter reference or command substitution)
+itemiz(Any series of the foregoing, concatenated without whitespace or
+other tokens between them)
+itemiz(Any reserved word (tt(case), tt(do), tt(else), etc.))
+enditemize()
+
+Reserved words are not eligible for aliasing when tt(POSIX_ALIASES) set.
+The alias builtin does not reject ineligible aliases, but they are not
+expanded.
+
 Alias expansion is done on the shell input before any other expansion
 except history expansion.  Therefore, if an alias is defined for the
 word tt(foo), alias expansion may be avoided by quoting part of the


^ permalink raw reply	[relevance 2%]

* Re: Attempt to document aliasing more fully
  2015-03-14 20:54  2% Attempt to document aliasing more fully Bart Schaefer
@ 2015-03-15 18:35  0% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-03-15 18:35 UTC (permalink / raw)
  To: Zsh hackers list

On Sat, 14 Mar 2015 13:54:06 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> So here is what I have (see diff below).  This describes the situation
> prior to workers/34641.  To keep 34641, we'd just have to add another
> itemiz() calling out command separators as a separate class of "word",
> though I still think that if included, those should (a) still exclude
> newline and (b) require "alias -g".

Thanks, that looks reasonable.  I'd sort of vaguely be inclined to point
out a bit more actively that if you're aliasing quoted stuff the quotes
form part of the alias (which is kind of weird if your use to shells written by normal people) and maybe hint what therefore doesn't get aliased (though I entirely agree with the basic logic, i.e. spelling out what does), but that's very minor.

I've got no very strong feelings about keeping the new feature since
it's been the way it has for decades and it only got noticed as a side
issue.  However, the limitations above sound sane, since using "alias
-g" is already for hotheads, so maybe that's a good compromise.

> Either way I rather suspect that POSIX_ALIASES should prohibit more
> than just the reserved words, e.g., I doubt that parameter references
> and quoted strings are meant to be allowed in aliases by POSIX.  That
> should get fixed, along with the bug(s) mentioned in 34668 and 34682.

Yes, I agree with that.

pws


^ permalink raw reply	[relevance 0%]

* Aliasing part 3 (or so) - Doc and POSIX_ALIASES
@ 2015-03-18  6:29  2% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-03-18  6:29 UTC (permalink / raw)
  To: zsh-workers

Probably still needs a couple of tests added, and this does not address
the bugs from 34668 and 34682.

This doc is tweaked a bit from the original sample in 34715.  I looked
up aliasing in the POSIX spec and (except allowed as an extension) it
does not include glob patterns either.  This turns out to be very easy
to do along with excluding quoted strings, parameter references, etc.;
see the third hunk of the lex.c patch.  The first hunk of that patch
handles the new requirement of "alias -g" for separators et al.

After this patch the doc and the code should be consistent.  I'm still
not entirely happy about being able to alias "||", ">&", etc. for all
the reasons I've previously mentioned, but further because there's no
way to quote such a token (to prevent alias expansion) that also gives
you back a token with the same semantics.


diff --git a/Doc/Zsh/grammar.yo b/Doc/Zsh/grammar.yo
index b30e423..522ad04 100644
--- a/Doc/Zsh/grammar.yo
+++ b/Doc/Zsh/grammar.yo
@@ -538,8 +538,7 @@ If so, it is replaced by the text of the alias if it is in command
 position (if it could be the first word of a simple command),
 or if the alias is global.
 If the replacement text ends with a space, the next word in the shell input
-is treated as though it were in command position for purposes of alias
-expansion.
+is always eligible for purposes of alias expansion.
 findex(alias, use of)
 cindex(aliases, global)
 An alias is defined using the tt(alias) builtin; global aliases
@@ -555,22 +554,32 @@ itemiz(Any parameter reference or command substitution)
 itemiz(Any series of the foregoing, concatenated without whitespace or
 other tokens between them)
 itemiz(Any reserved word (tt(case), tt(do), tt(else), etc.))
+itemiz(With global aliasing, any command separator, any redirection
+operator, and `tt(LPAR())' or `tt(RPAR())' when not part of a glob pattern)
 enditemize()
 
-Reserved words are not eligible for aliasing when tt(POSIX_ALIASES) is set.
-The tt(alias) builtin does not reject ineligible aliases, but they are not
-expanded.
+It is not presently possible to alias the `tt(LPAR()LPAR())' token that
+introduces arithmetic expressions, because until a full statement has been
+parsed, it cannot be distinguished from two consecutive `tt(LPAR())'
+tokens introducing nested subshells.
+
+When tt(POSIX_ALIASES) is set, only plain unquoted strings are eligible
+for aliasing.  The tt(alias) builtin does not reject ineligible aliases,
+but they are not expanded.
 
 Alias expansion is done on the shell input before any other expansion
 except history expansion.  Therefore, if an alias is defined for the
 word tt(foo), alias expansion may be avoided by quoting part of the
 word, e.g. tt(\foo).  Any form of quoting works, although there is
 nothing to prevent an alias being defined for the quoted form such as
-tt(\foo) as well.  For use with completion, which would remove an
-initial backslash followed by a character that isn't special, it may be
-more convenient to quote the word by starting with a single quote,
-i.e. tt('foo); completion will automatically add the trailing single
-quote.
+tt(\foo) as well.  Also, if a separator such as tt(&&) is aliased,
+tt(\&&) turns into the two tokens tt(\&) and tt(&), each of which may
+have been aliased separately.  Similarly for tt(\<<), tt(\>|), etc.
+
+For use with completion, which would remove an initial backslash followed
+by a character that isn't special, it may be more convenient to quote the
+word by starting with a single quote, i.e. tt('foo); completion will
+automatically add the trailing single quote.
 
 There is a commonly encountered problem with aliases
 illustrated by the following code:
diff --git a/Src/lex.c b/Src/lex.c
index 494ea88..1eb0bc7 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1740,12 +1740,13 @@ checkalias(void)
 
     if (!noaliases && isset(ALIASESOPT) &&
 	(!isset(POSIXALIASES) ||
-	 !reswdtab->getnode(reswdtab, zshlextext))) {
+	 (tok == STRING && !reswdtab->getnode(reswdtab, zshlextext)))) {
 	char *suf;
 
 	an = (Alias) aliastab->getnode(aliastab, zshlextext);
 	if (an && !an->inuse &&
-	    ((an->node.flags & ALIAS_GLOBAL) || incmdpos || inalmore)) {
+	    ((an->node.flags & ALIAS_GLOBAL) ||
+	     (incmdpos && tok == STRING) || inalmore)) {
 	    inpush(an->text, INP_ALIAS, an);
 	    if (an->text[0] == ' ' && !(an->node.flags & ALIAS_GLOBAL))
 		aliasspaceflag = 1;
@@ -1784,6 +1785,8 @@ exalias(void)
     if (!tokstr) {
 	zshlextext = tokstrings[tok];
 
+	if (tok == NEWLIN)
+	    return 0;
 	return checkalias();
     } else {
 	VARARR(char, copy, (strlen(tokstr) + 1));
@@ -1791,6 +1794,9 @@ exalias(void)
 	if (has_token(tokstr)) {
 	    char *p, *t;
 
+	    if (isset(POSIXALIASES))
+		return 0;
+
 	    zshlextext = p = copy;
 	    for (t = tokstr;
 		 (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
diff --git a/Test/A02alias.ztst b/Test/A02alias.ztst
index 36dfa24..314ec03 100644
--- a/Test/A02alias.ztst
+++ b/Test/A02alias.ztst
@@ -43,7 +43,7 @@
 0:Alias expansion works at the end of parsed strings
 >foo
 
-  alias '&&=(){ return $?; } && '
+  alias -g '&&=(){ return $?; } && '
   alias not_the_print_command=print
   eval 'print This is output
   && print And so is this


^ permalink raw reply	[relevance 2%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  @ 2015-03-28 22:33  3%       ` ZyX
  2015-03-28 22:45  4%         ` Bart Schaefer
  2015-03-28 23:07  0%         ` Eric Cook
  0 siblings, 2 replies; 200+ results
From: ZyX @ 2015-03-28 22:33 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

29.03.2015, 01:25, "Bart Schaefer" <schaefer@brasslantern.com>:
> On Mar 28,  5:55pm, Eric Cook wrote:
> }
> } % print $ZSH_PATCHLEVEL; emulate sh -c '[[ a == a ]]'
> } zsh-5.0.7-362-gab40656
> } zsh: command not found: [[
> }
> } Did that behavior change?
>
> Aha.  That makes more sense.
>
> The '[[' reserved word is handled a special kind of built-in alias [*]
> and the change to POSIX_ALIASES handling caused that to be disabled.
>
> This will take a bit of thought.
>
> [*] Not literally, but the alias expansion code is where '[[' is noted
> and the lexer changed into "parsing a conditional" state.

I would say that this is actually an expected behaviour: `posh -c '[[ a == a ]]'` will show `posh: [[: not found` because `[[` is not in POSIX. Similar error will be shown by dash.


^ permalink raw reply	[relevance 3%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 22:33  3%       ` ZyX
@ 2015-03-28 22:45  4%         ` Bart Schaefer
  2015-03-28 23:07  0%         ` Eric Cook
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2015-03-28 22:45 UTC (permalink / raw)
  To: zsh-workers

On Mar 29,  1:33am, ZyX wrote:
} Subject: Re: [[ is being treated as a pattern in the command/reserved word
}
} 29.03.2015, 01:25, "Bart Schaefer" <schaefer@brasslantern.com>:
} >
} > The '[[' reserved word is handled a special kind of built-in alias [*]
} > and the change to POSIX_ALIASES handling caused that to be disabled.
} 
} I would say that this is actually an expected behaviour:
} `posh -c '[[ a == a ]]'` will show `posh: [[: not found`
} because `[[` is not in POSIX. Similar error will be shown by dash.

That could be, but POSIX_ALIASES is the wrong way to handle that.  If we
wanted to remove the '[[' extension for posix emulation, we should do
`disable -r "[["` instead.


diff --git a/Src/lex.c b/Src/lex.c
index 4d8355b..2e61170 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -1794,9 +1794,6 @@ exalias(void)
 	if (has_token(tokstr)) {
 	    char *p, *t;
 
-	    if (isset(POSIXALIASES))
-		return 0;
-
 	    zshlextext = p = copy;
 	    for (t = tokstr;
 		 (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++););
@@ -1816,7 +1813,7 @@ exalias(void)
 
 	if (tok == STRING) {
 	    /* Check for an alias */
-	    if (checkalias()) {
+	    if ((zshlextext != copy || !isset(POSIXALIASES)) && checkalias()) {
 		if (zshlextext == copy)
 		    zshlextext = tokstr;
 		return 1;
diff --git a/Test/B07emulate.ztst b/Test/B07emulate.ztst
index 315206a..2de097e 100644
--- a/Test/B07emulate.ztst
+++ b/Test/B07emulate.ztst
@@ -247,3 +247,7 @@
 >extendedglob is initially off
 >bareglobqual is still on
 >extendedglob is on, too
+
+ emulate sh -c '[[ a == a ]]'
+0:regression test for POSIX_ALIASES reserved words
+F:Some reserved tokens are handled in alias expansion


^ permalink raw reply	[relevance 4%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 22:33  3%       ` ZyX
  2015-03-28 22:45  4%         ` Bart Schaefer
@ 2015-03-28 23:07  0%         ` Eric Cook
  2015-03-28 23:19  5%           ` ZyX
  1 sibling, 1 reply; 200+ results
From: Eric Cook @ 2015-03-28 23:07 UTC (permalink / raw)
  To: zsh-workers

On 03/28/2015 06:33 PM, ZyX wrote:
> 29.03.2015, 01:25, "Bart Schaefer" <schaefer@brasslantern.com>:
>> On Mar 28,  5:55pm, Eric Cook wrote:
>> }
>> } % print $ZSH_PATCHLEVEL; emulate sh -c '[[ a == a ]]'
>> } zsh-5.0.7-362-gab40656
>> } zsh: command not found: [[
>> }
>> } Did that behavior change?
>>
>> Aha.  That makes more sense.
>>
>> The '[[' reserved word is handled a special kind of built-in alias [*]
>> and the change to POSIX_ALIASES handling caused that to be disabled.
>>
>> This will take a bit of thought.
>>
>> [*] Not literally, but the alias expansion code is where '[[' is noted
>> and the lexer changed into "parsing a conditional" state.
> I would say that this is actually an expected behaviour: `posh -c '[[ a == a ]]'` will show `posh: [[: not found` because `[[` is not in POSIX. Similar error will be shown by dash.
Nor is it disallowed by POSIXand it used to work, the bug report is
still valid.


^ permalink raw reply	[relevance 0%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 23:07  0%         ` Eric Cook
@ 2015-03-28 23:19  5%           ` ZyX
  2015-03-28 23:27  0%             ` Eric Cook
  0 siblings, 1 reply; 200+ results
From: ZyX @ 2015-03-28 23:19 UTC (permalink / raw)
  To: Eric Cook, zsh-workers

29.03.2015, 02:07, "Eric Cook" <llua@gmx.com>:
> On 03/28/2015 06:33 PM, ZyX wrote:
>>  29.03.2015, 01:25, "Bart Schaefer" <schaefer@brasslantern.com>:
>>>  On Mar 28,  5:55pm, Eric Cook wrote:
>>>  }
>>>  } % print $ZSH_PATCHLEVEL; emulate sh -c '[[ a == a ]]'
>>>  } zsh-5.0.7-362-gab40656
>>>  } zsh: command not found: [[
>>>  }
>>>  } Did that behavior change?
>>>
>>>  Aha.  That makes more sense.
>>>
>>>  The '[[' reserved word is handled a special kind of built-in alias [*]
>>>  and the change to POSIX_ALIASES handling caused that to be disabled.
>>>
>>>  This will take a bit of thought.
>>>
>>>  [*] Not literally, but the alias expansion code is where '[[' is noted
>>>  and the lexer changed into "parsing a conditional" state.
>>  I would say that this is actually an expected behaviour: `posh -c '[[ a == a ]]'` will show `posh: [[: not found` because `[[` is not in POSIX. Similar error will be shown by dash.
>
> Nor is it disallowed by POSIXand it used to work, the bug report is
> still valid.

`[[` is a *syntax extension*. This *is* going against POSIX. If `[[` in POSIX emulation mode was implemented as a shell built-in in a manner that allows implementing it as a script your concern would be valid. But implementing `[[` as a shell built-in is breaking certain expectations about how `[[` is supposed to work.

Specifically, with

    setopt SH_WORD_SPLIT
    w="a = b"
    test $w # False: a ≠ b, expected
    [[ a = b ]] # False: a ≠ b, expected
    [[ $w ]] # True: w is not empty, should be false if shell is POSIX

. It is easier to disable `[[` then keep two implementations of it.


^ permalink raw reply	[relevance 5%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 23:19  5%           ` ZyX
@ 2015-03-28 23:27  0%             ` Eric Cook
  2015-03-28 23:57  4%               ` ZyX
  0 siblings, 1 reply; 200+ results
From: Eric Cook @ 2015-03-28 23:27 UTC (permalink / raw)
  To: ZyX, zsh-workers

On 03/28/2015 07:19 PM, ZyX wrote:
> 29.03.2015, 02:07, "Eric Cook" <llua@gmx.com>
> `[[` is a *syntax extension*. This *is* going against POSIX. If `[[` in POSIX emulation mode was implemented as a shell built-in in a manner that allows implementing it as a script your concern would be valid. But implementing `[[` as a shell built-in is breaking certain expectations about how `[[` is supposed to work.
>
> Specifically, with
>
>     setopt SH_WORD_SPLIT
>     w="a = b"
>     test $w # False: a ≠ b, expected
>     [[ a = b ]] # False: a ≠ b, expected
>     [[ $w ]] # True: w is not empty, should be false if shell is POSIX
>
> . It is easier to disable `[[` then keep two implementations of it.
See 2.4 of:
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html

> The following words may be recognized as reserved words on some
implementations (when none of the characters are quoted), causing
unspecified results:
>
> [[ ]]functionselect


^ permalink raw reply	[relevance 0%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 23:27  0%             ` Eric Cook
@ 2015-03-28 23:57  4%               ` ZyX
  2015-03-29  0:09  0%                 ` Eric Cook
  0 siblings, 1 reply; 200+ results
From: ZyX @ 2015-03-28 23:57 UTC (permalink / raw)
  To: Eric Cook, zsh-workers

29.03.2015, 02:27, "Eric Cook" <llua@gmx.com>:
> On 03/28/2015 07:19 PM, ZyX wrote:
>>  29.03.2015, 02:07, "Eric Cook" <llua@gmx.com>
>>  `[[` is a *syntax extension*. This *is* going against POSIX. If `[[` in POSIX emulation mode was implemented as a shell built-in in a manner that allows implementing it as a script your concern would be valid. But implementing `[[` as a shell built-in is breaking certain expectations about how `[[` is supposed to work.
>>
>>  Specifically, with
>>
>>      setopt SH_WORD_SPLIT
>>      w="a = b"
>>      test $w # False: a ≠ b, expected
>>      [[ a = b ]] # False: a ≠ b, expected
>>      [[ $w ]] # True: w is not empty, should be false if shell is POSIX
>>
>>  . It is easier to disable `[[` then keep two implementations of it.
>
> See 2.4 of:
> http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html
>>  The following words may be recognized as reserved words on some
>
> implementations (when none of the characters are quoted), causing
> unspecified results:
>>  [[ ]]functionselect

There is a bit of problem: http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_05 (Field Splitting) section does not talk about any exceptions for the field splitting. There is only one official exception to this rule: function definition. I cannot say whether “uspecified result” makes current behaviour of `[[` (non-)conformant.

There is also another consideration: POSIX does not define `[[`. So when you run an emulation mode *what exactly* should `[[` do? When emulating `bash` (not present for some reason) or `ksh` this is defined by those shells, but `sh` is clearly not a bash emulation (reasoning: BASH_REMATCH is not set) and not ksh emulation (reasoning: `emulate ksh` is a distinct emulation mode and `sh` emulation mode is not referenced as an alias of `ksh` emulation mode). I have failed to find what zsh developers meant by `sh` emulation exactly though: it is not explicitly said that it emulates POSIX shell. But since it not bash or ksh emulation mode `[[ $w ]]` in the above case should be `false` (busybox emulation) or a command-not-found error (posh or dash emulation).


^ permalink raw reply	[relevance 4%]

* Re: [[ is being treated as a pattern in the command/reserved word position.
  2015-03-28 23:57  4%               ` ZyX
@ 2015-03-29  0:09  0%                 ` Eric Cook
  0 siblings, 0 replies; 200+ results
From: Eric Cook @ 2015-03-29  0:09 UTC (permalink / raw)
  To: zsh-workers

On 03/28/2015 07:57 PM, ZyX wrote:
> There is also another consideration: POSIX does not define `[[`. So
> when you run an emulation mode *what exactly* should `[[` do? When
> emulating `bash` (not present for some reason) or `ksh` this is
> defined by those shells, but `sh` is clearly not a bash emulation
> (reasoning: BASH_REMATCH is not set) and not ksh emulation (reasoning:
> `emulate ksh` is a distinct emulation mode and `sh` emulation mode is
> not referenced as an alias of `ksh` emulation mode). I have failed to
> find what zsh developers meant by `sh` emulation exactly though: it is
> not explicitly said that it emulates POSIX shell. But since it not
> bash or ksh emulation mode `[[ $w ]]` in the above case should be
> `false` (busybox emulation) or a command-not-found error (posh or dash
> emulation). 
>From my understanding of emulate, it works similar to bash's posix mode.
Changing anything that conflicts with the mode, but doesn't disable
other non-conflicting extensions.

Distros like Arch Linux relies on it to source their /etc/profile from
the global zprofile is more sh like environment.
(with the added perk of stuff like [[ working.)
I've also been using it for stuff like that for a long time and would
appreciate it staying the way it currently is.


^ permalink raw reply	[relevance 0%]

* [RFC PATCH] Allow grouping of thousands in format string
@ 2015-04-03 13:52  4% Øystein Walle
  2015-04-04 11:11  0% ` Oliver Kiddle
  0 siblings, 1 reply; 200+ results
From: Øystein Walle @ 2015-04-03 13:52 UTC (permalink / raw)
  To: zsh-workers; +Cc: Øystein Walle

Putting an apostrophe before i, d, u, f, F, g or G is specified in POSIX
albeit noted as an extension to ISO C.
---

Bash handles this this and from what I can tell implements it much in the same
way so that stuff like %'s is passed straight on to the system's printf().
However POSIX also says that using the grouping specifier with other flags is
undefined. It works just fine on the limited range of systems I've tested it on
(all GNU).

If desired I could set a flag and then handle it further on by checking that
type == 2 or type == 3 or something like that, but that needs some rearranging.

If the idea behind the patch itself is undesired then I think the documentation
for zsh's printf should be updated.

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

diff --git a/Src/builtin.c b/Src/builtin.c
index 614b17d..225c034 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3735,7 +3735,7 @@ bin_print(char *name, char **args, Options ops, int func)
     int nnl = 0, fmttrunc = 0, ret = 0, maxarg = 0, nc = 0;
     int flags[5], *len;
     char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[13], *fmt = NULL;
-    char **first, **argp, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0';
+    char **first, **argp, *curarg, *flagch = "'0+- #", save = '\0', nullstr = '\0';
     size_t rcount, count = 0;
 #ifdef HAVE_OPEN_MEMSTREAM
     size_t mcount;
@@ -4312,8 +4312,8 @@ bin_print(char *name, char **args, Options ops, int func)
 		if (prec >= 0) *d++ = '.', *d++ = '*';
 	    }
 
-	    /* ignore any size modifier */
-	    if (*c == 'l' || *c == 'L' || *c == 'h') c++;
+	    /* ignore any size modifier and grouping specifier */
+	    if (*c == 'l' || *c == 'L' || *c == 'h' || *c == '\'') c++;
 
 	    if (!curarg && *argp) {
 		curarg = *argp;
-- 
2.2.0


^ permalink raw reply	[relevance 4%]

* Re: [RFC PATCH] Allow grouping of thousands in format string
  2015-04-03 13:52  4% [RFC PATCH] Allow grouping of thousands in format string Øystein Walle
@ 2015-04-04 11:11  0% ` Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2015-04-04 11:11 UTC (permalink / raw)
  To: Øystein Walle; +Cc: zsh-workers

Øystein Walle wrote:
> Putting an apostrophe before i, d, u, f, F, g or G is specified in POSIX
> albeit noted as an extension to ISO C.

There's other printf features that were left out because they weren't
portable at the time. %a %A and %F formats, for example.

After looking around the ' flag is supported on any system I now have
access to, even Solaris 8. However, I can't see a mention of it in the
OpenBSD manpage: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man3/asprintf.3?query=printf&sec=3
Anyone have an OpenBSD system they can verify with? Even if it
doesn't support the flag, it'd be good to know if it is just ignored or
causes printf to fail. The flag is locale dependent anyway so being
ignored is quite reasonable for zsh's printf.

%a/A/F are in Solaris 10 which is a reasonable minimum to expect these
days. Otherwise, they need OpenBSD 4.5 though I've no idea how common
that still is. It'd be possible to test for them with autoconf but the
documentation would need to mention that they depend on the C library
implementing them.

> Bash handles this this and from what I can tell implements it much in the same
> way so that stuff like %'s is passed straight on to the system's printf().
> However POSIX also says that using the grouping specifier with other flags is
> undefined. It works just fine on the limited range of systems I've tested it on
> (all GNU).

Is it undefined with other "flags" or with non-numeric format
specifiers? It might be best to add a test case so we find out if the
behaviour is undesirable on some other system.

> If desired I could set a flag and then handle it further on by checking that
> type == 2 or type == 3 or something like that, but that needs some rearranging.

A flag is already set because it checks that flags aren't duplicated to
avoid overflowing the spec buffer. It wouldn't need much rearranging but
then it's not checking the type with other numeric only flags such as
+. For a more general implementation, the flags array could be replaced
by a single int and bit manipulation and it could set a bit mask for
compatible flags in the switch statement.

> int flags[5], *len;
>      char *start, *endptr, *c, *d, *flag, *buf = NULL, spec[13], *fmt = NULL;
> -    char **first, **argp, *curarg, *flagch = "0+- #", save = '\0', nullstr = '\0';
> +    char **first, **argp, *curarg, *flagch = "'0+- #", save = '\0', nullstr = '\0';

I'm fairly sure that you'll also need to increment the size of the flags
and spec arrays too.

> -	    /* ignore any size modifier */
> -	    if (*c == 'l' || *c == 'L' || *c == 'h') c++;
> +	    /* ignore any size modifier and grouping specifier */
> +	    if (*c == 'l' || *c == 'L' || *c == 'h' || *c == '\'') c++;

I'm not convinced this part is right. Can you remember why you needed
it? The ' flag comes before width specifiers and size modifiers.
In, e.g. printf "%2\$10f\n" 1 2
the ' flag comes after the $ and not before the f.

Oliver


^ permalink raw reply	[relevance 0%]

* "var=value exec > file" ignores the assignment?
@ 2015-04-07 15:51  4% Jun T.
  0 siblings, 0 replies; 200+ results
From: Jun T. @ 2015-04-07 15:51 UTC (permalink / raw)
  To: zsh-workers

If 'exec' has no command arg but has both parameter assignment
and redirection, the assignment seems to be ignored.

The following script outputs "x = 0" into test.log:

#!/usr/local/bin/zsh
setopt POSIX_BUILTINS 
x=0
x=1 exec > test.log
echo "x = $x"

'ksh' and 'bash -posix' (or /bin/sh) output "x = 1", which I
guess what POSIX requires.

Moreover, assuming there is no command named 'junk',

x=$(junk) exec > test.log

does NOT issue "command not found: junk" error.

The following patch *seems* to fix these, but I believe this
is at most a partial fix (or regression at the worst).

Either with or without the patch, and either POSIX_BUILTINS is
set or unset, the following outputs "x = 1" (/bin/sh outputs
"x = 0"). But I don't know whether this need be fixed (or how
to fix it if it need be).

x=0
true | x=1 exec | true
echo "x = $x"


diff --git a/Src/exec.c b/Src/exec.c
index 1a6149a..fdb2470 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3305,6 +3305,13 @@ execcmd(Estate state, int input, int output, int how, int last1)
 	    closemn(mfds, i, REDIR_CLOSE);
 
     if (nullexec) {
+	/*
+	 * If nullexec is 2, we have variables to add with the redirections
+	 * in place.
+	 */
+	if (varspc)
+	    addvars(state, varspc, 0);
+	lastval = errflag ? errflag : cmdoutval;
 	if (nullexec == 1) {
 	    /*
 	     * If nullexec is 1 we specifically *don't* restore the original
@@ -3315,13 +3322,6 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		    zclose(save[i]);
 	    goto done;
 	}
-	/*
-	 * If nullexec is 2, we have variables to add with the redirections
-	 * in place.
-	 */
-	if (varspc)
-	    addvars(state, varspc, 0);
-	lastval = errflag ? errflag : cmdoutval;
 	if (isset(XTRACE)) {
 	    fputc('\n', xtrerr);
 	    fflush(xtrerr);



^ permalink raw reply	[relevance 4%]

* Re: `[[ -n $VAR ]]` equal to `[[ $VAR ]]`?
       [not found]               ` <CABx2=D_4Aw4W9AsBNa5o1houzAipLFDBtt82BnVq0CEyNshSUA__23909.3113611036$1428636185$gmane$org@mail.gmail.com>
@ 2015-04-10 20:33  3%             ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-04-10 20:33 UTC (permalink / raw)
  To: zsh-workers

2015-04-09 20:21:50 -0700, Kurtis Rader:
[...]
> if [ "${var}x" = x ]; then
> 
> so that if $var was unset or the empty string you still had a valid
> expression.
[...]

No, that "x" (and you need it *before* $var) was never about empty $var, 


if [ "$var" = "" ]

is perfectly fine in the Bourne shell when $var is empty.

The problem is with values of $var like ! or (.

That's for those that you need:

if [ "x$var" = x ]
or
if [ "" = "$var" ]

IIRC
if [ -n "$var" ]

would be a problem for values of $var like = in some shell.
Still is with /bin/sh on Solaris 10.

I don't know if any shell ever had a problem with

if [ "${var}x" = x ]

when $var == "-". I wouldn't bet on it.


Now POSIX clearly specifies "[" aka test when the number of
arguments is less than 4, so one can count on

[ -n "$var" ]

and

[ "$var" = "" ]

being reliable in conformant shells/tests.

More info at:

http://www.in-ulm.de/~mascheck/various/test/

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* [PATCH] correct typo in doc of posixtraps
@ 2015-04-12 22:24  6% Han Pingtian
  0 siblings, 0 replies; 200+ results
From: Han Pingtian @ 2015-04-12 22:24 UTC (permalink / raw)
  To: zsh-workers

Hi,

There is a typo in the doc of posixtraps.

Signed-off-by: Han Pingtian <hanpt@linux.vnet.ibm.com>
---
 Doc/Zsh/options.yo | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 19920ca..86c330b 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2097,7 +2097,7 @@ pindex(NOPOSIXTRAPS)
 cindex(traps, on function exit)
 cindex(traps, POSIX compatibility)
 item(tt(POSIX_TRAPS) <K> <S>)(
-When the is option is set, the usual zsh behaviour of executing
+When this option is set, the usual zsh behaviour of executing
 traps for tt(EXIT) on exit from shell functions is suppressed.
 In that case, manipulating tt(EXIT) traps always alters the global
 trap for exiting the shell; the tt(LOCAL_TRAPS) option is
-- 
1.9.3


^ permalink raw reply	[relevance 6%]

* Re: [BUG] Can't mark unset variables as read-only
  @ 2015-04-29 10:36  3% ` Peter Stephenson
  2015-04-29 13:55  3%   ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-04-29 10:36 UTC (permalink / raw)
  To: zsh-workers

On Wed, 29 Apr 2015 08:35:43 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> Unlike other shells, zsh can't mark an unset variable as read-only.

Yes, the standard does indeed require that ability.  As you can imagine,
something like this that completely breaks the normal programming model
of variables (a variable can't have state if it's unset because it
doesn't exist) is a nightmare to implement; however, it can at least be
limited to the POSIXBUILTINS option and maybe the cases using that are
simple enough that it mostly works.  I'm sure there are any number of
strange edge cases, though.

The output of "readonly -p" is still broken (doesn't show the unset
variables in a fashion that can be used for restoring the current state)
but it was anyway:

  typeset -ar '*'
  *=()

Er, no, I don't think that's going to work.

So that can be fixed separately.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index dd5a80f..985d19e 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1933,6 +1933,13 @@ item(tt(-r))(
 The given var(name)s are marked readonly.  Note that if var(name) is a
 special parameter, the readonly attribute can be turned on, but cannot then
 be turned off.
+
+If the tt(POSIX_BUILTINS) option is set, the readonly attribute is
+more restrictive: unset variables can be marked readonly and cannot then
+be set; furthermore, the readonly attribute cannot be removed from any
+variable.  Note that in zsh (unlike other shells) it is still possible
+to create a local variable of the same name as this is considered a
+different variable (though this variable, too, can be marked readonly).
 )
 item(tt(-t))(
 Tags the named parameters.  Tags have no special meaning to the shell.
diff --git a/Src/builtin.c b/Src/builtin.c
index de01014..0a57489 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -1931,8 +1931,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
      * locallevel as an unset one we use the pm struct anyway: that's
      * 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.
      */
-    usepm = pm && !(pm->node.flags & PM_UNSET);
+    usepm = pm && (!(pm->node.flags & PM_UNSET) ||
+		   (isset(POSIXBUILTINS) && (pm->node.flags & PM_READONLY)));
 
     /*
      * We need to compare types with an existing pm if special,
@@ -2032,6 +2036,20 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
     else if (newspecial != NS_NONE && strcmp(pname, "SECONDS") == 0)
 	newspecial = NS_SECONDS;
 
+    if (isset(POSIXBUILTINS)) {
+	/*
+	 * Stricter rules about retaining readonly attribute in this case.
+	 */
+	if ((on & PM_READONLY) && (!usepm || (pm->node.flags & PM_UNSET)) &&
+	    !value)
+	    on |= PM_UNSET;
+	else if (usepm && (pm->node.flags & PM_READONLY) &&
+		 !(on & PM_READONLY)) {
+	    zerr("read-only variable: %s", pm->node.nam);
+	    return NULL;
+	}
+    }
+
     /*
      * A parameter will be local if
      * 1. we are re-using an existing local parameter
@@ -2078,9 +2096,15 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	}
 	if (usepm == 2)		/* do not change the PM_UNSET flag */
 	    pm->node.flags = (pm->node.flags | (on & ~PM_READONLY)) & ~off;
-	else
+	else {
+	    /*
+	     * Keep unset if using readonly in POSIX mode.
+	     */
+	    if (!(on & PM_READONLY) || !isset(POSIXBUILTINS))
+		off |= PM_UNSET;
 	    pm->node.flags = (pm->node.flags |
-			      (on & ~PM_READONLY)) & ~(off | PM_UNSET);
+			      (on & ~PM_READONLY)) & ~off;
+	}
 	if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
 	    if (typeset_setwidth(cname, pm, ops, on, 0))
 		return NULL;
@@ -2256,7 +2280,12 @@ typeset_single(char *cname, char *pname, Param pm, UNUSED(int func),
 	 * readonly flag
 	 */
 	pm = createparam(pname, on & ~PM_READONLY);
-	DPUTS(!pm, "BUG: parameter not created");
+	if (!pm) {
+	    if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z |
+		      PM_INTEGER | PM_EFLOAT | PM_FFLOAT))
+		zerrnam(cname, "can't change variable attribute: %s", pname);
+	    return NULL;
+	}
 	if (on & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) {
 	    if (typeset_setwidth(cname, pm, ops, on, 0))
 		return NULL;
diff --git a/Src/params.c b/Src/params.c
index e8a9010..d53b6ca 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -874,10 +874,14 @@ createparam(char *name, int flags)
 	DPUTS(oldpm && oldpm->level > locallevel,
 	      "BUG: old local parameter not deleted");
 	if (oldpm && (oldpm->level == locallevel || !(flags & PM_LOCAL))) {
+	    if (isset(POSIXBUILTINS) && (oldpm->node.flags & PM_READONLY)) {
+		zerr("read-only variable: %s", name);
+		return NULL;
+	    }
 	    if (!(oldpm->node.flags & PM_UNSET) || (oldpm->node.flags & PM_SPECIAL)) {
 		oldpm->node.flags &= ~PM_UNSET;
 		if ((oldpm->node.flags & PM_SPECIAL) && oldpm->ename) {
-		    Param altpm = 
+		    Param altpm =
 			(Param) paramtab->getnode(paramtab, oldpm->ename);
 		    if (altpm)
 			altpm->node.flags &= ~PM_UNSET;
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 51ebc65..f4fb8ec 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -468,3 +468,20 @@
 0:retying arrays to same array works
 >foo bar
 >goo car
+
+ (
+   setopt POSIXBUILTINS
+   readonly pbro
+   print ${+pbro} >&2
+   (typeset pbro=3)
+   (pbro=4)
+   typeset -r pbro        # idempotent (no error)...
+   print ${+pbro} >&2     # ...so still readonly...
+   typeset +r pbro        # ...can't turn it off
+ )
+1:Readonly with POSIX_BUILTINS
+?0
+?(eval):5: read-only variable: pbro
+?(eval):6: read-only variable: pbro
+?0
+?(eval):9: read-only variable: pbro


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Can't mark unset variables as read-only
  2015-04-29 10:36  3% ` Peter Stephenson
@ 2015-04-29 13:55  3%   ` Bart Schaefer
  2015-04-29 14:41  0%     ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-04-29 13:55 UTC (permalink / raw)
  To: zsh-workers

On Apr 29, 11:36am, Peter Stephenson wrote:
}
} +Note that in zsh (unlike other shells) it is still possible
} +to create a local variable of the same name as this is considered a
} +different variable (though this variable, too, can be marked readonly).

Hrm, I wonder if that, combined with "typeset" automatically creating
locals when called in a function context (also a POSIX incompatibility?) 
defeats the whole purpose of an unset readonly?

Actually it probably undermines readonly for variables that are set, too,
so I probably shouldn't worry about it because it isn't changing.


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Can't mark unset variables as read-only
  2015-04-29 13:55  3%   ` Bart Schaefer
@ 2015-04-29 14:41  0%     ` Peter Stephenson
  2015-04-29 15:33  5%       ` Chet Ramey
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-04-29 14:41 UTC (permalink / raw)
  To: zsh-workers

On Wed, 29 Apr 2015 06:55:56 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:

> On Apr 29, 11:36am, Peter Stephenson wrote:
> }
> } +Note that in zsh (unlike other shells) it is still possible
> } +to create a local variable of the same name as this is considered a
> } +different variable (though this variable, too, can be marked readonly).
> 
> Hrm, I wonder if that, combined with "typeset" automatically creating
> locals when called in a function context (also a POSIX incompatibility?) 
> defeats the whole purpose of an unset readonly?

I don't think so... bash makes these local, too:

$ foo=bar
$ fn() { typeset foo=something_else; echo $foo; }
$ fn
something_else
$ echo $foo
bar

So "foo" in fn is logically something entirely different and I don't
think there's any requirement for it to be treated as readonly;
it's entirely a matter for the definition of "fn".

pws


^ permalink raw reply	[relevance 0%]

* Re: [BUG] Can't mark unset variables as read-only
  2015-04-29 14:41  0%     ` Peter Stephenson
@ 2015-04-29 15:33  5%       ` Chet Ramey
  2015-04-29 19:09  3%         ` Stephane Chazelas
  2015-04-30  3:57  5%         ` Bart Schaefer
  0 siblings, 2 replies; 200+ results
From: Chet Ramey @ 2015-04-29 15:33 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers; +Cc: chet.ramey

On 4/29/15 10:41 AM, Peter Stephenson wrote:
> On Wed, 29 Apr 2015 06:55:56 -0700
> Bart Schaefer <schaefer@brasslantern.com> wrote:
> 
>> On Apr 29, 11:36am, Peter Stephenson wrote:
>> }
>> } +Note that in zsh (unlike other shells) it is still possible
>> } +to create a local variable of the same name as this is considered a
>> } +different variable (though this variable, too, can be marked readonly).
>>
>> Hrm, I wonder if that, combined with "typeset" automatically creating
>> locals when called in a function context (also a POSIX incompatibility?) 

It's not a Posix incompatibility; Posix does not specify typeset or local
variables at all.  The Posix-conformant ways of declaring variables in a
function result in global variables, as Posix specifies.

>> defeats the whole purpose of an unset readonly?

The question is whether or not you can use local variables to `shadow'
readonly variables in a previous scope.  Bash doesn't allow you to do
that.  Given this script:

readonly foo=immutable

func()
{
	local foo=bar
	echo inside: $foo
}

func
echo outside: $foo

Bash gives the following output:

./x26: line 5: local: foo: readonly variable
inside: immutable
outside: immutable

If the purpose of readonly is to make a particular name/value pair
immutable, I think that allowing a local variable to shadow it,
especially if you're going to export that local variable, is a bad thing.

> 
> I don't think so... bash makes these local, too:
> 
> $ foo=bar
> $ fn() { typeset foo=something_else; echo $foo; }
> $ fn
> something_else
> $ echo $foo
> bar
> 
> So "foo" in fn is logically something entirely different and I don't
> think there's any requirement for it to be treated as readonly;

There's no requirement, since there are no standards for local variables
or variable scoping.  Bash does what I think is right.

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


^ permalink raw reply	[relevance 5%]

* Re: [BUG] Can't mark unset variables as read-only
  2015-04-29 15:33  5%       ` Chet Ramey
@ 2015-04-29 19:09  3%         ` Stephane Chazelas
  2015-04-30  3:57  5%         ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-04-29 19:09 UTC (permalink / raw)
  To: zsh-workers

2015-04-29 11:33:10 -0400, Chet Ramey:
[...]
> func()
> {
> 	local foo=bar
> 	echo inside: $foo
> }
> 
> func
> echo outside: $foo
> 
> Bash gives the following output:
> 
> ./x26: line 5: local: foo: readonly variable
> inside: immutable
> outside: immutable
> 
> If the purpose of readonly is to make a particular name/value pair
> immutable, I think that allowing a local variable to shadow it,
> especially if you're going to export that local variable, is a bad thing.
[...]

I don't agree.

The whole point of having local variables is to avoid problems
with clashing namespaces.


You can have:

f() {
  local foo=1 # f's own variable
  g xxx
  echo "$foo"
}

g() {
  local foo=2
  blah blah
}

(f and g possibly in different libraries)

By declaring foo local, you make sure that you're not clashing
with someone else's foo. 

You don't have to worry on how you name your functions like you
do in POSIX sh (where you'd need to call one variable f_foo, and
the other g_foo for intance).

Above, if you do:

f() {
  readonly foo=2
  g xxx
  echo "$foo"
}

You're basically breaking g for no good reason. f's doesn't want
the value of f to be modified, but g would not have modified it
since it's declaring its *own* foo variable.

Having said that, I don't remember ever using "readonly" in a
script so I can't say I care much.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: [BUG] Can't mark unset variables as read-only
  2015-04-29 15:33  5%       ` Chet Ramey
  2015-04-29 19:09  3%         ` Stephane Chazelas
@ 2015-04-30  3:57  5%         ` Bart Schaefer
  1 sibling, 0 replies; 200+ results
From: Bart Schaefer @ 2015-04-30  3:57 UTC (permalink / raw)
  To: zsh-workers

On Apr 29, 11:33am, Chet Ramey wrote:
} Subject: Re: [BUG] Can't mark unset variables as read-only
}
} > On Wed, 29 Apr 2015 06:55:56 -0700
} > Bart Schaefer <schaefer@brasslantern.com> wrote:
} > 
} >> On Apr 29, 11:36am, Peter Stephenson wrote:
} >> }
} >> } +Note that in zsh (unlike other shells) it is still possible
} >> } +to create a local variable of the same name as this is considered a
} >> } +different variable (though this variable, too, can be marked readonly).
} >>
} >> Hrm, I wonder if that, combined with "typeset" automatically creating
} >> locals when called in a function context (also a POSIX incompatibility?) 
} 
} It's not a Posix incompatibility; Posix does not specify typeset or local
} variables at all.  The Posix-conformant ways of declaring variables in a
} function result in global variables, as Posix specifies.

Thanks for refreshing my memory there.
 
} >> defeats the whole purpose of an unset readonly?
} 
} The question is whether or not you can use local variables to `shadow'
} readonly variables in a previous scope.  Bash doesn't allow you to do
} that.

This discussion has reminded me another thing I forgot:  for variables
that have defined meaning to the shell ("special" variables) zsh allows
shadowing of a readonly special only if the "-h" (hide) flag is passed
to "local" or one of its equivalents (integer, declare, etc.).

} If the purpose of readonly is to make a particular name/value pair
} immutable, I think that allowing a local variable to shadow it,
} especially if you're going to export that local variable, is a bad thing.

Here's a curious data point:  In ksh, functions declared with POSIX
syntax "name() { ...; }" treat readonly from the surrounding scope the
way bash does.  Those declared "function name { ...; }" treat readonly
the way zsh does, allowing shadowing in the local scope.

Maybe zsh needs yet another POSIX_* option.


^ permalink raw reply	[relevance 5%]

* Re: PATCH: 5.0.8 notes
  @ 2015-04-30 22:13  3% ` Mikael Magnusson
    0 siblings, 1 reply; 200+ results
From: Mikael Magnusson @ 2015-04-30 22:13 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Thu, Apr 30, 2015 at 10:03 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> There ought to be more worth mentioning...
>
> -Note in particular there is a security fix to disallow evaluation of the
> -initial values of integer variables imported from the environment (they
> -are instead treated as literal numbers).  That could allow local
> -privilege escalation, under some specific and atypical conditions where
> -zsh is being invoked in privilege elevation contexts when the
> -environment has not been properly sanitized, such as when zsh is invoked
> -by sudo on systems where "env_reset" has been disabled.
> +This is version 5.0.8 of the shell.  This is a stable release.
> +There are no significant new features since 5.0.6, but there

should this say .7?                                ^

I'm not sure how much we usually list here but here's some stuff from
a look through the git log,

${(p.$param.)

some numerous changes to the vi mode, i don't use it but maybe oliver
can chime in?

waiting on already exited processes

whence -v lists file function was defined in
       -S shows intermediate symlink steps

$(< error not fatal anymore

faster history lockfile retrying

zsh/db/gdbm module, ztie -r / zuntie -u

pattern support in watch variable

aliasing && and other tokens (this is already in NEWS, but not listed
separately for .8)

posix builtins and exec + assignments

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 3%]

* PATCH: update completions for some common Unix commands
@ 2015-05-01  9:58  5% Oliver Kiddle
  0 siblings, 0 replies; 200+ results
From: Oliver Kiddle @ 2015-05-01  9:58 UTC (permalink / raw)
  To: Zsh workers

This updates various _arguments options lists for some mostly common
Unix commands, in particular FreeBSD support is improved. In the case
of the other BSDs, I've consulted online manpages but that doesn't help
in all cases, e.g. in _ps_props(). I've left _beadm in the Solaris
directory despite it being applicable to FreeBSD. If moved, I'd
recommend _be_name be renamed _boot_environments: our normal convention
is for plural forms. Some of these need more work such as _ping and
_patch seems fairly broken with newer versions of patch.

Oliver

diff --git a/Completion/BSD/Type/_jails b/Completion/BSD/Type/_jails
new file mode 100644
index 0000000..36bffec
--- /dev/null
+++ b/Completion/BSD/Type/_jails
@@ -0,0 +1,5 @@
+#autoload
+
+jails=( ${${${${(f)"$(_call_program jails jls -n)"}##*jid=}/ name=/:}%% *} )
+
+_describe -t jails jail jails "$@"
diff --git a/Completion/Solaris/Command/_beadm b/Completion/Solaris/Command/_beadm
index 6e498be..8422653 100644
--- a/Completion/Solaris/Command/_beadm
+++ b/Completion/Solaris/Command/_beadm
@@ -1,76 +1,69 @@
 #compdef beadm
 
-_beadm() {
-	local context state line subcmds
-	typeset -A opt_args
+local cmd expl args
 
-	subcmds=( activate create destroy list mount rename unmount )
+if (( CURRENT == 2 )); then
+  _wanted subcommands expl 'subcommand' compadd \
+      activate create destroy list mount rename unmount
+  return
+fi
 
-	if [[ $service == "beadm" ]]; then
-		_arguments -C -A "-*" \
-			'*::command:->subcmd' && return 0
+cmd="$words[2]"
+curcontext="${curcontext%:*}-$cmd:"
+shift words
+(( CURRENT-- ))
 
-		if (( CURRENT == 1 )); then
-			_wanted commands expl 'beadm subcommand' compadd -a subcmds
-			return
-		fi
-		service="$words[1]"
-		curcontext="${curcontext%:*}=$service:"
-	fi
-
-	case $service in
-	(activate)
-		_arguments -A "-*" \
-			':BE name:_be_name'
-		;;
-
-	(create)
-		# TODO: Add support for -o, and for creating snapshots
-		_arguments -A "-*" \
-			'-a[Activate new BE]' \
-			'-d[Description]:' \
-			'-e[Base BE]:BE name or snapshot:_be_name -t all' \
-			'-p[Create new BE in specified ZFS pool]:ZFS pool:_zfs_pool' \
-			':new BE name:'
-		;;
-
-	(destroy)
-		_arguments -A "-*" \
-			'-f[Unmount BE if necessary]' \
-			"-F[Don't prompt for verification]" \
-			':BE or BE snapshot:_be_name'
-		;;
-
-	(list)
-		_arguments -A "-*" \
-			'-a[List subordinate filesystems and snapshots]' \
-			'-d[List subordinate filesystems]' \
-			'-s[List snapshots]' \
-			'-H[Parseable format]' \
-			':BE name:_be_name'
-		;;
-
-	(mount)
-		_arguments -A "-*" \
-			':BE name:_be_name' \
-			':mountpoint:_path_files -/'
-		;;
-
-	(rename)
-		_arguments -A "-*" \
-			':existing BE name:_be_name' \
-			':new BE name:'
-		;;
-
-	(unmount)
-		_arguments -A "-*" \
-			'-f[Force unmount]' \
-			':BE name:_be_name'
-		;;
-
-	(*)
-		_message "unknown beadm subcommand: $service"
-	esac
-}
-
-_beadm "$@"
+case $cmd in
+  activate)
+    _wanted boot-environs expl 'boot environment' _be_name
+  ;;
+  create)
+    [[ $OSTYPE = solaris* ]] && args=(
+      '-a[activate new BE]'
+      '-d[description]:description'
+      '*-o[property]:zfs property'
+      '-p[create new BE in specified zfs pool]:zfs pool:_zfs_pool'
+    )
+    _arguments -A "-*" $args \
+      '-e[base BE]:BE name or snapshot:_be_name -t all' \
+      ':new BE name:'
+  ;;
+  destroy)
+    [[ $OSTYPE = solaris* ]] && args=(
+      '-f[unmount BE if necessary]'
+    )
+    _arguments -A "-*" \
+      "-F[don't prompt for verification]" \
+      ':BE or BE snapshot:_be_name'
+  ;;
+  list)
+    if [[ $OSTYPE = solaris* ]]; then
+      args=( '-d[list subordinate filesystems]' )
+    elif [[ $OSTYPE = freebsd* ]]; then
+      args=( '-D[display space usage of boot environment]' )
+    fi
+    _arguments -A "-*" \
+      '-a[list subordinate filesystems and snapshots]' \
+      '-s[list snapshots]' \
+      '-H[parseable format]' \
+      ':boot environment:_be_name'
+  ;;
+  mount)
+    _arguments -A "-*" \
+      ':BE name:_be_name' \
+      ':mountpoint:_path_files -/'
+  ;;
+  rename)
+    _arguments -A "-*" \
+      ':existing boot environment name:_be_name' \
+      ':new boot environment:'
+  ;;
+  u(n|)mount)
+    _arguments -A "-*" \
+      '-f[force unmount]' \
+      ':boot environment:_be_name'
+  ;;
+  *)
+    _message "unknown beadm subcommand: $service"
+  ;;
+esac
diff --git a/Completion/Solaris/Command/_gcore b/Completion/Solaris/Command/_gcore
deleted file mode 100644
index d4ac9a0..0000000
--- a/Completion/Solaris/Command/_gcore
+++ /dev/null
@@ -1,31 +0,0 @@
-#compdef gcore
-
-_gcore() {
-	local -a content
-
-	content=(
-		"anon[anonymous private mappings]"
-		"ctf[CTF type information]"
-		"data[writable private file mappings]"
-		"dism[DISM mappings]"
-		"heap[process heap]"
-		"ism[ISM mappings]"
-		"rodata[read-only private file mappings]"
-		"shanon[anonymous shared mappings]"
-		"shfile[file-backed shared mappings]"
-		"shm[System V shared memory]"
-		"stack[process stack]"
-		"symtab[symbol table sections for loaded files]"
-		"text[readable and executable private file mappings]"
-	)
-
-	_arguments -s \
-		'-p[use per-process core file repository]' \
-		'-g[use global core file repository]' \
-		'-F[force grabbing the target process]' \
-		'-c[set core file content]:_values -s + "content" $content' \
-		'-o[set core file base name]:' \
-		'*:pids:_pids'
-}
-
-_gcore "$@"
diff --git a/Completion/Solaris/Command/_ps b/Completion/Solaris/Command/_ps
deleted file mode 100644
index 5ae6183..0000000
--- a/Completion/Solaris/Command/_ps
+++ /dev/null
@@ -1,77 +0,0 @@
-#compdef ps
-
-_ps()
-{
-	local -a o_opt
-
-o_opt=(
-	"user[user ID]"
-	"ruser[real user ID]"
-	"group[group ID]"
-	"rgroup[real group ID]"
-	"pid[process ID]"
-	"ppid[parent process ID]"
-	"pgid[process group ID]"
-	"pcpu[ratio of CPU time used recently to CPU time available]"
-	"vsz[total size of the process in virtual memory, in kilobytes]"
-	"nice[decimal value of the system scheduling priority of the process]"
-	"etime[elapsed time since the process was started]"
-	"time[cumulative CPU time of the process]"
-	"tty[name of the controlling terminal of the process]"
-	"comm[name of the command being executed]"
-	"args[command with all its arguments as a string]"
-	"f[flags associated with the process]"
-	"s[state of the process]"
-	"c[processor utilization for scheduling]"
-	"uid[effective user ID number]"
-	"ruid[real user ID number]"
-	"gid[effective group ID number]"
-	"rgid[real group ID numberu]"
-	"projid[project ID number]"
-	"project[project name]"
-	"zoneid[zone ID number]"
-	"zone[zone name]"
-	"sid[process ID of the session leader]"
-	"taskid[task ID of the process]"
-	"class[scheduling class]"
-	"pri[priority, higher number - higher priority]"
-	"opri[obsolete priority, lower number - higher priority]"
-	"lwp[lwd ID number]"
-	"nlwp[number of lwps in the process]"
-	"psr[number of the processor to which the process or lwp is bound]"
-	"pset[ID of the processor set to which the process or lwp is bound]"
-	"addr[memory address of the process]"
-	"osz[total size of the process in virtual memory, in pages]"
-	"wchan[address of an event for which the process is sleeping]"
-	"stime[starting time or date of the process]"
-	"rss[resident set size of the process, in kilobytes]"
-	"pmem[ratio of resident set size to physical memory on the machine, in %]"
-	"fname[first 8 bytes of base name of process's executable file]"
-	"ctid[contract ID number]"
-	"lgrp[home lgroup]"
-)
-_arguments \
-	'-a[information about all processes most frequently requested]' \
-	'-c[information in a format that reflects scheduler properties]' \
-	'-d[information about all processes except session leaders]' \
-	'-e[information about every process]' \
-	'-f[full listing]' \
-	'-g[only process data whose group leaders ID number(s) appears in grplist]:group leader ID list' \
-	'-G[information for processes whose real group ID numbers are in gidlist]:real group ID list' \
-	'-H[prints the home lgroup of the process]' \
-	'-j[prints session ID and process group ID]' \
-	'-l[long listing]' \
-	'-L[information about each light weight process]' \
-	'-o[specify output format]:property:_values -s , "property" $o_opt' \
-	'-p[only process data whose process ID numbers are given in proclist]:process ID list' \
-	'-P[Prints the number of the processor to which the process or lwp is bound]' \
-	'-s[information on all session leaders whose IDs appear in sidlist]:session leader ID list' \
-	'-t[lists only process data associated with term]:term' \
-	'-u[only process data whose effective user ID number or login name is given in uidlist]:UID:_users' \
-	'-U[information for processes whose real user ID numbers or login names are in uidlist]:UID:_users' \
-	'-y[both RSS and SZ is reported in kilobytes, instead pages (used with -l)]' \
-	'-z[lists only processes in the specified zones]:zone list' \
-	'-Z[prints the name of the zone with which the process is associated]'
-}
-
-_ps "$@"
diff --git a/Completion/Solaris/Type/_be_name b/Completion/Solaris/Type/_be_name
index b25a8ff..4b80c65 100644
--- a/Completion/Solaris/Type/_be_name
+++ b/Completion/Solaris/Type/_be_name
@@ -1,18 +1,13 @@
 #autoload
 
-local -a type be_names
-local name uuid activate mtpt space policy created snap
+local -a type be_names expl
 
 zparseopts -D -E -a type t+:
 
-beadm list -H | while IFS=\; read name uuid active mtpt space policy created; do
-	be_names=( $be_names $name )
-done
+be_names=( ${${(f)"$(_call_program boot-environs beadm list -H)"}%%;*} )
 
-if [[ -n $type[(r)all] ]]; then
-	beadm list -sH | while IFS=\; read name snap space policy created; do
-		be_names=( $be_names $snap )
-	done
-fi
+[[ -n $type[(r)all] ]] &&
+  be_names+=( ${${${(f)"$(_call_program boot-environs beadm list -sH)"}#*;}%%;*} )
 
-compadd "$@" - $be_names
+_description boot-environs expl 'boot environment'
+compadd "$@" "$expl[@]" -a be_names
diff --git a/Completion/Solaris/Type/_zones b/Completion/Solaris/Type/_zones
index 0c2d273..92064d2 100644
--- a/Completion/Solaris/Type/_zones
+++ b/Completion/Solaris/Type/_zones
@@ -1,13 +1,11 @@
 #autoload
 
-local -a type typearg
-local zonelist
+local -a type typearg expl
 
 zparseopts -D -E -a type t+:
 
 [[ -n $type[(r)c] ]] && typearg=-c
 [[ -n $type[(r)i] ]] && typearg=-i
 
-zonelist=( ${="$(zoneadm list $typearg)"} )
-
-compadd "$@" - $zonelist
+_description zones expl zone
+compadd "$@" "$expl[@]" - ${="$(_call_program zones /usr/sbin/zoneadm list $typearg)"}
diff --git a/Completion/Unix/Command/_chmod b/Completion/Unix/Command/_chmod
index 48ce050..85e6df1 100644
--- a/Completion/Unix/Command/_chmod
+++ b/Completion/Unix/Command/_chmod
@@ -1,34 +1,52 @@
-#compdef chmod
+#compdef chmod gchmod
 
 local curcontext="$curcontext" state line expl ret=1
 local -a args privs
 
-args=( '*:file:->files' )
-(( $+words[(r)--reference*] )) || args+=( '1:mode:->mode' )
+args=( '*:file:->files' '1:mode:->mode' )
 
 if _pick_variant gnu=Free\ Soft unix --version; then
   args+=(
     '(-v --verbose -c --changes)'{-c,--changes}'[report changes made]'
     '(-v --verbose -c --changes)'{-v,--verbose}'[output a diagnostic for every file processed]'
     '(-f --silent --quiet)'{-f,--silent,--quiet}'[suppress most error messages]'
-    '--reference=[copy permissions of specified file]:file:_files'
+    '(--no-preserve-root)--preserve-root[fail to operate recursively on /]'
+    "(--preserve-root)--no-preserve-root[don't treat / specially (default)]"
+    '(1)--reference=[copy permissions of specified file]:file:_files'
     '(-R --recursive)'{-R,--recursive}'[change files and directories recursively]'
     '(- : *)--help[display help information]'
     '(- : *)--version[display version information]'
   )
-  privs=(
-    'X[execute only if executable to another]'
-    "u[owner's current permissions]"
-    "g[group's current permissions]"
-    "o[other's current permissions]"
-  )
 else
-  # based on $OSTYPE = solaris2.8
   args+=(
     '-f[suppress most error messages]'
     '-R[change files and directories recursively]'
   )
-  privs=( 'l[mandatory locking]' )
+  case $OSTYPE in
+    freebsd*|dragonfly*|darwin*)
+      args+=( '-v[output a diagnostic for every file processed]')
+    ;|
+    freebsd*|netbsd*|darwin*|dragonfly*)
+      args+=( "-h[operate on symlinks them self]" )
+    ;|
+    freebsd*|openbsd*|netbsd*|darwin*|dragonfly*)
+      args+=(
+	'(-H -L -P)-L[follow all symlinks]'
+	'(-H -L -P)-H[follow symlinks on the command line]'
+	'(-H -L -P)-P[do not follow symlinks (default)]'
+      )
+    ;|
+    darwin*)
+      args+=(
+        '(1)-C[returns false if any of the named files have ACLs]'
+	'(1)-N[remove ACLs from specified files]'
+	'(1)-E[read ACL info from stdin as a sequential list of ACEs]'
+	'(1)-i[removes inherited bit from all entries in named files ACLs]'
+        '(1)-I[removes all inherited entries from named files ACLs]'
+      )
+    ;;
+    solaris*) privs=( 'l[mandatory locking]' ) ;;
+  esac
 fi
 
 _arguments -C -s "$args[@]" && ret=0
@@ -43,6 +61,10 @@ case "$state" in
       _values -S '' privilege \
 	'r[read]' 'w[write]' 'x[execute]' \
 	's[set uid/gid]' 't[sticky]' \
+	'X[execute only if directory or executable to another]' \
+	"u[owner's current permissions]" \
+	"g[group's current permissions]" \
+	"o[other's current permissions]" \
 	"$privs[@]" && ret=0
     else
       suf=( -S '' )
diff --git a/Completion/Unix/Command/_chown b/Completion/Unix/Command/_chown
index 71c21da..641b5a7 100644
--- a/Completion/Unix/Command/_chown
+++ b/Completion/Unix/Command/_chown
@@ -1,29 +1,42 @@
 #compdef chown chgrp zf_chown=chown zf_chgrp=chgrp
 
 local curcontext="$curcontext" state line expl ret=1
-local suf usr grp req deref args
+local suf usr grp req deref pattern arg args
 
 if _pick_variant gnu=Free\ Soft unix --version; then
   args=(
     '(-c --changes -v --verbose)'{-c,--changes}'[report each change made]'
     '(-c --changes -v --verbose)'{-v,--verbose}'[output info for every file processed]'
     '(-h --no-dereference)--dereference[dereference symlinks]'
-    '(-h --no-dereference --dereference)'{-h,--no-dereference}'[operate on symlinks them self]'
+    '(-h --no-dereference --dereference)'{-h,--no-dereference}'[operate on symlinks themselves]'
     '(-f --silent --quiet)'{-f,--silent,--quiet}"[don't report errors]"
+    '--preserve-root[fail to operate recursively on /]'
     '--reference=[copy ownership of specified file]:file:_files'
     '(-R --recursive)'{-R,--recursive}'[change files and directories recursively]'
+    '(-H -L -P)-L[follow all symlinks]'
+    '(-H -L -P)-H[follow symlinks on the command line]'
+    '(-H -L -P)-P[do not follow symlinks (default)]'
     '(- : *)--help[display help information]'
     '(- : *)--version[display version information]'
   )    
   [[ $service = chown ]] &&
       args+=( '--from=[restrict changes to files by current ownership]: :->owner' )
 else
-  # based on $OSTYPE = solaris2.8
   args=(
     "-f[don't report errors]"
     "-h[operate on symlinks them self]"
     '-R[change files and directories recursively]'
+    '(-H -L -P)-L[follow all symlinks]'
+    '(-H -L -P)-H[follow symlinks on the command line]'
+    '(-H -L -P)-P[do not follow symlinks (default)]'
   )
+  for pattern arg in \
+    'freebsd*' "-x[don't traverse file systems]" \
+    '(darwin|dragonfly|(free|net)bsd)*' '-v[output info for every file processed]' \
+    'solaris2.<11->' '-s[owner and/or group are Windows SID strings]'
+  do
+    [[ $OSTYPE = $~pattern ]] && args+=( $arg )
+  done
 fi
 
 (( $+words[(r)--reference*] )) || args+=( '(--reference)1: :->owner' )
diff --git a/Completion/Unix/Command/_cmp b/Completion/Unix/Command/_cmp
new file mode 100644
index 0000000..bcede8b
--- /dev/null
+++ b/Completion/Unix/Command/_cmp
@@ -0,0 +1,33 @@
+#compdef cmp gcmp
+
+local args variant
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+
+case $variant in
+  gnu)
+    args=(
+      '(-b --print-bytes)'{-b,--print-bytes}'[print differing bytes]'
+      '(-i --ignore-initial)'{-i+,--ignore-initial}'[skip specified number of bytes]:bytes'
+      '(-l --verbose -s --silent --quiet)'{-l,--verbose}'[output all differences]'
+      '(-n --bytes)'{-n+,--bytes=}'[specify maximum bytes to compare]:bytes'
+      '(-s --quiet --silent -l --verbose)'{-s,--quiet,--silent}'[return status alone signifies differences]'
+      '(- *)'{-v,--version}'[display version information]'
+      '(- *)--help[display help information]'
+    )
+  ;;
+  freebsd*|openbsd*)
+    args=(
+      "-h[don't follow symbolic links]"
+      '-x[hexadecimal output and zero based offset index]'
+      '-z[compare file sizes first]'
+    )
+  ;&
+  *)
+    args+=(
+      '(-s)-l[output all differences]'
+      '(-l)-s[silent: return status alone signifies differences]'
+    )
+  ;;
+esac
+
+_arguments -s $args '1:file 1:_files' '2:file 2:_files' '::byte offset' '::byte offset'
diff --git a/Completion/Unix/Command/_comm b/Completion/Unix/Command/_comm
index e90c317..d1d835f 100644
--- a/Completion/Unix/Command/_comm
+++ b/Completion/Unix/Command/_comm
@@ -1,20 +1,27 @@
-#compdef comm
+#compdef comm gcomm
 
 local -a args
 
 args=(
-  '-1[suppress lines unique to FILE1]'
-  '-2[suppress lines unique to FILE2]'
+  '-1[suppress lines unique to first file]'
+  '-2[suppress lines unique to second file]'
   '-3[suppress lines that appear in both files]'
-  '1:file1 to compare:_files'
-  '2:file2 to compare:_files'
+  '1:file to compare:_files'
+  '2:file to compare:_files'
 )
 
 if _pick_variant gnu=GNU unix --version; then
   args+=(
+    '(--nocheck-order)--check-order[check input is correctly sorted]'
+    "(--check-order)--nocheck-order[don't check input is correctly sorted]"
+    '--output-delimiter=:delimiter'
     '(- : *)--version[display version information]'
     '(- : *)--help[display help information]'
   )
+elif [[ $OSTYPE = (freebsd|dragonfly|darwin)* ]]; then
+  args+=( '-i[case insensitive comparison of lines]' )
+elif [[ $OSTYPE = (openbsd|netbsd)* ]]; then
+  args+=( '-f[case insensitive comparison of lines]' )
 fi
 
 _arguments -s $args
diff --git a/Completion/Unix/Command/_cp b/Completion/Unix/Command/_cp
index 70ab085..4c4dea2 100644
--- a/Completion/Unix/Command/_cp
+++ b/Completion/Unix/Command/_cp
@@ -1,22 +1,23 @@
-#compdef cp
+#compdef cp gcp
 
 if _pick_variant gnu=GNU unix --version; then
   _arguments -s -S \
-    '(-a --archive)'{-a,--archive}'[same as -dR --preserve=all]' \
+    '(-a --archive)'{-a,--archive}'[archive mode, same as -dR --preserve=all]' \
+    "--attributes-only[don't copy file data, just attributes]" \
     '(-b --backup)-b[backup]' \
-    '(-b --backup)--backup=[backup]:method:(none off numbered t existing nil simple never)' \
+    '(-b --backup)--backup=-[backup each destination file]::method:(none off numbered t existing nil simple never)' \
     '--copy-contents[copy contents of special files when recursive]' \
     '-d[same as --no-dereference --preserve=links]' \
     '(-f --force)'{-f,--force}'[remove and retry for destinations that cannot be opened]' \
-    '(-i --interactive)'{-i,--interactive}'[prompt before overwrite]' \
+    '(-i --interactive -n --no-clobber)'{-i,--interactive}'[prompt before overwrite]' \
     '-H[follow command-line symbolic links]' \
     '(-l --link)'{-l,--link}'[link files instead of copying]' \
     '(-L --dereference)'{-L,--dereference}'[always follow symbolic links]' \
-    '(-n --no-clobber)'{-n,--no-clobber}'[do not overwrite an existing file]' \
+    (-n --no-clobber -i --interactive){-n,--no-clobber}"[don't overwrite an existing file]" \
     '(-P --no-dereference)'{-P,--no-dereference}'[never follow symbolic links]' \
     '-p[same as --preserve=mode,ownership,timestamps]' \
-    '--preserve=[preserve specified attributes]:attributes to preserve:_values -s , mode timestamps ownership links context xattr all' \
-    '--no-preserve=[don'\''t preserve specified attributes]:attributes not to preserve:_values -s , mode timestamps ownership links context xattr all' \
+    '--preserve=-[preserve specified attributes]:: :_values -s , attribute mode timestamps ownership links context xattr all' \
+    "--no-preserve=[don't preserve specified attributes]: :_values -s , attribute mode timestamps ownership links context xattr all" \
     '--parents[append source path to target directory]' \
     '(-R -r --recursive)'{-R,-r,--recursive}'[copy directories recursively]' \
     '--reflink=-[control clone/CoW copies]::when to perform a lightweight copy:(always auto)' \
@@ -24,39 +25,41 @@ if _pick_variant gnu=GNU unix --version; then
     '--sparse=[control creation of sparse files]:when to create sparse files:(auto always never)' \
     '--strip-trailing-slashes[remove any trailing slashes from each source argument]' \
     '(-s --symbolic-link)'{-s,--symbolic-link}'[make symbolic links instead of copies of non-directories]' \
-    '(-S --suffix)'{-S,--suffix=}'[override the usual backup suffix]:backup suffix:' \
-    '(-t --target-directory)'{-t,--target-directory=}'[copy all source arguments into target directory]:target directory:_files -/' \
+    '(-S --suffix)'{-S+,--suffix=}'[override the usual backup suffix]:backup suffix' \
+    '(-t --target-directory)'{-t+,--target-directory=}'[copy all source arguments into target directory]:target directory:_files -/' \
     '(-T --no-target-directory)'{-T,--no-target-directory}'[treat DEST as a normal file]' \
     '(-u --update)'{-u,--update}'[copy only when source is newer than destination or destination is missing]' \
     '(-v --verbose)'{-v,--verbose}'[explain what is being done]' \
     '(-x --one-file-system)'{-x,--one-file-system}'[stay on this file system]' \
-    '--help' \
-    '--version' \
+    '(--context)-Z[set destination SELinux security context]' \
+    '(-Z)--context=-[set destination SELinux security context]::context' \
+    '(- *)--help' '(- *)--version' \
     '*:file or directory:_files'
-
-elif [[ "$OSTYPE" == darwin* ]]; then
-  _arguments -s -S \
-    '-R[copy directories recursively]' \
-    '(-L -P)-H[with -R, follow symlinks on the command line]' \
-    '(-H -P)-L[with -R, follow all symlinks]' \
-    '(-H -L)-P[with -R, do not follow symlinks (default)]' \
-    '(-i -n)-f[force overwriting existing file]' \
-    '(-f -n)-i[confirm before overwriting existing file]' \
-    '(-f -i)-n[do not overwrite existing file]' \
-    '-a[same as -pRP]' \
-    '-p[preserve timestamps, mode, owner, flags, ACLs, and Extended Attributes]' \
-    '-v[show file names as they are copied]' \
-    '-X[do not copy Extended Attributes or resource forks]' \
-    '(-)*:file or directory:_files'
-
-else    # assume POSIX
-  _arguments -s -S \
+else
+  local pattern arg args
+  args=(
+    '(-L -P)-H[follow symlinks on the command line in recursive mode]'
+    '(-H -P)-L[follow all symlinks in recursive mode]'
+    '(-H -L)-P[do not follow symlinks in recursive mode (default)]'
+    '(-i -n)-f[force overwriting existing file]'
+    '(-f -n)-i[confirm before overwriting existing file]'
+    '-p[preserve timestamps, mode, owner, flags, ACLs, and extended attributes]'
     '-R[copy directories recursively]' \
-    '(-L -P)-H[with -R, follow symlinks on the command line]' \
-    '(-H -P)-L[with -R, follow all symlinks]' \
-    '(-H -L)-P[do not follow symlinks]' \
-    '(-i)-f[force overwriting existing file]' \
-    '(-f)-i[confirm before overwriting existing file]' \
-    '-p[preserve timestamps, mode, and owner]' \
     '(-)*:file or directory:_files'
+  )
+  for pattern arg in \
+    '(aix|hpux|irix|solaris)*' '-r[copy directories recursively]' \
+    'solaris2.<9->*' '-@[preserve extended attributes]' \
+    'solaris2.<11->*' '-/[preserve extended attributes and extended system attributes]' \
+    '(darwin|dragonfly|freebsd)*' "(-f -i)-n[don't overwrite existing file]" \
+    'netbsd*' "-N[don't copy file flags]" \
+    '(darwin|dragonfly|freebsd|netbsd)*' '-a[archive mode, same as -RpP]' \
+    '(dragonfly|freebsd)*' '-l[link files instead of copying]' \
+    '(darwin|dragonfly|freebsd|netbsd)*' '-v[show file names as they are copied]' \
+    'darwin*' "-X[don't copy extended attributes or resource forks]" \
+    '(dragonfly|freebsd)*' "-x[don't traverse file systems]"
+  do
+    [[ $OSTYPE = $~pattern ]] && args+=( $arg )
+  done
+  _arguments -s -S $args
 fi
diff --git a/Completion/Unix/Command/_cut b/Completion/Unix/Command/_cut
index 1024c20..caf8f32 100644
--- a/Completion/Unix/Command/_cut
+++ b/Completion/Unix/Command/_cut
@@ -2,44 +2,41 @@
 
 typeset -A _cut_args
 
-if _pick_variant gnu="Free Soft" unix --version; then
-  case $LANG in
-    (de_DE.UTF-8)
-      _cut_args=(
-	bytes           "nur diese Bytes ausgeben"
-	characters      "nur diese Zeichen ausgeben"
-	delimiter       "Delimiter anstelle von Tabulator als Trenner benutzen"
-	fields          "nur diese Felder und alle Zeilen OHNE Trennzeichen ausgeben"
-	n               "(ignoriert)"
-	complement      $'das Komplement der Menge der gew\u00e4hlten Bytes, Zeichen oder Felder bilden'
-	only-delimited  "keine Zeilen ausgeben, die keinen Trenner enthalten"
-	output-delimiter "Zeichenkette als Ausgabetrennzeichen benutzen"
-	help            "diese Hilfe anzeigen und beenden"
-	version         "Versionsinformation anzeigen und beenden"
-      )
-    ;;
-    (*)
-      _cut_args=(
-	bytes           "select only these bytes"
-	characters      "select only these characters"
-	delimiter       "use DELIM instead of TAB for field delimiter"
-	fields          "select only these fields and lines without the delimiter character"
-	n               "(ignored)"
-	complement      "complement the set of selected bytes, characters or fields"
-	only-delimited  "do not print lines not containing delimiters"
-	output-delimiter "use STRING as the output delimiter"
-	help            "display this help and exit"
-	version         "output version information and exit"
-      )
-    ;;
-  esac
+case $LANG in
+  (de_DE.UTF-8)
+    _cut_args=(
+      bytes           "nur diese Bytes ausgeben"
+      characters      "nur diese Zeichen ausgeben"
+      delimiter       "Delimiter anstelle von Tabulator als Trenner benutzen"
+      fields          "nur diese Felder und alle Zeilen OHNE Trennzeichen ausgeben"
+      complement      $'das Komplement der Menge der gew\u00e4hlten Bytes, Zeichen oder Felder bilden'
+      only-delimited  "keine Zeilen ausgeben, die keinen Trenner enthalten"
+      output-delimiter "Zeichenkette als Ausgabetrennzeichen benutzen"
+      help            "diese Hilfe anzeigen und beenden"
+      version         "Versionsinformation anzeigen und beenden"
+    )
+  ;;
+  (*)
+    _cut_args=(
+      bytes           "select only specified bytes"
+      characters      "select only specified characters"
+      delimiter       "use alternate field delimiter"
+      fields          "select only specified fields"
+      complement      "negate the set of selected bytes, characters or fields"
+      only-delimited  "suppress lines with no delimiters"
+      output-delimiter "use specified string as the output delimiter"
+      help            "display help information"
+      version         "output version information"
+    )
+  ;;
+esac
 
+if _pick_variant gnu="Free Soft" unix --version; then
   _arguments \
     '(--bytes -b)'{--bytes=,-b+}'['$_cut_args[bytes]']:list' \
     '(--characters -c)'{--characters=,-c+}'['$_cut_args[characters]']:list' \
     '(--delimiter -d)'{--delimiter=,-d+}'['$_cut_args[delimiter]']:delimiter' \
     '(--fields -f)'{--fields=,-f+}'['$_cut_args[fields]']:list' \
-    '-n['$_cut_args[n]']' \
     '--complement['$_cut_args[complement]']' \
     '(--only-delimited -s)'{--only-delimited,-s}'['$_cut_args[only-delimited]']' \
     '--output-delimiter=['$_cut_args[output-delimiter]']:delimiter' \
@@ -47,12 +44,15 @@ if _pick_variant gnu="Free Soft" unix --version; then
     '(- *)--version['$_cut_args[version]']' \
     '*:file:_files'
 else
-  _arguments \
-    '-b[list specifies byte positions]:list:' \
-    '-c[list specifies character positions]:list:' \
-    '-d[use alternate delimiter]:delimiter' \
-    '-f[list specifies fields]:list:' \
-    '-n[do not split multi-byte characters]' \
-    '-s[suppress lines with no delimiters]' \
+  case $OSTYPE in
+    freebsd*|dragonfly*) args+=( '(-d)-w[use whitespace as the delimiter]' ) ;;
+  esac
+  _arguments $args \
+    "-b[${_cut_args[bytes]}]:list" \
+    "-c[${_cut_args[characters]}]:list" \
+    "(-w)-d[${_cut_args[delimiter]}]:delimiter" \
+    "-f[${_cut_args[fields]}]:list" \
+    "-n[do not split multi-byte characters]" \
+    "-s[${_cut_args[only-delimited]}]" \
     '*:file:_files'
 fi
diff --git a/Completion/Unix/Command/_date b/Completion/Unix/Command/_date
index 7b1d3a7..e596ac0 100644
--- a/Completion/Unix/Command/_date
+++ b/Completion/Unix/Command/_date
@@ -1,4 +1,4 @@
-#compdef date
+#compdef date gdate
 
 local -a args
 
@@ -8,7 +8,7 @@ if _pick_variant gnu="Free Software Foundation" unix --version; then
     '-f[output dates specified in file]:file:_files'
     '-I-[iso-8601]:precision:(date hours minutes seconds)'
     '-r[reference]:file:_files'
-    '-R[rfc-2822]'
+    '-R[RFC2822 format]'
     '-s[set]:time string'
     '--rfc-3339=-[output date and time in RFC 3339 format]:output type:(date seconds ns)'
     --
@@ -20,26 +20,23 @@ else
     solaris*)
       args=( '-a:adjustment' )
     ;;
-    freebsd*|darwin*)
+    freebsd*|darwin*|dragonfly*|netbsd*|openbsd*)
       args=(
 	'-n[only set time on current machine]'
 	'-d:daylight saving time value'
 	'-j[do not try to set date]'
-	'-f:parsing format'
 	'-r:seconds since epoch'
 	'-t:minutes west of GMT'
-	'-v:adjustment value'
       )
+    ;|
+    freebsd*) args+=( '-R[RFC2822 format]' ) ;|
+    freebsd*|dragonfly*|darwin*)
+      args+=( '-f:parsing format' '-v:adjustment value' )
     ;;
     openbsd*)
-      args=(
-	'-n[only set time on current machine]'
-	'-d:daylight saving time value'
-	'-a[gradually skew]'
-	'-r:seconds since epoch'
-	'-t:minutes west of GMT'
-      )
-    ;;
+      args+=( '-z[specify timezone for output]:time zone:_time_zone')
+    ;|
+    openbsd*|netbsd*) args=( '-a[gradually skew]' ) ;;
   esac
 fi
 
diff --git a/Completion/Unix/Command/_du b/Completion/Unix/Command/_du
index 8b053ba..d8871cd 100644
--- a/Completion/Unix/Command/_du
+++ b/Completion/Unix/Command/_du
@@ -1,4 +1,4 @@
-#compdef du
+#compdef du gdu
 
 if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then
   local context state line expl ret=1
@@ -18,7 +18,7 @@ if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then
     '(-l --count-links)'{-l,--count-links}'[count sizes many times if hard linked]' \
     '(-L --dereference -H -D --dereference-args -P --no-dereference)'{-L,--dereference}'[dereference all symlinks]' \
     '(-S --separate-dirs)'{-S,--separate-dirs}'[do not include size of subdirectories]' \
-    '(-s --summarize --max-depth -a --all)'{-s,--summarize}'[only display total for each argument]' \
+    '(-s --summarize --max-depth -a --all)'{-s,--summarize}'[only report total for each argument]' \
     '(-x --one-file-system)'{-x,--one-file-system}'[skip directories on different filesystems]' \
     '(-0 --null)'{-0,--null}'[end each output line with NUL instead of newline]' \
     \*{-X+,--exclude-from=}'[exclude files matching any pattern in file]:file:_files' \
@@ -26,17 +26,13 @@ if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then
     '(-s --summarize)--max-depth=[maximum levels to recurse]:levels' \
     '--files0-from=[use NUL-terminated list of files from file]:file:_files' \
     '--time-style=[show times using given style, +FORMAT for strftime formatted args]:style:->timestyle' \
-    '--time=-[show time of last modification of any file in the directory]:property:->time' \
+    '--time=-[show time of last modification of any file in the directory]:property:(atime access use ctime status)' \
+    '(-t --threshold)'{-t+,--threshold=}'[report only entries for which size exceeds threshold]:threshold' \
     '(* -)--help[display help information]' \
     '(* -)--version[display version information]' \
     '*:file:_files' && ret=0
 
   case $state in
-    (time)
-      local -a property
-      property=(atime access use ctime status)
-      _wanted -C $context property expl property compadd -a property && ret=0
-    ;;
     (timestyle)
       local -a style desc
       style=(full-iso long-iso iso +)
@@ -47,39 +43,36 @@ if _pick_variant gnu=Free\ Soft unix --version /dummy/no-such-file; then
 
   return ret
 
-elif [[ "$OSTYPE" == darwin* ]]; then
-  _arguments -s -A "-*" \
-    '(-H -L -P)-H[follow symlinks on the command line]' \
-    '(-H -L -P)-L[follow all symlinks]' \
-    '(-H -L -P)-P[do not follow symlinks (default)]' \
-    '*-I+[ignore files/directories matching specified mask]:mask' \
-    '(-a -s -d)-a[display entry also for files (not just directories) in file hierarchy]' \
-    '(-a -s -d)-d+[display entry for directories up to specified depth]:depth' \
-    '(-a -s -d)-s[display entry only for files/directories specified on the command line]' \
-    '(-h -k -m -g)-h[human readable output]' \
-    '(-h -k -m -g)-k[use block size of 1K-byte]' \
-    '(-h -k -m -g)-m[use block size of 1M-byte]' \
-    '(-h -k -m -g)-g[use block size of 1G-byte]' \
-    '-c[display grand total]' \
-    '-r[notify about unreadable files/directories]' \
-    '-x[exclude directories on different file systems]' \
-    '*:file:_files'
-
 else
-  # based on $OSTYPE = solaris2.8
+  local pattern arg args
+  args=(
+    '(-a -s -d)-a[report sizes for all files, not just directories]'
+    '(-H -L -P)-L[follow all symlinks]'
+    '(-a -s -d)-s[only report total for each argument]'
+    '(-h -m -g -B)-k[use block size of 1K-byte]'
+    '-r[notify about unreadable files/directories]'
+  )
   local xdev='[skip directories on different filesystems]'
-  if [[ ${commands[$words[1]]:-$words[1]} = *xpg4* ]]; then
-    args=( -x$xdev )
-  else
-    args=( -d$xdev
-      '-L[dereference symlinks]'
-      "(-a)-o[do not add child directories' usage to parent's total]"
-    )
-  fi
-  _arguments -s "$args[@]" \
-    '(-s -o)-a[write counts for all files]' \
-    '-k[use block size of 1k]' \
-    '-r[notify about unreadable files/directories]' \
-    '(-a)-s[only display total for each argument]' \
-    '*:file:_files'
+  for pattern arg in \
+    'freebsd*' '-A[apparent size instead of usage]' \
+    '(darwin*|*bsd*|dragonfly*|solaris2.<10->)' '(-H -L -P)-H[follow symlinks on the command line]' \
+    '(darwin|*bsd|dragonfly)*' '(-H -L -P)-P[do not follow symlinks (default)]' \
+    '(darwin|dragonfly|freebsd)*' '*-I+[ignore files/directories matching specified mask]:mask' \
+    '(darwin|*bsd|dragonfly)*' '(-a -s -d)-d+[display entry for directories up to specified depth]:depth' \
+    '(darwin*|*bsd*|dragonfly*|solaris2.<10->)' '(-k -m -g -B)-h[human readable output]' \
+    'netbsd*' '-i[output inode usage instead of blocks]' \
+    '(darwin*|freebsd*|netbsd*|solaris2.<11->)' '(-h -k -g -B)-m[use block size of 1M-byte]' \
+    '(darwin|freebsd<8->.|netbsd)*' '(-h -k -m -B)-g[use block size of 1G-byte]' \
+    'freebsd*' '(-h -k -m -g)-B[block size]:block size (bytes)' \
+    '(darwin|*bsd|dragonfly)*' '-c[display grand total]' \
+    'freebsd*' '-l[count sizes many times if hard linked]' \
+    '(freebsd|netbsd)*' '-n[ignore files and directories with nodump flag set]' \
+    'solaris*' "(-a)-o[don't add child directories' usage to parent's total]" \
+    'freebsd<8->.*' '-t+[report only entries for which size exceeds threshold]:threshold' \
+    'solaris*' "-d$xdev" \
+    '(darwin|*bsd|dragonfly|solaris)*' "-x$xdev"
+  do
+    [[ $OSTYPE = $~pattern ]] && args+=( $arg )
+  done
+  _arguments -s -A "-*" $args
 fi
diff --git a/Completion/Unix/Command/_elfdump b/Completion/Unix/Command/_elfdump
new file mode 100644
index 0000000..ee92402
--- /dev/null
+++ b/Completion/Unix/Command/_elfdump
@@ -0,0 +1,47 @@
+#compdef elfdump
+
+local -a args
+
+_elf_file() {
+  [[ -x $REPLY || $REPLY = (core*|*.([ao]|so|elf)) ]]
+}
+
+args=(
+  '-c[dump section header information]'
+  '-d[dump .dynamic section]'
+  '-e[dump file header]'
+  '-G[dump .got (global offset table) section]'
+  '-h[dump .hash section]'
+  '-i[dump .interp (interpreter) section]'
+  '-n[dump .note sections]'
+  '(-w)-p[dump program headers]'
+  '-r[dump relocation sections]'
+  '-s[dump symbol table sections]'
+  '(-p)-w[write contents of matched sections to file]:file:_files'
+)
+
+case $OSTYPE in
+  solaris*)
+    args+=(
+      '-g[dump .group section]'
+      '-H[dump .SUNW_cap (capabilities) section]'
+      '-m[dump .SUNW_move section]'
+      '-S[dump symbol table sections sorted according to symbol sort sections]'
+      '-u[dump stack unwind/exceptions sections]'
+      '-v[dump .SUNW_version (versioning) sections]'
+      '-y[dump .SUNW_syminfo (symbol bindings) section]'
+      '-I[match sections by index]:index or range'
+      "-N[match sections by name]:section"
+      '-T[match sections by type]:type'
+      '-C[demangle C++ symbol names]'
+      '-k[calculate ELF checksum]'
+      '-l[show long section names without truncation]'
+      '-O[specify osabi to apply]:osabi'
+      '-P[use alternative section header]'
+      "*:elf file:_files -g '*(-.e:_elf_file:)'"
+    )
+  ;;
+  freebsd*) args+=( '-a[dump all information]' ) ;;
+esac
+
+_arguments -s $args
diff --git a/Completion/Unix/Command/_find b/Completion/Unix/Command/_find
index 33767c0..8f80e36 100644
--- a/Completion/Unix/Command/_find
+++ b/Completion/Unix/Command/_find
@@ -1,82 +1,145 @@
-#compdef find
+#compdef find gfind
 
-_arguments \
-  '(- *)-help' '(-)--help' \
-  '(- *)-version' '(-)--version' \
+local variant args
+
+_pick_variant -r variant gnu=GNU $OSTYPE -version
+
+case $variant in
+  solaris*)
+    args+=(
+      '*-'{n,}'cpio:device:_files'
+      '*-local'
+    )
+  ;|
+  solaris*|darwin*)
+    args+=( '*-xattr' )
+  ;|
+  solaris2.<10->|freebsd*|darwin*)
+    args+=( '*-acl' )
+  ;|
+  solaris2.<11->|freebsd*|dragonfly*|darwin*|openbsd*|gnu)
+    args+=(
+      '*-amin:access time (minutes)'
+      '*-cmin:inode change time (minutes)'
+      '*-mmin:modification time (minutes)'
+      '*-iname:name pattern to match (case insensitive)'
+      '*-print0'
+    )
+  ;|
+  netbsd*|freebsd*|dragonfly*|darwin*|gnu)
+    args+=( '(-H -L)-P[never follow symlinks]' )
+  ;|
+  netbsd*|freebsd*|dragonfly*|openbsd*|darwin*|gnu)
+    args+=( '-d[depth first traversal]' )
+  ;|
+  darwin*|freebsd*|gnu)
+    args+=(
+      '*-Bmin:birth time (minutes)'
+      '*-Bnewer:file to compare (birth time):_files'
+      '*-Btime:birth time (hours)'
+    )
+  ;|
+  freebsd*|dragonfly*|darwin*|openbsd*|gnu)
+    args+=(
+      '*-anewer:file to compare (access time):_files'
+      '*-cnewer:file to compare (inode change time):_files'
+      '*-mnewer:file to compare (modification time):_files'
+      '*-maxdepth:maximum search depth'
+      '*-mindepth:minimum search depth'
+      '*-path:path pattern to search:'
+    )
+  ;|
+  freebsd*|dragonfly*|darwin*|gnu)
+    args+=(
+      '*-delete'
+      '*-empty'
+      '*-execdir:program: _command_names -e:*\;::program arguments: _normal'
+      '*-gid:numeric group ID'
+      '*-uid:numeric user ID'
+      '*-noleaf'
+      '*-lname:link pattern to search'
+      '*-ilname:link pattern to search (case insensitive)'
+      '*-ipath:path pattern to search (case insensitive)'
+      '*-regex:regular expression to search'
+      '*-iregex:regular expression to search (case insensitive)'
+      '*-wholename:full path pattern to search' \
+      '*-iwholename:full path pattern to search (case insensitive)'
+      '*-ignore_readdir_race'
+      '*-noignore_readdir_race'
+      '*-okdir:program: _command_names -e:*\;::program arguments: _normal'
+      '*-samefile:file to compare inode:_files' \
+      '*-true'
+      '*-false'
+      '*-and'
+      '*-or'
+      '*-not'
+    )
+  ;|
+  freebsd*|dragonfly*|gnu) args+=( '*-quit' ) ;|
+  netbsd*|freebsd*|dragonfly*|darwin*)
+    args+=(
+      '-E[use extended regular expressions with -regex/-iregex]'
+      '-X[warn if filename contains characters special to xargs]'
+      '-f[specify file hierarchy to traverse]:path:_directories'
+      '-s[traverse directories in sorted order]'
+      "-x[don't span filesystems]"
+      '*-flags:flags:_chflags'
+    )
+  ;|
+  freebsd*|dragonfly*) args+=( '*-sparse' ) ;|
+  darwin*) args+=( '*-xattrname:name' ) ;|
+  gnu)
+    args+=(
+      '(- *)-help' '(-)--help'
+      '(- *)-version' '(-)--version'
+      '-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)'
+      '*-warn'
+      '*-nowarn'
+      '*-xautofs'
+      '*-used:access after inode change (days)'
+      '*-executable'
+      '*-readable'
+      '*-writable'
+      '*-xtype:file type:((b\:block\ special\ file c\:character\ special\ file d\:directory p\:named\ pipe f\:normal\ file l\:symbolic\ link s\:socket))'
+      '*-fls:output file:_files'
+      '*-fprint:output file:_files'
+      '*-fprint0:output file:_files'
+      '*-fprintf:output file:_files:output format'
+      '*-printf:output format'
+    )
+    [[ $OSTYPE = linux-gnu ]] && args+=( '*-context:SELinux context' )
+  ;;
+esac
+
+_arguments $args \
   '(-L -P)-H[only follow symlinks when resolving command-line arguments]' \
   '(-H -P)-L[follow symlinks]' \
-  '(-H -L)-P[never follow symlinks]' \
-  '-D[print diagnostics]:deb option:(help tree search stat rates opt exec)' \
-  '-O+[enable query optimisation]:level:(1 2 3)' \
-  '*-daystart' \
-  '*-d' '*-depth' \
+  '*-atime:access time (days)' \
+  '*-ctime:inode change time (days)' \
+  '*-depth' \
+  '*-exec:program: _command_names -e:*\;::program arguments: _normal' \
   '*-follow' \
-  '(-noignore_readdir_race)-ignore_readdir_race' \
-  '*-maxdepth:maximum search depth' \
-  '*-mindepth:minimum search depth' \
-  '*-mount' \
-  '(-ignore_readdir_race)-noignore_readdir_race' \
-  '*-noleaf' \
-  '-regextype:regexp syntax:(emacs posix-awk posix-basic posix-egrep posix-extended)' \
-  '*-warn' \
-  '*-nowarn' \
-  '*-xdev' \
-  '*-amin:access time (minutes):' \
-  '*-cmin:inode change time (minutes):' \
-  '*-mmin:modification time (minutes):' \
-  '*-atime:access time (days):' \
-  '*-ctime:inode change time (days):' \
-  '*-mtime:modification time (days):' \
-  '*-anewer:file to compare (access time):_files' \
-  '*-cnewer:file to compare (inode change time):_files' \
-  '*-newer:file to compare (modification time):_files' \
-  '*-used:access after inode change (days):' \
-  '*-empty' \
-  '*-executable' \
-  '*-false' \
   '*-fstype:file system type:_file_systems' \
-  '*-gid:numeric group ID:' \
   '*-group:group:_groups' \
-  '*-uid:numeric user ID:' \
-  '*-user:user:_users' \
-  '*-lname:link pattern to search:' \
-  '*-ilname:link pattern to search (case insensitive):' \
-  '*-name:name pattern to search:' \
-  '*-iname:name pattern to search (case insensitive):' \
-  '*-path:path pattern to search:' \
-  '*-ipath:path pattern to search (case insensitive):' \
-  '*-regex:regular expression to search:' \
-  '*-iregex:regular expression to search (case insensitive):' \
-  '*-wholename:full path pattern to search:' \
-  '*-iwholename:full path pattern to search (case insensitive):' \
   '*-inum:inode number:' \
   '*-links:number of links:' \
-  '*-nouser' \
+  '*-ls' \
+  '*-mount' \
+  '*-mtime:modification time (days)' \
+  '*-name:name pattern' \
+  '*-newer:file to compare (modification time):_files' \
   '*-nogroup' \
-  '*-perm:file permission bits:' \
-  '*-readable' \
-  '*-writable' \
-  '*-size:file size:' \
-  '*-samefile:same inode as:_files' \
-  '*-true' \
-  '*-type:file type:((b\:block\ special\ file c\:character\ special\ file d\:directory p\:named\ pipe f\:normal\ file l\:symbolic\ link s\:socket))' \
-  '*-xtype:file type:((b\:block\ special\ file c\:character\ special\ file d\:directory p\:named\ pipe f\:normal\ file l\:symbolic\ link s\:socket))' \
-  '*-delete' \
-  '*-exec:program: _command_names -e:*\;::program arguments: _normal' \
-  '*-execdir:program: _command_names -e:*\;::program arguments: _normal' \
+  '*-nouser' \
   '*-ok:program: _command_names -e:*\;::program arguments: _normal' \
-  '*-okdir:program: _command_names -e:*\;::program arguments: _normal' \
-  '*-fls:output file:_files' \
-  '*-fprint:output file:_files' \
-  '*-fprint0:output file:_files' \
-  '*-fprintf:output file:_files:output format:' \
+  '*-perm:file permission bits' \
   '*-print' \
-  '*-print0' \
-  '*-printf:output format:' \
   '*-prune' \
-  '*-quit' \
-  '*-ls' \
-  '*-and' '*-a' \
-  '*-or' '*-o' \
-  '*-not' \
+  '*-size:file size (blocks)' \
+  '*-type:file type:((b\:block\ special\ file c\:character\ special\ file d\:directory p\:named\ pipe f\:normal\ file l\:symbolic\ link s\:socket))' \
+  '*-user:user:_users' \
+  '*-xdev' \
+  '*-a' '*-o' \
   '*:directory:_files -/'
diff --git a/Completion/Unix/Command/_fuser b/Completion/Unix/Command/_fuser
index ba0f301..f497729 100644
--- a/Completion/Unix/Command/_fuser
+++ b/Completion/Unix/Command/_fuser
@@ -1,10 +1,18 @@
 #compdef fuser
 
-local -a args arg1
+local -a args argf variant
 typeset -A opt_args
 
-if _pick_variant -c $words[1] psmisc='(#i)psmisc' unix -V; then
+args=(
+  '-u[append the user name of the process owner to each PID]'
+  '(-f)-c[list all processes accessing files on the filesystem specified by name]'
+  '(-c)-f[list all processes accessing named files]'
+)
+argf=( '*:file:_files' )
 
+_pick_variant -r variant psmisc='(#i)psmisc' $OSTYPE -V
+case $variant in
+  psmisc)
   (( $+functions[_fuser_services] )) ||
   _fuser_services() {
     local expl suf ret=1
@@ -23,45 +31,51 @@ if _pick_variant -c $words[1] psmisc='(#i)psmisc' unix -V; then
       compset -S ',*' || suf=( -S ${${opt_args[-n]/?*/,}:-/} -r "/, \t\n\-" )
       _ports $suf && ret=0
     fi
-      
+
     return ret
   }
 
-  _arguments \
-    '(-s)-a[show all files specified on the command line]' \
-    {-c,-m}'[list all processes accessing files on the filesystem specified by name]' \
-    '-k[kill processes accessing the file]' \
-    '-i[ask for confirmation before killing]' \
-    '-l[list all known signal names]' \
-    '-n[select name space]:namespace:(file udp tcp)' \
-    '(-a)-s[silent operation]' \
-    '-signal[send alternate signal with -k]:signal:_signals' \
-    '-u[append the user name of the process owner to each PID]' \
-    '-v[verbose mode]' \
-    '-V[display version information]' \
-    '-4[search only for IPv4 sockets]' \
-    '-6[search only for IPv6 sockets]' \
-    '*:name: _alternative "files:file:_files" "services:service:_fuser_services"'
-
-else
-  case $OSTYPE in
-    solaris2.9 )
-      args=(
-	'-n[list only processes with non-blocking mandatory locks]' 
-	'-s[send alternate signal with -k]:signal:_signals' 
-      )
-    ;;
-    sysv4 )
-      (( $+words[(r)-k] )) && arg1=( ':name: _alternative signals\:signal\:_signals\ -p files:file:_files' )
-    ;;
-  esac
+    args+=(
+      '(-s)-a[show all files specified on the command line]' \
+      {-c,-m}'[list all processes accessing files on the filesystem specified by name]' \
+      '-k[kill processes accessing the file]' \
+      '-i[ask for confirmation before killing]' \
+      '(-)-l[list all known signal names]' \
+      '-n[select name space]:namespace:(file udp tcp)' \
+      '(-a -u -v)-s[silent operation]' \
+      '-v[verbose mode]' \
+      '-V[display version information]' \
+      '-4[search only for IPv4 sockets]' \
+      '-6[search only for IPv6 sockets]' \
+    )
+    argf=( '*:name: _alternative "files:file:_files" "services:service:_fuser_services"' )
+    [[ -prefix -  && -z ${${words[1,CURRENT-1]}[(r)-[A-Z][A-Z]*]} ]] &&
+        argf[1]+=' "signal:signals:_signals -P-"'
+  ;;
+  freebsd*|openbsd*|solaris2.<9->)
+    args+=(
+      '-s[send alternate signal]:signal:_signals'
+      '-k[send SIGKILL to each process]'
+    )
+  ;|
+  openbsd*|freebsd*)
+    args+=(
+      '-M[extra values from specified core file]:core file:_files'
+      '-N[extract name list from specified system]:system'
+    )
+  ;|
+  freebsd*) args+=( '-m[include mapped files]' ) ;;
+  solaris2.<9->)
+    args+=(
+      '-n[list only processes with non-blocking mandatory locks]'
+    )
+  ;;
+  solaris2.<10->)
+    args+=( '-d[report device usage for all minor nodes bound to same device]' )
+  ;;
+  sysv4 )
+    (( $+words[(r)-k] )) && argf=( ':name: _alternative signals\:signal\:_signals\ -p files:file:_files' )
+  ;;
+esac
 
-  _arguments \
-    '(-f)-c[list all processes accessing files on the filesystem specified by name]' \
-    '(-c)-f[list all processes accessing named files]' \
-    '-k[kill processes accessing the file]' \
-    '-u[append the user name of the process owner to each PID]' \
-    $args \
-    $arg1 \
-    '*:file:_files'
-fi
+_arguments -s $args $argf
diff --git a/Completion/Unix/Command/_gcore b/Completion/Unix/Command/_gcore
new file mode 100644
index 0000000..4933ffe
--- /dev/null
+++ b/Completion/Unix/Command/_gcore
@@ -0,0 +1,50 @@
+#compdef gcore
+
+case $OSTYPE in
+  solaris*)
+    local -a content
+
+    content=(
+      'anon[anonymous private mappings]'
+      'ctf[CTF type information]'
+      'data[writable private file mappings]'
+      'dism[DISM mappings]'
+      'heap[process heap]'
+      'ism[ISM mappings]'
+      'rodata[read-only private file mappings]'
+      'shanon[anonymous shared mappings]'
+      'shfile[file-backed shared mappings]'
+      'shm[System V shared memory]'
+      'stack[process stack]'
+      'symtab[symbol table sections for loaded files]'
+      'text[readable and executable private file mappings]'
+    )
+
+    _arguments -s \
+      '(-c -g)-p[use per-process core file repository]' \
+      '(-c -p)-g[use global core file repository]' \
+      '-F[force grabbing the target process]' \
+      '(-p -g)-c[set core file content]: :_values -s + "content" $content' \
+      '-o[set core file base name]:file base name:_files' \
+      '*:pid:_pids'
+  ;;
+  netbsd*)
+    _arguments \
+      '-c+[write core file to specified file]:file:_files' \
+      '*:pid:_pids'
+    ;;
+  freebsd*)
+    _arguments -s \
+      '-c+[write core file to specified file]:file:_files' \
+      '-f[dump all available segments]' \
+      '-s[stop process while gathering image]' \
+      '::executable:' \
+      ':pid:_pids'
+  ;;
+  *)
+    # GNU GDB gcore
+    _arguments \
+      '-o[set core file base name]:file base name:_files' \
+      ':pid:_pids'
+  ;;
+esac
diff --git a/Completion/Unix/Command/_grep b/Completion/Unix/Command/_grep
index 5068f6e..d987c2b 100644
--- a/Completion/Unix/Command/_grep
+++ b/Completion/Unix/Command/_grep
@@ -1,4 +1,4 @@
-#compdef grep egrep fgrep -value-,GREP_OPTIONS,-default-
+#compdef grep egrep fgrep bsdgrep zgrep, zegrep, zfgrep -value-,GREP_OPTIONS,-default-
 # Ulrik Haugen 2001
 
 local arguments matchers command
diff --git a/Completion/Unix/Command/_iconv b/Completion/Unix/Command/_iconv
index 4bf29d4..d040be7 100644
--- a/Completion/Unix/Command/_iconv
+++ b/Completion/Unix/Command/_iconv
@@ -1,8 +1,8 @@
 #compdef iconv
 
-local expl curcontext="$curcontext" state line ret=1
+local expl curcontext="$curcontext" state line variant ret=1
 
-if _pick_variant libiconv='GNU*libiconv' glibc='(GNU*libc|EGLIBC|Gentoo)' unix --version; then
+if _pick_variant -r variant libiconv='GNU*libiconv' glibc='(GNU*libc|EGLIBC|Gentoo)' unix --version; then
   local -a args
   local exargs="-l --list -? --help --usage --version -V"
 
@@ -13,22 +13,22 @@ if _pick_variant libiconv='GNU*libiconv' glibc='(GNU*libc|EGLIBC|Gentoo)' unix -
     "($exargs)-c[omit invalid characters from output]"
     "(-s --silent --verbose $exargs)"{-s,--silent}'[suppress warnings]'
     '(-)'{-\?,--help}'[display help information]'
-    '(-)--usage[display a short usage message]'
     '(-)'{-V,--version}'[print program version]'
     '1:input file:_files' 
   )
 
-  case $_cmd_variant[$service] in
+  case $variant in
     (libiconv)
       args=( ${(R)args:#(|\*)(|\(*\))-[V\?]*} )  # remove -V and -?
       args+=(
-       '--byte-subst=[format for unconvertible bytes]:format string:'
-       '--widechar-subst=[format for unconvertible wide chars]:format string:'
-       '--unicode-subst=[format for unconvertible Unicode chars]:format string:'
+        '--byte-subst=[format for unconvertible bytes]:format string'
+        '--widechar-subst=[format for unconvertible wide chars]:format string'
+        '--unicode-subst=[format for unconvertible Unicode chars]:format string'
       )
       ;;
     (glibc)
       args+=( 
+        '(-)--usage[display a short usage message]'
         "(-o --output $exargs)"{-o+,--output=}'[specify output file]:output file:_files'
         "(-s --silent $exargs)--verbose[print progress information]"
       )
@@ -44,7 +44,7 @@ if _pick_variant libiconv='GNU*libiconv' glibc='(GNU*libc|EGLIBC|Gentoo)' unix -
     else
       _wanted codesets expl 'code set' compadd "$@" \
         -M 'm:{a-zA-Z}={A-Za-z} r:|-=* r:|=*' \
-        ${$(_call_program codesets iconv --list)%//} && ret=0
+        ${$(_call_program codesets $words[1] --list)%//} && ret=0
     fi
   fi
 
@@ -55,12 +55,17 @@ else
   local -U codeset
 
   _arguments -C \
-    '-f[specify code set of input file]:code set:->codeset' \
-    '-t[specify code set for output]:code set:->codeset' \
+    '(-l)-f[specify code set of input file]:code set:->codeset' \
+    '(-l)-t[specify code set for output]:code set:->codeset' \
+    '(-l)-c[omit invalid characters from output]' \
+    '(-l)-s[suppress warnings]' \
+    '(- 1)-l[list all character code sets]' \
     '1:file:_files' && return 0
 
   if [[ $state = codeset ]]; then
-    if [[ -f /usr/lib/iconv/iconv_data ]]; then  # IRIX & Solaris
+    if [[ $OSTYPE = freebsd* ]]; then
+      codeset=( $(_call_program codesets $words[1] -l) )
+    elif [[ -f /usr/lib/iconv/iconv_data ]]; then  # IRIX & Solaris
       codeset=( ${${(f)"$(</usr/lib/iconv/iconv_data)"}%%[[:blank:]]*} )
       codeset+=( /usr/lib/iconv/*%*.so(Ne.'reply=( ${${REPLY:t}%%%*} ${${REPLY:r}#*%} )'.) )
     elif [[ -d $LOCPATH/iconv ]]; then  # OSF
@@ -70,7 +75,7 @@ else
       return 1
     fi
 
-    _wanted codesets expl 'code set' compadd "$@" -a codeset
+    _wanted codesets expl 'code set' compadd -a codeset
   fi
 
 fi
diff --git a/Completion/Unix/Command/_id b/Completion/Unix/Command/_id
index 36cdf4c..74fe6d9 100644
--- a/Completion/Unix/Command/_id
+++ b/Completion/Unix/Command/_id
@@ -1,13 +1,49 @@
-#compdef id
+#compdef id gid
 
-_arguments \
-  '-a[no-op]' \
-  '(-Z --context)'{-Z,--context}'[print only context]' \
-  '(-g --group)'{-g,--group}'[print only EGID]' \
-  '(-G --groups)'{-G,--groups}'[print all GIDs]' \
-  '(-n --name)'{-n,--name}'[print name instead of number]' \
-  '(-r --real)'{-r,--real}'[print real ID instead of effective]' \
-  '(-u --user)'{-u,--user}'[print only EUID]' \
-  '--help[display help]' \
-  '--version[display version]' \
-  ':user:_users'
+local args choices
+
+if _pick_variant gnu=GNU $OSTYPE --version; then
+  choices='--help --version -Z --context -g --group -G --groups -u --user'
+  _arguments \
+    "($choices)"{-Z,--context}'[print only security context]' \
+    "($choices)"{-g,--group}'[print only EGID]' \
+    "($choices -r --real)"{-G,--groups}'[print all GIDs]' \
+    '(-n --name --help --version)'{-n,--name}'[show name instead of number]' \
+    '(-r --real -g --groups --help --version)'{-r,--real}'[show real ID instead of effective]' \
+    "($choices)"{-u,--user}'[print only EUID]' \
+    '(-z --zero --help --version)'{-z,--zero}'[delimit entries with NUL characters]' \
+    '(- :)--help[display help information]' \
+    '(- :)--version[display version]' \
+    ':user:_users'
+else
+  choices="-A -a -c -G -g -M -p -P -u"
+  args=(
+    "($choices)-g[print only EGID]"
+    "($choices -r)-G[print all GIDs]"
+    "($choices)-u[print only EUID]"
+    '(-A -c -M -P)-n[show name instead of number]'
+    '(-A -c -M -P)-r[show real ID instead of effective]'
+  )
+  case $OSTYPE in
+    solaris*)
+      args+=(
+        '(-g -G -u -n -r)-a[show user name, user ID and all the groups]'
+	'(-g -G -u -n -r)-p[show project membership]'
+      )
+    ;;
+    darwin*|dragonfly*|freebsd*)
+      args+=( '(-)-P[print id in the form of a password file entry]' )
+    ;|
+    darwin*|freebsd*)
+      args+=(
+	'(-)-A[print process audit user ID]'
+	'(-)-M[print MAC label of the current process]'
+      )
+    ;|
+    freebsd*) args+=( '(-)-c[print current login class]' ) ;|
+    darwin*|dragonfly*|freebsd*|netbsd*|openbsd*)
+      args+=( '(-)-p[human readable output]' )
+    ;;
+  esac
+  _arguments -s $args ':user:_users'
+fi
diff --git a/Completion/Unix/Command/_join b/Completion/Unix/Command/_join
index 956d9d3..4915a06 100644
--- a/Completion/Unix/Command/_join
+++ b/Completion/Unix/Command/_join
@@ -1,23 +1,29 @@
-#compdef join
+#compdef join gjoin
 
-# completions for GNU join version 5.97
-
-local arguments
-
-arguments=(
-    '-a+[print unpairable lines coming from file FILENUM, where FILENUM is 1 or 2, corresponding to FILE1 or FILE2]:file number:(1 2)'
-    '-e+[replace missing input fields with EMPTY]:replacement string:'
-    '(-i --ignore-case)'{-i,--ignore-case}'[ignore differences in case when comparing fields]'
-    "-j+[equivalent to '-1 FIELD -2 FIELD']:field number:"
-    '-o+[obey FORMAT while constructing output line]:format string:'
-    '-t+[use CHAR as input and output field separator]:separator:'
-    '-v+[like -a FILENUM, but suppress joined output lines]:file number:(1 2)'
-    '-1+[join on this FIELD of file 1]:field number:'
-    '-2+[join on this FIELD of file 2]:field number:'
-    --help'[display help and exit]'
-    --version'[output version information and exit]'
-    '1:file 1:_files'
-    '2:file 2:_files'
+local args variant
+args=(
+  '*-a+[print unpairable lines from specified file]:file number:(1 2)'
+  '-e+[replace missing input fields with specified string]:replacement string'
+  "(-1 -2)-j+[join on specified field for both files]:field number"
+  '-o+[use specified output format]:format string'
+  '-t+[use specified character as field separator]:separator'
+  '*-v+[like -a, but suppress joined output lines]:file number:(1 2)'
+  '(-j -1 -j1)'{-j1,-1+}'[join on specified field of first file]:field number'
+  '(-j -2 -j2)'{-j2,-2+}'[join on specified field of second file]:field number'
+  '1:file:_files' '2:file:_files'
+)
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+case $variant in
+  gnu)
+    args+=(
+      '(-i --ignore-case)'{-i,--ignore-case}'[ignore differences in case when comparing fields]'
+      '(-)--help[display help information]'
+      '(-)--version[output version information]'
+      '(--check-order --nocheck-order)'{--check-order,--nocheck-order}
+      '--header[treat first line in each file as field headers]'
+      '(-z --zero-terminated)'{-z,--zero-terminated}'[end lines with 0 byte, not newline]'
     )
+  ;;
+esac
 
-_arguments -s $arguments
+_arguments -s $args
diff --git a/Completion/Unix/Command/_last b/Completion/Unix/Command/_last
index 43a08a7..706d82f 100644
--- a/Completion/Unix/Command/_last
+++ b/Completion/Unix/Command/_last
@@ -1,17 +1,53 @@
 #compdef last lastb
 
-_arguments -s \
-  '-a[display hostname in last column]' \
-  '-n[number]:number' \
-  '-[number]:number' \
-  '-f[filename]:filename:_files' \
-  '-R[suppress display of hostname field]' \
-  '-d[translate IP to hostname]' \
-  '-i[display IP]' \
-  '-o[read old-format wtmp]' \
-  '-x[display shutdown/runlevel entries]' \
-  '-h[hostname]:host:_hosts' \
-  '-s[report duration in seconds]' \
-  '-t[tty]:tty' \
-  '-w[widen duration field]' \
-  '*:user:_users'
+local pattern arg args ttys
+ttys=( /dev/tty*(N) /dev/pts/*(N) reboot )
+ttys=( ${ttys#/dev/} )
+
+for pattern arg in \
+  '(solaris*|linux-gnu)' '-a[display hostname in last column]' \
+  '((free|net|open)bsd*|darwin*|dragonfly*|linux-gnu)' '-h[limit sessions by hostname]:host:_hosts' \
+  '((free|open)bsd*|linux-gnu)' '-s[report duration in seconds]' \
+  '(freebsd*|openbsd*)' '-d[limit sessions to those active at snapshot time]:time ([[CC]YY][MMDD]hhmm[.SS])' \
+  '((net|free|open)bsd*|darwin*|dragonfly*)' '-t[limit sessions by tty]:tty:compadd -a ttys' \
+  'openbsd*' '-c[calculate total time]' \
+  '^darwin*' '-f[specify account file]:file:_files' \
+  '(solaris*|linux-gnu|freebsd*|openbsd*)' '-n[specify number of lines to show]:number' \
+  '((open|net)bsd*|dragonfly*)' '-T[show more detailed time information including year and seconds]' \
+  'netbsd*' '-x[assume file is in wtmpx(5) format]' \
+  'netbsd*' '-n[show IP of remote hosts]' \
+  'freebsd*' '-w[show seconds in durarion field]' \
+  'freebsd*' '-y[show year in session start time]'
+do
+  [[ $OSTYPE = $~pattern ]] && args+=( $arg )
+done
+
+case $OSTYPE in
+  netbsd*|dragonfly*)
+    args+=(
+      '-H[specify width for host field]:width'
+      '-N[specify width for login name field]:width'
+      '-L[specify width for tty field]:width'
+    )
+  ;;
+  linux-gnu)
+    args+=(
+      '-R[suppress display of hostname field]'
+      '-d[translate IP to hostname]'
+      '-F[show full login and logout times and dates]'
+      '-i[show IP of remote hosts]'
+      '-o[read old-format wtmp]'
+      '-t[limit sessions to those active at snapshot time]:time (YYYYMMDDhhmmss)'
+      '-w[show full user and domain names]'
+      '-x[display shutdown/runlevel entries]'
+    )
+  ;;
+esac
+
+if [[ $OSTYPE = (linux-gnu|solaris*) ]]; then
+  args+=( '*:arg: _alternative "users:user:_users" "ttys:tty:compadd -a ttys"' )
+else
+  args+=( '*:user:_users' )
+fi
+
+_arguments -s $args
diff --git a/Completion/Unix/Command/_ldd b/Completion/Unix/Command/_ldd
index 381d127..19b8a91 100644
--- a/Completion/Unix/Command/_ldd
+++ b/Completion/Unix/Command/_ldd
@@ -1,6 +1,6 @@
 #compdef ldd
 
-if _pick_variant gnu='(GNU|EGLIBC|Gentoo)' solaris --version; then
+if _pick_variant gnu='(GNU|EGLIBC|Gentoo)' unix --version; then
   args=(
     '(- *)--version[display version information]'
     '(- *)--help[display help information]'
@@ -10,20 +10,31 @@ if _pick_variant gnu='(GNU|EGLIBC|Gentoo)' solaris --version; then
     '(-u --unused)'{-u,--unused}'[display any unused objects]'
   )
 else
-  args=(
-    -s
-    '(-r)-d[check immediate references]'
-    '(-d)-r[check immediate and lazy references]'
-    '-u[display any unused objects]'
-    '-U[display any unreferenced, or unused dependencies]'
-    '-e[set specified environment variable]:environment variable:(LD_PRELOAD LD_LIBRARY_PATH LD_RUN_PATH LD_DEBUG LD_DEBUG_OUTPUT LD_NOCONFIG LD_NOAUXFLTR)'
-    '-f[check for insecure executable]'
-    '-i[display order of execution of initialization sections]'
-    '-L[enable lazy loading]'
-    '-l[force immediate processing of any filters]'
-    '-s[display search path used]'
-    '-v[displays all dependency relationships]'
-  )
+  case $OSTYPE in
+    solaris*)
+      args=(
+	-s
+	'(-r)-d[check immediate references]'
+	'(-d)-r[check immediate and lazy references]'
+	'-u[display any unused objects]'
+	'-U[display any unreferenced, or unused dependencies]'
+	'-e[set specified environment variable]:environment variable:(LD_PRELOAD LD_LIBRARY_PATH LD_RUN_PATH LD_DEBUG LD_DEBUG_OUTPUT LD_NOCONFIG LD_NOAUXFLTR)'
+	'-f[check for insecure executable]'
+	'-i[display order of execution of initialization sections]'
+	'-L[enable lazy loading]'
+	'-l[force immediate processing of any filters]'
+	'-s[display search path used]'
+	'-v[displays all dependency relationships]'
+      )
+    ;;
+    freebsd*)
+      args=(
+        '-a[show all objects that are needed by each loaded object]'
+	'-v[verbose listing of the dynamic linking headers]'
+	'-f+[specify format]:format:((%a\:program\ name %A\:environment\ name %o\:library\ name %p\:path\ to\ library %x\:load\ address))'
+      )
+    ;;
+  esac
 fi
 
 _arguments $args \
diff --git a/Completion/Unix/Command/_ls b/Completion/Unix/Command/_ls
index 7680f92..f2e1494 100644
--- a/Completion/Unix/Command/_ls
+++ b/Completion/Unix/Command/_ls
@@ -1,11 +1,8 @@
 #compdef ls gls
-# Ulrik Haugen 2001
 
 local arguments is_gnu
 
-_pick_variant -r is_gnu gnu=gnu unix --help
-
-if [[ "$OSTYPE" = (netbsd*|freebsd*|openbsd*|darwin*) && "$is_gnu" != gnu ]]; then
+if ! _pick_variant gnu=gnu unix --help; then
   arguments=(
     '(-A)-a[list entries starting with .]'
     '(-a)-A[list all except . and ..]'
@@ -14,10 +11,8 @@ if [[ "$OSTYPE" = (netbsd*|freebsd*|openbsd*|darwin*) && "$is_gnu" != gnu ]]; th
     '-R[list subdirectories recursively]'
 
     '(-k)-h[print sizes in human readable form]'
-    '(-h)-k[print sizes of 1k]'
 
     '-i[print file inode numbers]'
-
     '(-l -g -1 -C -m -x)-l[long listing]'
     '(-l -1 -C -m -x)-g[long listing but without owner information]'
     '(-l -g -C -m -x)-1[single column output]'
@@ -25,35 +20,36 @@ if [[ "$OSTYPE" = (netbsd*|freebsd*|openbsd*|darwin*) && "$is_gnu" != gnu ]]; th
     '(-l -g -1 -C -x)-m[comma separated]'
     '(-l -g -1 -C -m)-x[sort horizontally]'
 
-    '-o[display file flags]'
-
     '-s[display size of each file in blocks]'
 
     '(-u)-c[status change time]'
     '(-c)-u[access time]'
 
-    '-f[unsorted, all, short list]'
     '-r[reverse sort order]'
 
-    '(-t)-S[sort by size]'
     '(-S)-t[sort by modification time]'
 
     '(-p)-F[append file type indicators]'
     '(-F)-p[append file type indicators for directory]'
 
-    '-f[output is not sorted]'
-
     '-n[numeric uid, gid]'
 
-    '-T[show complete time information]'
-
-    '(-B -b -w -q)-B[print octal escapes for control characters]'
     '(-B -b -w -q)-b[as -B, but use C escape codes whenever possible]'
     '(-B -b -w -q)-q[hide control chars]'
-    '(-B -b -w -q)-w[print raw characters]'
 
     '*:files:_files'
   )
+  if [[ "$OSTYPE" = (netbsd*|dragonfly*|freebsd*|openbsd*|darwin*) ]]; then
+    arguments+=(
+      '(-h)-k[print sizes of 1k]'
+      '(-t)-S[sort by size]'
+      '-T[show complete time information]'
+      '-o[display file flags]'
+      '-f[output is not sorted]'
+      '(-B -b -w -q)-w[print raw characters]'
+      '(-B -b -w -q)-B[print octal escapes for control characters]'
+    )
+  fi
   if [[ "$OSTYPE" = (freebsd*|darwin*) ]]; then
     arguments+=(
       '-G[enable colorized output]'
@@ -61,6 +57,18 @@ if [[ "$OSTYPE" = (netbsd*|freebsd*|openbsd*|darwin*) && "$is_gnu" != gnu ]]; th
       '-P[do not follow symlinks]'
     )
   fi
+  if [[ $OSTYPE = solaris* ]]; then
+    arguments+=(
+      '(-l -1 -C -m -x)-o[long listing but without group information]'
+      '(-l -t -s -r -a)-f[interpret each argument as a directory]'
+      '(-E -l)-e[long listing with full and consistent date/time]'
+      '(-e -l)-E[long listing with ISO format date/time]'
+      '-H[follow symlinks on the command line]'
+      '-v[long listing with verbose ACL information]'
+      '-V[long listing with compact ACL information]'
+      '-@[long listing with marker for extended attribute information]'
+    )
+  fi
 else
   arguments=(
     '(--all -a -A --almost-all)'{--all,-a}'[list entries starting with .]'
@@ -131,10 +139,6 @@ else
     '(- :)--version[display version information]'
     '*:files:_files'
   )
-  # remove long options?
-  if [[ $is_gnu != gnu ]]; then
-    arguments=( ${${${arguments:#(|*\))--*}//--[^ )]#/}/\( #\)/} )
-  fi
 fi
 
 _arguments -s $arguments
diff --git a/Completion/Unix/Command/_md5sum b/Completion/Unix/Command/_md5sum
index 2351d1a..c881a4e 100644
--- a/Completion/Unix/Command/_md5sum
+++ b/Completion/Unix/Command/_md5sum
@@ -1,10 +1,13 @@
-#compdef md5sum
+#compdef md5sum gmd5sum
 
 _arguments -S \
   '(-b --binary)'{-b,--binary}'[read in binary mode]' \
   '(-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]' \
+  '(-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]' \
diff --git a/Completion/Unix/Command/_mkdir b/Completion/Unix/Command/_mkdir
index 58d6c74..f2299f7 100644
--- a/Completion/Unix/Command/_mkdir
+++ b/Completion/Unix/Command/_mkdir
@@ -1,33 +1,23 @@
-#compdef mkdir
+#compdef mkdir gmkdir zf_mkdir
 
-local curcontext="$curcontext" line state \
-  args args_zsh args_cmd variant expl ret=1
-typeset -a opt_args
+local curcontext="$curcontext" state line expl args variant ret=1
+typeset -A opt_args
 
 args=(
   '(-m --mode)'{-m,--mode=}'[set permission mode]:numeric mode'
   '(-p --parents)'{-p,--parents}'[make parent directories as needed]'
-  )
-
-args_zsh=('(-)*: :->directories')
-
-args_cmd=(
-  '(-v --verbose)'{-v,--verbose}'[print message for each created directory]'
-  '(- :)--help[display help information]'
-  '(- :)--version[display version information]'
-  '*: :->directories'
-  )
+  '(-)*: :->directories'
+)
 
 case "$OSTYPE" in
   linux*)
-    args_cmd=(
+    args+=(
       '(-Z --context)'{-Z,--context=}'[set SELinux context]:SELinux context'
-      $args_cmd)
-    ;;
+    )
+  ;;
 esac
 
-_pick_variant -r variant gnu=gnu zsh='\(eval\)' unix --help
-
+_pick_variant -r variant gnu=gnu zsh='\(eval\)' $OSTYPE --help
 # It can still happen that there is a precommand command or builtin in the line.
 # In such cases, the variant has to be modified suitably, after further checking
 # the variant of the _command_ mkdir.
@@ -44,26 +34,34 @@ _pick_variant -r variant gnu=gnu zsh='\(eval\)' unix --help
 #   variant=zsh
 # fi
 
-if [[ $variant == zsh ]]; then
-  args+=($args_zsh)
-else
-  args+=($args_cmd)
-fi
-
-# remove long options?
-[[ $variant != gnu ]] && args=( ${${${args:#(|*\))--*}//--[^ )]#/}/\( #\)/} )
+case $variant in
+  gnu|freebsd*|dragonfly*)
+    args+=(
+      '(-v --verbose)'{-v,--verbose}'[print message for each created directory]'
+    )
+  ;|
+  gnu)
+    args+=(
+      '(- :)--help[display help information]'
+      '(- :)--version[display version information]'
+    )
+  ;;
+  zsh) # remove all options
+    args=( '*: :->directories' )
+  ;;
+  *) # non-GNU: remove long options
+    args=( ${${${args:#(|*\))--*}//--[^ )]#/}/\( #\)/} )
+  ;;
+esac
 
 _arguments -C -s $args && ret=0
 
 case "$state" in
   directories)
-    if (( $ret )) && [[ ! -prefix - ]] || \
-      [[ $variant == zsh && ${#${${words[2,-1]}:#-*}} -gt 0 ]]; then
-      _wanted directories expl \
-        'parent directory (alternatively specify name of directory)' \
-        _path_files -/ && ret=0
-    fi
-    ;;
+    _wanted directories expl \
+      'parent directory (alternatively specify name of directory)' \
+      _path_files -/ && ret=0
+  ;;
 esac
 
 return ret
diff --git a/Completion/Unix/Command/_nl b/Completion/Unix/Command/_nl
new file mode 100644
index 0000000..b3876dc
--- /dev/null
+++ b/Completion/Unix/Command/_nl
@@ -0,0 +1,40 @@
+#compdef nl gnl
+
+local curcontext="$curcontext" state line args ret=1
+
+args=(
+  '(-b --body-numbering)'{-b+,--body-numbering=}'[specify style for body lines]:style:->styles'
+  '(-d --section-delimiter)'{-d+,--section-delimiter=}'[separate logical pages with specified delimiter]:delimiter'
+  '(-f --footer-numbering)'{-f+,--footer-numbering=}'[specify style for footer lines]:style:->styles'
+  '(-h --header-numbering)'{-h+,--header-numbering=}'[specify style for header lines]:style:->styles'
+  '(-i --line-increment)'{-i+,--line-increment=}'[line number increment at each line]:increment'
+  '(-l --join-blank-lines)'{-l+,--join-blank-lines=}'[count consecutive empty lines as one]:number'
+  '(-n --number-format)'{-n+,--number-format=}'[specify format for line numbers]:format:((ln\:left\ justified rn\:right\ justified rz\:right\ justified\ with\ leading\ zeroes))'
+  '(-p --no-renumber)'{-p,--no-renumber}"[don't reset line numbers at logical pages]"
+  '(-s --number-separator)'{-s+,--number-separator=}'[add specified string after line numbers]:string'
+  '(-v --starting-line-number)'{-v+,--starting-line-number=}'[specify first line number on each logical page]:initial number'
+  '(-w --number-width)'{-w+,--number-width=}'[specify number of columns for line numbers]:columns'
+)
+
+if _pick_variant gnu=GNU unix --version; then
+  args+=(
+    '(- *)--help[display help information]'
+    '(- *)--version[display version information]'
+  )
+else
+  args=( ${(R)args:#(|\*)(|\(*\))--*} )    # remove long options
+fi
+
+_arguments -C -s $args '*:file:_files' && ret=0
+
+if [[ -n $state ]]; then
+  if compset -P p; then
+    _message -e regex 'regular expression'
+  else
+    _describe -t styles style '( p:number\ only\ lines\ matching\ regex )' -S '' -- '(
+      a:number\ all\ lines
+      t:number\ only\ non-empty\ lines
+      n:no\ line\ numbering
+    )'
+  fi
+fi || return ret
diff --git a/Completion/Unix/Command/_nm b/Completion/Unix/Command/_nm
index 7f395d6..8013632 100644
--- a/Completion/Unix/Command/_nm
+++ b/Completion/Unix/Command/_nm
@@ -1,6 +1,6 @@
-#compdef nm
+#compdef nm eu-nm
 
-local args files
+local args files variant
 
 _nm_object_file() {
   [[ -x $REPLY || $REPLY = *.([ao]|so|elf) ]]
@@ -15,7 +15,7 @@ args=(
   '(-t --radix -o -x)'{-t,--radix}'[specify radix for numeric values]:radix:((d\:decimal o\:octal x\:hexadecimal))'
 )
 
-if _pick_variant gnu=GNU unix -V; then
+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]'
@@ -24,22 +24,47 @@ if _pick_variant gnu=GNU unix -V; then
     '(-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)'{-f+,--format=}'[specify output format]:format:(bsd sysv posix)'
-    '(-l --line-numbers)'{-l,--line-numbers}'[display source file and line numbers from debug information]'
-    '(-n --numeric-sort -p --no-sort --size-sort)'{-n,--numeric-sort}'[sort symbols numerically by address]'
+    '(-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 --portability -B -f --format)'{-P,--portability}'[same as --format=posix]'
-    '(-r --reverse-sort -p --no-sort --size-sort)'{-r,--reverse-sort}'[reverse sort order]'
-    '--plugin[load specified plugin]:plugin'
+    '(-r --reverse-sort -p --no-sort --size-sort -v)'{-r,--reverse-sort}'[reverse sort order]'
     '(-u --undefined-only --defined-only)'{-u,--undefined-only}'[display only undefined symbols]'
-    "--target=[target object format]:targets:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
     '(-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)--size-sort[sort symbols by size]'
-    '--special-syms[include special symbols in the output]'
-    '--synthetic[display synthetic symbols as well]'
+    '(-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]'
+      )
+    ;|
+    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]'
+      )
+    ;;
+    elfutils)
+      args+=(
+        '--mark-special[mark special symbols]'
+	'--color=[use color in output]:color:(always auto never)'
+      )
+    ;;
+    binutils)
+      args+=(
+	'(-f --format -P)-f+[specify output format]:format:(bsd sysv posix)'
+	'--plugin[load specified plugin]:plugin'
+	'--special-syms[include special symbols in the output]'
+	'--synthetic[display synthetic symbols as well]'
+	"--target=[target object format]:targets:(${${(@M)${(f)$(_call_program targets nm --help)}:#*supported targets:*}##*: })"
+      )
+    ;;
+  esac
 else
   # following flags are accurate for Solaris
   args=( ${args:#(|*\)(\*|))-[o-]*}
diff --git a/Completion/Unix/Command/_od b/Completion/Unix/Command/_od
index 59775ab..db75b3f 100644
--- a/Completion/Unix/Command/_od
+++ b/Completion/Unix/Command/_od
@@ -1,4 +1,4 @@
-#compdef od
+#compdef od god
 
 local curcontext="$curcontext" state state_descr line args ret=1
 local -A opt_args
@@ -25,6 +25,8 @@ if _pick_variant gnu=GNU unix --version; then
   # -h -B -I and -L are obsolescent and undocumented
   args=( ${(R)args:#(|\*)(|\(*\))-[hBIL]*} )
   args+=(
+    '--traditional'
+    '--endian=[swap input bytes]:endianess:(big little)'
     {-S+,--strings=-}'[output strings of at least specfied bytes long]:length'
     {-w-,--width=-}'[output specified bytes per line]:bytes'
     '(- : *)--help[display help and exit]'
@@ -33,18 +35,29 @@ if _pick_variant gnu=GNU unix --version; then
 else
   args=( ${(R)args:#(|\*)(|\(*\))--*} )    # remove long options
   case "$OSTYPE" in
-    (darwin*|freebsd*|dragonfly*|openbsd*)
+    darwin*|freebsd*|dragonfly*|openbsd*)
       args+=(
-        '-D[output unsigned decimal ints (-t u4)]'
+        '-D[output unsigned decimal integers (-t u4)]'
         {-e,-F}'[output double-precision floats (-t fD)]'
         {-H,-X}'[output hexadecimal ints (-t x4)]'
         '-O[output octal ints (-t o4)]'
       )
-      ;;
+    ;;
+    solaris*)
+      args=(
+        ${(M)args:#(|\*)(|\(*\))-[AjNtvbcdfosx]*}
+	'-C[output all printable characters and use C-style escapes]'
+	'-D[output unsigned decimal long words (-t u4)]'
+	'-F[output double-precision floats (-t f8)]'
+	'-O[output octal ints (-t o4)]'
+	'-S[output decimal ints (-t d4)]'
+	'-X[output hexadecimal ints (-t x4)]'
+      )
+    ;;
     (*)
       # POSIX options only
       args=( ${(M)args:#(|\*)(|\(*\))-[AjNtvbcdosx]*} )
-      ;;
+    ;;
   esac
 fi
 
diff --git a/Completion/Unix/Command/_patch b/Completion/Unix/Command/_patch
index add4367..c0df00c 100644
--- a/Completion/Unix/Command/_patch
+++ b/Completion/Unix/Command/_patch
@@ -1,7 +1,7 @@
-#compdef patch
+#compdef patch gpatch
 
 if (( ! $+_patch_args )); then
-  local help="$(LC_ALL=C patch --help 2>&1)"
+  local help="$(LC_ALL=C $words[1] --help 2>&1)"
   local -A optionmap
   local arg
   local comp_p='compadd "$expl[@]" -S0 -r "1-9" - ""'
diff --git a/Completion/Unix/Command/_ping b/Completion/Unix/Command/_ping
index e59f6fa..a1a50e1 100644
--- a/Completion/Unix/Command/_ping
+++ b/Completion/Unix/Command/_ping
@@ -33,31 +33,37 @@ if _pick_variant iputils=iputils unix -V; then
 
 else
 
-# FreeBSD 4.11
-
   _arguments \
     '-A[audible for no packet]' \
-    '-Q[somewhat quiet]' \
-    '-R[record route]' \
     '-a[audible for each packet]' \
+    '-c:count' \
+    "-D[set the don't fragment bit]" \
     '-d[set SO_DEBUG on the socket]' \
     '-f[flood ping]' \
-    '-n[numeric output only]' \
-    '-q[quiet]' \
-    '-r[bypass normal routing tables]' \
-    '-v[verbose]' \
-    '-c:count' \
+    '-G[specify maximum size for ICMP payload for sweeping pings]:size' \
+    '-g[specify minimum size for ICMP payload for sweeping pings]:size [0]' \
+    '-h[specify size increment for ICMP payload for sweeping pings]:size [1]' \
     '-i:wait seconds' \
+    '-I[source interface for multicast packets]:iface:_net_interfaces' \
+    '-L[suppress loopback of multicast packets]' \
     '-l:preload number' \
+    '-M:icmp:(mask time)' \
     '-m:ttl' \
-    '-p:padding pattern' \
+    '-n[numeric output only]' \
+    '-o[exit after receiving one packet]' \
     '-P:IPsec policy' \
+    '-p:padding pattern' \
+    '-Q[somewhat quiet]' \
+    '-q[quiet]' \
+    '-R[record route]' \
+    '-r[bypass normal routing tables]' \
+    '-S:source address' \
     '-s:packet size in bytes' \
-    '-S:src addr' \
-    '-t:timeout in seconds' \
-    '-L[suppress loopback of multicast packets]' \
-    '-I:iface:_net_interfaces' \
     '-T:ttl for multicasted packets' \
+    '-t:timeout in seconds' \
+    '-v[verbose]' \
+    '-W:wait time (ms)' \
+    '-z:type of service' \
     ':host:_hosts'
 
 fi
diff --git a/Completion/Unix/Command/_ps b/Completion/Unix/Command/_ps
new file mode 100644
index 0000000..925f483
--- /dev/null
+++ b/Completion/Unix/Command/_ps
@@ -0,0 +1,188 @@
+#compdef ps
+
+_ps_props() {
+  local opts
+
+  if [[ $1 = -s ]]; then
+    shift
+    compset -P '[+-]' || _describe -t modifiers modifier \
+	'( +:ascending\ order -:descending\ order )' -S ''
+  fi
+
+  case $OSTYPE in
+    linux-gnu) opts=( ${${(f)"$(_call_program properties $words[1] L)"}%% *} ) ;;
+    freebsd*) opts=( $(_call_program properties $words[1] L) ) ;;
+    solaris*) opts=( ${=${(f)"$(_call_program properties $words[1] - 2>&1)"}[-3,-1]} ) ;;
+  esac
+
+  compadd "$@" -a opts
+}
+
+local curcontext="$curcontext" state line expl ret=1
+local short long
+local -a args bsd bsdarg pids
+local -A equivs
+
+args=(
+  '-a[select processes with tty except session leaders]'
+  {-A,-e}'[select every process]'
+  '-d[select all processes except session leaders]'
+  '*-p+[select processes by ID]:process ID:_sequence -s , _pids'
+  '*-G+[select processes by real group]:group:_sequence -s , _groups'
+  '*-g+[select processes by effective group or session]:group:_sequence -s , _groups'
+  '*-s+[select processes by session leaders]:session leader:_sequence -s , _pids'
+  '*-t+[select processes by attached terminal]:tty:_sequence -s , compadd - /dev/pts/<->(N\:s/\\/dev\\//) /dev/tty*(N\:t)'
+  '*-u+[select processes by effective user]:user:_sequence -s , _users'
+  '*-U+[select processes by real user]:user:_sequence -s , _users'
+  '-o+[specify output format]:property:_sequence -s , _ps_props -'
+
+  '-c[show scheduler properties]'
+  '-f[full listing]'
+  '-j[show session ID and process group ID]'
+  '-l[long listing]'
+  '-L[show information about each light weight process]'
+  '-y[show RSS in place of ADDR (used with -l)]'
+)
+
+bsd=(
+  'a[include processes belonging to other users]'
+  'e[show environment after command]'
+  '(j s u v X)l[output in long format]'
+  '(l s u v X)j[output in job control format]'
+  'x[include processes with no controlling terminal]'
+  '(j l s v X)u[output in resource usage format]'
+  '(j l s u X)v[output in virtual memory format]'
+  '*w[wide output]'
+  'H[show threads as if they were processes]'
+  'L[display all format specifiers]'
+  'S[include child process data with the parent]'
+  'T[select processes attached to current terminal]'
+  'Z[show security data]'
+)
+bsdarg=(
+  '*p[select processes by ID]'
+  '*t[select processes by attached terminal]'
+  '*U[select processes by effective user]'
+  'O[specify additional output fields]'
+  'o[specify output format]'
+  'N[set namelist file for WCHAN display]'
+)
+
+case $OSTYPE in
+  solaris2.<11->)
+    args+=(
+      '-h[select processes homed to the specified lgrp]:lgrp list'
+      '-H[show home lgroup of the process]'
+    )
+  ;|
+  solaris*)
+    args+=(
+      '-P[show processor to which the process or lwp is bound]'
+      '*-z[select processes by zone]:zone list:_sequence _zones'
+      '-Z[show zone with which process is associated]'
+    )
+  ;;
+  darwin*|dragonfly*|freebsd*|netbsd*|openbsd*)
+    bsd+=(
+      'A[select every process]'
+      'C[ignore resident time for CPU percentage]'
+      'c[show just executable name for command]'
+      'h[repeat header lines, one per page of output]'
+      '(r)m[sort by memory usage]'
+      '(m)r[sort by CPU usage]'
+    )
+    bsdarg+=(
+      'M[extract values from specified core]'
+    )
+  ;|
+  linux-gnu|netbsd*) bsdarg+=( 'k[specify sort order]' ) ;|
+  darwin*|freebsd*) bsdarg+=( 'G[select processes by real group]' ) ;|
+  freebsd*)
+    bsd+=(
+      'd[show process hierarchy]'
+      'f[show command and environment for swapped out processes]'
+      '*J[select processes by jail ID]'
+    )
+  ;;
+  netbsd*) bsd+=( '(j l u v)s[output in thread format]' ) ;;
+  openbsd*)
+    bsd+=(
+      'k[display information about kernel threads]'
+    )
+    bsdarg+=( 'W[extract swap information from the specified file]' )
+  ;;
+  linux-gnu)
+    args+=(
+      '-O+[specify additional output fields]:property:_sequence -s , _ps_props -'
+      '(-N --deselect)'{-N,--deselect}'[negate selection: all processes except those selected]'
+      '*-C[select processes by command name]:command:_sequence -s , _command_names -e'
+      '*--ppid[select processes by parent process ID]:parent process:_sequence -S , _pids'
+      '(-f)-F[extra full format listing]'
+      '--context[show SELinux security context format]'
+      '-M[show security data]'
+      '(--forest -H)'{--forest,-H}'[show process hierarchy]'
+      '--headers[repeat header lines, one per page of output]'
+      '(--cols --columns --width)'{--cols,--columns,--width}'[set screen width]:width'
+      '(--lines --rows)'{--lines,--rows}'[set screen height]'
+      '--cumulative[include child process data with the parent]'
+      '-n[set namelist file for WCHAN display]:file:_files'
+      '(--no-headers --no-heading)'{--no-headers,--no-heading}'[suppress headers]'
+      '--sort=[specify sort order]:order:_ps_props -s'
+      '-w[wide output]'
+      '-m[show threads after processes]'
+      '-T[show threads, with SPID column]'
+      '-Z[show security context format (SELinux)]'
+      '(- *)--help[display help information]::subject:(simple list output threads misc all)'
+      '(- *)--info[display debugging information]'
+      '(- *)'{-V,--version}'[display version information]'
+    )
+    equivs=( G Group g group p pid s sid t tty U User u user o format )
+    for short long in ${(kv)equivs}; do
+      args+=( ${${(M)args:#(\*|)-$short*}/$short+/-$long=} )
+    done
+    bsd+=(
+      'c[show true command name]'
+      'f[show process hierarchy]'
+      'h[suppress header]'
+      'm[show threads after processes]'
+      'n[numeric output for WCHAN and USER]'
+      'r[select running processes]'
+      '(j l u v X)s[output in signal format]'
+      'V[display version information]'
+      '(j l s u v)X[output in register format]'
+    )
+  ;;
+esac
+
+if (( CURRENT > 1 )) && [[ $OSTYPE != solaris* || ( $OSTYPE = linux-gnu && $words[CURRENT-1] != -* ) ]]; then
+  case $words[CURRENT-1] in
+    *k)
+      _wanted -C option-k-1 properties expl 'property' _sequence -s , _ps_props -s - && return
+    ;;
+    *G) _sequence -s , _groups && return ;;
+    *J) _sequence -s , _jails && return ;;
+    *[MNW]) _files && return ;;
+    *t)
+      _wanted -C option-t-1 ttys expl tty _sequence -s , \
+	  compadd - /dev/pts/<->(N\:s/\\/dev\\//) /dev/tty*(N\:t) && return
+    ;;
+    *p) _wanted -C option-p-1 processes expl 'process ID' _sequence -s , _pids && return;;
+    *U) _wanted -C option-U-1 users expl user _sequence -s , _users && return ;;
+    *[oO]) _wanted -C "option-${words[CURRENT-1][-1]}-1" properties \
+        expl 'property' _sequence -s , _ps_props - && return ;;
+  esac
+fi
+
+if [[ $OSTYPE = (*bsd*|darwin*|dragonfly*) ]]; then
+  compset -P - && pids=1
+else
+  _arguments -C -s $args '*:: :->rest' && ret=0
+  [[ -z "$state" || $OSTYPE = solaris* ]] && return ret
+fi
+
+_values -s '' -S ' ' 'options' $bsd && ret=0
+_values -S ' ' 'options' $bsdarg && ret=0
+if [[ -z $pids ]]; then
+  _pids && compstate[insert]=
+fi
+return ret
diff --git a/Completion/Unix/Command/_readelf b/Completion/Unix/Command/_readelf
new file mode 100644
index 0000000..9312ea8
--- /dev/null
+++ b/Completion/Unix/Command/_readelf
@@ -0,0 +1,62 @@
+#compdef readelf eu-readelf
+
+local variant args sections
+
+_elf_file() {
+  [[ -x $REPLY || $REPLY = (core*|*.([ao]|so|elf)) ]]
+}
+
+sections=( .bss .data .dynamic .dynsym .got .interp .shstrtab .symtab .text )
+_pick_variant -r variant elftoolchain=elftoolchain elfutils=elfutils binutils --version
+
+args=(
+  '(-a --all)'{-a,--all}'[show all tables]'
+  '(-h --file-header)'{-h,--file-header}'[show file header]'
+  '(-l --program-headers --segments)'{-l,--program-headers,--segments}'[show program headers]'
+  '(-S --section-headers --sections)'{-S,--section-headers,--sections}'[show sections header]'
+  '(-s --syms --symbols)'{-s,--syms,--symbols}'[show symbol table]'
+  '(-n --notes)'{-n,--notes}'[show core notes (if present)]'
+  '(-r --relocs)'{-r,--relocs}'[show relocations (if present)]'
+  '(-d --dynamic)'{-d,--dynamic}'[show dynamic section (if present)]'
+  '(-V --version-info)'{-V,--version-info}'[show version sections (if present)]'
+  '(-A --arch-specific)'{-A,--arch-specific}'[show architecture specific information (if any)]'
+  '(-c --archive-index)'{-c,--archive-index}'[show symbol/file index in an archive]'
+  \*{-x,--hex-dump=}"[dump contents of specified section as bytes]:section:($sections)"
+  \*{-p,--string-dump=}"[dump contents of specified section as strings]:section:($sections)"
+  '-w+[show the contents of DWARF2 debug sections]::debug section:(l L i a p r m f F s o R t)'
+  '--debug-dump=[show the contents of DWARF2 debug sections]::section:(rawline decodedline info abbrev pubnames aranges macro frames frames-interp str loc Ranges pubtypes gdb_index trace_info trace_abbrev trace_aranges)'
+  '(-I --histogram)'{-I,--histogram}'[show histogram of bucket list lengths]'
+  '(-W --wide)'{-W,--wide}'[allow output width to exceed 80 characters]'
+  '(- *)'{-H,--help}'[display help information]'
+  '(- *)'{-v,--version}'[display version information]'
+  "*:elf file:_files -g '*(-.e:_elf_file:)'"
+)
+
+case $variant in
+  elftoolchain|binutils)
+    args+=(
+      '(-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]'
+      '(-u --unwind)'{-u,--unwind}'[show unwind info (if present)]'
+      '(-D --use-dynamic)'{-D,--use-dynamic}'[use dynamic section info when showing symbols]'
+    )
+  ;|
+  binutils)
+    args+=(
+      '--dyn-syms[show dynamic symbol table]'
+      \*{-R,--relocated-dump=}"[dump contents of specified section as relocated bytes]:section:($sections)"
+      "--dwarf-depth=[don't show DIEs at greater than specified depth]:depth"
+      '--dwarf-start=[show DIEs starting at specified depth or deeper]:depth'
+    )
+  ;;
+  elfutils)
+    args+=(
+      '--elf-section[used specified section as ELF input data]::section'
+      '(-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]"
+    )
+  ;;
+esac
+
+_arguments -s "$args[@]"
diff --git a/Completion/Unix/Command/_rm b/Completion/Unix/Command/_rm
index 1f156c4..4728ad4 100644
--- a/Completion/Unix/Command/_rm
+++ b/Completion/Unix/Command/_rm
@@ -1,4 +1,4 @@
-#compdef rm
+#compdef rm grm zf_rm
 
 declare -a opts args
 args=(
@@ -16,12 +16,25 @@ if _pick_variant gnu=gnu unix --help; then
     '--one-file-system[stay within filesystems of files given as arguments]'
     '(                   --preserve-root)--no-preserve-root[do not treat / specially]'
     '(--no-preserve-root                )--preserve-root[do not remove / (default)]'
+    '(-d --dir)'{-d,--dir}'[remove directories as well]'
     '(-v --verbose)'{-v,--verbose}'[explain what is being done]'
     '(- *)--help[display help message and exit]'
     '(- *)--version[output version information and exit]'
   )
 else
   args=(${args:#*--(force|recursive)\[*})
+  case $OSTYPE in
+    freebsd*)
+      args+=(
+        '-d[remove directories as well]'
+	'(-i)-I[prompt when removing many files]'
+	'-P[overwrite files before deleting them]'
+	'-v[explain what is being done]'
+	'-W[attempt to undelete named files]'
+	"-x[don't cross file systems when removing a hierarchy]"
+      )
+    ;;
+  esac
 fi
 
 local curcontext=$curcontext state line ret=1
diff --git a/Completion/Unix/Command/_sed b/Completion/Unix/Command/_sed
index 4765752..8e2385c 100644
--- a/Completion/Unix/Command/_sed
+++ b/Completion/Unix/Command/_sed
@@ -1,22 +1,29 @@
-#compdef sed
+#compdef sed gsed psed s2p
 
-local args
+local args inplace extended
 
 args=(
   '(-n --quiet --silent)'{-n,--quiet,--silent}'[suppress automatic printing of pattern space]'
-  '(1)*'{-e,--expression=-}'[add sed commands to run]:sed script'
+  '(1)*'{-e,--expression=-}'[specify sed commands to run]:sed script'
   '(1)*'{-f,--file=-}'[add contents of file to commands to run]:file:_files'
   '(-e)1: :_guard "^-*" sed script'
   '*:input file:_files'
 )
+inplace='[edit files in-place, running scripts separately for each file]::suffix for backup'
+extended='[use extended regular expressions]'
 
-if _pick_variant gnu=GNU unix --version; then
+if [[ $service = (psed|s2p) ]]; then
+  args=(
+    "${(@)args:#(|\(*\))(|\*)--*}"
+    '-a[delay opening files listed with w function]'
+  )
+elif _pick_variant gnu=GNU unix --version; then
   args+=(
     '--follow-symlinks[follow symlinks when processing in place]'
-    '(-i --in-place)'{-i-,--in-place=-}'[edit files in place]::suffix for backup'
+    '(-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}'[use extended regular expressions]'
+    '(-r --regexp-extended)'{-r,--regexp-extended}$extended
     '(-s --separate)'{-s,--separate}'[consider files separately instead of as a combined stream]'
     '(-u --unbuffered)'{-u,--unbuffered}'[disable data buffering]'
     '(- 1 :)--help[print program usage]'
@@ -24,6 +31,27 @@ if _pick_variant gnu=GNU unix --version; then
   )
 else
   args=( "${(@)args:#(|\(*\))(|\*)--*}" )
+  case $OSTYPE in
+    openbsd*|freebsd*|netbsd*|darwin*|dragonfly*)
+      args+=(
+	'(-r -E)'{-r,-E}$extended
+	'-a[delay opening files listed with w function]'
+      )
+    ;|
+    darwin*|freebsd*|netbsd*)
+      args+=(
+        '-i'$inplace
+	'-l[make output line buffered]'
+      )
+    ;|
+    freebsd*) args+=( '-u[disable data buffering]' ) ;|
+    freebsd*|netbsd*)
+      args+=(
+        '-I[edit files in-place, treating all files as a single input stream]::suffix for backup'
+      )
+    ;;
+    openbsd*) args+=( '-u[make output line buffered]' ) ;;
+  esac
 fi
 
-_arguments "$args[@]"
+_arguments -s "$args[@]"
diff --git a/Completion/Unix/Command/_sort b/Completion/Unix/Command/_sort
index ff36b9b..2e7f0a0 100644
--- a/Completion/Unix/Command/_sort
+++ b/Completion/Unix/Command/_sort
@@ -1,37 +1,76 @@
-#compdef sort
+#compdef sort gsort
 
+local args variant
 local ordering='(-d --dictionary-order -g --general-numeric-sort -M --month-sort -h --human-numeric-sort -n --numeric-sort --sort -V --version-sort --help --version)'
 
-_arguments -s -S \
-  '(-b --ignore-leading-blanks)'{-b,--ignore-leading-blanks}'[ignore leading blanks]' \
-  "$ordering"{-d,--dictionary-order}'[consider only blanks and alphanumeric characters]' \
-  '(-f --ignore-case)'{-f,--ignore-case}'[fold lower case to upper case characters]' \
-  "$ordering"{-g,--general-numeric-sort}'[compare according to general numeric value]' \
-  '(-i --ignore-nonprinting)'{-i,--ignore-nonprinting}'[consider only printable characters]' \
-  "$ordering"{-M,--month-sort}"[compare (unknown) < 'JAN' < ... < 'DEC']" \
-  "$ordering"{-h,--human-numeric-sort}'[compare human readable numbers (e.g., 2K 1G)]' \
-  "$ordering"{-n,--numeric-sort}'[compare according to string numerical value]' \
-  "$ordering"{-R,--random-sort}'[sort by random hash of keys]' \
-  '--random-source=[get random bytes from file]:file:_files' \
-  '(-r --reverse)'{-r,--reverse}'[reverse the result of comparisons]' \
-  "$ordering--sort=[sort according to ordering]:ordering:(general-numeric human-numeric month numeric random version)" \
-  "$ordering"{-V,--version-sort}'[sort version numbers]' \
-  '--batch-size=[maximum inputs to merge]:number' \
-  '(-c --check -C)'{-c,-C}'[check whether input is sorted; do not sort]' \
-  '(-c --check -C)--check=-[check whether input is sorted; do not sort]::bad line handling:(diagnose-first silent quiet)' \
-  '--compress-program=[specify program to compress temporary files with]:program:(gzip bzip2 lzop xz)' \
-  '--debug[annotate the of the line used to sort]' \
-  '--files0-from=[read input files from file]:file:_files' \
-  '(-k --key)'{-k+,--key=}'[start a key at POS1, end it as POS2 (origin 1)]:key' \
-  '(-m --merge)'{-m,--merge}'[merge already sorted files; do not sort]' \
-  '(-o --output)'{-o+,--output=}'[write result to file instead of standard output]:output file:_files' \
-  '(-s --stable)'{-s,--stable}'[preserve original order of lines with the same key]' \
-  '(-S --buffer-size)'{-S+,--buffer-size=}'[specify size for main memory buffer]:size' \
-  '(-t --field-separator)'{-t+,--field-separator=}'[specify field separator instead of non-blank to blank transition]:separator' \
-  \*{-T+,--temporary-directory=}'[specify directory for temporary files]:directory:_directories' \
-  '(-u --unique)'{-u,--unique}'[with -c, check for strict ordering; without -c, output only the first of an equal run]' \
-  '--parallel=[set number of sorts run concurrently]:number' \
-  '(-z --zero-terminated)'{-z,--zero-terminated}'[end lines with 0 byte, not newline]' \
-  '(- *)--help[display help and exit]' \
-  '(- *)--version[output version information and exit]' \
-  '*:file:_files'
+args=(
+  '(-c --check -C)-c[check whether input is sorted; do not sort]'
+  '(-m --merge)'{-m,--merge}'[merge already sorted files; do not sort]'
+  '(-o --output)'{-o+,--output=}'[write result to file instead of standard output]:output file:_files'
+  \*{-T+,--temporary-directory=}'[specify directory for temporary files]:directory:_directories'
+  '(-u --unique)'{-u,--unique}'[with -c, check for strict ordering; without -c, output only the first of an equal run]'
+  "$ordering"{-d,--dictionary-order}'[consider only blanks and alphanumeric characters]'
+  '(-f --ignore-case)'{-f,--ignore-case}'[fold lower case to upper case characters]'
+  '(-i --ignore-nonprinting)'{-i,--ignore-nonprinting}'[consider only printable characters]'
+  "$ordering"{-n,--numeric-sort}'[compare according to string numerical value]'
+  '(-r --reverse)'{-r,--reverse}'[reverse the result of comparisons]'
+  '(-b --ignore-leading-blanks)'{-b,--ignore-leading-blanks}'[ignore leading blanks]'
+  '(-t --field-separator)'{-t+,--field-separator=}'[specify field separator instead of non-blank to blank transition]:separator'
+  '(-k --key)'{-k+,--key=}'[specified start and end fields for key]:key field'
+)
+
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+case $variant in
+  dragonfly*|netbsd*|openbsd*|freebsd*|gnu)
+    args+=(
+      '(-s --stable)'{-s,--stable}'[preserve original order of lines with the same key]'
+    )
+  ;|
+  openbsd*|freebsd*|gnu)
+    args+=(
+      '(-c --check -C)-C[check whether input is sorted; do not sort]'
+      '(-z --zero-terminated)'{-z,--zero-terminated}'[end lines with 0 byte, not newline]'
+    )
+  ;|
+  freebsd*|gnu)
+    args+=(
+      '(-c --check -C)--check=-[check whether input is sorted; do not sort]::bad line handling:(diagnose-first silent quiet)'
+      "$ordering"{-g,--general-numeric-sort}'[compare according to general numeric value]'
+      "$ordering"{-M,--month-sort}"[compare (unknown) < 'JAN' < ... < 'DEC']"
+      "$ordering"{-h,--human-numeric-sort}'[compare human readable numbers (e.g., 2K 1G)]'
+      "$ordering"{-R,--random-sort}'[sort by random hash of keys]'
+      "$ordering"{-V,--version-sort}'[sort version numbers]'
+      "$ordering--sort=[sort according to ordering]:ordering:(general-numeric human-numeric month numeric random version)"
+      '(-i --ignore-nonprinting)'{-i,--ignore-nonprinting}'[consider only printable characters]'
+      '--random-source=[get random bytes from file]:file:_files'
+      '--batch-size=[maximum inputs to merge]:number'
+      '--compress-program=[specify program to compress temporary files with]:program:(gzip bzip2 lzop xz)'
+      '--debug[annotate the of the line used to sort]'
+      '--files0-from=[read input files from file]:file:_files'
+      '(-S --buffer-size)'{-S+,--buffer-size=}'[specify size for main memory buffer]:size'
+      '(- *)--help[display help and exit]'
+      '(- *)--version[output version information and exit]'
+    )
+  ;|
+  netbsd*|dragonfly*)
+    args+=(
+      "${ordering}-l[sort by string length of field]"
+      "(-s)-S[don't use stable sort"
+    )
+  ;|
+  openbsd*)
+    args+=(
+      '-H[use a merge sort instead of a radix sort]'
+      '-R[specify record separator]:separator'
+    )
+  ;|
+  gnu)
+    args+=( '--parallel=[set number of sorts run concurrently]:number' )
+  ;;
+  freebsd*)
+    args+=( --radixsort  --mergesort --qsort --heapsort --mmap )
+  ;;
+  *) args=( "${(@)args:#(|\(*\))(|\*)--*}" ) ;;
+esac
+
+_arguments -s -S $args '*:file:_files'
diff --git a/Completion/Unix/Command/_uname b/Completion/Unix/Command/_uname
index 9b4663b..414a82a 100644
--- a/Completion/Unix/Command/_uname
+++ b/Completion/Unix/Command/_uname
@@ -1,53 +1,81 @@
 #compdef uname
 
 typeset -A _uname_args
+local -a args
+
+case $LANG in
+  de_*)
+    _uname_args=(
+      all               "alle Grundinformationen ausgeben"
+      kernel-name       "Namen des Kernels ausgeben"
+      nodename          "Netzwerknamen der Maschine ausgeben"
+      kernel-release    "Release-Nummer des Kernels ausgeben"
+      kernel-version    "Version des Kernels ausgeben"
+      os-release        "Release-Nummer des Betriebssystems ausgeben"
+      machine           "Maschinentyp (Hardware) ausgeben"
+      processor         "Typ des Prozessors ausgeben"
+      hardware-platform "Hardwareplattform ausgeben"
+      operating-system  "Namen des Betriebssystems ausgeben"
+      help              "Hilfe anzeigen und beenden"
+      version           "Versionsinformation anzeigen und beenden"
+    )
+  ;;
+  (*)
+    _uname_args=(
+      all               "print all basic information"
+      kernel-name       "print kernel name"
+      nodename          "print network node hostname"
+      kernel-release    "print kernel release"
+      kernel-version    "print kernel version"
+      os-release        "print operating system release level"
+      machine           "print machine hardware name"
+      processor         "print processor type"
+      hardware-platform "print hardware platform"
+      operating-system  "print name of the operating system"
+      help              "display help information"
+      version           "output version information and exit"
+    )
+  ;;
+esac
 
 if _pick_variant gnu="Free Soft" unix --version; then
-  case $LANG in
-    (de_DE.UTF-8)
-       _uname_args=(
-             all               "alle Informationen ausgeben"
-             kernel-name       "Namen des Kernels ausgeben"
-             nodename          "Netzwerknamen der Maschine ausgeben"
-             kernel-release    "Release-Nummer des Kernels ausgeben"
-             kernel-version    "Version des Kernels ausgeben"
-             machine           "Maschinentyp (Hardware) ausgeben"
-             processor         "Typ des Prozessors ausgeben (oder das Wort unknown)"
-             hardware-platform "Hardwareplattform ausgeben (oder das Wort unknown)"
-             operating-system  "Namen des Betriebssystems ausgeben"
-             help              "diese Hilfe anzeigen und beenden"
-             version           "Versionsinformation anzeigen und beenden"
-       )
+  _arguments -s \
+    '(-)'{--all,-a}'['$_uname_args[all]']' \
+    '(--kernel-name -s)'{--kernel-name,-s}'['$_uname_args[kernel-name]']' \
+    '(--nodename -n)'{--nodename,-n}'['$_uname_args[nodename]']' \
+    '(--kernel-release -r)'{--kernel-release,-r}'['$_uname_args[kernel-release]']' \
+    '(--kernel-version -v)'{--kernel-version,-v}'['$_uname_args[kernel-version]']' \
+    '(--machine -m)'{--machine,-m}'['$_uname_args[machine]']' \
+    '(--processor -p)'{--processor,-p}'['$_uname_args[processor]']' \
+    '(--hardware-platform -i)'{--hardware-platform,-i}'['$_uname_args[hardware-platform]']' \
+    '(--operating-system -o)'{--operating-system,-o}'['$_uname_args[operating-system]']' \
+    '(-)--help['$_uname_args[help]']' \
+    '(-)--version['$_uname_args[version]']'
+else
+  args=(
+    "(-m -n -r -s -v)-a[${_uname_args[all]}]"
+    '-m[print hardware class]'
+    "-n[${_uname_args[nodename]}]"
+    "-p[${_uname_args[processor]}]"
+    "-r[${_uname_args[os-release]}]"
+    "-s[${_uname_args[operating-system]}]"
+    '-v[print detailed operating system version]'
+  )
+  case $OSTYPE in
+    freebsd*|dragonfly*) args+=( '-i[print kernel ident]' ) ;|
+    freebsd<10->.*)
+      args+=(
+	'-K[print FreeBSD kernel version]'
+	'-U[print FreeBSD user environment version]'
+      )
     ;;
-    (*)
-       _uname_args=(
-             all               "print all information"
-             kernel-name       "print the kernel name"
-             nodename          "print the network node hostname"
-             kernel-release    "print the kernel release"
-             kernel-version    "print the kernel version"
-             machine           "print the machine hardware name"
-             processor         "print the processor type or \"unknown\""
-             hardware-platform "print the hardware platform or \"unknown\""
-             operating-system  "print the operating system"
-             help              "display this help and exit"
-             version           "output version information and exit"
-       )
+    solaris*)
+      args+=(
+        '-i[print platform name]'
+	'-S[set system name]:system name'
+        '-X[print expanded system information]'
+      )
     ;;
   esac
-
-  _arguments \
-        '(--all -a)'{--all,-a}'['$_uname_args[all]']' \
-        '(--kernel-name -s)'{--kernel-name,-s}'['$_uname_args[kernel-name]']' \
-        '(--nodename -n)'{--nodename,-n}'['$_uname_args[nodename]']' \
-        '(--kernel-release -r)'{--kernel-release,-r}'['$_uname_args[kernel-release]']' \
-        '(--kernel-version -v)'{--kernel-version,-v}'['$_uname_args[kernel-version]']' \
-        '(--machine -m)'{--machine,-m}'['$_uname_args[machine]']' \
-        '(--processor -p)'{--processor,-p}'['$_uname_args[processor]']' \
-        '(--hardware-platform -i)'{--hardware-platform,-i}'['$_uname_args[hardware-platform]']' \
-        '(--operating-system -o)'{--operating-system,-o}'['$_uname_args[operating-system]']' \
-        '--help['$_uname_args[help]']' \
-        '--version['$_uname_args[version]']'
-else
-#       TODO add options of a NON GNU implementation
+  _arguments -s $args
 fi
diff --git a/Completion/Unix/Command/_uniq b/Completion/Unix/Command/_uniq
index dcd7a6f..1cf1235 100644
--- a/Completion/Unix/Command/_uniq
+++ b/Completion/Unix/Command/_uniq
@@ -1,4 +1,4 @@
-#compdef uniq
+#compdef uniq guniq
 
 local args
 
@@ -20,7 +20,7 @@ args=(
 
 if ! _pick_variant gnu=Free\ Soft unix --version; then
   local optchars="cdufs"
-  if [[ "$OSTYPE" == (darwin|freebsd)* ]]; then
+  if [[ "$OSTYPE" == (darwin|dragonfly|freebsd)* ]]; then
     optchars="${optchars}i"
   fi
   args=( ${(M)args:#(|\*)(|\(*\))-[$optchars]*} )
diff --git a/Completion/Unix/Command/_wc b/Completion/Unix/Command/_wc
new file mode 100644
index 0000000..49a03ba
--- /dev/null
+++ b/Completion/Unix/Command/_wc
@@ -0,0 +1,26 @@
+#compdef wc gwc
+
+local args
+
+args=(
+  '(-c --bytes)'{-c,--bytes}'[print byte counts]'
+  '(-C -m --chars)'{-m,--chars}'[print character counts]'
+  '(-w --words)'{-w,--words}'[print word counts]'
+  '(-l --lines)'{-l,--lines}'[print line counts]'
+)
+
+if _pick_variant gnu=GNU unix --version; then
+  args+=(
+    '(*)--files0-from=[read NUL-terminated file list from specified file]:file:_files'
+    '(-L --max-line-length)'{-L,--max-line-length}'[print longest line lengths]'
+  )
+else
+  args=( -A "-*" "${(@)args:#(|\(*\))(|\*)--*}" )
+  case $OSTYPE in
+    freebsd*|netbsd*) args+=( '-L[print longest line lengths]' ) ;;
+    openbsd*) args+=( '-h[human readable: use unit suffixes]' ) ;;
+    solaris*) args+=( ${${(M)args:#*-m\[*}//-m\[/-C\[} ) ;;
+  esac
+fi
+
+_arguments -s -S $args '*:file:_files'
diff --git a/Completion/Unix/Command/_xargs b/Completion/Unix/Command/_xargs
index f727ed8..d8c0a0e 100644
--- a/Completion/Unix/Command/_xargs
+++ b/Completion/Unix/Command/_xargs
@@ -1,15 +1,63 @@
-#compdef xargs
-
-_arguments \
-  '(-t)-p[prompt user for each command]' \
-  '(-p)-t[verbose - echo each command]' \
-  '-x[exit if max size exceeded]' \
-  -{e-,E}':end-of-file string:' \
-  '(-x -I)-i-:replacement string for lines:' \
-  '(-x -i)-I:replacement string for lines:' \
-  '(-n -L -x)-l-:number of input lines:' \
-  '(-n -l)-L:number of input lines:' \
-  '(-l -L)-n-:maximum number of arguments:' \
-  '-s-:maximum command line length:' \
+#compdef xargs gxargs
+
+local args variant
+
+args=(
+  '(-l -L --max-lines -n --max-args -s --max-chars)'{-n+,--max-args=}'[specify maximum number of arguments for each line]:number of arguments' \
+  '(-l -L --max-lines -n --max-args -s --max-chars)'{-s+,--max-chars=}'[specify maximum characters per command line]:maximum command line length'
+  '(-p --verbose -t --interactive)'{-p,--interactive}'[prompt user for each command]'
+  '(-p --verbose -t --interactive)'{-t,--verbose}'[verbose - echo each command]'
+  '(-x --exit)'{-x,--exit}'[exit if max size exceeded]'
+)
+
+_pick_variant -r variant gnu=GNU $OSTYPE --version
+
+case $variant in
+  gnu|darwin*|freebsd*|netbsd*|openbsd*)
+    args+=(
+      '(--max-procs -P)'{-P,--max-procs}'[parallel mode]:maximum processes' '!-r'
+    )
+  ;|
+  dragonfly*|darwin*|freebsd*|netbsd*|openbsd*)
+    args=( "${(@)args:#(|\(*\))(|\*)--*}"
+      '-0[expect NUL characters as input separators]'
+      '-J[specify marker for position of arguments]:marker'
+      '-R[specify maximum arguments that -I will replace in]:replacements'
+    )
+  ;|
+  freebsd*|netbsd*)
+    args+=(
+      '-S[space that -I can use for replacements]:size (bytes) [255]'
+    )
+  ;;
+  solaris*|gnu)
+    args+=(
+      '(-x -I)'{-i-,--replace}'[specify replacement string for command line]::replacement string'
+      '(-n -L -x)-l-[call program for every number of lines]:number of input lines'
+      '(-E -e --eof)'{-e-,--eof=}'[specify EOF marker]:end-of-file marker'
+    )
+  ;|
+  solaris*) args=( "${(@)args:#(|\(*\))(|\*)--*}" ) ;|
+  solaris2.<11->)
+    args+=( '-0[expect NUL characters as input separators]' )
+  ;;
+  gnu)
+    args+=(
+      '(-a --arg-file)'{-a+,--arg-file=}'[read input items from specified file]:file:_files'
+      '(-0 --null -d --delimiter)'{-0,--null}'[expect NUL characters as input separators]'
+      '(-d --delimiter -0 --null)'{-d+,--delimiter=}'[specify delimiter of input items]:delimiter'
+      '(-l -L --max-lines -n --max-args -s --max-chars)--max-lines=-[call program for every number of lines]::number of input lines'
+      '(-r --no-run-if-empty)'{-r,--no-run-if-empty}"[don't run command in absence of input]"
+      '(- *)--help[show help information]'
+      '(- *)--version[show version information]'
+      '--show-limits[show OS imposed limits to command-line length]'
+    )
+  ;;
+esac
+
+_arguments -s $args \
+  '-E[specify EOF marker]:end-of-file marker' \
+  '(-x -i)-I[specify replacement string for command line]:replacement string' \
+  '(-n -l)-L[call program for every number of lines]:number of input lines' \
   '(-):command: _command_names -e' \
   '*::args: _normal'
diff --git a/Completion/Unix/Type/_diff_options b/Completion/Unix/Type/_diff_options
index 472838c..d76c265 100644
--- a/Completion/Unix/Type/_diff_options
+++ b/Completion/Unix/Type/_diff_options
@@ -103,17 +103,20 @@ if _pick_variant -c $cmd gnu=GNU unix -v; then
 else
   case $OSTYPE in
     solaris2.<9->)
-      args=( '(-c -e -f -C)-u[output a unified diff]' )
+      args=(
+	'(-c -e -f -C -U)-u[output a unified diff]'
+	'(-c -e -f -C -u)-U[output a unified diff]:lines of context'
+      )
     ;&
     solaris*)
       args+=(
 	'-i[case insensitive]'
         '-t[expand tabs to spaces]'
 	'-w[ignore all white space]'
-        '(-c -e -f -n -u -h -D)-C+[output a context diff]:number of lines of copied context'
-	'(-c -e -f -n -u -C -D)-h[do a fast, half-hearted job]'
-	'(-c -e -f -u -h -C -D)-n[reversed ed script]'
-	'(-c -e -f -n -u -h -C)-D[output merged file with preprocessor directives]:preprocessor symbol'
+	'(-c -e -f -n -u -U -h -D)-C+[output a context diff]:lines of context'
+	'(-c -e -f -n -u -U -C -D)-h[do a fast, half-hearted job]'
+	'(-c -e -f -u -U -h -C -D)-n[reversed ed script]'
+	'(-c -e -f -n -u -U -h -C)-D[output merged file with preprocessor directives]:preprocessor symbol'
         '-l[output through pr]'
 	'-s[report on identical files]'
         '-S+[set first file in comparison]:start with file:_files'
diff --git a/Completion/Unix/Type/_file_systems b/Completion/Unix/Type/_file_systems
index 4fdeabe..2d903d4 100644
--- a/Completion/Unix/Type/_file_systems
+++ b/Completion/Unix/Type/_file_systems
@@ -17,13 +17,14 @@ case $OSTYPE in
   osf*) fss=( advfs ufs nfs mfs cdfs ) ;;
   solaris*) fss=( ufs nfs hsfs s5fs pcfs cachefs tmpfs ) ;;
   dragonfly*)
-    fss=( cd9660 devfs ext2fs fdesc kernfs linprocfs mfs msdos nfs 
+    fss=( cd9660 devfs ext2fs fdesc kernfs linprocfs mfs msdos nfs
           ntfs null nwfs portal procfs std udf ufs umap union )
   ;;
   freebsd*)
+    fss=( ${${(f)"$(_call_program fstypes lsvfs)"}[3,-1]%% *} ) ||
     fss=( cd9660 devfs ext2fs fdescfs kernfs linprocfs linsysfs mfs msdosfs nfs
-    ntfs nullfs nwfs portalfs procfs smbfs std udf ufs unionfs 
-    reiserfs xfs)
+    ntfs nullfs nwfs portalfs procfs smbfs std tmpfs udf ufs unionfs
+    reiserfs xfs zfs )
   ;;
   darwin*)
     fss=( afp cd9660 cddafs devfs fdesc hfs lfs msdos nfs
@@ -36,11 +37,3 @@ case $OSTYPE in
 esac
 
 _wanted fstypes expl 'file system type' compadd "$@" -M 'L:|no=' -a "$@" - fss
-
-
- 
-
-
-
-
-


^ permalink raw reply	[relevance 5%]

* Re: PATCH: 5.0.8 notes
  @ 2015-05-03 18:09  5%     ` Peter Stephenson
  2015-05-03 20:11  0%       ` Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-05-03 18:09 UTC (permalink / raw)
  To: Zsh hackers list

[Sorry if this gets to you twice but I think I misdirected the first.]

Here's some NEWS, not quite as it happens.

pws

diff --git a/NEWS b/NEWS
index 3f60321..4163efc 100644
--- a/NEWS
+++ b/NEWS
@@ -4,8 +4,35 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
 
 Note also the list of incompatibilities in the README file.
 
-Changes since 5.0.0
--------------------
+Changes from 5.0.7 to 5.0.8
+---------------------------
+
+- Global aliases can be created for syntactic tokens such as command
+  separators (";", "&", "|", "&&", "||"), redirection operators, etc.
+  Use at your own risk!  The POSIX_ALIASES option is interpreted more
+  strictly to prevent expansion of these and other alias names containing
+  quotes, glob metacharacters, parameter references, etc.
+
+- There have been various further improvements to builtin handling
+  with the POSIXBUILTIN option (off by default) for compatibility with
+  the POSIX standard.
+
+- 'whence -v' is now more informative, and 'whence -S' shows you
+  how a full chain of symbolic links resolves to a command.
+
+- The 'p' parameter flag now allows an argument to be specified
+  as a referene to a variable, e.g. ${(ps.$sep.)foo} to split $foo
+  on a string given by $sep.
+
+- Elements of the watch variable may now be patterns.
+
+- The logic for retrying history locking has been improved.
+
+- Some rationalisations have been made to the zsh/gdbm module that
+  should make it more useful and predictable in operation.
+
+Changes from 5.0.0 to 5.0.7
+---------------------------
 
 - Numeric constants encountered in mathematical expressions (but not other
   contexts) can contain underscores as separators that will be ignored on
@@ -117,12 +144,6 @@ Changes since 5.0.0
   Running fn writes "hello" to logfile.  In older versions of the shell
   it would create an empty file at the point of definition.
 
-- Global aliases can be created for syntactic tokens such as command
-  separators (";", "&", "|", "&&", "||"), redirection operators, etc.
-  Use at your own risk!  The POSIX_ALIASES option is interpreted more
-  strictly to prevent expansion of these and other alias names containing
-  quotes, glob metacharacters, parameter references, etc.
-
 Changes between 4.2 and 5.0.0
 -----------------------------


^ permalink raw reply	[relevance 5%]

* Re: PATCH: 5.0.8 notes
  2015-05-03 18:09  5%     ` Peter Stephenson
@ 2015-05-03 20:11  0%       ` Mikael Magnusson
  0 siblings, 0 replies; 200+ results
From: Mikael Magnusson @ 2015-05-03 20:11 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Sun, May 3, 2015 at 8:09 PM, Peter Stephenson
<p.w.stephenson@ntlworld.com> wrote:
> [Sorry if this gets to you twice but I think I misdirected the first.]
>
> Here's some NEWS, not quite as it happens.
>
> pws
>
> diff --git a/NEWS b/NEWS
> index 3f60321..4163efc 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -4,8 +4,35 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH
>
>  Note also the list of incompatibilities in the README file.
>
> -Changes since 5.0.0
> --------------------
> +Changes from 5.0.7 to 5.0.8
> +---------------------------
> +
> +- Global aliases can be created for syntactic tokens such as command
> +  separators (";", "&", "|", "&&", "||"), redirection operators, etc.
> +  Use at your own risk!  The POSIX_ALIASES option is interpreted more
> +  strictly to prevent expansion of these and other alias names containing
> +  quotes, glob metacharacters, parameter references, etc.
> +
> +- There have been various further improvements to builtin handling
> +  with the POSIXBUILTIN option (off by default) for compatibility with
> +  the POSIX standard.

This should be POSIX_BUILTINS (the s being more important than the _,
but that would consistent with POSIX_ALIASES above).

> +- 'whence -v' is now more informative, and 'whence -S' shows you
> +  how a full chain of symbolic links resolves to a command.
> +
> +- The 'p' parameter flag now allows an argument to be specified
> +  as a referene to a variable, e.g. ${(ps.$sep.)foo} to split $foo
> +  on a string given by $sep.

referene -> reference

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* PATCH: readonly -p with POSIX_BUILTINS
@ 2015-05-07  9:35  8% Peter Stephenson
  2015-05-08 11:43  8% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-05-07  9:35 UTC (permalink / raw)
  To: Zsh Hackers' List

This fixes the POSIX_BUILTINS aspect of "readonly -p" output, i.e. it
needs to show unset variables (the standard is explicit about this).

It doesn't fix the non-POSIX_BUILTINS aspect of "readonly -p" output,
i.e. "er, this output is all a bit broken, isn't it?"  The object
of "readonly -p" is to have a set of commands to restore the current
state: that means it should work without complaint on a new shell (I
don't think it can possibly be required to work once you've already run
it as POSIX doesn't allow you to remove the readonly attribute).  I
think that means not printing values for readonly specials.  Feel free
to argue it shouldn't show readonly specials at all --- if you ran a
script so generated immediately on starting a shell and it included a
readonly special that was loaded from a module, then I think you'd be
screwed.  I'm vaguely inclining that way myself; you don't use the -p
option if you're just listing things for information.

diff --git a/Src/params.c b/Src/params.c
index d53b6ca..9eab51a 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5039,8 +5039,19 @@ printparamnode(HashNode hn, int printflags)
     Param p = (Param) hn;
     char *t, **u;
 
-    if (p->node.flags & PM_UNSET)
-	return;
+    if (p->node.flags & PM_UNSET) {
+	if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
+	    (printflags & PRINT_TYPESET))
+	{
+	    /*
+	     * Special POSIX rules: show the parameter as readonly
+	     * even though it's unset, but with no value.
+	     */
+	    printflags |= PRINT_NAMEONLY;
+	}
+	else
+	    return;
+    }
 
     if (printflags & PRINT_TYPESET)
 	printf("typeset ");
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index f4fb8ec..2edbb0b 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -475,13 +475,15 @@
    print ${+pbro} >&2
    (typeset pbro=3)
    (pbro=4)
+   readonly -p | grep pbro >&2  # shows up as "readonly" although unset
    typeset -r pbro        # idempotent (no error)...
    print ${+pbro} >&2     # ...so still readonly...
    typeset +r pbro        # ...can't turn it off
  )
-1:Readonly with POSIX_BUILTINS
+1:readonly with POSIX_BUILTINS
 ?0
 ?(eval):5: read-only variable: pbro
 ?(eval):6: read-only variable: pbro
+?typeset -r pbro
 ?0
-?(eval):9: read-only variable: pbro
+?(eval):10: read-only variable: pbro


^ permalink raw reply	[relevance 8%]

* Re: PATCH: readonly -p with POSIX_BUILTINS
  2015-05-07  9:35  8% PATCH: readonly -p with POSIX_BUILTINS Peter Stephenson
@ 2015-05-08 11:43  8% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-05-08 11:43 UTC (permalink / raw)
  To: Zsh Hackers' List

On Thu, 7 May 2015 10:35:51 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> It doesn't fix the non-POSIX_BUILTINS aspect of "readonly -p" output,
> i.e. "er, this output is all a bit broken, isn't it?"  The object
> of "readonly -p" is to have a set of commands to restore the current
> state: that means it should work without complaint on a new shell (I
> don't think it can possibly be required to work once you've already run
> it as POSIX doesn't allow you to remove the readonly attribute).  I
> think that means not printing values for readonly specials.  Feel free
> to argue it shouldn't show readonly specials at all --- if you ran a
> script so generated immediately on starting a shell and it included a
> readonly special that was loaded from a module, then I think you'd be
> screwed.  I'm vaguely inclining that way myself; you don't use the -p
> option if you're just listing things for information.

This is what I've done.

pws

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index 5b25290..9699cf3 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1785,6 +1785,11 @@ form of a typeset command and an assignment (which will be printed
 separately for arrays and associative arrays), regardless of other flags
 and options.  Note that the tt(-H) flag on parameters is respected; no
 value will be shown for these parameters.
+
+As the intention of this option is to produce output that can restore
+the current state, readonly specials (whose values cannot be
+changed) are not shown and assignments to arrays are shown before
+the tt(typeset) rendering the array readonly.
 )
 item(tt(-T) [ var(scalar)[tt(=)var(value)] var(array) [ var(sep) ] ])(
 This flag has a different meaning when used with tt(-f); see below.
diff --git a/Src/params.c b/Src/params.c
index 9eab51a..045ac1e 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -5032,78 +5032,11 @@ static const struct paramtypes pmtypes[] = {
 
 #define PMTYPES_SIZE ((int)(sizeof(pmtypes)/sizeof(struct paramtypes)))
 
-/**/
-mod_export void
-printparamnode(HashNode hn, int printflags)
+static void
+printparamvalue(Param p, int printflags)
 {
-    Param p = (Param) hn;
     char *t, **u;
 
-    if (p->node.flags & PM_UNSET) {
-	if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
-	    (printflags & PRINT_TYPESET))
-	{
-	    /*
-	     * Special POSIX rules: show the parameter as readonly
-	     * even though it's unset, but with no value.
-	     */
-	    printflags |= PRINT_NAMEONLY;
-	}
-	else
-	    return;
-    }
-
-    if (printflags & PRINT_TYPESET)
-	printf("typeset ");
-
-    /* Print the attributes of the parameter */
-    if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
-	int doneminus = 0, i;
-	const struct paramtypes *pmptr;
-
-	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
-	    int doprint = 0;
-	    if (pmptr->flags & PMTF_TEST_LEVEL) {
-		if (p->level)
-		    doprint = 1;
-	    } else if (p->node.flags & pmptr->binflag)
-		doprint = 1;
-
-	    if (doprint) {
-		if (printflags & PRINT_TYPESET) {
-		    if (pmptr->typeflag) {
-			if (!doneminus) {
-			    putchar('-');
-			    doneminus = 1;
-			}
-			putchar(pmptr->typeflag);
-		    }
-		} else {
-		    printf("%s ", pmptr->string);
-		}
-		if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
-		    printf("%d ", p->base);
-		    doneminus = 0;
-		}
-		if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
-		    printf("%d ", p->width);
-		    doneminus = 0;
-		}
-	    }
-	}
-	if (doneminus)
-	    putchar(' ');
-    }
-
-    if ((printflags & PRINT_NAMEONLY) ||
-	((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
-	zputs(p->node.nam, stdout);
-	putchar('\n');
-	return;
-    }
-
-    quotedzputs(p->node.nam, stdout);
-
     if (p->node.flags & PM_AUTOLOAD) {
 	putchar('\n');
 	return;
@@ -5112,7 +5045,7 @@ printparamnode(HashNode hn, int printflags)
 	putchar(' ');
     else if ((printflags & PRINT_TYPESET) &&
 	     (PM_TYPE(p->node.flags) == PM_ARRAY || PM_TYPE(p->node.flags) == PM_HASHED))
-	printf("\n%s=", p->node.nam);
+	printf("%s=", p->node.nam);
     else
 	putchar('=');
 
@@ -5171,3 +5104,108 @@ printparamnode(HashNode hn, int printflags)
     else
 	putchar('\n');
 }
+
+/**/
+mod_export void
+printparamnode(HashNode hn, int printflags)
+{
+    Param p = (Param) hn;
+    int array_typeset;
+
+    if (p->node.flags & PM_UNSET) {
+	if (isset(POSIXBUILTINS) && (p->node.flags & PM_READONLY) &&
+	    (printflags & PRINT_TYPESET))
+	{
+	    /*
+	     * Special POSIX rules: show the parameter as readonly
+	     * even though it's unset, but with no value.
+	     */
+	    printflags |= PRINT_NAMEONLY;
+	}
+	else
+	    return;
+    }
+
+    if (printflags & PRINT_TYPESET) {
+	if ((p->node.flags & (PM_READONLY|PM_SPECIAL)) ==
+	    (PM_READONLY|PM_SPECIAL)) {
+	    /*
+	     * It's not possible to restore the state of
+	     * these, so don't output.
+	     */
+	    return;
+	}
+	/*
+	 * Printing the value of array: this needs to be on
+	 * a separate line so more care is required.
+	 */
+	array_typeset = (PM_TYPE(p->node.flags) == PM_ARRAY ||
+			 PM_TYPE(p->node.flags) == PM_HASHED) &&
+	    !(printflags & PRINT_NAMEONLY);
+	if (array_typeset && (p->node.flags & PM_READONLY)) {
+	    /*
+	     * We need to create the array before making it
+	     * readonly.
+	     */
+	    printf("typeset -a ");
+	    zputs(p->node.nam, stdout);
+	    putchar('\n');
+	    printparamvalue(p, printflags);
+	    printflags |= PRINT_NAMEONLY;
+	}
+	printf("typeset ");
+    }
+    else
+	array_typeset = 0;
+
+    /* Print the attributes of the parameter */
+    if (printflags & (PRINT_TYPE|PRINT_TYPESET)) {
+	int doneminus = 0, i;
+	const struct paramtypes *pmptr;
+
+	for (pmptr = pmtypes, i = 0; i < PMTYPES_SIZE; i++, pmptr++) {
+	    int doprint = 0;
+	    if (pmptr->flags & PMTF_TEST_LEVEL) {
+		if (p->level)
+		    doprint = 1;
+	    } else if (p->node.flags & pmptr->binflag)
+		doprint = 1;
+
+	    if (doprint) {
+		if (printflags & PRINT_TYPESET) {
+		    if (pmptr->typeflag) {
+			if (!doneminus) {
+			    putchar('-');
+			    doneminus = 1;
+			}
+			putchar(pmptr->typeflag);
+		    }
+		} else {
+		    printf("%s ", pmptr->string);
+		}
+		if ((pmptr->flags & PMTF_USE_BASE) && p->base) {
+		    printf("%d ", p->base);
+		    doneminus = 0;
+		}
+		if ((pmptr->flags & PMTF_USE_WIDTH) && p->width) {
+		    printf("%d ", p->width);
+		    doneminus = 0;
+		}
+	    }
+	}
+	if (doneminus)
+	    putchar(' ');
+    }
+
+    if ((printflags & PRINT_NAMEONLY) ||
+	((p->node.flags & PM_HIDEVAL) && !(printflags & PRINT_INCLUDEVALUE))) {
+	zputs(p->node.nam, stdout);
+	putchar('\n');
+    } else {
+	quotedzputs(p->node.nam, stdout);
+
+	if (array_typeset)
+	    putchar('\n');
+	printparamvalue(p, printflags);
+    }
+}
diff --git a/Test/B02typeset.ztst b/Test/B02typeset.ztst
index 2edbb0b..9009619 100644
--- a/Test/B02typeset.ztst
+++ b/Test/B02typeset.ztst
@@ -487,3 +487,24 @@
 ?typeset -r pbro
 ?0
 ?(eval):10: read-only variable: pbro
+
+  readonly foo=bar novalue
+  readonly -p
+0:readonly -p output (no readonly specials)
+>typeset -r foo=bar
+>typeset -r novalue=''
+
+  local -a a1 a2
+  local -r r1=yes r2=no
+  a1=(one two) a2=(three four)
+  readonly a1
+  typeset -pm 'a[12]'
+  typeset -pm 'r[12]'
+0:readonly -p output
+>typeset -a a1
+>a1=(one two)
+>typeset -ar a1
+>typeset -a a2
+>a2=(three four)
+>typeset -r r1=yes
+>typeset -r r2=no


^ permalink raw reply	[relevance 8%]

* 'case' pattern matching bug with bracket expressions
@ 2015-05-14 13:14  5% Martijn Dekker
  2015-05-14 14:42  2% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-05-14 13:14 UTC (permalink / raw)
  To: zsh-workers

While writing a cross-platform shell library I've come across a bug in
the way zsh (in POSIX mode) matches patterns in 'case' statements that
are at variance with other POSIX shells.

Normally, zsh considers an empty bracket expression [] a bad pattern
while other shells ([d]ash, bash, ksh) consider it a negative:

case abc in ( [] ) echo yes ;; ( * ) echo no ;; esac

Expected output: no
Got output: zsh: bad pattern: []

This is inconvenient if you want to pass such a bracket expression in a
parameter or variable, e.g. ["$param"]. If the parameter or variable is
empty, a 'bad pattern: []' error is produced.

I'm not sure whether the above is a bug or a variance in behaviour
permitted by POSIX, though of course as a writer of cross-platform shell
programs I'd prefer it if zsh acted like the majority.

However, I'm quite sure the following is a serious bug.

The same thing does NOT produce an error, but a false positive (!), if
an extra non-matching pattern with | is added:

case abc in ( [] | *[!a-z]*) echo yes ;; ( * ) echo no ;; esac

Expected output: no
Got output: yes

The above needs to be tested in a non-interactive shell (i.e. a script)
due to the "!". Other shells I've tested (bash, dash, ksh, pdksh, mksh)
behave as expected.

I confirmed the bug in zsh 4.3.11, zsh 5.0.2 and zsh 5.0.7-dev-2.

Thanks,

- Martijn


^ permalink raw reply	[relevance 5%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 13:14  5% 'case' pattern matching bug with bracket expressions Martijn Dekker
@ 2015-05-14 14:42  2% ` Peter Stephenson
                       ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Peter Stephenson @ 2015-05-14 14:42 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers

On Thu, 14 May 2015 14:14:26 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> While writing a cross-platform shell library I've come across a bug in
> the way zsh (in POSIX mode) matches patterns in 'case' statements that
> are at variance with other POSIX shells.
> 
> Normally, zsh considers an empty bracket expression [] a bad pattern
> while other shells ([d]ash, bash, ksh) consider it a negative:
> 
> case abc in ( [] ) echo yes ;; ( * ) echo no ;; esac
> 
> Expected output: no
> Got output: zsh: bad pattern: []

This is the shell language being typically duplicitous and unhelpful.
"]" after a "[" indicates that the "]" is part of the set.  This is
normal; in bash as well as zsh:

  [[ ']' = []] ]] && echo yes

outputs 'yes'.

However, as you've found out, other shells handle the case where there
isn't another ']' later.  Generally there's no harm in this, and in most
cases we could do this (the case below is harder).

Nonetheless, there's a real ambiguity here, so given this and the
following I'd definitely suggest not relying on it if you can avoid
doing so --- use something else to signify an empty string.

> The same thing does NOT produce an error, but a false positive (!), if
> an extra non-matching pattern with | is added:
> 
> case abc in ( [] | *[!a-z]*) echo yes ;; ( * ) echo no ;; esac

This is the pattern:
 '['                   introducing bracketed expression
   '] | *[!a-z'        characters inside
 ']'                   end of bracketed expression
 '*'                   wildcard.

so it's a set including the character a followed by anything, and hence
matches.

I'm not really sure we *can* resolve this unambiguously the way you
want.  Is there something that forbids us from interpreting the pattern
that way?  The handling of ']' at the start is mandated, if I've
followed all the logic corretly --- POSIX 2007 Shell and Utilities
2.13.1 says:

[
    If an open bracket introduces a bracket expression as in XBD RE
    Bracket Expression, except that the <exclamation-mark> character (
    '!' ) shall replace the <circumflex> character ( '^' ) in its role
    in a non-matching list in the regular expression notation, it shall
    introduce a pattern bracket expression. A bracket expression
    starting with an unquoted <circumflex> character produces
    unspecified results. Otherwise, '[' shall match the character
    itself.

The languaqge is a little turgid, but I think it's saying "unless
you have ^ or [ just go with the RE rules in [section 9.3.5]".

9.3.5 (in regular expressions) says, amongst a lot of other things:

   The <right-square-bracket> ( ']' ) shall lose its special meaning and
   represent itself in a bracket expression if it occurs first in the
   list (after an initial <circumflex> ( '^' ), if any)

That's a "shall".

I haven't read through the "case" doc so there may be some killer reason
why that " | " has to be a case separator and not part of a
square-bracketed expression.  But that would seem to imply some form of
hierarchical parsing in which those characters couldn't occur within a
pattern.

By the way, we don't handle all forms in 9.3.5, e.g. equivalence sets,
so saying "it works like REs" isn't a perfect answer for zsh, either.

pws


^ permalink raw reply	[relevance 2%]

* Re: 'case' pattern matching bug with bracket expressions
  @ 2015-05-14 15:55  3%     ` Peter Stephenson
  2015-05-14 17:30  3%       ` Bart Schaefer
  2015-05-15  8:38  3%       ` Peter Stephenson
    1 sibling, 2 replies; 200+ results
From: Peter Stephenson @ 2015-05-14 15:55 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers

On Thu, 14 May 2015 16:47:49 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> Peter Stephenson schreef op 14-05-15 om 15:42:
> > This is the pattern:
> >  '['                   introducing bracketed expression
> >    '] | *[!a-z'        characters inside
> >  ']'                   end of bracketed expression
> >  '*'                   wildcard.
> 
> Ah ha, that makes sense of the whole thing. Thank you.
> 
> > I'm not really sure we *can* resolve this unambiguously the way you
> > want.  Is there something that forbids us from interpreting the pattern
> > that way?
> 
> Apparently not, as far as I can tell.

It occurs to me that other shells will treat whitespace as ending a
pattern for syntactic reasons, even if logically it can't:

[[ ' ' = [ ] ]]

works in zsh, but is a parse error in bash.

Usually zsh's behaviour is the more useful, because if the expression is
meaningful at all there has to be a closing brace(*).  But it's not
impossible it does break some rule about whitespace as separators ---
and you've come up with the first example I've ever seen of where it's
significant even if the alternative isn't an error.  So it might
be more useful to change this in POSIX compatibility mode, in which what
zsh users expect has never been a significant factor.

pws

(*) Relegated to a footnote because this is more of a rant than
a useful comment:  furthermore, the whole []] thing is designed
so that you *don't* need to quote characters in the [...].  So
do you, or don't you?  Bleugh.


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 15:55  3%     ` Peter Stephenson
@ 2015-05-14 17:30  3%       ` Bart Schaefer
  2015-05-15  0:05  3%         ` Chet Ramey
  2015-05-15  8:38  3%       ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2015-05-14 17:30 UTC (permalink / raw)
  To: zsh-workers

On May 14,  4:55pm, Peter Stephenson wrote:
}
} It occurs to me that other shells will treat whitespace as ending a
} pattern for syntactic reasons, even if logically it can't:
} 
} [[ ' ' = [ ] ]]
} 
} works in zsh, but is a parse error in bash.

Right, and your patch in 35131 does not change that.  Arguably (in POSIX
mode, at least) the space should need to be escaped?

Even in bash the space can be left unescaped in some contexts; e.g.

schaefer@burner:~$ var=' '
schaefer@burner:~$ echo ${var//[ ]/foo}
foo

I guess it's a quoting thing:

schaefer@burner:~$ case " " in ( [" "] ) echo OK;; esac
OK

In ${...} the space is already implicitly quoted, but quoting it again
doesn't change anything:

schaefer@burner:~$ echo ${var//[" "]/foo}
foo
schaefer@burner:~$ var='"'
schaefer@burner:~$ echo ${var//[" "]/foo}
"

Anyway, this is one of the rare cases where I don't think it would be
terrible if this changed in native zsh mode too, as long as the quoted
examples, like the above, don't break.

-- 
Barton E. Schaefer


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  @ 2015-05-14 17:43  3%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-05-14 17:43 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers

On Thu, 14 May 2015 18:07:39 +0100
Martijn Dekker <martijn@inlv.org> wrote:
> However, the more insidious case that bit me:
> 
> case abc in ( [] | [!a-z]* ) echo yes ;; ( * ) echo no ;; esac
> empty=''
> case abc in ( ["$empty"] | [!a-z]* ) echo yes ;; ( * ) echo no ;; esac
> 
> still produces a false positive even with the patch.

This is hairy because you're relying on whitespace performing word
splitting in a case where you don't need whitespace according to the
grammar anyway, i.e. if you have the valid expression

case abc in (["$empty"]|[!a-z]*) echo yes ;; (*) echo no ;; esac

it can only be parsed the way zsh parses it --- you'll find bash does
the same.

I'll have a look at changing the way we handle whitespace in
bracketed expressions in POSIX mode (POSIX_STRINGS option?  That's
about the closest I can see and underworked at the moment).

The above still needs some work, though, since we don't currently word
split case statements.  I think that probably is required by the
standard since it specifies word (though not word list) handling,
i.e. implying the same as command line words but with an additional "|"
token between words.  That's probably going to have to wait till after
5.0.8.

pws


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 14:42  2% ` Peter Stephenson
  @ 2015-05-14 21:23  3%   ` Chet Ramey
  2015-05-14 23:45  0%   ` Chet Ramey
  2 siblings, 0 replies; 200+ results
From: Chet Ramey @ 2015-05-14 21:23 UTC (permalink / raw)
  To: Peter Stephenson, Martijn Dekker, zsh-workers; +Cc: chet.ramey

On 5/14/15 10:42 AM, Peter Stephenson wrote:

> This is the pattern:
>  '['                   introducing bracketed expression
>    '] | *[!a-z'        characters inside
>  ']'                   end of bracketed expression
>  '*'                   wildcard.
> 
> so it's a set including the character a followed by anything, and hence
> matches.
> 
> I'm not really sure we *can* resolve this unambiguously the way you
> want.  Is there something that forbids us from interpreting the pattern
> that way?  

Look at the Posix grammar.  A case pattern list is a sequence of one
or more WORDs separated by (zero or more) `|'s.  WORDs are delimited by
metacharacters and cannot contain unquoted blanks.  The `[]' is a
separate WORD delimited by a space.

The rules governing how the pattern is treated only come into play
after the command is parsed.

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


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 14:42  2% ` Peter Stephenson
    2015-05-14 21:23  3%   ` Chet Ramey
@ 2015-05-14 23:45  0%   ` Chet Ramey
  2 siblings, 0 replies; 200+ results
From: Chet Ramey @ 2015-05-14 23:45 UTC (permalink / raw)
  To: Peter Stephenson, Martijn Dekker, zsh-workers; +Cc: chet.ramey

On 5/14/15 10:42 AM, Peter Stephenson wrote:

> The handling of ']' at the start is mandated, if I've
> followed all the logic corretly --- POSIX 2007 Shell and Utilities
> 2.13.1 says:
> 
> [
>     If an open bracket introduces a bracket expression as in XBD RE
>     Bracket Expression, except that the <exclamation-mark> character (
>     '!' ) shall replace the <circumflex> character ( '^' ) in its role
>     in a non-matching list in the regular expression notation, it shall
>     introduce a pattern bracket expression. A bracket expression
>     starting with an unquoted <circumflex> character produces
>     unspecified results. Otherwise, '[' shall match the character
>     itself.
> 
> The languaqge is a little turgid, but I think it's saying "unless
> you have ^ or [ just go with the RE rules in [section 9.3.5]".

I think it means that improperly-formed pattern bracket expressions have
to be matched by a literal `[' followed by whatever the following
characters mean.

> I haven't read through the "case" doc so there may be some killer reason
> why that " | " has to be a case separator and not part of a
> square-bracketed expression.  But that would seem to imply some form of
> hierarchical parsing in which those characters couldn't occur within a
> pattern.

It's the grammar.  If you want `|' to be in a pattern you have to quote it.
Otherwise it's a metacharacter and a token delimiter (section 2.2).

The basic idea is that you tokenize case patterns as words and analyze them
as patterns after doing so.

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


^ permalink raw reply	[relevance 0%]

* Re: 'case' pattern matching bug with bracket expressions
    @ 2015-05-14 23:59  3%       ` Chet Ramey
  1 sibling, 0 replies; 200+ results
From: Chet Ramey @ 2015-05-14 23:59 UTC (permalink / raw)
  To: Peter Stephenson, Martijn Dekker, zsh-workers; +Cc: chet.ramey

On 5/14/15 12:17 PM, Peter Stephenson wrote:

> I don't *think* the following patch makes anything worse, but notice
> you're in any case on fairly soggy ground here, even in bash:
> 
> $ var=
> $ [[ ']' = [$var]*[$var] ]] && echo matches
> matches
> 
> and presumably Chet would agree with me that's required by the
> standard.

Yes, everybody matches `]' with that pattern.  Posix requires that the
`case' equivalent match (`[[' is not in the standard), since it specifies
the expansions that take place on the pattern before you attempt
matching using the pattern matching rules.

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


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 17:30  3%       ` Bart Schaefer
@ 2015-05-15  0:05  3%         ` Chet Ramey
  0 siblings, 0 replies; 200+ results
From: Chet Ramey @ 2015-05-15  0:05 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers; +Cc: chet.ramey

On 5/14/15 1:30 PM, Bart Schaefer wrote:

> Even in bash the space can be left unescaped in some contexts; e.g.
> 
> schaefer@burner:~$ var=' '
> schaefer@burner:~$ echo ${var//[ ]/foo}
> foo

Yes.  Inside ${...}, the space doesn't delimit a token.  The Posix
tokenizing rules specify that.

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


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  2015-05-14 15:55  3%     ` Peter Stephenson
  2015-05-14 17:30  3%       ` Bart Schaefer
@ 2015-05-15  8:38  3%       ` Peter Stephenson
    1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2015-05-15  8:38 UTC (permalink / raw)
  To: Peter Stephenson, zsh-workers

On Thu, 14 May 2015 16:55:57 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> It occurs to me that other shells will treat whitespace as ending a
> pattern for syntactic reasons, even if logically it can't:
> 
> [[ ' ' = [ ] ]]
> 
> works in zsh, but is a parse error in bash.

I'm talking nonsense here --- I'm thinking of parentheses (which have
always been subtle because of zsh's pattern syntax and work differently
in POSIX mode anyway).  A space after a square bracket *does* split the
word.

Otherwise we wouldn't know whether "[ " at the start of the line was a
test command or the start of a group.

I don't think changing the case parsing to do proper words is *that*
difficult --- it's always been a bit of a hack, so could do with
being fixed.

pws


^ permalink raw reply	[relevance 3%]

* Re: 'case' pattern matching bug with bracket expressions
  @ 2015-05-15 21:48  3%           ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-05-15 21:48 UTC (permalink / raw)
  To: zsh-workers

On May 15,  9:48pm, Peter Stephenson wrote:
} Subject: Re: 'case' pattern matching bug with bracket expressions
}
} On Fri, 15 May 2015 09:38:51 +0100
} Peter Stephenson <p.stephenson@samsung.com> wrote:
} > I don't think changing the case parsing to do proper words is *that*
} > difficult --- it's always been a bit of a hack, so could do with
} > being fixed.
} 
} I'm on the case, but just to note this isn't completely benign.  There
} are (few) places in functions where we rely on the fact that anything in
} parentheses is parsed as a single quoted string, which won't happen any
} more.

Hm.  It appears we always parsed this "correctly" when using the old style
case statment:

torch% case "foo bar baz" in
case> foo bar *) echo here;;
zsh: parse error near `bar'

So perhaps the most benign thing is to apply the word parsing inside the
matched parens only in some sort of POSIX mode?

} I don't want to have to propagate the
} existing hack any more, however, so this isn't really possible to work
} around.

Urm.  OK.


^ permalink raw reply	[relevance 3%]

* PATCH: case pattern parsing
@ 2015-05-17 20:53  2% Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-05-17 20:53 UTC (permalink / raw)
  To: Zsh hackers list

This patch parses case patterns properly, removing the hack that
alternation was done by "|" within a single pattern that was shifted
around to remove spaces.  It should also means cases with and without a
leading "(" are parsed the same way.

Because of the change in wordcode I've updated the version number.

I have some ideas about how to get back (most of) the feature that it
was possible to use multiple words in a pattern, but this time with some
help from the lexer.  However, that's not in yet and I don't have time
to do it right now.  I've updated all the case statements in completion
functions I could see so they should work anyway.

As an additional bonus, I can now read the loop.c code that handled
cases without gibbering loudly about the programme counter arithmetic.

pws

diff --git a/Completion/Unix/Command/_ant b/Completion/Unix/Command/_ant
index 8e4bd82..ee9f7d9 100644
--- a/Completion/Unix/Command/_ant
+++ b/Completion/Unix/Command/_ant
@@ -123,8 +123,7 @@ case $state in
                     # Output target again indicating its the default one.
                     print -n "'${default_target}:(Default target) ' "
                 ;;
-                (Searching:*|Main:targets:|Subtargets:|BUILD:SUCCESSFUL|Total:time:
-                *)
+                (Searching:*|Main:targets:|Subtargets:|BUILD:SUCCESSFUL|Total:time:*)
                 ;;
                 (*)
                     # Return target and description
diff --git a/Completion/Unix/Command/_cp b/Completion/Unix/Command/_cp
index 4c4dea2..7087b4e 100644
--- a/Completion/Unix/Command/_cp
+++ b/Completion/Unix/Command/_cp
@@ -13,7 +13,7 @@ if _pick_variant gnu=GNU unix --version; then
     '-H[follow command-line symbolic links]' \
     '(-l --link)'{-l,--link}'[link files instead of copying]' \
     '(-L --dereference)'{-L,--dereference}'[always follow symbolic links]' \
-    (-n --no-clobber -i --interactive){-n,--no-clobber}"[don't overwrite an existing file]" \
+    '(-n --no-clobber -i --interactive)'{-n,--no-clobber}"[don't overwrite an existing file]" \
     '(-P --no-dereference)'{-P,--no-dereference}'[never follow symbolic links]' \
     '-p[same as --preserve=mode,ownership,timestamps]' \
     '--preserve=-[preserve specified attributes]:: :_values -s , attribute mode timestamps ownership links context xattr all' \
diff --git a/Completion/Unix/Command/_locate b/Completion/Unix/Command/_locate
index 0b35b7c..694f506 100644
--- a/Completion/Unix/Command/_locate
+++ b/Completion/Unix/Command/_locate
@@ -25,7 +25,7 @@ case $basename in
     ltype=gnu
     ;;
 
-    (*illegal option*)
+    (*"illegal option"*)
     if [[ $OSTYPE == (freebsd|openbsd|dragonfly|darwin)* ]]; then
       ltype=bsd
     else
diff --git a/Completion/Unix/Command/_make b/Completion/Unix/Command/_make
index 225c0af..c14a34c 100644
--- a/Completion/Unix/Command/_make
+++ b/Completion/Unix/Command/_make
@@ -65,7 +65,7 @@ _make-parseMakefile () {
   do
     case "$input " in
       # VARIABLE = value OR VARIABLE ?= value
-      ([[:alnum:]][[:alnum:]_]#[ $TAB]#(\?|)=*)
+      ([[:alnum:]][[:alnum:]_]#[" "$TAB]#(\?|)=*)
       var=${input%%[ $TAB]#(\?|)=*}
       val=${input#*=}
       val=${val##[ $TAB]#}
@@ -74,7 +74,7 @@ _make-parseMakefile () {
 
       # VARIABLE := value OR VARIABLE ::= value
       # Evaluated immediately
-      ([[:alnum:]][[:alnum:]_]#[ $TAB]#:(:|)=*)
+      ([[:alnum:]][[:alnum:]_]#[" "$TAB]#:(:|)=*)
       var=${input%%[ $TAB]#:(:|)=*}
       val=${input#*=}
       val=${val##[ $TAB]#}
@@ -97,7 +97,7 @@ _make-parseMakefile () {
       ;;
 
       # Include another makefile
-      (${~incl} *)
+      (${~incl}" "*)
       local f=${input##${~incl} ##}
       if [[ $incl == '.include' ]]
       then
diff --git a/Completion/Unix/Command/_tar b/Completion/Unix/Command/_tar
index ce58524..1e99ac0 100644
--- a/Completion/Unix/Command/_tar
+++ b/Completion/Unix/Command/_tar
@@ -23,7 +23,7 @@ local _tar_cmd tf tmp tmpb del index
 
 if _pick_variant gnu=GNU unix --version; then
   case "$($service --version)" in
-    (tar \(GNU tar\) (#b)([0-9.-]##)*)
+    ("tar (GNU tar) "(#b)([0-9.-]##)*)
     autoload -z is-at-least
     is-at-least 1.14.91 "$match[1]" || _cmd_variant[$service]="gnu-old"
     ;;
diff --git a/Completion/Unix/Type/_path_commands b/Completion/Unix/Type/_path_commands
index 22d2aae..423563c 100644
--- a/Completion/Unix/Type/_path_commands
+++ b/Completion/Unix/Type/_path_commands
@@ -25,7 +25,7 @@ return 1
 
 _call_whatis() { 
   case "$(whatis --version)" in
-  (whatis from *)
+  ("whatis from "*)
     local -A args
     zparseopts -D -A args s: r:
     apropos "${args[-r]:-"$@"}" | fgrep "($args[-s]"
diff --git a/Completion/X/Command/_xrandr b/Completion/X/Command/_xrandr
index 9d9323c..b085156 100644
--- a/Completion/X/Command/_xrandr
+++ b/Completion/X/Command/_xrandr
@@ -51,7 +51,7 @@ _arguments -C \
 case $state in
   value)
     case $words[CURRENT-1] in
-      (scaling* mode)
+      (scaling*" mode")
 	_description value expl "output property 'scaling mode'"
 	compadd "$@" "$expl[@]" None Full Center Full\ aspect && return 0
       ;;
diff --git a/Config/version.mk b/Config/version.mk
index d04d57d..acab748 100644
--- a/Config/version.mk
+++ b/Config/version.mk
@@ -27,5 +27,5 @@
 # This must also serve as a shell script, so do not add spaces around the
 # `=' signs.
 
-VERSION=5.0.7-dev-2
-VERSION_DATE='May 5, 2015'
+VERSION=5.0.7-dev-3
+VERSION_DATE='May 17, 2015'
diff --git a/Src/lex.c b/Src/lex.c
index 841fb0b..87b0cd3 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -761,6 +761,8 @@ gettok(void)
 	lexstop = 0;
 	return BAR;
     case LX1_INPAR:
+	if (incasepat == 2)
+	    return INPAR;
 	d = hgetc();
 	if (d == '(') {
 	    if (infor) {
diff --git a/Src/loop.c b/Src/loop.c
index d025fbb..e4e8e2d 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -545,7 +545,7 @@ execcase(Estate state, int do_exec)
     Wordcode end, next;
     wordcode code = state->pc[-1];
     char *word, *pat;
-    int npat, save;
+    int npat, save, nalts, ialt, patok;
     Patprog *spprog, pprog;
 
     end = state->pc + WC_CASE_SKIP(code);
@@ -561,60 +561,74 @@ execcase(Estate state, int do_exec)
 	if (wc_code(code) != WC_CASE)
 	    break;
 
-	pat = NULL;
-	pprog = NULL;
 	save = 0;
-	npat = state->pc[1];
-	spprog = state->prog->pats + npat;
-
 	next = state->pc + WC_CASE_SKIP(code);
+	nalts = *state->pc++;
+	ialt = patok = 0;
 
 	if (isset(XTRACE)) {
-	    char *opat;
-
-	    pat = dupstring(opat = ecrawstr(state->prog, state->pc, NULL));
-	    singsub(&pat);
-	    save = (!(state->prog->flags & EF_HEAP) &&
-		    !strcmp(pat, opat) && *spprog != dummy_patprog2);
-
 	    printprompt4();
 	    fprintf(xtrerr, "case %s (", word);
-	    quote_tokenized_output(pat, xtrerr);
-	    fprintf(xtrerr, ")\n");
-	    fflush(xtrerr);
 	}
-	state->pc += 2;
 
-	if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
-	    pprog = *spprog;
-
-	if (!pprog) {
-	    if (!pat) {
-		char *opat;
+	while (!patok && nalts) {
+	    npat = state->pc[1];
+	    spprog = state->prog->pats + npat;
+	    pprog = NULL;
+	    pat = NULL;
+	
+	    if (isset(XTRACE)) {
 		int htok = 0;
-
-		pat = dupstring(opat = ecrawstr(state->prog,
-						state->pc - 2, &htok));
+		pat = dupstring(ecrawstr(state->prog, state->pc, &htok));
 		if (htok)
 		    singsub(&pat);
-		save = (!(state->prog->flags & EF_HEAP) &&
-			!strcmp(pat, opat) && *spprog != dummy_patprog2);
+
+		if (ialt++)
+		    fprintf(stderr, " | ");
+		quote_tokenized_output(pat, xtrerr);
 	    }
-	    if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
-				     NULL)))
-		zerr("bad pattern: %s", pat);
-	    else if (save)
-		*spprog = pprog;
+
+	    if (*spprog != dummy_patprog1 && *spprog != dummy_patprog2)
+		pprog = *spprog;
+
+	    if (!pprog) {
+		if (!pat) {
+		    char *opat;
+		    int htok = 0;
+
+		    pat = dupstring(opat = ecrawstr(state->prog,
+						    state->pc, &htok));
+		    if (htok)
+			singsub(&pat);
+		    save = (!(state->prog->flags & EF_HEAP) &&
+			    !strcmp(pat, opat) && *spprog != dummy_patprog2);
+		}
+		if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
+					 NULL)))
+		    zerr("bad pattern: %s", pat);
+		else if (save)
+		    *spprog = pprog;
+	    }
+	    if (pprog && pattry(pprog, word))
+		patok = 1;
+	    state->pc += 2;
+	    nalts--;
+	}
+	state->pc += 2 * nalts;
+	if (isset(XTRACE)) {
+	    fprintf(xtrerr, ")\n");
+	    fflush(xtrerr);
 	}
-	if (pprog && pattry(pprog, word)) {
+	if (patok) {
 	    execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
 				do_exec));
 	    while (!retflag && wc_code(code) == WC_CASE &&
 		   WC_CASE_TYPE(code) == WC_CASE_AND) {
 		state->pc = next;
-		code = *state->pc;
-		state->pc += 3;
-		next = state->pc + WC_CASE_SKIP(code) - 2;
+		code = *state->pc++;
+		next = state->pc + WC_CASE_SKIP(code);
+		nalts = *state->pc++;
+		state->pc += 2 * nalts;
 		execlist(state, 1, ((WC_CASE_TYPE(code) == WC_CASE_OR) &&
 				    do_exec));
 	    }
diff --git a/Src/parse.c b/Src/parse.c
index 985eb8e..c938d2d 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -349,9 +349,8 @@ ecadd(wordcode c)
 	eclen += a;
     }
     ecbuf[ecused] = c;
-    ecused++;
 
-    return ecused - 1;
+    return ecused++;
 }
 
 /* Delete a wordcode. */
@@ -1128,7 +1127,7 @@ par_for(int *cmplx)
 static void
 par_case(int *cmplx)
 {
-    int oecused = ecused, brflag, p, pp, n = 1, type;
+    int oecused = ecused, brflag, p, pp, palts, type, nalts;
     int ona, onc;
 
     p = ecadd(0);
@@ -1153,7 +1152,7 @@ par_case(int *cmplx)
 	YYERRORV(oecused);
     }
     brflag = (tok == INBRACE);
-    incasepat = 1;
+    incasepat = 2;
     incmdpos = 0;
     noaliases = ona;
     nocorrect = onc;
@@ -1166,8 +1165,10 @@ par_case(int *cmplx)
 	    zshlex();
 	if (tok == OUTBRACE)
 	    break;
-	if (tok == INPAR)
+	if (tok == INPAR) {
+	    incasepat = 1;
 	    zshlex();
+	}
 	if (tok != STRING)
 	    YYERRORV(oecused);
 	if (!strcmp(tokstr, "esac"))
@@ -1176,89 +1177,45 @@ par_case(int *cmplx)
 	incasepat = 0;
 	incmdpos = 1;
 	type = WC_CASE_OR;
+	pp = ecadd(0);
+	palts = ecadd(0);
+	nalts = 0;
 	for (;;) {
+	    ecstr(str);
+	    ecadd(ecnpats++);
+	    nalts++;
+
 	    zshlex();
 	    if (tok == OUTPAR) {
 		incasepat = 0;
 		incmdpos = 1;
 		zshlex();
 		break;
-	    } else if (tok == BAR) {
-		char *str2;
-		int sl = strlen(str);
-
-		incasepat = 1;
-		incmdpos = 0;
-		str2 = hcalloc(sl + 2);
-		strcpy(str2, str);
-		str2[sl] = Bar;
-		str2[sl+1] = '\0';
-		str = str2;
-	    } else {
-		int sl = strlen(str);
-
-		if (!sl || str[sl - 1] != Bar) {
-		    /* POSIX allows (foo*) patterns */
-		    int pct;
-		    char *s;
-
-		    for (s = str, pct = 0; *s; s++) {
-			if (*s == Inpar)
-			    pct++;
-			if (!pct)
-			    break;
-			if (pct == 1) {
-			    if (*s == Bar || *s == Inpar)
-				while (iblank(s[1]))
-				    chuck(s+1);
-			    if (*s == Bar || *s == Outpar)
-				while (iblank(s[-1]) &&
-				       (s < str + 1 || s[-2] != Meta))
-				    chuck(--s);
-			}
-			if (*s == Outpar)
-			    pct--;
-		    }
-		    if (*s || pct || s == str)
-			YYERRORV(oecused);
-		    /* Simplify pattern by removing surrounding (...) */
-		    sl = strlen(str);
-		    DPUTS(*str != Inpar || str[sl - 1] != Outpar,
-			  "BUG: strange case pattern");
-		    str[sl - 1] = '\0';
-		    chuck(str);
-		    break;
-		} else {
-		    char *str2;
-
-		    if (tok != STRING)
-			YYERRORV(oecused);
-		    str2 = hcalloc(sl + strlen(tokstr) + 1);
-		    strcpy(str2, str);
-		    strcpy(str2 + sl, tokstr);
-		    str = str2;
-		}
-	    }
+	    } else if (tok != BAR)
+		YYERRORV(oecused);
+
+	    zshlex();
+	    if (tok != STRING)
+		YYERRORV(oecused);
+	    str = dupstring(tokstr);
 	}
-	pp = ecadd(0);
-	ecstr(str);
-	ecadd(ecnpats++);
 	par_save_list(cmplx);
-	n++;
 	if (tok == SEMIAMP)
 	    type = WC_CASE_AND;
 	else if (tok == SEMIBAR)
 	    type = WC_CASE_TESTAND;
 	ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp);
+	ecbuf[palts] = nalts;
 	if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag))
 	    break;
 	if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR)
 	    YYERRORV(oecused);
-	incasepat = 1;
+	incasepat = 2;
 	incmdpos = 0;
 	zshlex();
     }
     incmdpos = 1;
+    incasepat = 0;
     zshlex();
 
     ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p);
diff --git a/Src/text.c b/Src/text.c
index b58c251..958303c 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -602,6 +602,7 @@ gettext2(Estate state)
 	case WC_CASE:
 	    if (!s) {
 		Wordcode end = state->pc + WC_CASE_SKIP(code);
+		wordcode nalts;
 
 		taddstr("case ");
 		taddstr(ecgetstr(state, EC_NODUP, NULL));
@@ -622,8 +623,13 @@ gettext2(Estate state)
 			taddchr(' ');
 		    taddstr("(");
 		    code = *state->pc++;
-		    taddstr(ecgetstr(state, EC_NODUP, NULL));
-		    state->pc++;
+		    nalts = *state->pc++;
+		    while (nalts--) {
+			taddstr(ecgetstr(state, EC_NODUP, NULL));
+			state->pc++;
+			if (nalts)
+			    taddstr(" | ");
+		    }
 		    taddstr(") ");
 		    tindent++;
 		    n = tpush(code, 0);
@@ -631,6 +637,7 @@ gettext2(Estate state)
 		    n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
 		}
 	    } else if (state->pc < s->u._case.end) {
+		wordcode nalts;
 		dec_tindent();
 		switch (WC_CASE_TYPE(code)) {
 		case WC_CASE_OR:
@@ -638,11 +645,11 @@ gettext2(Estate state)
 		    break;
 
 		case WC_CASE_AND:
-		    taddstr(";&");
+		    taddstr(" ;&");
 		    break;
 
 		default:
-		    taddstr(";|");
+		    taddstr(" ;|");
 		    break;
 		}
 		if (tnewlins)
@@ -651,8 +658,13 @@ gettext2(Estate state)
 		    taddchr(' ');
 		taddstr("(");
 		code = *state->pc++;
-		taddstr(ecgetstr(state, EC_NODUP, NULL));
-		state->pc++;
+		nalts = *state->pc++;
+		while (nalts--) {
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    state->pc++;
+		    if (nalts)
+			taddstr(" | ");
+		}
 		taddstr(") ");
 		tindent++;
 		s->code = code;
@@ -666,11 +678,11 @@ gettext2(Estate state)
 		    break;
 
 		case WC_CASE_AND:
-		    taddstr(";&");
+		    taddstr(" ;&");
 		    break;
 
 		default:
-		    taddstr(";|");
+		    taddstr(" ;|");
 		    break;
 		}
 		dec_tindent();
diff --git a/Test/A01grammar.ztst b/Test/A01grammar.ztst
index 2de2919..1ba0a54 100644
--- a/Test/A01grammar.ztst
+++ b/Test/A01grammar.ztst
@@ -572,6 +572,7 @@
   $ZTST_testdir/../Src/zsh -f myscript
 127q:PATHSCRIPT option not used.
 ?$ZTST_testdir/../Src/zsh: can't open input file: myscript
+# '
 
   $ZTST_testdir/../Src/zsh -fc 'echo $0; echo $1' myargzero myargone
 0:$0 is traditionally if bizarrely set to the first argument with -c
@@ -611,3 +612,41 @@
 >BEGIN
 >mytrue
 >END
+
+  fn() {
+    case $1 in
+      ( one | two | three )
+      print Matched $1
+      ;;
+      ( fo* | fi* | si* )
+      print Pattern matched $1
+      ;;
+      ( []x | a[b]* )
+      print Character class matched $1
+      ;;
+    esac
+  }
+  which fn
+  fn one
+  fn two
+  fn three
+  fn four
+  fn five
+  fn six
+  fn abecedinarian
+  fn xylophone
+0: case word handling
+>fn () {
+>	case $1 in
+>		(one | two | three) print Matched $1 ;;
+>		(fo* | fi* | si*) print Pattern matched $1 ;;
+>		([]x | a[b]*) print Character class matched $1 ;;
+>	esac
+>}
+>Matched one
+>Matched two
+>Matched three
+>Pattern matched four
+>Pattern matched five
+>Pattern matched six
+>Character class matched abecedinarian


^ permalink raw reply	[relevance 2%]

* Re: Pattern matching: backslash escaping not active in pattern passed from variable
  @ 2015-05-18  8:49  3%   ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-05-18  8:49 UTC (permalink / raw)
  To: Mikael Magnusson, zsh workers

On Mon, 18 May 2015 10:33:31 +0200
Mikael Magnusson <mikachu@gmail.com> wrote:
> On Mon, May 18, 2015 at 5:07 AM, Martijn Dekker <martijn@inlv.org> wrote:
> > Peter Stephenson's patch for case pattern matching applied cleanly
> > against the latest git code and is working perfectly. Many thanks.
> >
> > There is another snag I've found in pattern matching, which seems to
> > have survived this patch: backslash escaping does not seem match the
> > standard if a glob pattern is passed from a variable or parameter. The
> > standard says:
> [...]
> > In any case, I would expect backslash escaping to work the same way
> > whether the glob pattern is passed from a variable or parameter or not.
> 
> see the GLOB_SUBST option.

GLOB_SUBST roughly covers the last remark (and GLOB_SUBST is on in POSIX
mode), but not the thing about backslashes --- zsh only removes the
backslashes around pattern characters, not other characters, if it knows
the context is just quoting patterns, which is true of characters made
"live" by the effect of GLOB_SUBST.  That's why the new (b) parameter
expansion flag turned up.

I suppose that ought to be fixable in compatibility mode --- we
certainly don't want to mess around with quoting in native mode.

(I said "roughly" above because there's a big can of worms here about
when quoting happens --- normal backslash quoting happens on input to
the lexer, backslash quoting of patterns much later and in this case
possibly in addition --- but the intention is GLOB_SUBST should at least
make zsh look like other shells, messy though that is.)

pws


^ permalink raw reply	[relevance 3%]

* zsh doesn't support standard "unalias -a"
@ 2015-05-18 13:28  3% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-05-18 13:28 UTC (permalink / raw)
  To: zsh-workers

In a cross-platform shell library I'm writing, I would like to start by
removing all aliases from the current execution environment, to help
assure a consistent command language. The standard command to remove all
aliases is "unalias -a". See:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/unalias.html

(For instance, ksh93 unhelpfully aliases "command" to "command " by
default, causing additional alias expansion where I don't want it.)

Unfortunately it appears that zsh does not support the "-a" option to
unalias, so I have to resort to the proprietary zsh variant:

unalias -m '*'

It would be nice if the standard -a option were added (at least in POSIX
mode, if nothing else).

Thanks,

- Martijn


^ permalink raw reply	[relevance 3%]

* test -z '(' : too many arguments
@ 2015-05-27 18:40  3% Martijn Dekker
  2015-05-27 20:23  7% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-05-27 18:40 UTC (permalink / raw)
  To: zsh-workers

In the current git version of zsh, there is a funny bug with test (as
well as '['). If the arguments to 'test -z' or 'test -n' are exactly
equal to either '(' or ')', then a "too many arguments" error message is
produced.

The exit status is 1, and not 2 or higher (as POSIX says it must be when
'test' fails). This means 'test -n' gives an incorrect exit status for
these values, but 'test -z' doesn't.

Buggy output:

% test -z '('
test: too many arguments
% echo $?
1
% test -n '('
test: too many arguments
% echo $?
1
% test -z ')'
test: too many arguments
% echo $?
1
% test -n ')'
test: too many arguments
% echo $?
1

Correct output:

% test -n '(('
% echo $?
0
% test -n 'a(b'
% echo $?
0
% test -n '(a'
% echo $?
0
% test -n 'a('
% echo $?
0
% test -z 'a('
% echo $?
1
%


^ permalink raw reply	[relevance 3%]

* Re: test -z '(' : too many arguments
  2015-05-27 18:40  3% test -z '(' : too many arguments Martijn Dekker
@ 2015-05-27 20:23  7% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-05-27 20:23 UTC (permalink / raw)
  To: zsh-workers

On Wed, 27 May 2015 20:40:42 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> % test -z '('
> test: too many arguments

The background here is we use the same code to parse "test" as to parse
"[[", except for test it doesn't really want parsing, it wants some ad
hoc following of the POSIX rules for the first few arguments.

At least it's a fairly special case, so with any luck this fix won't
have side effects.

I've made the code a bit more intelligible.  Not much, though.

pws

diff --git a/Src/parse.c b/Src/parse.c
index 06cea74..c932851 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2212,13 +2212,14 @@ par_cond_2(void)
 {
     char *s1, *s2, *s3;
     int dble = 0;
+    int n_testargs = (condlex == testlex) ? arrlen(testargs) + 1 : 0;
 
-    if (condlex == testlex) {
+    if (n_testargs) {
 	/* See the description of test in POSIX 1003.2 */
 	if (tok == NULLTOK)
 	    /* no arguments: false */
 	    return par_cond_double(dupstring("-n"), dupstring(""));
-	if (!*testargs) {
+	if (n_testargs == 1) {
 	    /* one argument: [ foo ] is equivalent to [ -n foo ] */
 	    s1 = tokstr;
 	    condlex();
@@ -2227,7 +2228,7 @@ par_cond_2(void)
 		return par_cond_double(s1, dupstring("1"));
 	    return par_cond_double(dupstring("-n"), s1);
 	}
-	if (testargs[1]) {
+	if (n_testargs > 2) {
 	    /* three arguments: if the second argument is a binary operator, *
 	     * perform that binary test on the first and the third argument  */
 	    if (!strcmp(*testargs, "=")  ||
@@ -2253,7 +2254,7 @@ par_cond_2(void)
 	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
 	 * are treated as "[string] [and] ..." and "[string] [or] ...".
 	 */
-	if (!(condlex == testlex && *testargs && 
+	if (!(n_testargs > 1 &&
 	      (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o"))))
 	{
 	    condlex();
@@ -2277,19 +2278,27 @@ par_cond_2(void)
     }
     s1 = tokstr;
     dble = (s1 && *s1 == '-'
-	    && (condlex != testlex
+	    && (!n_testargs
 		|| strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1)
 	    && !s1[2]);
     if (tok != STRING) {
 	/* Check first argument for [[ STRING ]] re-interpretation */
 	if (s1 /* tok != DOUTBRACK && tok != DAMPER && tok != DBAR */
-	    && tok != LEXERR && (!dble || condlex == testlex)) {
+	    && tok != LEXERR && (!dble || n_testargs)) {
 	    condlex();
 	    return par_cond_double(dupstring("-n"), s1);
 	} else
 	    YYERROR(ecused);
     }
     condlex();
+    if (n_testargs == 2 && tok != STRING && tokstr && s1[0] == '-') {
+	/*
+	 * Something like "test -z" followed by a token.
+	 * We'll turn the token into a string (we've also
+	 * checked it does have a string representation).
+	 */
+	tok = STRING;
+    }
     if (tok == INANG || tok == OUTANG) {
 	enum lextok xtok = tok;
 	condlex();
@@ -2308,7 +2317,7 @@ par_cond_2(void)
 	 * mean we have to go back and fix up the first one
 	 */
 	if (tok != LEXERR) {
-	    if (!dble || condlex == testlex)
+	    if (!dble || n_testargs)
 		return par_cond_double(dupstring("-n"), s1);
 	    else
 		return par_cond_multi(s1, newlinklist());
@@ -2316,7 +2325,7 @@ par_cond_2(void)
 	    YYERROR(ecused);
     }
     s2 = tokstr;   
-    if (condlex != testlex)
+    if (!n_testargs)
 	dble = (s2 && *s2 == '-' && !s2[2]);
     incond++;			/* parentheses do globbing */
     condlex();
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 6581b9d..02fa4d4 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -374,6 +374,20 @@ F:Failures in these cases do not indicate a problem in the shell.
 >foo is empty
 >foo is full
 
+  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
+
 %clean
   # This works around a bug in rm -f in some versions of Cygwin
   chmod 644 unmodish


^ permalink raw reply	[relevance 7%]

* Re: zsh-5.0.7-dev-4
  @ 2015-05-27 20:46  3%     ` Martijn Dekker
  2015-05-27 21:17  0%       ` zsh-5.0.7-dev-4 Mikael Magnusson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-05-27 20:46 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson schreef op 27-05-15 om 21:50:
> On Wed, 27 May 2015 21:33:52 +0200
> Martijn Dekker <martijn@inlv.org> wrote:
>> Peter Stephenson schreef op 27-05-15 om 21:06:
>>> You can get another test release of 5.0.8 from
>>>
>>> http://www.zsh.org/pub/development
>>>
>>> I'm hoping I can release this within a couple of days.
>>
>> Unfortunately, it has the 'test' bug I posted about just now.
> 
> That's very minor and has been there for ages --- I hope I'll get a
> chance to fix it (suspect it's easy) but it's not going to block the release
> anyway.

The spurious error message is not the real problem. Because of the
incorrect exit status, this causes any POSIX script that uses 'test -n
$stuff' or '[ -n $stuff ]' on arbitrary input (i.e. which might include
'(' or ')') to take the wrong action, so I would hardly call this minor.

- M.


^ permalink raw reply	[relevance 3%]

* Re: zsh-5.0.7-dev-4
  2015-05-27 20:46  3%     ` zsh-5.0.7-dev-4 Martijn Dekker
@ 2015-05-27 21:17  0%       ` Mikael Magnusson
  0 siblings, 0 replies; 200+ results
From: Mikael Magnusson @ 2015-05-27 21:17 UTC (permalink / raw)
  To: Martijn Dekker; +Cc: zsh workers

On Wed, May 27, 2015 at 10:46 PM, Martijn Dekker <martijn@inlv.org> wrote:
> Peter Stephenson schreef op 27-05-15 om 21:50:
>> On Wed, 27 May 2015 21:33:52 +0200
>> Martijn Dekker <martijn@inlv.org> wrote:
>>> Peter Stephenson schreef op 27-05-15 om 21:06:
>>>> You can get another test release of 5.0.8 from
>>>>
>>>> http://www.zsh.org/pub/development
>>>>
>>>> I'm hoping I can release this within a couple of days.
>>>
>>> Unfortunately, it has the 'test' bug I posted about just now.
>>
>> That's very minor and has been there for ages --- I hope I'll get a
>> chance to fix it (suspect it's easy) but it's not going to block the release
>> anyway.
>
> The spurious error message is not the real problem. Because of the
> incorrect exit status, this causes any POSIX script that uses 'test -n
> $stuff' or '[ -n $stuff ]' on arbitrary input (i.e. which might include
> '(' or ')') to take the wrong action, so I would hardly call this minor.

The important factor is that it is not a regression.

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* getopts doesn't update OPTIND when called from function
@ 2015-05-28 16:18  4% Martijn Dekker
  2015-05-28 17:17  4% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-05-28 16:18 UTC (permalink / raw)
  To: zsh-workers

I'm writing a shell function that extends the functionality of the
'getopts' builtin. For that to work, it is necessary to call the
'getopts' builtin from the shell function.

The POSIX standard specifies that OPTIND and OPTARG are global
variables, even if the positional parameters are local to the
function.[*] This makes it possible to call 'getopts' from a function by
simply passing the global positional parameters along by adding "$@".

My problem is that zsh does not update the global OPTIND variable when
getopts is called from a function, which defeats my function on zsh. (It
does update the global OPTARG variable, though.)

So, this is another bug report.

I made a little test program that demonstrates this; see below the
footnotes. It succeeds on bash, ksh93, pdksh, mksh, and yash, but not
zsh or (d)ash[*2].

Thanks,

- Martijn

[*] The POSIX standard specifies:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html
"The shell variable specified by the name operand, OPTIND, and OPTARG
shall affect the current shell execution environment", which implies
that they are global variables.
    Confusingly, that same page also says: "The shell variables OPTIND
and OPTARG shall be local to the caller of getopts and shall not be
exported by default."
    But I believe that "caller" here means the program that calls
getopts, not the function; POSIX does not support function-local
variables. This interpretation is supported by the added phrase "... and
shall not be exported by default" and by the evidence that the majority
of popular shells pass my test script.
    (Of course it should be possible to explicitly make OPTIND and
OPTARG local using the non-standard 'local' or 'typeset' keyword, but I
believe they should be global by default.)

[*2] (d)ash has a hairier bug where, if getopts is called from a
function, it updates the global OPTIND for the first option but not for
subsequent options, so OPTIND gets stuck on 3. I shall be bothering
their developers separately.

#### begin test script ####

#! /bin/sh

expect() {
    if [ "X$2" = "X$3" ]; then
        printf '%s: OK, got "%s"\n' "$1" "$2"
    else
        printf '%s: BUG: expected "%s", got "%s"\n' "$1" "$2" "$3"
        return 1
    fi
}

callgetopts() {
    getopts 'D:ln:vhL' opt "$@"
}

testfn() {
    expect OPTIND 1 "$OPTIND"

    callgetopts "$@"
    expect opt D "$opt"
    expect OPTARG 'test' "$OPTARG"

    callgetopts "$@"
    expect opt h "$opt"
    expect OPTARG '' "$OPTARG"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"
    expect opt n "$opt"
    expect OPTARG 1 "$OPTARG"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"

    callgetopts "$@"
    expect OPTIND 5 "$OPTIND"
}

testfn -D test -hn 1 test arguments

#### end test script ####

Output on zsh 5.0.7-dev-4:

OPTIND: OK, got "1"
opt: OK, got "D"
OPTARG: OK, got "test"
opt: BUG: expected "h", got "D"
OPTARG: BUG: expected "", got "test"
OPTIND: BUG: expected "5", got "1"
opt: BUG: expected "n", got "D"
OPTARG: BUG: expected "1", got "test"
OPTIND: BUG: expected "5", got "1"
OPTIND: BUG: expected "5", got "1"

Expected output (on bash, *ksh*, yash):

OPTIND: OK, got "1"
opt: OK, got "D"
OPTARG: OK, got "test"
opt: OK, got "h"
OPTARG: OK, got ""
OPTIND: OK, got "5"
opt: OK, got "n"
OPTARG: OK, got "1"
OPTIND: OK, got "5"
OPTIND: OK, got "5"


^ permalink raw reply	[relevance 4%]

* Re: getopts doesn't update OPTIND when called from function
  2015-05-28 16:18  4% getopts doesn't update OPTIND when called from function Martijn Dekker
@ 2015-05-28 17:17  4% ` Peter Stephenson
  2015-06-05  6:46  0%   ` Roman Neuhauser
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-05-28 17:17 UTC (permalink / raw)
  To: zsh-workers

On Thu, 28 May 2015 18:18:32 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> I'm writing a shell function that extends the functionality of the
> 'getopts' builtin. For that to work, it is necessary to call the
> 'getopts' builtin from the shell function.
> 
> The POSIX standard specifies that OPTIND and OPTARG are global
> variables, even if the positional parameters are local to the
> function.[*] This makes it possible to call 'getopts' from a function by
> simply passing the global positional parameters along by adding "$@".
> 
> My problem is that zsh does not update the global OPTIND variable when
> getopts is called from a function, which defeats my function on zsh. (It
> does update the global OPTARG variable, though.)

This is documented behaviour (well, sort of -- the documentation didn't
say quite what we actually do) so this needs another compatibility fix.
POSIX_BUILTINS seems appropriate.

diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index a2c03bc..f8e4edf 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -866,7 +866,8 @@ vindex(OPTARG, use of)
 
 The first option to be examined may be changed by explicitly assigning
 to tt(OPTIND).  tt(OPTIND) has an initial value of tt(1), and is
-normally reset to tt(1) upon exit from a shell function.  tt(OPTARG)
+normally set to tt(1) upon entry to a shell function and restored
+upon exit (this is disabled by the tt(POSIX_BUILTINS) option).  tt(OPTARG)
 is not reset and retains its value from the most recent call to
 tt(getopts).  If either of tt(OPTIND) or tt(OPTARG) is explicitly
 unset, it remains unset, and the index or option argument is not
diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 032423d..4c0ae12 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -2038,6 +2038,10 @@ tt(unset).
 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, the tt(getopts) builtin behaves in a POSIX-compatible
+fashion in that the associated variable tt(OPTIND) is not made
+local to functions.
 )
 pindex(POSIX_IDENTIFIERS)
 pindex(NO_POSIX_IDENTIFIERS)
diff --git a/Src/builtin.c b/Src/builtin.c
index a9afb45..18c22f2 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -4713,6 +4713,10 @@ bin_shift(char *name, char **argv, Options ops, UNUSED(int func))
     return ret;
 }
 
+/*
+ * Position of getopts option within OPTIND argument with multiple options.
+ */
+
 /**/
 int optcind;
 
diff --git a/Src/exec.c b/Src/exec.c
index 527d611..9f163a6 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4910,9 +4910,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     if (!(flags & PM_UNDEFINED))
 	scriptname = dupstring(name);
     oldzoptind = zoptind;
-    zoptind = 1;
     oldoptcind = optcind;
-    optcind = 0;
+    if (!isset(POSIXBUILTINS)) {
+	zoptind = 1;
+	optcind = 0;
+    }
 
     /* We need to save the current options even if LOCALOPTIONS is *
      * not currently set.  That's because if it gets set in the    *
@@ -5049,8 +5051,10 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 	argzero = oargv0;
     }
     pparams = pptab;
-    optcind = oldoptcind;
-    zoptind = oldzoptind;
+    if (!isset(POSIXBUILTINS)) {
+	zoptind = oldzoptind;
+	optcind = oldoptcind;
+    }
     scriptname = oldscriptname;
     oflags = ooflags;
 


^ permalink raw reply	[relevance 4%]

* Re: Arith parsing bug with minus after $#
  @ 2015-05-29 15:02  3% ` Peter Stephenson
  2015-05-29 15:43  0%   ` Martijn Dekker
                     ` (2 more replies)
  0 siblings, 3 replies; 200+ results
From: Peter Stephenson @ 2015-05-29 15:02 UTC (permalink / raw)
  To: zsh-workers

On Thu, 28 May 2015 21:42:41 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> % set --
> % echo $#
> 0
> % echo $(($#-1))
> 41

That's not a compatibility issue, that's just plain weird.  I don't know
the POSIX terminology.

The problem is the overloading of "#" --- the test to establish what to
do with it is trying too hard to resolve to ${#-}, which is a valid
substitution, because it hasn't taken into account that there are no
braces.  So what you're seeing is ${#-}1.

"-" is overloaded, too, so there could be other cases involving those
two characters where they're misinterpreted, even with braces.

diff --git a/Src/subst.c b/Src/subst.c
index d4a04b8..168f7f1 100644
--- a/Src/subst.c
+++ b/Src/subst.c
@@ -2170,7 +2170,7 @@ paramsubst(LinkList l, LinkNode n, char **str, int qt, int pf_flags)
 		     */
 		    || ((cc == '#' || cc == Pound) &&
 			s[2] == Outbrace)
-		    || cc == '-' || (cc == ':' && s[2] == '-')
+		    || (inbrace && (cc == '-' || (cc == ':' && s[2] == '-')))
 		    || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) {
 	    getlen = 1 + whichlen, s++;
 	    /*
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index d96ffb6..c41e05e 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -1703,3 +1703,8 @@
   funnychars='The qu*nk br!wan f@x j/mps o[]r \(e la~# ^"&;'
   [[ $funnychars = ${~${(b)funnychars}} ]]
 0:${(b)...} quoting protects from GLOB_SUBST
+
+  set --
+  print $#-1
+0:Avoid confusion after overloaded characters in braceless substitution
+>0-1


^ permalink raw reply	[relevance 3%]

* Re: Arith parsing bug with minus after $#
  2015-05-29 15:02  3% ` Peter Stephenson
@ 2015-05-29 15:43  0%   ` Martijn Dekker
    2015-06-07  1:08  3%   ` Bart Schaefer
  2 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-05-29 15:43 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson schreef op 29-05-15 om 17:02:
> On Thu, 28 May 2015 21:42:41 +0200
> Martijn Dekker <martijn@inlv.org> wrote:
>> % set --
>> % echo $#
>> 0
>> % echo $(($#-1))
>> 41
> 
> That's not a compatibility issue, that's just plain weird.  I don't know
> the POSIX terminology.
> 
> The problem is the overloading of "#" --- the test to establish what to
> do with it is trying too hard to resolve to ${#-}, which is a valid
> substitution, because it hasn't taken into account that there are no
> braces.  So what you're seeing is ${#-}1.

Ah, yes... ${#-} is the length in characters of $-, the shell options
that are set. Before 'emulate sh', the length of $- is 8, and after,
it's 4. That explains the results I got.

The fix is working; thanks yet again.

- M.


^ permalink raw reply	[relevance 0%]

* Re: Arith parsing bug with minus after $#
  @ 2015-05-29 19:33  3%     ` Martijn Dekker
  2015-05-29 20:48  0%       ` ZyX
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-05-29 19:33 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer schreef op 29-05-15 om 20:09:
> On May 29, 2015 8:02 AM, "Peter Stephenson" <p.stephenson@samsung.com>
> wrote:
>> The problem is the overloading of "#" --- the test to establish what to
>> do with it is trying too hard to resolve to ${#-}, which is a valid
>> substitution, because it hasn't taken into account that there are no
>> braces.  So what you're seeing is ${#-}1.
> 
> I think this actually was discussed on austin-group a few months back.  My
> recollection is that zsh's behavior was deemed permissible and I therefore
> thought no more about it at the time.

It is incompatible with every other shell and with the POSIX spec.
Parameter expansion is only supposed to be done if braces are present. See:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02

- M.


^ permalink raw reply	[relevance 3%]

* Re: Arith parsing bug with minus after $#
  2015-05-29 19:33  3%     ` Martijn Dekker
@ 2015-05-29 20:48  0%       ` ZyX
  0 siblings, 0 replies; 200+ results
From: ZyX @ 2015-05-29 20:48 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers



29.05.2015, 22:34, "Martijn Dekker" <martijn@inlv.org>:
> Bart Schaefer schreef op 29-05-15 om 20:09:
>>  On May 29, 2015 8:02 AM, "Peter Stephenson" <p.stephenson@samsung.com>
>>  wrote:
>>>  The problem is the overloading of "#" --- the test to establish what to
>>>  do with it is trying too hard to resolve to ${#-}, which is a valid
>>>  substitution, because it hasn't taken into account that there are no
>>>  braces.  So what you're seeing is ${#-}1.
>>  I think this actually was discussed on austin-group a few months back.  My
>>  recollection is that zsh's behavior was deemed permissible and I therefore
>>  thought no more about it at the time.
>
> It is incompatible with every other shell and with the POSIX spec.
> Parameter expansion is only supposed to be done if braces are present. See:
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02

It says that they are optional:

> The parameter name or symbol can be enclosed in braces, which are optional except for positional parameters with more than one digit or when parameter is a name and is followed by a character that could be interpreted as part of the name. The matching closing brace shall be determined by counting brace levels, skipping over enclosed quoted strings, and command substitutions.

This is the fourth paragraph.

But later it explicitly says that not enclosed in single braces may only be names or single-character variables. I.e. $#- is ${#}-, $10 is ${1}0, …

Besides $#- zsh has things like $array[index]: needs not be enclosed in braces (depends on some option: in `emulate sh` or `emulate ksh` this is ${array}[index], same in ksh). Or $file:h. I guess there are more I do not know about.

>
> - M.


^ permalink raw reply	[relevance 0%]

* Arith expansion accepts extra closing parenthesis
@ 2015-06-01 16:32  3% Martijn Dekker
  2015-06-02  8:56  0% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-01 16:32 UTC (permalink / raw)
  To: zsh-workers

I just found some more arithmetic parsing strangeness. zsh 5.0.8 and
4.3.11 both happily accept and ignore one (1) extra closing parenthesis
in variable expansion within arithmetic expansion (even in POSIX mode).

% X='1)'
% echo $(($X))
1
% echo $((X))
1

(Expected output: error message in both cases)

Yet, 'echo $((1)))' errors out as expected, as do 'echo $(($X))' and
'echo $((X))' for X='1))', X='1)))', X='(1', etc.

- Martijn


^ permalink raw reply	[relevance 3%]

* Re: Arith expansion accepts extra closing parenthesis
  2015-06-01 16:32  3% Arith expansion accepts extra closing parenthesis Martijn Dekker
@ 2015-06-02  8:56  0% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-06-02  8:56 UTC (permalink / raw)
  To: zsh-workers

On Mon, 1 Jun 2015 18:32:14 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> I just found some more arithmetic parsing strangeness. zsh 5.0.8 and
> 4.3.11 both happily accept and ignore one (1) extra closing parenthesis
> in variable expansion within arithmetic expansion (even in POSIX mode).
> 
> % X='1)'
> % echo $(($X))
> 1
> % echo $((X))
> 1

I think this is a special case, down to the way we handle parenthesesed
expressions --- we treat it as if it's a top-level expression but
expect a closing parenthesis next.  So checking for a stray closing
parenthesis on return from the top level of parsing ought to be a robust
fix.

pws

diff --git a/Src/math.c b/Src/math.c
index 97a97b3..e20a90c 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -407,6 +407,13 @@ mathevall(char *s, enum prec_type prec_tp, char **ep)
     stack[0].val.type = MN_INTEGER;
     stack[0].val.u.l = 0;
     mathparse(prec_tp == MPREC_TOP ? TOPPREC : ARGPREC);
+    /*
+     * Internally, we parse the contents of parentheses at top
+     * precedence... so we can return a parenthesis here if
+     * there are too many at the end.
+     */
+    if (mtok == M_OUTPAR && !errflag)
+	zerr("unexpected ')'");
     *ep = ptr;
     DPUTS(!errflag && sp > 0,
 	  "BUG: math: wallabies roaming too freely in outback");
diff --git a/Test/C01arith.ztst b/Test/C01arith.ztst
index d284e08..2d35ea6 100644
--- a/Test/C01arith.ztst
+++ b/Test/C01arith.ztst
@@ -395,3 +395,17 @@
 >6
 >7
 >120
+
+  foo="(1)"
+  print $((foo))
+  print $(($foo))
+  print $(((2)))
+  foo="3)"
+  (print $((foo))) 2>&1
+  (print $(($foo))) 2>&1
+1: Good and bad trailing parentheses
+>1
+>1
+>2
+>(eval):6: unexpected ')'
+>(eval):7: unexpected ')'


^ permalink raw reply	[relevance 0%]

* Re: getopts doesn't update OPTIND when called from function
  2015-05-28 17:17  4% ` Peter Stephenson
@ 2015-06-05  6:46  0%   ` Roman Neuhauser
  2015-06-06 16:46  0%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Roman Neuhauser @ 2015-06-05  6:46 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

# p.stephenson@samsung.com / 2015-05-28 18:17:40 +0100:
> On Thu, 28 May 2015 18:18:32 +0200
> Martijn Dekker <martijn@inlv.org> wrote:
> > I'm writing a shell function that extends the functionality of the
> > 'getopts' builtin. For that to work, it is necessary to call the
> > 'getopts' builtin from the shell function.
> > 
> > The POSIX standard specifies that OPTIND and OPTARG are global
> > variables, even if the positional parameters are local to the
> > function.[*] This makes it possible to call 'getopts' from a function by
> > simply passing the global positional parameters along by adding "$@".
> > 
> > My problem is that zsh does not update the global OPTIND variable when
> > getopts is called from a function, which defeats my function on zsh. (It
> > does update the global OPTARG variable, though.)
> 
> This is documented behaviour (well, sort of -- the documentation didn't
> say quite what we actually do) so this needs another compatibility fix.
> POSIX_BUILTINS seems appropriate.

thanks for the zshbuiltins(1) clarification.  

i have a problem similar to Martijn's, only there's no function in sight.
this diff shows how zsh (5.0.7, emulate -R sh) differs from other shells,
and the standard IIUC:

   $ getopts abc OPTNAM -a -b -- -c
   $ printf "%s=%s\n" OPTIND "$OPTIND" OPTNAM "$OPTNAM" OPTARG "$OPTARG"
-  OPTIND=2
+  OPTIND=1
   OPTNAM=a
   OPTARG=
   $ getopts abc OPTNAM -a -b -- -c
   $ printf "%s=%s\n" OPTIND "$OPTIND" OPTNAM "$OPTNAM" OPTARG "$OPTARG"
-  OPTIND=3
+  OPTIND=2
   OPTNAM=b
   OPTARG=
   $ getopts abc OPTNAM -a -b -- -c
   [1]
   $ printf "%s=%s\n" OPTIND "$OPTIND" OPTNAM "$OPTNAM" OPTARG "$OPTARG"
   OPTIND=4
-  OPTNAM=?
+  OPTNAM=b
   OPTARG=

it would be nice to have zsh aligned with other shells, at least under
posix_builtins or 'emulate sh'.

-- 
roman


^ permalink raw reply	[relevance 0%]

* Re: getopts doesn't update OPTIND when called from function
  2015-06-05  6:46  0%   ` Roman Neuhauser
@ 2015-06-06 16:46  0%     ` Bart Schaefer
  2015-06-07  8:30  0%       ` Roman Neuhauser
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-06 16:46 UTC (permalink / raw)
  To: zsh-workers, Roman Neuhauser

On Jun 5,  8:46am, Roman Neuhauser wrote:
} Subject: Re: getopts doesn't update OPTIND when called from function
}
} i have a problem similar to Martijn's, only there's no function in sight.
} this diff shows how zsh (5.0.7, emulate -R sh) differs from other shells,
} and the standard IIUC:

I believe this was previously discussed here:

  http://www.zsh.org/mla/workers//2015/msg00196.html

The key text:

> In zsh, if you add a SECOND call to getopts in the example function,
> you will find that the second call DOES exit with a value of 1, and
> that WHEN zsh getopts exits with a return value greater than zero,
> THEN the value of OPTIND is set as POSIX specifies.

No one responded with an opinion of whether this conforms to the literal
specification or not.

-- 
Barton E. Schaefer


^ permalink raw reply	[relevance 0%]

* In POSIX mode, ${#var} measures length in bytes, not characters
@ 2015-06-07  0:23 10% Martijn Dekker
  2015-06-07  0:34  9% ` ZyX
  2015-06-08  8:44  5% ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Martijn Dekker @ 2015-06-07  0:23 UTC (permalink / raw)
  To: zsh-workers

When in 'emulate sh' mode, ${#var} substitutes the length of the
variable in bytes, not characters. This is contrary to the standard; the
length in characters is supposed to be substituted.[*]

Oddly enough, zsh is POSIX compliant here in native mode, but
non-compliant in POSIX mode.

Confirmed in zsh 4.3.11 (Mac OS X), 5.0.2 (Linux) and 5.0.8 (Mac OS X).

$ zsh
% locale
LANG="nl_NL.UTF-8"
LC_COLLATE="nl_NL.UTF-8"
LC_CTYPE="nl_NL.UTF-8"
LC_MESSAGES="nl_NL.UTF-8"
LC_MONETARY="nl_NL.UTF-8"
LC_NUMERIC="nl_NL.UTF-8"
LC_TIME="nl_NL.UTF-8"
LC_ALL=
% mot=arrêté
% echo ${#mot}
6
% emulate sh
% echo ${#mot}
8

- Martijn

[*] Reference:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
> ${#parameter}
>     String Length. The length in characters of the value of parameter
>     shall be substituted. [...]


^ permalink raw reply	[relevance 10%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  0:23 10% In POSIX mode, ${#var} measures length in bytes, not characters Martijn Dekker
@ 2015-06-07  0:34  9% ` ZyX
  2015-06-07  1:23 10%   ` Bart Schaefer
  2015-06-07  2:21 10%   ` Martijn Dekker
  2015-06-08  8:44  5% ` Peter Stephenson
  1 sibling, 2 replies; 200+ results
From: ZyX @ 2015-06-07  0:34 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers

07.06.2015, 03:29, "Martijn Dekker" <martijn@inlv.org>:
> When in 'emulate sh' mode, ${#var} substitutes the length of the
> variable in bytes, not characters. This is contrary to the standard; the
> length in characters is supposed to be substituted.[*]
>
> Oddly enough, zsh is POSIX compliant here in native mode, but
> non-compliant in POSIX mode.

Do you have a reference where “character” is defined? This behaviour is the same in posh and dash:

    % posh -c 'VAR="«»"; echo ${#VAR}'
    4
    % dash -c 'VAR="«»"; echo ${#VAR}'
    4
    % zsh -c 'VAR="«»"; echo ${#VAR}' # Non-POSIX mode: length in Unicode codepoints for comparison
    2
    % locale
    LANG=ru_RU.UTF-8
    LC_CTYPE="ru_RU.UTF-8"
    LC_NUMERIC="ru_RU.UTF-8"
    LC_TIME="ru_RU.UTF-8"
    LC_COLLATE="ru_RU.UTF-8"
    LC_MONETARY="ru_RU.UTF-8"
    LC_MESSAGES="ru_RU.UTF-8"
    LC_PAPER="ru_RU.UTF-8"
    LC_NAME="ru_RU.UTF-8"
    LC_ADDRESS="ru_RU.UTF-8"
    LC_TELEPHONE="ru_RU.UTF-8"
    LC_MEASUREMENT="ru_RU.UTF-8"
    LC_IDENTIFICATION="ru_RU.UTF-8"
    LC_ALL=

>
> Confirmed in zsh 4.3.11 (Mac OS X), 5.0.2 (Linux) and 5.0.8 (Mac OS X).
>
> $ zsh
> % locale
> LANG="nl_NL.UTF-8"
> LC_COLLATE="nl_NL.UTF-8"
> LC_CTYPE="nl_NL.UTF-8"
> LC_MESSAGES="nl_NL.UTF-8"
> LC_MONETARY="nl_NL.UTF-8"
> LC_NUMERIC="nl_NL.UTF-8"
> LC_TIME="nl_NL.UTF-8"
> LC_ALL=
> % mot=arrêté
> % echo ${#mot}
> 6
> % emulate sh
> % echo ${#mot}
> 8
>
> - Martijn
>
> [*] Reference:
> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
>>  ${#parameter}
>>      String Length. The length in characters of the value of parameter
>>      shall be substituted. [...]


^ permalink raw reply	[relevance 9%]

* Re: Arith parsing bug with minus after $#
  2015-05-29 15:02  3% ` Peter Stephenson
  2015-05-29 15:43  0%   ` Martijn Dekker
  @ 2015-06-07  1:08  3%   ` Bart Schaefer
  2 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-06-07  1:08 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: Zsh hackers list

On Fri, May 29, 2015 at 8:02 AM, Peter Stephenson
<p.stephenson@samsung.com> wrote:
> On Thu, 28 May 2015 21:42:41 +0200
> Martijn Dekker <martijn@inlv.org> wrote:
>> % set --
>> % echo $#
>> 0
>> % echo $(($#-1))
>> 41
>
> That's not a compatibility issue, that's just plain weird.  I don't know
> the POSIX terminology.
>
> The problem is the overloading of "#" --- the test to establish what to
> do with it is trying too hard to resolve to ${#-}, which is a valid
> substitution, because it hasn't taken into account that there are no
> braces.  So what you're seeing is ${#-}1.

Incidentally, here is a few-years-old austin-group thread that is related:

http://thread.gmane.org/gmane.comp.standards.posix.austin.general/3784


^ permalink raw reply	[relevance 3%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  0:34  9% ` ZyX
@ 2015-06-07  1:23 10%   ` Bart Schaefer
  2015-06-07  1:27  5%     ` ZyX
  2015-06-07  2:21 10%   ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-07  1:23 UTC (permalink / raw)
  To: zsh-workers

On Jun 7,  3:34am, ZyX wrote:
} Subject: Re: In POSIX mode, ${#var} measures length in bytes, not characte
}
} 07.06.2015, 03:29, "Martijn Dekker" <martijn@inlv.org>:
} > When in 'emulate sh' mode, ${#var} substitutes the length of the
} > variable in bytes, not characters. This is contrary to the standard; the
} > length in characters is supposed to be substituted.[*]
} >
} > Oddly enough, zsh is POSIX compliant here in native mode, but
} > non-compliant in POSIX mode.
} 
} Do you have a reference where "character" is defined? This behaviour
} is the same in posh and dash:

I thought this was discussed on the austin-group list but I can't find a
search term to dig it out of the archives.  (I did find the thread about
${##} as a side-effect of the attempt.)

On my Ubuntu 12.04 system, /bin/sh is a link to dash, so zsh invoked
as sh behaves like /bin/sh.  On CentOS, /bin/sh links to bash, so they
behave differently.


^ permalink raw reply	[relevance 10%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  1:23 10%   ` Bart Schaefer
@ 2015-06-07  1:27  5%     ` ZyX
  0 siblings, 0 replies; 200+ results
From: ZyX @ 2015-06-07  1:27 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers



07.06.2015, 04:24, "Bart Schaefer" <schaefer@brasslantern.com>:
> On Jun 7,  3:34am, ZyX wrote:
> } Subject: Re: In POSIX mode, ${#var} measures length in bytes, not characte
> }
> } 07.06.2015, 03:29, "Martijn Dekker" <martijn@inlv.org>:
> } > When in 'emulate sh' mode, ${#var} substitutes the length of the
> } > variable in bytes, not characters. This is contrary to the standard; the
> } > length in characters is supposed to be substituted.[*]
> } >
> } > Oddly enough, zsh is POSIX compliant here in native mode, but
> } > non-compliant in POSIX mode.
> }
> } Do you have a reference where "character" is defined? This behaviour
> } is the same in posh and dash:
>
> I thought this was discussed on the austin-group list but I can't find a
> search term to dig it out of the archives.  (I did find the thread about
> ${##} as a side-effect of the attempt.)
>
> On my Ubuntu 12.04 system, /bin/sh is a link to dash, so zsh invoked
> as sh behaves like /bin/sh.  On CentOS, /bin/sh links to bash, so they
> behave differently.

Just checked out busybox (ash), it also emits 2 (recognizes unicode codepoints). Ksh emits 2, mksh 4.


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  0:34  9% ` ZyX
  2015-06-07  1:23 10%   ` Bart Schaefer
@ 2015-06-07  2:21 10%   ` Martijn Dekker
  2015-06-09 17:49  5%     ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-07  2:21 UTC (permalink / raw)
  To: zsh-workers

ZyX schreef op 07-06-15 om 02:34:
> Do you have a reference where “character” is defined?

Yes:
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap06.html#tag_06_02

POSIX specifically allows any character encoding, including multibyte
characters, depending on the user's locale, and on the condition that
the portable character set (basically US-ASCII) is a subset of the
locale's character set.

With UTF-8 now the de facto standard locale and it including multibyte
characters, it's become important for shells to get this right.

> This behaviour is the same in posh and dash:

Yes, dash and pdksh/mksh/posh unfortunately have this bug, too.

But bash, ksh93, and yash correctly measure characters, not bytes. (yash
is supposed to be the most POSIX-compliant of them all.)

Thanks,

- Martijn


^ permalink raw reply	[relevance 10%]

* Re: getopts doesn't update OPTIND when called from function
  2015-06-06 16:46  0%     ` Bart Schaefer
@ 2015-06-07  8:30  0%       ` Roman Neuhauser
  0 siblings, 0 replies; 200+ results
From: Roman Neuhauser @ 2015-06-07  8:30 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

# schaefer@brasslantern.com / 2015-06-06 09:46:41 -0700:
> On Jun 5,  8:46am, Roman Neuhauser wrote:
> } this diff shows how zsh (5.0.7, emulate -R sh) differs from other shells,
> } and the standard IIUC:
> 
> I believe this was previously discussed here:
> 
>   http://www.zsh.org/mla/workers//2015/msg00196.html
> 
> The key text:
> 
> > In zsh, if you add a SECOND call to getopts in the example function,
> > you will find that the second call DOES exit with a value of 1, and
> > that WHEN zsh getopts exits with a return value greater than zero,
> > THEN the value of OPTIND is set as POSIX specifies.
> 
> No one responded with an opinion of whether this conforms to the literal
> specification or not.

yeah, sorry.  i missed that conversation.

anyway, it seems perfectly unambiguous to me.  the spec[*] says

> Each time it is invoked, the getopts utility shall place the value of
> the next option in the shell variable specified by the name operand
> and the index of the next argument to be processed in the shell
> variable OPTIND.

*Each time* it is invoked ... shall place ... the index of *the next*
argument ... in ... OPTIND.

in zsh, OPTIND has the index of the last processed option instead, until
"the end of options is encountered".  so that's one clear violation of
the spec.

> When the end of options is encountered, the getopts utility shall exit
> with a return value greater than zero; the shell variable OPTIND shall
> be set to the index of the first operand, or the value "$#" +1 if
> there are no operands; the name variable shall be set to the
> <question-mark> character.

When the end of options is encountered ... the name variable shall be
set to the <question-mark> character.

in zsh, the name parameter has the value of the last processed option
instead.  that's another clear violation.

[*] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/getopts.html

-- 
roman


^ permalink raw reply	[relevance 0%]

* Re: printf, left-justification ignored in 5.0.8
  @ 2015-06-07 21:15  3%   ` Stephane Chazelas
  2015-06-12 11:30  0%     ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2015-06-07 21:15 UTC (permalink / raw)
  To: zsh-workers

2015-06-07 22:39:24 +0200, Oliver Kiddle:
> Roman Neuhauser wrote:
> > 
> > 5.0.8:
> > 
> > % printf "x:%-20s:y\n" fubar
> > x:               fubar:y
> 
> That'll be my fault for not checking thoroughly enough. The - flag is
> fine for numeric values but for strings it seems there is separate code
> to allow for UTF-8 which looks in the flags array. The patch should
> fix this, adds a test and makes the maximum specification length test
> include the ' flag.
[...]

BTW, there was a discussion lately on the Austin group mailing
list confirming that the %20s should count bytes, not
characters.

That is in a UTF-8 locale

printf '|%3s|\n' e é €

should print:

|  e|
| é|
|€|

not:

|  e|
|  é|
|  €|

I find the zsh behaviour more useful though, especially
considering that in zsh we can get the POSIX behaviour with:

$ LC_ALL=C printf '|%3s|\n' e é €
|  e|
| é|
|€|

But note that to get proper alignment, rather than number of
characters, the width of the glyphs should be considered
instead anyway:

$ printf '|%3b|\n' e '\ue9' 'e\u301' '\uff45'
|  e|
|  é|
| é|
|  e|

ksh93 has %3Ls for that:

$ printf '|%3Ls|\n' e $'\ue9' $'e\u301' $'\uff45'
|  e|
|  é|
|  é|
| e|

(possibly uses wcswidth()).

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  0:23 10% In POSIX mode, ${#var} measures length in bytes, not characters Martijn Dekker
  2015-06-07  0:34  9% ` ZyX
@ 2015-06-08  8:44  5% ` Peter Stephenson
  2015-06-09  2:19  9%   ` Martijn Dekker
  2015-06-11 11:23  5%   ` Daniel Shahaf
  1 sibling, 2 replies; 200+ results
From: Peter Stephenson @ 2015-06-08  8:44 UTC (permalink / raw)
  To: zsh-workers

When we started multibyte support, traditional sh's all only supported
the portable character set, so we let zsh behave as if characters were
all 8 bit as the least disruptive change.  Multibyte is on in all other
emulations, even ksh.

With multibyte character sets virtually universal, it's probably time to
assume obeying the localization screws things up least.

With MULTIBYTE always on when available, the "EMULATE" flag becomes
redundant.

pws

diff --git a/Src/options.c b/Src/options.c
index 3e3e074..78f603d 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -192,7 +192,7 @@ static struct optname optns[] = {
 {{NULL, "monitor",	      OPT_SPECIAL},		 MONITOR},
 {{NULL, "multibyte",
 #ifdef MULTIBYTE_SUPPORT
-			      OPT_EMULATE|OPT_ZSH|OPT_CSH|OPT_KSH
+			      OPT_ALL
 #else
 			      0
 #endif


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-08  8:44  5% ` Peter Stephenson
@ 2015-06-09  2:19  9%   ` Martijn Dekker
  2015-06-09  8:35  5%     ` Peter Stephenson
  2015-06-11 11:23  5%   ` Daniel Shahaf
  1 sibling, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-09  2:19 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson schreef op 08-06-15 om 10:44:
> With MULTIBYTE always on when available, the "EMULATE" flag becomes
> redundant.

I should have guessed there's a shell option for that. Still good to
have it on by default.

Between that and POSIX_ARGZERO, I've found (so far) that the following
puts zsh 5.0.8 in the most fully compliant POSIX mode:

emulate sh -o POSIX_ARGZERO -o MULTIBYTE

Thanks,

- M.


^ permalink raw reply	[relevance 9%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-09  2:19  9%   ` Martijn Dekker
@ 2015-06-09  8:35  5%     ` Peter Stephenson
  2015-06-09 15:37  5%       ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-06-09  8:35 UTC (permalink / raw)
  To: zsh-workers

On Tue, 9 Jun 2015 04:19:22 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> Between that and POSIX_ARGZERO, I've found (so far) that the following
> puts zsh 5.0.8 in the most fully compliant POSIX mode:
> 
> emulate sh -o POSIX_ARGZERO -o MULTIBYTE

I can't remember why POSIX_ARGZERO isn't on, or even if there was
actually a reason.

pws


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-09  8:35  5%     ` Peter Stephenson
@ 2015-06-09 15:37  5%       ` Bart Schaefer
  2015-06-09 15:43  5%         ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-09 15:37 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

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

On Tuesday, June 9, 2015, Peter Stephenson <p.stephenson@samsung.com> wrote:
>
>
> I can't remember why POSIX_ARGZERO isn't on, or even if there was
> actually a reason.
>
>
The doc actually does explain this, for once.

For compatibility with previous versions of the shell, emulations use
NO_FUNCTION_ARGZERO instead of POSIX_ARGZERO, which may result in
unexpected scoping of $0 if the emulation mode is changed inside a function
or script.

^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-09 15:37  5%       ` Bart Schaefer
@ 2015-06-09 15:43  5%         ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-06-09 15:43 UTC (permalink / raw)
  To: zsh-workers

On Tue, 9 Jun 2015 08:37:05 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Tuesday, June 9, 2015, Peter Stephenson <p.stephenson@samsung.com> wrote:
> >
> >
> > I can't remember why POSIX_ARGZERO isn't on, or even if there was
> > actually a reason.
> >
> >
> The doc actually does explain this, for once.
> 
> For compatibility with previous versions of the shell, emulations use
> NO_FUNCTION_ARGZERO instead of POSIX_ARGZERO, which may result in
> unexpected scoping of $0 if the emulation mode is changed inside a function
> or script.

So we'd have to special-case the top-level emulation on the assumption
once a sh, always a sh.  Not clear if it's worth it.

pws


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-07  2:21 10%   ` Martijn Dekker
@ 2015-06-09 17:49  5%     ` Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-06-09 17:49 UTC (permalink / raw)
  To: zsh-workers

Martijn Dekker schreef op 07-06-15 om 04:21:
> Yes, dash and pdksh/mksh/posh unfortunately have this bug, too.

Actually, mksh fixed it (though other pdksh variants haven't). Sorry for
the oversight.

- M.


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-08  8:44  5% ` Peter Stephenson
  2015-06-09  2:19  9%   ` Martijn Dekker
@ 2015-06-11 11:23  5%   ` Daniel Shahaf
  2015-06-11 11:33  4%     ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Daniel Shahaf @ 2015-06-11 11:23 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

Peter Stephenson wrote on Mon, Jun 08, 2015 at 09:44:20 +0100:
> diff --git a/Src/options.c b/Src/options.c
> index 3e3e074..78f603d 100644
> --- a/Src/options.c
> +++ b/Src/options.c
> @@ -192,7 +192,7 @@ static struct optname optns[] = {
>  {{NULL, "monitor",	      OPT_SPECIAL},		 MONITOR},
>  {{NULL, "multibyte",
>  #ifdef MULTIBYTE_SUPPORT
> -			      OPT_EMULATE|OPT_ZSH|OPT_CSH|OPT_KSH
> +			      OPT_ALL
>  #else
>  			      0
>  #endif

Update zshoptions.yo?


^ permalink raw reply	[relevance 5%]

* Re: In POSIX mode, ${#var} measures length in bytes, not characters
  2015-06-11 11:23  5%   ` Daniel Shahaf
@ 2015-06-11 11:33  4%     ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-06-11 11:33 UTC (permalink / raw)
  To: zsh-workers

On Thu, 11 Jun 2015 11:23:37 +0000
Daniel Shahaf <d.s@daniel.shahaf.name> wrote:
> Update zshoptions.yo?

Yes, I've been meaning to.

pws

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index fa54024..db9b18b 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -634,7 +634,7 @@ pindex(NO_MULTIBYTE)
 pindex(NOMULTIBYTE)
 cindex(characters, multibyte, in expansion and globbing)
 cindex(multibyte characters, in expansion and globbing)
-item(tt(MULTIBYTE) <C> <K> <Z>)(
+item(tt(MULTIBYTE) <D>)(
 Respect multibyte characters when found in strings.
 When this option is set, strings are examined using the
 system library to determine how many bytes form a character, depending
@@ -642,10 +642,8 @@ on the current locale.  This affects the way characters are counted in
 pattern matching, parameter values and various delimiters.
 
 The option is on by default if the shell was compiled with
-tt(MULTIBYTE_SUPPORT) except in tt(sh) emulation; otherwise it is off by
-default and has no effect if turned on.  The mode is off in tt(sh)
-emulation for compatibility but for interactive use may need to be
-turned on if the terminal interprets multibyte characters.
+tt(MULTIBYTE_SUPPORT); otherwise it is off by default and has no effect
+if turned on.
 
 If the option is off a single byte is always treated as a single
 character.  This setting is designed purely for examining strings


^ permalink raw reply	[relevance 4%]

* Re: printf, left-justification ignored in 5.0.8
  2015-06-07 21:15  3%   ` Stephane Chazelas
@ 2015-06-12 11:30  0%     ` Vincent Lefevre
  2015-06-12 12:31  0%       ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Vincent Lefevre @ 2015-06-12 11:30 UTC (permalink / raw)
  To: zsh-workers

On 2015-06-07 22:15:29 +0100, Stephane Chazelas wrote:
> BTW, there was a discussion lately on the Austin group mailing
> list confirming that the %20s should count bytes, not
> characters.
> 
> That is in a UTF-8 locale
> 
> printf '|%3s|\n' e é €
> 
> should print:
> 
> |  e|
> | é|
> |€|
> 
> not:
> 
> |  e|
> |  é|
> |  €|
> 
> I find the zsh behaviour more useful though,

Well, it depends on the context. As I've said in

  http://www.zsh.org/mla/workers/2012/msg00151.html

  Yes, the number is the size in bytes, not in characters. I think
  that the intent is to deal with internal structures (e.g. with
  file formats where some fields have a fixed or limited size, and
  the same syntax can be used in C to avoid buffer overflows).

I don't know if this is the real reason.

> especially considering that in zsh we can get the POSIX behaviour
> with:
> 
> $ LC_ALL=C printf '|%3s|\n' e é €
> |  e|
> | é|
> |€|

However the change of locale may affect other format specifiers,
like %f, and error messages.

> But note that to get proper alignment, rather than number of
> characters, the width of the glyphs should be considered
> instead anyway:
> 
> $ printf '|%3b|\n' e '\ue9' 'e\u301' '\uff45'
> |  e|
> |  é|
> | é|
> |  e|
> 
> ksh93 has %3Ls for that:
> 
> $ printf '|%3Ls|\n' e $'\ue9' $'e\u301' $'\uff45'
> |  e|
> |  é|
> |  é|
> | e|
> 
> (possibly uses wcswidth()).

This could be useful in zsh, and its support would be needed for
"emulate ksh".

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


^ permalink raw reply	[relevance 0%]

* Re: printf, left-justification ignored in 5.0.8
  2015-06-12 11:30  0%     ` Vincent Lefevre
@ 2015-06-12 12:31  0%       ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-06-12 12:31 UTC (permalink / raw)
  To: zsh-workers

2015-06-12 13:30:50 +0200, Vincent Lefevre:
> On 2015-06-07 22:15:29 +0100, Stephane Chazelas wrote:
> > BTW, there was a discussion lately on the Austin group mailing
> > list confirming that the %20s should count bytes, not
> > characters.
> > 
> > That is in a UTF-8 locale
> > 
> > printf '|%3s|\n' e é €
> > 
> > should print:
> > 
> > |  e|
> > | é|
> > |€|
> > 
> > not:
> > 
> > |  e|
> > |  é|
> > |  €|
> > 
> > I find the zsh behaviour more useful though,
> 
> Well, it depends on the context. As I've said in
> 
>   http://www.zsh.org/mla/workers/2012/msg00151.html
> 
>   Yes, the number is the size in bytes, not in characters. I think
>   that the intent is to deal with internal structures (e.g. with
>   file formats where some fields have a fixed or limited size, and
>   the same syntax can be used in C to avoid buffer overflows).
> 
> I don't know if this is the real reason.

I beleive the real reason was to align on C printf (not wprintf
for instance) (makes little sense to me)

> > especially considering that in zsh we can get the POSIX behaviour
> > with:
> > 
> > $ LC_ALL=C printf '|%3s|\n' e é €
> > |  e|
> > | é|
> > |€|
> 
> However the change of locale may affect other format specifiers,
> like %f, and error messages.

Well, that's a general problem with LC_* handling. Here however
it can be worked around by using several invocations of printf.

[...]
> > ksh93 has %3Ls for that:
> > 
> > $ printf '|%3Ls|\n' e $'\ue9' $'e\u301' $'\uff45'
> > |  e|
> > |  é|
> > |  é|
> > | e|
> > 
> > (possibly uses wcswidth()).
> 
> This could be useful in zsh, and its support would be needed for
> "emulate ksh".
[...]

While I agree that could be useful feature, note that zsh is not
(and will never be I hope) a superset of ksh93. The emulation
mode changes some behaviour that othewise differ from ksh. It
covers mostly ksh88, and zsh has a few features from ksh93 but
that's about it.

-- 
Stephane


^ permalink raw reply	[relevance 0%]

* Alias expansion rules taken up for POSIX standards review
@ 2015-06-13 21:47  5% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-06-13 21:47 UTC (permalink / raw)
  To: zsh-workers

I should have brought this up last week but have been somewhat
distracted from the austin-group of late.  Issue ID 953 has been
opened to clarify whether

  alias cmd='foo &'
  cmd&bar

should semantically expand to

  foo && bar # valid "and" syntax

vs.

  foo & & bar # syntax error

We made the latter choice for zsh as of the 5.0.8 release, for what I
think are several good reasons (and one pragmatic one, which is that
not doing that breaks our lexer in an unpleasant and difficult-to-fix
way).

My ability to post to the austin-group list has been crippled for a
while, so if any of you who are still able to be active want to chime
in, it would be appreciated.


^ permalink raw reply	[relevance 5%]

* Re: Read-only variables in emulation mode
  2013-12-19  7:57  3%       ` Bart Schaefer
@ 2015-06-16  0:10  0%         ` Mikael Magnusson
  0 siblings, 0 replies; 200+ results
From: Mikael Magnusson @ 2015-06-16  0:10 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh workers

On Thu, Dec 19, 2013 at 8:57 AM, Bart Schaefer
<schaefer@brasslantern.com> wrote:
> On Dec 18,  7:28pm, Peter Stephenson wrote:
> } Subject: Re: Read-only variables in emulation mode
> }
> } On Tue, 17 Dec 2013 22:36:51 -0800
> } Bart Schaefer <schaefer@brasslantern.com> wrote:
> } > It's a known limitation that invoking "emulate ..." after the shell is
> } > already running does [not] completely re-instantiate POSIX mode.
> }
> } I don't expect I'll get round to it myself, but in the case of
> } variables, I don't think this should be that difficult.
>
> The part about "_" is easy, though:
>
> diff --git a/Src/params.c b/Src/params.c
> index 26ad6b2..cadf268 100644
> --- a/Src/params.c
> +++ b/Src/params.c
> @@ -283,7 +283,7 @@ IPDEF2("TERM", term_gsu, 0),
>  IPDEF2("TERMINFO", terminfo_gsu, PM_UNSET),
>  IPDEF2("WORDCHARS", wordchars_gsu, 0),
>  IPDEF2("IFS", ifs_gsu, PM_DONTIMPORT),
> -IPDEF2("_", underscore_gsu, PM_READONLY),
> +IPDEF2("_", underscore_gsu, PM_DONTIMPORT),
>  IPDEF2("KEYBOARD_HACK", keyboard_hack_gsu, PM_DONTIMPORT),
>
>  #ifdef USE_LOCALE
>
>
> Feel free to commit that for me if you want it to go into 5.0.4, I'm
> going to be asleep for the next several hours ...

% echo hi; _=foo; echo $_
hi
hi

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

I'm not sure if this is better than printing a warning that $_ is readonly. :)

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* Field splitting: extra empty field with final non-whitespace IFS character
@ 2015-06-22  3:06  5% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-06-22  3:06 UTC (permalink / raw)
  To: zsh-workers

% emulate sh
% IFS=':'
% x='a:b::'
% set -- $x
% echo $#
4

zsh counts 4 fields instead of 3, like most other shells do. In other
words, zsh does not treat the non-whitespace IFS character as a field
terminator.

POSIX:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
"The shell shall treat each character of the IFS as a delimiter and use
the delimiters as field TERMINATORS to split the results of parameter
expansion and command substitution into fields." (emphasis mine)

bash, ash, dash, ksh93 and mksh act according to POSIX.

pdksh (which is obsolete) and yash act like zsh.

I think this should be changed to match the behaviour specified by POSIX
in sh and ksh emulation modes.

Thanks,

- Martijn


^ permalink raw reply	[relevance 5%]

* Re: "_alternative:shift:14: shift count must be <= $#" with zsh-5.0.8
  @ 2015-06-23 10:53  3% ` Peter Stephenson
  2015-06-23 11:19  0%   ` Markus Trippelsdorf
  0 siblings, 1 reply; 200+ results
From: Peter Stephenson @ 2015-06-23 10:53 UTC (permalink / raw)
  To: zsh-workers

On Tue, 23 Jun 2015 09:16:13 +0200
Markus Trippelsdorf <markus@trippelsdorf.de> wrote:
> Since the update to zsh-5.0.8 I observe the following issue:
> 
> _alternative:shift:14: shift count must be <= $#

shift OPTIND-1

Hmm...

POSIX_BUILTINS <K> <S>
       Furthermore, the getopts builtin behaves in  a  POSIX-compatible
       fashion in that the associated variable OPTIND is not made local
       to functions.

There ought to be a better way of doing this...

pws

diff --git a/Completion/compinit b/Completion/compinit
index 79f9d42..4b9a778 100644
--- a/Completion/compinit
+++ b/Completion/compinit
@@ -152,6 +152,7 @@ _comp_options=(
     NO_kshtypeset
     NO_markdirs
     NO_octalzeroes
+    NO_posixbuiltins
     NO_shwordsplit
     NO_shglob
     NO_warncreateglobal


^ permalink raw reply	[relevance 3%]

* Re: "_alternative:shift:14: shift count must be <= $#" with zsh-5.0.8
  2015-06-23 10:53  3% ` Peter Stephenson
@ 2015-06-23 11:19  0%   ` Markus Trippelsdorf
  0 siblings, 0 replies; 200+ results
From: Markus Trippelsdorf @ 2015-06-23 11:19 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On 2015.06.23 at 11:53 +0100, Peter Stephenson wrote:
> On Tue, 23 Jun 2015 09:16:13 +0200
> Markus Trippelsdorf <markus@trippelsdorf.de> wrote:
> > Since the update to zsh-5.0.8 I observe the following issue:
> > 
> > _alternative:shift:14: shift count must be <= $#
> 
> shift OPTIND-1
> 
> Hmm...
> 
> POSIX_BUILTINS <K> <S>
>        Furthermore, the getopts builtin behaves in  a  POSIX-compatible
>        fashion in that the associated variable OPTIND is not made local
>        to functions.
> 
> There ought to be a better way of doing this...
> 
> pws
> 
> diff --git a/Completion/compinit b/Completion/compinit
> index 79f9d42..4b9a778 100644
> --- a/Completion/compinit
> +++ b/Completion/compinit
> @@ -152,6 +152,7 @@ _comp_options=(
>      NO_kshtypeset
>      NO_markdirs
>      NO_octalzeroes
> +    NO_posixbuiltins
>      NO_shwordsplit
>      NO_shglob
>      NO_warncreateglobal

Many thanks. The patch fixes the issue.

-- 
Markus


^ permalink raw reply	[relevance 0%]

* Another thought about typeset-array: effect of/on POSIX_BUILTINS ?
@ 2015-06-24  6:53  3% Bart Schaefer
  2015-06-24  8:33  0% ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-24  6:53 UTC (permalink / raw)
  To: zsh-workers

Several of the aliases for typeset that we have just made into reserved
words are classified as POSIX "special builtins".  Do they need to have
reserved word behavior when POSIX_BUILTINS is set and those builtins are
prefixed by the "command" token?


^ permalink raw reply	[relevance 3%]

* Re: Another thought about typeset-array: effect of/on POSIX_BUILTINS ?
  2015-06-24  6:53  3% Another thought about typeset-array: effect of/on POSIX_BUILTINS ? Bart Schaefer
@ 2015-06-24  8:33  0% ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-06-24  8:33 UTC (permalink / raw)
  To: zsh-workers

On Tue, 23 Jun 2015 23:53:11 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> Several of the aliases for typeset that we have just made into reserved
> words are classified as POSIX "special builtins".  Do they need to have
> reserved word behavior when POSIX_BUILTINS is set and those builtins are
> prefixed by the "command" token?

That's an interesting question --- command itself would have to be a
reserved word for this to work --- but it doesn't seem to be how bash
works.

[pws@pwslap01u ~]$ typeset foo=(one two)
[pws@pwslap01u ~]$ command typeset foo=(one two)
bash: syntax error near unexpected token `('

pws


^ permalink raw reply	[relevance 0%]

* '>>' does not create file if set -C (noclobber) is active
@ 2015-06-25  1:02  4% Martijn Dekker
  2015-06-25  1:49  5% ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-25  1:02 UTC (permalink / raw)
  To: zsh-workers

If the 'noclobber' option (set -C) is active, the append ('>>') output
redirection will not create a file if it doesn't exist.

% set -C
% echo hi >> blah
zsh: no such file or directory: blah

POSIX:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07_03
"If the file does not exist, it shall be created." It does not mention
that the noclobber option should influence this.

By definition, a file that doesn't exist cannot be clobbered, so it
seems to me that logically this shell option shouldn't apply.

bash, (d)ash, ksh93, mksh, and yash all act like POSIX says.

I have no opinion on whether this should be an overall fix or a fix for
the emulation modes.

Thanks,

- Martijn


^ permalink raw reply	[relevance 4%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25  1:02  4% '>>' does not create file if set -C (noclobber) is active Martijn Dekker
@ 2015-06-25  1:49  5% ` Bart Schaefer
  2015-06-25  2:22  0%   ` Martijn Dekker
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-25  1:49 UTC (permalink / raw)
  To: Martijn Dekker, zsh-workers

On Jun 25,  3:02am, Martijn Dekker wrote:
}
} If the 'noclobber' option (set -C) is active, the append ('>>') output
} redirection will not create a file if it doesn't exist.
} 
} POSIX:

The noclobber option is an extension, and has nothing whatsoever to do
with POSIX.  It is not normally on in any emulation, so as soon as you
set it you're off in the weeds and appeal to POSIX is meaningless.

This is working the way it's intended to work.


^ permalink raw reply	[relevance 5%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25  1:49  5% ` Bart Schaefer
@ 2015-06-25  2:22  0%   ` Martijn Dekker
  2015-06-25  7:30  3%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-25  2:22 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

Bart Schaefer schreef op 25-06-15 om 03:49:
> On Jun 25,  3:02am, Martijn Dekker wrote:
> }
> } If the 'noclobber' option (set -C) is active, the append ('>>') output
> } redirection will not create a file if it doesn't exist.
> } 
> } POSIX:
> 
> The noclobber option is an extension, and has nothing whatsoever to do
> with POSIX.  It is not normally on in any emulation, so as soon as you
> set it you're off in the weeds and appeal to POSIX is meaningless.

That is not correct.

See:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_25

-C
    (Uppercase C.) Prevent existing files from being overwritten by the
shell's '>' redirection operator (see Redirecting Output); the ">|"
redirection operator shall override this noclobber option for an
individual file.

[...]

-o  option
[...]
noclobber
    Equivalent to -C (uppercase C).

Thanks,

- M.


^ permalink raw reply	[relevance 0%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25  2:22  0%   ` Martijn Dekker
@ 2015-06-25  7:30  3%     ` Bart Schaefer
  2015-06-25 14:04  3%       ` Stephane Chazelas
  2015-06-26 14:14  4%       ` Martijn Dekker
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2015-06-25  7:30 UTC (permalink / raw)
  To: zsh-workers

On Jun 25,  4:22am, Martijn Dekker wrote:
} Subject: Re: '>>' does not create file if set -C (noclobber) is active
}
} > The noclobber option is an extension, and has nothing whatsoever to do
} > with POSIX.
} 
} That is not correct.

Well, damn.  When did they do that?

As far as I know, this was first implemented in zsh and has worked as it
does in zsh since around 1990 -- there is no mention of the -C option in
the ksh88 manual, for example.  So I'm still inclined to say that this
is just not going to change, because we'd either have to (1) change it in
native mode or (2) do one of those hacks that tests the emulation mode
so it only works if you actually start the shell that way or (3) add an
entirely new setopt just for this.  I don't like any of those choices.


^ permalink raw reply	[relevance 3%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25  7:30  3%     ` Bart Schaefer
@ 2015-06-25 14:04  3%       ` Stephane Chazelas
  2015-06-25 16:00  3%         ` Bart Schaefer
  2015-06-26 14:14  4%       ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Stephane Chazelas @ 2015-06-25 14:04 UTC (permalink / raw)
  To: zsh-workers

2015-06-25 00:30:47 -0700, Bart Schaefer:
> On Jun 25,  4:22am, Martijn Dekker wrote:
> } Subject: Re: '>>' does not create file if set -C (noclobber) is active
> }
> } > The noclobber option is an extension, and has nothing whatsoever to do
> } > with POSIX.
> } 
> } That is not correct.
> 
> Well, damn.  When did they do that?
> 
> As far as I know, this was first implemented in zsh and has worked as it
> does in zsh since around 1990 -- there is no mention of the -C option in
> the ksh88 manual, for example.  So I'm still inclined to say that this
> is just not going to change, because we'd either have to (1) change it in
> native mode or (2) do one of those hacks that tests the emulation mode
> so it only works if you actually start the shell that way or (3) add an
> entirely new setopt just for this.  I don't like any of those choices.

Though that's initially a csh feature (from the start: 1979),
AFAIK, noclobber has always been in ksh. But the -C alias may
have been added in ksh93 and retrofitted to ksh88. The ksh88a
(http://www.in-ulm.de/~mascheck/various/shells/ksh88-fixes)
release notes mention noclobber. The ksh93 release notes mention
adding -C as an alias for noclobber.

The original pdksh didn't have either. I don't know when they
were added.

It was added to bash in January 1990 but first as a variable.
1.12 (Dec 1991) had it as both set -C and set -o noclobber.

I suspect both were already in POSIX.2. It was added to ash in
4.4BSD-Alpha (1992):
http://www.in-ulm.de/~mascheck/various/ash/index.html#44bsdalpha

I don't think it was ever added to the Bourne shell though.

-- 
Stephane


^ permalink raw reply	[relevance 3%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25 14:04  3%       ` Stephane Chazelas
@ 2015-06-25 16:00  3%         ` Bart Schaefer
  2015-06-25 19:20  4%           ` Chet Ramey
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-25 16:00 UTC (permalink / raw)
  To: zsh-workers

On Jun 25,  3:04pm, Stephane Chazelas wrote:
} Subject: Re: '>>' does not create file if set -C (noclobber) is active
}
} Though that's initially a csh feature (from the start: 1979),

Well, yeah, but the odds that POSIX adopted it from csh are pretty low.
Zsh adopted it from csh.

Thanks for the other summary, though.


^ permalink raw reply	[relevance 3%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25 16:00  3%         ` Bart Schaefer
@ 2015-06-25 19:20  4%           ` Chet Ramey
  0 siblings, 0 replies; 200+ results
From: Chet Ramey @ 2015-06-25 19:20 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers; +Cc: chet.ramey

On 6/25/15 12:00 PM, Bart Schaefer wrote:
> On Jun 25,  3:04pm, Stephane Chazelas wrote:
> } Subject: Re: '>>' does not create file if set -C (noclobber) is active
> }
> } Though that's initially a csh feature (from the start: 1979),
> 
> Well, yeah, but the odds that POSIX adopted it from csh are pretty low.
> Zsh adopted it from csh.

ksh88 picked up noclobber from csh, but used `set -o noclobber' and added
the >| redirection.  Posix.2 invented `set -C'.  Bash adopted noclobber
from ksh in 1990 and set -C/-o noclobber from a pre-1992 Posix.2 draft in
1991.

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


^ permalink raw reply	[relevance 4%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-25  7:30  3%     ` Bart Schaefer
  2015-06-25 14:04  3%       ` Stephane Chazelas
@ 2015-06-26 14:14  4%       ` Martijn Dekker
  2015-06-26 20:15  4%         ` Bart Schaefer
  2015-06-27 17:02  7%         ` Peter Stephenson
  1 sibling, 2 replies; 200+ results
From: Martijn Dekker @ 2015-06-26 14:14 UTC (permalink / raw)
  To: Bart Schaefer, zsh-workers

Bart Schaefer schreef op 25-06-15 om 09:30:
> So I'm still inclined to say that this
> is just not going to change, because we'd either have to (1) change it in
> native mode or (2) do one of those hacks that tests the emulation mode
> so it only works if you actually start the shell that way or (3) add an
> entirely new setopt just for this.  I don't like any of those choices.

I can understand and sympathize with this point of view. But, from my
point of view as someone writing cross-platform POSIX shell programs,
this is a legitimate compliance bug that breaks scripts running under
'set -C' that should be expected to work according to the standard. (It
has done in at least one real-life case, i.e. mine). A shell-specific
workaround ought not to be necessary for this. If the goal of 'emulate
sh' is to provide a compatible POSIX environment then this situation is
clearly inconsistent with that goal. So I hope you're willing to
reconsider and think of a solution -- perhaps a SH_APPEND shell option
(which would also apply to ksh emulation).

Thanks,

- M.


^ permalink raw reply	[relevance 4%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-26 14:14  4%       ` Martijn Dekker
@ 2015-06-26 20:15  4%         ` Bart Schaefer
  2015-06-27  1:54  5%           ` Martijn Dekker
  2015-06-27 17:02  7%         ` Peter Stephenson
  1 sibling, 1 reply; 200+ results
From: Bart Schaefer @ 2015-06-26 20:15 UTC (permalink / raw)
  To: zsh-workers

On Jun 26,  4:14pm, Martijn Dekker wrote:
}
} workaround ought not to be necessary for this. If the goal of 'emulate
} sh' is to provide a compatible POSIX environment then this situation is
} clearly inconsistent with that goal.

The goal of "emulate sh" is to provide a Bourne-sh compatible environment,
for the most part.

Just for example, neither POSIX_ARGZERO nor POSIX_CD is turned on by
default in any of the "emulate" modes, and there are a number of other
POSIX-isms that are not (yet, at least) supported at all.

That said, I'm not trying to shut down discussion of this issue, I'm just
pointing out that we're going to be choosing a least of evils whether we
do something or do nothing.


^ permalink raw reply	[relevance 4%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-26 20:15  4%         ` Bart Schaefer
@ 2015-06-27  1:54  5%           ` Martijn Dekker
  2015-06-27  3:38  6%             ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-27  1:54 UTC (permalink / raw)
  To: zsh-workers

Bart Schaefer schreef op 26-06-15 om 22:15:
> The goal of "emulate sh" is to provide a Bourne-sh compatible environment,
> for the most part.

I see. Since POSIX is now the lowest common denominator for the
overwhelming majority of Unix-like systems out there, I suppose I was
just assuming that was the intended target by now.

> Just for example, neither POSIX_ARGZERO nor POSIX_CD is turned on by
> default in any of the "emulate" modes, and there are a number of other
> POSIX-isms that are not (yet, at least) supported at all.

Hmm. On my system (zsh 5.0.8) POSIX_CD is in fact turned on by 'emulate
sh'. The only options I've found so far that aren't turned on, but
should be for POSIX compliance, are POSIX_ARGZERO (as you say), and
MULTIBYTE (but that was changed in git shortly after 5.0.8 was released).

So far, I've found that zsh 5.0.8 under 'emulate sh -o POSIX_ARGZERO -o
MULTIBYTE' is very close to a complete POSIX shell. I'd be very
interested to know exactly what other POSIX-isms are not yet supported
by zsh, so I can implement any necessary tests and workarounds in the
shell library I'm developing.

> That said, I'm not trying to shut down discussion of this issue, I'm just
> pointing out that we're going to be choosing a least of evils whether we
> do something or do nothing.

I understand. Thanks for your time and consideration in any case.

- Martijn


^ permalink raw reply	[relevance 5%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-27  1:54  5%           ` Martijn Dekker
@ 2015-06-27  3:38  6%             ` Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-06-27  3:38 UTC (permalink / raw)
  To: zsh-workers

On Jun 27,  3:54am, Martijn Dekker wrote:
}
} Hmm. On my system (zsh 5.0.8) POSIX_CD is in fact turned on by 'emulate
} sh'.

Documentation error, then.

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index b4a5e10..2371e35 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -124,7 +124,7 @@ pindex(POSIXCD)
 pindex(NO_POSIX_CD)
 pindex(NOPOSIXCD)
 cindex(CDPATH, order of checking)
-item(tt(POSIX_CD))(
+item(tt(POSIX_CD) <K> <S>)(
 Modifies the behaviour of tt(cd), tt(chdir) and tt(pushd) commands
 to make them more compatible with the POSIX standard. The behaviour with
 the option unset is described in the documentation for the tt(cd)


^ permalink raw reply	[relevance 6%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-26 14:14  4%       ` Martijn Dekker
  2015-06-26 20:15  4%         ` Bart Schaefer
@ 2015-06-27 17:02  7%         ` Peter Stephenson
  2015-06-28  0:02  3%           ` Martijn Dekker
  1 sibling, 1 reply; 200+ results
From: Peter Stephenson @ 2015-06-27 17:02 UTC (permalink / raw)
  To: zsh-workers

This isn't very elegant, but nor is it obviously problematic, and it
does at least draw attention to a potential issue.

pws

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 2371e35..6dd2239 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1819,6 +1819,20 @@ Make the tt(echo) builtin compatible with the BSD manref(echo)(1) command.
 This disables backslashed escape sequences in echo strings unless the
 tt(-e) option is specified.
 )
+pindex(CLOBBER_APPEND)
+pindex(NO_CLOBBER_APPEND)
+pindex(CLOBBERAPPEND)
+pindex(NOCLOBBERAPPEND)
+cindex(clobbering, POSIX compatibility)
+cindex(file clobbering, POSIX compatibility)
+cindex(no clobber, POSIX compatible)
+item(tt(CLOBBER_APPEND) <K> <S>)(
+This option only applies when tt(NO_CLOBBER) (-tt(C)) is in effect.
+
+If this option is not set, the shell will report an error when a
+append redirection (tt(>>)) is used on a file that does not already
+exists.  If the option is set, no error is reported.
+)
 pindex(CONTINUE_ON_ERROR)
 pindex(NO_CONTINUE_ON_ERROR)
 pindex(CONTINUEONERROR)
diff --git a/Src/exec.c b/Src/exec.c
index 50a11eb..4ddfdf4 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3315,7 +3315,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		    fil = -1;
 		else if (IS_APPEND_REDIR(fn->type))
 		    fil = open(unmeta(fn->name),
-			       (unset(CLOBBER) && !IS_CLOBBER_REDIR(fn->type)) ?
+			       ((unset(CLOBBER) || isset(CLOBBERAPPEND)) &&
+				!IS_CLOBBER_REDIR(fn->type)) ?
 			       O_WRONLY | O_APPEND | O_NOCTTY :
 			       O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0666);
 		else
diff --git a/Src/options.c b/Src/options.c
index da3d830..3a0c838 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -110,6 +110,7 @@ static struct optname optns[] = {
 {{NULL, "chaselinks",	      OPT_EMULATE},		 CHASELINKS},
 {{NULL, "checkjobs",	      OPT_EMULATE|OPT_ZSH},	 CHECKJOBS},
 {{NULL, "clobber",	      OPT_EMULATE|OPT_ALL},	 CLOBBER},
+{{NULL, "clobberappend",      OPT_EMULATE|OPT_BOURNE},	 CLOBBER},
 {{NULL, "combiningchars",     0},			 COMBININGCHARS},
 {{NULL, "completealiases",    0},			 COMPLETEALIASES},
 {{NULL, "completeinword",     0},			 COMPLETEINWORD},
diff --git a/Src/zsh.h b/Src/zsh.h
index ce9b979..05efa5f 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2120,6 +2120,7 @@ enum {
     CHASELINKS,
     CHECKJOBS,
     CLOBBER,
+    CLOBBERAPPEND,
     COMBININGCHARS,
     COMPLETEALIASES,
     COMPLETEINWORD,


^ permalink raw reply	[relevance 7%]

* Strange regression in zsh-git with redirecting output of 'readonly'
@ 2015-06-27 22:19  3% Martijn Dekker
  0 siblings, 0 replies; 200+ results
From: Martijn Dekker @ 2015-06-27 22:19 UTC (permalink / raw)
  To: zsh-workers

There's a regression in current zsh git version: attempting to
redirecting the output of a "readonly" with assignment argument (i.e. a
potential error message) causes at least three kinds of different and
unpredictable strange behaviour. But in all three cases, the command
fails to work. In zsh 5.0.8 and earlier, all this works fine.

First manifestation:

On my Mac, when standard output is redirected, the command does
absolutely nothing. The variable is not assigned or even set.

% readonly var=testvalue >/dev/null
% echo ${var+set}

%

Second manifestation:

When redirecting standard error instead, something very strange happens.
But the variable is still not assigned or set.

% readonly var=testvalue 2>/dev/null
'!'=0
'#'=0
'$'=66831
'*'=()
-=bims
'?'=0
@=()
ARGC=0
HISTCMD=6
LINENO=6
PPID=81942
TTYIDLE=0
ZSH_EVAL_CONTEXT=toplevel
ZSH_SUBSHELL=0
status=0
zsh_eval_context=(toplevel)
% echo ${var+set}

%

Third manifestation:

In the initialization routine of the cross-platform shell library I'm
developing, I redirect standard error of 'readonly' to suppress an error
message and then check the result to see if the current shell supports
assignment with the 'readonly' command (one of a number of POSIX
compliance checks). The library is loaded as a dot script. The readonly
command in that context gives different behaviour still:

% . modernish
/Users/martijn/bin/modernish:76: no such file or directory:
%

The shell exits immediately after producing this error. The 'readonly'
command is on line 76 (which references no file or directory at all), so
that's a third manifestation of strange behaviour. The relevant snippet
from my library, starting at line 76, is:

readonly MSH_VERSION=0.01dev 2>| /dev/null
test "${MSH_VERSION:-}" = 0.01dev || {
        echo "[BUG000] 'readonly' command doesn't support assignment." 1>&2
        _Msh_defect=y
}

Nevertheless, when I issue that same 'readonly' command in interactive
mode, that shell variable dump happens again:

% readonly MSH_VERSION=0.01dev 2>| /dev/null
'!'=0
'#'=0
'$'=66839
'*'=()
-=bims
'?'=0
@=()
ARGC=0
HISTCMD=1
LINENO=1
PPID=81942
TTYIDLE=0
ZSH_EVAL_CONTEXT=toplevel
ZSH_SUBSHELL=0
status=0
zsh_eval_context=(toplevel)
%

I hope this has been sufficient information to figure out what's going on.

Thanks,

- Martijn


^ permalink raw reply	[relevance 3%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-27 17:02  7%         ` Peter Stephenson
@ 2015-06-28  0:02  3%           ` Martijn Dekker
  2015-06-28 17:19 10%             ` Peter Stephenson
  0 siblings, 1 reply; 200+ results
From: Martijn Dekker @ 2015-06-28  0:02 UTC (permalink / raw)
  To: zsh-workers

Peter Stephenson schreef op 27-06-15 om 19:02:
> This isn't very elegant, but nor is it obviously problematic, and it
> does at least draw attention to a potential issue.

I've tested this patch against the current git version and noticed the
following:

- The new clobberappend option is on by default, but 'set -C' (-o
noclobber) turns clobberappend off. Conversely, 'set +C' (+o noclobber)
turns it back on. This applies even when noclobber is already on or off.

- Contrary to the documentation, unsetting clobberappend has effect even
when noclobber is not active. IOW, this currently provides a way to keep
'>>' from creating files even when noclobber is off.

- 'emulate sh' and 'emulate ksh' do not make any difference to the above.

While it's good to be able to modify this behaviour, this does not
achieve POSIX compatibility for 'set -C': even in the emulation modes,
'>>' still won't create nonexistent files, and enabling this ability
requires a zsh-specific 'set -o clobberappend' command.

At the risk of pedantry, I also wonder if 'createappend' or
'appendcreate' would be a better name, since "clobbering" is commonly
understood to mean overwriting pre-existing files, not creating new ones.

Hope this helps,

- M.


^ permalink raw reply	[relevance 3%]

* Re: '>>' does not create file if set -C (noclobber) is active
  2015-06-28  0:02  3%           ` Martijn Dekker
@ 2015-06-28 17:19 10%             ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-06-28 17:19 UTC (permalink / raw)
  To: zsh-workers

On Sun, 28 Jun 2015 02:02:05 +0200
Martijn Dekker <martijn@inlv.org> wrote:
> Peter Stephenson schreef op 27-06-15 om 19:02:
> > This isn't very elegant, but nor is it obviously problematic, and it
> > does at least draw attention to a potential issue.
> 
> I've tested this patch against the current git version and noticed the
> following:

Yep, I got throughly confused about the logic.  I think this is now
correct.

It doesn't have to have a name with CLOBBER in it, though it does have
to be related to NO_CLOBBER --- the whole point is to choose between
long-standing and documented zsh behaviour, and POSIX behaviour, when
you have NO_CLOBBER set.  You can now also make your own decision which
you want, and don't need to post messages to the list to tell us :-).
I've called it APPEND_CREATE.

diff --git a/Doc/Zsh/options.yo b/Doc/Zsh/options.yo
index 2371e35..833c975 100644
--- a/Doc/Zsh/options.yo
+++ b/Doc/Zsh/options.yo
@@ -1094,10 +1094,12 @@ pindex(NOCLOBBER)
 cindex(clobbering, of files)
 cindex(file clobbering, allowing)
 item(tt(CLOBBER) (tt(PLUS()C), ksh: tt(PLUS()C)) <D>)(
-Allows `tt(>)' redirection to truncate existing files,
-and `tt(>>)' to create files.
-Otherwise `tt(>!)' or `tt(>|)' must be used to truncate a file,
-and `tt(>>!)' or `tt(>>|)' to create a file.
+Allows `tt(>)' redirection to truncate existing files.
+Otherwise `tt(>!)' or `tt(>|)' must be used to truncate a file.
+
+If the option is not set, and the option tt(APPEND_CREATE) is also
+not set, `tt(>>!)' or `tt(>>|)' must be used to create a file.
+If either option is set, `tt(>>)' may be used.
 )
 pindex(CORRECT)
 pindex(NO_CORRECT)
@@ -1792,6 +1794,21 @@ enditem()
 
 subsect(Shell Emulation)
 startitem()
+pindex(APPEND_CREATE
+pindex(NO_APPEND_CREATE)
+pindex(APPENDCREATE)
+pindex(NOAPPENDCREATE)
+cindex(clobbering, POSIX compatibility)
+cindex(file clobbering, POSIX compatibility)
+cindex(no clobber, POSIX compatible)
+item(tt(APPEND_CREATE) <K> <S>)(
+This option only applies when tt(NO_CLOBBER) (-tt(C)) is in effect.
+
+If this option is not set, the shell will report an error when a
+append redirection (tt(>>)) is used on a file that does not already
+exists (the traditional zsh behaviour of tt(NO_CLOBBER)).  If the option
+is set, no error is reported (POSIX behaviour).
+)
 pindex(BASH_REMATCH)
 pindex(NO_BASH_REMATCH)
 pindex(BASHREMATCH)
diff --git a/Src/exec.c b/Src/exec.c
index 39d1326..960601f 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -3315,7 +3315,8 @@ execcmd(Estate state, int input, int output, int how, int last1)
 		    fil = -1;
 		else if (IS_APPEND_REDIR(fn->type))
 		    fil = open(unmeta(fn->name),
-			       (unset(CLOBBER) && !IS_CLOBBER_REDIR(fn->type)) ?
+			       ((unset(CLOBBER) && unset(APPENDCREATE)) &&
+				!IS_CLOBBER_REDIR(fn->type)) ?
 			       O_WRONLY | O_APPEND | O_NOCTTY :
 			       O_WRONLY | O_APPEND | O_CREAT | O_NOCTTY, 0666);
 		else
diff --git a/Src/options.c b/Src/options.c
index da3d830..320f46b 100644
--- a/Src/options.c
+++ b/Src/options.c
@@ -110,6 +110,7 @@ static struct optname optns[] = {
 {{NULL, "chaselinks",	      OPT_EMULATE},		 CHASELINKS},
 {{NULL, "checkjobs",	      OPT_EMULATE|OPT_ZSH},	 CHECKJOBS},
 {{NULL, "clobber",	      OPT_EMULATE|OPT_ALL},	 CLOBBER},
+{{NULL, "appendcreate",	      OPT_EMULATE|OPT_BOURNE},	 APPENDCREATE},
 {{NULL, "combiningchars",     0},			 COMBININGCHARS},
 {{NULL, "completealiases",    0},			 COMPLETEALIASES},
 {{NULL, "completeinword",     0},			 COMPLETEINWORD},
diff --git a/Src/zsh.h b/Src/zsh.h
index ce9b979..183620f 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -2120,6 +2120,7 @@ enum {
     CHASELINKS,
     CHECKJOBS,
     CLOBBER,
+    APPENDCREATE,
     COMBININGCHARS,
     COMPLETEALIASES,
     COMPLETEINWORD,


^ permalink raw reply	[relevance 10%]

* I almost hate to ask this, but:  Version 5.0.9?
@ 2015-07-25 22:46  3% Bart Schaefer
  2015-07-26  6:12  0% ` Mikael Magnusson
  2015-07-26 16:55  0% ` Peter Stephenson
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2015-07-25 22:46 UTC (permalink / raw)
  To: zsh-workers

I know it hasn't been that long since 5.0.8 but we've fixed a bunch of crash
bugs and deadlocks.  Heck, the "case" wordcode problem is probably bad enough
by itself to warrant a new release.

There are a few of Oliver's patches, including those during the sourceforge
outage, that haven't been pushed yet, but otherwise the most significant
thing I can recall that hasn't been addressed is the probable POSIX getopts
incompatibility.

Counter-point would be that the new typeset behavior hasn't been in the wild
for very long.


^ permalink raw reply	[relevance 3%]

* Re: I almost hate to ask this, but: Version 5.0.9?
  2015-07-25 22:46  3% I almost hate to ask this, but: Version 5.0.9? Bart Schaefer
@ 2015-07-26  6:12  0% ` Mikael Magnusson
  2015-07-26 16:55  0% ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Mikael Magnusson @ 2015-07-26  6:12 UTC (permalink / raw)
  To: zsh workers

On Sun, Jul 26, 2015 at 12:46 AM, Bart Schaefer
<schaefer@brasslantern.com> wrote:
> I know it hasn't been that long since 5.0.8 but we've fixed a bunch of crash
> bugs and deadlocks.  Heck, the "case" wordcode problem is probably bad enough
> by itself to warrant a new release.
>
> There are a few of Oliver's patches, including those during the sourceforge
> outage, that haven't been pushed yet, but otherwise the most significant
> thing I can recall that hasn't been addressed is the probable POSIX getopts
> incompatibility.
>
> Counter-point would be that the new typeset behavior hasn't been in the wild
> for very long.

I would say wait at least a few days for the $(( )) stuff? Those
patches looked a bit scary. And is the undo limit stuff sorted out? (I
haven't gotten around to actually testing git myself in a bit, just
looking over threads). Other than that, I can't think of anything.

-- 
Mikael Magnusson


^ permalink raw reply	[relevance 0%]

* Re: I almost hate to ask this, but:  Version 5.0.9?
  2015-07-25 22:46  3% I almost hate to ask this, but: Version 5.0.9? Bart Schaefer
  2015-07-26  6:12  0% ` Mikael Magnusson
@ 2015-07-26 16:55  0% ` Peter Stephenson
  1 sibling, 0 replies; 200+ results
From: Peter Stephenson @ 2015-07-26 16:55 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers

On Sat, 25 Jul 2015 15:46:37 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> I know it hasn't been that long since 5.0.8 but we've fixed a bunch of crash
> bugs and deadlocks.  Heck, the "case" wordcode problem is probably bad enough
> by itself to warrant a new release.
> 
> There are a few of Oliver's patches, including those during the sourceforge
> outage, that haven't been pushed yet, but otherwise the most significant
> thing I can recall that hasn't been addressed is the probable POSIX getopts
> incompatibility.
> 
> Counter-point would be that the new typeset behavior hasn't been in the wild
> for very long.

Sooner rather than later, anyway.  It would be good to wait until things
settle down after the outage.

pws


^ permalink raw reply	[relevance 0%]

* Re: Deadlock when receiving kill-signal from child process
  @ 2015-08-06 15:54  2%                             ` Bart Schaefer
  2015-08-07  0:45  2%                               ` Mathias Fredriksson
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-08-06 15:54 UTC (permalink / raw)
  To: zsh-workers

On Aug 6, 11:24am, Mathias Fredriksson wrote:
} Subject: Re: Deadlock when receiving kill-signal from child process
}
} On Thu, Aug 6, 2015 at 8:06 AM, Bart Schaefer wrote:
} }
} } I played around with this a bit by hacking loop() but the effect is
} } that with the test script Mathais provided, most of the USR1 signals
} } are just thrown away (they collapse into a single call to the trap
} } handler).  Not sure if that's actually the desired effect.
} 
} I would imagine some might rely on every signal being handled, e.g.
} keeping a count.

Even without spending most of the time in queuing, *some* of the signals
get dropped at the OS level.  The only way I can get them all to be
tallied is to remove the "sleep" from the trap function.

} The following traces have the last patches applied (I did multiple
} runs to see if I could hit different states):
} 
} #15 0x000000010df38e63 in runshfunc ()
} #16 0x000000010df38936 in doshfunc ()

This is confirms my suspicion about doshfunc().  Sadly it's called all
over the place, sometimes with signals explicitly un-queued and other
times with no change to the surrounding context.

} #0  0x00007fff8abfe166 in __psynch_mutexwait ()
} #1  0x00007fff8e4b578a in _pthread_mutex_lock ()
} #2  0x00007fff82ce5750 in fputc ()
} #9  <signal handler called>
} #22 <signal handler called>
} #32 <signal handler called>
} #34 0x00007fff8e4b5714 in _pthread_mutex_lock ()
} #35 0x00007fff82ce43a3 in ferror ()

This is the stdio thing again.  Anyone reading this familar enough with
the POSIX or C standards to point to whether stdio is required to be
signal-safe with pthreads?  I.e., is this our bug or someone else's?

(Not that zsh is using threads, but stdio is using pthread mutexes.)

} setopt NO_ASYNC_TRAPS:

NO_TRAPS_ASYNC ?

Anyway, same two issues as above, just slightly different paths (no
multiple signal handers in the stdio case, but one is enough).

As with the previous dotrapargs() patch, I'm a little nervous about
the dont_queue_signals() bits, but that's the only safe way to do
the disabling part of signal queueing when the enabling part is not
in local scope.

diff --git a/Src/exec.c b/Src/exec.c
index 7612d43..2886785 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -4820,11 +4833,9 @@ execshfunc(Shfunc shf, LinkList args)
     if ((osfc = sfcontext) == SFC_NONE)
 	sfcontext = SFC_DIRECT;
     xtrerr = stderr;
-    unqueue_signals();
 
     doshfunc(shf, args, 0);
 
-    queue_signals();
     sfcontext = osfc;
     free(cmdstack);
     cmdstack = ocs;
@@ -5039,6 +5050,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     static int funcdepth;
 #endif
 
+    queue_signals();	/* Lots of memory and global state changes coming */
+
     pushheap();
 
     oargv0 = NULL;
@@ -5261,6 +5274,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
     }
     popheap();
 
+    unqueue_signals();
+
     /*
      * Exit with a tidy up.
      * Only leave if we're at the end of the appropriate function ---
@@ -5296,7 +5311,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 mod_export void
 runshfunc(Eprog prog, FuncWrap wrap, char *name)
 {
-    int cont, ouu;
+    int cont, ouu, q = queue_signal_level();
     char *ou;
 
     ou = zalloc(ouu = underscoreused);
@@ -5305,7 +5320,9 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
 
     while (wrap) {
 	wrap->module->wrapper++;
+	dont_queue_signals();
 	cont = wrap->handler(prog, wrap->next, name);
+	restore_queue_signals(q);
 	wrap->module->wrapper--;
 
 	if (!wrap->module->wrapper &&
@@ -5320,7 +5337,9 @@ runshfunc(Eprog prog, FuncWrap wrap, char *name)
 	wrap = wrap->next;
     }
     startparamscope();
+    dont_queue_signals();
     execode(prog, 1, 0, "shfunc");
+    restore_queue_signals(q);
     if (ou) {
 	setunderscore(ou);
 	zfree(ou, ouu);


^ permalink raw reply	[relevance 2%]

* Re: Deadlock when receiving kill-signal from child process
  2015-08-06 15:54  2%                             ` Bart Schaefer
@ 2015-08-07  0:45  2%                               ` Mathias Fredriksson
  0 siblings, 0 replies; 200+ results
From: Mathias Fredriksson @ 2015-08-07  0:45 UTC (permalink / raw)
  To: zsh-workers

On Thu, Aug 6, 2015 at 6:54 PM, Bart Schaefer wrote:
}
} This is the stdio thing again.  Anyone reading this familar enough with
} the POSIX or C standards to point to whether stdio is required to be
} signal-safe with pthreads?  I.e., is this our bug or someone else's?

Sadly I can't be of much assistance here, I believe you can't call
pthread mutexes from a signal handler, but that isn't whats happening
here? If I understand correctly a signal is received while a mutex
lock is (being) aquired.

}
} NO_TRAPS_ASYNC ?

Yes, my bad, typo in the email message, used the correct setopt.

}
} As with the previous dotrapargs() patch, I'm a little nervous about
} the dont_queue_signals() bits, but that's the only safe way to do
} the disabling part of signal queueing when the enabling part is not
} in local scope.

I'm not quite sure I understand what these changes do, but at least
this last patch made it a lot harder for me to have zsh lock up. I had
to leave my script running in a while true; do ...; done loop
(eventually, 30sec-10min it would hit a lock).

#0  0x00007fff8abfe72a in __sigsuspend ()
#1  0x0000000107b59287 in signal_suspend ()
#2  0x0000000107b30671 in zwaitjob ()
#3  0x0000000107b304c4 in waitjobs ()
#4  0x0000000107b130e8 in execpline ()
#5  0x0000000107b122ce in execlist ()
#6  0x0000000107b120f6 in execode ()
#7  0x0000000107b15ebf in runshfunc ()
#8  0x0000000107b157f4 in doshfunc ()
#9  0x0000000107b5a70b in dotrapargs ()
#10 0x0000000107b597b2 in handletrap ()
#11 0x0000000107b590b0 in zhandler ()
#12 <signal handler called>
#13 0x00007fff82ce43a8 in ferror ()
#14 0x0000000107b2abc2 in loop ()
#15 0x0000000107b2d7e0 in zsh_main ()
#16 0x00007fff8610c5c9 in start ()

This just seems like the same mutex stuff again:

#0  0x00007fff8abfe166 in __psynch_mutexwait ()
#1  0x00007fff8e4b578a in _pthread_mutex_lock ()
#2  0x00007fff82ce5750 in fputc ()
#3  0x0000000102c20cd5 in zputs ()
#4  0x0000000102c20b3c in mb_niceformat ()
#5  0x0000000102c201cd in zwarning ()
#6  0x0000000102c20376 in zwarn ()
#7  0x0000000102c143da in wait_for_processes ()
#8  0x0000000102c140a6 in zhandler ()
#9  <signal handler called>
#10 0x00007fff8abfe72a in __sigsuspend ()

This also looks vaguely familiar but might as well post it:

#0  0x00007fff8abf95da in syscall_thread_switch ()
#1  0x00007fff853a982d in _OSSpinLockLockSlow ()
#2  0x00007fff896d771b in szone_malloc_should_clear ()
#3  0x00007fff896d7667 in malloc_zone_malloc ()
#4  0x00007fff896d6187 in malloc ()
#5  0x0000000101ccdeaf in zalloc ()
#6  0x0000000101cee2ca in ztrdup ()
#7  0x0000000101cf89b3 in mb_niceformat ()
#8  0x0000000101cf81cd in zwarning ()
#9  0x0000000101cf8376 in zwarn ()
#10 0x0000000101cec3da in wait_for_processes ()
#11 0x0000000101cec0a6 in zhandler ()
#12 <signal handler called>
#13 0x00007fff853aacd1 in _os_lock_spin_lock ()
#14 0x00007fff896d98d6 in szone_free_definite_size ()
#15 0x0000000101ca5874 in execlist ()
#16 0x0000000101ca50f6 in execode ()
#17 0x0000000101ca8ebf in runshfunc ()
#18 0x0000000101ca87f4 in doshfunc ()
#19 0x0000000101ced70b in dotrapargs ()
#20 0x0000000101cec7b2 in handletrap ()
#21 0x0000000101ced9ec in unqueue_traps ()
#22 0x0000000101cc372b in zwaitjob ()
#23 0x0000000101cc34c4 in waitjobs ()
#24 0x0000000101ca60e8 in execpline ()
#25 0x0000000101ca52ce in execlist ()
#26 0x0000000101ccaad0 in execwhile ()
#27 0x0000000101cac0d9 in execcmd ()
#28 0x0000000101ca5d24 in execpline ()
#29 0x0000000101ca52ce in execlist ()
#30 0x0000000101ca50f6 in execode ()
#31 0x0000000101cbdb8f in loop ()
#32 0x0000000101cc07e0 in zsh_main ()
#33 0x00007fff8610c5c9 in start ()

Bonus NO_TRAPS_ASYNC:

#0  0x00007fff8abfe72a in __sigsuspend ()
#1  0x0000000107509287 in signal_suspend ()
#2  0x00000001074e0671 in zwaitjob ()
#3  0x00000001074e04c4 in waitjobs ()
#4  0x00000001074c30e8 in execpline ()
#5  0x00000001074c22ce in execlist ()
#6  0x00000001074c20f6 in execode ()
#7  0x00000001074c5ebf in runshfunc ()
#8  0x00000001074c57f4 in doshfunc ()
#9  0x000000010750a70b in dotrapargs ()
#10 0x00000001075097b2 in handletrap ()
#11 0x00000001075090b0 in zhandler ()
#12 <signal handler called>
#13 0x00007fff8abfe97a in write$NOCANCEL ()
#14 0x00007fff82ceb9ed in _swrite ()
#15 0x00007fff82ce44a7 in __sflush ()
#16 0x00007fff82ce43f5 in fflush ()
#17 0x0000000107515376 in zwarn ()
#18 0x00000001075093da in wait_for_processes ()
#19 0x00000001075090a6 in zhandler ()
#20 <signal handler called>
#21 0x00007fff8abffa12 in sigprocmask ()


^ permalink raw reply	[relevance 2%]

* PATCH for NEWS update
@ 2015-08-11 18:50  7% Bart Schaefer
  0 siblings, 0 replies; 200+ results
From: Bart Schaefer @ 2015-08-11 18:50 UTC (permalink / raw)
  To: zsh-workers

Proposed NEWS list.  If anyone wants to elaborate on these or thinks I
have missed something important, please jump in.

diff --git a/NEWS b/NEWS
index d515a60..e6bd732 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,39 @@ creates a local "scalar" containing the text "one word"
 and an array "array" containing the words "several"
 "words".
 
+- The print builtin has new options -x and -X to expand tabs.
+
+- Several new command completions and numerous updates to others.
+
+- Options to "fc" to segregate internal and shared history.
+
+- All emulations including "sh" use multibyte by default; several
+  repairs to multibyte handling.
+
+- ZLE supports "bracketed paste" mode to avoid interpreting pasted
+  newlines as accept-line.  Pastes can be highlighted for visibility
+  and to make it more obvious whether accept-line has occurred.
+
+- Improved (though still not perfect) POSIX compatibility for getopts
+  builtin when POSIX_BUILTINS is set.
+
+- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behavior.
+
+- Completion of date values now displays in a calendar format when
+  the complist module is available.  Controllable by zstyle.
+
+- New parameter UNDO_LIMIT_NO for more control over ZLE undo repeat.
+
+- Several repairs/improvements to the contributed narrow-to-region
+  ZLE function.
+
+- Many changes to child-process and signal handling to eliminate race
+  conditions and avoid deadlocks on descriptor and memory management.
+
+- New builtin sysopen in zsh/system module for detailed control of
+  file descriptor modes.
+
+
 Changes from 5.0.0 to 5.0.8
 ---------------------------
 

-- 
Barton E. Schaefer


^ permalink raw reply	[relevance 7%]

* Re: invalid characters and multi-byte [x-y] ranges
  @ 2015-09-03 10:09  4%   ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-09-03 10:09 UTC (permalink / raw)
  To: zsh-workers

2015-09-03 10:00:37 +0100, Peter Stephenson:
> On Thu, 3 Sep 2015 00:07:11 +0100
> Stephane Chazelas <stephane.chazelas@gmail.com> wrote:
> > is this (in a UTF-8 locale):
> > 
> > $ zsh -c $'[[ \xcc = [\uaa-\udd] ]]' && echo yes
> > yes
> > 
> > expected or desirable?
> 
> This comes from the function charref() in pattern.c.  We discover the
> sequence is incomplete / invalid and don't know what to do with it, so we
> simply treat the single byte as a character:
> 
> 	return (wchar_t) STOUC(*x);
> 
> (the macro ensures we get an unsigned value to cast).  Typically this
> will do what you see (though wchar_t isn't guaranteed to have that
> property).
> 
> I'm not sure what else to do here.  The function is used all over the
> pattern code so anything other than tweak the code locally to return
> another character (what?) is horrific to get consistent.  We don't want
> [[ $'\xcc' = $'\xdd' ]] to succeed, but ideally we do want [[ $'\xcc' =
> $'\xcc' ]] to succeed comparing raw bytes (we're not morally forced to
> do that in a UTF-8 locale, I don't think, but it wouldn't be very
> helpful if it didn't work).
> 
> If wchar_t is 32 bits (the only place where it wasn't used to be Cygwin
> but I think that's changed) we could cheat by adding (wchar_t)0x7FFFFF00
> to it... that would fix your problem and (I hope) keep the two above
> working, and minimsie the likelihood of generating a valid character...
> that's about the least horrific I can come up with.
[...]

There was a related discussion not so long ago on the Austin
group ML (zsh was also mentioned there) on a related subject:

http://thread.gmane.org/gmane.comp.standards.posix.austin.general/11059/focus=11118
(the whole discussion started at
http://thread.gmane.org/gmane.comp.standards.posix.austin.general/11059/focus=11098 is interesting)

and see:
https://www.python.org/dev/peps/pep-0383/

A discussed approach there was to internally represent bytes not
forming part of a valid character as code points in the range
D800-DFFF (specifically DC80 DCFF for bytes 0x80 to 0xff) (those
code points are reserved in Unicode for UTF-16 surrogates and are *not*
characters, in particular the byte-sequence that
would be the UTF-8 encoding of a 0xD800 for example (ed a0 80)
would not form a valid character so be internally represented as 
DCED DCA0 DC80.

I beleive that's what python3 does.

-- 
Stephane


^ permalink raw reply	[relevance 4%]

* Re: Pasting UTF-8 characters with bracketed-paste-magic seems broken in 5.1
  @ 2015-09-10 18:57  6%             ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-09-10 18:57 UTC (permalink / raw)
  To: Peter Stephenson; +Cc: zsh-workers

On Thu, 10 Sep 2015 17:28:40 +0100
Peter Stephenson <p.stephenson@samsung.com> wrote:
> Wouldn't be hard to add [[:INCOMPLETE::]] or [[:INVALID:]] to the
> pattern code, but that's an extra step...

Easy to write, though slightly less convenient to use than you might
hope.  The point is that we treat invalid and incomplete characters byte
by byte, so you can guarantee to detect [[:INCOMPLETE:]] as the first
byte, but you can't in general guarantee how the rest will be treated,
particularly since we don't insist multibyte means UTF-8.  So
[[:INCOMPLETE:]]* is about the best you can do to determine your
sequence is incomplete.  But in general you can't be sure the sequence
is ever going to be complete anyway, so this isn't so much of a
limitation, and I've documented it.

Now should be possible to do more in shell code...

diff --git a/Doc/Zsh/expn.yo b/Doc/Zsh/expn.yo
index d44b40a..de12c85 100644
--- a/Doc/Zsh/expn.yo
+++ b/Doc/Zsh/expn.yo
@@ -1956,6 +1956,20 @@ ifzman(the zmanref(zshparam) manual page)\
 ifnzman(noderef(Parameters Used By The Shell))\
 .
 )
+item(tt([:INCOMPLETE:]))(
+Matches a byte that starts an incomplete multibyte character.
+Note that there may be a sequence of more than one bytes that
+taken together form the prefix of a multibyte character.  To
+test for a potentially incomplete byte sequence, use the pattern
+`tt([[:INCOMPLETE:]]*)'.  This will never match a sequence starting
+with a valid multibyte character.
+)
+item(tt([:INVALID:]))(
+Matches a byte that does not start a valid multibyte character.
+Note this may be a continuation byte of an incomplete multibyte
+character as any part of a multibyte string consisting of invalid and
+incomplete multibyte characters is treated as single bytes.
+)
 item(tt([:WORD:]))(
 The character is treated as part of a word; this test is sensitive
 to the value of the tt(WORDCHARS) parameter
diff --git a/Src/Zle/comp.h b/Src/Zle/comp.h
index 34da2ca..023c418 100644
--- a/Src/Zle/comp.h
+++ b/Src/Zle/comp.h
@@ -202,8 +202,9 @@ struct cpattern {
  * TODO: this will change.
  */
 #ifdef MULTIBYTE_SUPPORT
-#define PATMATCHRANGE(r, c, ip, mtp)	mb_patmatchrange(r, c, ip, mtp)
-#define PATMATCHINDEX(r, i, cp, mtp)	mb_patmatchindex(r, i, cp, mtp)
+#define PATMATCHRANGE(r, c, ip, mtp)		\
+    mb_patmatchrange(r, c, ZMB_VALID, ip, mtp)
+#define PATMATCHINDEX(r, i, cp, mtp)    mb_patmatchindex(r, i, cp, mtp)
 #define CONVCAST(c)			((wchar_t)(c))
 #define CHR_INVALID			(WEOF)
 #else
diff --git a/Src/pattern.c b/Src/pattern.c
index b4ba33e..3b55ccf 100644
--- a/Src/pattern.c
+++ b/Src/pattern.c
@@ -145,7 +145,7 @@ typedef union upat *Upat;
  *
  *  P_ANY, P_ANYOF:  the operand is a null terminated
  *    string.  Normal characters match as expected.  Characters
- *    in the range Meta+PP_ALPHA..Meta+PP_UNKNWN do the appropriate
+ *    in the range Meta+PP_ALPHA..Meta+PP_UNKWN do the appropriate
  *    Posix range tests.  This relies on imeta returning true for these
  *    characters.  We treat unknown POSIX ranges as never matching.
  *    PP_RANGE means the next two (possibly metafied) characters form
@@ -1119,7 +1119,7 @@ patgetglobflags(char **strp, long *assertp, int *ignore)
 static const char *colon_stuffs[]  = {
     "alpha", "alnum", "ascii", "blank", "cntrl", "digit", "graph", 
     "lower", "print", "punct", "space", "upper", "xdigit", "IDENT",
-    "IFS", "IFSSPACE", "WORD", NULL
+    "IFS", "IFSSPACE", "WORD", "INCOMPLETE", "INVALID", NULL
 };
 
 /*
@@ -1870,9 +1870,9 @@ static int globdots;			/* Glob initial dots? */
 #ifdef MULTIBYTE_SUPPORT
 
 /* Get a character from the start point in a string */
-#define CHARREF(x, y)	charref((x), (y))
+#define CHARREF(x, y)	charref((x), (y), (int *)NULL)
 static wchar_t
-charref(char *x, char *y)
+charref(char *x, char *y, int *zmb_ind)
 {
     wchar_t wc;
     size_t ret;
@@ -1886,9 +1886,13 @@ charref(char *x, char *y)
 	/* Error. */
 	/* Reset the shift state for next time. */
 	memset(&shiftstate, 0, sizeof(shiftstate));
+	if (zmb_ind)
+	    *zmb_ind = (ret == MB_INVALID) ? ZMB_INVALID : ZMB_INCOMPLETE;
 	return WCHAR_INVALID(*x);
     }
 
+    if (zmb_ind)
+	*zmb_ind = ZMB_VALID;
     return wc;
 }
 
@@ -2580,10 +2584,11 @@ patmatch(Upat prog)
 		fail = 1;
 	    else {
 #ifdef MULTIBYTE_SUPPORT
-		wchar_t cr = CHARREF(patinput, patinend);
+		int zmb_ind;
+		wchar_t cr = charref(patinput, patinend, &zmb_ind);
 		char *scanop = (char *)P_OPERAND(scan);
 		if (patglobflags & GF_MULTIBYTE) {
-		    if (mb_patmatchrange(scanop, cr, NULL, NULL) ^
+		    if (mb_patmatchrange(scanop, cr, zmb_ind, NULL, NULL) ^
 			(P_OP(scan) == P_ANYOF))
 			fail = 1;
 		    else
@@ -3351,6 +3356,9 @@ patmatch(Upat prog)
  * The null-terminated specification is in range; the test
  * character is in ch.
  *
+ * zmb is one of the enum defined above charref(), for indicating
+ * incomplete or invalid multibyte characters.
+ *
  * indptr is used by completion matching, which is why this
  * function is exported.  If indptr is not NULL we set *indptr
  * to the index of the character in the range string, adjusted
@@ -3367,7 +3375,7 @@ patmatch(Upat prog)
 
 /**/
 mod_export int
-mb_patmatchrange(char *range, wchar_t ch, wint_t *indptr, int *mtp)
+mb_patmatchrange(char *range, wchar_t ch, int zmb_ind, wint_t *indptr, int *mtp)
 {
     wchar_t r1, r2;
 
@@ -3476,6 +3484,14 @@ mb_patmatchrange(char *range, wchar_t ch, wint_t *indptr, int *mtp)
 		    *indptr += r2 - r1;
 		}
 		break;
+	    case PP_INCOMPLETE:
+		if (zmb_ind == ZMB_INCOMPLETE)
+		    return 1;
+		break;
+	    case PP_INVALID:
+		if (zmb_ind == ZMB_INVALID)
+		    return 1;
+		break;
 	    case PP_UNKWN:
 		DPUTS(1, "BUG: unknown posix range passed through.\n");
 		break;
@@ -3545,6 +3561,8 @@ mb_patmatchindex(char *range, wint_t ind, wint_t *chr, int *mtp)
 	    case PP_IFS:
 	    case PP_IFSSPACE:
 	    case PP_WORD:
+	    case PP_INCOMPLETE:
+	    case PP_INVALID:
 		if (!ind) {
 		    *mtp = swtype;
 		    return 1;
@@ -3698,6 +3716,10 @@ patmatchrange(char *range, int ch, int *indptr, int *mtp)
 		if (indptr && r1 < r2)
 		    *indptr += r2 - r1;
 		break;
+	    case PP_INCOMPLETE:
+	    case PP_INVALID:
+		/* Never true if not in multibyte mode */
+		break;
 	    case PP_UNKWN:
 		DPUTS(1, "BUG: unknown posix range passed through.\n");
 		break;
@@ -3768,6 +3790,8 @@ patmatchindex(char *range, int ind, int *chr, int *mtp)
 	    case PP_IFS:
 	    case PP_IFSSPACE:
 	    case PP_WORD:
+	    case PP_INCOMPLETE:
+	    case PP_INVALID:
 		if (!ind) {
 		    *mtp = swtype;
 		    return 1;
@@ -3851,9 +3875,10 @@ static int patrepeat(Upat p, char *charstart)
     case P_ANYBUT:
 	while (scan < patinend) {
 #ifdef MULTIBYTE_SUPPORT
-	    wchar_t cr = CHARREF(scan, patinend);
+	    int zmb_ind;
+	    wchar_t cr = charref(scan, patinend, &zmb_ind);
 	    if (patglobflags & GF_MULTIBYTE) {
-		if (mb_patmatchrange(opnd, cr, NULL, NULL) ^
+		if (mb_patmatchrange(opnd, cr, zmb_ind, NULL, NULL) ^
 		    (P_OP(p) == P_ANYOF))
 		    break;
 	    } else if (patmatchrange(opnd, (int)cr, NULL, NULL) ^
diff --git a/Src/zsh.h b/Src/zsh.h
index a99c900..4e2cb65 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -1562,13 +1562,15 @@ typedef struct zpc_disables_save *Zpc_disables_save;
 #define PP_IFS    15
 #define PP_IFSSPACE   16
 #define PP_WORD   17
+#define PP_INCOMPLETE 18
+#define PP_INVALID 19
 /* Special value for last definition */
-#define PP_LAST   17
+#define PP_LAST   19
 
 /* Unknown type.  Not used in a valid token. */
-#define PP_UNKWN  18
+#define PP_UNKWN  20
 /* Range: token followed by the (possibly multibyte) start and end */
-#define PP_RANGE  19
+#define PP_RANGE  21
 
 /* Globbing flags: lower 8 bits gives approx count */
 #define GF_LCMATCHUC	0x0100
@@ -1577,6 +1579,15 @@ typedef struct zpc_disables_save *Zpc_disables_save;
 #define GF_MATCHREF	0x0800
 #define GF_MULTIBYTE	0x1000	/* Use multibyte if supported by build */
 
+enum {
+    /* Valid multibyte character from charref */
+    ZMB_VALID,
+    /* Incomplete multibyte character from charref */
+    ZMB_INCOMPLETE,
+    /* Invalid multibyte character charref */
+    ZMB_INVALID
+};
+
 /* Dummy Patprog pointers. Used mainly in executable code, but the
  * pattern code needs to know about it, too. */
 
diff --git a/Test/D07multibyte.ztst b/Test/D07multibyte.ztst
index 3fadd80..ace191f 100644
--- a/Test/D07multibyte.ztst
+++ b/Test/D07multibyte.ztst
@@ -525,3 +525,9 @@
     fi
   done
 0:Invalid characters in pattern matching
+
+  [[ $'\xe3' == [[:INCOMPLETE:]] ]] || print fail 1
+  [[ $'\xe3\x83' == [[:INCOMPLETE:]][[:INVALID:]] ]] || print fail 2
+  [[ $'\xe3\x83\x9b' != [[:INCOMPLETE:][:NVALID:]] ]] || print fail 3
+  [[ $'\xe3\x83\x9b' = ? ]] || print fail 4
+0:Testing incomplete and invalid multibyte character components


^ permalink raw reply	[relevance 6%]

* Re: bug with $PWD in /
  @ 2015-09-19 18:08  5% ` Bart Schaefer
  2015-09-19 19:28  0%   ` Stephane Chazelas
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-09-19 18:08 UTC (permalink / raw)
  To: Zsh hackers list

On Sep 16,  5:26pm, Stephane Chazelas wrote:
} 
} It looks like zsh has a similar issue as bash as reported at:
} http://thread.gmane.org/gmane.comp.shells.bash.bugs/24162

How about this?

diff --git a/Src/utils.c b/Src/utils.c
index 1de3d95..0016fa1 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -692,9 +692,19 @@ ispwd(char *s)
 {
     struct stat sbuf, tbuf;
 
-    if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0)
-	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
-	    return 1;
+    if (stat((s = unmeta(s)), &sbuf) == 0 && stat(".", &tbuf) == 0)
+	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) {
+	    /* POSIX: No element of $PWD may be "." or ".." */
+	    while (*s) {
+		if (s[0] == '.' &&
+		    (!s[1] || s[1] == '/' ||
+		     (s[1] == '.' && (!s[2] || s[2] == '/'))))
+		    break;
+		while (*s++ != '/' && *s)
+		    continue;
+	    }
+	    return !*s;
+	}
     return 0;
 }
 


^ permalink raw reply	[relevance 5%]

* Re: bug with $PWD in /
  2015-09-19 18:08  5% ` Bart Schaefer
@ 2015-09-19 19:28  0%   ` Stephane Chazelas
  2015-09-19 20:47  7%     ` Bart Schaefer
  0 siblings, 1 reply; 200+ results
From: Stephane Chazelas @ 2015-09-19 19:28 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2015-09-19 11:08:00 -0700, Bart Schaefer:
> On Sep 16,  5:26pm, Stephane Chazelas wrote:
> } 
> } It looks like zsh has a similar issue as bash as reported at:
> } http://thread.gmane.org/gmane.comp.shells.bash.bugs/24162
> 
> How about this?
> 
> diff --git a/Src/utils.c b/Src/utils.c
> index 1de3d95..0016fa1 100644
> --- a/Src/utils.c
> +++ b/Src/utils.c
> @@ -692,9 +692,19 @@ ispwd(char *s)
>  {
>      struct stat sbuf, tbuf;
>  
> -    if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0)
> -	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
> -	    return 1;
> +    if (stat((s = unmeta(s)), &sbuf) == 0 && stat(".", &tbuf) == 0)
> +	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) {
> +	    /* POSIX: No element of $PWD may be "." or ".." */
[...]

Also, as mentioned on the bash thread:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_03

SUSv4> PWD
SUSv4>    Set by the shell and by the cd utility. In the shell the value
SUSv4>    shall be initialized from the environment as follows. If a value
SUSv4>    for PWD is passed to the shell in the environment when it is
SUSv4>    executed, the value is an absolute pathname of the current working
SUSv4>    directory that is no longer than {PATH_MAX} bytes including the
SUSv4>    terminating null byte, and the value does not contain any
SUSv4>    components that are dot or dot-dot, then the shell shall set PWD
SUSv4>    to the value from the environment. Otherwise, if a value for PWD
SUSv4>    is passed to the shell in the environment when it is executed, the
SUSv4>    value is an absolute pathname of the current working directory,
SUSv4>    and the value does not contain any components that are dot or
SUSv4>    dot-dot, then it is unspecified whether the shell sets PWD to the
SUSv4>    value from the environment or sets PWD to the pathname that would
SUSv4>    be output by pwd -P. Otherwise, the sh utility sets PWD to the
SUSv4>    pathname that would be output by pwd -P. In cases where PWD is set
SUSv4>    to the value from the environment, the value can contain
SUSv4>    components that refer to files of type symbolic link. In cases
SUSv4>    where PWD is set to the pathname that would be output by pwd -P,
SUSv4>    if there is insufficient permission on the current working
SUSv4>    directory, or on any parent of that directory, to determine what
SUSv4>    that pathname would be, the value of PWD is unspecified.
SUSv4>    Assignments to this variable may be ignored. If an application
SUSv4>    sets or unsets the value of PWD, the behaviors of the cd and pwd
SUSv4>    utilities are unspecified.

So, the should recompute $PWD if the one it gets from the
environment is a relative path (it's not only about . or ..,
think of symlinks).

-- 
Stephane


^ permalink raw reply	[relevance 0%]

* Re: bug with $PWD in /
  2015-09-19 19:28  0%   ` Stephane Chazelas
@ 2015-09-19 20:47  7%     ` Bart Schaefer
  2015-09-28 18:13  3%       ` Daniel Shahaf
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-09-19 20:47 UTC (permalink / raw)
  To: Zsh hackers list

On Sep 19,  8:28pm, Stephane Chazelas wrote:
} Subject: Re: bug with $PWD in /
}
} So, the should recompute $PWD if the one it gets from the
} environment is a relative path (it's not only about . or ..,
} think of symlinks).

It'd have to be a symlink from the current directory to itself, tho.
Other symbolic links are explicitly permitted by the text you quoted.

This replaces the previous patch, although it's 90% the same.

diff --git a/Src/utils.c b/Src/utils.c
index 1de3d95..ab3b0c2 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -692,9 +692,23 @@ ispwd(char *s)
 {
     struct stat sbuf, tbuf;
 
-    if (stat(unmeta(s), &sbuf) == 0 && stat(".", &tbuf) == 0)
-	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino)
-	    return 1;
+    /* POSIX: environment PWD must be absolute */
+    if (*s != '/')
+	return 0;
+
+    if (stat((s = unmeta(s)), &sbuf) == 0 && stat(".", &tbuf) == 0)
+	if (sbuf.st_dev == tbuf.st_dev && sbuf.st_ino == tbuf.st_ino) {
+	    /* POSIX: No element of $PWD may be "." or ".." */
+	    while (*s) {
+		if (s[0] == '.' &&
+		    (!s[1] || s[1] == '/' ||
+		     (s[1] == '.' && (!s[2] || s[2] == '/'))))
+		    break;
+		while (*s++ != '/' && *s)
+		    continue;
+	    }
+	    return !*s;
+	}
     return 0;
 }
 


^ permalink raw reply	[relevance 7%]

* Bug in llvm compiler
@ 2015-09-24 17:40  1% Sebastian Gniazdowski
  0 siblings, 0 replies; 200+ results
From: Sebastian Gniazdowski @ 2015-09-24 17:40 UTC (permalink / raw)
  To: zsh-workers

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

Hello,
I'm writing optimization of string.c. The point is that functions
there run strlen() and then in general discard the returned
information by running strcpy(). Consider this:

http://www.opensource.apple.com/source/Libc/Libc-997.1.1/string/strcpy.c

Of course there are different implementations that will not run
strlen() second time:

http://www.opensource.apple.com/source/Libc/Libc-262/i386/gen/strcpy.c

but still - utilizing the information allows for optimizations.

I think I've encountered a bug in Apple's llvm. Changing 11 line in
the patch, from "if( l < 8 ) {" to "if( l < 0 ) {" causes the script
to run for 2.5 seconds. Changing it to "if( l < 1 ) {" restores
running time of 2 seconds. Looking at generated assembly shows that
"if( l < 0 ) {" is treated as "if( 0 )" and only the memcpy() part is
emitted. That's fine, but why does that optimized version run slower
having in mind that "if( l < 1 ) {" is impossible condition (every
string has at least 1 byte). The problem doesn't reproduce on FreeBSD
10.1 and Ubuntu 12.10, running times are equal there. I thought I will
show the asm source, maybe someone will find something interesting in
it. In general this seems a bug that should be maybe considered as Zsh
uses memcpy() in various places (also: google
"-Wno-builtin-memcpy-chk-size"). As for string.c, I will provide
memcpy's implementation taken from glibc or other library.

The compiler is:
# gcc --version
Configured with:
--prefix=/Applications/Xcode.app/Contents/Developer/usr
--with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.1.0
Thread model: posix

Best regards,
Sebastian Gniazdowski

[-- Attachment #2: copymemory.patch --]
[-- Type: application/octet-stream, Size: 4391 bytes --]

diff --git a/Src/string.c b/Src/string.c
index 04e7446..f78fcba 100644
--- a/Src/string.c
+++ b/Src/string.c
@@ -28,16 +28,33 @@
 
 #include "zsh.mdh"
 
+#define copymemory_maybestring(dest,src,l,type) do      \
+            {                                           \
+                if( l < 8 ) {                           \
+                    type *d_;                           \
+                    const type *s_;                     \
+                    d_ = dest;                          \
+                    s_ = src;                           \
+                    while( (*d_++ = *s_++) ) {}         \
+                } else {                                \
+                    memcpy(dest, src, l*sizeof(type));  \
+                }                                       \
+            } while(0);
+
 /**/
 mod_export char *
 dupstring(const char *s)
 {
     char *t;
+    size_t lenw0;
 
     if (!s)
 	return NULL;
-    t = (char *) zhalloc(strlen((char *)s) + 1);
-    strcpy(t, s);
+
+    lenw0 = 1 + strlen((char *)s);
+    t = (char *) zhalloc(lenw0 * sizeof(char));
+    copymemory_maybestring(t, s, lenw0, char);
+
     return t;
 }
 
@@ -46,11 +63,15 @@ mod_export char *
 ztrdup(const char *s)
 {
     char *t;
+    size_t lenw0;
 
     if (!s)
 	return NULL;
-    t = (char *)zalloc(strlen((char *)s) + 1);
-    strcpy(t, s);
+
+    lenw0= 1 + strlen((char *)s);
+    t = (char *)zalloc(lenw0 * sizeof(char));
+    copymemory_maybestring(t, s, lenw0, char);
+
     return t;
 }
 
@@ -61,11 +82,15 @@ mod_export wchar_t *
 wcs_ztrdup(const wchar_t *s)
 {
     wchar_t *t;
+    size_t lenw0;
 
     if (!s)
 	return NULL;
-    t = (wchar_t *)zalloc(sizeof(wchar_t) * (wcslen((wchar_t *)s) + 1));
-    wcscpy(t, s);
+
+    lenw0 = 1 + wcslen((wchar_t *)s);
+    t = (wchar_t *)zalloc(lenw0 * sizeof(wchar_t));
+    copymemory_maybestring(t, s, lenw0, wchar_t);
+
     return t;
 }
 /**/
@@ -80,13 +105,14 @@ tricat(char const *s1, char const *s2, char const *s3)
 {
     /* This version always uses permanently-allocated space. */
     char *ptr;
-    size_t l1 = strlen(s1);
-    size_t l2 = strlen(s2);
-
-    ptr = (char *)zalloc(l1 + l2 + strlen(s3) + 1);
-    strcpy(ptr, s1);
-    strcpy(ptr + l1, s2);
-    strcpy(ptr + l1 + l2, s3);
+    size_t l1w0 = 1 + strlen(s1);
+    size_t l2w0 = 1 + strlen(s2);
+    size_t l3w0 = 1 + strlen(s3);
+
+    ptr = (char *)zalloc((l1w0 + l2w0 + l3w0 - 2) * sizeof(char));
+    copymemory_maybestring(ptr, s1, l1w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1, s2, l2w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1 + l2w0 - 1, s3, l3w0, char);
     return ptr;
 }
 
@@ -95,13 +121,14 @@ mod_export char *
 zhtricat(char const *s1, char const *s2, char const *s3)
 {
     char *ptr;
-    size_t l1 = strlen(s1);
-    size_t l2 = strlen(s2);
-
-    ptr = (char *)zhalloc(l1 + l2 + strlen(s3) + 1);
-    strcpy(ptr, s1);
-    strcpy(ptr + l1, s2);
-    strcpy(ptr + l1 + l2, s3);
+    size_t l1w0 = 1 + strlen(s1);
+    size_t l2w0 = 1 + strlen(s2);
+    size_t l3w0 = 1 + strlen(s3);
+
+    ptr = (char *)zhalloc((l1w0 + l2w0 + l3w0 - 2) * sizeof(char));
+    copymemory_maybestring(ptr, s1, l1w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1, s2, l2w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1 + l2w0 - 1, s3, l3w0, char);
     return ptr;
 }
 
@@ -113,11 +140,12 @@ dyncat(const char *s1, const char *s2)
 {
     /* This version always uses space from the current heap. */
     char *ptr;
-    size_t l1 = strlen(s1);
+    size_t l1w0 = 1 + strlen(s1);
+    size_t l2w0 = 1 + strlen(s2);
 
-    ptr = (char *)zhalloc(l1 + strlen(s2) + 1);
-    strcpy(ptr, s1);
-    strcpy(ptr + l1, s2);
+    ptr = (char *)zhalloc(l1w0 + l2w0 - 1);
+    copymemory_maybestring(ptr, s1, l1w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1, s2, l2w0, char);
     return ptr;
 }
 
@@ -127,11 +155,12 @@ bicat(const char *s1, const char *s2)
 {
     /* This version always uses permanently-allocated space. */
     char *ptr;
-    size_t l1 = strlen(s1);
+    size_t l1w0 = 1 + strlen(s1);
+    size_t l2w0 = 1 + strlen(s2);
 
-    ptr = (char *)zalloc(l1 + strlen(s2) + 1);
-    strcpy(ptr, s1);
-    strcpy(ptr + l1, s2);
+    ptr = (char *)zalloc(l1w0 + l2w0 - 1);
+    copymemory_maybestring(ptr, s1, l1w0, char);
+    copymemory_maybestring(ptr + l1w0 - 1, s2, l2w0, char);
     return ptr;
 }
 

[-- Attachment #3: out_if_smaller_t0.asm --]
[-- Type: application/octet-stream, Size: 9358 bytes --]

	.section	__TEXT,__text,regular,pure_instructions
	.globl	_dupstring
	.align	4, 0x90
_dupstring:                             ## @dupstring
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp3:
	.cfi_def_cfa_offset 16
Ltmp4:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp5:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp6:
	.cfi_offset %rbx, -40
Ltmp7:
	.cfi_offset %r14, -32
Ltmp8:
	.cfi_offset %r15, -24
	movq	%rdi, %r14
	testq	%r14, %r14
	je	LBB0_1
## BB#2:
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %rbx
	incq	%rbx
	movq	%rbx, %rdi
	callq	_zhalloc
	movq	%rax, %r15
	movq	%r15, %rdi
	movq	%r14, %rsi
	movq	%rbx, %rdx
	callq	_memcpy
	jmp	LBB0_3
LBB0_1:
	xorl	%r15d, %r15d
LBB0_3:
	movq	%r15, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_ztrdup
	.align	4, 0x90
_ztrdup:                                ## @ztrdup
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp12:
	.cfi_def_cfa_offset 16
Ltmp13:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp14:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp15:
	.cfi_offset %rbx, -40
Ltmp16:
	.cfi_offset %r14, -32
Ltmp17:
	.cfi_offset %r15, -24
	movq	%rdi, %r14
	testq	%r14, %r14
	je	LBB1_1
## BB#2:
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %rbx
	incq	%rbx
	movq	%rbx, %rdi
	callq	_zalloc
	movq	%rax, %r15
	movq	%r15, %rdi
	movq	%r14, %rsi
	movq	%rbx, %rdx
	callq	_memcpy
	jmp	LBB1_3
LBB1_1:
	xorl	%r15d, %r15d
LBB1_3:
	movq	%r15, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_wcs_ztrdup
	.align	4, 0x90
_wcs_ztrdup:                            ## @wcs_ztrdup
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp21:
	.cfi_def_cfa_offset 16
Ltmp22:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp23:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp24:
	.cfi_offset %rbx, -40
Ltmp25:
	.cfi_offset %r14, -32
Ltmp26:
	.cfi_offset %r15, -24
	movq	%rdi, %r14
	testq	%r14, %r14
	je	LBB2_1
## BB#2:
	movq	%r14, %rdi
	callq	_wcslen
	leaq	4(,%rax,4), %r15
	movq	%r15, %rdi
	callq	_zalloc
	movq	%rax, %rbx
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	jmp	LBB2_3
LBB2_1:
	xorl	%ebx, %ebx
LBB2_3:
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_tricat
	.align	4, 0x90
_tricat:                                ## @tricat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp30:
	.cfi_def_cfa_offset 16
Ltmp31:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp32:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	subq	$24, %rsp
Ltmp33:
	.cfi_offset %rbx, -56
Ltmp34:
	.cfi_offset %r12, -48
Ltmp35:
	.cfi_offset %r13, -40
Ltmp36:
	.cfi_offset %r14, -32
Ltmp37:
	.cfi_offset %r15, -24
	movq	%rdx, %r15
	movq	%r15, -48(%rbp)         ## 8-byte Spill
	movq	%rsi, %r14
	movq	%r14, -56(%rbp)         ## 8-byte Spill
	movq	%rdi, %r13
	callq	_strlen
	movq	%rax, %rbx
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r14
	leaq	(%rbx,%r14), %r12
	movq	%r15, %rdi
	callq	_strlen
	movq	%rax, -64(%rbp)         ## 8-byte Spill
	leaq	1(%rax,%r12), %rdi
	callq	_zalloc
	movq	%rax, %r15
	leaq	1(%rbx), %rdx
	movq	%r15, %rdi
	movq	%r13, %rsi
	callq	_memcpy
	addq	%r15, %rbx
	leaq	1(%r14), %rdx
	movq	%rbx, %rdi
	movq	-56(%rbp), %rsi         ## 8-byte Reload
	callq	_memcpy
	addq	%r15, %r12
	movq	-64(%rbp), %rax         ## 8-byte Reload
	leaq	1(%rax), %rdx
	movq	%r12, %rdi
	movq	-48(%rbp), %rsi         ## 8-byte Reload
	callq	_memcpy
	movq	%r15, %rax
	addq	$24, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_zhtricat
	.align	4, 0x90
_zhtricat:                              ## @zhtricat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp41:
	.cfi_def_cfa_offset 16
Ltmp42:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp43:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	subq	$24, %rsp
Ltmp44:
	.cfi_offset %rbx, -56
Ltmp45:
	.cfi_offset %r12, -48
Ltmp46:
	.cfi_offset %r13, -40
Ltmp47:
	.cfi_offset %r14, -32
Ltmp48:
	.cfi_offset %r15, -24
	movq	%rdx, %r15
	movq	%r15, -48(%rbp)         ## 8-byte Spill
	movq	%rsi, %r14
	movq	%r14, -56(%rbp)         ## 8-byte Spill
	movq	%rdi, %r13
	callq	_strlen
	movq	%rax, %rbx
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r14
	leaq	(%rbx,%r14), %r12
	movq	%r15, %rdi
	callq	_strlen
	movq	%rax, -64(%rbp)         ## 8-byte Spill
	leaq	1(%rax,%r12), %rdi
	callq	_zhalloc
	movq	%rax, %r15
	leaq	1(%rbx), %rdx
	movq	%r15, %rdi
	movq	%r13, %rsi
	callq	_memcpy
	addq	%r15, %rbx
	leaq	1(%r14), %rdx
	movq	%rbx, %rdi
	movq	-56(%rbp), %rsi         ## 8-byte Reload
	callq	_memcpy
	addq	%r15, %r12
	movq	-64(%rbp), %rax         ## 8-byte Reload
	leaq	1(%rax), %rdx
	movq	%r12, %rdi
	movq	-48(%rbp), %rsi         ## 8-byte Reload
	callq	_memcpy
	movq	%r15, %rax
	addq	$24, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_dyncat
	.align	4, 0x90
_dyncat:                                ## @dyncat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp52:
	.cfi_def_cfa_offset 16
Ltmp53:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp54:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	pushq	%rax
Ltmp55:
	.cfi_offset %rbx, -56
Ltmp56:
	.cfi_offset %r12, -48
Ltmp57:
	.cfi_offset %r13, -40
Ltmp58:
	.cfi_offset %r14, -32
Ltmp59:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %r15
	callq	_strlen
	movq	%rax, %rbx
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r12
	leaq	1(%rbx,%r12), %rdi
	callq	_zhalloc
	movq	%rax, %r13
	leaq	1(%rbx), %rdx
	movq	%r13, %rdi
	movq	%r15, %rsi
	callq	_memcpy
	addq	%r13, %rbx
	leaq	1(%r12), %rdx
	movq	%rbx, %rdi
	movq	%r14, %rsi
	callq	_memcpy
	movq	%r13, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_bicat
	.align	4, 0x90
_bicat:                                 ## @bicat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp63:
	.cfi_def_cfa_offset 16
Ltmp64:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp65:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	pushq	%rax
Ltmp66:
	.cfi_offset %rbx, -56
Ltmp67:
	.cfi_offset %r12, -48
Ltmp68:
	.cfi_offset %r13, -40
Ltmp69:
	.cfi_offset %r14, -32
Ltmp70:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %r15
	callq	_strlen
	movq	%rax, %rbx
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r12
	leaq	1(%rbx,%r12), %rdi
	callq	_zalloc
	movq	%rax, %r13
	leaq	1(%rbx), %rdx
	movq	%r13, %rdi
	movq	%r15, %rsi
	callq	_memcpy
	addq	%r13, %rbx
	leaq	1(%r12), %rdx
	movq	%rbx, %rdi
	movq	%r14, %rsi
	callq	_memcpy
	movq	%r13, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_dupstrpfx
	.align	4, 0x90
_dupstrpfx:                             ## @dupstrpfx
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp74:
	.cfi_def_cfa_offset 16
Ltmp75:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp76:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp77:
	.cfi_offset %rbx, -40
Ltmp78:
	.cfi_offset %r14, -32
Ltmp79:
	.cfi_offset %r15, -24
	movl	%esi, %r15d
	movq	%rdi, %r14
	leal	1(%r15), %eax
	movslq	%eax, %rdi
	callq	_zhalloc
	movq	%rax, %rbx
	movslq	%r15d, %r15
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	movb	$0, (%rbx,%r15)
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_ztrduppfx
	.align	4, 0x90
_ztrduppfx:                             ## @ztrduppfx
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp83:
	.cfi_def_cfa_offset 16
Ltmp84:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp85:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp86:
	.cfi_offset %rbx, -40
Ltmp87:
	.cfi_offset %r14, -32
Ltmp88:
	.cfi_offset %r15, -24
	movl	%esi, %r15d
	movq	%rdi, %r14
	leal	1(%r15), %eax
	movslq	%eax, %rdi
	callq	_zalloc
	movq	%rax, %rbx
	movslq	%r15d, %r15
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	movb	$0, (%rbx,%r15)
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_appstr
	.align	4, 0x90
_appstr:                                ## @appstr
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp92:
	.cfi_def_cfa_offset 16
Ltmp93:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp94:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp95:
	.cfi_offset %rbx, -40
Ltmp96:
	.cfi_offset %r14, -32
Ltmp97:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %rbx
	callq	_strlen
	movq	%rax, %r15
	movq	%r14, %rdi
	callq	_strlen
	leaq	1(%r15,%rax), %rsi
	movq	%rbx, %rdi
	callq	_realloc
	movq	%rax, %rdi
	movq	%r14, %rsi
	movq	$-1, %rdx
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	jmp	___strcat_chk           ## TAILCALL
	.cfi_endproc

	.globl	_strend
	.align	4, 0x90
_strend:                                ## @strend
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp101:
	.cfi_def_cfa_offset 16
Ltmp102:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp103:
	.cfi_def_cfa_register %rbp
	pushq	%rbx
	pushq	%rax
Ltmp104:
	.cfi_offset %rbx, -24
	movq	%rdi, %rbx
	cmpb	$0, (%rbx)
	je	LBB10_2
## BB#1:
	movq	%rbx, %rdi
	callq	_strlen
	leaq	-1(%rax,%rbx), %rbx
LBB10_2:
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%rbp
	ret
	.cfi_endproc


.subsections_via_symbols

[-- Attachment #4: out_if_smaller_t1.asm --]
[-- Type: application/octet-stream, Size: 14100 bytes --]

	.section	__TEXT,__text,regular,pure_instructions
	.globl	_dupstring
	.align	4, 0x90
_dupstring:                             ## @dupstring
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp3:
	.cfi_def_cfa_offset 16
Ltmp4:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp5:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp6:
	.cfi_offset %rbx, -40
Ltmp7:
	.cfi_offset %r14, -32
Ltmp8:
	.cfi_offset %r15, -24
	movq	%rdi, %r14
	xorl	%ebx, %ebx
	testq	%r14, %r14
	je	LBB0_5
## BB#1:
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r15
	leaq	1(%r15), %rdi
	callq	_zhalloc
	movq	%rax, %rbx
	incq	%r15
	je	LBB0_2
## BB#4:
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	jmp	LBB0_5
LBB0_2:
	xorl	%eax, %eax
	.align	4, 0x90
LBB0_3:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14,%rax), %cl
	movb	%cl, (%rbx,%rax)
	incq	%rax
	testb	%cl, %cl
	jne	LBB0_3
LBB0_5:                                 ## %.loopexit
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_ztrdup
	.align	4, 0x90
_ztrdup:                                ## @ztrdup
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp12:
	.cfi_def_cfa_offset 16
Ltmp13:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp14:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp15:
	.cfi_offset %rbx, -40
Ltmp16:
	.cfi_offset %r14, -32
Ltmp17:
	.cfi_offset %r15, -24
	movq	%rdi, %r14
	xorl	%ebx, %ebx
	testq	%r14, %r14
	je	LBB1_5
## BB#1:
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r15
	leaq	1(%r15), %rdi
	callq	_zalloc
	movq	%rax, %rbx
	incq	%r15
	je	LBB1_2
## BB#4:
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	jmp	LBB1_5
LBB1_2:
	xorl	%eax, %eax
	.align	4, 0x90
LBB1_3:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14,%rax), %cl
	movb	%cl, (%rbx,%rax)
	incq	%rax
	testb	%cl, %cl
	jne	LBB1_3
LBB1_5:                                 ## %.loopexit
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_wcs_ztrdup
	.align	4, 0x90
_wcs_ztrdup:                            ## @wcs_ztrdup
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp21:
	.cfi_def_cfa_offset 16
Ltmp22:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp23:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r12
	pushq	%rbx
Ltmp24:
	.cfi_offset %rbx, -48
Ltmp25:
	.cfi_offset %r12, -40
Ltmp26:
	.cfi_offset %r14, -32
Ltmp27:
	.cfi_offset %r15, -24
	movq	%rdi, %rbx
	xorl	%r14d, %r14d
	testq	%rbx, %rbx
	je	LBB2_5
## BB#1:
	movq	%rbx, %rdi
	callq	_wcslen
	movq	%rax, %r12
	leaq	4(,%r12,4), %r15
	incq	%r12
	movq	%r15, %rdi
	callq	_zalloc
	movq	%rax, %r14
	testq	%r12, %r12
	je	LBB2_2
## BB#4:
	movq	%r14, %rdi
	movq	%rbx, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	jmp	LBB2_5
LBB2_2:
	movq	%r14, %rax
	.align	4, 0x90
LBB2_3:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movl	(%rbx), %ecx
	movl	%ecx, (%rax)
	addq	$4, %rax
	addq	$4, %rbx
	testl	%ecx, %ecx
	jne	LBB2_3
LBB2_5:                                 ## %.loopexit
	movq	%r14, %rax
	popq	%rbx
	popq	%r12
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_tricat
	.align	4, 0x90
_tricat:                                ## @tricat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp31:
	.cfi_def_cfa_offset 16
Ltmp32:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp33:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	subq	$24, %rsp
Ltmp34:
	.cfi_offset %rbx, -56
Ltmp35:
	.cfi_offset %r12, -48
Ltmp36:
	.cfi_offset %r13, -40
Ltmp37:
	.cfi_offset %r14, -32
Ltmp38:
	.cfi_offset %r15, -24
	movq	%rdx, %r14
	movq	%rsi, %rbx
	movq	%rdi, %r13
	callq	_strlen
	movq	%rax, %r15
	movq	%rbx, %rdi
	callq	_strlen
	movq	%rax, -56(%rbp)         ## 8-byte Spill
	leaq	(%r15,%rax), %r12
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, -48(%rbp)         ## 8-byte Spill
	leaq	1(%rax,%r12), %rdi
	callq	_zalloc
	incq	-56(%rbp)               ## 8-byte Folded Spill
	incq	-48(%rbp)               ## 8-byte Folded Spill
	movq	%r15, %rdx
	incq	%rdx
	je	LBB3_1
## BB#3:
	movq	%rax, %rdi
	movq	%rax, -64(%rbp)         ## 8-byte Spill
	movq	%r13, %rsi
	callq	_memcpy
	movq	-64(%rbp), %rax         ## 8-byte Reload
	jmp	LBB3_4
LBB3_1:
	movq	%rax, %rdx
	.align	4, 0x90
LBB3_2:                                 ## %.preheader8
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r13), %cl
	movb	%cl, (%rdx)
	incq	%rdx
	incq	%r13
	testb	%cl, %cl
	jne	LBB3_2
LBB3_4:                                 ## %.loopexit9
	addq	%rax, %r15
	movq	-56(%rbp), %rdx         ## 8-byte Reload
	testq	%rdx, %rdx
	je	LBB3_5
## BB#6:
	movq	%r15, %rdi
	movq	%rax, %r15
	movq	%rbx, %rsi
	callq	_memcpy
	movq	%r15, %rax
	jmp	LBB3_7
	.align	4, 0x90
LBB3_5:                                 ## %.preheader6
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%rbx), %cl
	movb	%cl, (%r15)
	incq	%r15
	incq	%rbx
	testb	%cl, %cl
	jne	LBB3_5
LBB3_7:                                 ## %.loopexit7
	addq	%rax, %r12
	movq	-48(%rbp), %rdx         ## 8-byte Reload
	testq	%rdx, %rdx
	je	LBB3_8
## BB#9:
	movq	%r12, %rdi
	movq	%rax, %rbx
	movq	%r14, %rsi
	callq	_memcpy
	movq	%rbx, %rax
	jmp	LBB3_10
	.align	4, 0x90
LBB3_8:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14), %cl
	movb	%cl, (%r12)
	incq	%r12
	incq	%r14
	testb	%cl, %cl
	jne	LBB3_8
LBB3_10:                                ## %.loopexit
	addq	$24, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_zhtricat
	.align	4, 0x90
_zhtricat:                              ## @zhtricat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp42:
	.cfi_def_cfa_offset 16
Ltmp43:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp44:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	subq	$24, %rsp
Ltmp45:
	.cfi_offset %rbx, -56
Ltmp46:
	.cfi_offset %r12, -48
Ltmp47:
	.cfi_offset %r13, -40
Ltmp48:
	.cfi_offset %r14, -32
Ltmp49:
	.cfi_offset %r15, -24
	movq	%rdx, %r14
	movq	%rsi, %rbx
	movq	%rdi, %r13
	callq	_strlen
	movq	%rax, %r15
	movq	%rbx, %rdi
	callq	_strlen
	movq	%rax, -56(%rbp)         ## 8-byte Spill
	leaq	(%r15,%rax), %r12
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, -48(%rbp)         ## 8-byte Spill
	leaq	1(%rax,%r12), %rdi
	callq	_zhalloc
	incq	-56(%rbp)               ## 8-byte Folded Spill
	incq	-48(%rbp)               ## 8-byte Folded Spill
	movq	%r15, %rdx
	incq	%rdx
	je	LBB4_1
## BB#3:
	movq	%rax, %rdi
	movq	%rax, -64(%rbp)         ## 8-byte Spill
	movq	%r13, %rsi
	callq	_memcpy
	movq	-64(%rbp), %rax         ## 8-byte Reload
	jmp	LBB4_4
LBB4_1:
	movq	%rax, %rdx
	.align	4, 0x90
LBB4_2:                                 ## %.preheader8
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r13), %cl
	movb	%cl, (%rdx)
	incq	%rdx
	incq	%r13
	testb	%cl, %cl
	jne	LBB4_2
LBB4_4:                                 ## %.loopexit9
	addq	%rax, %r15
	movq	-56(%rbp), %rdx         ## 8-byte Reload
	testq	%rdx, %rdx
	je	LBB4_5
## BB#6:
	movq	%r15, %rdi
	movq	%rax, %r15
	movq	%rbx, %rsi
	callq	_memcpy
	movq	%r15, %rax
	jmp	LBB4_7
	.align	4, 0x90
LBB4_5:                                 ## %.preheader6
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%rbx), %cl
	movb	%cl, (%r15)
	incq	%r15
	incq	%rbx
	testb	%cl, %cl
	jne	LBB4_5
LBB4_7:                                 ## %.loopexit7
	addq	%rax, %r12
	movq	-48(%rbp), %rdx         ## 8-byte Reload
	testq	%rdx, %rdx
	je	LBB4_8
## BB#9:
	movq	%r12, %rdi
	movq	%rax, %rbx
	movq	%r14, %rsi
	callq	_memcpy
	movq	%rbx, %rax
	jmp	LBB4_10
	.align	4, 0x90
LBB4_8:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14), %cl
	movb	%cl, (%r12)
	incq	%r12
	incq	%r14
	testb	%cl, %cl
	jne	LBB4_8
LBB4_10:                                ## %.loopexit
	addq	$24, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_dyncat
	.align	4, 0x90
_dyncat:                                ## @dyncat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp53:
	.cfi_def_cfa_offset 16
Ltmp54:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp55:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	pushq	%rax
Ltmp56:
	.cfi_offset %rbx, -56
Ltmp57:
	.cfi_offset %r12, -48
Ltmp58:
	.cfi_offset %r13, -40
Ltmp59:
	.cfi_offset %r14, -32
Ltmp60:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %rbx
	callq	_strlen
	movq	%rax, %r13
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r12
	leaq	1(%r13,%r12), %rdi
	callq	_zhalloc
	movq	%rax, %r15
	incq	%r12
	movq	%r13, %rdx
	incq	%rdx
	je	LBB5_1
## BB#3:
	movq	%r15, %rdi
	movq	%rbx, %rsi
	callq	_memcpy
	jmp	LBB5_4
LBB5_1:
	movq	%r15, %rax
	.align	4, 0x90
LBB5_2:                                 ## %.preheader3
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%rbx), %cl
	movb	%cl, (%rax)
	incq	%rax
	incq	%rbx
	testb	%cl, %cl
	jne	LBB5_2
LBB5_4:                                 ## %.loopexit4
	addq	%r15, %r13
	testq	%r12, %r12
	je	LBB5_5
## BB#6:
	movq	%r13, %rdi
	movq	%r14, %rsi
	movq	%r12, %rdx
	callq	_memcpy
	jmp	LBB5_7
	.align	4, 0x90
LBB5_5:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14), %al
	movb	%al, (%r13)
	incq	%r13
	incq	%r14
	testb	%al, %al
	jne	LBB5_5
LBB5_7:                                 ## %.loopexit
	movq	%r15, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_bicat
	.align	4, 0x90
_bicat:                                 ## @bicat
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp64:
	.cfi_def_cfa_offset 16
Ltmp65:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp66:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%r13
	pushq	%r12
	pushq	%rbx
	pushq	%rax
Ltmp67:
	.cfi_offset %rbx, -56
Ltmp68:
	.cfi_offset %r12, -48
Ltmp69:
	.cfi_offset %r13, -40
Ltmp70:
	.cfi_offset %r14, -32
Ltmp71:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %rbx
	callq	_strlen
	movq	%rax, %r13
	movq	%r14, %rdi
	callq	_strlen
	movq	%rax, %r12
	leaq	1(%r13,%r12), %rdi
	callq	_zalloc
	movq	%rax, %r15
	incq	%r12
	movq	%r13, %rdx
	incq	%rdx
	je	LBB6_1
## BB#3:
	movq	%r15, %rdi
	movq	%rbx, %rsi
	callq	_memcpy
	jmp	LBB6_4
LBB6_1:
	movq	%r15, %rax
	.align	4, 0x90
LBB6_2:                                 ## %.preheader3
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%rbx), %cl
	movb	%cl, (%rax)
	incq	%rax
	incq	%rbx
	testb	%cl, %cl
	jne	LBB6_2
LBB6_4:                                 ## %.loopexit4
	addq	%r15, %r13
	testq	%r12, %r12
	je	LBB6_5
## BB#6:
	movq	%r13, %rdi
	movq	%r14, %rsi
	movq	%r12, %rdx
	callq	_memcpy
	jmp	LBB6_7
	.align	4, 0x90
LBB6_5:                                 ## %.preheader
                                        ## =>This Inner Loop Header: Depth=1
	movb	(%r14), %al
	movb	%al, (%r13)
	incq	%r13
	incq	%r14
	testb	%al, %al
	jne	LBB6_5
LBB6_7:                                 ## %.loopexit
	movq	%r15, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r12
	popq	%r13
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_dupstrpfx
	.align	4, 0x90
_dupstrpfx:                             ## @dupstrpfx
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp75:
	.cfi_def_cfa_offset 16
Ltmp76:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp77:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp78:
	.cfi_offset %rbx, -40
Ltmp79:
	.cfi_offset %r14, -32
Ltmp80:
	.cfi_offset %r15, -24
	movl	%esi, %r15d
	movq	%rdi, %r14
	leal	1(%r15), %eax
	movslq	%eax, %rdi
	callq	_zhalloc
	movq	%rax, %rbx
	movslq	%r15d, %r15
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	movb	$0, (%rbx,%r15)
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_ztrduppfx
	.align	4, 0x90
_ztrduppfx:                             ## @ztrduppfx
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp84:
	.cfi_def_cfa_offset 16
Ltmp85:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp86:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp87:
	.cfi_offset %rbx, -40
Ltmp88:
	.cfi_offset %r14, -32
Ltmp89:
	.cfi_offset %r15, -24
	movl	%esi, %r15d
	movq	%rdi, %r14
	leal	1(%r15), %eax
	movslq	%eax, %rdi
	callq	_zalloc
	movq	%rax, %rbx
	movslq	%r15d, %r15
	movq	%rbx, %rdi
	movq	%r14, %rsi
	movq	%r15, %rdx
	callq	_memcpy
	movb	$0, (%rbx,%r15)
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	ret
	.cfi_endproc

	.globl	_appstr
	.align	4, 0x90
_appstr:                                ## @appstr
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp93:
	.cfi_def_cfa_offset 16
Ltmp94:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp95:
	.cfi_def_cfa_register %rbp
	pushq	%r15
	pushq	%r14
	pushq	%rbx
	pushq	%rax
Ltmp96:
	.cfi_offset %rbx, -40
Ltmp97:
	.cfi_offset %r14, -32
Ltmp98:
	.cfi_offset %r15, -24
	movq	%rsi, %r14
	movq	%rdi, %rbx
	callq	_strlen
	movq	%rax, %r15
	movq	%r14, %rdi
	callq	_strlen
	leaq	1(%r15,%rax), %rsi
	movq	%rbx, %rdi
	callq	_realloc
	movq	%rax, %rdi
	movq	%r14, %rsi
	movq	$-1, %rdx
	addq	$8, %rsp
	popq	%rbx
	popq	%r14
	popq	%r15
	popq	%rbp
	jmp	___strcat_chk           ## TAILCALL
	.cfi_endproc

	.globl	_strend
	.align	4, 0x90
_strend:                                ## @strend
	.cfi_startproc
## BB#0:
	pushq	%rbp
Ltmp102:
	.cfi_def_cfa_offset 16
Ltmp103:
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
Ltmp104:
	.cfi_def_cfa_register %rbp
	pushq	%rbx
	pushq	%rax
Ltmp105:
	.cfi_offset %rbx, -24
	movq	%rdi, %rbx
	cmpb	$0, (%rbx)
	je	LBB10_2
## BB#1:
	movq	%rbx, %rdi
	callq	_strlen
	leaq	-1(%rax,%rbx), %rbx
LBB10_2:
	movq	%rbx, %rax
	addq	$8, %rsp
	popq	%rbx
	popq	%rbp
	ret
	.cfi_endproc


.subsections_via_symbols

[-- Attachment #5: opttest3.zsh --]
[-- Type: application/octet-stream, Size: 247 bytes --]

#!/usr/local/bin/zsh-0cpmem-5.1.1-dev-0
#!/usr/local/bin/zsh-1cpmem-5.1.1-dev-0

zmodload zsh/zprof

strtest() {
    a=""

    i=5000
    while (( i -- )); do
        b=$a
        a+="$i"
    done
}

strtest
strtest
strtest
strtest
strtest

zprof

^ permalink raw reply	[relevance 1%]

* Re: bug with $PWD in /
  2015-09-19 20:47  7%     ` Bart Schaefer
@ 2015-09-28 18:13  3%       ` Daniel Shahaf
  0 siblings, 0 replies; 200+ results
From: Daniel Shahaf @ 2015-09-28 18:13 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list, Stephane Chazelas

Bart Schaefer wrote on Sat, Sep 19, 2015 at 13:47:40 -0700:
> On Sep 19,  8:28pm, Stephane Chazelas wrote:
> } Subject: Re: bug with $PWD in /
> }
> } So, the should recompute $PWD if the one it gets from the
> } environment is a relative path (it's not only about . or ..,
> } think of symlinks).
> 
> It'd have to be a symlink from the current directory to itself, tho.
> Other symbolic links are explicitly permitted by the text you quoted.

Looking at the sole caller of ispwd(), setupvals(), it sometimes
initializes $PWD from getenv("HOME").  Is something like this needed,
then?

Or perhaps the condition should be "if not POSIX" rather than "if zsh".

diff --git a/Src/init.c b/Src/init.c
index 22db4b3..24a50c7 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1019,7 +1019,7 @@ setupvals(void)
        ptr = home;
     else
        ptr = zgetenv("HOME");
-    if (ptr && ispwd(ptr))
+    if (EMULATION(EMULATE_ZSH) && ptr && ispwd(ptr))
        pwd = ztrdup(ptr);
     else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) &&
             (ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr)))


^ permalink raw reply	[relevance 3%]

* [PATCH] minor doco spelling fixes
@ 2015-09-30 11:56 14% Andrew Janke
    0 siblings, 1 reply; 200+ results
From: Andrew Janke @ 2015-09-30 11:56 UTC (permalink / raw)
  To: Zsh hackers list

Hi, Zsh folks,

Found a couple typos etc in the doco; here's a suggested fix.

- Spelling error in README
- Inconsistent "OS's" vs "OSes" in MACHINES
- Inconsistent "behavior" vs "behaviour" spelling
- Updated URL for Yodl project; it moved off SourceForge

Also, the LICENCE file still says "copyright (c) 1992-2009".

Cheers,
Andrew


diff --git a/MACHINES b/MACHINES
index ddbf69a..73f80c7 100644
--- a/MACHINES
+++ b/MACHINES
@@ -162,8 +162,8 @@ Other machines

  Zsh has previously been compiled on the following machines, but the
  developers do not have direct access to them and the reports may be out
-of date.  Some of these OS's are now very long in the tooth.  We would
-be glad to receive any reports of success or failure on these OS's ---
+of date.  Some of these OSes are now very long in the tooth.  We would
+be glad to receive any reports of success or failure on these OSes ---
  and, of course, any others not mentioned in this file.

  Apple/NeXT OpenStep 4.2 for i386.
diff --git a/NEWS b/NEWS
index 7b2994b..bc14a8b 100644
--- a/NEWS
+++ b/NEWS
@@ -47,7 +47,7 @@ and an array "array" containing the words "several"
  - Improved (though still not perfect) POSIX compatibility for getopts
    builtin when POSIX_BUILTINS is set.

-- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behavior.
+- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behaviour.

  - Completion of date values now displays in a calendar format when
    the complist module is available.  Controllable by zstyle.
@@ -929,7 +929,7 @@ Parameter and expansion changes:
    - expansion of ~ and other globbing flags via ${~param} do not depend
      upon EXTENDED_GLOB (bug fix).
    - nested parameter substitutions require braces (this was always the
-    documented behavior, but previous parsers didn't enforce it).
+    documented behaviour, but previous parsers didn't enforce it).
    - quote only nested expansion, e.g. ${(f)"$(<file)"} reads complete
      `file', then splits lines into array.

@@ -954,7 +954,7 @@ Other changes:
  Debugging enhancements:
    - LINENO is now very much more useful in scripts and functions and is
      reported correctly in most error messages.
-  - ERREXIT behavior is now consistent with newer Bourne-like shells,
+  - ERREXIT behaviour is now consistent with newer Bourne-like shells,
      e.g. with respect to `if' tests that fail.

  Configuration changes:
diff --git a/README b/README
index 4b840b5..9571521 100644
--- a/README
+++ b/README
@@ -48,7 +48,7 @@ As noted in NEWS, the builtins declare, export, float, 
integer, local,
  readonly and typeset now have corresponding reserved words that provide
  true assignment semantics instead of an approximation by means of normal
  command line arguments.  It is hoped that this additional consistency
-provides a more natural interface.  However, compatbility with older
+provides a more natural interface.  However, compatibility with older
  versions of zsh can be obtained by turning off the reserved word
  interface, exposing the builtin interface:

@@ -392,7 +392,7 @@ Doc/Zsh/*.yo    The master source for the zsh 
documentation is written in
          It is not required by zsh but it is a nice program so you
          might want to get it anyway, especially if you are a zsh
          developer.  It can be downloaded from
-        ftp://yodl.sourceforge.net/
+        https://fbb-git.github.io/yodl/

  Doc/zsh*.1    Man pages in nroff format.  These will be installed
          by "make install.man" or "make install".  By default,


^ permalink raw reply	[relevance 14%]

* Re: [PATCH] minor doco spelling fixes
  @ 2015-10-01  1:14 13%     ` Andrew Janke
  0 siblings, 0 replies; 200+ results
From: Andrew Janke @ 2015-10-01  1:14 UTC (permalink / raw)
  To: Peter Stephenson, Zsh hackers list

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


On 9/30/15 9:43 AM, Peter Stephenson wrote:
> On Wed, 30 Sep 2015 14:25:24 +0100
> Peter Stephenson <p.stephenson@samsung.com> wrote:
>> On Wed, 30 Sep 2015 07:56:14 -0400
>> Andrew Janke <floss@apjanke.net> wrote:
>>> Found a couple typos etc in the doco; here's a suggested fix.
>> This seems to have got wrapped badly.  Send it as an attachment if
>> necessary.
> Actually, not sure it's wrapping, looking at it, but something funny
> about whitespace is preventing it applying...
>
> pws
Here it is as an attachment. This file applies cleanly to the head of 
the zsh repo for me.

[~/local/opp/zsh/zsh-02 on ⇄ master ±]
$ git remote -v
origin    git@github.com:zsh-users/zsh.git (fetch)
origin    git@github.com:zsh-users/zsh.git (push)
[~/local/opp/zsh/zsh-02 on ⇄ master]
$ patch -p1 <../zsh-typos-20150929.patch
patching file MACHINES
patching file NEWS
patching file README
[~/local/opp/zsh/zsh-02 on ⇄ master ±]
$ echo $?
0

Formatting must have been messed up by my mail client (Thunderbird on OS 
X). Sorry for the inconvenience.

Cheers,
Andrew

[-- Attachment #2: zsh-typos-20150929.patch --]
[-- Type: text/plain, Size: 3154 bytes --]

diff --git a/MACHINES b/MACHINES
index ddbf69a..73f80c7 100644
--- a/MACHINES
+++ b/MACHINES
@@ -162,8 +162,8 @@ Other machines
 
 Zsh has previously been compiled on the following machines, but the
 developers do not have direct access to them and the reports may be out
-of date.  Some of these OS's are now very long in the tooth.  We would
-be glad to receive any reports of success or failure on these OS's ---
+of date.  Some of these OSes are now very long in the tooth.  We would
+be glad to receive any reports of success or failure on these OSes ---
 and, of course, any others not mentioned in this file.
 
 Apple/NeXT OpenStep 4.2 for i386.
diff --git a/NEWS b/NEWS
index 7b2994b..bc14a8b 100644
--- a/NEWS
+++ b/NEWS
@@ -47,7 +47,7 @@ and an array "array" containing the words "several"
 - Improved (though still not perfect) POSIX compatibility for getopts
   builtin when POSIX_BUILTINS is set.
 
-- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behavior.
+- New setopt APPEND_CREATE for POSIX-compatible NO_CLOBBER behaviour.
 
 - Completion of date values now displays in a calendar format when
   the complist module is available.  Controllable by zstyle.
@@ -929,7 +929,7 @@ Parameter and expansion changes:
   - expansion of ~ and other globbing flags via ${~param} do not depend
     upon EXTENDED_GLOB (bug fix).
   - nested parameter substitutions require braces (this was always the
-    documented behavior, but previous parsers didn't enforce it).
+    documented behaviour, but previous parsers didn't enforce it).
   - quote only nested expansion, e.g. ${(f)"$(<file)"} reads complete
     `file', then splits lines into array.
 
@@ -954,7 +954,7 @@ Other changes:
 Debugging enhancements:
   - LINENO is now very much more useful in scripts and functions and is
     reported correctly in most error messages.
-  - ERREXIT behavior is now consistent with newer Bourne-like shells,
+  - ERREXIT behaviour is now consistent with newer Bourne-like shells,
     e.g. with respect to `if' tests that fail.
 
 Configuration changes:
diff --git a/README b/README
index 4b840b5..9571521 100644
--- a/README
+++ b/README
@@ -48,7 +48,7 @@ As noted in NEWS, the builtins declare, export, float, integer, local,
 readonly and typeset now have corresponding reserved words that provide
 true assignment semantics instead of an approximation by means of normal
 command line arguments.  It is hoped that this additional consistency
-provides a more natural interface.  However, compatbility with older
+provides a more natural interface.  However, compatibility with older
 versions of zsh can be obtained by turning off the reserved word
 interface, exposing the builtin interface:
 
@@ -392,7 +392,7 @@ Doc/Zsh/*.yo	The master source for the zsh documentation is written in
 		It is not required by zsh but it is a nice program so you
 		might want to get it anyway, especially if you are a zsh
 		developer.  It can be downloaded from
-		ftp://yodl.sourceforge.net/
+		https://fbb-git.github.io/yodl/
 
 Doc/zsh*.1	Man pages in nroff format.  These will be installed
 		by "make install.man" or "make install".  By default,

^ permalink raw reply	[relevance 13%]

* Re: syntax check of 'echo $HOME' crashes in ksh emulation mode
  @ 2015-10-06 15:34  3%         ` Bart Schaefer
    0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-10-06 15:34 UTC (permalink / raw)
  To: zsh-workers

On Oct 6, 10:15am, Peter Stephenson wrote:
}
} /**/
} mod_export void
} assignstrvalue(Value v, char *val, int flags)
} {
}     if (unset(EXECOPT))
} 	return;
} 
} (i) Doesn't that leak val?

Probably, but in no_exec state the shell can't possibly run for very long
so it doesn't matter?  However, every other case in assignstrvalue() has
zsfree(val) so this one probably should too.  Except:

} (ii) It's not clear how safe the above is, as this case shows.  However,
} it's definitely not safe to skip the tests in assignstrvalue() either

Do you mean that even for no_exec we should not be bailing out this
early in assignstrvalue()?  That is, we ought to be doing the tests of
read-only, wrong type, invalid subscript, etc., and then bail just
before removing the PM_UNSET flag?  Except:

} and if we run them it's doing too much work for syntax checking and is
} likely to mess things up owing to previous non-execution.

I don't know about too much work, but yes, some of them proceed a bit
too far into semantics.

} So this is all a bit nasty.  (Just for once.)

Does POSIX say anything about the environment in no_exec state?  Maybe
we should just temporarily toggle EXECOPT off during that part of the
shell initialization -- we're already avoiding execution of contents
of environment vars for security reasons, so it should be safe to do
the imports.


^ permalink raw reply	[relevance 3%]

* Re: ["regression"] Stéphane= 1 zsh -c 'echo $Stéphane'
  @ 2015-10-06 15:44  3% ` Bart Schaefer
  2015-10-06 18:59  0%   ` ZyX
  2015-10-07 13:15  5%   ` Stephane Chazelas
  0 siblings, 2 replies; 200+ results
From: Bart Schaefer @ 2015-10-06 15:44 UTC (permalink / raw)
  To: Zsh hackers list

This is discussed in the thread starting at workers/34004 and leading
up to workers/34015.

Nobody ever commented on whether the environment is allowed to contain
names with the high-order bit set, but POSIX identifiers cannot, so it
stands to reason you can't import something with that shape of name.

zsh -f -o posixidentifiers -c 'Stéphane=2; echo $Stéphane'
zsh:1: command not found: Stéphane=2
éphane

In effect the environment is always treated as POSIX_IDENTIFIERS.

POSIX_IDENTIFIERS <K> <S>
     When this option is set, only the ASCII characters a to z, A to Z,
     0 to 9 and _ may be used in identifiers (names of shell parameters
     and modules).


^ permalink raw reply	[relevance 3%]

* Re: ["regression"] Stéphane= 1 zsh -c 'echo $Stéphane'
  2015-10-06 15:44  3% ` ["regression"] Stéphane= 1 " Bart Schaefer
@ 2015-10-06 18:59  0%   ` ZyX
  2015-10-06 19:29  0%     ` Stephane Chazelas
  2015-10-07 13:15  5%   ` Stephane Chazelas
  1 sibling, 1 reply; 200+ results
From: ZyX @ 2015-10-06 18:59 UTC (permalink / raw)
  To: Bart Schaefer, Zsh hackers list


06.10.2015, 18:44, "Bart Schaefer" <schaefer@brasslantern.com>:
> This is discussed in the thread starting at workers/34004 and leading
> up to workers/34015.
>
> Nobody ever commented on whether the environment is allowed to contain
> names with the high-order bit set, but POSIX identifiers cannot, so it
> stands to reason you can't import something with that shape of name.

>From the list of shells I have ${Stéphane} with Stéphane=2 in environment accept only tcsh and ksh now (LANG=ru_RU.UTF-8).

Not accepting: mksh, rcsh*, posh, bash, dash, fish.

No shell accepts this with LANG=C.

glibc+tcc+getenv() call is fine with this name even with LANG=C.

Note: I do not know which standard describes environment variable names and what exactly it says about the issue.

* Plan 9 rc reimplementation, uses name `rcsh` due to name conflict with openrc.

>
> zsh -f -o posixidentifiers -c 'Stéphane=2; echo $Stéphane'
> zsh:1: command not found: Stéphane=2
> éphane
>
> In effect the environment is always treated as POSIX_IDENTIFIERS.
>
> POSIX_IDENTIFIERS <K> <S>
>      When this option is set, only the ASCII characters a to z, A to Z,
>      0 to 9 and _ may be used in identifiers (names of shell parameters
>      and modules).


^ permalink raw reply	[relevance 0%]

* Re: ["regression"] Stéphane= 1 zsh -c 'echo $Stéphane'
  2015-10-06 18:59  0%   ` ZyX
@ 2015-10-06 19:29  0%     ` Stephane Chazelas
  0 siblings, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-10-06 19:29 UTC (permalink / raw)
  To: ZyX; +Cc: Bart Schaefer, Zsh hackers list

2015-10-06 21:59:01 +0300, ZyX:
> 
> 06.10.2015, 18:44, "Bart Schaefer" <schaefer@brasslantern.com>:
> > This is discussed in the thread starting at workers/34004 and leading
> > up to workers/34015.
> >
> > Nobody ever commented on whether the environment is allowed to contain
> > names with the high-order bit set, but POSIX identifiers cannot, so it
> > stands to reason you can't import something with that shape of name.
> 
> From the list of shells I have ${Stéphane} with Stéphane=2 in environment accept only tcsh and ksh now (LANG=ru_RU.UTF-8).
[...]

Also bash, but not for multi-byte characters.

-- 
Stephane


^ permalink raw reply	[relevance 0%]

* Re: syntax check of 'echo $HOME' crashes in ksh emulation mode
  @ 2015-10-07  8:26  3%             ` Peter Stephenson
  0 siblings, 0 replies; 200+ results
From: Peter Stephenson @ 2015-10-07  8:26 UTC (permalink / raw)
  To: zsh-workers

On Tue, 6 Oct 2015 20:46:54 +0100
Peter Stephenson <p.w.stephenson@ntlworld.com> wrote:
> It's not very helpful.
  ^^^^ i.e. POSIX, in case it's not clear.  Somehow the quotation
  disappeared.

>     The shell shall read commands but does not execute them; this can be
>     used to check for shell script syntax errors. An interactive shell
>     may ignore this option.
> 
> But I think there is an argument for setting environment variables in
> full.

pws


^ permalink raw reply	[relevance 3%]

* Re: ["regression"] Stéphane= 1 zsh -c 'echo $Stéphane'
  2015-10-06 15:44  3% ` ["regression"] Stéphane= 1 " Bart Schaefer
  2015-10-06 18:59  0%   ` ZyX
@ 2015-10-07 13:15  5%   ` Stephane Chazelas
  1 sibling, 0 replies; 200+ results
From: Stephane Chazelas @ 2015-10-07 13:15 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Zsh hackers list

2015-10-06 08:44:16 -0700, Bart Schaefer:
> This is discussed in the thread starting at workers/34004 and leading
> up to workers/34015.
> 
> Nobody ever commented on whether the environment is allowed to contain
> names with the high-order bit set, but POSIX identifiers cannot, so it
> stands to reason you can't import something with that shape of name.

Note that it's not so much about the 8th bit (0-9 in EBCDIC have
the 8th bit set), but about being _, letters and digits in the
portable character set (0-9 a-z A-Z _).

POSIX doesn't forbid shells importing whatever they want from
the environment AFAICT. Only a POSIX application (script) must
not make use of those that are not valid POSIX identifiers.

IOW,

env Stéphane=1 sh -c 'echo "${Stéphane}"'

is an invalid inline-script, so it doesn't matter what sh does
with that Stéphane environment variable (as long as it's passed
along unmodified to the commands it executes, though not all
shells do it, and there was a discussion about it some time ago:
http://thread.gmane.org/gmane.comp.standards.posix.austin.general/690
)

> zsh -f -o posixidentifiers -c 'Stéphane=2; echo $Stéphane'
> zsh:1: command not found: Stéphane=2
> éphane
> 
> In effect the environment is always treated as POSIX_IDENTIFIERS.
> 
> POSIX_IDENTIFIERS <K> <S>
>      When this option is set, only the ASCII characters a to z, A to Z,
>      0 to 9 and _ may be used in identifiers (names of shell parameters
>      and modules).
[...]

Note that while POSIX (AFAICS) requires $Stéphane to be treated
as ${St}éphane, ksh93 and bash (in single-byte character
locales) don't.

The behaviour for ${Stéphane} would be unspecified, so
implementations may do whatever they want there.

Now, I won't be the one complaining if I can't use $Stéphane or
${Stéphane} as a variable name, I never liked the idea of the
syntax of a script being dependant on the locale.

-- 
Stephane


^ permalink raw reply	[relevance 5%]

* Re: Possible bug in signal handling
  @ 2015-11-04  4:46  3%     ` Bart Schaefer
  2015-11-04 14:25  4%       ` Vincent Lefevre
  0 siblings, 1 reply; 200+ results
From: Bart Schaefer @ 2015-11-04  4:46 UTC (permalink / raw)
  To: Dima Kogan, zsh-workers

On Nov 3,  8:27pm, Dima Kogan wrote:
}
} Thanks for looking at this, Bart. I don't really understand this area in
} detail, but should those changes be necessary? Is it not a bug in zsh
} (and bash, I guess) that the perl process is orphaned?

That's unclear.  The default response to SIGINT is supposed to be that
the process exits, not that it only exits if it has children that have
not yet exited.  If someone wants to pore over the POSIX spec and point
out where it says that rule is countermanded for the shell, go for it.
Otherwise I'd say it's up to the script to change the signal handling
away from the default.

You could also fix it by using "exec perl ..." which in zsh removes the
"inner zsh" from the process tree entirely (in that particular example;
more generally, "exec" the rightmost thing in the pipeline).


^ permalink raw reply	[relevance 3%]

* Re: Possible bug in signal handling
  2015-11-04  4:46  3%     ` Bart Schaefer
@ 2015-11-04 14:25  4%       ` Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2015-11-04 14:25 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: Dima Kogan, zsh-workers

On 2015-11-03 20:46:34 -0800, Bart Schaefer wrote:
> That's unclear.  The default response to SIGINT is supposed to be that
> the process exits, not that it only exits if it has children that have
> not yet exited.

I suppose you meant "if it does not have children...". You're thinking
about IUE (implemented by zsh, unless this has changed in the last few
years), while WCE (implemented by bash) is generally regarded to be
better:

  http://www.cons.org/cracauer/sigint.html

Dima's example may be more complex.

> If someone wants to pore over the POSIX spec and point out where it
> says that rule is countermanded for the shell, go for it.

I don't think that POSIX covers that, otherwise one wouldn't have
the above differences between POSIX shells.

-- 
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 4%]

* Inconsistency with SHWORDSPLIT and leading spaces
@ 2015-11-06 10:54  4% Christian Neukirchen
  0 siblings, 0 replies; 200+ results
From: Christian Neukirchen @ 2015-11-06 10:54 UTC (permalink / raw)
  To: zsh-workers

Hi,

I noticed the following different behavior trying to use zsh as /bin/sh:

juno ~% dash -c 'x=foo; echo x${x:+ $x}' 
x foo
juno ~% bash -c 'x=foo; echo x${x:+ $x}' 
x foo
juno ~% mksh -c 'x=foo; echo x${x:+ $x}' 
x foo
juno ~% ksh -c 'x=foo; echo x${x:+ $x}' 
x foo
juno ~% zsh -c 'x=foo; echo x${x:+ $x}' 
x foo
juno ~% zsh -c 'emulate -L sh; x=foo; echo x${x:+ $x}'           
xfoo
juno ~% zsh -c 'emulate -L ksh; x=foo; echo x${x:+ $x}' 
xfoo
juno ~% zsh -c 'setopt shwordsplit; x=foo; echo x${x:+ $x}' 
xfoo

zsh 5.1.1 (x86_64-unknown-linux-gnu)
zsh-5.1.1-0-g68405f3

It's not clear to me whether this is *actually* POSIX-nonconformant, but
it's at least surprising compared to the other POSIX-compatible shells.

Thanks,
-- 
Christian Neukirchen  <chneukirchen@gmail.com>  http://chneukirchen.org


^ permalink raw reply	[relevance 4%]

* The "set" utility outputs binary data
@ 2015-12-03 14:05  3% Vincent Lefevre
  0 siblings, 0 replies; 200+ results
From: Vincent Lefevre @ 2015-12-03 14:05 UTC (permalink / raw)
  To: zsh-workers

The "set" utility outputs binary data (probably due to escape
sequences for coloring and so on in some parameters such as
prompts):

zira:~> set | grep ZSH
Binary file (standard input) matches

Though I could use the non-standard -a grep option, this is annoying.
I think that by default, "set" should quote non-printable characters
(including invalid byte sequences, I assume). I don't think that this
is even forbidden by POSIX, which already requires the shell to quote
some characters so that the output is "suitable for reinput to the
shell".

This is also important when the output is on a terminal.

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


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 3%]

Results 1001-1200 of ~2400   |  | reverse | sort options + mbox downloads above
-- links below jump to the message on this page --
2012-08-17 10:50     pkgsrc patches for zsh [was Re: tgoto issue in zsh-5.0.0] Thomas Klausner
2012-08-17 11:35     ` Peter Stephenson
2012-08-17 12:16       ` Thomas Klausner
2014-06-24 14:37         ` ulimit -a: -r vs -N [was Re: pkgsrc patches for zsh] Thomas Klausner
2014-06-24 15:07           ` Peter Stephenson
2014-06-24 16:11             ` Thomas Klausner
2014-06-24 16:26               ` Peter Stephenson
2014-06-24 17:09                 ` Thomas Klausner
     [not found]                   ` <sfid-H20140625-102724-+051.56-1@spamfilter.osbf.lua>
2014-06-25  8:26                     ` Peter Stephenson
2014-06-25  8:36                       ` Thomas Klausner
2014-06-25 10:33  4%                     ` Peter Stephenson
2014-06-25 11:00                           ` Thomas Klausner
2014-06-25 11:11  5%                         ` Peter Stephenson
2013-11-23 17:48     modify functions hierarchy (was: Install run-help and *.zwc files system wide in build system) Peter Stephenson
2013-11-23 19:47     ` Helpfiles again (was Re: modify functions hierarchy (was: etc.)) Bart Schaefer
2013-11-23 21:25       ` Martin Vaeth
2013-11-24  5:06         ` Bart Schaefer
     [not found]           ` <20131124175649.27c2559a@pws!>
     [not found]             ` <-pc.ntlworld.com@samsung.com>
2013-11-25  8:18               ` Bart Schaefer
2013-11-25 14:24                 ` Jun T.
2013-11-25 15:49                   ` Peter Stephenson
2013-11-25 16:56                     ` Bart Schaefer
2013-12-12 22:17                       ` PATCH: Util/helpfiles failing on old-fashioned unix pda
2013-12-13  9:08  4%                     ` Martin Vaeth
2013-12-16 19:10  3% Read-only variables in emulation mode Øystein Walle
2013-12-16 19:40  3% ` Bart Schaefer
2013-12-18  6:36  5%   ` Bart Schaefer
2013-12-18 19:28  0%     ` Peter Stephenson
2013-12-19  7:57  3%       ` Bart Schaefer
2015-06-16  0:10  0%         ` Mikael Magnusson
2013-12-20 19:24  2% Fwd (potential regression in 5.0.3): Bug#732726: zsh function freeze Axel Beckert
2014-01-10 22:37  6% PATCH: shift -p Peter Stephenson
2014-01-22 15:59  4% [PATCH] new completion function for od Jun T.
2014-02-02 20:48  3% Following up from before 5.0.5: Change initialization of parameters Bart Schaefer
     [not found]     <20140220050415.GA29027@lilyforest>
     [not found]     ` <CAH+w=7Z+R_ZexSkesp2z+ndooHStOGJcMeWXtD7HCunjqJp9-Q@mail.gmail.com>
     [not found]       ` <20140220094053.137da74f@pwslap01u.europe.root.pri>
     [not found]         ` <20140220131659.GA21182@lilyforest>
2014-02-20 19:36           ` It seems that I find a zle -F full CPU bug Bart Schaefer
2014-02-20 20:04  3%         ` Peter Stephenson
2014-03-12 15:36  8% Zsh does not follow POSIX when return is called during the action of a trap Eduardo A. Bustamante López
2014-03-12 16:52  9% ` Bart Schaefer
2014-03-12 17:03  5%   ` Peter Stephenson
2014-03-12 17:47  7%     ` Eduardo A. Bustamante López
2014-03-12 17:49  5%     ` Chet Ramey
2014-03-12 18:23 10%       ` Peter Stephenson
2014-03-17 15:01  7% [PATCH] A few cleanups in manpages Jun T.
2014-04-01 21:22     LOGNAME not properly set on FreeBSD Erik Johnson
2014-04-02  0:27     ` Phil Pennock
2014-04-02  0:50       ` Erik Johnson
2014-04-02 20:54  3%     ` Phil Pennock
2014-04-02 21:11  0%       ` Erik Johnson
2014-04-02  9:23     ` Peter Stephenson
2014-04-02 19:06       ` Erik Johnson
2014-04-02 20:58  4%     ` Peter Stephenson
2014-04-02 21:14  0%       ` Erik Johnson
2014-04-24 16:48     zsh got stuck without any message because of history lock file Andreas
2014-04-24 17:02     ` Bart Schaefer
2014-04-25  5:02       ` Bart Schaefer
2014-06-26 20:46         ` Mikael Magnusson
2014-09-06  9:03           ` Mikael Magnusson
2014-09-06 18:51  2%         ` Bart Schaefer
     [not found]     <CAH_OBicpVKS-URnd-Gq=gj+qc6OhDCqf0mgDfVcda27mEEfUKg@mail.gmail.com>
     [not found]     ` <140416102727.ZM19090@torch.brasslantern.com>
     [not found]       ` <CAH_OBic7sX1Oc4VWn2KvX40smbRB6A7w8QGXLvPfZLD=CHMddQ@mail.gmail.com>
     [not found]         ` <534FE710.3020601@eastlink.ca>
     [not found]           ` <140417123722.ZM22179@torch.brasslantern.com>
     [not found]             ` <20140423165024.1480528a@pws-pc.ntlworld.com>
     [not found]               ` <lj984r$6uo$1@ger.gmane.org>
     [not found]                 ` <CAHYJk3QOZTnicq+Nqg4BXNANa_c6_j5mhyQNK1f8YNtDhxixgA@mail.gmail.com>
     [not found]                   ` <slrnlll0kq.v0i.martin@lounge.imp.fu-berlin.de>
     [not found]                     ` <20140425172112.7bf50606@pwslap01u.europe.root.pri>
     [not found]                       ` <slrnlln1bj.a9l.martin@epidot.math.uni-rostock.de>
2014-04-26 20:30  3%                     ` Parser issues and and [[ $var ]] Bart Schaefer
2014-05-10 21:09  2%                       ` Bart Schaefer
2014-05-29 23:04  3% 'emulate sh -c' and $0 Richard Hansen
2014-05-30  3:45  3% ` Bart Schaefer
2014-05-30  8:49  3%   ` Richard Hansen
2014-05-30 17:00         ` Bart Schaefer
2014-05-30 21:14  4%       ` Richard Hansen
2014-05-31  5:13  2%         ` Bart Schaefer
2014-06-03 20:15  0%           ` Richard Hansen
2014-06-03 20:26  3%             ` Peter Stephenson
2014-06-03 21:10  0%               ` Bart Schaefer
2014-06-04  2:12  3% Oddball output from zerrmsg() Bart Schaefer
2014-06-05 14:56  2% [PATCH] A few more format fix in docs Jun T
2014-06-28 12:34  2% Fwd: [Pkg-zsh-devel] Bug#702760: zsh: aptitude completion missing resolver options [origin: dbbcode@gmail.com] Axel Beckert
2014-06-28 13:50  3% Fwd: [Pkg-zsh-devel] Bug#702000: zsh: gzip completion: --rsyncable option is missing [origin: vincent@vinc17.net] Axel Beckert
2014-07-03 18:14  4% Discussion of path search for builtin utilities Bart Schaefer
2014-07-23 16:09  3% aliases+=(foo 'echo bar') crash Stephane Chazelas
2014-07-30 10:46  6% PATCH: ztrftime %. for fractions of a second in prompts Peter Stephenson
2014-07-30 13:16  0% ` Vin Shelton
2014-08-13 22:30  4% PATCH: assorted completion function updates Oliver Kiddle
2014-09-11 20:07 10% POSIX_ARGZERO: not POSIX compliant in sourced script?! Daniel Hahler
2014-09-12  3:59  9% ` Bart Schaefer
2014-09-14  1:03  5%   ` Daniel Hahler
2014-09-24 14:07     Surprising parsing result with anonymous functions and for loops Mikael Magnusson
2014-09-24 14:26     ` Peter Stephenson
2014-09-24 22:02       ` Mikael Magnusson
2014-09-25  5:35         ` Bart Schaefer
2014-09-25  5:53  3%       ` Bart Schaefer
     [not found]     ` <CAKjp4B7Gy9f2RCYzn8G6i+ADh_p7GWZEv1x_Cd0eR3Ggxv+APw@mail.gmail.com>
2014-09-24 19:14  4%   ` Fwd: " Clint Hepner
2014-10-14 20:32  1% PATCH: fix return status of completion functions Oliver Kiddle
2014-10-21  7:53     bug in zsh wait builtin - rhbz#1150541 Tim Speetjens
2014-10-21 20:02  3% ` Peter Stephenson
2014-10-22  6:55  4%   ` Bart Schaefer
2014-10-22 18:32  3%     ` Chet Ramey
2014-10-23  8:32  0%     ` Peter Stephenson
2014-10-24  4:50           ` Bart Schaefer
2014-10-25 19:08  2%         ` Peter Stephenson
     [not found]     <20141020215420.GB7819@chaz.gmail.com>
     [not found]     ` <54480AFD.9010504@case.edu>
2014-10-22 20:52  0%   ` [austin-group] Re: clarification on $*/$@ Bart Schaefer
2014-10-23  9:29  4%     ` Stephane Chazelas
2014-11-01 14:31     Bug report: Strange behaviour of $SHLVL in subshell Eliseo Martínez
2014-11-01 19:15  2% ` Peter Stephenson
2014-12-15 11:33  8% Different behaviour of zsh with two input redirections compared to all other POSIX shells I have installed Axel Beckert
2014-12-15 11:46  5% ` Peter Stephenson
2014-12-15 11:53  5%   ` Axel Beckert
2014-12-18 18:19     [BUG] Unicode variables can be exported and are exported metafied ZyX
2014-12-18 19:29     ` Peter Stephenson
2014-12-18 19:47       ` Peter Stephenson
2014-12-18 19:58  3%     ` Bart Schaefer
2014-12-18 20:09  0%       ` Peter Stephenson
     [not found]           ` <54933513.6010501@case.edu>
2014-12-18 20:20  0%         ` Fwd: " Bart Schaefer
2014-12-19  9:29  0%       ` Christoph (Stucki) von Stuckrad
2014-12-19 18:17  0%       ` Christoph (Stucki) von Stuckrad
2014-12-19 20:13  0%         ` Павлов Николай Александрович
2014-12-19 21:21  0%         ` Peter Stephenson
2014-12-19 22:44  0%           ` ZyX
2015-01-10  0:25     Math expression evaluation error? Bart Schaefer
2015-01-10  7:27     ` Ray Andrews
2015-01-10 16:53       ` Bart Schaefer
2015-01-10 18:48         ` Ray Andrews
2015-01-10 19:14           ` Bart Schaefer
2015-01-10 22:21             ` Ray Andrews
2015-01-11  1:51               ` Bart Schaefer
2015-01-11  5:10                 ` Ray Andrews
2015-01-12  9:17                   ` Vincent Lefevre
2015-01-12 16:18                     ` ZyX
2015-01-13 16:00  5%                   ` Vincent Lefevre
2015-01-13 23:03  5%                     ` ZyX
2015-01-14 14:47  4%                       ` Vincent Lefevre
2015-01-14 21:37  4%                         ` ZyX
2015-01-15 13:34  3%                           ` Vincent Lefevre
2015-01-15 13:41  3%                             ` Vincent Lefevre
2015-01-15 18:32  4%                             ` ZyX
2015-01-15 21:57  3%                               ` Bart Schaefer
2015-01-13 20:38  3% OPTIND set incorrectly by getopts for options without arg Simon Chiang
2015-01-13 21:34  4% ` Bart Schaefer
2015-03-14 20:54  2% Attempt to document aliasing more fully Bart Schaefer
2015-03-15 18:35  0% ` Peter Stephenson
2015-03-18  6:29  2% Aliasing part 3 (or so) - Doc and POSIX_ALIASES Bart Schaefer
2015-03-28 21:08     [[ is being treated as a pattern in the command/reserved word position Eric Cook
2015-03-28 21:44     ` Bart Schaefer
2015-03-28 21:55       ` Eric Cook
2015-03-28 22:24         ` Bart Schaefer
2015-03-28 22:33  3%       ` ZyX
2015-03-28 22:45  4%         ` Bart Schaefer
2015-03-28 23:07  0%         ` Eric Cook
2015-03-28 23:19  5%           ` ZyX
2015-03-28 23:27  0%             ` Eric Cook
2015-03-28 23:57  4%               ` ZyX
2015-03-29  0:09  0%                 ` Eric Cook
2015-04-03 13:52  4% [RFC PATCH] Allow grouping of thousands in format string Øystein Walle
2015-04-04 11:11  0% ` Oliver Kiddle
2015-04-07 15:51  4% "var=value exec > file" ignores the assignment? Jun T.
     [not found]     <mg78mg$vqb$1@ger.gmane.org>
     [not found]     ` <CABx2=D-VTpp3ihAE_A2KCdE3tcPu5RPuB8WJwtv-G=B0QNx0GQ@mail.gmail.com>
     [not found]       ` <mg79kr$vqb$2@ger.gmane.org>
     [not found]         ` <CABx2=D9Mk01ovQkMyWT_1nh9WdDvcpqmMJAOdka-oEmN8Xe4nw@mail.gmail.com>
     [not found]           ` <CABx2=D93rJDoqGHa=9=nGZZU=9oC_vc-0FHE8ZERV9LmxtqRaA@mail.gmail.com>
     [not found]             ` <CAHYJk3Qj6W=VZ26si0VjhsmS1u9go6mVGpXjDSTLk5knKaEtOg@mail.gmail.com>
     [not found]               ` <CABx2=D_4Aw4W9AsBNa5o1houzAipLFDBtt82BnVq0CEyNshSUA__23909.3113611036$1428636185$gmane$org@mail.gmail.com>
2015-04-10 20:33  3%             ` `[[ -n $VAR ]]` equal to `[[ $VAR ]]`? Stephane Chazelas
2015-04-12 22:24  6% [PATCH] correct typo in doc of posixtraps Han Pingtian
2015-04-29  6:35     [BUG] Can't mark unset variables as read-only Martijn Dekker
2015-04-29 10:36  3% ` Peter Stephenson
2015-04-29 13:55  3%   ` Bart Schaefer
2015-04-29 14:41  0%     ` Peter Stephenson
2015-04-29 15:33  5%       ` Chet Ramey
2015-04-29 19:09  3%         ` Stephane Chazelas
2015-04-30  3:57  5%         ` Bart Schaefer
2015-04-30 20:03     PATCH: 5.0.8 notes Peter Stephenson
2015-04-30 22:13  3% ` Mikael Magnusson
2015-05-01 20:32       ` Peter Stephenson
2015-05-03 18:09  5%     ` Peter Stephenson
2015-05-03 20:11  0%       ` Mikael Magnusson
2015-05-01  9:58  5% PATCH: update completions for some common Unix commands Oliver Kiddle
2015-05-07  9:35  8% PATCH: readonly -p with POSIX_BUILTINS Peter Stephenson
2015-05-08 11:43  8% ` Peter Stephenson
2015-05-14 13:14  5% 'case' pattern matching bug with bracket expressions Martijn Dekker
2015-05-14 14:42  2% ` Peter Stephenson
2015-05-14 15:47       ` Martijn Dekker
2015-05-14 15:55  3%     ` Peter Stephenson
2015-05-14 17:30  3%       ` Bart Schaefer
2015-05-15  0:05  3%         ` Chet Ramey
2015-05-15  8:38  3%       ` Peter Stephenson
2015-05-15 20:48             ` Peter Stephenson
2015-05-15 21:48  3%           ` Bart Schaefer
2015-05-14 16:17         ` Peter Stephenson
2015-05-14 17:07           ` Martijn Dekker
2015-05-14 17:43  3%         ` Peter Stephenson
2015-05-14 23:59  3%       ` Chet Ramey
2015-05-14 21:23  3%   ` Chet Ramey
2015-05-14 23:45  0%   ` Chet Ramey
2015-05-17 20:53  2% PATCH: case pattern parsing Peter Stephenson
2015-05-18  3:07     Pattern matching: backslash escaping not active in pattern passed from variable Martijn Dekker
2015-05-18  8:33     ` Mikael Magnusson
2015-05-18  8:49  3%   ` Peter Stephenson
2015-05-18 13:28  3% zsh doesn't support standard "unalias -a" Martijn Dekker
2015-05-27 18:40  3% test -z '(' : too many arguments Martijn Dekker
2015-05-27 20:23  7% ` Peter Stephenson
2015-05-27 19:06     zsh-5.0.7-dev-4 Peter Stephenson
2015-05-27 19:33     ` zsh-5.0.7-dev-4 Martijn Dekker
2015-05-27 19:50       ` zsh-5.0.7-dev-4 Peter Stephenson
2015-05-27 20:46  3%     ` zsh-5.0.7-dev-4 Martijn Dekker
2015-05-27 21:17  0%       ` zsh-5.0.7-dev-4 Mikael Magnusson
2015-05-28 16:18  4% getopts doesn't update OPTIND when called from function Martijn Dekker
2015-05-28 17:17  4% ` Peter Stephenson
2015-06-05  6:46  0%   ` Roman Neuhauser
2015-06-06 16:46  0%     ` Bart Schaefer
2015-06-07  8:30  0%       ` Roman Neuhauser
2015-05-28 19:42     Arith parsing bug with minus after $# Martijn Dekker
2015-05-29 15:02  3% ` Peter Stephenson
2015-05-29 15:43  0%   ` Martijn Dekker
2015-05-29 18:09       ` Bart Schaefer
2015-05-29 19:33  3%     ` Martijn Dekker
2015-05-29 20:48  0%       ` ZyX
2015-06-07  1:08  3%   ` Bart Schaefer
2015-06-01 16:32  3% Arith expansion accepts extra closing parenthesis Martijn Dekker
2015-06-02  8:56  0% ` Peter Stephenson
2015-06-07  0:23 10% In POSIX mode, ${#var} measures length in bytes, not characters Martijn Dekker
2015-06-07  0:34  9% ` ZyX
2015-06-07  1:23 10%   ` Bart Schaefer
2015-06-07  1:27  5%     ` ZyX
2015-06-07  2:21 10%   ` Martijn Dekker
2015-06-09 17:49  5%     ` Martijn Dekker
2015-06-08  8:44  5% ` Peter Stephenson
2015-06-09  2:19  9%   ` Martijn Dekker
2015-06-09  8:35  5%     ` Peter Stephenson
2015-06-09 15:37  5%       ` Bart Schaefer
2015-06-09 15:43  5%         ` Peter Stephenson
2015-06-11 11:23  5%   ` Daniel Shahaf
2015-06-11 11:33  4%     ` Peter Stephenson
     [not found]     <20150607081142.GF15174@isis.sigpipe.cz>
2015-06-07 20:39     ` printf, left-justification ignored in 5.0.8 Oliver Kiddle
2015-06-07 21:15  3%   ` Stephane Chazelas
2015-06-12 11:30  0%     ` Vincent Lefevre
2015-06-12 12:31  0%       ` Stephane Chazelas
2015-06-13 21:47  5% Alias expansion rules taken up for POSIX standards review Bart Schaefer
2015-06-22  3:06  5% Field splitting: extra empty field with final non-whitespace IFS character Martijn Dekker
2015-06-23  7:16     "_alternative:shift:14: shift count must be <= $#" with zsh-5.0.8 Markus Trippelsdorf
2015-06-23 10:53  3% ` Peter Stephenson
2015-06-23 11:19  0%   ` Markus Trippelsdorf
2015-06-24  6:53  3% Another thought about typeset-array: effect of/on POSIX_BUILTINS ? Bart Schaefer
2015-06-24  8:33  0% ` Peter Stephenson
2015-06-25  1:02  4% '>>' does not create file if set -C (noclobber) is active Martijn Dekker
2015-06-25  1:49  5% ` Bart Schaefer
2015-06-25  2:22  0%   ` Martijn Dekker
2015-06-25  7:30  3%     ` Bart Schaefer
2015-06-25 14:04  3%       ` Stephane Chazelas
2015-06-25 16:00  3%         ` Bart Schaefer
2015-06-25 19:20  4%           ` Chet Ramey
2015-06-26 14:14  4%       ` Martijn Dekker
2015-06-26 20:15  4%         ` Bart Schaefer
2015-06-27  1:54  5%           ` Martijn Dekker
2015-06-27  3:38  6%             ` Bart Schaefer
2015-06-27 17:02  7%         ` Peter Stephenson
2015-06-28  0:02  3%           ` Martijn Dekker
2015-06-28 17:19 10%             ` Peter Stephenson
2015-06-27 22:19  3% Strange regression in zsh-git with redirecting output of 'readonly' Martijn Dekker
2015-07-25 22:46  3% I almost hate to ask this, but: Version 5.0.9? Bart Schaefer
2015-07-26  6:12  0% ` Mikael Magnusson
2015-07-26 16:55  0% ` Peter Stephenson
2015-08-03 11:25     Deadlock when receiving kill-signal from child process Mathias Fredriksson
2015-08-03 15:52     ` Bart Schaefer
2015-08-03 20:36       ` Mathias Fredriksson
2015-08-03 20:58         ` Bart Schaefer
2015-08-04 21:52           ` Mathias Fredriksson
2015-08-05  6:53             ` Bart Schaefer
2015-08-05 10:37               ` Mathias Fredriksson
2015-08-05 15:52                 ` Bart Schaefer
2015-08-05 16:05                   ` Mathias Fredriksson
2015-08-05 18:52                     ` Bart Schaefer
2015-08-05 19:11                       ` Mathias Fredriksson
2015-08-05 20:20                         ` Bart Schaefer
2015-08-05 21:49                           ` Mathias Fredriksson
2015-08-06  5:06                             ` Bart Schaefer
2015-08-06  8:24                               ` Mathias Fredriksson
2015-08-06 15:54  2%                             ` Bart Schaefer
2015-08-07  0:45  2%                               ` Mathias Fredriksson
2015-08-11 18:50  7% PATCH for NEWS update Bart Schaefer
2015-09-02 23:07     invalid characters and multi-byte [x-y] ranges Stephane Chazelas
2015-09-03  9:00     ` Peter Stephenson
2015-09-03 10:09  4%   ` Stephane Chazelas
2015-09-06 15:57     Pasting UTF-8 characters with bracketed-paste-magic seems broken in 5.1 Axel Beckert
2015-09-10 14:39     ` Bart Schaefer
2015-09-10 14:57       ` Axel Beckert
2015-09-10 15:45         ` Bart Schaefer
2015-09-10 16:07           ` Peter Stephenson
2015-09-10 16:16             ` Bart Schaefer
2015-09-10 16:28               ` Peter Stephenson
2015-09-10 18:57  6%             ` Peter Stephenson
2015-09-16 16:26     bug with $PWD in / Stephane Chazelas
2015-09-19 18:08  5% ` Bart Schaefer
2015-09-19 19:28  0%   ` Stephane Chazelas
2015-09-19 20:47  7%     ` Bart Schaefer
2015-09-28 18:13  3%       ` Daniel Shahaf
2015-09-24 17:40  1% Bug in llvm compiler Sebastian Gniazdowski
2015-09-30 11:56 14% [PATCH] minor doco spelling fixes Andrew Janke
2015-09-30 13:25     ` Peter Stephenson
2015-09-30 13:43       ` Peter Stephenson
2015-10-01  1:14 13%     ` Andrew Janke
2015-10-05 16:09     syntax check of 'echo $HOME' crashes in ksh emulation mode Kamil Dudka
2015-10-05 16:42     ` Peter Stephenson
2015-10-05 17:45       ` Bart Schaefer
2015-10-06  8:33         ` Peter Stephenson
2015-10-06  9:15           ` Peter Stephenson
2015-10-06 15:34  3%         ` Bart Schaefer
2015-10-06 19:46               ` Peter Stephenson
2015-10-07  8:26  3%             ` Peter Stephenson
2015-10-06 11:04     ["regression"] Stéphane=1 zsh -c 'echo $Stéphane' Stephane Chazelas
2015-10-06 15:44  3% ` ["regression"] Stéphane= 1 " Bart Schaefer
2015-10-06 18:59  0%   ` ZyX
2015-10-06 19:29  0%     ` Stephane Chazelas
2015-10-07 13:15  5%   ` Stephane Chazelas
2015-11-02 10:10     Possible bug in signal handling Dima Kogan
2015-11-04  4:16     ` Bart Schaefer
2015-11-04  4:27       ` Dima Kogan
2015-11-04  4:46  3%     ` Bart Schaefer
2015-11-04 14:25  4%       ` Vincent Lefevre
2015-11-06 10:54  4% Inconsistency with SHWORDSPLIT and leading spaces Christian Neukirchen
2015-12-03 14:05  3% The "set" utility outputs binary data Vincent Lefevre
2015-12-10  1:52     expr length "$val" returns the wrong length for values containing NULL (\\0) D Gowers
2015-12-10  3:56  3% ` Nikolay Aleksandrovich Pavlov (ZyX)

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).