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"
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)
51 /* The kinds of value we can have. */
57 typedef enum valtype TYPE;
62 TYPE type; /* Which kind. */
64 { /* The value itself. */
69 typedef struct valinfo VALUE;
71 /* The arguments given to the program, minus the program name. */
74 /* The name this program was run with. */
77 static VALUE *eval (void);
78 static int nomoreargs (void);
79 static int null (VALUE *v);
80 static void printv (VALUE *v);
86 fprintf (stderr, _("Try `%s --help' for more information.\n"),
91 Usage: %s EXPRESSION\n\
94 program_name, program_name);
96 fputs (HELP_OPTION_DESCRIPTION, stdout);
97 fputs (VERSION_OPTION_DESCRIPTION, stdout);
100 Print the value of EXPRESSION to standard output. A blank line below\n\
101 separates increasing precedence groups. EXPRESSION may be:\n\
103 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
105 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
109 ARG1 < ARG2 ARG1 is less than ARG2\n\
110 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
111 ARG1 = ARG2 ARG1 is equal to ARG2\n\
112 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
113 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
114 ARG1 > ARG2 ARG1 is greater than ARG2\n\
118 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
119 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
123 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
124 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
125 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
129 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
131 match STRING REGEXP same as STRING : REGEXP\n\
132 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
133 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
134 length STRING length of STRING\n\
137 + TOKEN interpret TOKEN as a string, even if it is a\n\
138 keyword like `match' or an operator like `/'\n\
140 ( EXPRESSION ) value of EXPRESSION\n\
144 Beware that many operators need to be escaped or quoted for shells.\n\
145 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
146 Pattern matches return the string matched between \\( and \\) or null; if\n\
147 \\( and \\) are not used, they return the number of characters matched or 0.\n\
149 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
155 main (int argc, char **argv)
159 initialize_main (&argc, &argv);
160 program_name = argv[0];
161 setlocale (LC_ALL, "");
162 bindtextdomain (PACKAGE, LOCALEDIR);
163 textdomain (PACKAGE);
165 atexit (close_stdout);
167 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
169 /* The above handles --help and --version.
170 Since there is no other invocation of getopt, handle `--' here. */
171 if (argc > 1 && STREQ (argv[1], "--"))
179 error (0, 0, _("too few arguments"));
180 usage (EXIT_FAILURE);
187 error (2, 0, _("syntax error"));
193 /* Return a VALUE for I. */
196 int_value (intmax_t i)
206 /* Return a VALUE for S. */
215 v->u.s = xstrdup (s);
219 /* Free VALUE V, including structure components. */
224 if (v->type == string)
235 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
240 p = imaxtostr (v->u.i, buf);
252 /* Return nonzero if V is a null-string or zero-number. */
262 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
268 /* Coerce V to a string value (can't fail). */
273 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
278 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
288 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
311 i = i * 10 + *cp - '0';
318 v->u.i = i * (neg ? -1 : 1);
326 /* Return nonzero and advance if the next token matches STR exactly.
327 STR must not be NULL. */
336 int r = strcoll (*args, str) == 0;
342 /* Return nonzero if there no more tokens. */
351 /* Print evaluation trace and args remaining. */
360 for (a = args; *a; a++)
366 /* Do the : operator.
367 SV is the VALUE for the lhs (the string),
368 PV is the VALUE for the rhs (the pattern). */
371 docolon (VALUE *sv, VALUE *pv)
375 struct re_pattern_buffer re_buffer;
376 struct re_registers re_regs;
383 if (pv->u.s[0] == '^')
386 warning: unportable BRE: `%s': using `^' as the first character\n\
387 of the basic regular expression is not portable; it is being ignored"),
391 len = strlen (pv->u.s);
392 memset (&re_buffer, 0, sizeof (re_buffer));
393 memset (&re_regs, 0, sizeof (re_regs));
394 re_buffer.allocated = 2 * len;
395 if (re_buffer.allocated < len)
397 re_buffer.buffer = xmalloc (re_buffer.allocated);
398 re_buffer.translate = 0;
399 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
400 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
402 error (2, 0, "%s", errmsg);
404 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
407 /* Were \(...\) used? */
408 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
410 sv->u.s[re_regs.end[1]] = '\0';
411 v = str_value (sv->u.s + re_regs.start[1]);
414 v = int_value (matchlen);
418 /* Match failed -- return the right kind of null. */
419 if (re_buffer.re_nsub > 0)
424 free (re_buffer.buffer);
428 /* Handle bare operands and ( expr ) syntax. */
439 error (2, 0, _("syntax error"));
445 error (2, 0, _("syntax error"));
450 error (2, 0, _("syntax error"));
452 return str_value (*args++);
455 /* Handle match, substr, index, and length keywords, and quoting "+". */
472 error (2, 0, _("syntax error"));
473 return str_value (*args++);
475 else if (nextarg ("length"))
479 v = int_value (strlen (r->u.s));
483 else if (nextarg ("match"))
492 else if (nextarg ("index"))
498 v = int_value (strcspn (l->u.s, r->u.s) + 1);
499 if (v->u.i == strlen (l->u.s) + 1)
505 else if (nextarg ("substr"))
511 if (!toarith (i1) || !toarith (i2)
512 || strlen (l->u.s) < i1->u.i
513 || i1->u.i <= 0 || i2->u.i <= 0)
519 v->u.s = strncpy (xmalloc (i2->u.i + 1),
520 l->u.s + i1->u.i - 1, i2->u.i);
532 /* Handle : operator (pattern matching).
533 Calls docolon to do the real work. */
561 /* Handle *, /, % operators. */
568 enum { multiply, divide, mod } fxn;
579 else if (nextarg ("/"))
581 else if (nextarg ("%"))
586 if (!toarith (l) || !toarith (r))
587 error (2, 0, _("non-numeric argument"));
589 val = l->u.i * r->u.i;
593 error (2, 0, _("division by zero"));
594 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
602 /* Handle +, - operators. */
609 enum { plus, minus } fxn;
620 else if (nextarg ("-"))
625 if (!toarith (l) || !toarith (r))
626 error (2, 0, _("non-numeric argument"));
627 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
634 /* Handle comparisons. */
643 less_than, less_equal, equal, not_equal, greater_equal, greater_than
657 else if (nextarg ("<="))
659 else if (nextarg ("=") || nextarg ("=="))
661 else if (nextarg ("!="))
663 else if (nextarg (">="))
665 else if (nextarg (">"))
672 lval = strcoll (l->u.s, r->u.s);
674 if (toarith (l) && toarith (r))
681 case less_than: val = (lval < rval); break;
682 case less_equal: val = (lval <= rval); break;
683 case equal: val = (lval == rval); break;
684 case not_equal: val = (lval != rval); break;
685 case greater_equal: val = (lval >= rval); break;
686 case greater_than: val = (lval > rval); break;
712 if (null (l) || null (r))