/* expr -- evaluate expressions.                                                This is the expr utility
   Copyright (C) 1986-2018 Free Software Foundation, Inc.                       
                                                                                
   This program is free software: you can redistribute it and/or modify         
   it under the terms of the GNU General Public License as published by         
   the Free Software Foundation, either version 3 of the License, or            
   (at your option) any later version.                                          
                                                                                
   This program is distributed in the hope that it will be useful,              
   but WITHOUT ANY WARRANTY; without even the implied warranty of               
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                
   GNU General Public License for more details.                                 
                                                                                
   You should have received a copy of the GNU General Public License            
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */   The GNUv3 license
                                                                                
/* Author: Mike Parker.                                                         
   Modified for arbitrary-precision calculation by James Youngman.              
                                                                                
   This program evaluates expressions.  Each token (operator, operand,          
   parenthesis) of the expression must be a separate argument.  The             
   parser used is a reasonably general one, though any incarnation of           
   it is language-specific.  It is especially nice for expressions.             
                                                                                
   No parse tree is needed; a new node is evaluated immediately.                
   One function can handle multiple operators all of equal precedence,          
   provided they all associate ((x op x) op x).                                 
                                                                                
   Define EVAL_TRACE to print an evaluation trace.  */                          
                                                                                
#include <config.h>                                                             Provides system specific information
#include <stdio.h>                                                              Provides standard I/O capability
#include <sys/types.h>                                                          Provides system data types
#include "system.h"                                                             ...!includes auto-comment...
                                                                                
#include <regex.h>                                                              ...!includes auto-comment...
#include "die.h"                                                                ...!includes auto-comment...
#include "error.h"                                                              ...!includes auto-comment...
#include "long-options.h"                                                       ...!includes auto-comment...
#include "mbuiter.h"                                                            ...!includes auto-comment...
#include "strnumcmp.h"                                                          ...!includes auto-comment...
#include "xstrtol.h"                                                            ...!includes auto-comment...
                                                                                
/* Various parts of this code assume size_t fits into unsigned long             
   int, the widest unsigned type that GMP supports.  */                         
verify (SIZE_MAX <= ULONG_MAX);                                                 Line 46
                                                                                
#ifndef HAVE_GMP                                                                Line 48
# define HAVE_GMP 0                                                             Line 49
#endif                                                                          Line 50
                                                                                
#if HAVE_GMP                                                                    Line 52
# include <gmp.h>                                                               Line 53
#else                                                                           Line 54
static void integer_overflow (char) ATTRIBUTE_NORETURN;                         Line 55
/* Approximate gmp.h well enough for expr.c's purposes.  */                     
typedef intmax_t mpz_t[1];                                                      Line 57
static void mpz_clear (mpz_t z) { (void) z; }                                   Line 58Block 1
static void mpz_init_set_ui (mpz_t z, unsigned long int i) { z[0] = i; }        Line 59Block 2
static int                                                                      Line 60
mpz_init_set_str (mpz_t z, char *s, int base)                                   Line 61
{                                                                               
  return xstrtoimax (s, NULL, base, z, NULL) == LONGINT_OK ? 0 : -1;            Line 63
}                                                                               Block 3
static void                                                                     Line 65
mpz_add (mpz_t r, mpz_t a0, mpz_t b0)                                           Line 66
{                                                                               
  intmax_t a = a0[0];                                                           Line 68
  intmax_t b = b0[0];                                                           Line 69
  intmax_t val = a + b;                                                         Line 70
  if ((val < a) != (b < 0))                                                     Line 71
    integer_overflow ('+');                                                     Line 72
  r[0] = val;                                                                   Line 73
}                                                                               Block 4
static void                                                                     Line 75
mpz_sub (mpz_t r, mpz_t a0, mpz_t b0)                                           Line 76
{                                                                               
  intmax_t a = a0[0];                                                           Line 78
  intmax_t b = b0[0];                                                           Line 79
  intmax_t val = a - b;                                                         Line 80
  if ((a < val) != (b < 0))                                                     Line 81
    integer_overflow ('-');                                                     Line 82
  r[0] = val;                                                                   Line 83
}                                                                               Block 5
static void                                                                     Line 85
mpz_mul (mpz_t r, mpz_t a0, mpz_t b0)                                           Line 86
{                                                                               
  intmax_t a = a0[0];                                                           Line 88
  intmax_t b = b0[0];                                                           Line 89
  intmax_t val = a * b;                                                         Line 90
  if (! (a == 0 || b == 0                                                       Line 91
         || ((val < 0) == ((a < 0) ^ (b < 0)) && val / a == b)))                Line 92
    integer_overflow ('*');                                                     Line 93
  r[0] = val;                                                                   Line 94
}                                                                               Block 6
static void                                                                     Line 96
mpz_tdiv_q (mpz_t r, mpz_t a0, mpz_t b0)                                        Line 97
{                                                                               
  intmax_t a = a0[0];                                                           Line 99
  intmax_t b = b0[0];                                                           Line 100
                                                                                
  /* Some x86-style hosts raise an exception for INT_MIN / -1.  */              
  if (a < - INTMAX_MAX && b == -1)                                              Line 103
    integer_overflow ('/');                                                     Line 104
  r[0] = a / b;                                                                 Line 105
}                                                                               Block 7
static void                                                                     Line 107
mpz_tdiv_r (mpz_t r, mpz_t a0, mpz_t b0)                                        Line 108
{                                                                               
  intmax_t a = a0[0];                                                           Line 110
  intmax_t b = b0[0];                                                           Line 111
                                                                                
  /* Some x86-style hosts raise an exception for INT_MIN % -1.  */              
  r[0] = a < - INTMAX_MAX && b == -1 ? 0 : a % b;                               Line 114
}                                                                               Block 8
static char * _GL_ATTRIBUTE_MALLOC                                              Line 116
mpz_get_str (char const *str, int base, mpz_t z)                                Line 117
{                                                                               
  (void) str; (void) base;                                                      Line 119
  char buf[INT_BUFSIZE_BOUND (intmax_t)];                                       Line 120
  return xstrdup (imaxtostr (z[0], buf));                                       Line 121
}                                                                               Block 9
static int                                                                      Line 123
mpz_sgn (mpz_t z)                                                               Line 124
{                                                                               
  return z[0] < 0 ? -1 : 0 < z[0];                                              Line 126
}                                                                               Block 10
static int                                                                      Line 128
mpz_fits_ulong_p (mpz_t z)                                                      Line 129
{                                                                               
  return 0 <= z[0] && z[0] <= ULONG_MAX;                                        Line 131
}                                                                               Block 11
static unsigned long int                                                        Line 133
mpz_get_ui (mpz_t z)                                                            Line 134
{                                                                               
  return z[0];                                                                  Line 136
}                                                                               Block 12
static int                                                                      Line 138
mpz_out_str (FILE *stream, int base, mpz_t z)                                   Line 139
{                                                                               
  (void) base;                                                                  Line 141
  char buf[INT_BUFSIZE_BOUND (intmax_t)];                                       Line 142
  return fputs (imaxtostr (z[0], buf), stream) != EOF;                          Line 143
}                                                                               Block 13
#endif                                                                          Line 145
                                                                                
