rpm2cpio: handle bz2 too; code shrink
[oweals/busybox.git] / coreutils / test.c
index ae40192a2155961a99aac01695b57679ae1edadb..c430f221015004417cce4878077431b845ae28a2 100644 (file)
@@ -19,7 +19,6 @@
  * Original copyright notice states:
  *     "This program is in the Public Domain."
  */
-
 #include "libbb.h"
 #include <setjmp.h>
 
@@ -29,7 +28,6 @@
  * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL
  * state. */
 
-
 /* test(1) accepts the following grammar:
        oexpr   ::= aexpr | aexpr "-o" oexpr ;
        aexpr   ::= nexpr | nexpr "-a" aexpr ;
        operand ::= <any legal UNIX file name>
 */
 
+/* TODO: handle [[ expr ]] bashism bash-compatibly.
+ * [[ ]] is meant to be a "better [ ]", with less weird syntax
+ * and without the risk of variables and quoted strings misinterpreted
+ * as operators.
+ * This will require support from shells - we need to know quote status
+ * of each parameter (see below).
+ *
+ * Word splitting and pathname expansion should NOT be performed:
+ *      # a="a b"; [[ $a = "a b" ]] && echo YES
+ *      YES
+ *      # [[ /bin/m* ]] && echo YES
+ *      YES
+ *
+ * =~ should do regexp match
+ * = and == should do pattern match against right side:
+ *      # [[ *a* == bab ]] && echo YES
+ *      # [[ bab == *a* ]] && echo YES
+ *      YES
+ * != does the negated == (i.e., also with pattern matching).
+ * Pattern matching is quotation-sensitive:
+ *      # [[ bab == "b"a* ]] && echo YES
+ *      YES
+ *      # [[ bab == b"a*" ]] && echo YES
+ *
+ * Conditional operators such as -f must be unquoted literals to be recognized:
+ *      # [[ -e /bin ]] && echo YES
+ *      YES
+ *      # [[ '-e' /bin ]] && echo YES
+ *      bash: conditional binary operator expected...
+ *      # A='-e'; [[ $A /bin ]] && echo YES
+ *      bash: conditional binary operator expected...
+ *
+ * || and && should work as -o and -a work in [ ]
+ * -a and -o aren't recognized (&& and || are to be used instead)
+ * ( and ) do not need to be quoted unlike in [ ]:
+ *      # [[ ( abc ) && '' ]] && echo YES
+ *      # [[ ( abc ) || '' ]] && echo YES
+ *      YES
+ *      # [[ ( abc ) -o '' ]] && echo YES
+ *      bash: syntax error in conditional expression...
+ *
+ * Apart from the above, [[ expr ]] should work as [ expr ]
+ */
+
 #define TEST_DEBUG 0
 
 enum token {
        EOI,
-       FILRD,
+
+       FILRD, /* file access */
        FILWR,
        FILEX,
+
        FILEXIST,
-       FILREG,
+
+       FILREG, /* file type */
        FILDIR,
        FILCDEV,
        FILBDEV,
        FILFIFO,
        FILSOCK,
+
        FILSYM,
        FILGZ,
        FILTT,
-       FILSUID,
+
+       FILSUID, /* file bit */
        FILSGID,
        FILSTCK,
-       FILNT,
+
+       FILNT, /* file ops */
        FILOT,
        FILEQ,
+
        FILUID,
        FILGID,
-       STREZ,
+
+       STREZ, /* str ops */
        STRNZ,
        STREQ,
        STRNE,
        STRLT,
        STRGT,
-       INTEQ,
+
+       INTEQ, /* int ops */
        INTNE,
        INTGE,
        INTGT,
        INTLE,
        INTLT,
+
        UNOT,
        BAND,
        BOR,
@@ -385,8 +437,8 @@ static int binop(void)
                        return val1 >  val2;
                if (op->op_num == INTLE)
                        return val1 <= val2;
-               if (op->op_num == INTLT)
-                       return val1 <  val2;
+               /*if (op->op_num == INTLT)*/
+               return val1 <  val2;
        }
        if (is_str_op(op->op_num)) {
                val1 = strcmp(opnd1, opnd2);
@@ -396,8 +448,8 @@ static int binop(void)
                        return val1 != 0;
                if (op->op_num == STRLT)
                        return val1 < 0;
-               if (op->op_num == STRGT)
-                       return val1 > 0;
+               /*if (op->op_num == STRGT)*/
+               return val1 > 0;
        }
        /* We are sure that these three are by now the only binops we didn't check
         * yet, so we do not check if the class is correct:
@@ -412,25 +464,29 @@ static int binop(void)
                        return b1.st_mtime > b2.st_mtime;
                if (op->op_num == FILOT)
                        return b1.st_mtime < b2.st_mtime;
-               if (op->op_num == FILEQ)
-                       return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
+               /*if (op->op_num == FILEQ)*/
+               return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
        }
-       return 1; /* NOTREACHED */
+       /*return 1; - NOTREACHED */
 }
 
 
 static void initialize_group_array(void)
 {
-       ngroups = getgroups(0, NULL);
-       if (ngroups > 0) {
+       int n;
+
+       /* getgroups may be expensive, try to use it only once */
+       ngroups = 32;
+       do {
                /* FIXME: ash tries so hard to not die on OOM,
                 * and we spoil it with just one xrealloc here */
                /* We realloc, because test_main can be entered repeatedly by shell.
                 * Testcase (ash): 'while true; do test -x some_file; done'
                 * and watch top. (some_file must have owner != you) */
-               group_array = xrealloc(group_array, ngroups * sizeof(gid_t));
-               getgroups(ngroups, group_array);
-       }
+               n = ngroups;
+               group_array = xrealloc(group_array, n * sizeof(gid_t));
+               ngroups = getgroups(n, group_array);
+       } while (ngroups > n);
 }
 
 
@@ -571,7 +627,14 @@ static number_t nexpr(enum token n)
 
        nest_msg(">nexpr(%s)\n", TOKSTR[n]);
        if (n == UNOT) {
-               res = !nexpr(check_operator(*++args));
+               n = check_operator(*++args);
+               if (n == EOI) {
+                       /* special case: [ ! ], [ a -a ! ] are valid */
+                       /* IOW, "! ARG" may miss ARG */
+                       unnest_msg("<nexpr:1 (!EOI)\n");
+                       return 1;
+               }
+               res = !nexpr(n);
                unnest_msg("<nexpr:%lld\n", res);
                return res;
        }
@@ -717,7 +780,7 @@ int test_main(int argc, char **argv)
         * isn't likely in the case of a shell.  paranoia
         * prevails...
         */
-       ngroups = 0;
+       /*ngroups = 0; - done by INIT_S() */
 
        //argc--;
        argv++;
@@ -742,7 +805,7 @@ int test_main(int argc, char **argv)
                check_operator(argv[1]);
                if (last_operator->op_type == BINOP) {
                        /* "test [!] arg1 <binary_op> arg2" */
-                       args = &argv[0];
+                       args = argv;
                        res = (binop() == 0);
                        goto ret;
                }
@@ -755,7 +818,7 @@ int test_main(int argc, char **argv)
                argv--;
        }
 #endif
-       args = &argv[0];
+       args = argv;
        res = !oexpr(check_operator(*args));
 
        if (*args != NULL && *++args != NULL) {