summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Kiddle <opk@zsh.org>2016-09-16 00:00:28 +0200
committerOliver Kiddle <opk@zsh.org>2016-09-16 00:00:28 +0200
commitfbafc5b509e311efee064bbd12396a2e207f3393 (patch)
tree9fdf8f236fb1d25b54079e81cf75bf05eeca0b26
parent00708285e94ce42a31fd59bbcd06d010a6d0d6ee (diff)
downloadzsh-fbafc5b509e311efee064bbd12396a2e207f3393.tar.gz
zsh-fbafc5b509e311efee064bbd12396a2e207f3393.zip
39332: support ksh's [[ -v varname ]] condition for checking if variables are set
-rw-r--r--ChangeLog4
-rw-r--r--Completion/Zsh/Context/_condition3
-rw-r--r--Doc/Zsh/cond.yo3
-rw-r--r--Src/cond.c2
-rw-r--r--Src/params.c30
-rw-r--r--Src/parse.c4
-rw-r--r--Test/C02cond.ztst19
7 files changed, 63 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 1c749ae64..f54d78ca3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2016-09-15 Oliver Kiddle <opk@zsh.org>
+ * 39332: Doc/Zsh/cond.yo, Src/cond.c, Src/params.c, Src/parse.c,
+ Completion/Zsh/Context/_condition, Test/C02cond.ztst: support
+ ksh's [[ -v varname ]] condition for checking if variables are set
+
* unposted: Src/parse.c: remove duplicated assignment
2016-09-14 Peter Stephenson <p.stephenson@samsung.com>
diff --git a/Completion/Zsh/Context/_condition b/Completion/Zsh/Context/_condition
index 6f5e601f0..0285911ac 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 474baa1ec..e08fc0d36 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 f25ebd4a3..42e9de30f 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 842b2f0d1..384c30a1a 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 d3c418184..24b8cd97f 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2385,7 +2385,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 */
@@ -2464,7 +2464,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 78e644a72..40e4dfb0b 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