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