use gnulib's progname module
[platform/upstream/coreutils.git] / src / expr.c
1 /* expr -- evaluate expressions.
2    Copyright (C) 86, 1991-1997, 1999-2008 Free Software Foundation, Inc.
3
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 3 of the License, or
7    (at your option) any later version.
8
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.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Author: Mike Parker.
18
19    This program evaluates expressions.  Each token (operator, operand,
20    parenthesis) of the expression must be a seperate argument.  The
21    parser used is a reasonably general one, though any incarnation of
22    it is language-specific.  It is especially nice for expressions.
23
24    No parse tree is needed; a new node is evaluated immediately.
25    One function can handle multiple operators all of equal precedence,
26    provided they all associate ((x op x) op x).
27
28    Define EVAL_TRACE to print an evaluation trace.  */
29
30 #include <config.h>
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include "system.h"
34
35 #include <regex.h>
36 #include "long-options.h"
37 #include "error.h"
38 #include "inttostr.h"
39 #include "quotearg.h"
40 #include "strnumcmp.h"
41 #include "xstrtol.h"
42
43 /* The official name of this program (e.g., no `g' prefix).  */
44 #define PROGRAM_NAME "expr"
45
46 #define AUTHORS proper_name ("Mike Parker")
47
48 /* Exit statuses.  */
49 enum
50   {
51     /* Invalid expression: e.g., its form does not conform to the
52        grammar for expressions.  Our grammar is an extension of the
53        POSIX grammar.  */
54     EXPR_INVALID = 2,
55
56     /* An internal error occurred, e.g., arithmetic overflow, storage
57        exhaustion.  */
58     EXPR_FAILURE
59   };
60
61 /* The kinds of value we can have.  */
62 enum valtype
63 {
64   integer,
65   string
66 };
67 typedef enum valtype TYPE;
68
69 /* A value is.... */
70 struct valinfo
71 {
72   TYPE type;                    /* Which kind. */
73   union
74   {                             /* The value itself. */
75     intmax_t i;
76     char *s;
77   } u;
78 };
79 typedef struct valinfo VALUE;
80
81 /* The arguments given to the program, minus the program name.  */
82 static char **args;
83
84 static VALUE *eval (bool);
85 static bool nomoreargs (void);
86 static bool null (VALUE *v);
87 static void printv (VALUE *v);
88
89 void
90 usage (int status)
91 {
92   if (status != EXIT_SUCCESS)
93     fprintf (stderr, _("Try `%s --help' for more information.\n"),
94              program_name);
95   else
96     {
97       printf (_("\
98 Usage: %s EXPRESSION\n\
99   or:  %s OPTION\n\
100 "),
101               program_name, program_name);
102       putchar ('\n');
103       fputs (HELP_OPTION_DESCRIPTION, stdout);
104       fputs (VERSION_OPTION_DESCRIPTION, stdout);
105       fputs (_("\
106 \n\
107 Print the value of EXPRESSION to standard output.  A blank line below\n\
108 separates increasing precedence groups.  EXPRESSION may be:\n\
109 \n\
110   ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\
111 \n\
112   ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\
113 "), stdout);
114       fputs (_("\
115 \n\
116   ARG1 < ARG2       ARG1 is less than ARG2\n\
117   ARG1 <= ARG2      ARG1 is less than or equal to ARG2\n\
118   ARG1 = ARG2       ARG1 is equal to ARG2\n\
119   ARG1 != ARG2      ARG1 is unequal to ARG2\n\
120   ARG1 >= ARG2      ARG1 is greater than or equal to ARG2\n\
121   ARG1 > ARG2       ARG1 is greater than ARG2\n\
122 "), stdout);
123       fputs (_("\
124 \n\
125   ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\
126   ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\
127 "), stdout);
128       /* Tell xgettext that the "% A" below is not a printf-style
129          format string:  xgettext:no-c-format */
130       fputs (_("\
131 \n\
132   ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\
133   ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\
134   ARG1 % ARG2       arithmetic remainder of ARG1 divided by ARG2\n\
135 "), stdout);
136       fputs (_("\
137 \n\
138   STRING : REGEXP   anchored pattern match of REGEXP in STRING\n\
139 \n\
140   match STRING REGEXP        same as STRING : REGEXP\n\
141   substr STRING POS LENGTH   substring of STRING, POS counted from 1\n\
142   index STRING CHARS         index in STRING where any CHARS is found, or 0\n\
143   length STRING              length of STRING\n\
144 "), stdout);
145       fputs (_("\
146   + TOKEN                    interpret TOKEN as a string, even if it is a\n\
147                                keyword like `match' or an operator like `/'\n\
148 \n\
149   ( EXPRESSION )             value of EXPRESSION\n\
150 "), stdout);
151       fputs (_("\
152 \n\
153 Beware that many operators need to be escaped or quoted for shells.\n\
154 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
155 Pattern matches return the string matched between \\( and \\) or null; if\n\
156 \\( and \\) are not used, they return the number of characters matched or 0.\n\
157 "), stdout);
158       fputs (_("\
159 \n\
160 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
161 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
162 "), stdout);
163       emit_bug_reporting_address ();
164     }
165   exit (status);
166 }
167
168 /* Report a syntax error and exit.  */
169 static void
170 syntax_error (void)
171 {
172   error (EXPR_INVALID, 0, _("syntax error"));
173 }
174
175 /* Report an integer overflow for operation OP and exit.  */
176 static void
177 integer_overflow (char op)
178 {
179   error (EXPR_FAILURE, ERANGE, "%c", op);
180 }
181
182 int
183 main (int argc, char **argv)
184 {
185   VALUE *v;
186
187   initialize_main (&argc, &argv);
188   set_program_name (argv[0]);
189   setlocale (LC_ALL, "");
190   bindtextdomain (PACKAGE, LOCALEDIR);
191   textdomain (PACKAGE);
192
193   initialize_exit_failure (EXPR_FAILURE);
194   atexit (close_stdout);
195
196   parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
197                       usage, AUTHORS, (char const *) NULL);
198   /* The above handles --help and --version.
199      Since there is no other invocation of getopt, handle `--' here.  */
200   if (argc > 1 && STREQ (argv[1], "--"))
201     {
202       --argc;
203       ++argv;
204     }
205
206   if (argc <= 1)
207     {
208       error (0, 0, _("missing operand"));
209       usage (EXPR_INVALID);
210     }
211
212   args = argv + 1;
213
214   v = eval (true);
215   if (!nomoreargs ())
216     syntax_error ();
217   printv (v);
218
219   exit (null (v));
220 }
221
222 /* Return a VALUE for I.  */
223
224 static VALUE *
225 int_value (intmax_t i)
226 {
227   VALUE *v = xmalloc (sizeof *v);
228   v->type = integer;
229   v->u.i = i;
230   return v;
231 }
232
233 /* Return a VALUE for S.  */
234
235 static VALUE *
236 str_value (char const *s)
237 {
238   VALUE *v = xmalloc (sizeof *v);
239   v->type = string;
240   v->u.s = xstrdup (s);
241   return v;
242 }
243
244 /* Free VALUE V, including structure components.  */
245
246 static void
247 freev (VALUE *v)
248 {
249   if (v->type == string)
250     free (v->u.s);
251   free (v);
252 }
253
254 /* Print VALUE V.  */
255
256 static void
257 printv (VALUE *v)
258 {
259   char *p;
260   char buf[INT_BUFSIZE_BOUND (intmax_t)];
261
262   switch (v->type)
263     {
264     case integer:
265       p = imaxtostr (v->u.i, buf);
266       break;
267     case string:
268       p = v->u.s;
269       break;
270     default:
271       abort ();
272     }
273
274   puts (p);
275 }
276
277 /* Return true if V is a null-string or zero-number.  */
278
279 static bool
280 null (VALUE *v)
281 {
282   switch (v->type)
283     {
284     case integer:
285       return v->u.i == 0;
286     case string:
287       {
288         char const *cp = v->u.s;
289         if (*cp == '\0')
290           return true;
291
292         cp += (*cp == '-');
293
294         do
295           {
296             if (*cp != '0')
297               return false;
298           }
299         while (*++cp);
300
301         return true;
302       }
303     default:
304       abort ();
305     }
306 }
307
308 /* Return true if CP takes the form of an integer.  */
309
310 static bool
311 looks_like_integer (char const *cp)
312 {
313   cp += (*cp == '-');
314
315   do
316     if (! ISDIGIT (*cp))
317       return false;
318   while (*++cp);
319
320   return true;
321 }
322
323 /* Coerce V to a string value (can't fail).  */
324
325 static void
326 tostring (VALUE *v)
327 {
328   char buf[INT_BUFSIZE_BOUND (intmax_t)];
329
330   switch (v->type)
331     {
332     case integer:
333       v->u.s = xstrdup (imaxtostr (v->u.i, buf));
334       v->type = string;
335       break;
336     case string:
337       break;
338     default:
339       abort ();
340     }
341 }
342
343 /* Coerce V to an integer value.  Return true on success, false on failure.  */
344
345 static bool
346 toarith (VALUE *v)
347 {
348   switch (v->type)
349     {
350     case integer:
351       return true;
352     case string:
353       {
354         intmax_t value;
355
356         if (! looks_like_integer (v->u.s))
357           return false;
358         if (xstrtoimax (v->u.s, NULL, 10, &value, NULL) != LONGINT_OK)
359           error (EXPR_FAILURE, ERANGE, "%s", v->u.s);
360         free (v->u.s);
361         v->u.i = value;
362         v->type = integer;
363         return true;
364       }
365     default:
366       abort ();
367     }
368 }
369
370 /* Return true and advance if the next token matches STR exactly.
371    STR must not be NULL.  */
372
373 static bool
374 nextarg (char const *str)
375 {
376   if (*args == NULL)
377     return false;
378   else
379     {
380       bool r = STREQ (*args, str);
381       args += r;
382       return r;
383     }
384 }
385
386 /* Return true if there no more tokens.  */
387
388 static bool
389 nomoreargs (void)
390 {
391   return *args == 0;
392 }
393
394 #ifdef EVAL_TRACE
395 /* Print evaluation trace and args remaining.  */
396
397 static void
398 trace (fxn)
399      char *fxn;
400 {
401   char **a;
402
403   printf ("%s:", fxn);
404   for (a = args; *a; a++)
405     printf (" %s", *a);
406   putchar ('\n');
407 }
408 #endif
409
410 /* Do the : operator.
411    SV is the VALUE for the lhs (the string),
412    PV is the VALUE for the rhs (the pattern).  */
413
414 static VALUE *
415 docolon (VALUE *sv, VALUE *pv)
416 {
417   VALUE *v IF_LINT (= NULL);
418   const char *errmsg;
419   struct re_pattern_buffer re_buffer;
420   char fastmap[UCHAR_MAX + 1];
421   struct re_registers re_regs;
422   regoff_t matchlen;
423
424   tostring (sv);
425   tostring (pv);
426
427   re_regs.num_regs = 0;
428   re_regs.start = NULL;
429   re_regs.end = NULL;
430
431   re_buffer.buffer = NULL;
432   re_buffer.allocated = 0;
433   re_buffer.fastmap = fastmap;
434   re_buffer.translate = NULL;
435   re_syntax_options =
436     RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
437   errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
438   if (errmsg)
439     error (EXPR_INVALID, 0, "%s", errmsg);
440   re_buffer.newline_anchor = 0;
441
442   matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
443   if (0 <= matchlen)
444     {
445       /* Were \(...\) used? */
446       if (re_buffer.re_nsub > 0)
447         {
448           sv->u.s[re_regs.end[1]] = '\0';
449           v = str_value (sv->u.s + re_regs.start[1]);
450         }
451       else
452         v = int_value (matchlen);
453     }
454   else if (matchlen == -1)
455     {
456       /* Match failed -- return the right kind of null.  */
457       if (re_buffer.re_nsub > 0)
458         v = str_value ("");
459       else
460         v = int_value (0);
461     }
462   else
463     error (EXPR_FAILURE,
464            (matchlen == -2 ? errno : EOVERFLOW),
465            _("error in regular expression matcher"));
466
467   if (0 < re_regs.num_regs)
468     {
469       free (re_regs.start);
470       free (re_regs.end);
471     }
472   re_buffer.fastmap = NULL;
473   regfree (&re_buffer);
474   return v;
475 }
476
477 /* Handle bare operands and ( expr ) syntax.  */
478
479 static VALUE *
480 eval7 (bool evaluate)
481 {
482   VALUE *v;
483
484 #ifdef EVAL_TRACE
485   trace ("eval7");
486 #endif
487   if (nomoreargs ())
488     syntax_error ();
489
490   if (nextarg ("("))
491     {
492       v = eval (evaluate);
493       if (!nextarg (")"))
494         syntax_error ();
495       return v;
496     }
497
498   if (nextarg (")"))
499     syntax_error ();
500
501   return str_value (*args++);
502 }
503
504 /* Handle match, substr, index, and length keywords, and quoting "+".  */
505
506 static VALUE *
507 eval6 (bool evaluate)
508 {
509   VALUE *l;
510   VALUE *r;
511   VALUE *v;
512   VALUE *i1;
513   VALUE *i2;
514
515 #ifdef EVAL_TRACE
516   trace ("eval6");
517 #endif
518   if (nextarg ("+"))
519     {
520       if (nomoreargs ())
521         syntax_error ();
522       return str_value (*args++);
523     }
524   else if (nextarg ("length"))
525     {
526       r = eval6 (evaluate);
527       tostring (r);
528       v = int_value (strlen (r->u.s));
529       freev (r);
530       return v;
531     }
532   else if (nextarg ("match"))
533     {
534       l = eval6 (evaluate);
535       r = eval6 (evaluate);
536       if (evaluate)
537         {
538           v = docolon (l, r);
539           freev (l);
540         }
541       else
542         v = l;
543       freev (r);
544       return v;
545     }
546   else if (nextarg ("index"))
547     {
548       l = eval6 (evaluate);
549       r = eval6 (evaluate);
550       tostring (l);
551       tostring (r);
552       v = int_value (strcspn (l->u.s, r->u.s) + 1);
553       if (v->u.i == strlen (l->u.s) + 1)
554         v->u.i = 0;
555       freev (l);
556       freev (r);
557       return v;
558     }
559   else if (nextarg ("substr"))
560     {
561       size_t llen;
562       l = eval6 (evaluate);
563       i1 = eval6 (evaluate);
564       i2 = eval6 (evaluate);
565       tostring (l);
566       llen = strlen (l->u.s);
567       if (!toarith (i1) || !toarith (i2)
568           || llen < i1->u.i
569           || i1->u.i <= 0 || i2->u.i <= 0)
570         v = str_value ("");
571       else
572         {
573           size_t vlen = MIN (i2->u.i, llen - i1->u.i + 1);
574           char *vlim;
575           v = xmalloc (sizeof *v);
576           v->type = string;
577           v->u.s = xmalloc (vlen + 1);
578           vlim = mempcpy (v->u.s, l->u.s + i1->u.i - 1, vlen);
579           *vlim = '\0';
580         }
581       freev (l);
582       freev (i1);
583       freev (i2);
584       return v;
585     }
586   else
587     return eval7 (evaluate);
588 }
589
590 /* Handle : operator (pattern matching).
591    Calls docolon to do the real work.  */
592
593 static VALUE *
594 eval5 (bool evaluate)
595 {
596   VALUE *l;
597   VALUE *r;
598   VALUE *v;
599
600 #ifdef EVAL_TRACE
601   trace ("eval5");
602 #endif
603   l = eval6 (evaluate);
604   while (1)
605     {
606       if (nextarg (":"))
607         {
608           r = eval6 (evaluate);
609           if (evaluate)
610             {
611               v = docolon (l, r);
612               freev (l);
613               l = v;
614             }
615           freev (r);
616         }
617       else
618         return l;
619     }
620 }
621
622 /* Handle *, /, % operators.  */
623
624 static VALUE *
625 eval4 (bool evaluate)
626 {
627   VALUE *l;
628   VALUE *r;
629   enum { multiply, divide, mod } fxn;
630   intmax_t val = 0;
631
632 #ifdef EVAL_TRACE
633   trace ("eval4");
634 #endif
635   l = eval5 (evaluate);
636   while (1)
637     {
638       if (nextarg ("*"))
639         fxn = multiply;
640       else if (nextarg ("/"))
641         fxn = divide;
642       else if (nextarg ("%"))
643         fxn = mod;
644       else
645         return l;
646       r = eval5 (evaluate);
647       if (evaluate)
648         {
649           if (!toarith (l) || !toarith (r))
650             error (EXPR_INVALID, 0, _("non-numeric argument"));
651           if (fxn == multiply)
652             {
653               val = l->u.i * r->u.i;
654               if (! (l->u.i == 0 || r->u.i == 0
655                      || ((val < 0) == ((l->u.i < 0) ^ (r->u.i < 0))
656                          && val / l->u.i == r->u.i)))
657                 integer_overflow ('*');
658             }
659           else
660             {
661               if (r->u.i == 0)
662                 error (EXPR_INVALID, 0, _("division by zero"));
663               if (l->u.i < - INTMAX_MAX && r->u.i == -1)
664                 {
665                   /* Some x86-style hosts raise an exception for
666                      INT_MIN / -1 and INT_MIN % -1, so handle these
667                      problematic cases specially.  */
668                   if (fxn == divide)
669                     integer_overflow ('/');
670                   val = 0;
671                 }
672               else
673                 val = fxn == divide ? l->u.i / r->u.i : l->u.i % r->u.i;
674             }
675         }
676       freev (l);
677       freev (r);
678       l = int_value (val);
679     }
680 }
681
682 /* Handle +, - operators.  */
683
684 static VALUE *
685 eval3 (bool evaluate)
686 {
687   VALUE *l;
688   VALUE *r;
689   enum { plus, minus } fxn;
690   intmax_t val = 0;
691
692 #ifdef EVAL_TRACE
693   trace ("eval3");
694 #endif
695   l = eval4 (evaluate);
696   while (1)
697     {
698       if (nextarg ("+"))
699         fxn = plus;
700       else if (nextarg ("-"))
701         fxn = minus;
702       else
703         return l;
704       r = eval4 (evaluate);
705       if (evaluate)
706         {
707           if (!toarith (l) || !toarith (r))
708             error (EXPR_INVALID, 0, _("non-numeric argument"));
709           if (fxn == plus)
710             {
711               val = l->u.i + r->u.i;
712               if ((val < l->u.i) != (r->u.i < 0))
713                 integer_overflow ('+');
714             }
715           else
716             {
717               val = l->u.i - r->u.i;
718               if ((l->u.i < val) != (r->u.i < 0))
719                 integer_overflow ('-');
720             }
721         }
722       freev (l);
723       freev (r);
724       l = int_value (val);
725     }
726 }
727
728 /* Handle comparisons.  */
729
730 static VALUE *
731 eval2 (bool evaluate)
732 {
733   VALUE *l;
734
735 #ifdef EVAL_TRACE
736   trace ("eval2");
737 #endif
738   l = eval3 (evaluate);
739   while (1)
740     {
741       VALUE *r;
742       enum
743         {
744           less_than, less_equal, equal, not_equal, greater_equal, greater_than
745         } fxn;
746       bool val = false;
747
748       if (nextarg ("<"))
749         fxn = less_than;
750       else if (nextarg ("<="))
751         fxn = less_equal;
752       else if (nextarg ("=") || nextarg ("=="))
753         fxn = equal;
754       else if (nextarg ("!="))
755         fxn = not_equal;
756       else if (nextarg (">="))
757         fxn = greater_equal;
758       else if (nextarg (">"))
759         fxn = greater_than;
760       else
761         return l;
762       r = eval3 (evaluate);
763
764       if (evaluate)
765         {
766           int cmp;
767           tostring (l);
768           tostring (r);
769
770           if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
771             cmp = strintcmp (l->u.s, r->u.s);
772           else
773             {
774               errno = 0;
775               cmp = strcoll (l->u.s, r->u.s);
776
777               if (errno)
778                 {
779                   error (0, errno, _("string comparison failed"));
780                   error (0, 0, _("Set LC_ALL='C' to work around the problem."));
781                   error (EXPR_INVALID, 0,
782                          _("The strings compared were %s and %s."),
783                          quotearg_n_style (0, locale_quoting_style, l->u.s),
784                          quotearg_n_style (1, locale_quoting_style, r->u.s));
785                 }
786             }
787
788           switch (fxn)
789             {
790             case less_than:     val = (cmp <  0); break;
791             case less_equal:    val = (cmp <= 0); break;
792             case equal:         val = (cmp == 0); break;
793             case not_equal:     val = (cmp != 0); break;
794             case greater_equal: val = (cmp >= 0); break;
795             case greater_than:  val = (cmp >  0); break;
796             default: abort ();
797             }
798         }
799
800       freev (l);
801       freev (r);
802       l = int_value (val);
803     }
804 }
805
806 /* Handle &.  */
807
808 static VALUE *
809 eval1 (bool evaluate)
810 {
811   VALUE *l;
812   VALUE *r;
813
814 #ifdef EVAL_TRACE
815   trace ("eval1");
816 #endif
817   l = eval2 (evaluate);
818   while (1)
819     {
820       if (nextarg ("&"))
821         {
822           r = eval2 (evaluate & ~ null (l));
823           if (null (l) || null (r))
824             {
825               freev (l);
826               freev (r);
827               l = int_value (0);
828             }
829           else
830             freev (r);
831         }
832       else
833         return l;
834     }
835 }
836
837 /* Handle |.  */
838
839 static VALUE *
840 eval (bool evaluate)
841 {
842   VALUE *l;
843   VALUE *r;
844
845 #ifdef EVAL_TRACE
846   trace ("eval");
847 #endif
848   l = eval1 (evaluate);
849   while (1)
850     {
851       if (nextarg ("|"))
852         {
853           r = eval1 (evaluate & null (l));
854           if (null (l))
855             {
856               freev (l);
857               l = r;
858               if (null (l))
859                 {
860                   freev (l);
861                   l = int_value (0);
862                 }
863             }
864           else
865             freev (r);
866         }
867       else
868         return l;
869     }
870 }