1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2005 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: i.e., its form does not conform to the
54 grammar for expressions. Our grammar is an extension of the
58 /* Some other error occurred. */
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 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
170 /* Report a syntax error and exit. */
174 error (EXPR_INVALID, 0, _("syntax error"));
178 main (int argc, char **argv)
182 initialize_main (&argc, &argv);
183 program_name = argv[0];
184 setlocale (LC_ALL, "");
185 bindtextdomain (PACKAGE, LOCALEDIR);
186 textdomain (PACKAGE);
188 initialize_exit_failure (EXPR_FAILURE);
189 atexit (close_stdout);
191 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
192 usage, AUTHORS, (char const *) NULL);
193 /* The above handles --help and --version.
194 Since there is no other invocation of getopt, handle `--' here. */
195 if (argc > 1 && STREQ (argv[1], "--"))
203 error (0, 0, _("missing operand"));
204 usage (EXPR_INVALID);
217 /* Return a VALUE for I. */
220 int_value (intmax_t i)
222 VALUE *v = xmalloc (sizeof *v);
228 /* Return a VALUE for S. */
233 VALUE *v = xmalloc (sizeof *v);
235 v->u.s = xstrdup (s);
239 /* Free VALUE V, including structure components. */
244 if (v->type == string)
255 char buf[INT_BUFSIZE_BOUND (intmax_t)];
260 p = imaxtostr (v->u.i, buf);
272 /* Return true if V is a null-string or zero-number. */
283 char const *cp = v->u.s;
303 /* Return true if CP takes the form of an integer. */
306 looks_like_integer (char const *cp)
318 /* Coerce V to a string value (can't fail). */
323 char buf[INT_BUFSIZE_BOUND (intmax_t)];
328 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
338 /* Coerce V to an integer value. Return true on success, false on failure. */
351 if (! looks_like_integer (v->u.s))
353 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
354 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
365 /* Return true and advance if the next token matches STR exactly.
366 STR must not be NULL. */
369 nextarg (char const *str)
375 bool r = STREQ (*args, str);
381 /* Return true if there no more tokens. */
390 /* Print evaluation trace and args remaining. */
399 for (a = args; *a; a++)
405 /* Do the : operator.
406 SV is the VALUE for the lhs (the string),
407 PV is the VALUE for the rhs (the pattern). */
410 docolon (VALUE *sv, VALUE *pv)
412 VALUE *v IF_LINT (= NULL);
414 struct re_pattern_buffer re_buffer;
415 struct re_registers re_regs;
422 if (pv->u.s[0] == '^')
425 warning: unportable BRE: %s: using `^' as the first character\n\
426 of the basic regular expression is not portable; it is being ignored"),
430 len = strlen (pv->u.s);
431 memset (&re_buffer, 0, sizeof (re_buffer));
432 memset (&re_regs, 0, sizeof (re_regs));
433 re_buffer.buffer = xnmalloc (len, 2);
434 re_buffer.allocated = 2 * len;
435 re_buffer.translate = NULL;
436 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
437 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
439 error (EXPR_FAILURE, 0, "%s", errmsg);
441 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
444 /* Were \(...\) used? */
445 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
447 sv->u.s[re_regs.end[1]] = '\0';
448 v = str_value (sv->u.s + re_regs.start[1]);
451 v = int_value (matchlen);
453 else if (matchlen == -1)
455 /* Match failed -- return the right kind of null. */
456 if (re_buffer.re_nsub > 0)
463 (matchlen == -2 ? errno : EOVERFLOW),
464 _("error in regular expression matcher"));
466 free (re_buffer.buffer);
470 /* Handle bare operands and ( expr ) syntax. */
473 eval7 (bool evaluate)
494 return str_value (*args++);
497 /* Handle match, substr, index, and length keywords, and quoting "+". */
500 eval6 (bool evaluate)
515 return str_value (*args++);
517 else if (nextarg ("length"))
519 r = eval6 (evaluate);
521 v = int_value (strlen (r->u.s));
525 else if (nextarg ("match"))
527 l = eval6 (evaluate);
528 r = eval6 (evaluate);
539 else if (nextarg ("index"))
541 l = eval6 (evaluate);
542 r = eval6 (evaluate);
545 v = int_value (strcspn (l->u.s, r->u.s) + 1);
546 if (v->u.i == strlen (l->u.s) + 1)
552 else if (nextarg ("substr"))
554 l = eval6 (evaluate);
555 i1 = eval6 (evaluate);
556 i2 = eval6 (evaluate);
558 if (!toarith (i1) || !toarith (i2)
559 || strlen (l->u.s) < i1->u.i
560 || i1->u.i <= 0 || i2->u.i <= 0)
564 v = xmalloc (sizeof *v);
566 v->u.s = strncpy (xmalloc (i2->u.i + 1),
567 l->u.s + i1->u.i - 1, i2->u.i);
576 return eval7 (evaluate);
579 /* Handle : operator (pattern matching).
580 Calls docolon to do the real work. */
583 eval5 (bool evaluate)
592 l = eval6 (evaluate);
597 r = eval6 (evaluate);
611 /* Handle *, /, % operators. */
614 eval4 (bool evaluate)
618 enum { multiply, divide, mod } fxn;
624 l = eval5 (evaluate);
629 else if (nextarg ("/"))
631 else if (nextarg ("%"))
635 r = eval5 (evaluate);
638 if (!toarith (l) || !toarith (r))
639 error (EXPR_FAILURE, 0, _("non-numeric argument"));
641 val = l->u.i * r->u.i;
645 error (EXPR_FAILURE, 0, _("division by zero"));
646 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
655 /* Handle +, - operators. */
658 eval3 (bool evaluate)
662 enum { plus, minus } fxn;
668 l = eval4 (evaluate);
673 else if (nextarg ("-"))
677 r = eval4 (evaluate);
680 if (!toarith (l) || !toarith (r))
681 error (EXPR_FAILURE, 0, _("non-numeric argument"));
682 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
690 /* Handle comparisons. */
693 eval2 (bool evaluate)
700 l = eval3 (evaluate);
706 less_than, less_equal, equal, not_equal, greater_equal, greater_than
712 else if (nextarg ("<="))
714 else if (nextarg ("=") || nextarg ("=="))
716 else if (nextarg ("!="))
718 else if (nextarg (">="))
720 else if (nextarg (">"))
724 r = eval3 (evaluate);
732 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
733 cmp = strintcmp (l->u.s, r->u.s);
737 cmp = strcoll (l->u.s, r->u.s);
741 error (0, errno, _("string comparison failed"));
742 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
743 error (EXPR_FAILURE, 0,
744 _("The strings compared were %s and %s."),
745 quotearg_n_style (0, locale_quoting_style, l->u.s),
746 quotearg_n_style (1, locale_quoting_style, r->u.s));
752 case less_than: val = (cmp < 0); break;
753 case less_equal: val = (cmp <= 0); break;
754 case equal: val = (cmp == 0); break;
755 case not_equal: val = (cmp != 0); break;
756 case greater_equal: val = (cmp >= 0); break;
757 case greater_than: val = (cmp > 0); break;
771 eval1 (bool evaluate)
779 l = eval2 (evaluate);
784 r = eval2 (evaluate & ~ null (l));
785 if (null (l) || null (r))
810 l = eval1 (evaluate);
815 r = eval1 (evaluate & null (l));