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"
48 #define NEW(Type) XMALLOC (Type, 1)
49 #define OLD(x) free (x)
54 /* Invalid expression: i.e., its form does not conform to the
55 grammar for expressions. Our grammar is an extension of the
59 /* Some other error occurred. */
63 /* The kinds of value we can have. */
69 typedef enum valtype TYPE;
74 TYPE type; /* Which kind. */
76 { /* The value itself. */
81 typedef struct valinfo VALUE;
83 /* The arguments given to the program, minus the program name. */
86 /* The name this program was run with. */
89 static VALUE *eval (void);
90 static bool nomoreargs (void);
91 static bool null (VALUE *v);
92 static void printv (VALUE *v);
97 if (status != EXIT_SUCCESS)
98 fprintf (stderr, _("Try `%s --help' for more information.\n"),
103 Usage: %s EXPRESSION\n\
106 program_name, program_name);
108 fputs (HELP_OPTION_DESCRIPTION, stdout);
109 fputs (VERSION_OPTION_DESCRIPTION, stdout);
112 Print the value of EXPRESSION to standard output. A blank line below\n\
113 separates increasing precedence groups. EXPRESSION may be:\n\
115 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
117 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
121 ARG1 < ARG2 ARG1 is less than ARG2\n\
122 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
123 ARG1 = ARG2 ARG1 is equal to ARG2\n\
124 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
125 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
126 ARG1 > ARG2 ARG1 is greater than ARG2\n\
130 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
131 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
135 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
136 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
137 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
141 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
143 match STRING REGEXP same as STRING : REGEXP\n\
144 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
145 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
146 length STRING length of STRING\n\
149 + TOKEN interpret TOKEN as a string, even if it is a\n\
150 keyword like `match' or an operator like `/'\n\
152 ( EXPRESSION ) value of EXPRESSION\n\
156 Beware that many operators need to be escaped or quoted for shells.\n\
157 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
158 Pattern matches return the string matched between \\( and \\) or null; if\n\
159 \\( and \\) are not used, they return the number of characters matched or 0.\n\
161 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
166 /* Report a syntax error and exit. */
170 error (EXPR_INVALID, 0, _("syntax error"));
174 main (int argc, char **argv)
178 initialize_main (&argc, &argv);
179 program_name = argv[0];
180 setlocale (LC_ALL, "");
181 bindtextdomain (PACKAGE, LOCALEDIR);
182 textdomain (PACKAGE);
184 initialize_exit_failure (EXPR_FAILURE);
185 atexit (close_stdout);
187 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
188 usage, AUTHORS, (char const *) NULL);
189 /* The above handles --help and --version.
190 Since there is no other invocation of getopt, handle `--' here. */
191 if (argc > 1 && STREQ (argv[1], "--"))
199 error (0, 0, _("too few arguments"));
200 usage (EXPR_INVALID);
213 /* Return a VALUE for I. */
216 int_value (intmax_t i)
226 /* Return a VALUE for S. */
235 v->u.s = xstrdup (s);
239 /* Free VALUE V, including structure components. */
244 if (v->type == string)
255 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
260 p = imaxtostr (v->u.i, buf);
272 /* Return true if V is a null-string or zero-number. */
282 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
288 /* Coerce V to a string value (can't fail). */
293 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
298 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
308 /* Coerce V to an integer value. Return true on success, false on failure. */
331 i = i * 10 + *cp - '0';
338 v->u.i = i * (neg ? -1 : 1);
346 /* Return nonzero and advance if the next token matches STR exactly.
347 STR must not be NULL. */
350 nextarg (char const *str)
356 bool r = strcmp (*args, str) == 0;
362 /* Return true if there no more tokens. */
371 /* Print evaluation trace and args remaining. */
380 for (a = args; *a; a++)
386 /* Do the : operator.
387 SV is the VALUE for the lhs (the string),
388 PV is the VALUE for the rhs (the pattern). */
391 docolon (VALUE *sv, VALUE *pv)
395 struct re_pattern_buffer re_buffer;
396 struct re_registers re_regs;
403 if (pv->u.s[0] == '^')
406 warning: unportable BRE: `%s': using `^' as the first character\n\
407 of the basic regular expression is not portable; it is being ignored"),
411 len = strlen (pv->u.s);
412 memset (&re_buffer, 0, sizeof (re_buffer));
413 memset (&re_regs, 0, sizeof (re_regs));
414 re_buffer.allocated = 2 * len;
415 if (re_buffer.allocated < len)
417 re_buffer.buffer = xmalloc (re_buffer.allocated);
418 re_buffer.translate = 0;
419 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
420 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
422 error (EXPR_FAILURE, 0, "%s", errmsg);
424 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
427 /* Were \(...\) used? */
428 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
430 sv->u.s[re_regs.end[1]] = '\0';
431 v = str_value (sv->u.s + re_regs.start[1]);
434 v = int_value (matchlen);
438 /* Match failed -- return the right kind of null. */
439 if (re_buffer.re_nsub > 0)
444 free (re_buffer.buffer);
448 /* Handle bare operands and ( expr ) syntax. */
472 return str_value (*args++);
475 /* Handle match, substr, index, and length keywords, and quoting "+". */
493 return str_value (*args++);
495 else if (nextarg ("length"))
499 v = int_value (strlen (r->u.s));
503 else if (nextarg ("match"))
512 else if (nextarg ("index"))
518 v = int_value (strcspn (l->u.s, r->u.s) + 1);
519 if (v->u.i == strlen (l->u.s) + 1)
525 else if (nextarg ("substr"))
531 if (!toarith (i1) || !toarith (i2)
532 || strlen (l->u.s) < i1->u.i
533 || i1->u.i <= 0 || i2->u.i <= 0)
539 v->u.s = strncpy (xmalloc (i2->u.i + 1),
540 l->u.s + i1->u.i - 1, i2->u.i);
552 /* Handle : operator (pattern matching).
553 Calls docolon to do the real work. */
581 /* Handle *, /, % operators. */
588 enum { multiply, divide, mod } fxn;
599 else if (nextarg ("/"))
601 else if (nextarg ("%"))
606 if (!toarith (l) || !toarith (r))
607 error (EXPR_FAILURE, 0, _("non-numeric argument"));
609 val = l->u.i * r->u.i;
613 error (EXPR_FAILURE, 0, _("division by zero"));
614 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
622 /* Handle +, - operators. */
629 enum { plus, minus } fxn;
640 else if (nextarg ("-"))
645 if (!toarith (l) || !toarith (r))
646 error (EXPR_FAILURE, 0, _("non-numeric argument"));
647 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
654 /* Handle comparisons. */
663 less_than, less_equal, equal, not_equal, greater_equal, greater_than
669 char *collation_arg1;
679 else if (nextarg ("<="))
681 else if (nextarg ("=") || nextarg ("=="))
683 else if (nextarg ("!="))
685 else if (nextarg (">="))
687 else if (nextarg (">"))
695 /* Save the first arg to strcoll, in case we need its value for
696 a diagnostic later. This is needed because 'toarith' might
697 free the first arg. */
698 collation_arg1 = xstrdup (l->u.s);
701 lval = strcoll (collation_arg1, r->u.s);
702 collation_errno = errno;
704 if (toarith (l) && toarith (r))
709 else if (collation_errno)
711 error (0, collation_errno, _("string comparison failed"));
712 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
713 error (EXPR_FAILURE, 0,
714 _("The strings compared were %s and %s."),
715 quotearg_n_style (0, locale_quoting_style, collation_arg1),
716 quotearg_n_style (1, locale_quoting_style, r->u.s));
721 case less_than: val = (lval < rval); break;
722 case less_equal: val = (lval <= rval); break;
723 case equal: val = (lval == rval); break;
724 case not_equal: val = (lval != rval); break;
725 case greater_equal: val = (lval >= rval); break;
726 case greater_than: val = (lval > rval); break;
731 free (collation_arg1);
753 if (null (l) || null (r))