summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOtto Moerbeek <otto@cvs.openbsd.org>2009-03-01 20:11:07 +0000
committerOtto Moerbeek <otto@cvs.openbsd.org>2009-03-01 20:11:07 +0000
commita0af60bef78801387b42663bd4a6138f1379d135 (patch)
tree688acee263f2b9d9764c4ae59b4a12a44b91afbc
parent04b853ae83225adad2e406dc2d010366587ff73b (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.c26
-rw-r--r--bin/test/test.c35
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)
{