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 /* The official name of this program (e.g., no `g' prefix). */
43 #define PROGRAM_NAME "expr"
45 #define AUTHORS "Mike Parker"
50 /* Invalid expression: i.e., its form does not conform to the
51 grammar for expressions. Our grammar is an extension of the
55 /* Some other error occurred. */
59 /* The kinds of value we can have. */
65 typedef enum valtype TYPE;
70 TYPE type; /* Which kind. */
72 { /* The value itself. */
77 typedef struct valinfo VALUE;
79 /* The arguments given to the program, minus the program name. */
82 /* The name this program was run with. */
85 static VALUE *eval (bool);
86 static bool nomoreargs (void);
87 static bool null (VALUE *v);
88 static void printv (VALUE *v);
93 if (status != EXIT_SUCCESS)
94 fprintf (stderr, _("Try `%s --help' for more information.\n"),
99 Usage: %s EXPRESSION\n\
102 program_name, program_name);
104 fputs (HELP_OPTION_DESCRIPTION, stdout);
105 fputs (VERSION_OPTION_DESCRIPTION, stdout);
108 Print the value of EXPRESSION to standard output. A blank line below\n\
109 separates increasing precedence groups. EXPRESSION may be:\n\
111 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
113 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
117 ARG1 < ARG2 ARG1 is less than ARG2\n\
118 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
119 ARG1 = ARG2 ARG1 is equal to ARG2\n\
120 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
121 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
122 ARG1 > ARG2 ARG1 is greater than ARG2\n\
126 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
127 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
131 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
132 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
133 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
137 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
139 match STRING REGEXP same as STRING : REGEXP\n\
140 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
141 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
142 length STRING length of STRING\n\
145 + TOKEN interpret TOKEN as a string, even if it is a\n\
146 keyword like `match' or an operator like `/'\n\
148 ( EXPRESSION ) value of EXPRESSION\n\
152 Beware that many operators need to be escaped or quoted for shells.\n\
153 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
154 Pattern matches return the string matched between \\( and \\) or null; if\n\
155 \\( and \\) are not used, they return the number of characters matched or 0.\n\
159 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
160 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
162 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
167 /* Report a syntax error and exit. */
171 error (EXPR_INVALID, 0, _("syntax error"));
175 main (int argc, char **argv)
179 initialize_main (&argc, &argv);
180 program_name = argv[0];
181 setlocale (LC_ALL, "");
182 bindtextdomain (PACKAGE, LOCALEDIR);
183 textdomain (PACKAGE);
185 initialize_exit_failure (EXPR_FAILURE);
186 atexit (close_stdout);
188 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
189 usage, AUTHORS, (char const *) NULL);
190 /* The above handles --help and --version.
191 Since there is no other invocation of getopt, handle `--' here. */
192 if (argc > 1 && STREQ (argv[1], "--"))
200 error (0, 0, _("missing operand"));
201 usage (EXPR_INVALID);
214 /* Return a VALUE for I. */
217 int_value (intmax_t i)
219 VALUE *v = xmalloc (sizeof *v);
225 /* Return a VALUE for S. */
230 VALUE *v = xmalloc (sizeof *v);
232 v->u.s = xstrdup (s);
236 /* Free VALUE V, including structure components. */
241 if (v->type == string)
252 char buf[INT_BUFSIZE_BOUND (intmax_t)];
257 p = imaxtostr (v->u.i, buf);
269 /* Return true if V is a null-string or zero-number. */
280 char const *cp = v->u.s;
300 /* Coerce V to a string value (can't fail). */
305 char buf[INT_BUFSIZE_BOUND (intmax_t)];
310 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
320 /* Coerce V to an integer value. Return true on success, false on failure. */
333 int sign = (*cp == '-' ? -1 : 1);
342 intmax_t new_v = 10 * value + sign * (*cp - '0');
344 ? (INTMAX_MAX / 10 < value || new_v < 0)
345 : (value < INTMAX_MIN / 10 || 0 < new_v))
346 error (EXPR_FAILURE, 0,
348 ? _("integer is too large: %s")
349 : _("integer is too small: %s")),
350 quotearg_colon (v->u.s));
359 v->u.i = value * sign;
368 /* Return true and advance if the next token matches STR exactly.
369 STR must not be NULL. */
372 nextarg (char const *str)
378 bool r = STREQ (*args, str);
384 /* Return true if there no more tokens. */
393 /* Print evaluation trace and args remaining. */
402 for (a = args; *a; a++)
408 /* Do the : operator.
409 SV is the VALUE for the lhs (the string),
410 PV is the VALUE for the rhs (the pattern). */
413 docolon (VALUE *sv, VALUE *pv)
417 struct re_pattern_buffer re_buffer;
418 struct re_registers re_regs;
425 if (pv->u.s[0] == '^')
428 warning: unportable BRE: `%s': using `^' as the first character\n\
429 of the basic regular expression is not portable; it is being ignored"),
433 len = strlen (pv->u.s);
434 memset (&re_buffer, 0, sizeof (re_buffer));
435 memset (&re_regs, 0, sizeof (re_regs));
436 re_buffer.allocated = 2 * len;
437 if (re_buffer.allocated < len)
439 re_buffer.buffer = xmalloc (re_buffer.allocated);
440 re_buffer.translate = NULL;
441 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
442 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
444 error (EXPR_FAILURE, 0, "%s", errmsg);
446 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
449 /* Were \(...\) used? */
450 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
452 sv->u.s[re_regs.end[1]] = '\0';
453 v = str_value (sv->u.s + re_regs.start[1]);
456 v = int_value (matchlen);
460 /* Match failed -- return the right kind of null. */
461 if (re_buffer.re_nsub > 0)
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)
699 less_than, less_equal, equal, not_equal, greater_equal, greater_than
705 char *collation_arg1;
710 l = eval3 (evaluate);
715 else if (nextarg ("<="))
717 else if (nextarg ("=") || nextarg ("=="))
719 else if (nextarg ("!="))
721 else if (nextarg (">="))
723 else if (nextarg (">"))
727 r = eval3 (evaluate);
731 /* Save the first arg to strcoll, in case we need its value for
732 a diagnostic later. This is needed because 'toarith' might
733 free the first arg. */
734 collation_arg1 = xstrdup (l->u.s);
737 lval = strcoll (collation_arg1, r->u.s);
738 collation_errno = errno;
740 if (toarith (l) && toarith (r))
745 else if (collation_errno && evaluate)
747 error (0, collation_errno, _("string comparison failed"));
748 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
749 error (EXPR_FAILURE, 0,
750 _("The strings compared were %s and %s."),
751 quotearg_n_style (0, locale_quoting_style, collation_arg1),
752 quotearg_n_style (1, locale_quoting_style, r->u.s));
757 case less_than: val = (lval < rval); break;
758 case less_equal: val = (lval <= rval); break;
759 case equal: val = (lval == rval); break;
760 case not_equal: val = (lval != rval); break;
761 case greater_equal: val = (lval >= rval); break;
762 case greater_than: val = (lval > rval); break;
767 free (collation_arg1);
775 eval1 (bool evaluate)
783 l = eval2 (evaluate);
788 r = eval2 (evaluate & ~ null (l));
789 if (null (l) || null (r))
814 l = eval1 (evaluate);
819 r = eval1 (evaluate & null (l));