1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2002 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 ((char *) 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 PARAMS ((void));
78 static int nomoreargs PARAMS ((void));
79 static int null PARAMS ((VALUE *v));
80 static void printv PARAMS ((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 program_name = argv[0];
160 setlocale (LC_ALL, "");
161 bindtextdomain (PACKAGE, LOCALEDIR);
162 textdomain (PACKAGE);
164 atexit (close_stdout);
166 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
168 /* The above handles --help and --version.
169 Since there is no other invocation of getopt, handle `--' here. */
170 if (argc > 1 && STREQ (argv[1], "--"))
178 error (0, 0, _("too few arguments"));
179 usage (EXIT_FAILURE);
186 error (2, 0, _("syntax error"));
192 /* Return a VALUE for I. */
195 int_value (intmax_t i)
205 /* Return a VALUE for S. */
214 v->u.s = xstrdup (s);
218 /* Free VALUE V, including structure components. */
223 if (v->type == string)
234 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
239 p = imaxtostr (v->u.i, buf);
251 /* Return nonzero if V is a null-string or zero-number. */
261 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
267 /* Coerce V to a string value (can't fail). */
272 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
277 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
287 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
310 i = i * 10 + *cp - '0';
317 v->u.i = i * (neg ? -1 : 1);
325 /* Return nonzero and advance if the next token matches STR exactly.
326 STR must not be NULL. */
335 int r = strcoll (*args, str) == 0;
341 /* Return nonzero if there no more tokens. */
350 /* Print evaluation trace and args remaining. */
359 for (a = args; *a; a++)
365 /* Do the : operator.
366 SV is the VALUE for the lhs (the string),
367 PV is the VALUE for the rhs (the pattern). */
370 docolon (VALUE *sv, VALUE *pv)
374 struct re_pattern_buffer re_buffer;
375 struct re_registers re_regs;
382 if (pv->u.s[0] == '^')
385 warning: unportable BRE: `%s': using `^' as the first character\n\
386 of the basic regular expression is not portable; it is being ignored"),
390 len = strlen (pv->u.s);
391 memset (&re_buffer, 0, sizeof (re_buffer));
392 memset (&re_regs, 0, sizeof (re_regs));
393 re_buffer.allocated = 2 * len;
394 if (re_buffer.allocated < len)
396 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
397 re_buffer.translate = 0;
398 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
399 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
401 error (2, 0, "%s", errmsg);
403 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
406 /* Were \(...\) used? */
407 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
409 sv->u.s[re_regs.end[1]] = '\0';
410 v = str_value (sv->u.s + re_regs.start[1]);
413 v = int_value (matchlen);
417 /* Match failed -- return the right kind of null. */
418 if (re_buffer.re_nsub > 0)
423 free (re_buffer.buffer);
427 /* Handle bare operands and ( expr ) syntax. */
438 error (2, 0, _("syntax error"));
444 error (2, 0, _("syntax error"));
449 error (2, 0, _("syntax error"));
451 return str_value (*args++);
454 /* Handle match, substr, index, and length keywords, and quoting "+". */
471 error (2, 0, _("syntax error"));
472 return str_value (*args++);
474 else if (nextarg ("length"))
478 v = int_value (strlen (r->u.s));
482 else if (nextarg ("match"))
491 else if (nextarg ("index"))
497 v = int_value (strcspn (l->u.s, r->u.s) + 1);
498 if (v->u.i == strlen (l->u.s) + 1)
504 else if (nextarg ("substr"))
510 if (!toarith (i1) || !toarith (i2)
511 || strlen (l->u.s) < i1->u.i
512 || i1->u.i <= 0 || i2->u.i <= 0)
518 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
519 l->u.s + i1->u.i - 1, i2->u.i);
531 /* Handle : operator (pattern matching).
532 Calls docolon to do the real work. */
560 /* Handle *, /, % operators. */
567 enum { multiply, divide, mod } fxn;
578 else if (nextarg ("/"))
580 else if (nextarg ("%"))
585 if (!toarith (l) || !toarith (r))
586 error (2, 0, _("non-numeric argument"));
588 val = l->u.i * r->u.i;
592 error (2, 0, _("division by zero"));
593 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
601 /* Handle +, - operators. */
608 enum { plus, minus } fxn;
619 else if (nextarg ("-"))
624 if (!toarith (l) || !toarith (r))
625 error (2, 0, _("non-numeric argument"));
626 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
633 /* Handle comparisons. */
642 less_than, less_equal, equal, not_equal, greater_equal, greater_than
656 else if (nextarg ("<="))
658 else if (nextarg ("=") || nextarg ("=="))
660 else if (nextarg ("!="))
662 else if (nextarg (">="))
664 else if (nextarg (">"))
671 lval = strcoll (l->u.s, r->u.s);
673 if (toarith (l) && toarith (r))
680 case less_than: val = (lval < rval); break;
681 case less_equal: val = (lval <= rval); break;
682 case equal: val = (lval == rval); break;
683 case not_equal: val = (lval != rval); break;
684 case greater_equal: val = (lval >= rval); break;
685 case greater_than: val = (lval > rval); break;
711 if (null (l) || null (r))