zsh-workers
 help / color / mirror / code / Atom feed
From: Oliver Kiddle <okiddle@yahoo.co.uk>
To: zsh-workers@zsh.org
Subject: PATCH: [[ -v varname ]]
Date: Thu, 15 Sep 2016 00:01:50 +0200	[thread overview]
Message-ID: <90414.1473890510@hydra.kiddle.eu> (raw)
In-Reply-To: <20160909085231.GA9717@chaz.gmail.com>

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


  parent reply	other threads:[~2016-09-14 22:07 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-09-05 21:27 [PATCH] Use == in expressions instead of the deprecated = Teubel György
2016-09-08  8:35 ` Peter Stephenson
2016-09-08 11:16   ` Peter Stephenson
2016-09-08 14:31     ` Stephane Chazelas
2016-09-08 15:06       ` Stephane Chazelas
2016-09-08 15:14       ` Peter Stephenson
2016-09-08 16:39         ` Mikael Magnusson
2016-09-08 18:47           ` Stephane Chazelas
2016-09-09 12:03         ` Vincent Lefevre
     [not found]           ` <CGME20160912143133eucas1p11a4e6916dd70b3ceaa163bf3bddfb007@eucas1p1.samsung.com>
2016-09-12 14:31             ` Peter Stephenson
2016-09-09  8:52       ` Stephane Chazelas
2016-09-09  9:31         ` Peter Stephenson
2016-09-09 16:00           ` Stephane Chazelas
2016-09-14 22:01         ` Oliver Kiddle [this message]
2016-09-15 10:55           ` PATCH: [[ -v varname ]] Vincent Lefevre
2016-09-16  0:36             ` Bart Schaefer
2016-09-15 11:08           ` Stephane Chazelas
2016-09-15 11:22             ` wrong "export -p" output for exported but not set variables (Was: PATCH: [[ -v varname ]]) Stephane Chazelas
2016-09-09 17:01       ` [PATCH] Use == in expressions instead of the deprecated = Christian Neukirchen
2016-09-09 18:54         ` Stephane Chazelas
2016-09-09 13:05     ` Peter Stephenson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=90414.1473890510@hydra.kiddle.eu \
    --to=okiddle@yahoo.co.uk \
    --cc=zsh-workers@zsh.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).