1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2004 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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\
157 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
162 /* Report a syntax error and exit. */
166 error (EXPR_INVALID, 0, _("syntax error"));
170 main (int argc, char **argv)
174 initialize_main (&argc, &argv);
175 program_name = argv[0];
176 setlocale (LC_ALL, "");
177 bindtextdomain (PACKAGE, LOCALEDIR);
178 textdomain (PACKAGE);
180 initialize_exit_failure (EXPR_FAILURE);
181 atexit (close_stdout);
183 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
184 usage, AUTHORS, (char const *) NULL);
185 /* The above handles --help and --version.
186 Since there is no other invocation of getopt, handle `--' here. */
187 if (argc > 1 && STREQ (argv[1], "--"))
195 error (0, 0, _("missing operand"));
196 usage (EXPR_INVALID);
209 /* Return a VALUE for I. */
212 int_value (intmax_t i)
214 VALUE *v = xmalloc (sizeof *v);
220 /* Return a VALUE for S. */
225 VALUE *v = xmalloc (sizeof *v);
227 v->u.s = xstrdup (s);
231 /* Free VALUE V, including structure components. */
236 if (v->type == string)
247 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
252 p = imaxtostr (v->u.i, buf);
264 /* Return true if V is a null-string or zero-number. */
275 char const *cp = v->u.s;
295 /* Coerce V to a string value (can't fail). */
300 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
305 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
315 /* Coerce V to an integer value. Return true on success, false on failure. */
338 i = i * 10 + *cp - '0';
345 v->u.i = i * (neg ? -1 : 1);
353 /* Return true and advance if the next token matches STR exactly.
354 STR must not be NULL. */
357 nextarg (char const *str)
363 bool r = STREQ (*args, str);
369 /* Return true if there no more tokens. */
378 /* Print evaluation trace and args remaining. */
387 for (a = args; *a; a++)
393 /* Do the : operator.
394 SV is the VALUE for the lhs (the string),
395 PV is the VALUE for the rhs (the pattern). */
398 docolon (VALUE *sv, VALUE *pv)
402 struct re_pattern_buffer re_buffer;
403 struct re_registers re_regs;
410 if (pv->u.s[0] == '^')
413 warning: unportable BRE: `%s': using `^' as the first character\n\
414 of the basic regular expression is not portable; it is being ignored"),
418 len = strlen (pv->u.s);
419 memset (&re_buffer, 0, sizeof (re_buffer));
420 memset (&re_regs, 0, sizeof (re_regs));
421 re_buffer.allocated = 2 * len;
422 if (re_buffer.allocated < len)
424 re_buffer.buffer = xmalloc (re_buffer.allocated);
425 re_buffer.translate = 0;
426 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
427 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
429 error (EXPR_FAILURE, 0, "%s", errmsg);
431 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
434 /* Were \(...\) used? */
435 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
437 sv->u.s[re_regs.end[1]] = '\0';
438 v = str_value (sv->u.s + re_regs.start[1]);
441 v = int_value (matchlen);
445 /* Match failed -- return the right kind of null. */
446 if (re_buffer.re_nsub > 0)
451 free (re_buffer.buffer);
455 /* Handle bare operands and ( expr ) syntax. */
458 eval7 (bool evaluate)
479 return str_value (*args++);
482 /* Handle match, substr, index, and length keywords, and quoting "+". */
485 eval6 (bool evaluate)
500 return str_value (*args++);
502 else if (nextarg ("length"))
504 r = eval6 (evaluate);
506 v = int_value (strlen (r->u.s));
510 else if (nextarg ("match"))
512 l = eval6 (evaluate);
513 r = eval6 (evaluate);
524 else if (nextarg ("index"))
526 l = eval6 (evaluate);
527 r = eval6 (evaluate);
530 v = int_value (strcspn (l->u.s, r->u.s) + 1);
531 if (v->u.i == strlen (l->u.s) + 1)
537 else if (nextarg ("substr"))
539 l = eval6 (evaluate);
540 i1 = eval6 (evaluate);
541 i2 = eval6 (evaluate);
543 if (!toarith (i1) || !toarith (i2)
544 || strlen (l->u.s) < i1->u.i
545 || i1->u.i <= 0 || i2->u.i <= 0)
549 v = xmalloc (sizeof *v);
551 v->u.s = strncpy (xmalloc (i2->u.i + 1),
552 l->u.s + i1->u.i - 1, i2->u.i);
561 return eval7 (evaluate);
564 /* Handle : operator (pattern matching).
565 Calls docolon to do the real work. */
568 eval5 (bool evaluate)
577 l = eval6 (evaluate);
582 r = eval6 (evaluate);
596 /* Handle *, /, % operators. */
599 eval4 (bool evaluate)
603 enum { multiply, divide, mod } fxn;
609 l = eval5 (evaluate);
614 else if (nextarg ("/"))
616 else if (nextarg ("%"))
620 r = eval5 (evaluate);
623 if (!toarith (l) || !toarith (r))
624 error (EXPR_FAILURE, 0, _("non-numeric argument"));
626 val = l->u.i * r->u.i;
630 error (EXPR_FAILURE, 0, _("division by zero"));
631 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
640 /* Handle +, - operators. */
643 eval3 (bool evaluate)
647 enum { plus, minus } fxn;
653 l = eval4 (evaluate);
658 else if (nextarg ("-"))
662 r = eval4 (evaluate);
665 if (!toarith (l) || !toarith (r))
666 error (EXPR_FAILURE, 0, _("non-numeric argument"));
667 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
675 /* Handle comparisons. */
678 eval2 (bool evaluate)
684 less_than, less_equal, equal, not_equal, greater_equal, greater_than
690 char *collation_arg1;
695 l = eval3 (evaluate);
700 else if (nextarg ("<="))
702 else if (nextarg ("=") || nextarg ("=="))
704 else if (nextarg ("!="))
706 else if (nextarg (">="))
708 else if (nextarg (">"))
712 r = eval3 (evaluate);
716 /* Save the first arg to strcoll, in case we need its value for
717 a diagnostic later. This is needed because 'toarith' might
718 free the first arg. */
719 collation_arg1 = xstrdup (l->u.s);
722 lval = strcoll (collation_arg1, r->u.s);
723 collation_errno = errno;
725 if (toarith (l) && toarith (r))
730 else if (collation_errno && evaluate)
732 error (0, collation_errno, _("string comparison failed"));
733 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
734 error (EXPR_FAILURE, 0,
735 _("The strings compared were %s and %s."),
736 quotearg_n_style (0, locale_quoting_style, collation_arg1),
737 quotearg_n_style (1, locale_quoting_style, r->u.s));
742 case less_than: val = (lval < rval); break;
743 case less_equal: val = (lval <= rval); break;
744 case equal: val = (lval == rval); break;
745 case not_equal: val = (lval != rval); break;
746 case greater_equal: val = (lval >= rval); break;
747 case greater_than: val = (lval > rval); break;
752 free (collation_arg1);
760 eval1 (bool evaluate)
768 l = eval2 (evaluate);
773 r = eval2 (evaluate & ~ null (l));
774 if (null (l) || null (r))
799 l = eval1 (evaluate);
804 r = eval1 (evaluate & null (l));