zsh-workers
 help / color / mirror / code / Atom feed
* Builtin test and parsing of conditionals
@ 2013-09-04 16:15 Bart Schaefer
  2013-09-04 16:31 ` Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2013-09-04 16:15 UTC (permalink / raw)
  To: zsh-workers

According to some discussion on the austin-group (POSIX) mailing list,
the following:

	test ! -a !
	test ! -o !
	test ! = !

should all be parsed as comparing the string "!" to the string "!", but
zsh gets this right only in the last case.

This is especially annoying because

	test ! -f !

should be interpreted as the negation of the unary file-exists operator.

This is probably complicated by the different meanings of -a and -o in
[[ ... ]] as opposed to "test" because the same parser is used.

Furthermore:

	test ! = -o a

should be parsed as the negation of the comparison between the strings "="
and "a", implying that zsh also gets this wrong:

	test ! = = =

which should return false (negation of (equal is the same string as equal)),
rather than give a parse error as zsh does.  (Zsh does get

	test = = =

right.)

Apparently the only way to do this correctly is to examine both argv[1] and
the number of arguments, and skip to argv[2] for recursive descent parsing
when argv[1] is "!" and there are four arguments.  (As already mentioned in
the zsh manual, what to do with more than four arguments in the absence of
explicit parens is unclear [unspecified?].)


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-04 16:15 Builtin test and parsing of conditionals Bart Schaefer
@ 2013-09-04 16:31 ` Peter Stephenson
  2013-09-04 17:39   ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2013-09-04 16:31 UTC (permalink / raw)
  To: zsh-workers

On Wed, 04 Sep 2013 09:15:03 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> According to some discussion on the austin-group (POSIX) mailing list,
> the following:
> 
> 	test ! -a !
> 	test ! -o !
> 	test ! = !
> 
> should all be parsed as comparing the string "!" to the string "!", but
> zsh gets this right only in the last case.

I don't understand that.  -a means "and" and -o means "or", unless
they're being interpreted as strings, but I don't see how that could be
if ! is supposed to be interpreted as a string.   So where does the
implicit comparison come from?  If -a were taken as high precedence you
might read it as

test -n ! -a n !
test -n ! -a n !

which is how

test foo -a bar
test foo -o bar

are interpreted, which you can see by

test foo -a '' # false
test foo -o '' # true

... same if you omit the ''.

(Outside our control, but I imagine people aren't daft enough to rely on
this sort of behaviour in new scripts...?)

pws


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-04 16:31 ` Peter Stephenson
@ 2013-09-04 17:39   ` Bart Schaefer
  2013-09-04 19:09     ` Peter Stephenson
  2013-09-04 20:15     ` Chet Ramey
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Schaefer @ 2013-09-04 17:39 UTC (permalink / raw)
  To: zsh-workers

On Sep 4,  5:31pm, Peter Stephenson wrote:
} Subject: Re: Builtin test and parsing of conditionals
}
} On Wed, 04 Sep 2013 09:15:03 -0700
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > According to some discussion on the austin-group (POSIX) mailing list,
} > the following:
} > 
} > 	test ! -a !
} > 	test ! -o !
} > 	test ! = !
} > 
} > should all be parsed as comparing the string "!" to the string "!", but
} > zsh gets this right only in the last case.
} 
} I don't understand that.  -a means "and" and -o means "or", unless
} they're being interpreted as strings, but I don't see how that could be
} if ! is supposed to be interpreted as a string.

Sorry, perhaps I should have been clearer:  "! -a !" means to compare the
truth value "!" to the truth value of "!".  But "truth value" in "test"
is the same as "non-empty string" (true) and "empty string" (false) [not
0 or 1 as numeric values], so the -a operator is still comparing two
strings.

The point being that "!" should be parsed as a string, not as a negation
operator, in the three-argument case.

} So where does the
} implicit comparison come from?  If -a were taken as high precedence you
} might read it as
} 
} test -n ! -a n !
} test -n ! -a n !

Presuming you mean -a -n there, this is exactly how the austin-group
thread claims it should be interpreted, and is reportedly how ksh and
bash and GNU /usr/bin/test all interpret it.

} (Outside our control, but I imagine people aren't daft enough to rely on
} this sort of behaviour in new scripts...?)

