Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/coreutils/test.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 19  Line 19 
19   * Original copyright notice states:   * Original copyright notice states:
20   *     "This program is in the Public Domain."   *     "This program is in the Public Domain."
21   */   */
   
22  #include "libbb.h"  #include "libbb.h"
23  #include <setjmp.h>  #include <setjmp.h>
24    
# Line 29  Line 28 
28   * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL   * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL
29   * state. */   * state. */
30    
   
31  /* test(1) accepts the following grammar:  /* test(1) accepts the following grammar:
32   oexpr ::= aexpr | aexpr "-o" oexpr ;   oexpr ::= aexpr | aexpr "-o" oexpr ;
33   aexpr ::= nexpr | nexpr "-a" aexpr ;   aexpr ::= nexpr | nexpr "-a" aexpr ;
# Line 47  Line 45 
45   operand ::= <any legal UNIX file name>   operand ::= <any legal UNIX file name>
46  */  */
47    
48    /* TODO: handle [[ expr ]] bashism bash-compatibly.
49     * [[ ]] is meant to be a "better [ ]", with less weird syntax
50     * and without the risk of variables and quoted strings misinterpreted
51     * as operators.
52     * This will require support from shells - we need to know quote status
53     * of each parameter (see below).
54     *
55     * Word splitting and pathname expansion should NOT be performed:
56     *      # a="a b"; [[ $a = "a b" ]] && echo YES
57     *      YES
58     *      # [[ /bin/m* ]] && echo YES
59     *      YES
60     *
61     * =~ should do regexp match
62     * = and == should do pattern match against right side:
63     *      # [[ *a* == bab ]] && echo YES
64     *      # [[ bab == *a* ]] && echo YES
65     *      YES
66     * != does the negated == (i.e., also with pattern matching).
67     * Pattern matching is quotation-sensitive:
68     *      # [[ bab == "b"a* ]] && echo YES
69     *      YES
70     *      # [[ bab == b"a*" ]] && echo YES
71     *
72     * Conditional operators such as -f must be unquoted literals to be recognized:
73     *      # [[ -e /bin ]] && echo YES
74     *      YES
75     *      # [[ '-e' /bin ]] && echo YES
76     *      bash: conditional binary operator expected...
77     *      # A='-e'; [[ $A /bin ]] && echo YES
78     *      bash: conditional binary operator expected...
79     *
80     * || and && should work as -o and -a work in [ ]
81     * -a and -o aren't recognized (&& and || are to be used instead)
82     * ( and ) do not need to be quoted unlike in [ ]:
83     *      # [[ ( abc ) && '' ]] && echo YES
84     *      # [[ ( abc ) || '' ]] && echo YES
85     *      YES
86     *      # [[ ( abc ) -o '' ]] && echo YES
87     *      bash: syntax error in conditional expression...
88     *
89     * Apart from the above, [[ expr ]] should work as [ expr ]
90     */
91    
92  #define TEST_DEBUG 0  #define TEST_DEBUG 0
93    
94  enum token {  enum token {
95   EOI,   EOI,
96   FILRD,  
97     FILRD, /* file access */
98   FILWR,   FILWR,
99   FILEX,   FILEX,
100    
101   FILEXIST,   FILEXIST,
102   FILREG,  
103     FILREG, /* file type */
104   FILDIR,   FILDIR,
105   FILCDEV,   FILCDEV,
106   FILBDEV,   FILBDEV,
107   FILFIFO,   FILFIFO,
108   FILSOCK,   FILSOCK,
109    
110   FILSYM,   FILSYM,
111   FILGZ,   FILGZ,
112   FILTT,   FILTT,
113   FILSUID,  
114     FILSUID, /* file bit */
115   FILSGID,   FILSGID,
116   FILSTCK,   FILSTCK,
117   FILNT,  
118     FILNT, /* file ops */
119   FILOT,   FILOT,
120   FILEQ,   FILEQ,
121    
122   FILUID,   FILUID,
123   FILGID,   FILGID,
124   STREZ,  
125     STREZ, /* str ops */
126   STRNZ,   STRNZ,
127   STREQ,   STREQ,
128   STRNE,   STRNE,
129   STRLT,   STRLT,
130   STRGT,   STRGT,
131   INTEQ,  
132     INTEQ, /* int ops */
133   INTNE,   INTNE,
134   INTGE,   INTGE,
135   INTGT,   INTGT,
136   INTLE,   INTLE,
137   INTLT,   INTLT,
138    
139   UNOT,   UNOT,
140   BAND,   BAND,
141   BOR,   BOR,
# Line 170  static const char *const TOKSTR[] = { Line 222  static const char *const TOKSTR[] = {
222  #define unnest_msg_and_return(expr, ...) return expr  #define unnest_msg_and_return(expr, ...) return expr
223  #endif  #endif
224    
225  enum token_types {  enum {
226   UNOP,   UNOP,
227   BINOP,   BINOP,
228   BUNOP,   BUNOP,
# Line 179  enum token_types { Line 231  enum token_types {
231  };  };
232    
233  struct operator_t {  struct operator_t {
  char op_text[4];  
234   unsigned char op_num, op_type;   unsigned char op_num, op_type;
235  };  };
236    
237  static const struct operator_t ops[] = {  static const struct operator_t ops_table[] = {
238   { "-r", FILRD   , UNOP   },   { /* "-r" */ FILRD   , UNOP   },
239   { "-w", FILWR   , UNOP   },   { /* "-w" */ FILWR   , UNOP   },
240   { "-x", FILEX   , UNOP   },   { /* "-x" */ FILEX   , UNOP   },
241   { "-e", FILEXIST, UNOP   },   { /* "-e" */ FILEXIST, UNOP   },
242   { "-f", FILREG  , UNOP   },   { /* "-f" */ FILREG  , UNOP   },
243   { "-d", FILDIR  , UNOP   },   { /* "-d" */ FILDIR  , UNOP   },
244   { "-c", FILCDEV , UNOP   },   { /* "-c" */ FILCDEV , UNOP   },
245   { "-b", FILBDEV , UNOP   },   { /* "-b" */ FILBDEV , UNOP   },
246   { "-p", FILFIFO , UNOP   },   { /* "-p" */ FILFIFO , UNOP   },
247   { "-u", FILSUID , UNOP   },   { /* "-u" */ FILSUID , UNOP   },
248   { "-g", FILSGID , UNOP   },   { /* "-g" */ FILSGID , UNOP   },
249   { "-k", FILSTCK , UNOP   },   { /* "-k" */ FILSTCK , UNOP   },
250   { "-s", FILGZ   , UNOP   },   { /* "-s" */ FILGZ   , UNOP   },
251   { "-t", FILTT   , UNOP   },   { /* "-t" */ FILTT   , UNOP   },
252   { "-z", STREZ   , UNOP   },   { /* "-z" */ STREZ   , UNOP   },
253   { "-n", STRNZ   , UNOP   },   { /* "-n" */ STRNZ   , UNOP   },
254   { "-h", FILSYM  , UNOP   },    /* for backwards compat */   { /* "-h" */ FILSYM  , UNOP   },    /* for backwards compat */
255    
256   { "-O" , FILUID , UNOP   },   { /* "-O" */ FILUID  , UNOP   },
257   { "-G" , FILGID , UNOP   },   { /* "-G" */ FILGID  , UNOP   },
258   { "-L" , FILSYM , UNOP   },   { /* "-L" */ FILSYM  , UNOP   },
259   { "-S" , FILSOCK, UNOP   },   { /* "-S" */ FILSOCK , UNOP   },
260   { "="  , STREQ  , BINOP  },   { /* "="  */ STREQ   , BINOP  },
261   { "==" , STREQ  , BINOP  },   { /* "==" */ STREQ   , BINOP  },
262   { "!=" , STRNE  , BINOP  },   { /* "!=" */ STRNE   , BINOP  },
263   { "<"  , STRLT  , BINOP  },   { /* "<"  */ STRLT   , BINOP  },
264   { ">"  , STRGT  , BINOP  },   { /* ">"  */ STRGT   , BINOP  },
265   { "-eq", INTEQ  , BINOP  },   { /* "-eq"*/ INTEQ   , BINOP  },
266   { "-ne", INTNE  , BINOP  },   { /* "-ne"*/ INTNE   , BINOP  },
267   { "-ge", INTGE  , BINOP  },   { /* "-ge"*/ INTGE   , BINOP  },
268   { "-gt", INTGT  , BINOP  },   { /* "-gt"*/ INTGT   , BINOP  },
269   { "-le", INTLE  , BINOP  },   { /* "-le"*/ INTLE   , BINOP  },
270   { "-lt", INTLT  , BINOP  },   { /* "-lt"*/ INTLT   , BINOP  },
271   { "-nt", FILNT  , BINOP  },   { /* "-nt"*/ FILNT   , BINOP  },
272   { "-ot", FILOT  , BINOP  },   { /* "-ot"*/ FILOT   , BINOP  },
273   { "-ef", FILEQ  , BINOP  },   { /* "-ef"*/ FILEQ   , BINOP  },
274   { "!"  , UNOT   , BUNOP  },   { /* "!"  */ UNOT    , BUNOP  },
275   { "-a" , BAND   , BBINOP },   { /* "-a" */ BAND    , BBINOP },
276   { "-o" , BOR    , BBINOP },   { /* "-o" */ BOR     , BBINOP },
277   { "("  , LPAREN , PAREN  },   { /* "("  */ LPAREN  , PAREN  },
278   { ")"  , RPAREN , PAREN  },   { /* ")"  */ RPAREN  , PAREN  },
279  };  };
280    /* Please keep these two tables in sync */
281    static const char ops_texts[] ALIGN1 =
282     "-r"  "\0"
283     "-w"  "\0"
284     "-x"  "\0"
285     "-e"  "\0"
286     "-f"  "\0"
287     "-d"  "\0"
288     "-c"  "\0"
289     "-b"  "\0"
290     "-p"  "\0"
291     "-u"  "\0"
292     "-g"  "\0"
293     "-k"  "\0"
294     "-s"  "\0"
295     "-t"  "\0"
296     "-z"  "\0"
297     "-n"  "\0"
298     "-h"  "\0"
299    
300     "-O"  "\0"
301     "-G"  "\0"
302     "-L"  "\0"
303     "-S"  "\0"
304     "="   "\0"
305     "=="  "\0"
306     "!="  "\0"
307     "<"   "\0"
308     ">"   "\0"
309     "-eq" "\0"
310     "-ne" "\0"
311     "-ge" "\0"
312     "-gt" "\0"
313     "-le" "\0"
314     "-lt" "\0"
315     "-nt" "\0"
316     "-ot" "\0"
317     "-ef" "\0"
318     "!"   "\0"
319     "-a"  "\0"
320     "-o"  "\0"
321     "("   "\0"
322     ")"   "\0"
323    ;
324    
325    
326  #if ENABLE_FEATURE_TEST_64  #if ENABLE_FEATURE_TEST_64
# Line 332  static int equalf(const char *f1, const Line 427  static int equalf(const char *f1, const
427  */  */
428    
429    
430  static enum token check_operator(char *s)  static enum token check_operator(const char *s)
431  {  {
432   static const struct operator_t no_op = {   static const struct operator_t no_op = {
433   .op_num = -1,   .op_num = -1,
434   .op_type = -1   .op_type = -1
435   };   };
436   const struct operator_t *op;   int n;
437    
438   last_operator = &no_op;   last_operator = &no_op;
439   if (s == NULL) {   if (s == NULL)
440   return EOI;   return EOI;
441   }   n = index_in_strings(ops_texts, s);
442     if (n < 0)
443   op = ops;   return OPERAND;
444   do {   last_operator = &ops_table[n];
445   if (strcmp(s, op->op_text) == 0) {   return ops_table[n].op_num;
  last_operator = op;  
  return op->op_num;  
  }  
  op++;  
  } while (op < ops + ARRAY_SIZE(ops));  
   
  return OPERAND;  
446  }  }
447    
448    
# Line 370  static int binop(void) Line 458  static int binop(void)
458    
459   opnd2 = *++args;   opnd2 = *++args;
460   if (opnd2 == NULL)   if (opnd2 == NULL)
461   syntax(op->op_text, "argument expected");   syntax(args[-1], "argument expected");
462    
463   if (is_int_op(op->op_num)) {   if (is_int_op(op->op_num)) {
464   val1 = getn(opnd1);   val1 = getn(opnd1);
# Line 385  static int binop(void) Line 473  static int binop(void)
473   return val1 >  val2;   return val1 >  val2;
474   if (op->op_num == INTLE)   if (op->op_num == INTLE)
475   return val1 <= val2;   return val1 <= val2;
476   if (op->op_num == INTLT)   /*if (op->op_num == INTLT)*/
477   return val1 <  val2;   return val1 <  val2;
478   }   }
479   if (is_str_op(op->op_num)) {   if (is_str_op(op->op_num)) {
480   val1 = strcmp(opnd1, opnd2);   val1 = strcmp(opnd1, opnd2);
# Line 396  static int binop(void) Line 484  static int binop(void)
484   return val1 != 0;   return val1 != 0;
485   if (op->op_num == STRLT)   if (op->op_num == STRLT)
486   return val1 < 0;   return val1 < 0;
487   if (op->op_num == STRGT)   /*if (op->op_num == STRGT)*/
488   return val1 > 0;   return val1 > 0;
489   }   }
490   /* We are sure that these three are by now the only binops we didn't check   /* We are sure that these three are by now the only binops we didn't check
491   * yet, so we do not check if the class is correct:   * yet, so we do not check if the class is correct:
# Line 412  static int binop(void) Line 500  static int binop(void)
500   return b1.st_mtime > b2.st_mtime;   return b1.st_mtime > b2.st_mtime;
501   if (op->op_num == FILOT)   if (op->op_num == FILOT)
502   return b1.st_mtime < b2.st_mtime;   return b1.st_mtime < b2.st_mtime;
503   if (op->op_num == FILEQ)   /*if (op->op_num == FILEQ)*/
504   return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;   return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino;
505   }   }
506   return 1; /* NOTREACHED */   /*return 1; - NOTREACHED */
507  }  }
508    
509    
510  static void initialize_group_array(void)  static void initialize_group_array(void)
511  {  {
512   ngroups = getgroups(0, NULL);   int n;
513   if (ngroups > 0) {  
514     /* getgroups may be expensive, try to use it only once */
515     ngroups = 32;
516     do {
517   /* FIXME: ash tries so hard to not die on OOM,   /* FIXME: ash tries so hard to not die on OOM,
518   * and we spoil it with just one xrealloc here */   * and we spoil it with just one xrealloc here */
519   /* We realloc, because test_main can be entered repeatedly by shell.   /* We realloc, because test_main can be entered repeatedly by shell.
520   * Testcase (ash): 'while true; do test -x some_file; done'   * Testcase (ash): 'while true; do test -x some_file; done'
521   * and watch top. (some_file must have owner != you) */   * and watch top. (some_file must have owner != you) */
522   group_array = xrealloc(group_array, ngroups * sizeof(gid_t));   n = ngroups;
523   getgroups(ngroups, group_array);   group_array = xrealloc(group_array, n * sizeof(gid_t));
524   }   ngroups = getgroups(n, group_array);
525     } while (ngroups > n);
526  }  }
527    
528    
# Line 571  static number_t nexpr(enum token n) Line 663  static number_t nexpr(enum token n)
663    
664   nest_msg(">nexpr(%s)\n", TOKSTR[n]);   nest_msg(">nexpr(%s)\n", TOKSTR[n]);
665   if (n == UNOT) {   if (n == UNOT) {
666   res = !nexpr(check_operator(*++args));   n = check_operator(*++args);
667     if (n == EOI) {
668     /* special case: [ ! ], [ a -a ! ] are valid */
669     /* IOW, "! ARG" may miss ARG */
670     unnest_msg("<nexpr:1 (!EOI)\n");
671     return 1;
672     }
673     res = !nexpr(n);
674   unnest_msg("<nexpr:%lld\n", res);   unnest_msg("<nexpr:%lld\n", res);
675   return res;   return res;
676   }   }
# Line 717  int test_main(int argc, char **argv) Line 816  int test_main(int argc, char **argv)
816   * isn't likely in the case of a shell.  paranoia   * isn't likely in the case of a shell.  paranoia
817   * prevails...   * prevails...
818   */   */
819   ngroups = 0;   /*ngroups = 0; - done by INIT_S() */
820    
821   //argc--;   //argc--;
822   argv++;   argv++;
# Line 742  int test_main(int argc, char **argv) Line 841  int test_main(int argc, char **argv)
841   check_operator(argv[1]);   check_operator(argv[1]);
842   if (last_operator->op_type == BINOP) {   if (last_operator->op_type == BINOP) {
843   /* "test [!] arg1 <binary_op> arg2" */   /* "test [!] arg1 <binary_op> arg2" */
844   args = &argv[0];   args = argv;
845   res = (binop() == 0);   res = (binop() == 0);
846   goto ret;   goto ret;
847   }   }
# Line 755  int test_main(int argc, char **argv) Line 854  int test_main(int argc, char **argv)
854   argv--;   argv--;
855   }   }
856  #endif  #endif
857   args = &argv[0];   args = argv;
858   res = !oexpr(check_operator(*args));   res = !oexpr(check_operator(*args));
859    
860   if (*args != NULL && *++args != NULL) {   if (*args != NULL && *++args != NULL) {

Legend:
Removed from v.983  
changed lines
  Added in v.984