From owner-svn-src-stable-7@FreeBSD.ORG Fri Apr 9 22:48:28 2010 Return-Path: Delivered-To: svn-src-stable-7@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 399C71065673; Fri, 9 Apr 2010 22:48:28 +0000 (UTC) (envelope-from emaste@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 26F958FC0A; Fri, 9 Apr 2010 22:48:28 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o39MmSiU090933; Fri, 9 Apr 2010 22:48:28 GMT (envelope-from emaste@svn.freebsd.org) Received: (from emaste@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o39MmSDf090930; Fri, 9 Apr 2010 22:48:28 GMT (envelope-from emaste@svn.freebsd.org) Message-Id: <201004092248.o39MmSDf090930@svn.freebsd.org> From: Ed Maste Date: Fri, 9 Apr 2010 22:48:28 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org X-SVN-Group: stable-7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r206432 - stable/7/bin/test X-BeenThere: svn-src-stable-7@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for only the 7-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Apr 2010 22:48:28 -0000 Author: emaste Date: Fri Apr 9 22:48:27 2010 New Revision: 206432 URL: http://svn.freebsd.org/changeset/base/206432 Log: MFC r192862: > Description of fields to fill in above: 76 columns --| Fix various cases with 3 or 4 parameters in test(1) to be POSIX compliant. More precisely, this gives precedence to an interpretation not using the '(', ')', '-a' and '-o' in their special meaning, if possible. For example, it is now safe to write [ "$a" = "$b" ] and assume it compares the two strings. The man page already says that test(1) works this way, so does not need to be changed. Interpretation of input with more parameters tries a bit harder to find a valid parse in some cases. Add various additional test cases to TEST.sh. PR: standards/133369 Discussed with: jilles Modified: stable/7/bin/test/TEST.sh stable/7/bin/test/test.c Directory Properties: stable/7/bin/test/ (props changed) Modified: stable/7/bin/test/TEST.sh ============================================================================== --- stable/7/bin/test/TEST.sh Fri Apr 9 21:18:46 2010 (r206431) +++ stable/7/bin/test/TEST.sh Fri Apr 9 22:48:27 2010 (r206432) @@ -133,5 +133,45 @@ t 0 '"a" -a ! ""' t 1 '""' t 0 '! ""' +t 0 '!' +t 0 '\(' +t 0 '\)' + +t 1 '\( = \)' +t 0 '\( != \)' +t 0 '\( ! \)' +t 0 '\( \( \)' +t 0 '\( \) \)' +t 0 '! = !' +t 1 '! != !' +t 1 '-n = \)' +t 0 '! != \)' +t 1 '! = a' +t 0 '! != -n' +t 0 '! -c /etc/passwd' + +t 0 '! \( = \)' +t 1 '! \( != \)' +t 1 '! = = =' +t 0 '! = = \)' +t 0 '! "" -o ""' +t 1 '! "x" -o ""' +t 1 '! "" -o "x"' +t 1 '! "x" -o "x"' +t 0 '\( -f /etc/passwd \)' +t 1 '\( ! = \)' +t 0 '\( ! "" \)' +t 1 '\( ! -e \)' + +t 0 '0 -eq 0 -a -d /' +t 0 '-s = "" -o "" = ""' +t 0 '"" = "" -o -s = ""' +t 1 '-s = "" -o -s = ""' +t 0 '-z x -o x = "#" -o x = x' +t 1 '-z y -o y = "#" -o y = x' +t 0 '0 -ne 0 -o ! -f /' +t 0 '1 -ne 0 -o ! -f /etc/passwd' +t 1 '0 -ne 0 -o ! -f /etc/passwd' + echo "" echo "Syntax errors: $ERROR Failed: $FAILED" Modified: stable/7/bin/test/test.c ============================================================================== --- stable/7/bin/test/test.c Fri Apr 9 21:18:46 2010 (r206431) +++ stable/7/bin/test/test.c Fri Apr 9 22:48:27 2010 (r206432) @@ -163,6 +163,7 @@ struct t_op { struct t_op const *t_wp_op; int nargc; char **t_wp; +int parenlevel; static int aexpr(enum token); static int binop(void); @@ -171,7 +172,9 @@ static int filstat(char *, enum token); static int getn(const char *); static intmax_t getq(const char *); static int intcmp(const char *, const char *); -static int isoperand(void); +static int isunopoperand(void); +static int islparenoperand(void); +static int isrparenoperand(void); static int newerf(const char *, const char *); static int nexpr(enum token); static int oexpr(enum token); @@ -205,7 +208,14 @@ main(int argc, char **argv) #endif nargc = argc; 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 (--nargc > 0) syntax(*t_wp, "unexpected operator"); @@ -268,12 +278,16 @@ primary(enum token n) if (n == EOI) return 0; /* missing expression */ if (n == LPAREN) { + parenlevel++; if ((nn = t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL)) == - RPAREN) + RPAREN) { + parenlevel--; return 0; /* missing expression */ + } res = oexpr(nn); if (t_lex(nargc > 0 ? (--nargc, *++t_wp) : NULL) != RPAREN) syntax(NULL, "closing paren expected"); + parenlevel--; return res; } if (t_wp_op && t_wp_op->op_type == UNOP) { @@ -410,8 +424,10 @@ t_lex(char *s) } while (op->op_text) { if (strcmp(s, op->op_text) == 0) { - if ((op->op_type == UNOP && isoperand()) || - (op->op_num == LPAREN && nargc == 1)) + if (((op->op_type == UNOP || op->op_type == BUNOP) + && isunopoperand()) || + (op->op_num == LPAREN && islparenoperand()) || + (op->op_num == RPAREN && isrparenoperand())) break; t_wp_op = op; return op->op_num; @@ -423,7 +439,7 @@ t_lex(char *s) } static int -isoperand(void) +isunopoperand(void) { struct t_op const *op = ops; char *s; @@ -431,19 +447,53 @@ isoperand(void) if (nargc == 1) return 1; - if (nargc == 2) - return 0; s = *(t_wp + 1); + if (nargc == 2) + return parenlevel == 1 && strcmp(s, ")") == 0; t = *(t_wp + 2); while (op->op_text) { if (strcmp(s, op->op_text) == 0) return op->op_type == BINOP && - (t[0] != ')' || t[1] != '\0'); + (parenlevel == 0 || t[0] != ')' || t[1] != '\0'); + op++; + } + return 0; +} + +static int +islparenoperand(void) +{ + struct t_op const *op = ops; + char *s; + + if (nargc == 1) + return 1; + s = *(t_wp + 1); + if (nargc == 2) + return parenlevel == 1 && strcmp(s, ")") == 0; + if (nargc != 3) + return 0; + while (op->op_text) { + if (strcmp(s, op->op_text) == 0) + return op->op_type == BINOP; op++; } 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; +} + /* atoi with error detection */ static int getn(const char *s)