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