/* The official name of this program (e.g., no 'g' prefix).  */                 
#define PROGRAM_NAME "expr"                                                     Line 148
                                                                                
#define AUTHORS \                                                               Line 150
  proper_name ("Mike Parker"), \                                                Line 151
  proper_name ("James Youngman"), \                                             Line 152
  proper_name ("Paul Eggert")                                                   Line 153
                                                                                
/* Exit statuses.  */                                                           
enum                                                                            Line 156
  {                                                                             
    /* Invalid expression: e.g., its form does not conform to the               
       grammar for expressions.  Our grammar is an extension of the             
       POSIX grammar.  */                                                       
    EXPR_INVALID = 2,                                                           Line 161
                                                                                
    /* An internal error occurred, e.g., arithmetic overflow, storage           
       exhaustion.  */                                                          
    EXPR_FAILURE                                                                Line 165
  };                                                                            
                                                                                
/* The kinds of value we can have.  */                                          
enum valtype                                                                    Line 169
{                                                                               
  integer,                                                                      Line 171
  string                                                                        Line 172
};                                                                              Block 15
typedef enum valtype TYPE;                                                      Line 174
                                                                                
/* A value is.... */                                                            
struct valinfo                                                                  Line 177
{                                                                               
  TYPE type;   /* Which kind. */                                                Line 179
  union                                                                         Line 180
  {    /* The value itself. */                                                  Line 181
    mpz_t i;                                                                    Line 182
    char *s;                                                                    Line 183
  } u;                                                                          Line 184
};                                                                              Block 16
typedef struct valinfo VALUE;                                                   Line 186
                                                                                
/* The arguments given to the program, minus the program name.  */              
static char **args;                                                             Line 189
                                                                                
static VALUE *eval (bool);                                                      Line 191
static bool nomoreargs (void);                                                  Line 192
static bool null (VALUE *v);                                                    Line 193
static void printv (VALUE *v);                                                  Line 194
                                                                                
                                                                                
/*                                                                              
   Find the first occurrence in the character string STRING of any character    
   in the character string ACCEPT.                                              
                                                                                
   Copied from gnulib's mbscspn, with two differences:                          
   1. Returns 1-based position of first found character, or zero if not found.  
   2. Returned value is the logical character index, NOT byte offset.           
                                                                                
   Examples:                                                                    
     mbs_logical_cspn ('hello','a')  => 0                                       
     mbs_logical_cspn ('hello','h')  => 1                                       
     mbs_logical_cspn ('hello','oe') => 1                                       
     mbs_logical_cspn ('hello','lo') => 3                                       
                                                                                
   In UTF-8 \xCE\xB1 is a single character (greek alpha):                       
     mbs_logical_cspn ('\xCE\xB1bc','\xCE\xB1') => 1                            
     mbs_logical_cspn ('\xCE\xB1bc','c') => 3 */                                
static size_t                                                                   Line 214
mbs_logical_cspn (const char *s, const char *accept)                            Line 215
{                                                                               
  size_t idx = 0;                                                               Line 217
                                                                                
  if (accept[0] == '\0')                                                        Line 219
    return 0;                                                                   Line 220
                                                                                
  /* General case.  */                                                          
  if (MB_CUR_MAX > 1)                                                           Line 223
    {                                                                           
      mbui_iterator_t iter;                                                     Line 225
                                                                                
      for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))         Line 227
        {                                                                       
          ++idx;                                                                Line 229
          if (mb_len (mbui_cur (iter)) == 1)                                    Line 230
            {                                                                   
              if (mbschr (accept, *mbui_cur_ptr (iter)))                        Line 232
                return idx;                                                     Line 233
            }                                                                   
          else                                                                  Line 235
            {                                                                   
              mbui_iterator_t aiter;                                            Line 237
                                                                                
              for (mbui_init (aiter, accept);                                   Line 239
                   mbui_avail (aiter);                                          Line 240
                   mbui_advance (aiter))                                        Line 241
                if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))               Line 242
                  return idx;                                                   Line 243
            }                                                                   
        }                                                                       
                                                                                
      /* not found */                                                           
      return 0;                                                                 Line 248
    }                                                                           
  else                                                                          Line 250
    {                                                                           
      /* single-byte locale,                                                    
         convert returned byte offset to 1-based index or zero if not found. */ 
      size_t i = strcspn (s, accept);                                           Line 254
      return (s[i] ? i + 1 : 0);                                                Line 255
    }                                                                           
}                                                                               Block 17
                                                                                
