1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2003 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"
43 /* The official name of this program (e.g., no `g' prefix). */
44 #define PROGRAM_NAME "expr"
46 #define AUTHORS "Mike Parker"
49 #define NEW(Type) XMALLOC (Type, 1)
50 #define OLD(x) free (x)
55 /* Invalid expression: i.e., its form does not conform to the
56 grammar for expressions. Our grammar is an extension of the
60 /* Some other error occurred. */
64 /* The kinds of value we can have. */
70 typedef enum valtype TYPE;
75 TYPE type; /* Which kind. */
77 { /* The value itself. */
82 typedef struct valinfo VALUE;
84 /* The arguments given to the program, minus the program name. */
87 /* The name this program was run with. */
90 static VALUE *eval (void);
91 static bool nomoreargs (void);
92 static bool null (VALUE *v);
93 static void printv (VALUE *v);
99 fprintf (stderr, _("Try `%s --help' for more information.\n"),
104 Usage: %s EXPRESSION\n\
107 program_name, program_name);
109 fputs (HELP_OPTION_DESCRIPTION, stdout);
110 fputs (VERSION_OPTION_DESCRIPTION, stdout);
113 Print the value of EXPRESSION to standard output. A blank line below\n\
114 separates increasing precedence groups. EXPRESSION may be:\n\
116 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
118 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
122 ARG1 < ARG2 ARG1 is less than ARG2\n\
123 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
124 ARG1 = ARG2 ARG1 is equal to ARG2\n\
125 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
126 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
127 ARG1 > ARG2 ARG1 is greater than ARG2\n\
131 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
132 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
136 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
137 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
138 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
142 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
144 match STRING REGEXP same as STRING : REGEXP\n\
145 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
146 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
147 length STRING length of STRING\n\
150 + TOKEN interpret TOKEN as a string, even if it is a\n\
151 keyword like `match' or an operator like `/'\n\
153 ( EXPRESSION ) value of EXPRESSION\n\
157 Beware that many operators need to be escaped or quoted for shells.\n\
158 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
159 Pattern matches return the string matched between \\( and \\) or null; if\n\
160 \\( and \\) are not used, they return the number of characters matched or 0.\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 /* Change the way library functions fail. */
186 exit_failure = EXPR_ERROR;
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, _("too few arguments"));
203 usage (EXPR_INVALID);
216 /* Return a VALUE for I. */
219 int_value (intmax_t i)
229 /* Return a VALUE for S. */
238 v->u.s = xstrdup (s);
242 /* Free VALUE V, including structure components. */
247 if (v->type == string)
258 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
263 p = imaxtostr (v->u.i, buf);
275 /* Return true if V is a null-string or zero-number. */
285 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
291 /* Coerce V to a string value (can't fail). */
296 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
301 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
311 /* Coerce V to an integer value. Return true on success, false on failure. */
334 i = i * 10 + *cp - '0';
341 v->u.i = i * (neg ? -1 : 1);
349 /* Return nonzero and advance if the next token matches STR exactly.
350 STR must not be NULL. */
353 nextarg (char const *str)
359 bool r = strcmp (*args, str) == 0;
365 /* Return true if there no more tokens. */
374 /* Print evaluation trace and args remaining. */
383 for (a = args; *a; a++)
389 /* Do the : operator.
390 SV is the VALUE for the lhs (the string),
391 PV is the VALUE for the rhs (the pattern). */
394 docolon (VALUE *sv, VALUE *pv)
398 struct re_pattern_buffer re_buffer;
399 struct re_registers re_regs;
406 if (pv->u.s[0] == '^')
409 warning: unportable BRE: `%s': using `^' as the first character\n\
410 of the basic regular expression is not portable; it is being ignored"),
414 len = strlen (pv->u.s);
415 memset (&re_buffer, 0, sizeof (re_buffer));
416 memset (&re_regs, 0, sizeof (re_regs));
417 re_buffer.allocated = 2 * len;
418 if (re_buffer.allocated < len)
420 re_buffer.buffer = xmalloc (re_buffer.allocated);
421 re_buffer.translate = 0;
422 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
423 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
425 error (EXPR_ERROR, 0, "%s", errmsg);
427 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
430 /* Were \(...\) used? */
431 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
433 sv->u.s[re_regs.end[1]] = '\0';
434 v = str_value (sv->u.s + re_regs.start[1]);
437 v = int_value (matchlen);
441 /* Match failed -- return the right kind of null. */
442 if (re_buffer.re_nsub > 0)
447 free (re_buffer.buffer);
451 /* Handle bare operands and ( expr ) syntax. */
475 return str_value (*args++);
478 /* Handle match, substr, index, and length keywords, and quoting "+". */
496 return str_value (*args++);
498 else if (nextarg ("length"))
502 v = int_value (strlen (r->u.s));
506 else if (nextarg ("match"))
515 else if (nextarg ("index"))
521 v = int_value (strcspn (l->u.s, r->u.s) + 1);
522 if (v->u.i == strlen (l->u.s) + 1)
528 else if (nextarg ("substr"))
534 if (!toarith (i1) || !toarith (i2)
535 || strlen (l->u.s) < i1->u.i
536 || i1->u.i <= 0 || i2->u.i <= 0)
542 v->u.s = strncpy (xmalloc (i2->u.i + 1),
543 l->u.s + i1->u.i - 1, i2->u.i);
555 /* Handle : operator (pattern matching).
556 Calls docolon to do the real work. */
584 /* Handle *, /, % operators. */
591 enum { multiply, divide, mod } fxn;
602 else if (nextarg ("/"))
604 else if (nextarg ("%"))
609 if (!toarith (l) || !toarith (r))
610 error (EXPR_ERROR, 0, _("non-numeric argument"));
612 val = l->u.i * r->u.i;
616 error (EXPR_ERROR, 0, _("division by zero"));
617 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
625 /* Handle +, - operators. */
632 enum { plus, minus } fxn;
643 else if (nextarg ("-"))
648 if (!toarith (l) || !toarith (r))
649 error (EXPR_ERROR, 0, _("non-numeric argument"));
650 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
657 /* Handle comparisons. */
666 less_than, less_equal, equal, not_equal, greater_equal, greater_than
672 char *collation_arg1;
682 else if (nextarg ("<="))
684 else if (nextarg ("=") || nextarg ("=="))
686 else if (nextarg ("!="))
688 else if (nextarg (">="))
690 else if (nextarg (">"))
698 /* Save the first arg to strcoll, in case we need its value for
699 a diagnostic later. This is needed because 'toarith' might
700 free the first arg. */
701 collation_arg1 = xstrdup (l->u.s);
704 lval = strcoll (collation_arg1, r->u.s);
705 collation_errno = errno;
707 if (toarith (l) && toarith (r))
712 else if (collation_errno)
714 error (0, collation_errno, _("string comparison failed"));
715 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
716 error (EXPR_ERROR, 0,
717 _("The strings compared were %s and %s."),
718 quotearg_n_style (0, locale_quoting_style, collation_arg1),
719 quotearg_n_style (1, locale_quoting_style, r->u.s));
724 case less_than: val = (lval < rval); break;
725 case less_equal: val = (lval <= rval); break;
726 case equal: val = (lval == rval); break;
727 case not_equal: val = (lval != rval); break;
728 case greater_equal: val = (lval >= rval); break;
729 case greater_than: val = (lval > rval); break;
734 free (collation_arg1);
756 if (null (l) || null (r))