1 /* expr -- evaluate expressions.
2 Copyright (C) 86,91,92,93,94,95,96,1997 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"
40 #define NEW(type) ((type *) xmalloc (sizeof (type)))
41 #define OLD(x) free ((char *) x)
43 /* The kinds of value we can have. */
49 typedef enum valtype TYPE;
54 TYPE type; /* Which kind. */
56 { /* The value itself. */
61 typedef struct valinfo VALUE;
63 /* Non-zero if the POSIXLY_CORRECT environment variable is set.
64 The unary operator `quote' is disabled when this variable is zero. */
65 static int posixly_correct;
67 /* The arguments given to the program, minus the program name. */
70 /* The name this program was run with. */
77 static VALUE *docolon __P ((VALUE *sv, VALUE *pv));
78 static VALUE *eval __P ((void));
79 static VALUE *int_value __P ((int i));
80 static VALUE *str_value __P ((char *s));
81 static int isstring __P ((VALUE *v));
82 static int nextarg __P ((char *str));
83 static int nomoreargs __P ((void));
84 static int null __P ((VALUE *v));
85 static int toarith __P ((VALUE *v));
86 static void freev __P ((VALUE *v));
87 static void printv __P ((VALUE *v));
88 static void tostring __P ((VALUE *v));
98 fprintf (stderr, _("Try `%s --help' for more information.\n"),
103 Usage: %s EXPRESSION\n\
106 program_name, program_name);
109 --help display this help and exit\n\
110 --version output version information and exit\n\
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\
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\
128 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
129 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
131 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
132 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
133 ARG1 %% ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
135 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
137 match STRING REGEXP same as STRING : REGEXP\n\
138 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
139 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
140 length STRING length of STRING\n\
141 quote TOKEN interpret TOKEN as a string, even if it is a\n\
142 keyword like `match' or an operator like `/'\n\
144 ( EXPRESSION ) value of EXPRESSION\n\
148 Beware that many operators need to be escaped or quoted for shells.\n\
149 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
150 Pattern matches return the string matched between \\( and \\) or null; if\n\
151 \\( and \\) are not used, they return the number of characters matched or 0.\n\
153 puts (_("\nReport bugs to <sh-utils-bugs@gnu.org>."));
159 main (int argc, char **argv)
163 program_name = argv[0];
164 setlocale (LC_ALL, "");
165 bindtextdomain (PACKAGE, LOCALEDIR);
166 textdomain (PACKAGE);
168 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
170 /* Recognize --help or --version only if POSIXLY_CORRECT is not set. */
171 if (!posixly_correct)
172 parse_long_options (argc, argv, "expr", GNU_PACKAGE, VERSION, usage);
176 error (0, 0, _("too few arguments"));
184 error (2, 0, _("syntax error"));
190 /* Return a VALUE for I. */
203 /* Return a VALUE for S. */
212 v->u.s = xstrdup (s);
216 /* Free VALUE V, including structure components. */
221 if (v->type == string)
234 printf ("%d\n", v->u.i);
237 printf ("%s\n", v->u.s);
244 /* Return nonzero if V is a null-string or zero-number. */
254 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
260 /* Return nonzero if V is a string value. */
265 return v->type == string;
268 /* Coerce V to a string value (can't fail). */
278 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
279 sprintf (temp, "%d", v->u.i);
290 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
306 /* Don't interpret the empty string as an integer. */
315 i = i * 10 + *cp - '0';
320 v->u.i = i * (neg ? -1 : 1);
328 /* Return nonzero if the next token matches STR exactly.
329 STR must not be NULL. */
336 return strcmp (*args, str) == 0;
339 /* Return nonzero if there no more tokens. */
347 /* The comparison operator handling functions. */
349 #define cmpf(name, rel) \
351 int name (l, r) VALUE *l; VALUE *r; \
353 if (isstring (l) || isstring (r)) \
357 return strcmp (l->u.s, r->u.s) rel 0; \
360 return l->u.i rel r->u.i; \
363 cmpf (less_equal, <=)
366 cmpf (greater_equal, >=)
367 cmpf (greater_than, >)
371 /* The arithmetic operator handling functions. */
373 #define arithf(name, op) \
375 int name (l, r) VALUE *l; VALUE *r; \
377 if (!toarith (l) || !toarith (r)) \
378 error (2, 0, _("non-numeric argument")); \
379 return l->u.i op r->u.i; \
382 #define arithdivf(name, op) \
383 int name (l, r) VALUE *l; VALUE *r; \
385 if (!toarith (l) || !toarith (r)) \
386 error (2, 0, _("non-numeric argument")); \
388 error (2, 0, _("division by zero")); \
389 return l->u.i op r->u.i; \
395 arithdivf (divide, /)
402 /* Print evaluation trace and args remaining. */
411 for (a = args; *a; a++)
417 /* Do the : operator.
418 SV is the VALUE for the lhs (the string),
419 PV is the VALUE for the rhs (the pattern). */
422 docolon (VALUE *sv, VALUE *pv)
426 struct re_pattern_buffer re_buffer;
427 struct re_registers re_regs;
433 if (pv->u.s[0] == '^')
436 warning: unportable BRE: `%s': using `^' as the first character\n\
437 of the basic regular expression is not portable; it is being ignored"),
441 len = strlen (pv->u.s);
442 memset (&re_buffer, 0, sizeof (re_buffer));
443 memset (&re_regs, 0, sizeof (re_regs));
444 re_buffer.allocated = 2 * len;
445 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
446 re_buffer.translate = 0;
447 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
448 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
450 error (2, 0, "%s", errmsg);
452 len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
455 /* Were \(...\) used? */
456 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
458 sv->u.s[re_regs.end[1]] = '\0';
459 v = str_value (sv->u.s + re_regs.start[1]);
466 /* Match failed -- return the right kind of null. */
467 if (re_buffer.re_nsub > 0)
472 free (re_buffer.buffer);
476 /* Handle bare operands and ( expr ) syntax. */
487 error (2, 0, _("syntax error"));
494 error (2, 0, _("syntax error"));
500 error (2, 0, _("syntax error"));
502 return str_value (*args++);
505 /* Handle match, substr, index, length, and quote keywords. */
519 if (!posixly_correct && nextarg ("quote"))
523 error (2, 0, _("syntax error"));
524 return str_value (*args++);
526 else if (nextarg ("length"))
531 v = int_value (strlen (r->u.s));
535 else if (nextarg ("match"))
545 else if (nextarg ("index"))
552 v = int_value (strcspn (l->u.s, r->u.s) + 1);
553 if (v->u.i == (int) strlen (l->u.s) + 1)
559 else if (nextarg ("substr"))
566 if (!toarith (i1) || !toarith (i2)
567 || i1->u.i > (int) strlen (l->u.s)
568 || i1->u.i <= 0 || i2->u.i <= 0)
574 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
575 l->u.s + i1->u.i - 1, i2->u.i);
587 /* Handle : operator (pattern matching).
588 Calls docolon to do the real work. */
617 /* Handle *, /, % operators. */
635 else if (nextarg ("/"))
637 else if (nextarg ("%"))
650 /* Handle +, - operators. */
668 else if (nextarg ("-"))
681 /* Handle comparisons. */
699 else if (nextarg ("<="))
701 else if (nextarg ("=") || nextarg ("=="))
703 else if (nextarg ("!="))
705 else if (nextarg (">="))
707 else if (nextarg (">"))
740 if (null (l) || null (r))