I would hope so, but ...


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-04 17:39   ` Bart Schaefer
@ 2013-09-04 19:09     ` Peter Stephenson
  2013-09-05 14:25       ` Bart Schaefer
  2013-09-04 20:15     ` Chet Ramey
  1 sibling, 1 reply; 7+ messages in thread
From: Peter Stephenson @ 2013-09-04 19:09 UTC (permalink / raw)
  To: zsh-workers

On Wed, 04 Sep 2013 10:39:40 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> On Sep 4,  5:31pm, Peter Stephenson wrote:
> } On Wed, 04 Sep 2013 09:15:03 -0700
> } Bart Schaefer <schaefer@brasslantern.com> wrote:
> } > According to some discussion on the austin-group (POSIX) mailing list,
> } > the following:
> } > 
> } > 	test ! -a !
> } > 	test ! -o !
> } > 	test ! = !
> } > 
> } > should all be parsed as comparing the string "!" to the string "!", but
> } > zsh gets this right only in the last case.
> 
> Sorry, perhaps I should have been clearer:  "! -a !" means to compare the
> truth value "!" to the truth value of "!".  But "truth value" in "test"
> is the same as "non-empty string" (true) and "empty string" (false) [not
> 0 or 1 as numeric values], so the -a operator is still comparing two
> strings.

OK, this looks straightforward enough.

diff --git a/Src/parse.c b/Src/parse.c
index 0c2a458..f0d0855 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -2088,9 +2088,17 @@ par_cond_2(void)
 	}
     }
     if (tok == BANG) {
-	condlex();
-	ecadd(WCB_COND(COND_NOT, 0));
-	return par_cond_2();
+	/*
+	 * In "test" compatibility mode, "! -a ..." and "! -o ..."
+	 * are treated as "[string] [and] ..." and "[string] [or] ...".
+	 */
+	if (!(condlex == testlex && *testargs && 
+	      (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o"))))
+	{
+	    condlex();
+	    ecadd(WCB_COND(COND_NOT, 0));
+	    return par_cond_2();
+	}
     }
     if (tok == INPAR) {
 	int r;
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 494261e..8562519 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -324,6 +324,27 @@ F:Failures in these cases do not indicate a problem in the shell.
 >	fi
 >}
 
+  weirdies=(
+    '! -a !'
+    '! -o !'
+    '! -a'
+    '! -o'
+    '! -a ! -a !'
+    '! = !'
+    '! !')
+  for w in $weirdies; do
+     eval test $w
+     print $?
+  done
+0:test compatability weirdness: treat ! as a string sometimes
+>0
+>0
+>1
+>0
+>0
+>0
+>1
+
 %clean
   # This works around a bug in rm -f in some versions of Cygwin
   chmod 644 unmodish

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


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-04 17:39   ` Bart Schaefer
  2013-09-04 19:09     ` Peter Stephenson
@ 2013-09-04 20:15     ` Chet Ramey
  1 sibling, 0 replies; 7+ messages in thread
From: Chet Ramey @ 2013-09-04 20:15 UTC (permalink / raw)
  To: Bart Schaefer; +Cc: zsh-workers, chet.ramey

On 9/4/13 1:39 PM, Bart Schaefer wrote:

> } So where does the
> } implicit comparison come from?  If -a were taken as high precedence you
> } might read it as
> } 
> } test -n ! -a n !
> } test -n ! -a n !
> 
> Presuming you mean -a -n there, this is exactly how the austin-group
> thread claims it should be interpreted, and is reportedly how ksh and
> bash and GNU /usr/bin/test all interpret it.

The rules, at least through four arguments, are well-defined.

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

-a and -o are binary primaries.

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	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-04 19:09     ` Peter Stephenson
@ 2013-09-05 14:25       ` Bart Schaefer
  2013-09-06 19:20         ` Peter Stephenson
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2013-09-05 14:25 UTC (permalink / raw)
  To: zsh-workers

On Sep 4,  8:09pm, Peter Stephenson wrote:
}
} On Wed, 04 Sep 2013 10:39:40 -0700
} Bart Schaefer <schaefer@brasslantern.com> wrote:
} > Sorry, perhaps I should have been clearer:  "! -a !" means to compare the
} > truth value "!" to the truth value of "!".
} 
} OK, this looks straightforward enough.

