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"
44 /* The official name of this program (e.g., no `g' prefix). */
45 #define PROGRAM_NAME "expr"
47 #define AUTHORS "Mike Parker"
50 #define NEW(Type) XMALLOC (Type, 1)
51 #define OLD(x) free (x)
56 /* Invalid expression: i.e., its form does not conform to the
57 grammar for expressions. Our grammar is an extension of the
61 /* Some other error occurred. */
65 /* The kinds of value we can have. */
71 typedef enum valtype TYPE;
76 TYPE type; /* Which kind. */
78 { /* The value itself. */
83 typedef struct valinfo VALUE;
85 /* The arguments given to the program, minus the program name. */
88 /* The name this program was run with. */
91 static VALUE *eval (void);
92 static bool nomoreargs (void);
93 static bool null (VALUE *v);
94 static void printv (VALUE *v);
100 fprintf (stderr, _("Try `%s --help' for more information.\n"),
105 Usage: %s EXPRESSION\n\
108 program_name, program_name);
110 fputs (HELP_OPTION_DESCRIPTION, stdout);
111 fputs (VERSION_OPTION_DESCRIPTION, stdout);
114 Print the value of EXPRESSION to standard output. A blank line below\n\
115 separates increasing precedence groups. EXPRESSION may be:\n\
117 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
119 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
123 ARG1 < ARG2 ARG1 is less than ARG2\n\
124 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
125 ARG1 = ARG2 ARG1 is equal to ARG2\n\
126 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
127 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
128 ARG1 > ARG2 ARG1 is greater than ARG2\n\
132 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
133 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
137 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
138 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
139 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
143 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
145 match STRING REGEXP same as STRING : REGEXP\n\
146 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
147 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
148 length STRING length of STRING\n\
151 + TOKEN interpret TOKEN as a string, even if it is a\n\
152 keyword like `match' or an operator like `/'\n\
154 ( EXPRESSION ) value of EXPRESSION\n\
158 Beware that many operators need to be escaped or quoted for shells.\n\
159 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
160 Pattern matches return the string matched between \\( and \\) or null; if\n\
161 \\( and \\) are not used, they return the number of characters matched or 0.\n\
163 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
168 /* Report a syntax error and exit. */
172 error (EXPR_INVALID, 0, _("syntax error"));
176 main (int argc, char **argv)
180 initialize_main (&argc, &argv);
181 program_name = argv[0];
182 setlocale (LC_ALL, "");
183 bindtextdomain (PACKAGE, LOCALEDIR);
184 textdomain (PACKAGE);
186 /* Change the way library functions fail. */
187 exit_failure = EXPR_ERROR;
189 atexit (close_stdout);
191 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
193 /* The above handles --help and --version.
194 Since there is no other invocation of getopt, handle `--' here. */
195 if (argc > 1 && STREQ (argv[1], "--"))
203 error (0, 0, _("too few arguments"));
204 usage (EXPR_INVALID);
217 /* Return a VALUE for I. */
220 int_value (intmax_t i)
230 /* Return a VALUE for S. */
239 v->u.s = xstrdup (s);
243 /* Free VALUE V, including structure components. */
248 if (v->type == string)
259 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
264 p = imaxtostr (v->u.i, buf);
276 /* Return true if V is a null-string or zero-number. */
286 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
292 /* Coerce V to a string value (can't fail). */
297 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
302 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
312 /* Coerce V to an integer value. Return true on success, false on failure. */
335 i = i * 10 + *cp - '0';
342 v->u.i = i * (neg ? -1 : 1);
350 /* Return nonzero and advance if the next token matches STR exactly.
351 STR must not be NULL. */
354 nextarg (char const *str)
360 bool r = strcmp (*args, str) == 0;
366 /* Return true if there no more tokens. */
375 /* Print evaluation trace and args remaining. */
384 for (a = args; *a; a++)
390 /* Do the : operator.
391 SV is the VALUE for the lhs (the string),
392 PV is the VALUE for the rhs (the pattern). */
395 docolon (VALUE *sv, VALUE *pv)
399 struct re_pattern_buffer re_buffer;
400 struct re_registers re_regs;
407 if (pv->u.s[0] == '^')
410 warning: unportable BRE: `%s': using `^' as the first character\n\
411 of the basic regular expression is not portable; it is being ignored"),
415 len = strlen (pv->u.s);
416 memset (&re_buffer, 0, sizeof (re_buffer));
417 memset (&re_regs, 0, sizeof (re_regs));
418 re_buffer.allocated = 2 * len;
419 if (re_buffer.allocated < len)
421 re_buffer.buffer = xmalloc (re_buffer.allocated);
422 re_buffer.translate = 0;
423 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
424 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
426 error (EXPR_ERROR, 0, "%s", errmsg);
428 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
431 /* Were \(...\) used? */
432 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
434 sv->u.s[re_regs.end[1]] = '\0';
435 v = str_value (sv->u.s + re_regs.start[1]);
438 v = int_value (matchlen);
442 /* Match failed -- return the right kind of null. */
443 if (re_buffer.re_nsub > 0)
448 free (re_buffer.buffer);
452 /* Handle bare operands and ( expr ) syntax. */
476 return str_value (*args++);
479 /* Handle match, substr, index, and length keywords, and quoting "+". */
497 return str_value (*args++);
499 else if (nextarg ("length"))
503 v = int_value (strlen (r->u.s));
507 else if (nextarg ("match"))
516 else if (nextarg ("index"))
522 v = int_value (strcspn (l->u.s, r->u.s) + 1);
523 if (v->u.i == strlen (l->u.s) + 1)
529 else if (nextarg ("substr"))
535 if (!toarith (i1) || !toarith (i2)
536 || strlen (l->u.s) < i1->u.i
537 || i1->u.i <= 0 || i2->u.i <= 0)
543 v->u.s = strncpy (xmalloc (i2->u.i + 1),
544 l->u.s + i1->u.i - 1, i2->u.i);
556 /* Handle : operator (pattern matching).
557 Calls docolon to do the real work. */
585 /* Handle *, /, % operators. */
592 enum { multiply, divide, mod } fxn;
603 else if (nextarg ("/"))
605 else if (nextarg ("%"))
610 if (!toarith (l) || !toarith (r))
611 error (EXPR_ERROR, 0, _("non-numeric argument"));
613 val = l->u.i * r->u.i;
617 error (EXPR_ERROR, 0, _("division by zero"));
618 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
626 /* Handle +, - operators. */
633 enum { plus, minus } fxn;
644 else if (nextarg ("-"))
649 if (!toarith (l) || !toarith (r))
650 error (EXPR_ERROR, 0, _("non-numeric argument"));
651 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
658 /* Handle comparisons. */
667 less_than, less_equal, equal, not_equal, greater_equal, greater_than
673 char *collation_arg1;
683 else if (nextarg ("<="))
685 else if (nextarg ("=") || nextarg ("=="))
687 else if (nextarg ("!="))
689 else if (nextarg (">="))
691 else if (nextarg (">"))
699 /* Save the first arg to strcoll, in case we need its value for
700 a diagnostic later. This is needed because 'toarith' might
701 free the first arg. */
702 collation_arg1 = xstrdup (l->u.s);
705 lval = strcoll (collation_arg1, r->u.s);
706 collation_errno = errno;
708 if (toarith (l) && toarith (r))
713 else if (collation_errno)
715 error (0, collation_errno, _("string comparison failed"));
716 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
717 error (EXPR_ERROR, 0,
718 _("The strings compared were %s and %s."),
719 quotearg_n_style (0, locale_quoting_style, collation_arg1),
720 quotearg_n_style (1, locale_quoting_style, r->u.s));
725 case less_than: val = (lval < rval); break;
726 case less_equal: val = (lval <= rval); break;
727 case equal: val = (lval == rval); break;
728 case not_equal: val = (lval != rval); break;
729 case greater_equal: val = (lval >= rval); break;
730 case greater_than: val = (lval > rval); break;
735 free (collation_arg1);
757 if (null (l) || null (r))