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 2, or (at your option)
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, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
18 /* Author: Mike Parker.
20 This program evaluates expressions. Each token (operator, operand,
21 parenthesis) of the expression must be a seperate argument. The
22 parser used is a reasonably general one, though any incarnation of
23 it is language-specific. It is especially nice for expressions.
25 No parse tree is needed; a new node is evaluated immediately.
26 One function can handle multiple operators all of equal precedence,
27 provided they all associate ((x op x) op x).
29 Define EVAL_TRACE to print an evaluation trace. */
33 #include <sys/types.h>
37 #include "long-options.h"
41 #include "strnumcmp.h"
44 /* The official name of this program (e.g., no `g' prefix). */
45 #define PROGRAM_NAME "expr"
47 #define AUTHORS "Mike Parker"
52 /* Invalid expression: e.g., its form does not conform to the
53 grammar for expressions. Our grammar is an extension of the
57 /* An internal error occurred, e.g., arithmetic overflow, storage
62 /* The kinds of value we can have. */
68 typedef enum valtype TYPE;
73 TYPE type; /* Which kind. */
75 { /* The value itself. */
80 typedef struct valinfo VALUE;
82 /* The arguments given to the program, minus the program name. */
85 /* The name this program was run with. */
88 static VALUE *eval (bool);
89 static bool nomoreargs (void);
90 static bool null (VALUE *v);
91 static void printv (VALUE *v);
96 if (status != EXIT_SUCCESS)
97 fprintf (stderr, _("Try `%s --help' for more information.\n"),
102 Usage: %s EXPRESSION\n\
105 program_name, program_name);
107 fputs (HELP_OPTION_DESCRIPTION, stdout);
108 fputs (VERSION_OPTION_DESCRIPTION, stdout);
111 Print the value of EXPRESSION to standard output. A blank line below\n\
112 separates increasing precedence groups. EXPRESSION may be:\n\
114 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
116 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
120 ARG1 < ARG2 ARG1 is less than ARG2\n\
121 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
122 ARG1 = ARG2 ARG1 is equal to ARG2\n\
123 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
124 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
125 ARG1 > ARG2 ARG1 is greater than ARG2\n\
129 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
130 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
134 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
135 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
136 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
140 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
142 match STRING REGEXP same as STRING : REGEXP\n\
143 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
144 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
145 length STRING length of STRING\n\
148 + TOKEN interpret TOKEN as a string, even if it is a\n\
149 keyword like `match' or an operator like `/'\n\
151 ( EXPRESSION ) value of EXPRESSION\n\
155 Beware that many operators need to be escaped or quoted for shells.\n\
156 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
157 Pattern matches return the string matched between \\( and \\) or null; if\n\
158 \\( and \\) are not used, they return the number of characters matched or 0.\n\
162 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
163 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
165 emit_bug_reporting_address ();
170 /* Report a syntax error and exit. */
174 error (EXPR_INVALID, 0, _("syntax error"));
177 /* Report an integer overflow for operation OP and exit. */
179 integer_overflow (char op)
181 error (EXPR_FAILURE, ERANGE, "%c", op);
185 main (int argc, char **argv)
189 initialize_main (&argc, &argv);
190 program_name = argv[0];
191 setlocale (LC_ALL, "");
192 bindtextdomain (PACKAGE, LOCALEDIR);
193 textdomain (PACKAGE);
195 initialize_exit_failure (EXPR_FAILURE);
196 atexit (close_stdout);
198 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
199 usage, AUTHORS, (char const *) NULL);
200 /* The above handles --help and --version.
201 Since there is no other invocation of getopt, handle `--' here. */
202 if (argc > 1 && STREQ (argv[1], "--"))
210 error (0, 0, _("missing operand"));
211 usage (EXPR_INVALID);
224 /* Return a VALUE for I. */
227 int_value (intmax_t i)
229 VALUE *v = xmalloc (sizeof *v);
235 /* Return a VALUE for S. */
238 str_value (char const *s)
240 VALUE *v = xmalloc (sizeof *v);
242 v->u.s = xstrdup (s);
246 /* Free VALUE V, including structure components. */
251 if (v->type == string)
262 char buf[INT_BUFSIZE_BOUND (intmax_t)];
267 p = imaxtostr (v->u.i, buf);
279 /* Return true if V is a null-string or zero-number. */
290 char const *cp = v->u.s;
310 /* Return true if CP takes the form of an integer. */
313 looks_like_integer (char const *cp)
325 /* Coerce V to a string value (can't fail). */
330 char buf[INT_BUFSIZE_BOUND (intmax_t)];
335 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
345 /* Coerce V to an integer value. Return true on success, false on failure. */
358 if (! looks_like_integer (v->u.s))
360 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
361 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
372 /* Return true and advance if the next token matches STR exactly.
373 STR must not be NULL. */
376 nextarg (char const *str)
382 bool r = STREQ (*args, str);
388 /* Return true if there no more tokens. */
397 /* Print evaluation trace and args remaining. */
406 for (a = args; *a; a++)
412 /* Do the : operator.
413 SV is the VALUE for the lhs (the string),
414 PV is the VALUE for the rhs (the pattern). */
417 docolon (VALUE *sv, VALUE *pv)
419 VALUE *v IF_LINT (= NULL);
421 struct re_pattern_buffer re_buffer;
422 char fastmap[UCHAR_MAX + 1];
423 struct re_registers re_regs;
429 re_regs.num_regs = 0;
430 re_regs.start = NULL;
433 re_buffer.buffer = NULL;
434 re_buffer.allocated = 0;
435 re_buffer.fastmap = fastmap;
436 re_buffer.translate = NULL;
438 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
439 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
441 error (EXPR_INVALID, 0, "%s", errmsg);
442 re_buffer.newline_anchor = 0;
444 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
447 /* Were \(...\) used? */
448 if (re_buffer.re_nsub > 0)
450 sv->u.s[re_regs.end[1]] = '\0';
451 v = str_value (sv->u.s + re_regs.start[1]);
454 v = int_value (matchlen);
456 else if (matchlen == -1)
458 /* Match failed -- return the right kind of null. */
459 if (re_buffer.re_nsub > 0)
466 (matchlen == -2 ? errno : EOVERFLOW),
467 _("error in regular expression matcher"));
469 if (0 < re_regs.num_regs)
471 free (re_regs.start);
474 re_buffer.fastmap = NULL;
475 regfree (&re_buffer);
479 /* Handle bare operands and ( expr ) syntax. */
482 eval7 (bool evaluate)
503 return str_value (*args++);
506 /* Handle match, substr, index, and length keywords, and quoting "+". */
509 eval6 (bool evaluate)
524 return str_value (*args++);
526 else if (nextarg ("length"))
528 r = eval6 (evaluate);
530 v = int_value (strlen (r->u.s));
534 else if (nextarg ("match"))
536 l = eval6 (evaluate);
537 r = eval6 (evaluate);
548 else if (nextarg ("index"))
550 l = eval6 (evaluate);
551 r = eval6 (evaluate);
554 v = int_value (strcspn (l->u.s, r->u.s) + 1);
555 if (v->u.i == strlen (l->u.s) + 1)
561 else if (nextarg ("substr"))
564 l = eval6 (evaluate);
565 i1 = eval6 (evaluate);
566 i2 = eval6 (evaluate);
568 llen = strlen (l->u.s);
569 if (!toarith (i1) || !toarith (i2)
571 || i1->u.i <= 0 || i2->u.i <= 0)
575 size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
577 v = xmalloc (sizeof *v);
579 v->u.s = xmalloc (vlen + 1);
580 vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
589 return eval7 (evaluate);
592 /* Handle : operator (pattern matching).
593 Calls docolon to do the real work. */
596 eval5 (bool evaluate)
605 l = eval6 (evaluate);
610 r = eval6 (evaluate);
624 /* Handle *, /, % operators. */
627 eval4 (bool evaluate)
631 enum { multiply, divide, mod } fxn;
637 l = eval5 (evaluate);
642 else if (nextarg ("/"))
644 else if (nextarg ("%"))
648 r = eval5 (evaluate);
651 if (!toarith (l) || !toarith (r))
652 error (EXPR_INVALID, 0, _("non-numeric argument"));
655 val = l->u.i * r->u.i;
656 if (! (l->u.i == 0 || r->u.i == 0
657 || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
658 && val / l->u.i == r->u.i)))
659 integer_overflow ('*');
664 error (EXPR_INVALID, 0, _("division by zero"));
665 if (l->u.i < - INTMAX_MAX && r->u.i == -1)
667 /* Some x86-style hosts raise an exception for
668 INT_MIN / -1 and INT_MIN % -1, so handle these
669 problematic cases specially. */
671 integer_overflow ('/');
675 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
684 /* Handle +, - operators. */
687 eval3 (bool evaluate)
691 enum { plus, minus } fxn;
697 l = eval4 (evaluate);
702 else if (nextarg ("-"))
706 r = eval4 (evaluate);
709 if (!toarith (l) || !toarith (r))
710 error (EXPR_INVALID, 0, _("non-numeric argument"));
713 val = l->u.i + r->u.i;
714 if ((val < l->u.i) != (r->u.i < 0))
715 integer_overflow ('+');
719 val = l->u.i - r->u.i;
720 if ((l->u.i < val) != (r->u.i < 0))
721 integer_overflow ('-');
730 /* Handle comparisons. */
733 eval2 (bool evaluate)
740 l = eval3 (evaluate);
746 less_than, less_equal, equal, not_equal, greater_equal, greater_than
752 else if (nextarg ("<="))
754 else if (nextarg ("=") || nextarg ("=="))
756 else if (nextarg ("!="))
758 else if (nextarg (">="))
760 else if (nextarg (">"))
764 r = eval3 (evaluate);
772 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
773 cmp = strintcmp (l->u.s, r->u.s);
777 cmp = strcoll (l->u.s, r->u.s);
781 error (0, errno, _("string comparison failed"));
782 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
783 error (EXPR_INVALID, 0,
784 _("The strings compared were %s and %s."),
785 quotearg_n_style (0, locale_quoting_style, l->u.s),
786 quotearg_n_style (1, locale_quoting_style, r->u.s));
792 case less_than: val = (cmp < 0); break;
793 case less_equal: val = (cmp <= 0); break;
794 case equal: val = (cmp == 0); break;
795 case not_equal: val = (cmp != 0); break;
796 case greater_equal: val = (cmp >= 0); break;
797 case greater_than: val = (cmp > 0); break;
811 eval1 (bool evaluate)
819 l = eval2 (evaluate);
824 r = eval2 (evaluate & ~ null (l));
825 if (null (l) || null (r))
850 l = eval1 (evaluate);
855 r = eval1 (evaluate & null (l));