1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2008 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 proper_name ("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\
131 /* Tell xgettext that the "% A" below is not a printf-style
132 format string: xgettext:no-c-format */
135 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
136 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
137 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
141 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
143 match STRING REGEXP same as STRING : REGEXP\n\
144 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
145 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
146 length STRING length of STRING\n\
149 + TOKEN interpret TOKEN as a string, even if it is a\n\
150 keyword like `match' or an operator like `/'\n\
152 ( EXPRESSION ) value of EXPRESSION\n\
156 Beware that many operators need to be escaped or quoted for shells.\n\
157 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
158 Pattern matches return the string matched between \\( and \\) or null; if\n\
159 \\( and \\) are not used, they return the number of characters matched or 0.\n\
163 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
164 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
166 emit_bug_reporting_address ();
171 /* Report a syntax error and exit. */
175 error (EXPR_INVALID, 0, _("syntax error"));
178 /* Report an integer overflow for operation OP and exit. */
180 integer_overflow (char op)
182 error (EXPR_FAILURE, ERANGE, "%c", op);
186 main (int argc, char **argv)
190 initialize_main (&argc, &argv);
191 program_name = argv[0];
192 setlocale (LC_ALL, "");
193 bindtextdomain (PACKAGE, LOCALEDIR);
194 textdomain (PACKAGE);
196 initialize_exit_failure (EXPR_FAILURE);
197 atexit (close_stdout);
199 parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
200 usage, AUTHORS, (char const *) NULL);
201 /* The above handles --help and --version.
202 Since there is no other invocation of getopt, handle `--' here. */
203 if (argc > 1 && STREQ (argv[1], "--"))
211 error (0, 0, _("missing operand"));
212 usage (EXPR_INVALID);
225 /* Return a VALUE for I. */
228 int_value (intmax_t i)
230 VALUE *v = xmalloc (sizeof *v);
236 /* Return a VALUE for S. */
239 str_value (char const *s)
241 VALUE *v = xmalloc (sizeof *v);
243 v->u.s = xstrdup (s);
247 /* Free VALUE V, including structure components. */
252 if (v->type == string)
263 char buf[INT_BUFSIZE_BOUND (intmax_t)];
268 p = imaxtostr (v->u.i, buf);
280 /* Return true if V is a null-string or zero-number. */
291 char const *cp = v->u.s;
311 /* Return true if CP takes the form of an integer. */
314 looks_like_integer (char const *cp)
326 /* Coerce V to a string value (can't fail). */
331 char buf[INT_BUFSIZE_BOUND (intmax_t)];
336 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
346 /* Coerce V to an integer value. Return true on success, false on failure. */
359 if (! looks_like_integer (v->u.s))
361 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
362 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
373 /* Return true and advance if the next token matches STR exactly.
374 STR must not be NULL. */
377 nextarg (char const *str)
383 bool r = STREQ (*args, str);
389 /* Return true if there no more tokens. */
398 /* Print evaluation trace and args remaining. */
407 for (a = args; *a; a++)
413 /* Do the : operator.
414 SV is the VALUE for the lhs (the string),
415 PV is the VALUE for the rhs (the pattern). */
418 docolon (VALUE *sv, VALUE *pv)
420 VALUE *v IF_LINT (= NULL);
422 struct re_pattern_buffer re_buffer;
423 char fastmap[UCHAR_MAX + 1];
424 struct re_registers re_regs;
430 re_regs.num_regs = 0;
431 re_regs.start = NULL;
434 re_buffer.buffer = NULL;
435 re_buffer.allocated = 0;
436 re_buffer.fastmap = fastmap;
437 re_buffer.translate = NULL;
439 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
440 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
442 error (EXPR_INVALID, 0, "%s", errmsg);
443 re_buffer.newline_anchor = 0;
445 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
448 /* Were \(...\) used? */
449 if (re_buffer.re_nsub > 0)
451 sv->u.s[re_regs.end[1]] = '\0';
452 v = str_value (sv->u.s + re_regs.start[1]);
455 v = int_value (matchlen);
457 else if (matchlen == -1)
459 /* Match failed -- return the right kind of null. */
460 if (re_buffer.re_nsub > 0)
467 (matchlen == -2 ? errno : EOVERFLOW),
468 _("error in regular expression matcher"));
470 if (0 < re_regs.num_regs)
472 free (re_regs.start);
475 re_buffer.fastmap = NULL;
476 regfree (&re_buffer);
480 /* Handle bare operands and ( expr ) syntax. */
483 eval7 (bool evaluate)
504 return str_value (*args++);
507 /* Handle match, substr, index, and length keywords, and quoting "+". */
510 eval6 (bool evaluate)
525 return str_value (*args++);
527 else if (nextarg ("length"))
529 r = eval6 (evaluate);
531 v = int_value (strlen (r->u.s));
535 else if (nextarg ("match"))
537 l = eval6 (evaluate);
538 r = eval6 (evaluate);
549 else if (nextarg ("index"))
551 l = eval6 (evaluate);
552 r = eval6 (evaluate);
555 v = int_value (strcspn (l->u.s, r->u.s) + 1);
556 if (v->u.i == strlen (l->u.s) + 1)
562 else if (nextarg ("substr"))
565 l = eval6 (evaluate);
566 i1 = eval6 (evaluate);
567 i2 = eval6 (evaluate);
569 llen = strlen (l->u.s);
570 if (!toarith (i1) || !toarith (i2)
572 || i1->u.i <= 0 || i2->u.i <= 0)
576 size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
578 v = xmalloc (sizeof *v);
580 v->u.s = xmalloc (vlen + 1);
581 vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
590 return eval7 (evaluate);
593 /* Handle : operator (pattern matching).
594 Calls docolon to do the real work. */
597 eval5 (bool evaluate)
606 l = eval6 (evaluate);
611 r = eval6 (evaluate);
625 /* Handle *, /, % operators. */
628 eval4 (bool evaluate)
632 enum { multiply, divide, mod } fxn;
638 l = eval5 (evaluate);
643 else if (nextarg ("/"))
645 else if (nextarg ("%"))
649 r = eval5 (evaluate);
652 if (!toarith (l) || !toarith (r))
653 error (EXPR_INVALID, 0, _("non-numeric argument"));
656 val = l->u.i * r->u.i;
657 if (! (l->u.i == 0 || r->u.i == 0
658 || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
659 && val / l->u.i == r->u.i)))
660 integer_overflow ('*');
665 error (EXPR_INVALID, 0, _("division by zero"));
666 if (l->u.i < - INTMAX_MAX && r->u.i == -1)
668 /* Some x86-style hosts raise an exception for
669 INT_MIN / -1 and INT_MIN % -1, so handle these
670 problematic cases specially. */
672 integer_overflow ('/');
676 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
685 /* Handle +, - operators. */
688 eval3 (bool evaluate)
692 enum { plus, minus } fxn;
698 l = eval4 (evaluate);
703 else if (nextarg ("-"))
707 r = eval4 (evaluate);
710 if (!toarith (l) || !toarith (r))
711 error (EXPR_INVALID, 0, _("non-numeric argument"));
714 val = l->u.i + r->u.i;
715 if ((val < l->u.i) != (r->u.i < 0))
716 integer_overflow ('+');
720 val = l->u.i - r->u.i;
721 if ((l->u.i < val) != (r->u.i < 0))
722 integer_overflow ('-');
731 /* Handle comparisons. */
734 eval2 (bool evaluate)
741 l = eval3 (evaluate);
747 less_than, less_equal, equal, not_equal, greater_equal, greater_than
753 else if (nextarg ("<="))
755 else if (nextarg ("=") || nextarg ("=="))
757 else if (nextarg ("!="))
759 else if (nextarg (">="))
761 else if (nextarg (">"))
765 r = eval3 (evaluate);
773 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
774 cmp = strintcmp (l->u.s, r->u.s);
778 cmp = strcoll (l->u.s, r->u.s);
782 error (0, errno, _("string comparison failed"));
783 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
784 error (EXPR_INVALID, 0,
785 _("The strings compared were %s and %s."),
786 quotearg_n_style (0, locale_quoting_style, l->u.s),
787 quotearg_n_style (1, locale_quoting_style, r->u.s));
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;
812 eval1 (bool evaluate)
820 l = eval2 (evaluate);
825 r = eval2 (evaluate & ~ null (l));
826 if (null (l) || null (r))
851 l = eval1 (evaluate);
856 r = eval1 (evaluate & null (l));