1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2006 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"
42 #include "strnumcmp.h"
45 /* The official name of this program (e.g., no `g' prefix). */
46 #define PROGRAM_NAME "expr"
48 #define AUTHORS "Mike Parker"
53 /* Invalid expression: e.g., its form does not conform to the
54 grammar for expressions. Our grammar is an extension of the
58 /* An internal error occurred, e.g., arithmetic overflow, storage
63 /* The kinds of value we can have. */
69 typedef enum valtype TYPE;
74 TYPE type; /* Which kind. */
76 { /* The value itself. */
81 typedef struct valinfo VALUE;
83 /* The arguments given to the program, minus the program name. */
86 /* The name this program was run with. */
89 static VALUE *eval (bool);
90 static bool nomoreargs (void);
91 static bool null (VALUE *v);
92 static void printv (VALUE *v);
97 if (status != EXIT_SUCCESS)
98 fprintf (stderr, _("Try `%s --help' for more information.\n"),
103 Usage: %s EXPRESSION\n\
106 program_name, program_name);
108 fputs (HELP_OPTION_DESCRIPTION, stdout);
109 fputs (VERSION_OPTION_DESCRIPTION, stdout);
112 Print the value of EXPRESSION to standard output. A blank line below\n\
113 separates increasing precedence groups. EXPRESSION may be:\n\
115 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
117 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
121 ARG1 < ARG2 ARG1 is less than ARG2\n\
122 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
123 ARG1 = ARG2 ARG1 is equal to ARG2\n\
124 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
125 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
126 ARG1 > ARG2 ARG1 is greater than ARG2\n\
130 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
131 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
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 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
171 /* Report a syntax error and exit. */
175 error (EXPR_INVALID, 0, _("syntax error"));
179 main (int argc, char **argv)
183 initialize_main (&argc, &argv);
184 program_name = argv[0];
185 setlocale (LC_ALL, "");
186 bindtextdomain (PACKAGE, LOCALEDIR);
187 textdomain (PACKAGE);
189 initialize_exit_failure (EXPR_FAILURE);
190 atexit (close_stdout);
192 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
193 usage, AUTHORS, (char const *) NULL);
194 /* The above handles --help and --version.
195 Since there is no other invocation of getopt, handle `--' here. */
196 if (argc > 1 && STREQ (argv[1], "--"))
204 error (0, 0, _("missing operand"));
205 usage (EXPR_INVALID);
218 /* Return a VALUE for I. */
221 int_value (intmax_t i)
223 VALUE *v = xmalloc (sizeof *v);
229 /* Return a VALUE for S. */
234 VALUE *v = xmalloc (sizeof *v);
236 v->u.s = xstrdup (s);
240 /* Free VALUE V, including structure components. */
245 if (v->type == string)
256 char buf[INT_BUFSIZE_BOUND (intmax_t)];
261 p = imaxtostr (v->u.i, buf);
273 /* Return true if V is a null-string or zero-number. */
284 char const *cp = v->u.s;
304 /* Return true if CP takes the form of an integer. */
307 looks_like_integer (char const *cp)
319 /* Coerce V to a string value (can't fail). */
324 char buf[INT_BUFSIZE_BOUND (intmax_t)];
329 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
339 /* Coerce V to an integer value. Return true on success, false on failure. */
352 if (! looks_like_integer (v->u.s))
354 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
355 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
366 /* Return true and advance if the next token matches STR exactly.
367 STR must not be NULL. */
370 nextarg (char const *str)
376 bool r = STREQ (*args, str);
382 /* Return true if there no more tokens. */
391 /* Print evaluation trace and args remaining. */
400 for (a = args; *a; a++)
406 /* Do the : operator.
407 SV is the VALUE for the lhs (the string),
408 PV is the VALUE for the rhs (the pattern). */
411 docolon (VALUE *sv, VALUE *pv)
413 VALUE *v IF_LINT (= NULL);
415 struct re_pattern_buffer re_buffer;
416 char fastmap[UCHAR_MAX + 1];
417 struct re_registers re_regs;
423 re_buffer.buffer = NULL;
424 re_buffer.allocated = 0;
425 re_buffer.fastmap = fastmap;
426 re_buffer.translate = NULL;
427 re_syntax_options = RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP;
428 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
430 error (EXPR_INVALID, 0, "%s", errmsg);
431 re_buffer.newline_anchor = 0;
433 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
436 /* Were \(...\) used? */
437 if (re_buffer.re_nsub > 0)
439 sv->u.s[re_regs.end[1]] = '\0';
440 v = str_value (sv->u.s + re_regs.start[1]);
443 v = int_value (matchlen);
445 else if (matchlen == -1)
447 /* Match failed -- return the right kind of null. */
448 if (re_buffer.re_nsub > 0)
455 (matchlen == -2 ? errno : EOVERFLOW),
456 _("error in regular expression matcher"));
458 free (re_buffer.buffer);
462 /* Handle bare operands and ( expr ) syntax. */
465 eval7 (bool evaluate)
486 return str_value (*args++);
489 /* Handle match, substr, index, and length keywords, and quoting "+". */
492 eval6 (bool evaluate)
507 return str_value (*args++);
509 else if (nextarg ("length"))
511 r = eval6 (evaluate);
513 v = int_value (strlen (r->u.s));
517 else if (nextarg ("match"))
519 l = eval6 (evaluate);
520 r = eval6 (evaluate);
531 else if (nextarg ("index"))
533 l = eval6 (evaluate);
534 r = eval6 (evaluate);
537 v = int_value (strcspn (l->u.s, r->u.s) + 1);
538 if (v->u.i == strlen (l->u.s) + 1)
544 else if (nextarg ("substr"))
546 l = eval6 (evaluate);
547 i1 = eval6 (evaluate);
548 i2 = eval6 (evaluate);
550 if (!toarith (i1) || !toarith (i2)
551 || strlen (l->u.s) < i1->u.i
552 || i1->u.i <= 0 || i2->u.i <= 0)
556 v = xmalloc (sizeof *v);
558 v->u.s = strncpy (xmalloc (i2->u.i + 1),
559 l->u.s + i1->u.i - 1, i2->u.i);
568 return eval7 (evaluate);
571 /* Handle : operator (pattern matching).
572 Calls docolon to do the real work. */
575 eval5 (bool evaluate)
584 l = eval6 (evaluate);
589 r = eval6 (evaluate);
603 /* Handle *, /, % operators. */
606 eval4 (bool evaluate)
610 enum { multiply, divide, mod } fxn;
616 l = eval5 (evaluate);
621 else if (nextarg ("/"))
623 else if (nextarg ("%"))
627 r = eval5 (evaluate);
630 if (!toarith (l) || !toarith (r))
631 error (EXPR_INVALID, 0, _("non-numeric argument"));
633 val = l->u.i * r->u.i;
637 error (EXPR_INVALID, 0, _("division by zero"));
638 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
647 /* Handle +, - operators. */
650 eval3 (bool evaluate)
654 enum { plus, minus } fxn;
660 l = eval4 (evaluate);
665 else if (nextarg ("-"))
669 r = eval4 (evaluate);
672 if (!toarith (l) || !toarith (r))
673 error (EXPR_INVALID, 0, _("non-numeric argument"));
674 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
682 /* Handle comparisons. */
685 eval2 (bool evaluate)
692 l = eval3 (evaluate);
698 less_than, less_equal, equal, not_equal, greater_equal, greater_than
704 else if (nextarg ("<="))
706 else if (nextarg ("=") || nextarg ("=="))
708 else if (nextarg ("!="))
710 else if (nextarg (">="))
712 else if (nextarg (">"))
716 r = eval3 (evaluate);
724 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
725 cmp = strintcmp (l->u.s, r->u.s);
729 cmp = strcoll (l->u.s, r->u.s);
733 error (0, errno, _("string comparison failed"));
734 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
735 error (EXPR_INVALID, 0,
736 _("The strings compared were %s and %s."),
737 quotearg_n_style (0, locale_quoting_style, l->u.s),
738 quotearg_n_style (1, locale_quoting_style, r->u.s));
744 case less_than: val = (cmp < 0); break;
745 case less_equal: val = (cmp <= 0); break;
746 case equal: val = (cmp == 0); break;
747 case not_equal: val = (cmp != 0); break;
748 case greater_equal: val = (cmp >= 0); break;
749 case greater_than: val = (cmp > 0); break;
763 eval1 (bool evaluate)
771 l = eval2 (evaluate);
776 r = eval2 (evaluate & ~ null (l));
777 if (null (l) || null (r))
802 l = eval1 (evaluate);
807 r = eval1 (evaluate & null (l));