That's good, but it still doesn't fix the other case mentioned in my
original email:

torch% /usr/bin/test ! = -a o ; print $?
1
torch% test ! = -a o ; print $? 
test: too many arguments
1

Do you want to try to handle that in parse.c, or am I correct that peeling
off the "!" in builtin.c:bin_test [the way parens are peeled off] is the
better way to go?

Either way, the comment in builtin.c should be updated with the new URL
path to test.html that Chet was kind enough to provide.  The one that's
there now is from 2007.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: Builtin test and parsing of conditionals
  2013-09-05 14:25       ` Bart Schaefer
@ 2013-09-06 19:20         ` Peter Stephenson
  0 siblings, 0 replies; 7+ messages in thread
From: Peter Stephenson @ 2013-09-06 19:20 UTC (permalink / raw)
  To: zsh-workers

On Thu, 05 Sep 2013 07:25:45 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
> That's good, but it still doesn't fix the other case mentioned in my
> original email:
> 
> torch% /usr/bin/test ! = -a o ; print $?
> 1
> torch% test ! = -a o ; print $? 
> test: too many arguments
> 1
> 
> Do you want to try to handle that in parse.c, or am I correct that peeling
> off the "!" in builtin.c:bin_test [the way parens are peeled off] is the
> better way to go?

That seems sensible.

diff --git a/Src/builtin.c b/Src/builtin.c
index f8be4ac..c3f0169 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -5995,7 +5995,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
     char **s;
     Eprog prog;
     struct estate state;
-    int nargs;
+    int nargs, sense = 0, ret;
 
     /* if "test" was invoked as "[", it needs a matching "]" *
      * which is subsequently ignored                         */
@@ -6014,7 +6014,7 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
     /*
      * Implement some XSI extensions to POSIX here.
      * See
-     * http://www.opengroup.org/onlinepubs/009695399/utilities/test.html.
+     * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html
      */
     nargs = arrlen(argv);
     if (nargs == 3 || nargs == 4)
@@ -6023,6 +6023,10 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
 	    argv[nargs-1] = NULL;
 	    argv++;
 	}
+	if (nargs == 4 && !strcmp("!", argv[0])) {
+	    sense = 1;
+	    argv++;
+	}
     }
 
     lexsave();
@@ -6057,8 +6061,11 @@ bin_test(char *name, char **argv, UNUSED(Options ops), int func)
     state.pc = prog->prog;
     state.strs = prog->strs;
 
+    ret = evalcond(&state, name);
+    if (ret < 2 && sense)
+	ret = ! ret;
 
-    return evalcond(&state, name);
+    return ret;
 }
 
 /* display a time, provided in units of 1/60s, as minutes and seconds */
diff --git a/Test/C02cond.ztst b/Test/C02cond.ztst
index 8562519..94fca8b 100644
--- a/Test/C02cond.ztst
+++ b/Test/C02cond.ztst
@@ -331,7 +331,9 @@ F:Failures in these cases do not indicate a problem in the shell.
     '! -o'
     '! -a ! -a !'
     '! = !'
-    '! !')
+    '! !'
+    '= -a o'
+    '! = -a o')
   for w in $weirdies; do
      eval test $w
      print $?
@@ -344,6 +346,8 @@ F:Failures in these cases do not indicate a problem in the shell.
 >0
 >0
 >1
+>0
+>1
 
 %clean
   # This works around a bug in rm -f in some versions of Cygwin


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2013-09-06 19:25 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-09-04 16:15 Builtin test and parsing of conditionals Bart Schaefer
2013-09-04 16:31 ` Peter Stephenson
2013-09-04 17:39   ` Bart Schaefer
2013-09-04 19:09     ` Peter Stephenson
2013-09-05 14:25       ` Bart Schaefer
2013-09-06 19:20         ` Peter Stephenson
2013-09-04 20:15     ` Chet Ramey

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).