/* Extract the substring of S, from logical character                           
   position POS and LEN characters.                                             
   first character position is 1.                                               
   POS and LEN refer to logical characters, not octets.                         
                                                                                
   Upon exit, sets v->s to the new string.                                      
   The new string might be empty if POS/LEN are invalid. */                     
static char *                                                                   Line 266
mbs_logical_substr (const char *s, size_t pos, size_t len)                      Line 267
{                                                                               
  char *v, *vlim;                                                               Line 269
                                                                                
  size_t blen = strlen (s); /* byte length */                                   Line 271
  size_t llen = (MB_CUR_MAX > 1) ? mbslen (s) : blen; /* logical length */      Line 272
                                                                                
  if (llen < pos || pos == 0 || len == 0 || len == SIZE_MAX)                    Line 274
    return xstrdup ("");                                                        Line 275
                                                                                
  /* characters to copy */                                                      
  size_t vlen = MIN (len, llen - pos + 1);                                      Line 278
                                                                                
  if (MB_CUR_MAX == 1)                                                          Line 280
    {                                                                           
      /* Single-byte case */                                                    
      v = xmalloc (vlen + 1);                                                   Line 283
      vlim = mempcpy (v, s + pos - 1, vlen);                                    Line 284
    }                                                                           
  else                                                                          Line 286
    {                                                                           
      /* Multibyte case */                                                      
                                                                                
      /* FIXME: this is wasteful. Some memory can be saved by counting          
         how many bytes the matching characters occupy. */                      
      vlim = v = xmalloc (blen + 1);                                            Line 292
                                                                                
      mbui_iterator_t iter;                                                     Line 294
      size_t idx=1;                                                             Line 295
      for (mbui_init (iter, s);                                                 Line 296
           mbui_avail (iter) && vlen > 0;                                       Line 297
           mbui_advance (iter), ++idx)                                          Line 298
        {                                                                       
          /* Skip until we reach the starting position */                       
          if (idx < pos)                                                        Line 301
            continue;                                                           Line 302
                                                                                
          /* Copy one character */                                              
          --vlen;                                                               Line 305
          vlim = mempcpy (vlim, mbui_cur_ptr (iter), mb_len (mbui_cur (iter))); Line 306
        }                                                                       
    }                                                                           
  *vlim = '\0';                                                                 Line 309
  return v;                                                                     Line 310
}                                                                               Block 18
                                                                                
/* Return the number of logical characteres (possibly multibyte)                
   that are in string S in the first OFS octets.                                
                                                                                
   Example in UTF-8:                                                            
   "\xE2\x9D\xA7" is "U+2767 ROTATED FLORAL HEART BULLET".                      
   In the string below, there are only two characters                           
   up to the first 4 bytes (The U+2767 which occupies 3 bytes and 'x'):         
      mbs_count_to_offset ("\xE2\x9D\xA7xyz", 4) => 2  */                       
static size_t                                                                   Line 321
mbs_offset_to_chars (const char *s, size_t ofs)                                 Line 322
{                                                                               
  mbui_iterator_t iter;                                                         Line 324
  size_t c = 0;                                                                 Line 325
  for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))             Line 326
    {                                                                           
      ptrdiff_t d = mbui_cur_ptr (iter) - s;                                    Line 328
      if (d >= ofs)                                                             Line 329
        break;                                                                  Line 330
      ++c;                                                                      Line 331
    }                                                                           
  return c;                                                                     Line 333
}                                                                               Block 19
                                                                                
                                                                                
                                                                                
