diff options
author | Otto Moerbeek <otto@cvs.openbsd.org> | 2009-03-01 20:11:07 +0000 |
---|---|---|
committer | Otto Moerbeek <otto@cvs.openbsd.org> | 2009-03-01 20:11:07 +0000 |
commit | a0af60bef78801387b42663bd4a6138f1379d135 (patch) | |
tree | 688acee263f2b9d9764c4ae59b4a12a44b91afbc | |
parent | 04b853ae83225adad2e406dc2d010366587ff73b (diff) |
Fix PR #723: test(1) operator precedence inconsistent with POSIX
Make sure ksh builtin test and test(1) do not differ.
From Christiano Farina Haesbaert. ok miod@
-rw-r--r-- | bin/ksh/c_test.c | 26 | ||||
-rw-r--r-- | bin/test/test.c | 35 |
2 files changed, 46 insertions, 15 deletions
diff --git a/bin/ksh/c_test.c b/bin/ksh/c_test.c index 9e03fb0c3d3..33b2cf6a976 100644 --- a/bin/ksh/c_test.c +++ b/bin/ksh/c_test.c @@ -1,4 +1,4 @@ -/* $OpenBSD: c_test.c,v 1.17 2005/03/30 17:16:37 deraadt Exp $ */ +/* $OpenBSD: c_test.c,v 1.18 2009/03/01 20:11:06 otto Exp $ */ /* * test(1); version 7-like -- author Erik Baalbergen @@ -457,15 +457,23 @@ test_primary(Test_env *te, int do_eval) } return res; } - if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) { - /* unary expression */ - opnd1 = (*te->getopnd)(te, op, do_eval); - if (!opnd1) { - (*te->error)(te, -1, "missing argument"); - return 0; - } + /* + * Binary should have precedence over unary in this case + * so that something like test \( -f = -f \) is accepted + */ + if ((te->flags & TEF_DBRACKET) || (&te->pos.wp[1] < te->wp_end && + !test_isop(te, TM_BINOP, te->pos.wp[1]))) { + if ((op = (Test_op) (*te->isa)(te, TM_UNOP))) { + /* unary expression */ + opnd1 = (*te->getopnd)(te, op, do_eval); + if (!opnd1) { + (*te->error)(te, -1, "missing argument"); + return 0; + } - return (*te->eval)(te, op, opnd1, (const char *) 0, do_eval); + return (*te->eval)(te, op, opnd1, (const char *) 0, + do_eval); + } } opnd1 = (*te->getopnd)(te, TO_NONOP, do_eval); if (!opnd1) { diff --git a/bin/test/test.c b/bin/test/test.c index 255426d9a06..8bf5e93a7d1 100644 --- a/bin/test/test.c +++ b/bin/test/test.c @@ -1,4 +1,4 @@ -/* $OpenBSD: test.c,v 1.9 2006/04/25 04:39:04 deraadt Exp $ */ +/* $OpenBSD: test.c,v 1.10 2009/03/01 20:11:06 otto Exp $ */ /* $NetBSD: test.c,v 1.15 1995/03/21 07:04:06 cgd Exp $ */ /* @@ -12,7 +12,7 @@ */ #ifndef lint -static char rcsid[] = "$OpenBSD: test.c,v 1.9 2006/04/25 04:39:04 deraadt Exp $"; +static char rcsid[] = "$OpenBSD: test.c,v 1.10 2009/03/01 20:11:06 otto Exp $"; #endif #include <sys/types.h> @@ -143,6 +143,7 @@ char **t_wp; struct t_op const *t_wp_op; static enum token t_lex(char *); +static enum token t_lex_type(char *); static int oexpr(enum token n); static int aexpr(enum token n); static int nexpr(enum token n); @@ -260,6 +261,16 @@ primary(enum token n) syntax(NULL, "closing paren expected"); return res; } + /* + * We need this, if not binary operations with more than 4 + * arguments will always fall into unary. + */ + if(t_lex_type(t_wp[1]) == BINOP) { + t_lex(t_wp[1]); + if (t_wp_op && t_wp_op->op_type == BINOP) + return binop(); + } + if (t_wp_op && t_wp_op->op_type == UNOP) { /* unary expression */ if (*++t_wp == NULL) @@ -276,10 +287,6 @@ primary(enum token n) } } - if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { - return binop(); - } - return strlen(*t_wp) > 0; } @@ -327,6 +334,22 @@ binop(void) /* NOTREACHED */ } +static enum token +t_lex_type(char *s) +{ + struct t_op const *op = ops; + + if (s == NULL) + return -1; + + while (op->op_text) { + if (strcmp(s, op->op_text) == 0) + return op->op_type; + op++; + } + return -1; +} + static int filstat(char *nm, enum token mode) { |