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