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)
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to