void                                                                            Line 338
usage (int status)                                                              Line 339
{                                                                               
  if (status != EXIT_SUCCESS)                                                   Line 341
    emit_try_help ();                                                           ...!common auto-comment...
  else                                                                          Line 343
    {                                                                           
      printf (_("\                                                              Line 345
Usage: %s EXPRESSION\n\                                                         Line 346
  or:  %s OPTION\n\                                                             Line 347
"),                                                                             Line 348
              program_name, program_name);                                      Line 349
      putchar ('\n');                                                           Line 350
      fputs (HELP_OPTION_DESCRIPTION, stdout);                                  Line 351
      fputs (VERSION_OPTION_DESCRIPTION, stdout);                               Line 352
      fputs (_("\                                                               Line 353
\n\                                                                             
Print the value of EXPRESSION to standard output.  A blank line below\n\        Line 355
separates increasing precedence groups.  EXPRESSION may be:\n\                  Line 356
\n\                                                                             
  ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\         Line 358
\n\                                                                             
  ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\       Line 360
"), stdout);                                                                    Line 361
      fputs (_("\                                                               Line 362
\n\                                                                             
  ARG1 < ARG2       ARG1 is less than ARG2\n\                                   Line 364
  ARG1 <= ARG2      ARG1 is less than or equal to ARG2\n\                       Line 365
  ARG1 = ARG2       ARG1 is equal to ARG2\n\                                    Line 366
  ARG1 != ARG2      ARG1 is unequal to ARG2\n\                                  Line 367
  ARG1 >= ARG2      ARG1 is greater than or equal to ARG2\n\                    Line 368
  ARG1 > ARG2       ARG1 is greater than ARG2\n\                                Line 369
"), stdout);                                                                    Line 370
      fputs (_("\                                                               Line 371
\n\                                                                             
  ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\                          Line 373
  ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\                   Line 374
"), stdout);                                                                    Line 375
      /* Tell xgettext that the "% A" below is not a printf-style               
         format string:  xgettext:no-c-format */                                
      fputs (_("\                                                               Line 378
\n\                                                                             
  ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\                      Line 380
  ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\              Line 381
  ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2\n\             Line 382
"), stdout);                                                                    Line 383
      fputs (_("\                                                               Line 384
\n\                                                                             
  STRING : REGEXP   anchored pattern match of REGEXP in STRING\n\               Line 386
\n\                                                                             
  match STRING REGEXP        same as STRING : REGEXP\n\                         Line 388
  substr STRING POS LENGTH   substring of STRING, POS counted from 1\n\         Line 389
  index STRING CHARS         index in STRING where any CHARS is found, or 0\n\  Line 390
  length STRING              length of STRING\n\                                Line 391
"), stdout);                                                                    Line 392
      fputs (_("\                                                               Line 393
  + TOKEN                    interpret TOKEN as a string, even if it is a\n\    Line 394
                               keyword like 'match' or an operator like '/'\n\  Line 395
\n\                                                                             
  ( EXPRESSION )             value of EXPRESSION\n\                             Line 397
"), stdout);                                                                    Line 398
      fputs (_("\                                                               Line 399
\n\                                                                             
Beware that many operators need to be escaped or quoted for shells.\n\          Line 401
Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\   Line 402
Pattern matches return the string matched between \\( and \\) or null; if\n\    Line 403
\\( and \\) are not used, they return the number of characters matched or 0.\n\ Line 404
"), stdout);                                                                    Line 405
      fputs (_("\                                                               Line 406
\n\                                                                             
Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\Line 408
or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\  Line 409
"), stdout);                                                                    Line 410
      emit_ancillary_info (PROGRAM_NAME);                                       Line 411
    }                                                                           
  exit (status);                                                                Line 413
}                                                                               Block 20
                                                                                
                                                                                
#if ! HAVE_GMP                                                                  Line 417
/* Report an integer overflow for operation OP and exit.  */                    
static void                                                                     Line 419
integer_overflow (char op)                                                      Line 420
{                                                                               
  die (EXPR_FAILURE, ERANGE, "%c", op);                                         Line 422
}                                                                               Block 21
#endif                                                                          Line 424
                                                                                
int                                                                             
main (int argc, char **argv)                                                    Line 427
{                                                                               
  VALUE *v;                                                                     Line 429
                                                                                
  initialize_main (&argc, &argv);                                               VMS-specific entry point handling wildcard expansion
  set_program_name (argv[0]);                                                   Retains program name and discards path
  setlocale (LC_ALL, "");                                                       Sets up internationalization (i18n)
  bindtextdomain (PACKAGE, LOCALEDIR);                                          Assigns i18n directorySets text domain for _() [gettext()] function
  textdomain (PACKAGE);                                                         Sets text domain for _() [gettext()] function
                                                                                
  initialize_exit_failure (EXPR_FAILURE);                                       Line 437
  atexit (close_stdout);                                                        Close stdout on exit (see gnulib)
                                                                                
  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,          ...!common auto-comment...
                      usage, AUTHORS, (char const *) NULL);                     Line 441
                                                                                
  /* The above handles --help and --version.                                    
     Since there is no other invocation of getopt, handle '--' here.  */        
  unsigned int u_argc = argc;                                                   Line 445
  if (1 < u_argc && STREQ (argv[1], "--"))                                      Line 446
    {                                                                           
      --u_argc;                                                                 Line 448
      ++argv;                                                                   Line 449
    }                                                                           
                                                                                
  if (u_argc <= 1)                                                              Line 452
    {                                                                           
      error (0, 0, _("missing operand"));                                       Line 454
      usage (EXPR_INVALID);                                                     Line 455
    }                                                                           
                                                                                
  args = argv + 1;                                                              Line 458
                                                                                
  v = eval (true);                                                              Line 460
  if (!nomoreargs ())                                                           Line 461
    die (EXPR_INVALID, 0, _("syntax error: unexpected argument %s"),            Line 462
         quotearg_n_style (0, locale_quoting_style, *args));                    Line 463
                                                                                
  printv (v);                                                                   Line 465
                                                                                
  return null (v);                                                              Line 467
}                                                                               Block 22
                                                                                
/* Return a VALUE for I.  */                                                    
                                                                                
static VALUE *                                                                  Line 472
int_value (unsigned long int i)                                                 Line 473
{                                                                               
  VALUE *v = xmalloc (sizeof *v);                                               Line 475
  v->type = integer;                                                            Line 476
  mpz_init_set_ui (v->u.i, i);                                                  Line 477
  return v;                                                                     Line 478
}                                                                               Block 23
                                                                                
/* Return a VALUE for S.  */                                                    
                                                                                
static VALUE *                                                                  Line 483
str_value (char const *s)                                                       Line 484
{                                                                               
  VALUE *v = xmalloc (sizeof *v);                                               Line 486
  v->type = string;                                                             Line 487
  v->u.s = xstrdup (s);                                                         Line 488
  return v;                                                                     Line 489
}                                                                               Block 24
                                                                                
/* Free VALUE V, including structure components.  */                            
                                                                                
static void                                                                     Line 494
freev (VALUE *v)                                                                Line 495
{                                                                               
  if (v->type == string)                                                        Line 497
    free (v->u.s);                                                              Line 498
  else                                                                          Line 499
    mpz_clear (v->u.i);                                                         Line 500
  free (v);                                                                     Line 501
}                                                                               Block 25
                                                                                
/* Print VALUE V.  */                                                           
                                                                                
static void                                                                     Line 506
printv (VALUE *v)                                                               Line 507
{                                                                               
  switch (v->type)                                                              Line 509
    {                                                                           
    case integer:                                                               Line 511
      mpz_out_str (stdout, 10, v->u.i);                                         Line 512
      putchar ('\n');                                                           Line 513
      break;                                                                    Line 514
    case string:                                                                Line 515
      puts (v->u.s);                                                            Line 516
      break;                                                                    Line 517
    default:                                                                    Line 518
      abort ();                                                                 ...!common auto-comment...
    }                                                                           
}                                                                               Block 26
                                                                                
/* Return true if V is a null-string or zero-number.  */                        
                                                                                
static bool _GL_ATTRIBUTE_PURE                                                  Line 525
null (VALUE *v)                                                                 Line 526
{                                                                               
  switch (v->type)                                                              Line 528
    {                                                                           
    case integer:                                                               Line 530
      return mpz_sgn (v->u.i) == 0;                                             Line 531
    case string:                                                                Line 532
      {                                                                         
        char const *cp = v->u.s;                                                Line 534
        if (*cp == '\0')                                                        Line 535
          return true;                                                          Line 536
                                                                                
        cp += (*cp == '-');                                                     Line 538
                                                                                
        do                                                                      
          {                                                                     
            if (*cp != '0')                                                     Line 542
              return false;                                                     Line 543
          }                                                                     
        while (*++cp);                                                          Line 545
                                                                                
        return true;                                                            Line 547
      }                                                                         
    default:                                                                    Line 549
      abort ();                                                                 ...!common auto-comment...
    }                                                                           
}                                                                               Block 27
                                                                                
/* Return true if CP takes the form of an integer.  */                          
                                                                                
static bool _GL_ATTRIBUTE_PURE                                                  Line 556
looks_like_integer (char const *cp)                                             Line 557
{                                                                               
  cp += (*cp == '-');                                                           Line 559
                                                                                
  do                                                                            
    if (! ISDIGIT (*cp))                                                        Line 562
      return false;                                                             Line 563
  while (*++cp);                                                                Line 564
                                                                                
  return true;                                                                  Line 566
}                                                                               Block 28
                                                                                
/* Coerce V to a string value (can't fail).  */                                 
                                                                                
static void                                                                     Line 571
tostring (VALUE *v)                                                             Line 572
{                                                                               
  switch (v->type)                                                              Line 574
    {                                                                           
    case integer:                                                               Line 576
      {                                                                         
        char *s = mpz_get_str (NULL, 10, v->u.i);                               Line 578
        mpz_clear (v->u.i);                                                     Line 579
        v->u.s = s;                                                             Line 580
        v->type = string;                                                       Line 581
      }                                                                         
      break;                                                                    Line 583
    case string:                                                                Line 584
      break;                                                                    Line 585
    default:                                                                    Line 586
      abort ();                                                                 ...!common auto-comment...
    }                                                                           
}                                                                               Block 29
                                                                                
/* Coerce V to an integer value.  Return true on success, false on failure.  */ 
                                                                                
static bool                                                                     Line 593
toarith (VALUE *v)                                                              Line 594
{                                                                               
  switch (v->type)                                                              Line 596
    {                                                                           
    case integer:                                                               Line 598
      return true;                                                              Line 599
    case string:                                                                Line 600
      {                                                                         
        char *s = v->u.s;                                                       Line 602
                                                                                
        if (! looks_like_integer (s))                                           Line 604
          return false;                                                         Line 605
        if (mpz_init_set_str (v->u.i, s, 10) != 0 && !HAVE_GMP)                 Line 606
          die (EXPR_FAILURE, ERANGE, "%s", (s));                                Line 607
        free (s);                                                               Line 608
        v->type = integer;                                                      Line 609
        return true;                                                            Line 610
      }                                                                         
    default:                                                                    Line 612
      abort ();                                                                 ...!common auto-comment...
    }                                                                           
}                                                                               Block 30
                                                                                
/* Extract a size_t value from an integer value I.                              
   If the value is negative, return SIZE_MAX.                                   
   If the value is too large, return SIZE_MAX - 1.  */                          
static size_t                                                                   Line 620
getsize (mpz_t i)                                                               Line 621
{                                                                               
  if (mpz_sgn (i) < 0)                                                          Line 623
    return SIZE_MAX;                                                            Line 624
  if (mpz_fits_ulong_p (i))                                                     Line 625
    {                                                                           
      unsigned long int ul = mpz_get_ui (i);                                    Line 627
      if (ul < SIZE_MAX)                                                        Line 628
        return ul;                                                              Line 629
    }                                                                           
  return SIZE_MAX - 1;                                                          Line 631
}                                                                               Block 31
                                                                                
/* Return true and advance if the next token matches STR exactly.               
   STR must not be NULL.  */                                                    
                                                                                
static bool                                                                     Line 637
nextarg (char const *str)                                                       Line 638
{                                                                               
  if (*args == NULL)                                                            Line 640
    return false;                                                               Line 641
  else                                                                          Line 642
    {                                                                           
      bool r = STREQ (*args, str);                                              Line 644
      args += r;                                                                Line 645
      return r;                                                                 Line 646
    }                                                                           
}                                                                               Block 32
                                                                                
/* Return true if there no more tokens.  */                                     
                                                                                
static bool                                                                     Line 652
nomoreargs (void)                                                               Line 653
{                                                                               
  return *args == 0;                                                            Line 655
}                                                                               Block 33
                                                                                
/* Report missing operand.                                                      
   There is an implicit assumption that there was a previous argument,          
   and (args-1) is valid. */                                                    
static void                                                                     Line 661
require_more_args (void)                                                        Line 662
{                                                                               
  if (nomoreargs ())                                                            Line 664
    die (EXPR_INVALID, 0, _("syntax error: missing argument after %s"),         Line 665
         quotearg_n_style (0, locale_quoting_style, *(args-1)));                Line 666
}                                                                               Block 34
                                                                                
                                                                                
#ifdef EVAL_TRACE                                                               Line 670
/* Print evaluation trace and args remaining.  */                               
                                                                                
static void                                                                     Line 673
trace (fxn)                                                                     Line 674
     char *fxn;                                                                 Line 675
{                                                                               
  char **a;                                                                     Line 677
                                                                                
  printf ("%s:", fxn);                                                          Line 679
  for (a = args; *a; a++)                                                       Line 680
    printf (" %s", *a);                                                         Line 681
  putchar ('\n');                                                               Line 682
}                                                                               Block 35
#endif                                                                          Line 684
                                                                                
/* Do the : operator.                                                           
   SV is the VALUE for the lhs (the string),                                    
   PV is the VALUE for the rhs (the pattern).  */                               
                                                                                
static VALUE *                                                                  Line 690
docolon (VALUE *sv, VALUE *pv)                                                  Line 691
{                                                                               
  VALUE *v IF_LINT ( = NULL);                                                   Line 693
  const char *errmsg;                                                           Line 694
  struct re_pattern_buffer re_buffer;                                           Line 695
  char fastmap[UCHAR_MAX + 1];                                                  Line 696
  struct re_registers re_regs;                                                  Line 697
  regoff_t matchlen;                                                            Line 698
                                                                                
  tostring (sv);                                                                Line 700
  tostring (pv);                                                                Line 701
                                                                                
  re_regs.num_regs = 0;                                                         Line 703
  re_regs.start = NULL;                                                         Line 704
  re_regs.end = NULL;                                                           Line 705
                                                                                
  re_buffer.buffer = NULL;                                                      Line 707
  re_buffer.allocated = 0;                                                      Line 708
  re_buffer.fastmap = fastmap;                                                  Line 709
  re_buffer.translate = NULL;                                                   Line 710
  re_syntax_options =                                                           Line 711
    RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;      Line 712
  errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);          Line 713
  if (errmsg)                                                                   Line 714
    die (EXPR_INVALID, 0, "%s", (errmsg));                                      Line 715
  re_buffer.newline_anchor = 0;                                                 Line 716
                                                                                
  matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);     Line 718
  if (0 <= matchlen)                                                            Line 719
    {                                                                           
      /* Were \(...\) used? */                                                  
      if (re_buffer.re_nsub > 0)                                                Line 722
        {                                                                       
          sv->u.s[re_regs.end[1]] = '\0';                                       Line 724
          v = str_value (sv->u.s + re_regs.start[1]);                           Line 725
        }                                                                       
      else                                                                      Line 727
        {                                                                       
          /* In multibyte locales, convert the matched offset (=number of bytes)
             to the number of matched characters. */                            
          size_t i = (MB_CUR_MAX == 1                                           Line 731
                      ? matchlen                                                Line 732
                      : mbs_offset_to_chars (sv->u.s, matchlen));               Line 733
          v = int_value (i);                                                    Line 734
        }                                                                       
    }                                                                           
  else if (matchlen == -1)                                                      Line 737
    {                                                                           
      /* Match failed -- return the right kind of null.  */                     
      if (re_buffer.re_nsub > 0)                                                Line 740
        v = str_value ("");                                                     Line 741
      else                                                                      Line 742
        v = int_value (0);                                                      Line 743
    }                                                                           
  else                                                                          Line 745
    die (EXPR_FAILURE,                                                          Line 746
         (matchlen == -2 ? errno : EOVERFLOW),                                  Line 747
         _("error in regular expression matcher"));                             Line 748
                                                                                
  if (0 < re_regs.num_regs)                                                     Line 750
    {                                                                           
      free (re_regs.start);                                                     Line 752
      free (re_regs.end);                                                       Line 753
    }                                                                           
  re_buffer.fastmap = NULL;                                                     Line 755
  regfree (&re_buffer);                                                         Line 756
  return v;                                                                     Line 757
}                                                                               Block 36
                                                                                
/* Handle bare operands and ( expr ) syntax.  */                                
                                                                                
static VALUE *                                                                  Line 762
eval7 (bool evaluate)                                                           Line 763
{                                                                               
  VALUE *v;                                                                     Line 765
                                                                                
#ifdef EVAL_TRACE                                                               Line 767
  trace ("eval7");                                                              Line 768
#endif                                                                          Line 769
  require_more_args ();                                                         Line 770
                                                                                
  if (nextarg ("("))                                                            Line 772
    {                                                                           
      v = eval (evaluate);                                                      Line 774
      if (nomoreargs ())                                                        Line 775
        die (EXPR_INVALID, 0, _("syntax error: expecting ')' after %s"),        Line 776
             quotearg_n_style (0, locale_quoting_style, *(args-1)));            Line 777
      if (!nextarg (")"))                                                       Line 778
        die (EXPR_INVALID, 0, _("syntax error: expecting ')' instead of %s"),   Line 779
             quotearg_n_style (0, locale_quoting_style, *args));                Line 780
      return v;                                                                 Line 781
    }                                                                           
                                                                                
  if (nextarg (")"))                                                            Line 784
    die (EXPR_INVALID, 0, _("syntax error: unexpected ')'"));                   Line 785
                                                                                
  return str_value (*args++);                                                   Line 787
}                                                                               Block 37
                                                                                
/* Handle match, substr, index, and length keywords, and quoting "+".  */       
                                                                                
static VALUE *                                                                  Line 792
eval6 (bool evaluate)                                                           Line 793
{                                                                               
  VALUE *l;                                                                     Line 795
  VALUE *r;                                                                     Line 796
  VALUE *v;                                                                     Line 797
  VALUE *i1;                                                                    Line 798
  VALUE *i2;                                                                    Line 799
                                                                                
#ifdef EVAL_TRACE                                                               Line 801
  trace ("eval6");                                                              Line 802
#endif                                                                          Line 803
  if (nextarg ("+"))                                                            Line 804
    {                                                                           
      require_more_args ();                                                     Line 806
      return str_value (*args++);                                               Line 807
    }                                                                           
  else if (nextarg ("length"))                                                  Line 809
    {                                                                           
      r = eval6 (evaluate);                                                     Line 811
      tostring (r);                                                             Line 812
      v = int_value (mbslen (r->u.s));                                          Line 813
      freev (r);                                                                Line 814
      return v;                                                                 Line 815
    }                                                                           
  else if (nextarg ("match"))                                                   Line 817
    {                                                                           
      l = eval6 (evaluate);                                                     Line 819
      r = eval6 (evaluate);                                                     Line 820
      if (evaluate)                                                             Line 821
        {                                                                       
          v = docolon (l, r);                                                   Line 823
          freev (l);                                                            Line 824
        }                                                                       
      else                                                                      Line 826
        v = l;                                                                  Line 827
      freev (r);                                                                Line 828
      return v;                                                                 Line 829
    }                                                                           
  else if (nextarg ("index"))                                                   Line 831
    {                                                                           
      size_t pos;                                                               Line 833
                                                                                
      l = eval6 (evaluate);                                                     Line 835
      r = eval6 (evaluate);                                                     Line 836
      tostring (l);                                                             Line 837
      tostring (r);                                                             Line 838
      pos = mbs_logical_cspn (l->u.s, r->u.s);                                  Line 839
      v = int_value (pos);                                                      Line 840
      freev (l);                                                                Line 841
      freev (r);                                                                Line 842
      return v;                                                                 Line 843
    }                                                                           
  else if (nextarg ("substr"))                                                  Line 845
    {                                                                           
      l = eval6 (evaluate);                                                     Line 847
      i1 = eval6 (evaluate);                                                    Line 848
      i2 = eval6 (evaluate);                                                    Line 849
      tostring (l);                                                             Line 850
                                                                                
      if (!toarith (i1) || !toarith (i2))                                       Line 852
        v = str_value ("");                                                     Line 853
      else                                                                      Line 854
        {                                                                       
          size_t pos = getsize (i1->u.i);                                       Line 856
          size_t len = getsize (i2->u.i);                                       Line 857
                                                                                
          char *s = mbs_logical_substr (l->u.s, pos, len);                      Line 859
          v = str_value (s);                                                    Line 860
          free (s);                                                             Line 861
        }                                                                       
      freev (l);                                                                Line 863
      freev (i1);                                                               Line 864
      freev (i2);                                                               Line 865
      return v;                                                                 Line 866
    }                                                                           
  else                                                                          Line 868
    return eval7 (evaluate);                                                    Line 869
}                                                                               Block 38
                                                                                
/* Handle : operator (pattern matching).                                        
   Calls docolon to do the real work.  */                                       
                                                                                
static VALUE *                                                                  Line 875
eval5 (bool evaluate)                                                           Line 876
{                                                                               
  VALUE *l;                                                                     Line 878
  VALUE *r;                                                                     Line 879
  VALUE *v;                                                                     Line 880
                                                                                
#ifdef EVAL_TRACE                                                               Line 882
  trace ("eval5");                                                              Line 883
#endif                                                                          Line 884
  l = eval6 (evaluate);                                                         Line 885
  while (1)                                                                     Line 886
    {                                                                           
      if (nextarg (":"))                                                        Line 888
        {                                                                       
          r = eval6 (evaluate);                                                 Line 890
          if (evaluate)                                                         Line 891
            {                                                                   
              v = docolon (l, r);                                               Line 893
              freev (l);                                                        Line 894
              l = v;                                                            Line 895
            }                                                                   
          freev (r);                                                            Line 897
        }                                                                       
      else                                                                      Line 899
        return l;                                                               Line 900
    }                                                                           
}                                                                               Block 39
                                                                                
/* Handle *, /, % operators.  */                                                
                                                                                
static VALUE *                                                                  Line 906
eval4 (bool evaluate)                                                           Line 907
{                                                                               
  VALUE *l;                                                                     Line 909
  VALUE *r;                                                                     Line 910
  enum { multiply, divide, mod } fxn;                                           Line 911
                                                                                
#ifdef EVAL_TRACE                                                               Line 913
  trace ("eval4");                                                              Line 914
#endif                                                                          Line 915
  l = eval5 (evaluate);                                                         Line 916
  while (1)                                                                     Line 917
    {                                                                           
      if (nextarg ("*"))                                                        Line 919
        fxn = multiply;                                                         Line 920
      else if (nextarg ("/"))                                                   Line 921
        fxn = divide;                                                           Line 922
      else if (nextarg ("%"))                                                   Line 923
        fxn = mod;                                                              Line 924
      else                                                                      Line 925
        return l;                                                               Line 926
      r = eval5 (evaluate);                                                     Line 927
      if (evaluate)                                                             Line 928
        {                                                                       
          if (!toarith (l) || !toarith (r))                                     Line 930
            die (EXPR_INVALID, 0, _("non-integer argument"));                   Line 931
          if (fxn != multiply && mpz_sgn (r->u.i) == 0)                         Line 932
            die (EXPR_INVALID, 0, _("division by zero"));                       Line 933
          ((fxn == multiply ? mpz_mul                                           Line 934
            : fxn == divide ? mpz_tdiv_q                                        Line 935
            : mpz_tdiv_r)                                                       Line 936
           (l->u.i, l->u.i, r->u.i));                                           Line 937
        }                                                                       
      freev (r);                                                                Line 939
    }                                                                           
}                                                                               Block 40
                                                                                
/* Handle +, - operators.  */                                                   
                                                                                
static VALUE *                                                                  Line 945
eval3 (bool evaluate)                                                           Line 946
{                                                                               
  VALUE *l;                                                                     Line 948
  VALUE *r;                                                                     Line 949
  enum { plus, minus } fxn;                                                     Line 950
                                                                                
#ifdef EVAL_TRACE                                                               Line 952
  trace ("eval3");                                                              Line 953
#endif                                                                          Line 954
  l = eval4 (evaluate);                                                         Line 955
  while (1)                                                                     Line 956
    {                                                                           
      if (nextarg ("+"))                                                        Line 958
        fxn = plus;                                                             Line 959
      else if (nextarg ("-"))                                                   Line 960
        fxn = minus;                                                            Line 961
      else                                                                      Line 962
        return l;                                                               Line 963
      r = eval4 (evaluate);                                                     Line 964
      if (evaluate)                                                             Line 965
        {                                                                       
          if (!toarith (l) || !toarith (r))                                     Line 967
            die (EXPR_INVALID, 0, _("non-integer argument"));                   Line 968
          (fxn == plus ? mpz_add : mpz_sub) (l->u.i, l->u.i, r->u.i);           Line 969
        }                                                                       
      freev (r);                                                                Line 971
    }                                                                           
}                                                                               Block 41
                                                                                
/* Handle comparisons.  */                                                      
                                                                                
static VALUE *                                                                  Line 977
eval2 (bool evaluate)                                                           Line 978
{                                                                               
  VALUE *l;                                                                     Line 980
                                                                                
#ifdef EVAL_TRACE                                                               Line 982
  trace ("eval2");                                                              Line 983
#endif                                                                          Line 984
  l = eval3 (evaluate);                                                         Line 985
  while (1)                                                                     Line 986
    {                                                                           
      VALUE *r;                                                                 Line 988
      enum                                                                      Line 989
        {                                                                       
          less_than, less_equal, equal, not_equal, greater_equal, greater_than  Line 991
        } fxn;                                                                  Line 992
      bool val = false;                                                         Line 993
                                                                                
      if (nextarg ("<"))                                                        Line 995
        fxn = less_than;                                                        Line 996
      else if (nextarg ("<="))                                                  Line 997
        fxn = less_equal;                                                       Line 998
      else if (nextarg ("=") || nextarg ("=="))                                 Line 999
        fxn = equal;                                                            Line 1000
      else if (nextarg ("!="))                                                  Line 1001
        fxn = not_equal;                                                        Line 1002
      else if (nextarg (">="))                                                  Line 1003
        fxn = greater_equal;                                                    Line 1004
      else if (nextarg (">"))                                                   Line 1005
        fxn = greater_than;                                                     Line 1006
      else                                                                      Line 1007
        return l;                                                               Line 1008
      r = eval3 (evaluate);                                                     Line 1009
                                                                                
      if (evaluate)                                                             Line 1011
        {                                                                       
          int cmp;                                                              Line 1013
          tostring (l);                                                         Line 1014
          tostring (r);                                                         Line 1015
                                                                                
          if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))       Line 1017
            cmp = strintcmp (l->u.s, r->u.s);                                   Line 1018
          else                                                                  Line 1019
            {                                                                   
              errno = 0;                                                        Line 1021
              cmp = strcoll (l->u.s, r->u.s);                                   Line 1022
                                                                                
              if (errno)                                                        Line 1024
                {                                                               
                  error (0, errno, _("string comparison failed"));              Line 1026
                  error (0, 0, _("set LC_ALL='C' to work around the problem")); Line 1027
                  die (EXPR_INVALID, 0,                                         Line 1028
                       _("the strings compared were %s and %s"),                Line 1029
                       quotearg_n_style (0, locale_quoting_style, l->u.s),      Line 1030
                       quotearg_n_style (1, locale_quoting_style, r->u.s));     Line 1031
                }                                                               
            }                                                                   
                                                                                
          switch (fxn)                                                          Line 1035
            {                                                                   
            case less_than:     val = (cmp <  0); break;                        Line 1037
            case less_equal:    val = (cmp <= 0); break;                        Line 1038
            case equal:         val = (cmp == 0); break;                        Line 1039
            case not_equal:     val = (cmp != 0); break;                        Line 1040
            case greater_equal: val = (cmp >= 0); break;                        Line 1041
            case greater_than:  val = (cmp >  0); break;                        Line 1042
            default: abort ();                                                  ...!common auto-comment...
            }                                                                   
        }                                                                       
                                                                                
      freev (l);                                                                Line 1047
      freev (r);                                                                Line 1048
      l = int_value (val);                                                      Line 1049
    }                                                                           
}                                                                               Block 42
                                                                                
/* Handle &.  */                                                                
                                                                                
static VALUE *                                                                  Line 1055
eval1 (bool evaluate)                                                           Line 1056
{                                                                               
  VALUE *l;                                                                     Line 1058
  VALUE *r;                                                                     Line 1059
                                                                                
#ifdef EVAL_TRACE                                                               Line 1061
  trace ("eval1");                                                              Line 1062
#endif                                                                          Line 1063
  l = eval2 (evaluate);                                                         Line 1064
  while (1)                                                                     Line 1065
    {                                                                           
      if (nextarg ("&"))                                                        Line 1067
        {                                                                       
          r = eval2 (evaluate && !null (l));                                    Line 1069
          if (null (l) || null (r))                                             Line 1070
            {                                                                   
              freev (l);                                                        Line 1072
              freev (r);                                                        Line 1073
              l = int_value (0);                                                Line 1074
            }                                                                   
          else                                                                  Line 1076
            freev (r);                                                          Line 1077
        }                                                                       
      else                                                                      Line 1079
        return l;                                                               Line 1080
    }                                                                           
}                                                                               Block 43
                                                                                
/* Handle |.  */                                                                
                                                                                
static VALUE *                                                                  Line 1086
eval (bool evaluate)                                                            Line 1087
{                                                                               
  VALUE *l;                                                                     Line 1089
  VALUE *r;                                                                     Line 1090
                                                                                
#ifdef EVAL_TRACE                                                               Line 1092
  trace ("eval");                                                               Line 1093
#endif                                                                          Line 1094
  l = eval1 (evaluate);                                                         Line 1095
  while (1)                                                                     Line 1096
    {                                                                           
      if (nextarg ("|"))                                                        Line 1098
        {                                                                       
          r = eval1 (evaluate && null (l));                                     Line 1100
          if (null (l))                                                         Line 1101
            {                                                                   
              freev (l);                                                        Line 1103
              l = r;                                                            Line 1104
              if (null (l))                                                     Line 1105
                {                                                               
                  freev (l);                                                    Line 1107
                  l = int_value (0);                                            Line 1108
                }                                                               
            }                                                                   
          else                                                                  Line 1111
            freev (r);                                                          Line 1112
        }                                                                       
      else                                                                      Line 1114
        return l;                                                               Line 1115
    }                                                                           
}                                                                               Block 44