1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999 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. */
75 static VALUE *docolon PARAMS ((VALUE *sv, VALUE *pv));
76 static VALUE *eval PARAMS ((void));
77 static VALUE *int_value PARAMS ((int i));
78 static VALUE *str_value PARAMS ((char *s));
79 static int isstring PARAMS ((VALUE *v));
80 static int nextarg PARAMS ((char *str));
81 static int nomoreargs PARAMS ((void));
82 static int null PARAMS ((VALUE *v));
83 static int toarith PARAMS ((VALUE *v));
84 static void freev PARAMS ((VALUE *v));
85 static void printv PARAMS ((VALUE *v));
86 static void tostring PARAMS ((VALUE *v));
96 fprintf (stderr, _("Try `%s --help' for more information.\n"),
101 Usage: %s EXPRESSION\n\
104 program_name, program_name);
107 --help display this help and exit\n\
108 --version output version information and exit\n\
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\
119 ARG1 < ARG2 ARG1 is less than ARG2\n\
120 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
121 ARG1 = ARG2 ARG1 is equal to ARG2\n\
122 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
123 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
124 ARG1 > ARG2 ARG1 is greater than ARG2\n\
126 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
127 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
129 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
130 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
131 ARG1 %% ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
133 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
135 match STRING REGEXP same as STRING : REGEXP\n\
136 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
137 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
138 length STRING length of STRING\n\
139 quote TOKEN interpret TOKEN as a string, even if it is a\n\
140 keyword like `match' or an operator like `/'\n\
142 ( EXPRESSION ) value of EXPRESSION\n\
146 Beware that many operators need to be escaped or quoted for shells.\n\
147 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
148 Pattern matches return the string matched between \\( and \\) or null; if\n\
149 \\( and \\) are not used, they return the number of characters matched or 0.\n\
151 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
157 main (int argc, char **argv)
161 program_name = argv[0];
162 setlocale (LC_ALL, "");
163 bindtextdomain (PACKAGE, LOCALEDIR);
164 textdomain (PACKAGE);
166 posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
168 /* Recognize --help or --version only if POSIXLY_CORRECT is not set. */
169 if (!posixly_correct)
170 parse_long_options (argc, argv, "expr", GNU_PACKAGE, VERSION, usage);
174 error (0, 0, _("too few arguments"));
182 error (2, 0, _("syntax error"));
188 /* Return a VALUE for I. */
201 /* Return a VALUE for S. */
210 v->u.s = xstrdup (s);
214 /* Free VALUE V, including structure components. */
219 if (v->type == string)
232 printf ("%d\n", v->u.i);
235 printf ("%s\n", v->u.s);
242 /* Return nonzero if V is a null-string or zero-number. */
252 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
258 /* Return nonzero if V is a string value. */
263 return v->type == string;
266 /* Coerce V to a string value (can't fail). */
276 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
277 sprintf (temp, "%d", v->u.i);
288 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
304 /* Don't interpret the empty string as an integer. */
313 i = i * 10 + *cp - '0';
318 v->u.i = i * (neg ? -1 : 1);
326 /* Return nonzero if the next token matches STR exactly.
327 STR must not be NULL. */
334 return strcmp (*args, str) == 0;
337 /* Return nonzero if there no more tokens. */
345 /* The comparison operator handling functions. */
347 #define cmpf(name, rel) \
349 int name (l, r) VALUE *l; VALUE *r; \
351 if (isstring (l) || isstring (r)) \
355 return strcmp (l->u.s, r->u.s) rel 0; \
358 return l->u.i rel r->u.i; \
361 cmpf (less_equal, <=)
364 cmpf (greater_equal, >=)
365 cmpf (greater_than, >)
369 /* The arithmetic operator handling functions. */
371 #define arithf(name, op) \
373 int name (l, r) VALUE *l; VALUE *r; \
375 if (!toarith (l) || !toarith (r)) \
376 error (2, 0, _("non-numeric argument")); \
377 return l->u.i op r->u.i; \
380 #define arithdivf(name, op) \
381 int name (l, r) VALUE *l; VALUE *r; \
383 if (!toarith (l) || !toarith (r)) \
384 error (2, 0, _("non-numeric argument")); \
386 error (2, 0, _("division by zero")); \
387 return l->u.i op r->u.i; \
393 arithdivf (divide, /)
400 /* Print evaluation trace and args remaining. */
409 for (a = args; *a; a++)
415 /* Do the : operator.
416 SV is the VALUE for the lhs (the string),
417 PV is the VALUE for the rhs (the pattern). */
420 docolon (VALUE *sv, VALUE *pv)
424 struct re_pattern_buffer re_buffer;
425 struct re_registers re_regs;
431 if (pv->u.s[0] == '^')
434 warning: unportable BRE: `%s': using `^' as the first character\n\
435 of the basic regular expression is not portable; it is being ignored"),
439 len = strlen (pv->u.s);
440 memset (&re_buffer, 0, sizeof (re_buffer));
441 memset (&re_regs, 0, sizeof (re_regs));
442 re_buffer.allocated = 2 * len;
443 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
444 re_buffer.translate = 0;
445 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
446 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
448 error (2, 0, "%s", errmsg);
450 len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
453 /* Were \(...\) used? */
454 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
456 sv->u.s[re_regs.end[1]] = '\0';
457 v = str_value (sv->u.s + re_regs.start[1]);
464 /* Match failed -- return the right kind of null. */
465 if (re_buffer.re_nsub > 0)
470 free (re_buffer.buffer);
474 /* Handle bare operands and ( expr ) syntax. */
485 error (2, 0, _("syntax error"));
492 error (2, 0, _("syntax error"));
498 error (2, 0, _("syntax error"));
500 return str_value (*args++);
503 /* Handle match, substr, index, length, and quote keywords. */
517 if (!posixly_correct && nextarg ("quote"))
521 error (2, 0, _("syntax error"));
522 return str_value (*args++);
524 else if (nextarg ("length"))
529 v = int_value (strlen (r->u.s));
533 else if (nextarg ("match"))
543 else if (nextarg ("index"))
550 v = int_value (strcspn (l->u.s, r->u.s) + 1);
551 if (v->u.i == (int) strlen (l->u.s) + 1)
557 else if (nextarg ("substr"))
564 if (!toarith (i1) || !toarith (i2)
565 || i1->u.i > (int) strlen (l->u.s)
566 || i1->u.i <= 0 || i2->u.i <= 0)
572 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
573 l->u.s + i1->u.i - 1, i2->u.i);
585 /* Handle : operator (pattern matching).
586 Calls docolon to do the real work. */
615 /* Handle *, /, % operators. */
633 else if (nextarg ("/"))
635 else if (nextarg ("%"))
648 /* Handle +, - operators. */
666 else if (nextarg ("-"))
679 /* Handle comparisons. */
697 else if (nextarg ("<="))
699 else if (nextarg ("=") || nextarg ("=="))
701 else if (nextarg ("!="))
703 else if (nextarg (">="))
705 else if (nextarg (">"))
738 if (null (l) || null (r))