home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / sh-utils.12 / sh-utils / sh-utils-1.12 / src / expr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-21  |  13.9 KB  |  767 lines

  1. /* expr -- evaluate expressions.
  2.    Copyright (C) 1986, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Author: Mike Parker.
  19.  
  20.    This program evaluates expressions.  Each token (operator, operand,
  21.    parenthesis) of the expression must be a seperate argument.  The
  22.    parser used is a reasonably general one, though any incarnation of
  23.    it is language-specific.  It is especially nice for expressions.
  24.  
  25.    No parse tree is needed; a new node is evaluated immediately.
  26.    One function can handle multiple operators all of equal precedence,
  27.    provided they all associate ((x op x) op x).
  28.  
  29.    Define EVAL_TRACE to print an evaluation trace.  */
  30.  
  31. #include <config.h>
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <regex.h>
  35.  
  36. #include "system.h"
  37. #include "version.h"
  38. #include "long-options.h"
  39.  
  40. #define NEW(type) ((type *) xmalloc (sizeof (type)))
  41. #define OLD(x) free ((char *) x)
  42.  
  43. /* The kinds of value we can have.  */
  44. enum valtype
  45. {
  46.   integer,
  47.   string
  48. };
  49. typedef enum valtype TYPE;
  50.  
  51. /* A value is.... */
  52. struct valinfo
  53. {
  54.   TYPE type;            /* Which kind. */
  55.   union
  56.   {                /* The value itself. */
  57.     int i;
  58.     char *s;
  59.   } u;
  60. };
  61. typedef struct valinfo VALUE;
  62.  
  63. /* The arguments given to the program, minus the program name.  */
  64. static char **args;
  65.  
  66. /* The name this program was run with. */
  67. char *program_name;
  68.  
  69. void error ();
  70. char *xstrdup ();
  71. char *strstr ();
  72. char *xmalloc ();
  73.  
  74. static VALUE *docolon ();
  75. static VALUE *eval ();
  76. static VALUE *int_value ();
  77. static VALUE *str_value ();
  78. static int isstring ();
  79. static int nextarg ();
  80. static int nomoreargs ();
  81. static int null ();
  82. static int toarith ();
  83. static void freev ();
  84. static void printv ();
  85. static void tostring ();
  86.  
  87. #ifdef EVAL_TRACE
  88. static void trace ();
  89. #endif
  90.  
  91. static void
  92. usage (status)
  93.      int status;
  94. {
  95.   if (status != 0)
  96.     fprintf (stderr, "Try `%s --help' for more information.\n",
  97.          program_name);
  98.   else
  99.     {
  100.       printf ("\
  101. Usage: %s EXPRESSION\n\
  102.   or:  %s OPTION\n\
  103. ",
  104.           program_name, program_name);
  105.       printf ("\
  106. \n\
  107.   --help      display this help and exit\n\
  108.   --version   output version information and exit\n\
  109. \n\
  110. ");
  111.       printf ("\
  112. EXPRESSION value is written on standard output.  A white line\n\
  113. separates increasing precedence groups.  EXPRESSION may be:\n\
  114. \n\
  115.   ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\
  116. \n\
  117.   ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\
  118. \n\
  119.   ARG1 < ARG2       ARG1 is less than ARG2\n\
  120.   ARG1 <= ARG2      ARG1 is less than or equal to ARG2\n\
  121.   ARG1 = ARG2       ARG1 is equal to ARG2\n\
  122.   ARG1 != ARG2      ARG1 is unequal to ARG2\n\
  123.   ARG1 >= ARG2      ARG1 is greater than or equal to ARG2\n\
  124.   ARG1 > ARG2       ARG1 is greater than ARG2\n\
  125. \n\
  126.   ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\
  127.   ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\
  128. \n\
  129.   ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\
  130.   ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\
  131.   ARG1 %% ARG2       arithmetic remainder of ARG1 divided by ARG2\n\
  132. \n\
  133.   STRING : REGEXP   anchored pattern match of REGEXP in STRING\n\
  134. \n\
  135.   match STRING REGEXP        same as STRING : REGEXP\n\
  136.   substr STRING POS LENGTH   substring of STRING, POS counted from 1\n\
  137.   index STRING CHARS         index in STRING where any CHARS is found, or 0\n\
  138.   length STRING              length of STRING\n\
  139. \n\
  140.   ( EXPRESSION )             value of EXPRESSION\n\
  141. ");
  142.       printf ("\
  143. \n\
  144. Beware that some operators need to be escaped by backslashes for shells.\n\
  145. Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
  146. Pattern matches return the string matched between \\( and \\) or null; if\n\
  147. \\( and \\) are not used, they return the number of characters matched or 0.\n\
  148. ");
  149.     }
  150.   exit (status);
  151. }
  152.  
  153. void
  154. main (argc, argv)
  155.      int argc;
  156.      char **argv;
  157. {
  158.   VALUE *v;
  159.  
  160.   program_name = argv[0];
  161.  
  162.   parse_long_options (argc, argv, "expr", version_string, usage);
  163.  
  164.   if (argc == 1)
  165.     {
  166.       error (0, 0, "too few arguments");
  167.       usage (1);
  168.     }
  169.  
  170.   args = argv + 1;
  171.  
  172.   v = eval ();
  173.   if (!nomoreargs ())
  174.     error (2, 0, "syntax error");
  175.   printv (v);
  176.  
  177.   exit (null (v));
  178. }
  179.  
  180. /* Return a VALUE for I.  */
  181.  
  182. static VALUE *
  183. int_value (i)
  184.      int i;
  185. {
  186.   VALUE *v;
  187.  
  188.   v = NEW (VALUE);
  189.   v->type = integer;
  190.   v->u.i = i;
  191.   return v;
  192. }
  193.  
  194. /* Return a VALUE for S.  */
  195.  
  196. static VALUE *
  197. str_value (s)
  198.      char *s;
  199. {
  200.   VALUE *v;
  201.  
  202.   v = NEW (VALUE);
  203.   v->type = string;
  204.   v->u.s = xstrdup (s);
  205.   return v;
  206. }
  207.  
  208. /* Free VALUE V, including structure components.  */
  209.  
  210. static void
  211. freev (v)
  212.      VALUE *v;
  213. {
  214.   if (v->type == string)
  215.     free (v->u.s);
  216.   OLD (v);
  217. }
  218.  
  219. /* Print VALUE V.  */
  220.  
  221. static void
  222. printv (v)
  223.      VALUE *v;
  224. {
  225.   switch (v->type)
  226.     {
  227.     case integer:
  228.       printf ("%d\n", v->u.i);
  229.       break;
  230.     case string:
  231.       printf ("%s\n", v->u.s);
  232.       break;
  233.     default:
  234.       abort ();
  235.     }
  236. }
  237.  
  238. /* Return nonzero if V is a null-string or zero-number.  */
  239.  
  240. static int
  241. null (v)
  242.      VALUE *v;
  243. {
  244.   switch (v->type)
  245.     {
  246.     case integer:
  247.       return v->u.i == 0;
  248.     case string:
  249.       return v->u.s[0] == '\0' || strcmp(v->u.s, "0") == 0;
  250.     default:
  251.       abort ();
  252.     }
  253. }
  254.  
  255. /* Return nonzero if V is a string value.  */
  256.  
  257. static int
  258. isstring (v)
  259.      VALUE *v;
  260. {
  261.   return v->type == string;
  262. }
  263.  
  264. /* Coerce V to a string value (can't fail).  */
  265.  
  266. static void
  267. tostring (v)
  268.      VALUE *v;
  269. {
  270.   char *temp;
  271.  
  272.   switch (v->type)
  273.     {
  274.     case integer:
  275.       temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
  276.       sprintf (temp, "%d", v->u.i);
  277.       v->u.s = temp;
  278.       v->type = string;
  279.       break;
  280.     case string:
  281.       break;
  282.     default:
  283.       abort ();
  284.     }
  285. }
  286.  
  287. /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
  288.  
  289. static int
  290. toarith (v)
  291.      VALUE *v;
  292. {
  293.   int i;
  294.   int neg;
  295.   char *cp;
  296.  
  297.   switch (v->type)
  298.     {
  299.     case integer:
  300.       return 1;
  301.     case string:
  302.       i = 0;
  303.       cp = v->u.s;
  304.       /* Don't interpret the empty string as an integer.  */
  305.       if (*cp == 0)
  306.     return 0;
  307.       neg = (*cp == '-');
  308.       if (neg)
  309.     cp++;
  310.       for (; *cp; cp++)
  311.     {
  312.       if (ISDIGIT (*cp))
  313.         i = i * 10 + *cp - '0';
  314.       else
  315.         return 0;
  316.     }
  317.       free (v->u.s);
  318.       v->u.i = i * (neg ? -1 : 1);
  319.       v->type = integer;
  320.       return 1;
  321.     default:
  322.       abort ();
  323.     }
  324. }
  325.  
  326. /* Return nonzero if the next token matches STR exactly.
  327.    STR must not be NULL.  */
  328.  
  329. static int
  330. nextarg (str)
  331.      char *str;
  332. {
  333.   if (*args == NULL)
  334.     return 0;
  335.   return strcmp (*args, str) == 0;
  336. }
  337.  
  338. /* Return nonzero if there no more tokens.  */
  339.  
  340. static int
  341. nomoreargs ()
  342. {
  343.   return *args == 0;
  344. }
  345.  
  346. /* The comparison operator handling functions.  */
  347.  
  348. #define cmpf(name, rel)                \
  349. static                        \
  350. int name (l, r) VALUE *l; VALUE *r;        \
  351. {                        \
  352.   if (isstring (l) || isstring (r))        \
  353.     {                        \
  354.        tostring (l);                \
  355.        tostring (r);                \
  356.        return strcmp (l->u.s, r->u.s) rel 0;    \
  357.     }                        \
  358.  else                        \
  359.    return l->u.i rel r->u.i;            \
  360. }
  361. cmpf (less_than, <)
  362. cmpf (less_equal, <=)
  363. cmpf (equal, ==)
  364. cmpf (not_equal, !=)
  365. cmpf (greater_equal, >=)
  366. cmpf (greater_than, >)
  367.  
  368. #undef cmpf
  369.  
  370. /* The arithmetic operator handling functions.  */
  371.  
  372. #define arithf(name, op)            \
  373. static                        \
  374. int name (l, r) VALUE *l; VALUE *r;        \
  375. {                        \
  376.   if (!toarith (l) || !toarith (r))        \
  377.     error (2, 0, "non-numeric argument");    \
  378.   return l->u.i op r->u.i;            \
  379. }
  380.  
  381. #define arithdivf(name, op)            \
  382. int name (l, r) VALUE *l; VALUE *r;        \
  383. {                        \
  384.   if (!toarith (l) || !toarith (r))        \
  385.     error (2, 0, "non-numeric argument");    \
  386.   if (r->u.i == 0)                \
  387.     error (2, 0, "division by zero");        \
  388.   return l->u.i op r->u.i;            \
  389. }
  390.  
  391. arithf (plus, +)
  392. arithf (minus, -)
  393. arithf (multiply, *)
  394. arithdivf (divide, /)
  395. arithdivf (mod, %)
  396.  
  397. #undef arithf
  398. #undef arithdivf
  399.  
  400. #ifdef EVAL_TRACE
  401. /* Print evaluation trace and args remaining.  */
  402.  
  403. static void
  404. trace (fxn)
  405.      char *fxn;
  406. {
  407.   char **a;
  408.  
  409.   printf ("%s:", fxn);
  410.   for (a = args; *a; a++)
  411.     printf (" %s", *a);
  412.   putchar ('\n');
  413. }
  414. #endif
  415.  
  416. /* Do the : operator.
  417.    SV is the VALUE for the lhs (the string),
  418.    PV is the VALUE for the rhs (the pattern).  */
  419.  
  420. static VALUE *
  421. docolon (sv, pv)
  422.      VALUE *sv;
  423.      VALUE *pv;
  424. {
  425.   VALUE *v;
  426.   const char *errmsg;
  427.   struct re_pattern_buffer re_buffer;
  428.   struct re_registers re_regs;
  429.   int len;
  430.  
  431.   tostring (sv);
  432.   tostring (pv);
  433.  
  434.   len = strlen (pv->u.s);
  435.   re_buffer.allocated = 2 * len;
  436.   re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
  437.   re_buffer.translate = 0;
  438.   errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
  439.   if (errmsg)
  440.     error (2, 0, "%s", errmsg);
  441.  
  442.   len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
  443.   if (len >= 0)
  444.     {
  445.       /* Were \(...\) used? */
  446.       if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
  447.     {
  448.       sv->u.s[re_regs.end[1]] = '\0';
  449.       v = str_value (sv->u.s + re_regs.start[1]);
  450.     }
  451.       else
  452.     v = int_value (len);
  453.     }
  454.   else
  455.     {
  456.       /* Match failed -- return the right kind of null.  */
  457.       if (strstr (pv->u.s, "\\("))
  458.     v = str_value ("");
  459.       else
  460.     v = int_value (0);
  461.     }
  462.   free (re_buffer.buffer);
  463.   return v;
  464. }
  465.  
  466. /* Handle bare operands and ( expr ) syntax.  */
  467.  
  468. static VALUE *
  469. eval7 ()
  470. {
  471.   VALUE *v;
  472.  
  473. #ifdef EVAL_TRACE
  474.   trace ("eval7");
  475. #endif
  476.   if (nomoreargs ())
  477.     error (2, 0, "syntax error");
  478.  
  479.   if (nextarg ("("))
  480.     {
  481.       args++;
  482.       v = eval ();
  483.       if (!nextarg (")"))
  484.     error (2, 0, "syntax error");
  485.       args++;
  486.       return v;
  487.     }
  488.  
  489.   if (nextarg (")"))
  490.     error (2, 0, "syntax error");
  491.  
  492.   return str_value (*args++);
  493. }
  494.  
  495. /* Handle match, substr, index, and length keywords.  */
  496.  
  497. static VALUE *
  498. eval6 ()
  499. {
  500.   VALUE *l;
  501.   VALUE *r;
  502.   VALUE *v;
  503.   VALUE *i1;
  504.   VALUE *i2;
  505.  
  506. #ifdef EVAL_TRACE
  507.   trace ("eval6");
  508. #endif
  509.   if (nextarg ("length"))
  510.     {
  511.       args++;
  512.       r = eval6 ();
  513.       tostring (r);
  514.       v = int_value (strlen (r->u.s));
  515.       freev (r);
  516.       return v;
  517.     }
  518.   else if (nextarg ("match"))
  519.     {
  520.       args++;
  521.       l = eval6 ();
  522.       r = eval6 ();
  523.       v = docolon (l, r);
  524.       freev (l);
  525.       freev (r);
  526.       return v;
  527.     }
  528.   else if (nextarg ("index"))
  529.     {
  530.       args++;
  531.       l = eval6 ();
  532.       r = eval6 ();
  533.       tostring (l);
  534.       tostring (r);
  535.       v = int_value (strcspn (l->u.s, r->u.s) + 1);
  536.       if (v->u.i == strlen (l->u.s) + 1)
  537.     v->u.i = 0;
  538.       freev (l);
  539.       freev (r);
  540.       return v;
  541.     }
  542.   else if (nextarg ("substr"))
  543.     {
  544.       args++;
  545.       l = eval6 ();
  546.       i1 = eval6 ();
  547.       i2 = eval6 ();
  548.       tostring (l);
  549.       if (!toarith (i1) || !toarith (i2)
  550.       || i1->u.i > strlen (l->u.s)
  551.       || i1->u.i <= 0 || i2->u.i <= 0)
  552.     v = str_value ("");
  553.       else
  554.     {
  555.       v = NEW (VALUE);
  556.       v->type = string;
  557.       v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
  558.                 l->u.s + i1->u.i - 1, i2->u.i);
  559.       v->u.s[i2->u.i] = 0;
  560.     }
  561.       freev (l);
  562.       freev (i1);
  563.       freev (i2);
  564.       return v;
  565.     }
  566.   else
  567.     return eval7 ();
  568. }
  569.  
  570. /* Handle : operator (pattern matching).
  571.    Calls docolon to do the real work.  */
  572.  
  573. static VALUE *
  574. eval5 ()
  575. {
  576.   VALUE *l;
  577.   VALUE *r;
  578.   VALUE *v;
  579.  
  580. #ifdef EVAL_TRACE
  581.   trace ("eval5");
  582. #endif
  583.   l = eval6 ();
  584.   while (1)
  585.     {
  586.       if (nextarg (":"))
  587.     {
  588.       args++;
  589.       r = eval6 ();
  590.       v = docolon (l, r);
  591.       freev (l);
  592.       freev (r);
  593.       l = v;
  594.     }
  595.       else
  596.     return l;
  597.     }
  598. }
  599.  
  600. /* Handle *, /, % operators.  */
  601.  
  602. static VALUE *
  603. eval4 ()
  604. {
  605.   VALUE *l;
  606.   VALUE *r;
  607.   int (*fxn) ();
  608.   int val;
  609.  
  610. #ifdef EVAL_TRACE
  611.   trace ("eval4");
  612. #endif
  613.   l = eval5 ();
  614.   while (1)
  615.     {
  616.       if (nextarg ("*"))
  617.     fxn = multiply;
  618.       else if (nextarg ("/"))
  619.     fxn = divide;
  620.       else if (nextarg ("%"))
  621.     fxn = mod;
  622.       else
  623.     return l;
  624.       args++;
  625.       r = eval5 ();
  626.       val = (*fxn) (l, r);
  627.       freev (l);
  628.       freev (r);
  629.       l = int_value (val);
  630.     }
  631. }
  632.  
  633. /* Handle +, - operators.  */
  634.  
  635. static VALUE *
  636. eval3 ()
  637. {
  638.   VALUE *l;
  639.   VALUE *r;
  640.   int (*fxn) ();
  641.   int val;
  642.  
  643. #ifdef EVAL_TRACE
  644.   trace ("eval3");
  645. #endif
  646.   l = eval4 ();
  647.   while (1)
  648.     {
  649.       if (nextarg ("+"))
  650.     fxn = plus;
  651.       else if (nextarg ("-"))
  652.     fxn = minus;
  653.       else
  654.     return l;
  655.       args++;
  656.       r = eval4 ();
  657.       val = (*fxn) (l, r);
  658.       freev (l);
  659.       freev (r);
  660.       l = int_value (val);
  661.     }
  662. }
  663.  
  664. /* Handle comparisons.  */
  665.  
  666. static VALUE *
  667. eval2 ()
  668. {
  669.   VALUE *l;
  670.   VALUE *r;
  671.   int (*fxn) ();
  672.   int val;
  673.  
  674. #ifdef EVAL_TRACE
  675.   trace ("eval2");
  676. #endif
  677.   l = eval3 ();
  678.   while (1)
  679.     {
  680.       if (nextarg ("<"))
  681.     fxn = less_than;
  682.       else if (nextarg ("<="))
  683.     fxn = less_equal;
  684.       else if (nextarg ("=") || nextarg ("=="))
  685.     fxn = equal;
  686.       else if (nextarg ("!="))
  687.     fxn = not_equal;
  688.       else if (nextarg (">="))
  689.     fxn = greater_equal;
  690.       else if (nextarg (">"))
  691.     fxn = greater_than;
  692.       else
  693.     return l;
  694.       args++;
  695.       r = eval3 ();
  696.       toarith (l);
  697.       toarith (r);
  698.       val = (*fxn) (l, r);
  699.       freev (l);
  700.       freev (r);
  701.       l = int_value (val);
  702.     }
  703. }
  704.  
  705. /* Handle &.  */
  706.  
  707. static VALUE *
  708. eval1 ()
  709. {
  710.   VALUE *l;
  711.   VALUE *r;
  712.  
  713. #ifdef EVAL_TRACE
  714.   trace ("eval1");
  715. #endif
  716.   l = eval2 ();
  717.   while (1)
  718.     {
  719.       if (nextarg ("&"))
  720.     {
  721.       args++;
  722.       r = eval2 ();
  723.       if (null (l) || null (r))
  724.         {
  725.           freev (l);
  726.           freev (r);
  727.           l = int_value (0);
  728.         }
  729.       else
  730.         freev (r);
  731.     }
  732.       else
  733.     return l;
  734.     }
  735. }
  736.  
  737. /* Handle |.  */
  738.  
  739. static VALUE *
  740. eval ()
  741. {
  742.   VALUE *l;
  743.   VALUE *r;
  744.  
  745. #ifdef EVAL_TRACE
  746.   trace ("eval");
  747. #endif
  748.   l = eval1 ();
  749.   while (1)
  750.     {
  751.       if (nextarg ("|"))
  752.     {
  753.       args++;
  754.       r = eval1 ();
  755.       if (null (l))
  756.         {
  757.           freev (l);
  758.           l = r;
  759.         }
  760.       else
  761.         freev (r);
  762.     }
  763.       else
  764.     return l;
  765.     }
  766. }
  767.