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