home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / AP / ASH / ASH-LINU.2 / ASH-LINU / ash-linux-0.2 / bltin / test.c < prev   
Encoding:
C/C++ Source or Header  |  1993-10-04  |  7.4 KB  |  391 lines

  1. /*
  2.  * test(1); version 7-like  --  author Erik Baalbergen
  3.  * modified by Eric Gisin to be used as built-in.
  4.  * modified by Arnold Robbins to add SVR3 compatibility
  5.  * (-x -c -b -p -u -g -k) plus Korn's -L -nt -ot -ef and new -S (socket).
  6.  */
  7.  
  8. static char *RCSid = "$Id: c_test.c,v 3.3 89/03/27 15:47:25 egisin Exp $";
  9.  
  10. #include <stddef.h>
  11. /*#include <string.h>*/
  12. #include <signal.h>
  13. #include <errno.h>
  14. #include <setjmp.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include "bltin.h"
  18.  
  19. /* test(1) accepts the following grammar:
  20.     oexpr    ::= aexpr | aexpr "-o" oexpr ;
  21.     aexpr    ::= nexpr | nexpr "-a" aexpr ;
  22.     nexpr    ::= primary ! "!" primary
  23.     primary    ::= unary-operator operand
  24.         | operand binary-operator operand
  25.         | operand
  26.         | "(" oexpr ")"
  27.         ;
  28.     unary-operator ::= "-r"|"-w"|"-x"|"-f"|"-d"|"-c"|"-b"|"-p"|
  29.         "-u"|"-g"|"-k"|"-s"|"-t"|"-z"|"-n"|"-o"|"-O"|"-G"|"-L"|"-S";
  30.  
  31.     binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt"|
  32.             "-nt"|"-ot"|"-ef";
  33.     operand ::= <any legal UNIX file name>
  34. */
  35.  
  36. #define    evaluate(x)    getn(x)
  37. #define    errorf        error
  38.  
  39. #define EOI    0
  40. #define FILRD    1
  41. #define FILWR    2
  42. #define FILREG    3
  43. #define FILID    4
  44. #define FILGZ    5
  45. #define FILTT    6
  46. #define STZER    7
  47. #define STNZE    8
  48. #define STEQL    9
  49. #define STNEQ    10
  50. #define INTEQ    11
  51. #define INTNE    12
  52. #define INTGE    13
  53. #define INTGT    14
  54. #define INTLE    15
  55. #define INTLT    16
  56. #define UNOT    17
  57. #define BAND    18
  58. #define BOR    19
  59. #define LPAREN    20
  60. #define RPAREN    21
  61. #define OPERAND    22
  62. #define FILEX    23
  63. #define FILCDEV    24
  64. #define FILBDEV    25
  65. #define FILFIFO    26
  66. #define FILSETU    27
  67. #define FILSETG    28
  68. #define FILSTCK    29
  69. #define FILSYM    30
  70. #define FILNT    31
  71. #define FILOT    32
  72. #define FILEQ    33
  73. #define FILSOCK    34
  74. #define    FILUID    35
  75. #define    FILGID    36
  76. #define    OPTION    37
  77.  
  78. #define UNOP    1
  79. #define BINOP    2
  80. #define BUNOP    3
  81. #define BBINOP    4
  82. #define PAREN    5
  83.  
  84. struct t_op {
  85.     char *op_text;
  86.     short op_num, op_type;
  87. } const ops [] = {
  88.     {"-r",    FILRD,    UNOP},
  89.     {"-w",    FILWR,    UNOP},
  90.     {"-x",    FILEX,    UNOP},
  91.     {"-f",    FILREG,    UNOP},
  92.     {"-d",    FILID,    UNOP},
  93.     {"-c",    FILCDEV,UNOP},
  94.     {"-b",    FILBDEV,UNOP},
  95.     {"-p",    FILFIFO,UNOP},
  96.     {"-u",    FILSETU,UNOP},
  97.     {"-g",    FILSETG,UNOP},
  98.     {"-k",    FILSTCK,UNOP},
  99.     {"-s",    FILGZ,    UNOP},
  100.     {"-t",    FILTT,    UNOP},
  101.     {"-z",    STZER,    UNOP},
  102.     {"-n",    STNZE,    UNOP},
  103. #if 0                /* conficts with binary -o */
  104.     {"-o",    OPTION,    UNOP},
  105. #endif
  106.     {"-U",    FILUID,    UNOP},
  107.     {"-G",    FILGID,    UNOP},
  108.     {"-L",    FILSYM,    UNOP},
  109.     {"-S",    FILSOCK,UNOP},
  110.     {"=",    STEQL,    BINOP},
  111.     {"!=",    STNEQ,    BINOP},
  112.     {"-eq",    INTEQ,    BINOP},
  113.     {"-ne",    INTNE,    BINOP},
  114.     {"-ge",    INTGE,    BINOP},
  115.     {"-gt",    INTGT,    BINOP},
  116.     {"-le",    INTLE,    BINOP},
  117.     {"-lt",    INTLT,    BINOP},
  118.     {"-nt",    FILNT,    BINOP},
  119.     {"-ot",    FILOT,    BINOP},
  120.     {"-ef",    FILEQ,    BINOP},
  121.     {"!",    UNOT,    BUNOP},
  122.     {"-a",    BAND,    BBINOP},
  123.     {"-o",    BOR,    BBINOP},
  124.     {"(",    LPAREN,    PAREN},
  125.     {")",    RPAREN,    PAREN},
  126.     {0,    0,    0}
  127. };
  128.  
  129. char **t_wp;
  130. struct t_op const *t_wp_op;
  131.  
  132. static void syntax();
  133.  
  134. int
  135. testcmd(argc, wp)
  136.     char **wp;
  137. {
  138.     int    res;
  139.  
  140.     t_wp = wp+1;
  141.     if (strcmp(wp[0], "[") == 0) {
  142.         while (*wp != NULL)
  143.             wp++;
  144.         if (strcmp(*--wp, "]") != 0)
  145.             errorf("[: missing ]");
  146.         *wp = NULL;
  147.     }
  148.     res = *t_wp == NULL || !oexpr(t_lex(*t_wp));
  149.  
  150.     if (*t_wp != NULL && *++t_wp != NULL)
  151.         syntax(*t_wp, "unknown operand");
  152.  
  153.     return res;
  154. }
  155.  
  156. static void
  157. syntax(op, msg)
  158.     char    *op;
  159.     char    *msg;
  160. {
  161.     if (op && *op)
  162.         errorf("%s: %s", op, msg);
  163.     else
  164.         errorf("%s", msg);
  165. }
  166.  
  167. oexpr(n)
  168. {
  169.     int res;
  170.  
  171.     res = aexpr(n);
  172.     if (t_lex(*++t_wp) == BOR)
  173.         return oexpr(t_lex(*++t_wp)) || res;
  174.     t_wp--;
  175.     return res;
  176. }
  177.  
  178. aexpr(n)
  179. {
  180.     int res;
  181.  
  182.     res = nexpr(n);
  183.     if (t_lex(*++t_wp) == BAND)
  184.         return aexpr(t_lex(*++t_wp)) && res;
  185.     t_wp--;
  186.     return res;
  187. }
  188.  
  189. nexpr(n)
  190.     int n;            /* token */
  191. {
  192.     if (n == UNOT)
  193.         return !nexpr(t_lex(*++t_wp));
  194.     return primary(n);
  195. }
  196.  
  197. primary(n)
  198.     int n;            /* token */
  199. {
  200.     register char *opnd1, *opnd2;
  201.     int res;
  202.  
  203.     if (n == EOI)
  204.         syntax(NULL, "argument expected");
  205.     if (n == LPAREN) {
  206.         res = oexpr(t_lex(*++t_wp));
  207.         if (t_lex(*++t_wp) != RPAREN)
  208.             syntax(NULL, "closing paren expected");
  209.         return res;
  210.     }
  211.     if (t_wp_op && t_wp_op->op_type == UNOP) {
  212.         /* unary expression */
  213.         if (*++t_wp == NULL && n != FILTT)
  214.             syntax(t_wp_op->op_text, "argument expected");
  215.         switch (n) {
  216.           /**
  217.           case OPTION:
  218.             return flag[option(*t_wp)];
  219.             **/
  220.           case STZER:
  221.             return strlen(*t_wp) == 0;
  222.           case STNZE:
  223.             return strlen(*t_wp) != 0;
  224.           case FILTT:
  225.             if (**t_wp < '0' || **t_wp > '9')
  226.                 return filstat("0", n);
  227.           default:    /* all other FIL* */
  228.             return filstat(*t_wp, n);
  229.         }
  230.     }
  231.     opnd1 = *t_wp;
  232.     (void) t_lex(*++t_wp);
  233.     if (t_wp_op && t_wp_op->op_type == BINOP) {
  234.         struct t_op const *op = t_wp_op;
  235.  
  236.         if ((opnd2 = *++t_wp) == (char *)0)
  237.             syntax(op->op_text, "argument expected");
  238.         
  239.         switch (op->op_num) {
  240.         case STEQL:
  241.             return strcmp(opnd1, opnd2) == 0;
  242.         case STNEQ:
  243.             return strcmp(opnd1, opnd2) != 0;
  244.         case INTEQ:
  245.             return evaluate(opnd1) == evaluate(opnd2);
  246.         case INTNE:
  247.             return evaluate(opnd1) != evaluate(opnd2);
  248.         case INTGE:
  249.             return evaluate(opnd1) >= evaluate(opnd2);
  250.         case INTGT:
  251.             return evaluate(opnd1) > evaluate(opnd2);
  252.         case INTLE:
  253.             return evaluate(opnd1) <= evaluate(opnd2);
  254.         case INTLT:
  255.             return evaluate(opnd1) < evaluate(opnd2);
  256.         case FILNT:
  257.             return newerf (opnd1, opnd2);
  258.         case FILOT:
  259.             return olderf (opnd1, opnd2);
  260.         case FILEQ:
  261.             return equalf (opnd1, opnd2);
  262.         }
  263.     }
  264.     t_wp--;
  265.     return strlen(opnd1) > 0;
  266. }
  267.  
  268. filstat(nm, mode)
  269.     char *nm;
  270. {
  271.     struct stat s;
  272.     
  273.     switch (mode) {
  274.     case FILRD:
  275.         return access(nm, 4) == 0;
  276.     case FILWR:
  277.         return access(nm, 2) == 0;
  278.     case FILEX:
  279.         return access(nm, 1) == 0;
  280.     case FILREG:
  281.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFREG;
  282.     case FILID:
  283.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFDIR;
  284.     case FILCDEV:
  285.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFCHR;
  286.     case FILBDEV:
  287.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFBLK;
  288.     case FILFIFO:
  289. #ifdef S_IFIFO
  290.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFIFO;
  291. #else
  292.         return 0;
  293. #endif
  294.     case FILSETU:
  295.         return stat(nm, &s) == 0 && (s.st_mode & S_ISUID) == S_ISUID;
  296.     case FILSETG:
  297.         return stat(nm, &s) == 0 && (s.st_mode & S_ISGID) == S_ISGID;
  298.     case FILSTCK:
  299.         return stat(nm, &s) == 0 && (s.st_mode & S_ISVTX) == S_ISVTX;
  300.     case FILGZ:
  301.         return stat(nm, &s) == 0 && s.st_size > 0L;
  302.     case FILTT:
  303.         return isatty(getn(nm));
  304.       case FILUID:
  305.         return stat(nm, &s) == 0 && s.st_uid == geteuid();
  306.       case FILGID:
  307.         return stat(nm, &s) == 0 && s.st_gid == getegid();
  308. #ifdef S_IFLNK
  309.     case FILSYM:
  310.         return lstat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFLNK;
  311. #endif
  312. #ifdef S_IFSOCK
  313.     case FILSOCK:
  314.         return stat(nm, &s) == 0 && (s.st_mode & S_IFMT) == S_IFSOCK;
  315. #endif
  316.       default:
  317.         return 1;
  318.     }
  319. }
  320.  
  321. int
  322. t_lex(s)
  323.     register char *s;
  324. {
  325.     register struct t_op const *op = ops;
  326.  
  327.     if (s == 0) {
  328.         t_wp_op = (struct t_op *)0;
  329.         return EOI;
  330.     }
  331.     while (op->op_text) {
  332.         if (strcmp(s, op->op_text) == 0) {
  333.             t_wp_op = op;
  334.             return op->op_num;
  335.         }
  336.         op++;
  337.     }
  338.     t_wp_op = (struct t_op *)0;
  339.     return OPERAND;
  340. }
  341.  
  342. newerf (f1, f2)
  343. char *f1, *f2;
  344. {
  345.     struct stat b1, b2;
  346.  
  347.     return (stat (f1, &b1) == 0 &&
  348.         stat (f2, &b2) == 0 &&
  349.         b1.st_mtime > b2.st_mtime);
  350. }
  351.  
  352. olderf (f1, f2)
  353. char *f1, *f2;
  354. {
  355.     struct stat b1, b2;
  356.  
  357.     return (stat (f1, &b1) == 0 &&
  358.         stat (f2, &b2) == 0 &&
  359.         b1.st_mtime < b2.st_mtime);
  360. }
  361.  
  362. equalf (f1, f2)
  363. char *f1, *f2;
  364. {
  365.     struct stat b1, b2;
  366.  
  367.     return (stat (f1, &b1) == 0 &&
  368.         stat (f2, &b2) == 0 &&
  369.         b1.st_dev == b2.st_dev &&
  370.         b1.st_ino == b2.st_ino);
  371. }
  372.  
  373. /* atoi with error detection */
  374.  
  375. getn(as)
  376.     char *as;
  377. {
  378.     register char *s;
  379.     register int n;
  380.  
  381.     s = as;
  382.     if (*s == '-')
  383.         s++;
  384.     for (n = 0; *s >= '0' && *s <= '9'; s++)
  385.         n = (n*10) + (*s-'0');
  386.     if (*s)
  387.         errorf("%s: bad number", as);
  388.     return (*as == '-') ? -n : n;
  389. }
  390.  
  391.