(NEW): Undefine to avoid warning about redefinition.
[platform/upstream/coreutils.git] / src / expr.c
1 /* expr -- evaluate expressions.
2    Copyright (C) 86, 1991-1997, 1999 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "xalloc.h"
40
41 /* The official name of this program (e.g., no `g' prefix).  */
42 #define PROGRAM_NAME "expr"
43
44 #define AUTHORS "Mike Parker"
45
46 #undef NEW
47 #define NEW(Type) XMALLOC (Type, 1)
48 #define OLD(x) free ((char *) x)
49
50 /* The kinds of value we can have.  */
51 enum valtype
52 {
53   integer,
54   string
55 };
56 typedef enum valtype TYPE;
57
58 /* A value is.... */
59 struct valinfo
60 {
61   TYPE type;                    /* Which kind. */
62   union
63   {                             /* The value itself. */
64     int i;
65     char *s;
66   } u;
67 };
68 typedef struct valinfo VALUE;
69
70 /* Non-zero if the POSIXLY_CORRECT environment variable is set.
71    The unary operator `quote' is disabled when this variable is zero.  */
72 static int posixly_correct;
73
74 /* The arguments given to the program, minus the program name.  */
75 static char **args;
76
77 /* The name this program was run with. */
78 char *program_name;
79
80 static VALUE *docolon PARAMS ((VALUE *sv, VALUE *pv));
81 static VALUE *eval PARAMS ((void));
82 static VALUE *int_value PARAMS ((int i));
83 static VALUE *str_value PARAMS ((char *s));
84 static int isstring PARAMS ((VALUE *v));
85 static int nextarg PARAMS ((char *str));
86 static int nomoreargs PARAMS ((void));
87 static int null PARAMS ((VALUE *v));
88 static int toarith PARAMS ((VALUE *v));
89 static void freev PARAMS ((VALUE *v));
90 static void printv PARAMS ((VALUE *v));
91 static void tostring PARAMS ((VALUE *v));
92
93 #ifdef EVAL_TRACE
94 static void trace ();
95 #endif
96
97 void
98 usage (int status)
99 {
100   if (status != 0)
101     fprintf (stderr, _("Try `%s --help' for more information.\n"),
102              program_name);
103   else
104     {
105       printf (_("\
106 Usage: %s EXPRESSION\n\
107   or:  %s OPTION\n\
108 "),
109               program_name, program_name);
110       printf (_("\
111 \n\
112   --help      display this help and exit\n\
113   --version   output version information and exit\n\
114 \n\
115 "));
116       printf (_("\
117 Print the value of EXPRESSION to standard output.  A blank line below\n\
118 separates increasing precedence groups.  EXPRESSION may be:\n\
119 \n\
120   ARG1 | ARG2       ARG1 if it is neither null nor 0, otherwise ARG2\n\
121 \n\
122   ARG1 & ARG2       ARG1 if neither argument is null or 0, otherwise 0\n\
123 \n\
124   ARG1 < ARG2       ARG1 is less than ARG2\n\
125   ARG1 <= ARG2      ARG1 is less than or equal to ARG2\n\
126   ARG1 = ARG2       ARG1 is equal to ARG2\n\
127   ARG1 != ARG2      ARG1 is unequal to ARG2\n\
128   ARG1 >= ARG2      ARG1 is greater than or equal to ARG2\n\
129   ARG1 > ARG2       ARG1 is greater than ARG2\n\
130 \n\
131   ARG1 + ARG2       arithmetic sum of ARG1 and ARG2\n\
132   ARG1 - ARG2       arithmetic difference of ARG1 and ARG2\n\
133 \n\
134   ARG1 * ARG2       arithmetic product of ARG1 and ARG2\n\
135   ARG1 / ARG2       arithmetic quotient of ARG1 divided by ARG2\n\
136   ARG1 %% ARG2       arithmetic remainder of ARG1 divided by ARG2\n\
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   quote TOKEN                interpret TOKEN as a string, even if it is a\n\
145                                keyword like `match' or an operator like `/'\n\
146 \n\
147   ( EXPRESSION )             value of EXPRESSION\n\
148 "));
149       printf (_("\
150 \n\
151 Beware that many operators need to be escaped or quoted for shells.\n\
152 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
153 Pattern matches return the string matched between \\( and \\) or null; if\n\
154 \\( and \\) are not used, they return the number of characters matched or 0.\n\
155 "));
156       puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
157     }
158   exit (status);
159 }
160
161 int
162 main (int argc, char **argv)
163 {
164   VALUE *v;
165
166   program_name = argv[0];
167   setlocale (LC_ALL, "");
168   bindtextdomain (PACKAGE, LOCALEDIR);
169   textdomain (PACKAGE);
170
171   posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
172
173   /* Recognize --help or --version only if POSIXLY_CORRECT is not set.  */
174   if (!posixly_correct)
175     parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
176                         AUTHORS, usage);
177
178   if (argc == 1)
179     {
180       error (0, 0, _("too few arguments"));
181       usage (1);
182     }
183
184   args = argv + 1;
185
186   v = eval ();
187   if (!nomoreargs ())
188     error (2, 0, _("syntax error"));
189   printv (v);
190
191   exit (null (v));
192 }
193
194 /* Return a VALUE for I.  */
195
196 static VALUE *
197 int_value (int i)
198 {
199   VALUE *v;
200
201   v = NEW (VALUE);
202   v->type = integer;
203   v->u.i = i;
204   return v;
205 }
206
207 /* Return a VALUE for S.  */
208
209 static VALUE *
210 str_value (char *s)
211 {
212   VALUE *v;
213
214   v = NEW (VALUE);
215   v->type = string;
216   v->u.s = xstrdup (s);
217   return v;
218 }
219
220 /* Free VALUE V, including structure components.  */
221
222 static void
223 freev (VALUE *v)
224 {
225   if (v->type == string)
226     free (v->u.s);
227   OLD (v);
228 }
229
230 /* Print VALUE V.  */
231
232 static void
233 printv (VALUE *v)
234 {
235   switch (v->type)
236     {
237     case integer:
238       printf ("%d\n", v->u.i);
239       break;
240     case string:
241       printf ("%s\n", v->u.s);
242       break;
243     default:
244       abort ();
245     }
246 }
247
248 /* Return nonzero if V is a null-string or zero-number.  */
249
250 static int
251 null (VALUE *v)
252 {
253   switch (v->type)
254     {
255     case integer:
256       return v->u.i == 0;
257     case string:
258       return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
259     default:
260       abort ();
261     }
262 }
263
264 /* Return nonzero if V is a string value.  */
265
266 static int
267 isstring (VALUE *v)
268 {
269   return v->type == string;
270 }
271
272 /* Coerce V to a string value (can't fail).  */
273
274 static void
275 tostring (VALUE *v)
276 {
277   char *temp;
278
279   switch (v->type)
280     {
281     case integer:
282       temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
283       sprintf (temp, "%d", v->u.i);
284       v->u.s = temp;
285       v->type = string;
286       break;
287     case string:
288       break;
289     default:
290       abort ();
291     }
292 }
293
294 /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
295
296 static int
297 toarith (VALUE *v)
298 {
299   int i;
300   int neg;
301   char *cp;
302
303   switch (v->type)
304     {
305     case integer:
306       return 1;
307     case string:
308       i = 0;
309       cp = v->u.s;
310       /* Don't interpret the empty string as an integer.  */
311       if (*cp == 0)
312         return 0;
313       neg = (*cp == '-');
314       if (neg)
315         cp++;
316       for (; *cp; cp++)
317         {
318           if (ISDIGIT (*cp))
319             i = i * 10 + *cp - '0';
320           else
321             return 0;
322         }
323       free (v->u.s);
324       v->u.i = i * (neg ? -1 : 1);
325       v->type = integer;
326       return 1;
327     default:
328       abort ();
329     }
330 }
331
332 /* Return nonzero if the next token matches STR exactly.
333    STR must not be NULL.  */
334
335 static int
336 nextarg (char *str)
337 {
338   if (*args == NULL)
339     return 0;
340   return strcmp (*args, str) == 0;
341 }
342
343 /* Return nonzero if there no more tokens.  */
344
345 static int
346 nomoreargs (void)
347 {
348   return *args == 0;
349 }
350
351 /* The comparison operator handling functions.  */
352
353 #define cmpf(name, rel)                         \
354 static                                          \
355 int name (l, r) VALUE *l; VALUE *r;             \
356 {                                               \
357   if (isstring (l) || isstring (r))             \
358     {                                           \
359        tostring (l);                            \
360        tostring (r);                            \
361        return strcmp (l->u.s, r->u.s) rel 0;    \
362     }                                           \
363  else                                           \
364    return l->u.i rel r->u.i;                    \
365 }
366  cmpf (less_than, <)
367  cmpf (less_equal, <=)
368  cmpf (equal, ==)
369  cmpf (not_equal, !=)
370  cmpf (greater_equal, >=)
371  cmpf (greater_than, >)
372
373 #undef cmpf
374
375 /* The arithmetic operator handling functions.  */
376
377 #define arithf(name, op)                        \
378 static                                          \
379 int name (l, r) VALUE *l; VALUE *r;             \
380 {                                               \
381   if (!toarith (l) || !toarith (r))             \
382     error (2, 0, _("non-numeric argument"));    \
383   return l->u.i op r->u.i;                      \
384 }
385
386 #define arithdivf(name, op)                     \
387 int name (l, r) VALUE *l; VALUE *r;             \
388 {                                               \
389   if (!toarith (l) || !toarith (r))             \
390     error (2, 0, _("non-numeric argument"));    \
391   if (r->u.i == 0)                              \
392     error (2, 0, _("division by zero"));                \
393   return l->u.i op r->u.i;                      \
394 }
395
396  arithf (plus, +)
397  arithf (minus, -)
398  arithf (multiply, *)
399  arithdivf (divide, /)
400  arithdivf (mod, %)
401
402 #undef arithf
403 #undef arithdivf
404
405 #ifdef EVAL_TRACE
406 /* Print evaluation trace and args remaining.  */
407
408 static void
409 trace (fxn)
410      char *fxn;
411 {
412   char **a;
413
414   printf ("%s:", fxn);
415   for (a = args; *a; a++)
416     printf (" %s", *a);
417   putchar ('\n');
418 }
419 #endif
420
421 /* Do the : operator.
422    SV is the VALUE for the lhs (the string),
423    PV is the VALUE for the rhs (the pattern).  */
424
425 static VALUE *
426 docolon (VALUE *sv, VALUE *pv)
427 {
428   VALUE *v;
429   const char *errmsg;
430   struct re_pattern_buffer re_buffer;
431   struct re_registers re_regs;
432   int len;
433
434   tostring (sv);
435   tostring (pv);
436
437   if (pv->u.s[0] == '^')
438     {
439       error (0, 0, _("\
440 warning: unportable BRE: `%s': using `^' as the first character\n\
441 of the basic regular expression is not portable; it is being ignored"),
442              pv->u.s);
443     }
444
445   len = strlen (pv->u.s);
446   memset (&re_buffer, 0, sizeof (re_buffer));
447   memset (&re_regs, 0, sizeof (re_regs));
448   re_buffer.allocated = 2 * len;
449   re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
450   re_buffer.translate = 0;
451   re_syntax_options = RE_SYNTAX_POSIX_BASIC;
452   errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
453   if (errmsg)
454     error (2, 0, "%s", errmsg);
455
456   len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
457   if (len >= 0)
458     {
459       /* Were \(...\) used? */
460       if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
461         {
462           sv->u.s[re_regs.end[1]] = '\0';
463           v = str_value (sv->u.s + re_regs.start[1]);
464         }
465       else
466         v = int_value (len);
467     }
468   else
469     {
470       /* Match failed -- return the right kind of null.  */
471       if (re_buffer.re_nsub > 0)
472         v = str_value ("");
473       else
474         v = int_value (0);
475     }
476   free (re_buffer.buffer);
477   return v;
478 }
479
480 /* Handle bare operands and ( expr ) syntax.  */
481
482 static VALUE *
483 eval7 (void)
484 {
485   VALUE *v;
486
487 #ifdef EVAL_TRACE
488   trace ("eval7");
489 #endif
490   if (nomoreargs ())
491     error (2, 0, _("syntax error"));
492
493   if (nextarg ("("))
494     {
495       args++;
496       v = eval ();
497       if (!nextarg (")"))
498         error (2, 0, _("syntax error"));
499       args++;
500       return v;
501     }
502
503   if (nextarg (")"))
504     error (2, 0, _("syntax error"));
505
506   return str_value (*args++);
507 }
508
509 /* Handle match, substr, index, length, and quote keywords.  */
510
511 static VALUE *
512 eval6 (void)
513 {
514   VALUE *l;
515   VALUE *r;
516   VALUE *v;
517   VALUE *i1;
518   VALUE *i2;
519
520 #ifdef EVAL_TRACE
521   trace ("eval6");
522 #endif
523   if (!posixly_correct && nextarg ("quote"))
524     {
525       args++;
526       if (nomoreargs ())
527         error (2, 0, _("syntax error"));
528       return str_value (*args++);
529     }
530   else if (nextarg ("length"))
531     {
532       args++;
533       r = eval6 ();
534       tostring (r);
535       v = int_value (strlen (r->u.s));
536       freev (r);
537       return v;
538     }
539   else if (nextarg ("match"))
540     {
541       args++;
542       l = eval6 ();
543       r = eval6 ();
544       v = docolon (l, r);
545       freev (l);
546       freev (r);
547       return v;
548     }
549   else if (nextarg ("index"))
550     {
551       args++;
552       l = eval6 ();
553       r = eval6 ();
554       tostring (l);
555       tostring (r);
556       v = int_value (strcspn (l->u.s, r->u.s) + 1);
557       if (v->u.i == (int) strlen (l->u.s) + 1)
558         v->u.i = 0;
559       freev (l);
560       freev (r);
561       return v;
562     }
563   else if (nextarg ("substr"))
564     {
565       args++;
566       l = eval6 ();
567       i1 = eval6 ();
568       i2 = eval6 ();
569       tostring (l);
570       if (!toarith (i1) || !toarith (i2)
571           || i1->u.i > (int) strlen (l->u.s)
572           || i1->u.i <= 0 || i2->u.i <= 0)
573         v = str_value ("");
574       else
575         {
576           v = NEW (VALUE);
577           v->type = string;
578           v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
579                             l->u.s + i1->u.i - 1, i2->u.i);
580           v->u.s[i2->u.i] = 0;
581         }
582       freev (l);
583       freev (i1);
584       freev (i2);
585       return v;
586     }
587   else
588     return eval7 ();
589 }
590
591 /* Handle : operator (pattern matching).
592    Calls docolon to do the real work.  */
593
594 static VALUE *
595 eval5 (void)
596 {
597   VALUE *l;
598   VALUE *r;
599   VALUE *v;
600
601 #ifdef EVAL_TRACE
602   trace ("eval5");
603 #endif
604   l = eval6 ();
605   while (1)
606     {
607       if (nextarg (":"))
608         {
609           args++;
610           r = eval6 ();
611           v = docolon (l, r);
612           freev (l);
613           freev (r);
614           l = v;
615         }
616       else
617         return l;
618     }
619 }
620
621 /* Handle *, /, % operators.  */
622
623 static VALUE *
624 eval4 (void)
625 {
626   VALUE *l;
627   VALUE *r;
628   int (*fxn) ();
629   int val;
630
631 #ifdef EVAL_TRACE
632   trace ("eval4");
633 #endif
634   l = eval5 ();
635   while (1)
636     {
637       if (nextarg ("*"))
638         fxn = multiply;
639       else if (nextarg ("/"))
640         fxn = divide;
641       else if (nextarg ("%"))
642         fxn = mod;
643       else
644         return l;
645       args++;
646       r = eval5 ();
647       val = (*fxn) (l, r);
648       freev (l);
649       freev (r);
650       l = int_value (val);
651     }
652 }
653
654 /* Handle +, - operators.  */
655
656 static VALUE *
657 eval3 (void)
658 {
659   VALUE *l;
660   VALUE *r;
661   int (*fxn) ();
662   int val;
663
664 #ifdef EVAL_TRACE
665   trace ("eval3");
666 #endif
667   l = eval4 ();
668   while (1)
669     {
670       if (nextarg ("+"))
671         fxn = plus;
672       else if (nextarg ("-"))
673         fxn = minus;
674       else
675         return l;
676       args++;
677       r = eval4 ();
678       val = (*fxn) (l, r);
679       freev (l);
680       freev (r);
681       l = int_value (val);
682     }
683 }
684
685 /* Handle comparisons.  */
686
687 static VALUE *
688 eval2 (void)
689 {
690   VALUE *l;
691   VALUE *r;
692   int (*fxn) ();
693   int val;
694
695 #ifdef EVAL_TRACE
696   trace ("eval2");
697 #endif
698   l = eval3 ();
699   while (1)
700     {
701       if (nextarg ("<"))
702         fxn = less_than;
703       else if (nextarg ("<="))
704         fxn = less_equal;
705       else if (nextarg ("=") || nextarg ("=="))
706         fxn = equal;
707       else if (nextarg ("!="))
708         fxn = not_equal;
709       else if (nextarg (">="))
710         fxn = greater_equal;
711       else if (nextarg (">"))
712         fxn = greater_than;
713       else
714         return l;
715       args++;
716       r = eval3 ();
717       toarith (l);
718       toarith (r);
719       val = (*fxn) (l, r);
720       freev (l);
721       freev (r);
722       l = int_value (val);
723     }
724 }
725
726 /* Handle &.  */
727
728 static VALUE *
729 eval1 (void)
730 {
731   VALUE *l;
732   VALUE *r;
733
734 #ifdef EVAL_TRACE
735   trace ("eval1");
736 #endif
737   l = eval2 ();
738   while (1)
739     {
740       if (nextarg ("&"))
741         {
742           args++;
743           r = eval2 ();
744           if (null (l) || null (r))
745             {
746               freev (l);
747               freev (r);
748               l = int_value (0);
749             }
750           else
751             freev (r);
752         }
753       else
754         return l;
755     }
756 }
757
758 /* Handle |.  */
759
760 static VALUE *
761 eval (void)
762 {
763   VALUE *l;
764   VALUE *r;
765
766 #ifdef EVAL_TRACE
767   trace ("eval");
768 #endif
769   l = eval1 ();
770   while (1)
771     {
772       if (nextarg ("|"))
773         {
774           args++;
775           r = eval1 ();
776           if (null (l))
777             {
778               freev (l);
779               l = r;
780             }
781           else
782             freev (r);
783         }
784       else
785         return l;
786     }
787 }