From 4df1e776cd079357f877f0d491a80a234f670452 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Sun, 13 Jul 2008 19:20:10 +0800 Subject: [BUILTIN] Fixed 3,4-argument cases for test per POSIX ----- Forwarded message from Gerrit Pape ----- Subject: Bug#455828: dash: 4-argument test "test \( ! -e \)" yields an error Date: Fri, 28 Dec 2007 08:53:29 +0000 From: Gerrit Pape To: Vincent Lefevre , 455828@bugs.debian.org On Thu, Dec 27, 2007 at 06:23:20PM +0100, Vincent Lefevre wrote: > On 2007-12-27 16:00:06 +0000, Gerrit Pape wrote: > > On Wed, Dec 12, 2007 at 02:18:47AM +0100, Vincent Lefevre wrote: > > > According to POSIX[*], "test \( ! -e \)" is a 4-argument test and is > > > here equivalent to "test ! -e". But dash (like ksh93 and bash) yields > > > an error: > > > > > > $ test \( ! -e \) || echo $? > > > test: 1: closing paren expected > > > 2 > > > $ test ! -e || echo $? > > > 1 > > > > Hi Vincent, > > > > the -e switch to test takes an argument, a pathname. > > According to POSIX, in both above examples, "-e" is *not* a switch, > just a string. > > test \( ! -e \) > > means: return true if the string "-e" is empty, otherwhise return false. > The error in dash is that it incorrectly thinks that "-e" is a switch in > this context. I see, you're right. Thanks, Gerrit. ----- End forwarded message ----- This patch hard-codes the 3,4-argument cases in the way required by POSIX. Signed-off-by: Herbert Xu --- src/bltin/test.c | 81 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 57 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/bltin/test.c b/src/bltin/test.c index bc8b175..89d8d86 100644 --- a/src/bltin/test.c +++ b/src/bltin/test.c @@ -155,9 +155,23 @@ static inline intmax_t getn(const char *s) return atomax10(s); } +static const struct t_op *getop(const char *s) +{ + const struct t_op *op; + + for (op = ops; op->op_text; op++) { + if (strcmp(s, op->op_text) == 0) + return op; + } + + return NULL; +} + int testcmd(int argc, char **argv) { + const struct t_op *op; + enum token n; int res; if (*argv[0] == '[') { @@ -166,14 +180,42 @@ testcmd(int argc, char **argv) argv[argc] = NULL; } - if (argc < 2) + argv++; + argc--; + + if (argc < 1) return 1; - t_wp = &argv[1]; - res = !oexpr(t_lex(*t_wp)); + /* + * POSIX prescriptions: he who wrote this deserves the Nobel + * peace prize. + */ + switch (argc) { + case 3: + op = getop(argv[1]); + if (op && op->op_type == BINOP) { + n = OPERAND; + goto eval; + } + /* fall through */ - if (*t_wp != NULL && *++t_wp != NULL) - syntax(*t_wp, "unexpected operator"); + case 4: + if (!strcmp(argv[0], "(") && !strcmp(argv[argc - 1], ")")) { + argv[--argc] = NULL; + argv++; + argc--; + } + } + + n = t_lex(*argv); + +eval: + t_wp = argv; + res = !oexpr(n); + argv = t_wp; + + if (argv[0] != NULL && argv[1] != NULL) + syntax(argv[0], "unexpected operator"); return res; } @@ -359,22 +401,18 @@ t_lex(char *s) { struct t_op const *op; - op = ops; - if (s == 0) { t_wp_op = (struct t_op *)0; return EOI; } - while (op->op_text) { - if (strcmp(s, op->op_text) == 0) { - if ((op->op_type == UNOP && isoperand()) || - (op->op_num == LPAREN && *(t_wp+1) == 0)) - break; - t_wp_op = op; - return op->op_num; - } - op++; + + op = getop(s); + if (op && !(op->op_type == UNOP && isoperand()) && + !(op->op_num == LPAREN && *(t_wp+1) == 0)) { + t_wp_op = op; + return op->op_num; } + t_wp_op = (struct t_op *)0; return OPERAND; } @@ -385,18 +423,13 @@ isoperand(void) struct t_op const *op; char *s, *t; - op = ops; if ((s = *(t_wp+1)) == 0) return 1; if ((t = *(t_wp+2)) == 0) return 0; - while (op->op_text) { - if (strcmp(s, op->op_text) == 0) - return op->op_type == BINOP && - (t[0] != ')' || t[1] != '\0'); - op++; - } - return 0; + + op = getop(s); + return op && op->op_type == BINOP; } static int -- cgit 1.4.1