Don't include version.h.
[coreutils.git] / src / expr.c
blob4fc074910dc97a82e74b5eaf5f80cc5ab540eccc
1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
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.
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.
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
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Author: Mike Parker.
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.
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).
29 Define EVAL_TRACE to print an evaluation trace. */
31 #include <config.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include <regex.h>
36 #include "system.h"
37 #include "long-options.h"
38 #include "error.h"
40 #define NEW(type) ((type *) xmalloc (sizeof (type)))
41 #define OLD(x) free ((char *) x)
43 /* The kinds of value we can have. */
44 enum valtype
46 integer,
47 string
49 typedef enum valtype TYPE;
51 /* A value is.... */
52 struct valinfo
54 TYPE type; /* Which kind. */
55 union
56 { /* The value itself. */
57 int i;
58 char *s;
59 } u;
61 typedef struct valinfo VALUE;
63 /* The arguments given to the program, minus the program name. */
64 static char **args;
66 /* The name this program was run with. */
67 char *program_name;
69 char *xstrdup ();
70 char *strstr ();
71 char *xmalloc ();
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));
86 #ifdef EVAL_TRACE
87 static void trace ();
88 #endif
90 static void
91 usage (int status)
93 if (status != 0)
94 fprintf (stderr, _("Try `%s --help' for more information.\n"),
95 program_name);
96 else
98 printf (_("\
99 Usage: %s EXPRESSION\n\
100 or: %s OPTION\n\
102 program_name, program_name);
103 printf (_("\
105 --help display this help and exit\n\
106 --version output version information and exit\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\
113 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
115 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\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\
124 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
125 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\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\
131 STRING : REGEXP anchored pattern match of REGEXP in STRING\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\
138 ( EXPRESSION ) value of EXPRESSION\n\
139 "));
140 printf (_("\
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 "));
148 exit (status);
151 void
152 main (int argc, char **argv)
154 VALUE *v;
156 program_name = argv[0];
157 setlocale (LC_ALL, "");
158 bindtextdomain (PACKAGE, LOCALEDIR);
159 textdomain (PACKAGE);
161 parse_long_options (argc, argv, "expr", PACKAGE_VERSION, usage);
163 if (argc == 1)
165 error (0, 0, _("too few arguments"));
166 usage (1);
169 args = argv + 1;
171 v = eval ();
172 if (!nomoreargs ())
173 error (2, 0, _("syntax error"));
174 printv (v);
176 exit (null (v));
179 /* Return a VALUE for I. */
181 static VALUE *
182 int_value (int i)
184 VALUE *v;
186 v = NEW (VALUE);
187 v->type = integer;
188 v->u.i = i;
189 return v;
192 /* Return a VALUE for S. */
194 static VALUE *
195 str_value (char *s)
197 VALUE *v;
199 v = NEW (VALUE);
200 v->type = string;
201 v->u.s = xstrdup (s);
202 return v;
205 /* Free VALUE V, including structure components. */
207 static void
208 freev (VALUE *v)
210 if (v->type == string)
211 free (v->u.s);
212 OLD (v);
215 /* Print VALUE V. */
217 static void
218 printv (VALUE *v)
220 switch (v->type)
222 case integer:
223 printf ("%d\n", v->u.i);
224 break;
225 case string:
226 printf ("%s\n", v->u.s);
227 break;
228 default:
229 abort ();
233 /* Return nonzero if V is a null-string or zero-number. */
235 static int
236 null (VALUE *v)
238 switch (v->type)
240 case integer:
241 return v->u.i == 0;
242 case string:
243 return v->u.s[0] == '\0' || strcmp(v->u.s, "0") == 0;
244 default:
245 abort ();
249 /* Return nonzero if V is a string value. */
251 static int
252 isstring (VALUE *v)
254 return v->type == string;
257 /* Coerce V to a string value (can't fail). */
259 static void
260 tostring (VALUE *v)
262 char *temp;
264 switch (v->type)
266 case integer:
267 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
268 sprintf (temp, "%d", v->u.i);
269 v->u.s = temp;
270 v->type = string;
271 break;
272 case string:
273 break;
274 default:
275 abort ();
279 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
281 static int
282 toarith (VALUE *v)
284 int i;
285 int neg;
286 char *cp;
288 switch (v->type)
290 case integer:
291 return 1;
292 case string:
293 i = 0;
294 cp = v->u.s;
295 /* Don't interpret the empty string as an integer. */
296 if (*cp == 0)
297 return 0;
298 neg = (*cp == '-');
299 if (neg)
300 cp++;
301 for (; *cp; cp++)
303 if (ISDIGIT (*cp))
304 i = i * 10 + *cp - '0';
305 else
306 return 0;
308 free (v->u.s);
309 v->u.i = i * (neg ? -1 : 1);
310 v->type = integer;
311 return 1;
312 default:
313 abort ();
317 /* Return nonzero if the next token matches STR exactly.
318 STR must not be NULL. */
320 static int
321 nextarg (char *str)
323 if (*args == NULL)
324 return 0;
325 return strcmp (*args, str) == 0;
328 /* Return nonzero if there no more tokens. */
330 static int
331 nomoreargs (void)
333 return *args == 0;
336 /* The comparison operator handling functions. */
338 #define cmpf(name, rel) \
339 static \
340 int name (l, r) VALUE *l; VALUE *r; \
342 if (isstring (l) || isstring (r)) \
344 tostring (l); \
345 tostring (r); \
346 return strcmp (l->u.s, r->u.s) rel 0; \
348 else \
349 return l->u.i rel r->u.i; \
351 cmpf (less_than, <)
352 cmpf (less_equal, <=)
353 cmpf (equal, ==)
354 cmpf (not_equal, !=)
355 cmpf (greater_equal, >=)
356 cmpf (greater_than, >)
358 #undef cmpf
360 /* The arithmetic operator handling functions. */
362 #define arithf(name, op) \
363 static \
364 int name (l, r) VALUE *l; VALUE *r; \
366 if (!toarith (l) || !toarith (r)) \
367 error (2, 0, _("non-numeric argument")); \
368 return l->u.i op r->u.i; \
371 #define arithdivf(name, op) \
372 int name (l, r) VALUE *l; VALUE *r; \
374 if (!toarith (l) || !toarith (r)) \
375 error (2, 0, _("non-numeric argument")); \
376 if (r->u.i == 0) \
377 error (2, 0, _("division by zero")); \
378 return l->u.i op r->u.i; \
381 arithf (plus, +)
382 arithf (minus, -)
383 arithf (multiply, *)
384 arithdivf (divide, /)
385 arithdivf (mod, %)
387 #undef arithf
388 #undef arithdivf
390 #ifdef EVAL_TRACE
391 /* Print evaluation trace and args remaining. */
393 static void
394 trace (fxn)
395 char *fxn;
397 char **a;
399 printf ("%s:", fxn);
400 for (a = args; *a; a++)
401 printf (" %s", *a);
402 putchar ('\n');
404 #endif
406 /* Do the : operator.
407 SV is the VALUE for the lhs (the string),
408 PV is the VALUE for the rhs (the pattern). */
410 static VALUE *
411 docolon (VALUE *sv, VALUE *pv)
413 VALUE *v;
414 const char *errmsg;
415 struct re_pattern_buffer re_buffer;
416 struct re_registers re_regs;
417 int len;
419 tostring (sv);
420 tostring (pv);
422 len = strlen (pv->u.s);
423 memset (&re_buffer, 0, sizeof (re_buffer));
424 memset (&re_regs, 0, sizeof (re_regs));
425 re_buffer.allocated = 2 * len;
426 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
427 re_buffer.translate = 0;
428 re_syntax_options = RE_SYNTAX_POSIX_MINIMAL_BASIC;
429 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
430 if (errmsg)
431 error (2, 0, "%s", errmsg);
433 len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
434 if (len >= 0)
436 /* Were \(...\) used? */
437 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
439 sv->u.s[re_regs.end[1]] = '\0';
440 v = str_value (sv->u.s + re_regs.start[1]);
442 else
443 v = int_value (len);
445 else
447 /* Match failed -- return the right kind of null. */
448 if (strstr (pv->u.s, "\\("))
449 v = str_value ("");
450 else
451 v = int_value (0);
453 free (re_buffer.buffer);
454 return v;
457 /* Handle bare operands and ( expr ) syntax. */
459 static VALUE *
460 eval7 (void)
462 VALUE *v;
464 #ifdef EVAL_TRACE
465 trace ("eval7");
466 #endif
467 if (nomoreargs ())
468 error (2, 0, _("syntax error"));
470 if (nextarg ("("))
472 args++;
473 v = eval ();
474 if (!nextarg (")"))
475 error (2, 0, _("syntax error"));
476 args++;
477 return v;
480 if (nextarg (")"))
481 error (2, 0, _("syntax error"));
483 return str_value (*args++);
486 /* Handle match, substr, index, and length keywords. */
488 static VALUE *
489 eval6 (void)
491 VALUE *l;
492 VALUE *r;
493 VALUE *v;
494 VALUE *i1;
495 VALUE *i2;
497 #ifdef EVAL_TRACE
498 trace ("eval6");
499 #endif
500 if (nextarg ("length"))
502 args++;
503 r = eval6 ();
504 tostring (r);
505 v = int_value (strlen (r->u.s));
506 freev (r);
507 return v;
509 else if (nextarg ("match"))
511 args++;
512 l = eval6 ();
513 r = eval6 ();
514 v = docolon (l, r);
515 freev (l);
516 freev (r);
517 return v;
519 else if (nextarg ("index"))
521 args++;
522 l = eval6 ();
523 r = eval6 ();
524 tostring (l);
525 tostring (r);
526 v = int_value (strcspn (l->u.s, r->u.s) + 1);
527 if (v->u.i == (int) strlen (l->u.s) + 1)
528 v->u.i = 0;
529 freev (l);
530 freev (r);
531 return v;
533 else if (nextarg ("substr"))
535 args++;
536 l = eval6 ();
537 i1 = eval6 ();
538 i2 = eval6 ();
539 tostring (l);
540 if (!toarith (i1) || !toarith (i2)
541 || i1->u.i > (int) strlen (l->u.s)
542 || i1->u.i <= 0 || i2->u.i <= 0)
543 v = str_value ("");
544 else
546 v = NEW (VALUE);
547 v->type = string;
548 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
549 l->u.s + i1->u.i - 1, i2->u.i);
550 v->u.s[i2->u.i] = 0;
552 freev (l);
553 freev (i1);
554 freev (i2);
555 return v;
557 else
558 return eval7 ();
561 /* Handle : operator (pattern matching).
562 Calls docolon to do the real work. */
564 static VALUE *
565 eval5 (void)
567 VALUE *l;
568 VALUE *r;
569 VALUE *v;
571 #ifdef EVAL_TRACE
572 trace ("eval5");
573 #endif
574 l = eval6 ();
575 while (1)
577 if (nextarg (":"))
579 args++;
580 r = eval6 ();
581 v = docolon (l, r);
582 freev (l);
583 freev (r);
584 l = v;
586 else
587 return l;
591 /* Handle *, /, % operators. */
593 static VALUE *
594 eval4 (void)
596 VALUE *l;
597 VALUE *r;
598 int (*fxn) ();
599 int val;
601 #ifdef EVAL_TRACE
602 trace ("eval4");
603 #endif
604 l = eval5 ();
605 while (1)
607 if (nextarg ("*"))
608 fxn = multiply;
609 else if (nextarg ("/"))
610 fxn = divide;
611 else if (nextarg ("%"))
612 fxn = mod;
613 else
614 return l;
615 args++;
616 r = eval5 ();
617 val = (*fxn) (l, r);
618 freev (l);
619 freev (r);
620 l = int_value (val);
624 /* Handle +, - operators. */
626 static VALUE *
627 eval3 (void)
629 VALUE *l;
630 VALUE *r;
631 int (*fxn) ();
632 int val;
634 #ifdef EVAL_TRACE
635 trace ("eval3");
636 #endif
637 l = eval4 ();
638 while (1)
640 if (nextarg ("+"))
641 fxn = plus;
642 else if (nextarg ("-"))
643 fxn = minus;
644 else
645 return l;
646 args++;
647 r = eval4 ();
648 val = (*fxn) (l, r);
649 freev (l);
650 freev (r);
651 l = int_value (val);
655 /* Handle comparisons. */
657 static VALUE *
658 eval2 (void)
660 VALUE *l;
661 VALUE *r;
662 int (*fxn) ();
663 int val;
665 #ifdef EVAL_TRACE
666 trace ("eval2");
667 #endif
668 l = eval3 ();
669 while (1)
671 if (nextarg ("<"))
672 fxn = less_than;
673 else if (nextarg ("<="))
674 fxn = less_equal;
675 else if (nextarg ("=") || nextarg ("=="))
676 fxn = equal;
677 else if (nextarg ("!="))
678 fxn = not_equal;
679 else if (nextarg (">="))
680 fxn = greater_equal;
681 else if (nextarg (">"))
682 fxn = greater_than;
683 else
684 return l;
685 args++;
686 r = eval3 ();
687 toarith (l);
688 toarith (r);
689 val = (*fxn) (l, r);
690 freev (l);
691 freev (r);
692 l = int_value (val);
696 /* Handle &. */
698 static VALUE *
699 eval1 (void)
701 VALUE *l;
702 VALUE *r;
704 #ifdef EVAL_TRACE
705 trace ("eval1");
706 #endif
707 l = eval2 ();
708 while (1)
710 if (nextarg ("&"))
712 args++;
713 r = eval2 ();
714 if (null (l) || null (r))
716 freev (l);
717 freev (r);
718 l = int_value (0);
720 else
721 freev (r);
723 else
724 return l;
728 /* Handle |. */
730 static VALUE *
731 eval (void)
733 VALUE *l;
734 VALUE *r;
736 #ifdef EVAL_TRACE
737 trace ("eval");
738 #endif
739 l = eval1 ();
740 while (1)
742 if (nextarg ("|"))
744 args++;
745 r = eval1 ();
746 if (null (l))
748 freev (l);
749 l = r;
751 else
752 freev (r);
754 else
755 return l;