zsh-workers
 help / color / mirror / code / Atom feed
* test -z '(' : too many arguments
@ 2015-05-27 18:40 Martijn Dekker
  2015-05-27 20:23 ` Peter Stephenson
  0 siblings, 1 reply; 2+ messages in thread
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	[flat|nested] 2+ messages in thread

* Re: test -z '(' : too many arguments
  2015-05-27 18:40 test -z '(' : too many arguments Martijn Dekker
@ 2015-05-27 20:23 ` Peter Stephenson
  0 siblings, 0 replies; 2+ messages in thread
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	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2015-05-27 20:23 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-27 18:40 test -z '(' : too many arguments Martijn Dekker
2015-05-27 20:23 ` Peter Stephenson

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