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