PageRenderTime 46ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/c/coreutils-7.4/src/expr.c

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