1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2007 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
17 /* Author: Mike Parker.
19 This program evaluates expressions. Each token (operator, operand,
20 parenthesis) of the expression must be a seperate argument. The
21 parser used is a reasonably general one, though any incarnation of
22 it is language-specific. It is especially nice for expressions.
24 No parse tree is needed; a new node is evaluated immediately.
25 One function can handle multiple operators all of equal precedence,
26 provided they all associate ((x op x) op x).
28 Define EVAL_TRACE to print an evaluation trace. */
32 #include <sys/types.h>
36 #include "long-options.h"
40 #include "strnumcmp.h"
43 /* The official name of this program (e.g., no `g' prefix). */
44 #define PROGRAM_NAME "expr"
46 #define AUTHORS "Mike Parker"
51 /* Invalid expression: e.g., its form does not conform to the
52 grammar for expressions. Our grammar is an extension of the
56 /* An internal error occurred, e.g., arithmetic overflow, storage
61 /* The kinds of value we can have. */
67 typedef enum valtype TYPE;
72 TYPE type; /* Which kind. */
74 { /* The value itself. */
79 typedef struct valinfo VALUE;
81 /* The arguments given to the program, minus the program name. */
84 /* The name this program was run with. */
87 static VALUE *eval (bool);
88 static bool nomoreargs (void);
89 static bool null (VALUE *v);
90 static void printv (VALUE *v);
95 if (status != EXIT_SUCCESS)
96 fprintf (stderr, _("Try `%s --help' for more information.\n"),
101 Usage: %s EXPRESSION\n\
104 program_name, program_name);
106 fputs (HELP_OPTION_DESCRIPTION, stdout);
107 fputs (VERSION_OPTION_DESCRIPTION, stdout);
110 Print the value of EXPRESSION to standard output. A blank line below\n\
111 separates increasing precedence groups. EXPRESSION may be:\n\
113 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
115 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
119 ARG1 < ARG2 ARG1 is less than ARG2\n\
120 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
121 ARG1 = ARG2 ARG1 is equal to ARG2\n\
122 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
123 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
124 ARG1 > ARG2 ARG1 is greater than ARG2\n\
128 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
129 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
133 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
134 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
135 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
139 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
141 match STRING REGEXP same as STRING : REGEXP\n\
142 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
143 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
144 length STRING length of STRING\n\
147 + TOKEN interpret TOKEN as a string, even if it is a\n\
148 keyword like `match' or an operator like `/'\n\
150 ( EXPRESSION ) value of EXPRESSION\n\
154 Beware that many operators need to be escaped or quoted for shells.\n\
155 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
156 Pattern matches return the string matched between \\( and \\) or null; if\n\
157 \\( and \\) are not used, they return the number of characters matched or 0.\n\
161 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
162 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
164 emit_bug_reporting_address ();
169 /* Report a syntax error and exit. */
173 error (EXPR_INVALID, 0, _("syntax error"));
176 /* Report an integer overflow for operation OP and exit. */
178 integer_overflow (char op)
180 error (EXPR_FAILURE, ERANGE, "%c", op);
184 main (int argc, char **argv)
188 initialize_main (&argc, &argv);
189 program_name = argv[0];
190 setlocale (LC_ALL, "");
191 bindtextdomain (PACKAGE, LOCALEDIR);
192 textdomain (PACKAGE);
194 initialize_exit_failure (EXPR_FAILURE);
195 atexit (close_stdout);
197 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
198 usage, AUTHORS, (char const *) NULL);
199 /* The above handles --help and --version.
200 Since there is no other invocation of getopt, handle `--' here. */
201 if (argc > 1 && STREQ (argv[1], "--"))
209 error (0, 0, _("missing operand"));
210 usage (EXPR_INVALID);
223 /* Return a VALUE for I. */
226 int_value (intmax_t i)
228 VALUE *v = xmalloc (sizeof *v);
234 /* Return a VALUE for S. */
237 str_value (char const *s)
239 VALUE *v = xmalloc (sizeof *v);
241 v->u.s = xstrdup (s);
245 /* Free VALUE V, including structure components. */
250 if (v->type == string)
261 char buf[INT_BUFSIZE_BOUND (intmax_t)];
266 p = imaxtostr (v->u.i, buf);
278 /* Return true if V is a null-string or zero-number. */
289 char const *cp = v->u.s;
309 /* Return true if CP takes the form of an integer. */
312 looks_like_integer (char const *cp)
324 /* Coerce V to a string value (can't fail). */
329 char buf[INT_BUFSIZE_BOUND (intmax_t)];
334 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
344 /* Coerce V to an integer value. Return true on success, false on failure. */
357 if (! looks_like_integer (v->u.s))
359 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
360 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
371 /* Return true and advance if the next token matches STR exactly.
372 STR must not be NULL. */
375 nextarg (char const *str)
381 bool r = STREQ (*args, str);
387 /* Return true if there no more tokens. */
396 /* Print evaluation trace and args remaining. */
405 for (a = args; *a; a++)
411 /* Do the : operator.
412 SV is the VALUE for the lhs (the string),
413 PV is the VALUE for the rhs (the pattern). */
416 docolon (VALUE *sv, VALUE *pv)
418 VALUE *v IF_LINT (= NULL);
420 struct re_pattern_buffer re_buffer;
421 char fastmap[UCHAR_MAX + 1];
422 struct re_registers re_regs;
428 re_regs.num_regs = 0;
429 re_regs.start = NULL;
432 re_buffer.buffer = NULL;
433 re_buffer.allocated = 0;
434 re_buffer.fastmap = fastmap;
435 re_buffer.translate = NULL;
437 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
438 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
440 error (EXPR_INVALID, 0, "%s", errmsg);
441 re_buffer.newline_anchor = 0;
443 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
446 /* Were \(...\) used? */
447 if (re_buffer.re_nsub > 0)
449 sv->u.s[re_regs.end[1]] = '\0';
450 v = str_value (sv->u.s + re_regs.start[1]);
453 v = int_value (matchlen);
455 else if (matchlen == -1)
457 /* Match failed -- return the right kind of null. */
458 if (re_buffer.re_nsub > 0)
465 (matchlen == -2 ? errno : EOVERFLOW),
466 _("error in regular expression matcher"));
468 if (0 < re_regs.num_regs)
470 free (re_regs.start);
473 re_buffer.fastmap = NULL;
474 regfree (&re_buffer);
478 /* Handle bare operands and ( expr ) syntax. */
481 eval7 (bool evaluate)
502 return str_value (*args++);
505 /* Handle match, substr, index, and length keywords, and quoting "+". */
508 eval6 (bool evaluate)
523 return str_value (*args++);
525 else if (nextarg ("length"))
527 r = eval6 (evaluate);
529 v = int_value (strlen (r->u.s));
533 else if (nextarg ("match"))
535 l = eval6 (evaluate);
536 r = eval6 (evaluate);
547 else if (nextarg ("index"))
549 l = eval6 (evaluate);
550 r = eval6 (evaluate);
553 v = int_value (strcspn (l->u.s, r->u.s) + 1);
554 if (v->u.i == strlen (l->u.s) + 1)
560 else if (nextarg ("substr"))
563 l = eval6 (evaluate);
564 i1 = eval6 (evaluate);
565 i2 = eval6 (evaluate);
567 llen = strlen (l->u.s);
568 if (!toarith (i1) || !toarith (i2)
570 || i1->u.i <= 0 || i2->u.i <= 0)
574 size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
576 v = xmalloc (sizeof *v);
578 v->u.s = xmalloc (vlen + 1);
579 vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
588 return eval7 (evaluate);
591 /* Handle : operator (pattern matching).
592 Calls docolon to do the real work. */
595 eval5 (bool evaluate)
604 l = eval6 (evaluate);
609 r = eval6 (evaluate);
623 /* Handle *, /, % operators. */
626 eval4 (bool evaluate)
630 enum { multiply, divide, mod } fxn;
636 l = eval5 (evaluate);
641 else if (nextarg ("/"))
643 else if (nextarg ("%"))
647 r = eval5 (evaluate);
650 if (!toarith (l) || !toarith (r))
651 error (EXPR_INVALID, 0, _("non-numeric argument"));
654 val = l->u.i * r->u.i;
655 if (! (l->u.i == 0 || r->u.i == 0
656 || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
657 && val / l->u.i == r->u.i)))
658 integer_overflow ('*');
663 error (EXPR_INVALID, 0, _("division by zero"));
664 if (l->u.i < - INTMAX_MAX && r->u.i == -1)
666 /* Some x86-style hosts raise an exception for
667 INT_MIN / -1 and INT_MIN % -1, so handle these
668 problematic cases specially. */
670 integer_overflow ('/');
674 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
683 /* Handle +, - operators. */
686 eval3 (bool evaluate)
690 enum { plus, minus } fxn;
696 l = eval4 (evaluate);
701 else if (nextarg ("-"))
705 r = eval4 (evaluate);
708 if (!toarith (l) || !toarith (r))
709 error (EXPR_INVALID, 0, _("non-numeric argument"));
712 val = l->u.i + r->u.i;
713 if ((val < l->u.i) != (r->u.i < 0))
714 integer_overflow ('+');
718 val = l->u.i - r->u.i;
719 if ((l->u.i < val) != (r->u.i < 0))
720 integer_overflow ('-');
729 /* Handle comparisons. */
732 eval2 (bool evaluate)
739 l = eval3 (evaluate);
745 less_than, less_equal, equal, not_equal, greater_equal, greater_than
751 else if (nextarg ("<="))
753 else if (nextarg ("=") || nextarg ("=="))
755 else if (nextarg ("!="))
757 else if (nextarg (">="))
759 else if (nextarg (">"))
763 r = eval3 (evaluate);
771 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
772 cmp = strintcmp (l->u.s, r->u.s);
776 cmp = strcoll (l->u.s, r->u.s);
780 error (0, errno, _("string comparison failed"));
781 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
782 error (EXPR_INVALID, 0,
783 _("The strings compared were %s and %s."),
784 quotearg_n_style (0, locale_quoting_style, l->u.s),
785 quotearg_n_style (1, locale_quoting_style, r->u.s));
791 case less_than: val = (cmp < 0); break;
792 case less_equal: val = (cmp <= 0); break;
793 case equal: val = (cmp == 0); break;
794 case not_equal: val = (cmp != 0); break;
795 case greater_equal: val = (cmp >= 0); break;
796 case greater_than: val = (cmp > 0); break;
810 eval1 (bool evaluate)
818 l = eval2 (evaluate);
823 r = eval2 (evaluate & ~ null (l));
824 if (null (l) || null (r))
849 l = eval1 (evaluate);
854 r = eval1 (evaluate & null (l));