*** empty log message ***
[coreutils.git] / src / expr.c
blob99bbdd8fd4766409aabca10d8ca2fd2ce24f996a
1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2006 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)
7 any later version.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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. */
31 #include <config.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include "system.h"
36 #include <regex.h>
37 #include "long-options.h"
38 #include "error.h"
39 #include "inttostr.h"
40 #include "quote.h"
41 #include "quotearg.h"
42 #include "strnumcmp.h"
43 #include "xstrtol.h"
45 /* The official name of this program (e.g., no `g' prefix). */
46 #define PROGRAM_NAME "expr"
48 #define AUTHORS "Mike Parker"
50 /* Exit statuses. */
51 enum
53 /* Invalid expression: e.g., its form does not conform to the
54 grammar for expressions. Our grammar is an extension of the
55 POSIX grammar. */
56 EXPR_INVALID = 2,
58 /* An internal error occurred, e.g., arithmetic overflow, storage
59 exhaustion. */
60 EXPR_FAILURE
63 /* The kinds of value we can have. */
64 enum valtype
66 integer,
67 string
69 typedef enum valtype TYPE;
71 /* A value is.... */
72 struct valinfo
74 TYPE type; /* Which kind. */
75 union
76 { /* The value itself. */
77 intmax_t i;
78 char *s;
79 } u;
81 typedef struct valinfo VALUE;
83 /* The arguments given to the program, minus the program name. */
84 static char **args;
86 /* The name this program was run with. */
87 char *program_name;
89 static VALUE *eval (bool);
90 static bool nomoreargs (void);
91 static bool null (VALUE *v);
92 static void printv (VALUE *v);
94 void
95 usage (int status)
97 if (status != EXIT_SUCCESS)
98 fprintf (stderr, _("Try `%s --help' for more information.\n"),
99 program_name);
100 else
102 printf (_("\
103 Usage: %s EXPRESSION\n\
104 or: %s OPTION\n\
106 program_name, program_name);
107 putchar ('\n');
108 fputs (HELP_OPTION_DESCRIPTION, stdout);
109 fputs (VERSION_OPTION_DESCRIPTION, stdout);
110 fputs (_("\
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\
118 "), stdout);
119 fputs (_("\
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\
127 "), stdout);
128 fputs (_("\
130 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
131 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
132 "), stdout);
133 fputs (_("\
135 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
136 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
137 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
138 "), stdout);
139 fputs (_("\
141 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
143 match STRING REGEXP same as STRING : REGEXP\n\
144 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
145 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
146 length STRING length of STRING\n\
147 "), stdout);
148 fputs (_("\
149 + TOKEN interpret TOKEN as a string, even if it is a\n\
150 keyword like `match' or an operator like `/'\n\
152 ( EXPRESSION ) value of EXPRESSION\n\
153 "), stdout);
154 fputs (_("\
156 Beware that many operators need to be escaped or quoted for shells.\n\
157 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
158 Pattern matches return the string matched between \\( and \\) or null; if\n\
159 \\( and \\) are not used, they return the number of characters matched or 0.\n\
160 "), stdout);
161 fputs (_("\
163 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
164 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
165 "), stdout);
166 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
168 exit (status);
171 /* Report a syntax error and exit. */
172 static void
173 syntax_error (void)
175 error (EXPR_INVALID, 0, _("syntax error"));
178 /* Report an integer overflow for operation OP and exit. */
179 static void
180 integer_overflow (char op)
182 error (EXPR_FAILURE, ERANGE, "%c", op);
186 main (int argc, char **argv)
188 VALUE *v;
190 initialize_main (&argc, &argv);
191 program_name = argv[0];
192 setlocale (LC_ALL, "");
193 bindtextdomain (PACKAGE, LOCALEDIR);
194 textdomain (PACKAGE);
196 initialize_exit_failure (EXPR_FAILURE);
197 atexit (close_stdout);
199 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
200 usage, AUTHORS, (char const *) NULL);
201 /* The above handles --help and --version.
202 Since there is no other invocation of getopt, handle `--' here. */
203 if (argc > 1 && STREQ (argv[1], "--"))
205 --argc;
206 ++argv;
209 if (argc <= 1)
211 error (0, 0, _("missing operand"));
212 usage (EXPR_INVALID);
215 args = argv + 1;
217 v = eval (true);
218 if (!nomoreargs ())
219 syntax_error ();
220 printv (v);
222 exit (null (v));
225 /* Return a VALUE for I. */
227 static VALUE *
228 int_value (intmax_t i)
230 VALUE *v = xmalloc (sizeof *v);
231 v->type = integer;
232 v->u.i = i;
233 return v;
236 /* Return a VALUE for S. */
238 static VALUE *
239 str_value (char *s)
241 VALUE *v = xmalloc (sizeof *v);
242 v->type = string;
243 v->u.s = xstrdup (s);
244 return v;
247 /* Free VALUE V, including structure components. */
249 static void
250 freev (VALUE *v)
252 if (v->type == string)
253 free (v->u.s);
254 free (v);
257 /* Print VALUE V. */
259 static void
260 printv (VALUE *v)
262 char *p;
263 char buf[INT_BUFSIZE_BOUND (intmax_t)];
265 switch (v->type)
267 case integer:
268 p = imaxtostr (v->u.i, buf);
269 break;
270 case string:
271 p = v->u.s;
272 break;
273 default:
274 abort ();
277 puts (p);
280 /* Return true if V is a null-string or zero-number. */
282 static bool
283 null (VALUE *v)
285 switch (v->type)
287 case integer:
288 return v->u.i == 0;
289 case string:
291 char const *cp = v->u.s;
292 if (*cp == '\0')
293 return true;
295 cp += (*cp == '-');
299 if (*cp != '0')
300 return false;
302 while (*++cp);
304 return true;
306 default:
307 abort ();
311 /* Return true if CP takes the form of an integer. */
313 static bool
314 looks_like_integer (char const *cp)
316 cp += (*cp == '-');
319 if (! ISDIGIT (*cp))
320 return false;
321 while (*++cp);
323 return true;
326 /* Coerce V to a string value (can't fail). */
328 static void
329 tostring (VALUE *v)
331 char buf[INT_BUFSIZE_BOUND (intmax_t)];
333 switch (v->type)
335 case integer:
336 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
337 v->type = string;
338 break;
339 case string:
340 break;
341 default:
342 abort ();
346 /* Coerce V to an integer value. Return true on success, false on failure. */
348 static bool
349 toarith (VALUE *v)
351 switch (v->type)
353 case integer:
354 return true;
355 case string:
357 intmax_t value;
359 if (! looks_like_integer (v->u.s))
360 return false;
361 if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
362 error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
363 free (v->u.s);
364 v->u.i = value;
365 v->type = integer;
366 return true;
368 default:
369 abort ();
373 /* Return true and advance if the next token matches STR exactly.
374 STR must not be NULL. */
376 static bool
377 nextarg (char const *str)
379 if (*args == NULL)
380 return false;
381 else
383 bool r = STREQ (*args, str);
384 args += r;
385 return r;
389 /* Return true if there no more tokens. */
391 static bool
392 nomoreargs (void)
394 return *args == 0;
397 #ifdef EVAL_TRACE
398 /* Print evaluation trace and args remaining. */
400 static void
401 trace (fxn)
402 char *fxn;
404 char **a;
406 printf ("%s:", fxn);
407 for (a = args; *a; a++)
408 printf (" %s", *a);
409 putchar ('\n');
411 #endif
413 /* Do the : operator.
414 SV is the VALUE for the lhs (the string),
415 PV is the VALUE for the rhs (the pattern). */
417 static VALUE *
418 docolon (VALUE *sv, VALUE *pv)
420 VALUE *v IF_LINT (= NULL);
421 const char *errmsg;
422 struct re_pattern_buffer re_buffer;
423 char fastmap[UCHAR_MAX + 1];
424 struct re_registers re_regs;
425 regoff_t matchlen;
427 tostring (sv);
428 tostring (pv);
430 re_buffer.buffer = NULL;
431 re_buffer.allocated = 0;
432 re_buffer.fastmap = fastmap;
433 re_buffer.translate = NULL;
434 re_syntax_options =
435 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
436 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
437 if (errmsg)
438 error (EXPR_INVALID, 0, "%s", errmsg);
439 re_buffer.newline_anchor = 0;
441 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
442 if (0 <= matchlen)
444 /* Were \(...\) used? */
445 if (re_buffer.re_nsub > 0)
447 sv->u.s[re_regs.end[1]] = '\0';
448 v = str_value (sv->u.s + re_regs.start[1]);
450 else
451 v = int_value (matchlen);
453 else if (matchlen == -1)
455 /* Match failed -- return the right kind of null. */
456 if (re_buffer.re_nsub > 0)
457 v = str_value ("");
458 else
459 v = int_value (0);
461 else
462 error (EXPR_FAILURE,
463 (matchlen == -2 ? errno : EOVERFLOW),
464 _("error in regular expression matcher"));
466 free (re_buffer.buffer);
467 return v;
470 /* Handle bare operands and ( expr ) syntax. */
472 static VALUE *
473 eval7 (bool evaluate)
475 VALUE *v;
477 #ifdef EVAL_TRACE
478 trace ("eval7");
479 #endif
480 if (nomoreargs ())
481 syntax_error ();
483 if (nextarg ("("))
485 v = eval (evaluate);
486 if (!nextarg (")"))
487 syntax_error ();
488 return v;
491 if (nextarg (")"))
492 syntax_error ();
494 return str_value (*args++);
497 /* Handle match, substr, index, and length keywords, and quoting "+". */
499 static VALUE *
500 eval6 (bool evaluate)
502 VALUE *l;
503 VALUE *r;
504 VALUE *v;
505 VALUE *i1;
506 VALUE *i2;
508 #ifdef EVAL_TRACE
509 trace ("eval6");
510 #endif
511 if (nextarg ("+"))
513 if (nomoreargs ())
514 syntax_error ();
515 return str_value (*args++);
517 else if (nextarg ("length"))
519 r = eval6 (evaluate);
520 tostring (r);
521 v = int_value (strlen (r->u.s));
522 freev (r);
523 return v;
525 else if (nextarg ("match"))
527 l = eval6 (evaluate);
528 r = eval6 (evaluate);
529 if (evaluate)
531 v = docolon (l, r);
532 freev (l);
534 else
535 v = l;
536 freev (r);
537 return v;
539 else if (nextarg ("index"))
541 l = eval6 (evaluate);
542 r = eval6 (evaluate);
543 tostring (l);
544 tostring (r);
545 v = int_value (strcspn (l->u.s, r->u.s) + 1);
546 if (v->u.i == strlen (l->u.s) + 1)
547 v->u.i = 0;
548 freev (l);
549 freev (r);
550 return v;
552 else if (nextarg ("substr"))
554 size_t llen;
555 l = eval6 (evaluate);
556 i1 = eval6 (evaluate);
557 i2 = eval6 (evaluate);
558 tostring (l);
559 llen = strlen (l->u.s);
560 if (!toarith (i1) || !toarith (i2)
561 || llen < i1->u.i
562 || i1->u.i <= 0 || i2->u.i <= 0)
563 v = str_value ("");
564 else
566 size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
567 char *vlim;
568 v = xmalloc (sizeof *v);
569 v->type = string;
570 v->u.s = xmalloc (vlen + 1);
571 vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
572 *vlim = '\0';
574 freev (l);
575 freev (i1);
576 freev (i2);
577 return v;
579 else
580 return eval7 (evaluate);
583 /* Handle : operator (pattern matching).
584 Calls docolon to do the real work. */
586 static VALUE *
587 eval5 (bool evaluate)
589 VALUE *l;
590 VALUE *r;
591 VALUE *v;
593 #ifdef EVAL_TRACE
594 trace ("eval5");
595 #endif
596 l = eval6 (evaluate);
597 while (1)
599 if (nextarg (":"))
601 r = eval6 (evaluate);
602 if (evaluate)
604 v = docolon (l, r);
605 freev (l);
606 l = v;
608 freev (r);
610 else
611 return l;
615 /* Handle *, /, % operators. */
617 static VALUE *
618 eval4 (bool evaluate)
620 VALUE *l;
621 VALUE *r;
622 enum { multiply, divide, mod } fxn;
623 intmax_t val = 0;
625 #ifdef EVAL_TRACE
626 trace ("eval4");
627 #endif
628 l = eval5 (evaluate);
629 while (1)
631 if (nextarg ("*"))
632 fxn = multiply;
633 else if (nextarg ("/"))
634 fxn = divide;
635 else if (nextarg ("%"))
636 fxn = mod;
637 else
638 return l;
639 r = eval5 (evaluate);
640 if (evaluate)
642 if (!toarith (l) || !toarith (r))
643 error (EXPR_INVALID, 0, _("non-numeric argument"));
644 if (fxn == multiply)
646 val = l->u.i * r->u.i;
647 if (! (l->u.i == 0 || r->u.i == 0
648 || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
649 && val / l->u.i == r->u.i)))
650 integer_overflow ('*');
652 else
654 if (r->u.i == 0)
655 error (EXPR_INVALID, 0, _("division by zero"));
656 if (l->u.i < - INTMAX_MAX && r->u.i == -1)
658 /* Some x86-style hosts raise an exception for
659 INT_MIN / -1 and INT_MIN % -1, so handle these
660 problematic cases specially. */
661 if (fxn == divide)
662 integer_overflow ('/');
663 val = 0;
665 else
666 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
669 freev (l);
670 freev (r);
671 l = int_value (val);
675 /* Handle +, - operators. */
677 static VALUE *
678 eval3 (bool evaluate)
680 VALUE *l;
681 VALUE *r;
682 enum { plus, minus } fxn;
683 intmax_t val = 0;
685 #ifdef EVAL_TRACE
686 trace ("eval3");
687 #endif
688 l = eval4 (evaluate);
689 while (1)
691 if (nextarg ("+"))
692 fxn = plus;
693 else if (nextarg ("-"))
694 fxn = minus;
695 else
696 return l;
697 r = eval4 (evaluate);
698 if (evaluate)
700 if (!toarith (l) || !toarith (r))
701 error (EXPR_INVALID, 0, _("non-numeric argument"));
702 if (fxn == plus)
704 val = l->u.i + r->u.i;
705 if ((val < l->u.i) != (r->u.i < 0))
706 integer_overflow ('+');
708 else
710 val = l->u.i - r->u.i;
711 if ((l->u.i < val) != (r->u.i < 0))
712 integer_overflow ('-');
715 freev (l);
716 freev (r);
717 l = int_value (val);
721 /* Handle comparisons. */
723 static VALUE *
724 eval2 (bool evaluate)
726 VALUE *l;
728 #ifdef EVAL_TRACE
729 trace ("eval2");
730 #endif
731 l = eval3 (evaluate);
732 while (1)
734 VALUE *r;
735 enum
737 less_than, less_equal, equal, not_equal, greater_equal, greater_than
738 } fxn;
739 bool val = false;
741 if (nextarg ("<"))
742 fxn = less_than;
743 else if (nextarg ("<="))
744 fxn = less_equal;
745 else if (nextarg ("=") || nextarg ("=="))
746 fxn = equal;
747 else if (nextarg ("!="))
748 fxn = not_equal;
749 else if (nextarg (">="))
750 fxn = greater_equal;
751 else if (nextarg (">"))
752 fxn = greater_than;
753 else
754 return l;
755 r = eval3 (evaluate);
757 if (evaluate)
759 int cmp;
760 tostring (l);
761 tostring (r);
763 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
764 cmp = strintcmp (l->u.s, r->u.s);
765 else
767 errno = 0;
768 cmp = strcoll (l->u.s, r->u.s);
770 if (errno)
772 error (0, errno, _("string comparison failed"));
773 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
774 error (EXPR_INVALID, 0,
775 _("The strings compared were %s and %s."),
776 quotearg_n_style (0, locale_quoting_style, l->u.s),
777 quotearg_n_style (1, locale_quoting_style, r->u.s));
781 switch (fxn)
783 case less_than: val = (cmp < 0); break;
784 case less_equal: val = (cmp <= 0); break;
785 case equal: val = (cmp == 0); break;
786 case not_equal: val = (cmp != 0); break;
787 case greater_equal: val = (cmp >= 0); break;
788 case greater_than: val = (cmp > 0); break;
789 default: abort ();
793 freev (l);
794 freev (r);
795 l = int_value (val);
799 /* Handle &. */
801 static VALUE *
802 eval1 (bool evaluate)
804 VALUE *l;
805 VALUE *r;
807 #ifdef EVAL_TRACE
808 trace ("eval1");
809 #endif
810 l = eval2 (evaluate);
811 while (1)
813 if (nextarg ("&"))
815 r = eval2 (evaluate & ~ null (l));
816 if (null (l) || null (r))
818 freev (l);
819 freev (r);
820 l = int_value (0);
822 else
823 freev (r);
825 else
826 return l;
830 /* Handle |. */
832 static VALUE *
833 eval (bool evaluate)
835 VALUE *l;
836 VALUE *r;
838 #ifdef EVAL_TRACE
839 trace ("eval");
840 #endif
841 l = eval1 (evaluate);
842 while (1)
844 if (nextarg ("|"))
846 r = eval1 (evaluate & null (l));
847 if (null (l))
849 freev (l);
850 l = r;
851 if (null (l))
853 freev (l);
854 l = int_value (0);
857 else
858 freev (r);
860 else
861 return l;