On Sep 21, 10:01pm, da...@l8s.co.uk (David Laight) wrote: -- Subject: Re: CVS commit: src/distrib
| On Sun, Sep 20, 2009 at 05:32:17PM -0400, Christos Zoulas wrote: | > | > | Although posix defines strict rules for expressions with small | > | numbers of arguments, netbsd'd parser doesn't obey them! | > | > Really? Can you give me an example. | | See PR/34646 | | $ test ! = foo This should prolly fix it... From FreeBSD. christos Index: test.c =================================================================== RCS file: /cvsroot/src/bin/test/test.c,v retrieving revision 1.37 diff -u -u -r1.37 test.c --- test.c 10 Sep 2008 19:00:51 -0000 1.37 +++ test.c 21 Sep 2009 22:37:06 -0000 @@ -153,8 +153,10 @@ {"z", STREZ, UNOP}, }; +static int nargc; static char **t_wp; static struct t_op const *t_wp_op; +static int parenlevel; static void syntax(const char *, const char *); static int oexpr(enum token); @@ -165,8 +167,10 @@ static int test_access(struct stat *, mode_t); static int filstat(char *, enum token); static enum token t_lex(char *); -static int isoperand(void); static long long getn(const char *); +static int isunopoperand(void); +static int islparenoperand(void); +static int isrparenoperand(void); static int newerf(const char *, const char *); static int olderf(const char *, const char *); static int equalf(const char *, const char *); @@ -200,6 +204,8 @@ } #endif +#define GETARG (nargc > 0 ? (--nargc, *++t_wp) : NULL) + #ifdef SHELL int testcmd(int, char **); @@ -228,13 +234,21 @@ argv[argc] = NULL; } - if (argc < 2) + if (--argc <= 0) return 1; + nargc = argc - 1; t_wp = &argv[1]; - res = !oexpr(t_lex(*t_wp)); + parenlevel = 0; + if (nargc == 4 && strcmp(*t_wp, "!") == 0) { + /* Things like ! "" -o x do not fit in the normal grammar. */ + --nargc; + ++t_wp; + res = oexpr(t_lex(*t_wp)); + } else + res = !oexpr(t_lex(*t_wp)); - if (*t_wp != NULL && *++t_wp != NULL) + if (--nargc > 0) syntax(*t_wp, "unexpected operator"); return res; @@ -258,9 +272,10 @@ res = aexpr(n); if (*t_wp == NULL) return res; - if (t_lex(*++t_wp) == BOR) - return oexpr(t_lex(*++t_wp)) || res; + if (t_lex(GETARG) == BOR) + return oexpr(t_lex(GETARG)) || res; t_wp--; + nargc++; return res; } @@ -272,9 +287,10 @@ res = nexpr(n); if (*t_wp == NULL) return res; - if (t_lex(*++t_wp) == BAND) - return aexpr(t_lex(*++t_wp)) && res; + if (t_lex(GETARG) == BAND) + return aexpr(t_lex(GETARG)) && res; t_wp--; + nargc++; return res; } @@ -283,7 +299,7 @@ { if (n == UNOT) - return !nexpr(t_lex(*++t_wp)); + return !nexpr(t_lex(GETARG)); return primary(n); } @@ -296,30 +312,35 @@ if (n == EOI) return 0; /* missing expression */ if (n == LPAREN) { - if ((nn = t_lex(*++t_wp)) == RPAREN) + parenlevel++; + if ((nn = t_lex(GETARG)) == RPAREN) { + parenlevel--; return 0; /* missing expression */ + } res = oexpr(nn); - if (t_lex(*++t_wp) != RPAREN) + if (t_lex(GETARG) != RPAREN) syntax(NULL, "closing paren expected"); + parenlevel--; return res; } if (t_wp_op && t_wp_op->op_type == UNOP) { /* unary expression */ - if (*++t_wp == NULL) + if (--nargc == 0) syntax(t_wp_op->op_text, "argument expected"); switch (n) { case STREZ: - return strlen(*t_wp) == 0; + return strlen(*++t_wp) == 0; case STRNZ: - return strlen(*t_wp) != 0; + return strlen(*++t_wp) != 0; case FILTT: - return isatty((int)getn(*t_wp)); + return isatty((int)getn(*++t_wp)); default: - return filstat(*t_wp, n); + return filstat(*++t_wp, n); } } - if (t_lex(t_wp[1]), t_wp_op && t_wp_op->op_type == BINOP) { + if (t_lex(nargc > 0 ? t_wp[1] : NULL), t_wp_op && t_wp_op->op_type == + BINOP) { return binop(); } @@ -333,10 +354,10 @@ struct t_op const *op; opnd1 = *t_wp; - (void) t_lex(*++t_wp); + (void) t_lex(GETARG); op = t_wp_op; - if ((opnd2 = *++t_wp) == NULL) + if ((opnd2 = GETARG) == NULL) syntax(op->op_text, "argument expected"); switch (op->op_num) { @@ -639,28 +660,67 @@ } if ((op = findop(s)) != NULL) { - if (!((op->op_type == UNOP && isoperand()) || - (op->op_num == LPAREN && *(t_wp+1) == 0))) { - t_wp_op = op; - return op->op_num; - } + if (((op->op_type == UNOP || op->op_type == BUNOP) + && isunopoperand()) || + (op->op_num == LPAREN && islparenoperand()) || + (op->op_num == RPAREN && isrparenoperand())) + goto out; + t_wp_op = op; + return op->op_num; } +out: t_wp_op = NULL; return OPERAND; } static int -isoperand(void) +isunopoperand(void) +{ + struct t_op const *op; + char *s; + char *t; + + if (nargc == 1) + return 1; + s = *(t_wp + 1); + if (nargc == 2) + return parenlevel == 1 && strcmp(s, ")") == 0; + t = *(t_wp + 2); + if ((op = findop(s)) != NULL) { + return op->op_type == BINOP && + (parenlevel == 0 || t[0] != ')' || t[1] != '\0'); + } + return 0; +} + +static int +islparenoperand(void) { struct t_op const *op; - char *s, *t; + char *s; - if ((s = *(t_wp+1)) == 0) + if (nargc == 1) return 1; - if ((t = *(t_wp+2)) == 0) + s = *(t_wp + 1); + if (nargc == 2) + return parenlevel == 1 && strcmp(s, ")") == 0; + if (nargc != 3) return 0; if ((op = findop(s)) != NULL) - return op->op_type == BINOP && (t[0] != ')' || t[1] != '\0'); + return op->op_type == BINOP; + return 0; +} + +static int +isrparenoperand(void) +{ + char *s; + + if (nargc == 1) + return 0; + s = *(t_wp + 1); + if (nargc == 2) + return parenlevel == 1 && strcmp(s, ")") == 0; return 0; }