*** empty log message ***
[coreutils.git] / src / expr.c
blobd085b4be787dda6be6e5f9404ac04d305b18fe06
1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 1991-1997, 1999-2004 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., 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. */
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 "quotearg.h"
42 /* The official name of this program (e.g., no `g' prefix). */
43 #define PROGRAM_NAME "expr"
45 #define AUTHORS "Mike Parker"
47 #undef NEW
48 #define NEW(Type) XMALLOC (Type, 1)
49 #define OLD(x) free (x)
51 /* Exit statuses. */
52 enum
54 /* Invalid expression: i.e., its form does not conform to the
55 grammar for expressions. Our grammar is an extension of the
56 POSIX grammar. */
57 EXPR_INVALID = 2,
59 /* Some other error occurred. */
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 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
163 exit (status);
166 /* Report a syntax error and exit. */
167 static void
168 syntax_error (void)
170 error (EXPR_INVALID, 0, _("syntax error"));
174 main (int argc, char **argv)
176 VALUE *v;
178 initialize_main (&argc, &argv);
179 program_name = argv[0];
180 setlocale (LC_ALL, "");
181 bindtextdomain (PACKAGE, LOCALEDIR);
182 textdomain (PACKAGE);
184 initialize_exit_failure (EXPR_FAILURE);
185 atexit (close_stdout);
187 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
188 usage, AUTHORS, (char const *) NULL);
189 /* The above handles --help and --version.
190 Since there is no other invocation of getopt, handle `--' here. */
191 if (argc > 1 && STREQ (argv[1], "--"))
193 --argc;
194 ++argv;
197 if (argc <= 1)
199 error (0, 0, _("too few arguments"));
200 usage (EXPR_INVALID);
203 args = argv + 1;
205 v = eval (true);
206 if (!nomoreargs ())
207 syntax_error ();
208 printv (v);
210 exit (null (v));
213 /* Return a VALUE for I. */
215 static VALUE *
216 int_value (intmax_t i)
218 VALUE *v;
220 v = NEW (VALUE);
221 v->type = integer;
222 v->u.i = i;
223 return v;
226 /* Return a VALUE for S. */
228 static VALUE *
229 str_value (char *s)
231 VALUE *v;
233 v = NEW (VALUE);
234 v->type = string;
235 v->u.s = xstrdup (s);
236 return v;
239 /* Free VALUE V, including structure components. */
241 static void
242 freev (VALUE *v)
244 if (v->type == string)
245 free (v->u.s);
246 OLD (v);
249 /* Print VALUE V. */
251 static void
252 printv (VALUE *v)
254 char *p;
255 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
257 switch (v->type)
259 case integer:
260 p = imaxtostr (v->u.i, buf);
261 break;
262 case string:
263 p = v->u.s;
264 break;
265 default:
266 abort ();
269 puts (p);
272 /* Return true if V is a null-string or zero-number. */
274 static bool
275 null (VALUE *v)
277 switch (v->type)
279 case integer:
280 return v->u.i == 0;
281 case string:
283 char const *cp = v->u.s;
284 if (*cp == '\0')
285 return true;
287 cp += (*cp == '-');
291 if (*cp != '0')
292 return false;
294 while (*++cp);
296 return true;
298 default:
299 abort ();
303 /* Coerce V to a string value (can't fail). */
305 static void
306 tostring (VALUE *v)
308 char buf[INT_STRLEN_BOUND (intmax_t) + 1];
310 switch (v->type)
312 case integer:
313 v->u.s = xstrdup (imaxtostr (v->u.i, buf));
314 v->type = string;
315 break;
316 case string:
317 break;
318 default:
319 abort ();
323 /* Coerce V to an integer value. Return true on success, false on failure. */
325 static bool
326 toarith (VALUE *v)
328 intmax_t i;
329 bool neg;
330 char *cp;
332 switch (v->type)
334 case integer:
335 return true;
336 case string:
337 i = 0;
338 cp = v->u.s;
339 neg = (*cp == '-');
340 if (neg)
341 cp++;
345 if (ISDIGIT (*cp))
346 i = i * 10 + *cp - '0';
347 else
348 return false;
350 while (*++cp);
352 free (v->u.s);
353 v->u.i = i * (neg ? -1 : 1);
354 v->type = integer;
355 return true;
356 default:
357 abort ();
361 /* Return nonzero and advance if the next token matches STR exactly.
362 STR must not be NULL. */
364 static bool
365 nextarg (char const *str)
367 if (*args == NULL)
368 return 0;
369 else
371 bool r = strcmp (*args, str) == 0;
372 args += r;
373 return r;
377 /* Return true if there no more tokens. */
379 static bool
380 nomoreargs (void)
382 return *args == 0;
385 #ifdef EVAL_TRACE
386 /* Print evaluation trace and args remaining. */
388 static void
389 trace (fxn)
390 char *fxn;
392 char **a;
394 printf ("%s:", fxn);
395 for (a = args; *a; a++)
396 printf (" %s", *a);
397 putchar ('\n');
399 #endif
401 /* Do the : operator.
402 SV is the VALUE for the lhs (the string),
403 PV is the VALUE for the rhs (the pattern). */
405 static VALUE *
406 docolon (VALUE *sv, VALUE *pv)
408 VALUE *v;
409 const char *errmsg;
410 struct re_pattern_buffer re_buffer;
411 struct re_registers re_regs;
412 size_t len;
413 int matchlen;
415 tostring (sv);
416 tostring (pv);
418 if (pv->u.s[0] == '^')
420 error (0, 0, _("\
421 warning: unportable BRE: `%s': using `^' as the first character\n\
422 of the basic regular expression is not portable; it is being ignored"),
423 pv->u.s);
426 len = strlen (pv->u.s);
427 memset (&re_buffer, 0, sizeof (re_buffer));
428 memset (&re_regs, 0, sizeof (re_regs));
429 re_buffer.allocated = 2 * len;
430 if (re_buffer.allocated < len)
431 xalloc_die ();
432 re_buffer.buffer = xmalloc (re_buffer.allocated);
433 re_buffer.translate = 0;
434 re_syntax_options = RE_SYNTAX_POSIX_BASIC;
435 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
436 if (errmsg)
437 error (EXPR_FAILURE, 0, "%s", errmsg);
439 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
440 if (0 <= matchlen)
442 /* Were \(...\) used? */
443 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
445 sv->u.s[re_regs.end[1]] = '\0';
446 v = str_value (sv->u.s + re_regs.start[1]);
448 else
449 v = int_value (matchlen);
451 else
453 /* Match failed -- return the right kind of null. */
454 if (re_buffer.re_nsub > 0)
455 v = str_value ("");
456 else
457 v = int_value (0);
459 free (re_buffer.buffer);
460 return v;
463 /* Handle bare operands and ( expr ) syntax. */
465 static VALUE *
466 eval7 (bool evaluate)
468 VALUE *v;
470 #ifdef EVAL_TRACE
471 trace ("eval7");
472 #endif
473 if (nomoreargs ())
474 syntax_error ();
476 if (nextarg ("("))
478 v = eval (evaluate);
479 if (!nextarg (")"))
480 syntax_error ();
481 return v;
484 if (nextarg (")"))
485 syntax_error ();
487 return str_value (*args++);
490 /* Handle match, substr, index, and length keywords, and quoting "+". */
492 static VALUE *
493 eval6 (bool evaluate)
495 VALUE *l;
496 VALUE *r;
497 VALUE *v;
498 VALUE *i1;
499 VALUE *i2;
501 #ifdef EVAL_TRACE
502 trace ("eval6");
503 #endif
504 if (nextarg ("+"))
506 if (nomoreargs ())
507 syntax_error ();
508 return str_value (*args++);
510 else if (nextarg ("length"))
512 r = eval6 (evaluate);
513 tostring (r);
514 v = int_value (strlen (r->u.s));
515 freev (r);
516 return v;
518 else if (nextarg ("match"))
520 l = eval6 (evaluate);
521 r = eval6 (evaluate);
522 if (evaluate)
524 v = docolon (l, r);
525 freev (l);
527 else
528 v = l;
529 freev (r);
530 return v;
532 else if (nextarg ("index"))
534 l = eval6 (evaluate);
535 r = eval6 (evaluate);
536 tostring (l);
537 tostring (r);
538 v = int_value (strcspn (l->u.s, r->u.s) + 1);
539 if (v->u.i == strlen (l->u.s) + 1)
540 v->u.i = 0;
541 freev (l);
542 freev (r);
543 return v;
545 else if (nextarg ("substr"))
547 l = eval6 (evaluate);
548 i1 = eval6 (evaluate);
549 i2 = eval6 (evaluate);
550 tostring (l);
551 if (!toarith (i1) || !toarith (i2)
552 || strlen (l->u.s) < i1->u.i
553 || i1->u.i <= 0 || i2->u.i <= 0)
554 v = str_value ("");
555 else
557 v = NEW (VALUE);
558 v->type = string;
559 v->u.s = strncpy (xmalloc (i2->u.i + 1),
560 l->u.s + i1->u.i - 1, i2->u.i);
561 v->u.s[i2->u.i] = 0;
563 freev (l);
564 freev (i1);
565 freev (i2);
566 return v;
568 else
569 return eval7 (evaluate);
572 /* Handle : operator (pattern matching).
573 Calls docolon to do the real work. */
575 static VALUE *
576 eval5 (bool evaluate)
578 VALUE *l;
579 VALUE *r;
580 VALUE *v;
582 #ifdef EVAL_TRACE
583 trace ("eval5");
584 #endif
585 l = eval6 (evaluate);
586 while (1)
588 if (nextarg (":"))
590 r = eval6 (evaluate);
591 if (evaluate)
593 v = docolon (l, r);
594 freev (l);
595 l = v;
597 freev (r);
599 else
600 return l;
604 /* Handle *, /, % operators. */
606 static VALUE *
607 eval4 (bool evaluate)
609 VALUE *l;
610 VALUE *r;
611 enum { multiply, divide, mod } fxn;
612 intmax_t val = 0;
614 #ifdef EVAL_TRACE
615 trace ("eval4");
616 #endif
617 l = eval5 (evaluate);
618 while (1)
620 if (nextarg ("*"))
621 fxn = multiply;
622 else if (nextarg ("/"))
623 fxn = divide;
624 else if (nextarg ("%"))
625 fxn = mod;
626 else
627 return l;
628 r = eval5 (evaluate);
629 if (evaluate)
631 if (!toarith (l) || !toarith (r))
632 error (EXPR_FAILURE, 0, _("non-numeric argument"));
633 if (fxn == multiply)
634 val = l->u.i * r->u.i;
635 else
637 if (r->u.i == 0)
638 error (EXPR_FAILURE, 0, _("division by zero"));
639 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
642 freev (l);
643 freev (r);
644 l = int_value (val);
648 /* Handle +, - operators. */
650 static VALUE *
651 eval3 (bool evaluate)
653 VALUE *l;
654 VALUE *r;
655 enum { plus, minus } fxn;
656 intmax_t val = 0;
658 #ifdef EVAL_TRACE
659 trace ("eval3");
660 #endif
661 l = eval4 (evaluate);
662 while (1)
664 if (nextarg ("+"))
665 fxn = plus;
666 else if (nextarg ("-"))
667 fxn = minus;
668 else
669 return l;
670 r = eval4 (evaluate);
671 if (evaluate)
673 if (!toarith (l) || !toarith (r))
674 error (EXPR_FAILURE, 0, _("non-numeric argument"));
675 val = fxn == plus ? l->u.i + r->u.i : l->u.i - r->u.i;
677 freev (l);
678 freev (r);
679 l = int_value (val);
683 /* Handle comparisons. */
685 static VALUE *
686 eval2 (bool evaluate)
688 VALUE *l;
689 VALUE *r;
690 enum
692 less_than, less_equal, equal, not_equal, greater_equal, greater_than
693 } fxn;
694 bool val;
695 intmax_t lval;
696 intmax_t rval;
697 int collation_errno;
698 char *collation_arg1;
700 #ifdef EVAL_TRACE
701 trace ("eval2");
702 #endif
703 l = eval3 (evaluate);
704 while (1)
706 if (nextarg ("<"))
707 fxn = less_than;
708 else if (nextarg ("<="))
709 fxn = less_equal;
710 else if (nextarg ("=") || nextarg ("=="))
711 fxn = equal;
712 else if (nextarg ("!="))
713 fxn = not_equal;
714 else if (nextarg (">="))
715 fxn = greater_equal;
716 else if (nextarg (">"))
717 fxn = greater_than;
718 else
719 return l;
720 r = eval3 (evaluate);
721 tostring (l);
722 tostring (r);
724 /* Save the first arg to strcoll, in case we need its value for
725 a diagnostic later. This is needed because 'toarith' might
726 free the first arg. */
727 collation_arg1 = xstrdup (l->u.s);
729 errno = 0;
730 lval = strcoll (collation_arg1, r->u.s);
731 collation_errno = errno;
732 rval = 0;
733 if (toarith (l) && toarith (r))
735 lval = l->u.i;
736 rval = r->u.i;
738 else if (collation_errno && evaluate)
740 error (0, collation_errno, _("string comparison failed"));
741 error (0, 0, _("Set LC_ALL='C' to work around the problem."));
742 error (EXPR_FAILURE, 0,
743 _("The strings compared were %s and %s."),
744 quotearg_n_style (0, locale_quoting_style, collation_arg1),
745 quotearg_n_style (1, locale_quoting_style, r->u.s));
748 switch (fxn)
750 case less_than: val = (lval < rval); break;
751 case less_equal: val = (lval <= rval); break;
752 case equal: val = (lval == rval); break;
753 case not_equal: val = (lval != rval); break;
754 case greater_equal: val = (lval >= rval); break;
755 case greater_than: val = (lval > rval); break;
756 default: abort ();
758 freev (l);
759 freev (r);
760 free (collation_arg1);
761 l = int_value (val);
765 /* Handle &. */
767 static VALUE *
768 eval1 (bool evaluate)
770 VALUE *l;
771 VALUE *r;
773 #ifdef EVAL_TRACE
774 trace ("eval1");
775 #endif
776 l = eval2 (evaluate);
777 while (1)
779 if (nextarg ("&"))
781 r = eval2 (evaluate & ~ null (l));
782 if (null (l) || null (r))
784 freev (l);
785 freev (r);
786 l = int_value (0);
788 else
789 freev (r);
791 else
792 return l;
796 /* Handle |. */
798 static VALUE *
799 eval (bool evaluate)
801 VALUE *l;
802 VALUE *r;
804 #ifdef EVAL_TRACE
805 trace ("eval");
806 #endif
807 l = eval1 (evaluate);
808 while (1)
810 if (nextarg ("|"))
812 r = eval1 (evaluate & null (l));
813 if (null (l))
815 freev (l);
816 l = r;
817 if (null (l))
819 freev (l);
820 l = int_value (0);
823 else
824 freev (r);
826 else
827 return l;