LCOV - code coverage report
Current view: top level - src - expr.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 277 346 80.1 %
Date: 2018-01-30 Functions: 22 23 95.7 %

          Line data    Source code
       1             : /* expr -- evaluate expressions.
       2             :    Copyright (C) 86, 1991-1997, 1999-2007 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 3 of the License, or
       7             :    (at your option) 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, see <http://www.gnu.org/licenses/>.  */
      16             : 
      17             : /* Author: Mike Parker.
      18             : 
      19             :    This program evaluates expressions.  Each token (operator, operand,
      20             :    parenthesis) of the expression must be a seperate argument.  The
      21             :    parser used is a reasonably general one, though any incarnation of
      22             :    it is language-specific.  It is especially nice for expressions.
      23             : 
      24             :    No parse tree is needed; a new node is evaluated immediately.
      25             :    One function can handle multiple operators all of equal precedence,
      26             :    provided they all associate ((x op x) op x).
      27             : 
      28             :    Define EVAL_TRACE to print an evaluation trace.  */
      29             : 
      30             : #include <config.h>
      31             : #include <stdio.h>
      32             : #include <sys/types.h>
      33             : #include "system.h"
      34             : 
      35             : #include <regex.h>
      36             : #include "long-options.h"
      37             : #include "error.h"
      38             : #include "inttostr.h"
      39             : #include "quotearg.h"
      40             : #include "strnumcmp.h"
      41             : #include "xstrtol.h"
      42             : 
      43             : /* The official name of this program (e.g., no `g' prefix).  */
      44             : #define PROGRAM_NAME "expr"
      45             : 
      46             : #define AUTHORS "Mike Parker"
      47             : 
      48             : /* Exit statuses.  */
      49             : enum
      50             :   {
      51             :     /* Invalid expression: e.g., its form does not conform to the
      52             :        grammar for expressions.  Our grammar is an extension of the
      53             :        POSIX grammar.  */
      54             :     EXPR_INVALID = 2,
      55             : 
      56             :     /* An internal error occurred, e.g., arithmetic overflow, storage
      57             :        exhaustion.  */
      58             :     EXPR_FAILURE
      59             :   };
      60             : 
      61             : /* The kinds of value we can have.  */
      62             : enum valtype
      63             : {
      64             :   integer,
      65             :   string
      66             : };
      67             : typedef enum valtype TYPE;
      68             : 
      69             : /* A value is.... */
      70             : struct valinfo
      71             : {
      72             :   TYPE type;                    /* Which kind. */
      73             :   union
      74             :   {                             /* The value itself. */
      75             :     intmax_t i;
      76             :     char *s;
      77             :   } u;
      78             : };
      79             : typedef struct valinfo VALUE;
      80             : 
      81             : /* The arguments given to the program, minus the program name.  */
      82             : static char **args;
      83             : 
      84             : /* The name this program was run with. */
      85             : char *program_name;
      86             : 
      87             : static VALUE *eval (bool);
      88             : static bool nomoreargs (void);
      89             : static bool null (VALUE *v);
      90             : static void printv (VALUE *v);
      91             : 
      92             : void
      93           4 : usage (int status)
      94             : {
      95           4 :   if (status != EXIT_SUCCESS)
      96           2 :     fprintf (stderr, _("Try `%s --help' for more information.\n"),
      97             :              program_name);
      98             :   else
      99             :     {
     100           2 :       printf (_("\
     101             : Usage: %s EXPRESSION\n\
     102             :   or:  %s OPTION\n\
     103             : "),
     104             :               program_name, program_name);
     105           2 :       putchar ('\n');
     106           2 :       fputs (HELP_OPTION_DESCRIPTION, stdout);
     107           2 :       fputs (VERSION_OPTION_DESCRIPTION, stdout);
     108           2 :       fputs (_("\
     109             : \n\
     110             : Print the value of EXPRESSION to standard output.  A blank line below\n\
     111             : separates increasing precedence groups.  EXPRESSION may be:\n\
     112             : \n\
     113             :   ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\
     114             : \n\
     115             :   ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\
     116             : "), stdout);
     117           2 :       fputs (_("\
     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             : "), stdout);
     126           2 :       fputs (_("\
     127             : \n\
     128             :   ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\
     129             :   ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\
     130             : "), stdout);
     131             :       /* Tell xgettext that the "% A" below is not a printf-style
     132             :          format string:  xgettext:no-c-format */
     133           2 :       fputs (_("\
     134             : \n\
     135             :   ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\
     136             :   ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\
     137             :   ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2\n\
     138             : "), stdout);
     139           2 :       fputs (_("\
     140             : \n\
     141             :   STRING : REGEXP   anchored pattern match of REGEXP in STRING\n\
     142             : \n\
     143             :   match STRING REGEXP        same as STRING : REGEXP\n\
     144             :   substr STRING POS LENGTH   substring of STRING, POS counted from 1\n\
     145             :   index STRING CHARS         index in STRING where any CHARS is found, or 0\n\
     146             :   length STRING              length of STRING\n\
     147             : "), stdout);
     148           2 :       fputs (_("\
     149             :   + TOKEN                    interpret TOKEN as a string, even if it is a\n\
     150             :                                keyword like `match' or an operator like `/'\n\
     151             : \n\
     152             :   ( EXPRESSION )             value of EXPRESSION\n\
     153             : "), stdout);
     154           2 :       fputs (_("\
     155             : \n\
     156             : Beware that many operators need to be escaped or quoted for shells.\n\
     157             : Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
     158             : Pattern matches return the string matched between \\( and \\) or null; if\n\
     159             : \\( and \\) are not used, they return the number of characters matched or 0.\n\
     160             : "), stdout);
     161           2 :       fputs (_("\
     162             : \n\
     163             : Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
     164             : or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
     165             : "), stdout);
     166           2 :       emit_bug_reporting_address ();
     167             :     }
     168           4 :   exit (status);
     169             : }
     170             : 
     171             : /* Report a syntax error and exit.  */
     172             : static void
     173          27 : syntax_error (void)
     174             : {
     175          27 :   error (EXPR_INVALID, 0, _("syntax error"));
     176           0 : }
     177             : 
     178             : /* Report an integer overflow for operation OP and exit.  */
     179             : static void
     180           0 : integer_overflow (char op)
     181             : {
     182           0 :   error (EXPR_FAILURE, ERANGE, "%c", op);
     183           0 : }
     184             : 
     185             : int
     186         121 : main (int argc, char **argv)
     187             : {
     188             :   VALUE *v;
     189             : 
     190             :   initialize_main (&argc, &argv);
     191         121 :   program_name = argv[0];
     192         121 :   setlocale (LC_ALL, "");
     193             :   bindtextdomain (PACKAGE, LOCALEDIR);
     194             :   textdomain (PACKAGE);
     195             : 
     196         121 :   initialize_exit_failure (EXPR_FAILURE);
     197         121 :   atexit (close_stdout);
     198             : 
     199         121 :   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
     200             :                       usage, AUTHORS, (char const *) NULL);
     201             :   /* The above handles --help and --version.
     202             :      Since there is no other invocation of getopt, handle `--' here.  */
     203         118 :   if (argc > 1 && STREQ (argv[1], "--"))
     204             :     {
     205           6 :       --argc;
     206           6 :       ++argv;
     207             :     }
     208             : 
     209         118 :   if (argc <= 1)
     210             :     {
     211           2 :       error (0, 0, _("missing operand"));
     212           2 :       usage (EXPR_INVALID);
     213             :     }
     214             : 
     215         116 :   args = argv + 1;
     216             : 
     217         116 :   v = eval (true);
     218          73 :   if (!nomoreargs ())
     219           1 :     syntax_error ();
     220          72 :   printv (v);
     221             : 
     222          72 :   exit (null (v));
     223             : }
     224             : 
     225             : /* Return a VALUE for I.  */
     226             : 
     227             : static VALUE *
     228          59 : int_value (intmax_t i)
     229             : {
     230          59 :   VALUE *v = xmalloc (sizeof *v);
     231          59 :   v->type = integer;
     232          59 :   v->u.i = i;
     233          59 :   return v;
     234             : }
     235             : 
     236             : /* Return a VALUE for S.  */
     237             : 
     238             : static VALUE *
     239         189 : str_value (char const *s)
     240             : {
     241         189 :   VALUE *v = xmalloc (sizeof *v);
     242         189 :   v->type = string;
     243         189 :   v->u.s = xstrdup (s);
     244         189 :   return v;
     245             : }
     246             : 
     247             : /* Free VALUE V, including structure components.  */
     248             : 
     249             : static void
     250         119 : freev (VALUE *v)
     251             : {
     252         119 :   if (v->type == string)
     253         103 :     free (v->u.s);
     254         119 :   free (v);
     255         119 : }
     256             : 
     257             : /* Print VALUE V.  */
     258             : 
     259             : static void
     260          72 : printv (VALUE *v)
     261             : {
     262             :   char *p;
     263             :   char buf[INT_BUFSIZE_BOUND (intmax_t)];
     264             : 
     265          72 :   switch (v->type)
     266             :     {
     267          59 :     case integer:
     268          59 :       p = imaxtostr (v->u.i, buf);
     269          59 :       break;
     270          13 :     case string:
     271          13 :       p = v->u.s;
     272          13 :       break;
     273           0 :     default:
     274           0 :       abort ();
     275             :     }
     276             : 
     277          72 :   puts (p);
     278          72 : }
     279             : 
     280             : /* Return true if V is a null-string or zero-number.  */
     281             : 
     282             : static bool
     283          82 : null (VALUE *v)
     284             : {
     285          82 :   switch (v->type)
     286             :     {
     287          59 :     case integer:
     288          59 :       return v->u.i == 0;
     289          23 :     case string:
     290             :       {
     291          23 :         char const *cp = v->u.s;
     292          23 :         if (*cp == '\0')
     293           2 :           return true;
     294             : 
     295          21 :         cp += (*cp == '-');
     296             : 
     297             :         do
     298             :           {
     299          23 :             if (*cp != '0')
     300          16 :               return false;
     301             :           }
     302           7 :         while (*++cp);
     303             : 
     304           5 :         return true;
     305             :       }
     306           0 :     default:
     307           0 :       abort ();
     308             :     }
     309             : }
     310             : 
     311             : /* Return true if CP takes the form of an integer.  */
     312             : 
     313             : static bool
     314          32 : looks_like_integer (char const *cp)
     315             : {
     316          32 :   cp += (*cp == '-');
     317             : 
     318             :   do
     319          35 :     if (! ISDIGIT (*cp))
     320          11 :       return false;
     321          24 :   while (*++cp);
     322             : 
     323          21 :   return true;
     324             : }
     325             : 
     326             : /* Coerce V to a string value (can't fail).  */
     327             : 
     328             : static void
     329         123 : tostring (VALUE *v)
     330             : {
     331             :   char buf[INT_BUFSIZE_BOUND (intmax_t)];
     332             : 
     333         123 :   switch (v->type)
     334             :     {
     335           0 :     case integer:
     336           0 :       v->u.s = xstrdup (imaxtostr (v->u.i, buf));
     337           0 :       v->type = string;
     338           0 :       break;
     339         123 :     case string:
     340         123 :       break;
     341           0 :     default:
     342           0 :       abort ();
     343             :     }
     344         123 : }
     345             : 
     346             : /* Coerce V to an integer value.  Return true on success, false on failure.  */
     347             : 
     348             : static bool
     349          24 : toarith (VALUE *v)
     350             : {
     351          24 :   switch (v->type)
     352             :     {
     353           0 :     case integer:
     354           0 :       return true;
     355          24 :     case string:
     356             :       {
     357             :         intmax_t value;
     358             : 
     359          24 :         if (! looks_like_integer (v->u.s))
     360           4 :           return false;
     361          20 :         if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
     362           0 :           error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
     363          20 :         free (v->u.s);
     364          20 :         v->u.i = value;
     365          20 :         v->type = integer;
     366          20 :         return true;
     367             :       }
     368           0 :     default:
     369           0 :       abort ();
     370             :     }
     371             : }
     372             : 
     373             : /* Return true and advance if the next token matches STR exactly.
     374             :    STR must not be NULL.  */
     375             : 
     376             : static bool
     377        2842 : nextarg (char const *str)
     378             : {
     379        2842 :   if (*args == NULL)
     380        1192 :     return false;
     381             :   else
     382             :     {
     383        1650 :       bool r = STREQ (*args, str);
     384        1650 :       args += r;
     385        1650 :       return r;
     386             :     }
     387             : }
     388             : 
     389             : /* Return true if there no more tokens.  */
     390             : 
     391             : static bool
     392         289 : nomoreargs (void)
     393             : {
     394         289 :   return *args == 0;
     395             : }
     396             : 
     397             : #ifdef EVAL_TRACE
     398             : /* Print evaluation trace and args remaining.  */
     399             : 
     400             : static void
     401             : trace (fxn)
     402             :      char *fxn;
     403             : {
     404             :   char **a;
     405             : 
     406             :   printf ("%s:", fxn);
     407             :   for (a = args; *a; a++)
     408             :     printf (" %s", *a);
     409             :   putchar ('\n');
     410             : }
     411             : #endif
     412             : 
     413             : /* Do the : operator.
     414             :    SV is the VALUE for the lhs (the string),
     415             :    PV is the VALUE for the rhs (the pattern).  */
     416             : 
     417             : static VALUE *
     418          51 : docolon (VALUE *sv, VALUE *pv)
     419             : {
     420             :   VALUE *v IF_LINT (= NULL);
     421             :   const char *errmsg;
     422             :   struct re_pattern_buffer re_buffer;
     423             :   char fastmap[UCHAR_MAX + 1];
     424             :   struct re_registers re_regs;
     425             :   regoff_t matchlen;
     426             : 
     427          51 :   tostring (sv);
     428          51 :   tostring (pv);
     429             : 
     430          51 :   re_regs.num_regs = 0;
     431          51 :   re_regs.start = NULL;
     432          51 :   re_regs.end = NULL;
     433             : 
     434          51 :   re_buffer.buffer = NULL;
     435          51 :   re_buffer.allocated = 0;
     436          51 :   re_buffer.fastmap = fastmap;
     437          51 :   re_buffer.translate = NULL;
     438          51 :   re_syntax_options =
     439             :     RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
     440          51 :   errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
     441          51 :   if (errmsg)
     442          12 :     error (EXPR_INVALID, 0, "%s", errmsg);
     443          39 :   re_buffer.newline_anchor = 0;
     444             : 
     445          39 :   matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
     446          39 :   if (0 <= matchlen)
     447             :     {
     448             :       /* Were \(...\) used? */
     449          14 :       if (re_buffer.re_nsub > 0)
     450             :         {
     451           0 :           sv->u.s[re_regs.end[1]] = '\0';
     452           0 :           v = str_value (sv->u.s + re_regs.start[1]);
     453             :         }
     454             :       else
     455          14 :         v = int_value (matchlen);
     456             :     }
     457          25 :   else if (matchlen == -1)
     458             :     {
     459             :       /* Match failed -- return the right kind of null.  */
     460          25 :       if (re_buffer.re_nsub > 0)
     461           0 :         v = str_value ("");
     462             :       else
     463          25 :         v = int_value (0);
     464             :     }
     465             :   else
     466           0 :     error (EXPR_FAILURE,
     467           0 :            (matchlen == -2 ? errno : EOVERFLOW),
     468             :            _("error in regular expression matcher"));
     469             : 
     470          39 :   if (0 < re_regs.num_regs)
     471             :     {
     472          14 :       free (re_regs.start);
     473          14 :       free (re_regs.end);
     474             :     }
     475          39 :   re_buffer.fastmap = NULL;
     476          39 :   regfree (&re_buffer);
     477          39 :   return v;
     478             : }
     479             : 
     480             : /* Handle bare operands and ( expr ) syntax.  */
     481             : 
     482             : static VALUE *
     483         198 : eval7 (bool evaluate)
     484             : {
     485             :   VALUE *v;
     486             : 
     487             : #ifdef EVAL_TRACE
     488             :   trace ("eval7");
     489             : #endif
     490         198 :   if (nomoreargs ())
     491          17 :     syntax_error ();
     492             : 
     493         181 :   if (nextarg ("("))
     494             :     {
     495           2 :       v = eval (evaluate);
     496           1 :       if (!nextarg (")"))
     497           1 :         syntax_error ();
     498           0 :       return v;
     499             :     }
     500             : 
     501         179 :   if (nextarg (")"))
     502           1 :     syntax_error ();
     503             : 
     504         178 :   return str_value (*args++);
     505             : }
     506             : 
     507             : /* Handle match, substr, index, and length keywords, and quoting "+".  */
     508             : 
     509             : static VALUE *
     510         225 : eval6 (bool evaluate)
     511             : {
     512             :   VALUE *l;
     513             :   VALUE *r;
     514             :   VALUE *v;
     515             :   VALUE *i1;
     516             :   VALUE *i2;
     517             : 
     518             : #ifdef EVAL_TRACE
     519             :   trace ("eval6");
     520             : #endif
     521         225 :   if (nextarg ("+"))
     522             :     {
     523          18 :       if (nomoreargs ())
     524           7 :         syntax_error ();
     525          11 :       return str_value (*args++);
     526             :     }
     527         207 :   else if (nextarg ("length"))
     528             :     {
     529           1 :       r = eval6 (evaluate);
     530           1 :       tostring (r);
     531           1 :       v = int_value (strlen (r->u.s));
     532           1 :       freev (r);
     533           1 :       return v;
     534             :     }
     535         206 :   else if (nextarg ("match"))
     536             :     {
     537           2 :       l = eval6 (evaluate);
     538           2 :       r = eval6 (evaluate);
     539           1 :       if (evaluate)
     540             :         {
     541           1 :           v = docolon (l, r);
     542           1 :           freev (l);
     543             :         }
     544             :       else
     545           0 :         v = l;
     546           1 :       freev (r);
     547           1 :       return v;
     548             :     }
     549         204 :   else if (nextarg ("index"))
     550             :     {
     551           4 :       l = eval6 (evaluate);
     552           4 :       r = eval6 (evaluate);
     553           3 :       tostring (l);
     554           3 :       tostring (r);
     555           3 :       v = int_value (strcspn (l->u.s, r->u.s) + 1);
     556           3 :       if (v->u.i == strlen (l->u.s) + 1)
     557           2 :         v->u.i = 0;
     558           3 :       freev (l);
     559           3 :       freev (r);
     560           3 :       return v;
     561             :     }
     562         200 :   else if (nextarg ("substr"))
     563             :     {
     564             :       size_t llen;
     565           2 :       l = eval6 (evaluate);
     566           2 :       i1 = eval6 (evaluate);
     567           1 :       i2 = eval6 (evaluate);
     568           0 :       tostring (l);
     569           0 :       llen = strlen (l->u.s);
     570           0 :       if (!toarith (i1) || !toarith (i2)
     571           0 :           || llen < i1->u.i
     572           0 :           || i1->u.i <= 0 || i2->u.i <= 0)
     573           0 :         v = str_value ("");
     574             :       else
     575             :         {
     576           0 :           size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
     577             :           char *vlim;
     578           0 :           v = xmalloc (sizeof *v);
     579           0 :           v->type = string;
     580           0 :           v->u.s = xmalloc (vlen + 1);
     581           0 :           vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
     582           0 :           *vlim = '\0';
     583             :         }
     584           0 :       freev (l);
     585           0 :       freev (i1);
     586           0 :       freev (i2);
     587           0 :       return v;
     588             :     }
     589             :   else
     590         198 :     return eval7 (evaluate);
     591             : }
     592             : 
     593             : /* Handle : operator (pattern matching).
     594             :    Calls docolon to do the real work.  */
     595             : 
     596             : static VALUE *
     597         155 : eval5 (bool evaluate)
     598             : {
     599             :   VALUE *l;
     600             :   VALUE *r;
     601             :   VALUE *v;
     602             : 
     603             : #ifdef EVAL_TRACE
     604             :   trace ("eval5");
     605             : #endif
     606         155 :   l = eval6 (evaluate);
     607             :   while (1)
     608             :     {
     609         206 :       if (nextarg (":"))
     610             :         {
     611          52 :           r = eval6 (evaluate);
     612          50 :           if (evaluate)
     613             :             {
     614          50 :               v = docolon (l, r);
     615          38 :               freev (l);
     616          38 :               l = v;
     617             :             }
     618          38 :           freev (r);
     619             :         }
     620             :       else
     621         232 :         return l;
     622             :     }
     623             : }
     624             : 
     625             : /* Handle *, /, % operators.  */
     626             : 
     627             : static VALUE *
     628         141 : eval4 (bool evaluate)
     629             : {
     630             :   VALUE *l;
     631             :   VALUE *r;
     632             :   enum { multiply, divide, mod } fxn;
     633         141 :   intmax_t val = 0;
     634             : 
     635             : #ifdef EVAL_TRACE
     636             :   trace ("eval4");
     637             : #endif
     638         141 :   l = eval5 (evaluate);
     639             :   while (1)
     640             :     {
     641         121 :       if (nextarg ("*"))
     642           8 :         fxn = multiply;
     643         105 :       else if (nextarg ("/"))
     644           4 :         fxn = divide;
     645         101 :       else if (nextarg ("%"))
     646           2 :         fxn = mod;
     647             :       else
     648         198 :         return l;
     649          14 :       r = eval5 (evaluate);
     650          11 :       if (evaluate)
     651             :         {
     652          11 :           if (!toarith (l) || !toarith (r))
     653           2 :             error (EXPR_INVALID, 0, _("non-numeric argument"));
     654           9 :           if (fxn == multiply)
     655             :             {
     656           5 :               val = l->u.i * r->u.i;
     657           8 :               if (! (l->u.i == 0 || r->u.i == 0
     658           3 :                      || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
     659           3 :                          && val / l->u.i == r->u.i)))
     660           0 :                 integer_overflow ('*');
     661             :             }
     662             :           else
     663             :             {
     664           4 :               if (r->u.i == 0)
     665           1 :                 error (EXPR_INVALID, 0, _("division by zero"));
     666           3 :               if (l->u.i < - INTMAX_MAX && r->u.i == -1)
     667             :                 {
     668             :                   /* Some x86-style hosts raise an exception for
     669             :                      INT_MIN / -1 and INT_MIN % -1, so handle these
     670             :                      problematic cases specially.  */
     671           0 :                   if (fxn == divide)
     672           0 :                     integer_overflow ('/');
     673           0 :                   val = 0;
     674             :                 }
     675             :               else
     676           3 :                 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
     677             :             }
     678             :         }
     679           8 :       freev (l);
     680           8 :       freev (r);
     681           8 :       l = int_value (val);
     682             :     }
     683             : }
     684             : 
     685             : /* Handle +, - operators.  */
     686             : 
     687             : static VALUE *
     688         137 : eval3 (bool evaluate)
     689             : {
     690             :   VALUE *l;
     691             :   VALUE *r;
     692             :   enum { plus, minus } fxn;
     693         137 :   intmax_t val = 0;
     694             : 
     695             : #ifdef EVAL_TRACE
     696             :   trace ("eval3");
     697             : #endif
     698         137 :   l = eval4 (evaluate);
     699             :   while (1)
     700             :     {
     701          97 :       if (nextarg ("+"))
     702           3 :         fxn = plus;
     703          94 :       else if (nextarg ("-"))
     704           1 :         fxn = minus;
     705             :       else
     706         186 :         return l;
     707           4 :       r = eval4 (evaluate);
     708           2 :       if (evaluate)
     709             :         {
     710           2 :           if (!toarith (l) || !toarith (r))
     711           2 :             error (EXPR_INVALID, 0, _("non-numeric argument"));
     712           0 :           if (fxn == plus)
     713             :             {
     714           0 :               val = l->u.i + r->u.i;
     715           0 :               if ((val < l->u.i) != (r->u.i < 0))
     716           0 :                 integer_overflow ('+');
     717             :             }
     718             :           else
     719             :             {
     720           0 :               val = l->u.i - r->u.i;
     721           0 :               if ((l->u.i < val) != (r->u.i < 0))
     722           0 :                 integer_overflow ('-');
     723             :             }
     724             :         }
     725           0 :       freev (l);
     726           0 :       freev (r);
     727           0 :       l = int_value (val);
     728             :     }
     729             : }
     730             : 
     731             : /* Handle comparisons.  */
     732             : 
     733             : static VALUE *
     734         123 : eval2 (bool evaluate)
     735             : {
     736             :   VALUE *l;
     737             : 
     738             : #ifdef EVAL_TRACE
     739             :   trace ("eval2");
     740             : #endif
     741         123 :   l = eval3 (evaluate);
     742             :   while (1)
     743           7 :     {
     744             :       VALUE *r;
     745             :       enum
     746             :         {
     747             :           less_than, less_equal, equal, not_equal, greater_equal, greater_than
     748             :         } fxn;
     749          93 :       bool val = false;
     750             : 
     751          93 :       if (nextarg ("<"))
     752           3 :         fxn = less_than;
     753          90 :       else if (nextarg ("<="))
     754           2 :         fxn = less_equal;
     755          88 :       else if (nextarg ("=") || nextarg ("=="))
     756           3 :         fxn = equal;
     757          85 :       else if (nextarg ("!="))
     758           2 :         fxn = not_equal;
     759          83 :       else if (nextarg (">="))
     760           2 :         fxn = greater_equal;
     761          81 :       else if (nextarg (">"))
     762           2 :         fxn = greater_than;
     763             :       else
     764         158 :         return l;
     765          14 :       r = eval3 (evaluate);
     766             : 
     767           7 :       if (evaluate)
     768             :         {
     769             :           int cmp;
     770           7 :           tostring (l);
     771           7 :           tostring (r);
     772             : 
     773           7 :           if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
     774           0 :             cmp = strintcmp (l->u.s, r->u.s);
     775             :           else
     776             :             {
     777           7 :               errno = 0;
     778           7 :               cmp = strcoll (l->u.s, r->u.s);
     779             : 
     780           7 :               if (errno)
     781             :                 {
     782           0 :                   error (0, errno, _("string comparison failed"));
     783           0 :                   error (0, 0, _("Set LC_ALL='C' to work around the problem."));
     784           0 :                   error (EXPR_INVALID, 0,
     785             :                          _("The strings compared were %s and %s."),
     786           0 :                          quotearg_n_style (0, locale_quoting_style, l->u.s),
     787           0 :                          quotearg_n_style (1, locale_quoting_style, r->u.s));
     788             :                 }
     789             :             }
     790             : 
     791           7 :           switch (fxn)
     792             :             {
     793           2 :             case less_than:     val = (cmp <  0); break;
     794           1 :             case less_equal:    val = (cmp <= 0); break;
     795           1 :             case equal:         val = (cmp == 0); break;
     796           1 :             case not_equal:     val = (cmp != 0); break;
     797           1 :             case greater_equal: val = (cmp >= 0); break;
     798           1 :             case greater_than:  val = (cmp >  0); break;
     799           0 :             default: abort ();
     800             :             }
     801           0 :         }
     802             : 
     803           7 :       freev (l);
     804           7 :       freev (r);
     805           7 :       l = int_value (val);
     806             :     }
     807             : }
     808             : 
     809             : /* Handle &.  */
     810             : 
     811             : static VALUE *
     812         120 : eval1 (bool evaluate)
     813             : {
     814             :   VALUE *l;
     815             :   VALUE *r;
     816             : 
     817             : #ifdef EVAL_TRACE
     818             :   trace ("eval1");
     819             : #endif
     820         120 :   l = eval2 (evaluate);
     821             :   while (1)
     822             :     {
     823          81 :       if (nextarg ("&"))
     824             :         {
     825           3 :           r = eval2 (evaluate & ~ null (l));
     826           2 :           if (null (l) || null (r))
     827             :             {
     828           1 :               freev (l);
     829           1 :               freev (r);
     830           1 :               l = int_value (0);
     831             :             }
     832             :           else
     833           1 :             freev (r);
     834             :         }
     835             :       else
     836         152 :         return l;
     837             :     }
     838             : }
     839             : 
     840             : /* Handle |.  */
     841             : 
     842             : static VALUE *
     843         118 : eval (bool evaluate)
     844             : {
     845             :   VALUE *l;
     846             :   VALUE *r;
     847             : 
     848             : #ifdef EVAL_TRACE
     849             :   trace ("eval");
     850             : #endif
     851         118 :   l = eval1 (evaluate);
     852             :   while (1)
     853             :     {
     854          77 :       if (nextarg ("|"))
     855             :         {
     856           2 :           r = eval1 (evaluate & null (l));
     857           1 :           if (null (l))
     858             :             {
     859           0 :               freev (l);
     860           0 :               l = r;
     861           0 :               if (null (l))
     862             :                 {
     863           0 :                   freev (l);
     864           0 :                   l = int_value (0);
     865             :                 }
     866             :             }
     867             :           else
     868           1 :             freev (r);
     869             :         }
     870             :       else
     871         148 :         return l;
     872             :     }
     873             : }

Generated by: LCOV version 1.10