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"
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: i.e., its form does not conform to the
53 grammar for expressions. Our grammar is an extension of the
57 /* Some other error occurred. */
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 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
169 /* Report a syntax error and exit. */
173 error (EXPR_INVALID, 0, _("syntax error"));
177 main (int argc, char **argv)
181 initialize_main (&argc, &argv);
182 program_name = argv[0];
183 setlocale (LC_ALL, "");
184 bindtextdomain (PACKAGE, LOCALEDIR);
185 textdomain (PACKAGE);
187 initialize_exit_failure (EXPR_FAILURE);
188 atexit (close_stdout);
190 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
191 usage, AUTHORS, (char const *) NULL);
192 /* The above handles --help and --version.
193 Since there is no other invocation of getopt, handle `--' here. */
194 if (argc > 1 && STREQ (argv[1], "--"))
202 error (0, 0, _("missing operand"));
203 usage (EXPR_INVALID);
216 /* Return a VALUE for I. */
219 int_value (intmax_t i)
221 VALUE *v = xmalloc (sizeof *v);
227 /* Return a VALUE for S. */
232 VALUE *v = xmalloc (sizeof *v);
234 v->u.s = xstrdup (s);
238 /* Free VALUE V, including structure components. */
243 if (v->type == string)
254 char buf[INT_BUFSIZE_BOUND (intmax_t)];
259 p = imaxtostr (v->u.i, buf);
271 /* Return true if V is a null-string or zero-number. */
282 char const *cp = v->u.s;
302 /* Return true if CP takes the form of an integer. */
305 looks_like_integer (char const *cp)
317 /* Coerce V to a string value (can't fail). */
322 char buf[INT_BUFSIZE_BOUND (intmax_t)];
327 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
337 /* Coerce V to an integer value. Return true on success, false on failure. */
350 if (! looks_like_integer (v->u.s))
352 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
353 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
364 /* Return true and advance if the next token matches STR exactly.
365 STR must not be NULL. */
368 nextarg (char const *str)
374 bool r = STREQ (*args, str);
380 /* Return true if there no more tokens. */
389 /* Print evaluation trace and args remaining. */
398 for (a = args; *a; a++)
404 /* Do the : operator.
405 SV is the VALUE for the lhs (the string),
406 PV is the VALUE for the rhs (the pattern). */
409 docolon (VALUE *sv, VALUE *pv)
413 struct re_pattern_buffer re_buffer;
414 struct re_registers re_regs;
421 if (pv->u.s[0] == '^')
424 warning: unportable BRE: `%s': using `^' as the first character\n\
425 of the basic regular expression is not portable; it is being ignored"),
429 len = strlen (pv->u.s);
430 memset (&re_buffer, 0, sizeof (re_buffer));
431 memset (&re_regs, 0, sizeof (re_regs));
432 re_buffer.allocated = 2 * len;
433 if (re_buffer.allocated < len)
435 re_buffer.buffer = xmalloc (re_buffer.allocated);
436 re_buffer.translate = NULL;
437 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
438 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
440 error (EXPR_FAILURE, 0, "%s", errmsg);
442 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
445 /* Were \(...\) used? */
446 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
448 sv->u.s[re_regs.end[1]] = '\0';
449 v = str_value (sv->u.s + re_regs.start[1]);
452 v = int_value (matchlen);
456 /* Match failed -- return the right kind of null. */
457 if (re_buffer.re_nsub > 0)
462 free (re_buffer.buffer);
466 /* Handle bare operands and ( expr ) syntax. */
469 eval7 (bool evaluate)
490 return str_value (*args++);
493 /* Handle match, substr, index, and length keywords, and quoting "+". */
496 eval6 (bool evaluate)
511 return str_value (*args++);
513 else if (nextarg ("length"))
515 r = eval6 (evaluate);
517 v = int_value (strlen (r->u.s));
521 else if (nextarg ("match"))
523 l = eval6 (evaluate);
524 r = eval6 (evaluate);
535 else if (nextarg ("index"))
537 l = eval6 (evaluate);
538 r = eval6 (evaluate);
541 v = int_value (strcspn (l->u.s, r->u.s) + 1);
542 if (v->u.i == strlen (l->u.s) + 1)
548 else if (nextarg ("substr"))
550 l = eval6 (evaluate);
551 i1 = eval6 (evaluate);
552 i2 = eval6 (evaluate);
554 if (!toarith (i1) || !toarith (i2)
555 || strlen (l->u.s) < i1->u.i
556 || i1->u.i <= 0 || i2->u.i <= 0)
560 v = xmalloc (sizeof *v);
562 v->u.s = strncpy (xmalloc (i2->u.i + 1),
563 l->u.s + i1->u.i - 1, i2->u.i);
572 return eval7 (evaluate);
575 /* Handle : operator (pattern matching).
576 Calls docolon to do the real work. */
579 eval5 (bool evaluate)
588 l = eval6 (evaluate);
593 r = eval6 (evaluate);
607 /* Handle *, /, % operators. */
610 eval4 (bool evaluate)
614 enum { multiply, divide, mod } fxn;
620 l = eval5 (evaluate);
625 else if (nextarg ("/"))
627 else if (nextarg ("%"))
631 r = eval5 (evaluate);
634 if (!toarith (l) || !toarith (r))
635 error (EXPR_FAILURE, 0, _("non-numeric argument"));
637 val = l->u.i * r->u.i;
641 error (EXPR_FAILURE, 0, _("division by zero"));
642 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
651 /* Handle +, - operators. */
654 eval3 (bool evaluate)
658 enum { plus, minus } fxn;
664 l = eval4 (evaluate);
669 else if (nextarg ("-"))
673 r = eval4 (evaluate);
676 if (!toarith (l) || !toarith (r))
677 error (EXPR_FAILURE, 0, _("non-numeric argument"));
678 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
686 /* Handle comparisons. */
689 eval2 (bool evaluate)
696 l = eval3 (evaluate);
702 less_than, less_equal, equal, not_equal, greater_equal, greater_than
708 else if (nextarg ("<="))
710 else if (nextarg ("=") || nextarg ("=="))
712 else if (nextarg ("!="))
714 else if (nextarg (">="))
716 else if (nextarg (">"))
720 r = eval3 (evaluate);
728 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
729 cmp = strintcmp (l->u.s, r->u.s);
733 cmp = strcoll (l->u.s, r->u.s);
737 error (0, errno, _("string comparison failed"));
738 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
739 error (EXPR_FAILURE, 0,
740 _("The strings compared were %s and %s."),
741 quotearg_n_style (0, locale_quoting_style, l->u.s),
742 quotearg_n_style (1, locale_quoting_style, r->u.s));
748 case less_than: val = (cmp < 0); break;
749 case less_equal: val = (cmp <= 0); break;
750 case equal: val = (cmp == 0); break;
751 case not_equal: val = (cmp != 0); break;
752 case greater_equal: val = (cmp >= 0); break;
753 case greater_than: val = (cmp > 0); break;
767 eval1 (bool evaluate)
775 l = eval2 (evaluate);
780 r = eval2 (evaluate & ~ null (l));
781 if (null (l) || null (r))
806 l = eval1 (evaluate);
811 r = eval1 (evaluate & null (l));