From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 2863 invoked by alias); 14 Sep 2016 22:07:54 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: X-Seq: 39332 Received: (qmail 17190 invoked from network); 14 Sep 2016 22:07:54 -0000 X-Qmail-Scanner-Diagnostics: from nm25-vm4.bullet.mail.ir2.yahoo.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.99.2/21882. spamassassin: 3.4.1. Clear:RC:0(212.82.97.37):SA:0(0.0/5.0):. Processed in 0.479475 secs); 14 Sep 2016 22:07:54 -0000 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=FREEMAIL_FROM,SPF_PASS, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.1 X-Envelope-From: okiddle@yahoo.co.uk X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _spf.mail.yahoo.com designates 212.82.97.37 as permitted sender) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.co.uk; s=s2048; t=1473890511; bh=tzIySvyoKpSd2hPLqE9a/bZwtRHptTpL5Sm5AmTu0aE=; h=In-reply-to:From:References:To:Subject:Date:From:Subject; b=nebTmEIBoYlKdYS0gJNdchyDr9+zHw020yxGiJ6+xrPLvsRt+lat2KFo5F01sFmsh3kh0tR2DNAtTnGo71c5MPz4hcpHcowPoH3RkuXu4ua8Jmy49d3UUsqjdtSYcWLak1Q7KiUwYC4jx7KbUlTrjmQCYDTXzeM3njYvcF187ySv8P0vYMNd0wlPWVt36PY80rgwHnICIYav9NL2PM2nBGIEACOI1wvJQsr3styjIK1u2UcbHNhHiNURAa8O8DtgRwq9/HExIP/mZX5O4TZR4SrbYk9JXLXgWTqOl8zjXKYi0fzALDowV4bEIut5F0fSQ3vY4su3XlGwqqglrqQufQ== X-Yahoo-Newman-Id: 728934.1806.bm@smtp121.mail.ir2.yahoo.com X-Yahoo-Newman-Property: ymail-3 X-YMail-OSG: tEqLAacVM1mn00GHuLyfPDZ_LcZTklEZ10WAv5lvWL2LoNq 4J2L8B1i3F319bGmAwar3vQ.Udv6CDd4Nuym5LKk2TKgsEd98m6mTenKx50V 5zy8whIo4hRLwy2Vg53nhTdaa8UHJRiM9Df3SdEnYm3R1gZ5p9ZxRGmn6hpP ngM3eLlHnN636uitYuMQ48Oqo1pyKfDXoq9LGgMEJrUcp6odJwXmL_6ihRLS RfCHqwREdmTLwcIz68Ife36R96BUADUsnwmn03HPnP.h9wqBKOdH520DIN5P ctSbKElztTmdrZnjrvc5K40lqkApYOnqPlzMpRdS6kNIjztcS3Lru2.U9iX4 cCh.vhZZCMVmsjuQKUaTRw8F3I4balIW2rqaRjxXxGDTRThJS5_0WHK4lRRT 5vz8F1GTbT3GdkwZjKbp4lS3A0g7MnHX3TUWQ6oJd8uTyGDKtskstemaBgXO vMd4OLTVpBfrSarHc1Gziw7fJ65KsbBYDE3I4BhXt78FvhAzZi_fmmQ_I3FQ s1fneMwqoByiLeMe6d7asH3Np_6lpCRSXYAp.F0V3QT6LyvN6HZ3gK0MELPc EqA_U6IwLHrPtZoSKnz.dM3iLmKF_w_Shjt57cxeoNJzSw0iRGaGIBA-- X-Yahoo-SMTP: opAkk_CswBAce_kJ3nIPlH80cJI- In-reply-to: <20160909085231.GA9717@chaz.gmail.com> From: Oliver Kiddle References: <20160905212754.24998-1-tgyurci@gmail.com> <20160908093516.4fc2dd1e@pwslap01u.europe.root.pri> <20160908121628.78977edd@pwslap01u.europe.root.pri> <20160908143128.GA14933@chaz.gmail.com> <20160909085231.GA9717@chaz.gmail.com> To: zsh-workers@zsh.org Subject: PATCH: [[ -v varname ]] MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-ID: <90413.1473890510.1@hydra.kiddle.eu> Date: Thu, 15 Sep 2016 00:01:50 +0200 Message-ID: <90414.1473890510@hydra.kiddle.eu> On 9 Sep, Stephane Chazelas wrote: > You guys may want to comment on the latest proposal there: > http://austingroupbugs.net/file_download.php?file_id=31&type=bug > as it would make zsh non-conformant. One thing it also includes is the bash/ksh [[ -v ... ]] condition for checking if a particular variable is set. Zsh has the ${+varname} syntax which provides the same functionality in a different form. The following patch adds the ksh form for compatibility. The code for ${+...} is mixed in with the rest of the parameter substitution code so I couldn't easily reuse it. There may be subtle differences as a result. In particular it returns false for a string slice. That's arguably not a variable and would raise the question of string slices on an array slice. There's also subtle differences relative to bash/ksh. local/typeset in bash/ksh leave the variable undefined until it is given a value rather than making it an empty scalar. And bash doesn't seem to handle the positional parameters. Oliver diff --git a/Completion/Zsh/Context/_condition b/Completion/Zsh/Context/_condition index 6f5e601..0285911 100644 --- a/Completion/Zsh/Context/_condition +++ b/Completion/Zsh/Context/_condition @@ -8,6 +8,8 @@ elif [[ "$prev" = -([a-hkprsuwxLOGSN]|[no]t|ef) ]]; then _tags -C "$prev" files && _files elif [[ "$prev" = -t ]]; then _file_descriptors +elif [[ "$prev" = -v ]]; then + _parameters -r "\= \t\n\[\-" else if [[ "$PREFIX" = -* ]] || ! zstyle -T ":completion:${curcontext}:options" prefix-needed; then @@ -30,6 +32,7 @@ else -s:non-empty\ file -t:terminal\ file\ descriptor -u:setuid\ bit + -v:set\ variable -w:writable\ file -x:executable\ file -z:empty\ string diff --git a/Doc/Zsh/cond.yo b/Doc/Zsh/cond.yo index 474baa1..e08fc0d 100644 --- a/Doc/Zsh/cond.yo +++ b/Doc/Zsh/cond.yo @@ -63,6 +63,9 @@ is open and associated with a terminal device. item(tt(-u) var(file))( true if var(file) exists and has its setuid bit set. ) +item(tt(-v) var(varname))( +true if shell variable var(varname) is set. +) item(tt(-w) var(file))( true if var(file) exists and is writable by current process. ) diff --git a/Src/cond.c b/Src/cond.c index f25ebd4..42e9de3 100644 --- a/Src/cond.c +++ b/Src/cond.c @@ -351,6 +351,8 @@ evalcond(Estate state, char *fromtest) return (!S_ISSOCK(dostat(left))); case 'u': return (!(dostat(left) & S_ISUID)); + case 'v': + return (!issetvar(left)); case 'w': return (!doaccess(left, W_OK)); case 'x': diff --git a/Src/params.c b/Src/params.c index 842b2f0..5c534af 100644 --- a/Src/params.c +++ b/Src/params.c @@ -626,6 +626,36 @@ getvaluearr(Value v) return NULL; } +/* Return whether the variable is set * + * checks that array slices are within range * + * used for [[ -v ... ]] condition test */ + +/**/ +int +issetvar(char *name) +{ + struct value vbuf; + Value v; + int slice; + char **arr; + + if (!(v = getvalue(&vbuf, &name, 1)) || *name) + return 0; /* no value or more chars after the variable name */ + if (v->isarr & ~SCANPM_ARRONLY) + return v->end > 1; /* for extracted elements, end gives us a count */ + + slice = v->start != 0 || v->end != -1; + if (PM_TYPE(v->pm->node.flags) != PM_ARRAY || !slice) + return !slice && !(v->pm->node.flags & PM_UNSET); + + if (!v->end) /* empty array slice */ + return 0; + /* get the array and check end is within range */ + if (!(arr = getvaluearr(v))) + return 0; + return arrlen_ge(arr, v->end < 0 ? - v->end : v->end); +} + /* * Split environment string into (name, value) pair. * this is used to avoid in-place editing of environment table diff --git a/Src/parse.c b/Src/parse.c index 6e7d40e..2f81939 100644 --- a/Src/parse.c +++ b/Src/parse.c @@ -2386,7 +2386,7 @@ par_cond_2(void) s1 = tokstr; dble = (s1 && *s1 == '-' && (!n_testargs - || strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1) + || strspn(s1+1, "abcdefghknoprstuvwxzLONGS") == 1) && !s1[2]); if (tok != STRING) { /* Check first argument for [[ STRING ]] re-interpretation */ @@ -2465,7 +2465,7 @@ par_cond_double(char *a, char *b) { if (a[0] != '-' || !a[1]) COND_ERROR("parse error: condition expected: %s", a); - else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) { + else if (!a[2] && strspn(a+1, "abcdefgknoprstuvwxzhLONGS") == 1) { ecadd(WCB_COND(a[1], 0)); ecstr(b); } else { diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst index 78e644a..40e4dfb 100644 --- a/Test/C02cond.ztst +++ b/Test/C02cond.ztst @@ -269,6 +269,25 @@ F:Failures in these cases do not indicate a problem in the shell. 0:-nt shouldn't abort on non-existent files >status = 1 + str='string' empty='' + [[ -v IFS && -v str && -v empty && ! -v str[3] && ! -v not_a_variable ]] +0:-v cond + + arr=( 1 2 3 4 ) empty=() + [[ -v arr && -v arr[1,4] && -v arr[1] && -v arr[4] && -v arr[-4] && + -v arr[(i)3] && ! -v arr[(i)x] && + ! -v arr[0] && ! -v arr[5] && ! -v arr[-5] && ! -v arr[2][1] && + ! -v arr[3]extra && -v empty && ! -v empty[1] ]] +0:-v cond with array + + typeset -A assoc=( key val num 4 ) + [[ -v assoc && -v assoc[key] && -v assoc[(i)*] && -v assoc[(I)*] && + ! -v assoc[x] && ! -v assoc[key][1] ]] +0:-v cond with association + + () { [[ -v 0 && -v 1 && -v 2 && ! -v 3 ]] } arg '' +0:-v cond with positional parameters + # core dumps on failure if zmodload zsh/regex 2>/dev/null; then echo >regex_test.sh 'if [[ $# = 1 ]]; then