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