(root)/
coreutils-9.4/
src/
expr.c
       1  /* expr -- evaluate expressions.
       2     Copyright (C) 1986-2023 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 <https://www.gnu.org/licenses/>.  */
      16  
      17  /* Author: Mike Parker.
      18     Modified for arbitrary-precision calculation by James Youngman.
      19  
      20     This program evaluates expressions.  Each token (operator, operand,
      21     parenthesis) of the expression must be a separate 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 "system.h"
      35  
      36  #include <gmp.h>
      37  #include <regex.h>
      38  #include "long-options.h"
      39  #include "mbuiter.h"
      40  #include "strnumcmp.h"
      41  #include "xstrtol.h"
      42  
      43  /* Various parts of this code assume size_t fits into unsigned long
      44     int, the widest unsigned type that GMP supports.  */
      45  static_assert (SIZE_MAX <= ULONG_MAX);
      46  
      47  /* The official name of this program (e.g., no 'g' prefix).  */
      48  #define PROGRAM_NAME "expr"
      49  
      50  #define AUTHORS \
      51    proper_name ("Mike Parker"), \
      52    proper_name ("James Youngman"), \
      53    proper_name ("Paul Eggert")
      54  
      55  /* Exit statuses.  */
      56  enum
      57    {
      58      /* Invalid expression: e.g., its form does not conform to the
      59         grammar for expressions.  Our grammar is an extension of the
      60         POSIX grammar.  */
      61      EXPR_INVALID = 2,
      62  
      63      /* An internal error occurred, e.g., arithmetic overflow, storage
      64         exhaustion.  */
      65      EXPR_FAILURE
      66    };
      67  
      68  /* The kinds of value we can have.  */
      69  enum valtype
      70  {
      71    integer,
      72    string
      73  };
      74  typedef enum valtype TYPE;
      75  
      76  /* A value is.... */
      77  struct valinfo
      78  {
      79    TYPE type;			/* Which kind. */
      80    union
      81    {				/* The value itself. */
      82      mpz_t i;
      83      char *s;
      84    } u;
      85  };
      86  typedef struct valinfo VALUE;
      87  
      88  /* The arguments given to the program, minus the program name.  */
      89  static char **args;
      90  
      91  static VALUE *eval (bool);
      92  static bool nomoreargs (void);
      93  static bool null (VALUE *v);
      94  static void printv (VALUE *v);
      95  
      96  
      97  /*
      98     Find the first occurrence in the character string STRING of any character
      99     in the character string ACCEPT.
     100  
     101     Copied from gnulib's mbscspn, with two differences:
     102     1. Returns 1-based position of first found character, or zero if not found.
     103     2. Returned value is the logical character index, NOT byte offset.
     104  
     105     Examples:
     106       mbs_logical_cspn ('hello','a')  => 0
     107       mbs_logical_cspn ('hello','h')  => 1
     108       mbs_logical_cspn ('hello','oe') => 1
     109       mbs_logical_cspn ('hello','lo') => 3
     110  
     111     In UTF-8 \xCE\xB1 is a single character (greek alpha):
     112       mbs_logical_cspn ('\xCE\xB1bc','\xCE\xB1') => 1
     113       mbs_logical_cspn ('\xCE\xB1bc','c') => 3 */
     114  static size_t
     115  mbs_logical_cspn (char const *s, char const *accept)
     116  {
     117    size_t idx = 0;
     118  
     119    if (accept[0] == '\0')
     120      return 0;
     121  
     122    /* General case.  */
     123    if (MB_CUR_MAX > 1)
     124      {
     125        mbui_iterator_t iter;
     126  
     127        for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))
     128          {
     129            ++idx;
     130            if (mb_len (mbui_cur (iter)) == 1)
     131              {
     132                if (mbschr (accept, *mbui_cur_ptr (iter)))
     133                  return idx;
     134              }
     135            else
     136              {
     137                mbui_iterator_t aiter;
     138  
     139                for (mbui_init (aiter, accept);
     140                     mbui_avail (aiter);
     141                     mbui_advance (aiter))
     142                  if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))
     143                    return idx;
     144              }
     145          }
     146  
     147        /* not found */
     148        return 0;
     149      }
     150    else
     151      {
     152        /* single-byte locale,
     153           convert returned byte offset to 1-based index or zero if not found. */
     154        size_t i = strcspn (s, accept);
     155        return (s[i] ? i + 1 : 0);
     156      }
     157  }
     158  
     159  /* Extract the substring of S, from logical character
     160     position POS and LEN characters.
     161     first character position is 1.
     162     POS and LEN refer to logical characters, not octets.
     163  
     164     Upon exit, sets v->s to the new string.
     165     The new string might be empty if POS/LEN are invalid. */
     166  static char *
     167  mbs_logical_substr (char const *s, size_t pos, size_t len)
     168  {
     169    char *v, *vlim;
     170  
     171    size_t blen = strlen (s); /* byte length */
     172    size_t llen = (MB_CUR_MAX > 1) ? mbslen (s) : blen; /* logical length */
     173  
     174    if (llen < pos || pos == 0 || len == 0 || len == SIZE_MAX)
     175      return xstrdup ("");
     176  
     177    /* characters to copy */
     178    size_t vlen = MIN (len, llen - pos + 1);
     179  
     180    if (MB_CUR_MAX == 1)
     181      {
     182        /* Single-byte case */
     183        v = xmalloc (vlen + 1);
     184        vlim = mempcpy (v, s + pos - 1, vlen);
     185      }
     186    else
     187      {
     188        /* Multibyte case */
     189  
     190        /* FIXME: this is wasteful. Some memory can be saved by counting
     191           how many bytes the matching characters occupy. */
     192        vlim = v = xmalloc (blen + 1);
     193  
     194        mbui_iterator_t iter;
     195        size_t idx=1;
     196        for (mbui_init (iter, s);
     197             mbui_avail (iter) && vlen > 0;
     198             mbui_advance (iter), ++idx)
     199          {
     200            /* Skip until we reach the starting position */
     201            if (idx < pos)
     202              continue;
     203  
     204            /* Copy one character */
     205            --vlen;
     206            vlim = mempcpy (vlim, mbui_cur_ptr (iter), mb_len (mbui_cur (iter)));
     207          }
     208      }
     209    *vlim = '\0';
     210    return v;
     211  }
     212  
     213  /* Return the number of logical characters (possibly multibyte)
     214     that are in string S in the first OFS octets.
     215  
     216     Example in UTF-8:
     217     "\xE2\x9D\xA7" is "U+2767 ROTATED FLORAL HEART BULLET".
     218     In the string below, there are only two characters
     219     up to the first 4 bytes (The U+2767 which occupies 3 bytes and 'x'):
     220        mbs_count_to_offset ("\xE2\x9D\xA7xyz", 4) => 2  */
     221  static size_t
     222  mbs_offset_to_chars (char const *s, size_t ofs)
     223  {
     224    mbui_iterator_t iter;
     225    size_t c = 0;
     226    for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))
     227      {
     228        ptrdiff_t d = mbui_cur_ptr (iter) - s;
     229        if (d >= ofs)
     230          break;
     231        ++c;
     232      }
     233    return c;
     234  }
     235  
     236  
     237  
     238  void
     239  usage (int status)
     240  {
     241    if (status != EXIT_SUCCESS)
     242      emit_try_help ();
     243    else
     244      {
     245        printf (_("\
     246  Usage: %s EXPRESSION\n\
     247    or:  %s OPTION\n\
     248  "),
     249                program_name, program_name);
     250        putchar ('\n');
     251        fputs (HELP_OPTION_DESCRIPTION, stdout);
     252        fputs (VERSION_OPTION_DESCRIPTION, stdout);
     253        fputs (_("\
     254  \n\
     255  Print the value of EXPRESSION to standard output.  A blank line below\n\
     256  separates increasing precedence groups.  EXPRESSION may be:\n\
     257  \n\
     258    ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\
     259  \n\
     260    ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\
     261  "), stdout);
     262        fputs (_("\
     263  \n\
     264    ARG1 < ARG2       ARG1 is less than ARG2\n\
     265    ARG1 <= ARG2      ARG1 is less than or equal to ARG2\n\
     266    ARG1 = ARG2       ARG1 is equal to ARG2\n\
     267    ARG1 != ARG2      ARG1 is unequal to ARG2\n\
     268    ARG1 >= ARG2      ARG1 is greater than or equal to ARG2\n\
     269    ARG1 > ARG2       ARG1 is greater than ARG2\n\
     270  "), stdout);
     271        fputs (_("\
     272  \n\
     273    ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\
     274    ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\
     275  "), stdout);
     276        /* Tell xgettext that the "% A" below is not a printf-style
     277           format string:  xgettext:no-c-format */
     278        fputs (_("\
     279  \n\
     280    ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\
     281    ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\
     282    ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2\n\
     283  "), stdout);
     284        fputs (_("\
     285  \n\
     286    STRING : REGEXP   anchored pattern match of REGEXP in STRING\n\
     287  \n\
     288    match STRING REGEXP        same as STRING : REGEXP\n\
     289    substr STRING POS LENGTH   substring of STRING, POS counted from 1\n\
     290    index STRING CHARS         index in STRING where any CHARS is found, or 0\n\
     291    length STRING              length of STRING\n\
     292  "), stdout);
     293        fputs (_("\
     294    + TOKEN                    interpret TOKEN as a string, even if it is a\n\
     295                                 keyword like 'match' or an operator like '/'\n\
     296  \n\
     297    ( EXPRESSION )             value of EXPRESSION\n\
     298  "), stdout);
     299        fputs (_("\
     300  \n\
     301  Beware that many operators need to be escaped or quoted for shells.\n\
     302  Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
     303  Pattern matches return the string matched between \\( and \\) or null; if\n\
     304  \\( and \\) are not used, they return the number of characters matched or 0.\n\
     305  "), stdout);
     306        fputs (_("\
     307  \n\
     308  Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
     309  or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
     310  "), stdout);
     311        emit_ancillary_info (PROGRAM_NAME);
     312      }
     313    exit (status);
     314  }
     315  
     316  
     317  int
     318  main (int argc, char **argv)
     319  {
     320    VALUE *v;
     321  
     322    initialize_main (&argc, &argv);
     323    set_program_name (argv[0]);
     324    setlocale (LC_ALL, "");
     325    bindtextdomain (PACKAGE, LOCALEDIR);
     326    textdomain (PACKAGE);
     327  
     328    initialize_exit_failure (EXPR_FAILURE);
     329    atexit (close_stdout);
     330  
     331    parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
     332                        usage, AUTHORS, (char const *) nullptr);
     333  
     334    /* The above handles --help and --version.
     335       Since there is no other invocation of getopt, handle '--' here.  */
     336    if (1 < argc && STREQ (argv[1], "--"))
     337      {
     338        --argc;
     339        ++argv;
     340      }
     341  
     342    if (argc <= 1)
     343      {
     344        error (0, 0, _("missing operand"));
     345        usage (EXPR_INVALID);
     346      }
     347  
     348    args = argv + 1;
     349  
     350    v = eval (true);
     351    if (!nomoreargs ())
     352      error (EXPR_INVALID, 0, _("syntax error: unexpected argument %s"),
     353             quotearg_n_style (0, locale_quoting_style, *args));
     354  
     355    printv (v);
     356  
     357    main_exit (null (v));
     358  }
     359  
     360  /* Return a VALUE for I.  */
     361  
     362  static VALUE *
     363  int_value (unsigned long int i)
     364  {
     365    VALUE *v = xmalloc (sizeof *v);
     366    v->type = integer;
     367    mpz_init_set_ui (v->u.i, i);
     368    return v;
     369  }
     370  
     371  /* Return a VALUE for S.  */
     372  
     373  static VALUE *
     374  str_value (char const *s)
     375  {
     376    VALUE *v = xmalloc (sizeof *v);
     377    v->type = string;
     378    v->u.s = xstrdup (s);
     379    return v;
     380  }
     381  
     382  /* Free VALUE V, including structure components.  */
     383  
     384  static void
     385  freev (VALUE *v)
     386  {
     387    if (v->type == string)
     388      free (v->u.s);
     389    else
     390      mpz_clear (v->u.i);
     391    free (v);
     392  }
     393  
     394  /* Print VALUE V.  */
     395  
     396  static void
     397  printv (VALUE *v)
     398  {
     399    switch (v->type)
     400      {
     401      case integer:
     402        mpz_out_str (stdout, 10, v->u.i);
     403        putchar ('\n');
     404        break;
     405      case string:
     406        puts (v->u.s);
     407        break;
     408      default:
     409        unreachable ();
     410      }
     411  }
     412  
     413  /* Return true if V is a null-string or zero-number.  */
     414  
     415  ATTRIBUTE_PURE
     416  static bool
     417  null (VALUE *v)
     418  {
     419    switch (v->type)
     420      {
     421      case integer:
     422        return mpz_sgn (v->u.i) == 0;
     423      case string:
     424        {
     425          char const *cp = v->u.s;
     426          if (*cp == '\0')
     427            return true;
     428  
     429          cp += (*cp == '-');
     430  
     431          do
     432            {
     433              if (*cp != '0')
     434                return false;
     435            }
     436          while (*++cp);
     437  
     438          return true;
     439        }
     440      default:
     441        unreachable ();
     442      }
     443  }
     444  
     445  /* Return true if CP takes the form of an integer.  */
     446  
     447  ATTRIBUTE_PURE
     448  static bool
     449  looks_like_integer (char const *cp)
     450  {
     451    cp += (*cp == '-');
     452  
     453    do
     454      if (! ISDIGIT (*cp))
     455        return false;
     456    while (*++cp);
     457  
     458    return true;
     459  }
     460  
     461  /* Coerce V to a string value (can't fail).  */
     462  
     463  static void
     464  tostring (VALUE *v)
     465  {
     466    switch (v->type)
     467      {
     468      case integer:
     469        {
     470          char *s = mpz_get_str (nullptr, 10, v->u.i);
     471          mpz_clear (v->u.i);
     472          v->u.s = s;
     473          v->type = string;
     474        }
     475        break;
     476      case string:
     477        break;
     478      default:
     479        unreachable ();
     480      }
     481  }
     482  
     483  /* Coerce V to an integer value.  Return true on success, false on failure.  */
     484  
     485  static bool
     486  toarith (VALUE *v)
     487  {
     488    switch (v->type)
     489      {
     490      case integer:
     491        return true;
     492      case string:
     493        {
     494          char *s = v->u.s;
     495  
     496          if (! looks_like_integer (s))
     497            return false;
     498          if (mpz_init_set_str (v->u.i, s, 10) != 0)
     499            error (EXPR_FAILURE, ERANGE, "%s", (s));
     500          free (s);
     501          v->type = integer;
     502          return true;
     503        }
     504      default:
     505        unreachable ();
     506      }
     507  }
     508  
     509  /* Extract a size_t value from an integer value I.
     510     If the value is negative, return SIZE_MAX.
     511     If the value is too large, return SIZE_MAX - 1.  */
     512  static size_t
     513  getsize (mpz_t i)
     514  {
     515    if (mpz_sgn (i) < 0)
     516      return SIZE_MAX;
     517    if (mpz_fits_ulong_p (i))
     518      {
     519        unsigned long int ul = mpz_get_ui (i);
     520        if (ul < SIZE_MAX)
     521          return ul;
     522      }
     523    return SIZE_MAX - 1;
     524  }
     525  
     526  /* Return true and advance if the next token matches STR exactly.
     527     STR must not be null.  */
     528  
     529  static bool
     530  nextarg (char const *str)
     531  {
     532    if (*args == nullptr)
     533      return false;
     534    else
     535      {
     536        bool r = STREQ (*args, str);
     537        args += r;
     538        return r;
     539      }
     540  }
     541  
     542  /* Return true if there no more tokens.  */
     543  
     544  static bool
     545  nomoreargs (void)
     546  {
     547    return *args == 0;
     548  }
     549  
     550  /* Report missing operand.
     551     There is an implicit assumption that there was a previous argument,
     552     and (args-1) is valid. */
     553  static void
     554  require_more_args (void)
     555  {
     556    if (nomoreargs ())
     557      error (EXPR_INVALID, 0, _("syntax error: missing argument after %s"),
     558             quotearg_n_style (0, locale_quoting_style, *(args - 1)));
     559  }
     560  
     561  
     562  #ifdef EVAL_TRACE
     563  /* Print evaluation trace and args remaining.  */
     564  
     565  static void
     566  trace (fxn)
     567       char *fxn;
     568  {
     569    char **a;
     570  
     571    printf ("%s:", fxn);
     572    for (a = args; *a; a++)
     573      printf (" %s", *a);
     574    putchar ('\n');
     575  }
     576  #endif
     577  
     578  /* Do the : operator.
     579     SV is the VALUE for the lhs (the string),
     580     PV is the VALUE for the rhs (the pattern).  */
     581  
     582  static VALUE *
     583  docolon (VALUE *sv, VALUE *pv)
     584  {
     585    VALUE *v;
     586    char const *errmsg;
     587    struct re_pattern_buffer re_buffer;
     588    char fastmap[UCHAR_MAX + 1];
     589    struct re_registers re_regs;
     590    regoff_t matchlen;
     591  
     592    tostring (sv);
     593    tostring (pv);
     594  
     595    re_regs.num_regs = 0;
     596    re_regs.start = nullptr;
     597    re_regs.end = nullptr;
     598  
     599    re_buffer.buffer = nullptr;
     600    re_buffer.allocated = 0;
     601    re_buffer.fastmap = fastmap;
     602    re_buffer.translate = nullptr;
     603    re_syntax_options =
     604      RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
     605    errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
     606    if (errmsg)
     607      error (EXPR_INVALID, 0, "%s", (errmsg));
     608    re_buffer.newline_anchor = 0;
     609  
     610    matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
     611    if (0 <= matchlen)
     612      {
     613        /* Were \(...\) used? */
     614        if (re_buffer.re_nsub > 0)
     615          {
     616            if (re_regs.end[1] < 0)
     617              v = str_value ("");
     618            else
     619              {
     620                sv->u.s[re_regs.end[1]] = '\0';
     621                v = str_value (sv->u.s + re_regs.start[1]);
     622              }
     623          }
     624        else
     625          {
     626            /* In multibyte locales, convert the matched offset (=number of bytes)
     627               to the number of matched characters. */
     628            size_t i = (MB_CUR_MAX == 1
     629                        ? matchlen
     630                        : mbs_offset_to_chars (sv->u.s, matchlen));
     631            v = int_value (i);
     632          }
     633      }
     634    else if (matchlen == -1)
     635      {
     636        /* Match failed -- return the right kind of null.  */
     637        if (re_buffer.re_nsub > 0)
     638          v = str_value ("");
     639        else
     640          v = int_value (0);
     641      }
     642    else
     643      error (EXPR_FAILURE,
     644             matchlen == -2 ? errno : EOVERFLOW,
     645             _("error in regular expression matcher"));
     646  
     647    if (0 < re_regs.num_regs)
     648      {
     649        free (re_regs.start);
     650        free (re_regs.end);
     651      }
     652    re_buffer.fastmap = nullptr;
     653    regfree (&re_buffer);
     654    return v;
     655  }
     656  
     657  /* Handle bare operands and ( expr ) syntax.  */
     658  
     659  static VALUE *
     660  eval7 (bool evaluate)
     661  {
     662    VALUE *v;
     663  
     664  #ifdef EVAL_TRACE
     665    trace ("eval7");
     666  #endif
     667    require_more_args ();
     668  
     669    if (nextarg ("("))
     670      {
     671        v = eval (evaluate);
     672        if (nomoreargs ())
     673          error (EXPR_INVALID, 0, _("syntax error: expecting ')' after %s"),
     674                 quotearg_n_style (0, locale_quoting_style, *(args - 1)));
     675        if (!nextarg (")"))
     676          error (EXPR_INVALID, 0, _("syntax error: expecting ')' instead of %s"),
     677                 quotearg_n_style (0, locale_quoting_style, *args));
     678        return v;
     679      }
     680  
     681    if (nextarg (")"))
     682      error (EXPR_INVALID, 0, _("syntax error: unexpected ')'"));
     683  
     684    return str_value (*args++);
     685  }
     686  
     687  /* Handle match, substr, index, and length keywords, and quoting "+".  */
     688  
     689  static VALUE *
     690  eval6 (bool evaluate)
     691  {
     692    VALUE *l;
     693    VALUE *r;
     694    VALUE *v;
     695    VALUE *i1;
     696    VALUE *i2;
     697  
     698  #ifdef EVAL_TRACE
     699    trace ("eval6");
     700  #endif
     701    if (nextarg ("+"))
     702      {
     703        require_more_args ();
     704        return str_value (*args++);
     705      }
     706    else if (nextarg ("length"))
     707      {
     708        r = eval6 (evaluate);
     709        tostring (r);
     710        v = int_value (mbslen (r->u.s));
     711        freev (r);
     712        return v;
     713      }
     714    else if (nextarg ("match"))
     715      {
     716        l = eval6 (evaluate);
     717        r = eval6 (evaluate);
     718        if (evaluate)
     719          {
     720            v = docolon (l, r);
     721            freev (l);
     722          }
     723        else
     724          v = l;
     725        freev (r);
     726        return v;
     727      }
     728    else if (nextarg ("index"))
     729      {
     730        size_t pos;
     731  
     732        l = eval6 (evaluate);
     733        r = eval6 (evaluate);
     734        tostring (l);
     735        tostring (r);
     736        pos = mbs_logical_cspn (l->u.s, r->u.s);
     737        v = int_value (pos);
     738        freev (l);
     739        freev (r);
     740        return v;
     741      }
     742    else if (nextarg ("substr"))
     743      {
     744        l = eval6 (evaluate);
     745        i1 = eval6 (evaluate);
     746        i2 = eval6 (evaluate);
     747        tostring (l);
     748  
     749        if (!toarith (i1) || !toarith (i2))
     750          v = str_value ("");
     751        else
     752          {
     753            size_t pos = getsize (i1->u.i);
     754            size_t len = getsize (i2->u.i);
     755  
     756            char *s = mbs_logical_substr (l->u.s, pos, len);
     757            v = str_value (s);
     758            free (s);
     759          }
     760        freev (l);
     761        freev (i1);
     762        freev (i2);
     763        return v;
     764      }
     765    else
     766      return eval7 (evaluate);
     767  }
     768  
     769  /* Handle : operator (pattern matching).
     770     Calls docolon to do the real work.  */
     771  
     772  static VALUE *
     773  eval5 (bool evaluate)
     774  {
     775    VALUE *l;
     776    VALUE *r;
     777    VALUE *v;
     778  
     779  #ifdef EVAL_TRACE
     780    trace ("eval5");
     781  #endif
     782    l = eval6 (evaluate);
     783    while (true)
     784      {
     785        if (nextarg (":"))
     786          {
     787            r = eval6 (evaluate);
     788            if (evaluate)
     789              {
     790                v = docolon (l, r);
     791                freev (l);
     792                l = v;
     793              }
     794            freev (r);
     795          }
     796        else
     797          return l;
     798      }
     799  }
     800  
     801  /* Handle *, /, % operators.  */
     802  
     803  static VALUE *
     804  eval4 (bool evaluate)
     805  {
     806    VALUE *l;
     807    VALUE *r;
     808    enum { multiply, divide, mod } fxn;
     809  
     810  #ifdef EVAL_TRACE
     811    trace ("eval4");
     812  #endif
     813    l = eval5 (evaluate);
     814    while (true)
     815      {
     816        if (nextarg ("*"))
     817          fxn = multiply;
     818        else if (nextarg ("/"))
     819          fxn = divide;
     820        else if (nextarg ("%"))
     821          fxn = mod;
     822        else
     823          return l;
     824        r = eval5 (evaluate);
     825        if (evaluate)
     826          {
     827            if (!toarith (l) || !toarith (r))
     828              error (EXPR_INVALID, 0, _("non-integer argument"));
     829            if (fxn != multiply && mpz_sgn (r->u.i) == 0)
     830              error (EXPR_INVALID, 0, _("division by zero"));
     831            ((fxn == multiply ? mpz_mul
     832              : fxn == divide ? mpz_tdiv_q
     833              : mpz_tdiv_r)
     834             (l->u.i, l->u.i, r->u.i));
     835          }
     836        freev (r);
     837      }
     838  }
     839  
     840  /* Handle +, - operators.  */
     841  
     842  static VALUE *
     843  eval3 (bool evaluate)
     844  {
     845    VALUE *l;
     846    VALUE *r;
     847    enum { plus, minus } fxn;
     848  
     849  #ifdef EVAL_TRACE
     850    trace ("eval3");
     851  #endif
     852    l = eval4 (evaluate);
     853    while (true)
     854      {
     855        if (nextarg ("+"))
     856          fxn = plus;
     857        else if (nextarg ("-"))
     858          fxn = minus;
     859        else
     860          return l;
     861        r = eval4 (evaluate);
     862        if (evaluate)
     863          {
     864            if (!toarith (l) || !toarith (r))
     865              error (EXPR_INVALID, 0, _("non-integer argument"));
     866            (fxn == plus ? mpz_add : mpz_sub) (l->u.i, l->u.i, r->u.i);
     867          }
     868        freev (r);
     869      }
     870  }
     871  
     872  /* Handle comparisons.  */
     873  
     874  static VALUE *
     875  eval2 (bool evaluate)
     876  {
     877    VALUE *l;
     878  
     879  #ifdef EVAL_TRACE
     880    trace ("eval2");
     881  #endif
     882    l = eval3 (evaluate);
     883    while (true)
     884      {
     885        VALUE *r;
     886        enum
     887          {
     888            less_than, less_equal, equal, not_equal, greater_equal, greater_than
     889          } fxn;
     890        bool val = false;
     891  
     892        if (nextarg ("<"))
     893          fxn = less_than;
     894        else if (nextarg ("<="))
     895          fxn = less_equal;
     896        else if (nextarg ("=") || nextarg ("=="))
     897          fxn = equal;
     898        else if (nextarg ("!="))
     899          fxn = not_equal;
     900        else if (nextarg (">="))
     901          fxn = greater_equal;
     902        else if (nextarg (">"))
     903          fxn = greater_than;
     904        else
     905          return l;
     906        r = eval3 (evaluate);
     907  
     908        if (evaluate)
     909          {
     910            int cmp;
     911            tostring (l);
     912            tostring (r);
     913  
     914            if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
     915              cmp = strintcmp (l->u.s, r->u.s);
     916            else
     917              {
     918                errno = 0;
     919                cmp = strcoll (l->u.s, r->u.s);
     920  
     921                if (errno)
     922                  {
     923                    error (0, errno, _("string comparison failed"));
     924                    error (0, 0, _("set LC_ALL='C' to work around the problem"));
     925                    error (EXPR_INVALID, 0,
     926                           _("the strings compared were %s and %s"),
     927                           quotearg_n_style (0, locale_quoting_style, l->u.s),
     928                           quotearg_n_style (1, locale_quoting_style, r->u.s));
     929                  }
     930              }
     931  
     932            switch (fxn)
     933              {
     934              case less_than:     val = (cmp <  0); break;
     935              case less_equal:    val = (cmp <= 0); break;
     936              case equal:         val = (cmp == 0); break;
     937              case not_equal:     val = (cmp != 0); break;
     938              case greater_equal: val = (cmp >= 0); break;
     939              case greater_than:  val = (cmp >  0); break;
     940              default: unreachable ();
     941              }
     942          }
     943  
     944        freev (l);
     945        freev (r);
     946        l = int_value (val);
     947      }
     948  }
     949  
     950  /* Handle &.  */
     951  
     952  static VALUE *
     953  eval1 (bool evaluate)
     954  {
     955    VALUE *l;
     956    VALUE *r;
     957  
     958  #ifdef EVAL_TRACE
     959    trace ("eval1");
     960  #endif
     961    l = eval2 (evaluate);
     962    while (true)
     963      {
     964        if (nextarg ("&"))
     965          {
     966            r = eval2 (evaluate && !null (l));
     967            if (null (l) || null (r))
     968              {
     969                freev (l);
     970                freev (r);
     971                l = int_value (0);
     972              }
     973            else
     974              freev (r);
     975          }
     976        else
     977          return l;
     978      }
     979  }
     980  
     981  /* Handle |.  */
     982  
     983  static VALUE *
     984  eval (bool evaluate)
     985  {
     986    VALUE *l;
     987    VALUE *r;
     988  
     989  #ifdef EVAL_TRACE
     990    trace ("eval");
     991  #endif
     992    l = eval1 (evaluate);
     993    while (true)
     994      {
     995        if (nextarg ("|"))
     996          {
     997            r = eval1 (evaluate && null (l));
     998            if (null (l))
     999              {
    1000                freev (l);
    1001                l = r;
    1002                if (null (l))
    1003                  {
    1004                    freev (l);
    1005                    l = int_value (0);
    1006                  }
    1007              }
    1008            else
    1009              freev (r);
    1010          }
    1011        else
    1012          return l;
    1013      }
    1014  }