It turns out that DODMALLOC was broken when I reorganized busybox.h
[oweals/busybox.git] / coreutils / expr.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini expr implementation for busybox
4  *
5  * based on GNU expr Mike Parker.
6  * Copyright (C) 86, 1991-1997, 1999 Free Software Foundation, Inc.
7  *
8  * Busybox modifications 
9  * Copyright (c) 2000  Edward Betts <edward@debian.org>.
10  *
11  * this program is free software; you can redistribute it and/or modify
12  * it under the terms of the gnu general public license as published by
13  * the free software foundation; either version 2 of the license, or
14  * (at your option) any later version.
15  *
16  * this program is distributed in the hope that it will be useful,
17  * but without any warranty; without even the implied warranty of
18  * merchantability or fitness for a particular purpose. see the gnu
19  * general public license for more details.
20  *
21  * you should have received a copy of the gnu general public license
22  * along with this program; if not, write to the free software
23  * foundation, inc., 59 temple place, suite 330, boston, ma 02111-1307 usa
24  *
25  */
26
27 /* This program evaluates expressions.  Each token (operator, operand,
28  * parenthesis) of the expression must be a seperate argument.  The
29  * parser used is a reasonably general one, though any incarnation of
30  * it is language-specific.  It is especially nice for expressions.
31  *
32  * No parse tree is needed; a new node is evaluated immediately.
33  * One function can handle multiple operators all of equal precedence,
34  * provided they all associate ((x op x) op x). */
35
36 #include <stdio.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <regex.h>
40 #include <sys/types.h>
41 #include "busybox.h"
42
43
44 /* The kinds of value we can have.  */
45 enum valtype {
46         integer,
47         string
48 };
49 typedef enum valtype TYPE;
50
51 /* A value is.... */
52 struct valinfo {
53         TYPE type;                      /* Which kind. */
54         union {                         /* The value itself. */
55                 int i;
56                 char *s;
57         } u;
58 };
59 typedef struct valinfo VALUE;
60
61 /* The arguments given to the program, minus the program name.  */
62 static char **args;
63
64 static VALUE *docolon (VALUE *sv, VALUE *pv);
65 static VALUE *eval (void);
66 static VALUE *int_value (int i);
67 static VALUE *str_value (char *s);
68 static int nextarg (char *str);
69 static int null (VALUE *v);
70 static int toarith (VALUE *v);
71 static void freev (VALUE *v);
72 static void tostring (VALUE *v);
73
74 int expr_main (int argc, char **argv)
75 {
76         VALUE *v;
77
78         if (argc == 1) {
79                 error_msg_and_die("too few arguments");
80         }
81
82         args = argv + 1;
83
84         v = eval ();
85         if (*args)
86                 error_msg_and_die ("syntax error");
87
88         if (v->type == integer)
89                 printf ("%d\n", v->u.i);
90         else 
91                 printf ("%s\n", v->u.s);
92
93         exit (null (v));
94 }
95
96 /* Return a VALUE for I.  */
97
98 static VALUE *int_value (int i)
99 {
100         VALUE *v;
101
102         v = xmalloc (sizeof(VALUE));
103         v->type = integer;
104         v->u.i = i;
105         return v;
106 }
107
108 /* Return a VALUE for S.  */
109
110 static VALUE *str_value (char *s)
111 {
112         VALUE *v;
113
114         v = xmalloc (sizeof(VALUE));
115         v->type = string;
116         v->u.s = strdup (s);
117         return v;
118 }
119
120 /* Free VALUE V, including structure components.  */
121
122 static void freev (VALUE *v)
123 {
124         if (v->type == string)
125                 free (v->u.s);
126         free (v);
127 }
128
129 /* Return nonzero if V is a null-string or zero-number.  */
130
131 static int null (VALUE *v)
132 {
133         switch (v->type) {
134                 case integer:
135                         return v->u.i == 0;
136                 case string:
137                         return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
138                 default:
139                         abort ();
140         }
141 }
142
143 /* Coerce V to a string value (can't fail).  */
144
145 static void tostring (VALUE *v)
146 {
147         char *temp;
148
149         if (v->type == integer) {
150                 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
151                 sprintf (temp, "%d", v->u.i);
152                 v->u.s = temp;
153                 v->type = string;
154         }
155 }
156
157 /* Coerce V to an integer value.  Return 1 on success, 0 on failure.  */
158
159 static int toarith (VALUE *v)
160 {
161         int i;
162
163         switch (v->type) {
164                 case integer:
165                         return 1;
166                 case string:
167                         i = 0;
168                         /* Don't interpret the empty string as an integer.  */
169                         if (v->u.s == 0)
170                                 return 0;
171                         i = atoi(v->u.s);
172                         free (v->u.s);
173                         v->u.i = i;
174                         v->type = integer;
175                         return 1;
176                 default:
177                         abort ();
178         }
179 }
180
181 /* Return nonzero if the next token matches STR exactly.
182    STR must not be NULL.  */
183
184 static int
185 nextarg (char *str)
186 {
187         if (*args == NULL)
188                 return 0;
189         return strcmp (*args, str) == 0;
190 }
191
192 /* The comparison operator handling functions.  */
193
194 #define cmpf(name, rel)                                 \
195 static int name (l, r) VALUE *l; VALUE *r;              \
196 {                                                       \
197         if (l->type == string || r->type == string) {           \
198                 tostring (l);                           \
199                 tostring (r);                           \
200                 return strcmp (l->u.s, r->u.s) rel 0;   \
201         }                                               \
202         else                                            \
203                 return l->u.i rel r->u.i;               \
204 }
205  cmpf (less_than, <)
206  cmpf (less_equal, <=)
207  cmpf (equal, ==)
208  cmpf (not_equal, !=)
209  cmpf (greater_equal, >=)
210  cmpf (greater_than, >)
211
212 #undef cmpf
213
214 /* The arithmetic operator handling functions.  */
215
216 #define arithf(name, op)                        \
217 static                                          \
218 int name (l, r) VALUE *l; VALUE *r;             \
219 {                                               \
220   if (!toarith (l) || !toarith (r))             \
221     error_msg_and_die ("non-numeric argument"); \
222   return l->u.i op r->u.i;                      \
223 }
224
225 #define arithdivf(name, op)                     \
226 int name (l, r) VALUE *l; VALUE *r;             \
227 {                                               \
228   if (!toarith (l) || !toarith (r))             \
229     error_msg_and_die ( "non-numeric argument");        \
230   if (r->u.i == 0)                              \
231     error_msg_and_die ( "division by zero");            \
232   return l->u.i op r->u.i;                      \
233 }
234
235  arithf (plus, +)
236  arithf (minus, -)
237  arithf (multiply, *)
238  arithdivf (divide, /)
239  arithdivf (mod, %)
240
241 #undef arithf
242 #undef arithdivf
243
244 /* Do the : operator.
245    SV is the VALUE for the lhs (the string),
246    PV is the VALUE for the rhs (the pattern).  */
247
248 static VALUE *docolon (VALUE *sv, VALUE *pv)
249 {
250         VALUE *v;
251         const char *errmsg;
252         struct re_pattern_buffer re_buffer;
253         struct re_registers re_regs;
254         int len;
255
256         tostring (sv);
257         tostring (pv);
258
259         if (pv->u.s[0] == '^') {
260                 fprintf (stderr, "\
261 warning: unportable BRE: `%s': using `^' as the first character\n\
262 of a basic regular expression is not portable; it is being ignored",
263                 pv->u.s);
264         }
265
266         len = strlen (pv->u.s);
267         memset (&re_buffer, 0, sizeof (re_buffer));
268         memset (&re_regs, 0, sizeof (re_regs));
269         re_buffer.allocated = 2 * len;
270         re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
271         re_buffer.translate = 0;
272         re_syntax_options = RE_SYNTAX_POSIX_BASIC;
273         errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
274         if (errmsg) {
275                 error_msg_and_die("%s", errmsg);
276         }
277
278         len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
279         if (len >= 0) {
280                 /* Were \(...\) used? */
281                 if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */
282                         sv->u.s[re_regs.end[1]] = '\0';
283                         v = str_value (sv->u.s + re_regs.start[1]);
284                 }
285                 else
286                         v = int_value (len);
287         }
288         else {
289                 /* Match failed -- return the right kind of null.  */
290                 if (re_buffer.re_nsub > 0)
291                         v = str_value ("");
292                 else
293                         v = int_value (0);
294         }
295         free (re_buffer.buffer);
296         return v;
297 }
298
299 /* Handle bare operands and ( expr ) syntax.  */
300
301 static VALUE *eval7 (void)
302 {
303         VALUE *v;
304
305         if (!*args)
306                 error_msg_and_die ( "syntax error");
307
308         if (nextarg ("(")) {
309                 args++;
310                 v = eval ();
311                 if (!nextarg (")"))
312                         error_msg_and_die ( "syntax error");
313                         args++;
314                         return v;
315                 }
316
317         if (nextarg (")"))
318                 error_msg_and_die ( "syntax error");
319
320         return str_value (*args++);
321 }
322
323 /* Handle match, substr, index, length, and quote keywords.  */
324
325 static VALUE *eval6 (void)
326 {
327         VALUE *l, *r, *v, *i1, *i2;
328
329         if (nextarg ("quote")) {
330                 args++;
331                 if (!*args)
332                         error_msg_and_die ( "syntax error");
333                 return str_value (*args++);
334         }
335         else if (nextarg ("length")) {
336                 args++;
337                 r = eval6 ();
338                 tostring (r);
339                 v = int_value (strlen (r->u.s));
340                 freev (r);
341                 return v;
342         }
343         else if (nextarg ("match")) {
344                 args++;
345                 l = eval6 ();
346                 r = eval6 ();
347                 v = docolon (l, r);
348                 freev (l);
349                 freev (r);
350                 return v;
351         }
352         else if (nextarg ("index")) {
353                 args++;
354                 l = eval6 ();
355                 r = eval6 ();
356                 tostring (l);
357                 tostring (r);
358                 v = int_value (strcspn (l->u.s, r->u.s) + 1);
359                 if (v->u.i == (int) strlen (l->u.s) + 1)
360                         v->u.i = 0;
361                 freev (l);
362                 freev (r);
363                 return v;
364         }
365         else if (nextarg ("substr")) {
366                 args++;
367                 l = eval6 ();
368                 i1 = eval6 ();
369                 i2 = eval6 ();
370                 tostring (l);
371                 if (!toarith (i1) || !toarith (i2)
372                         || i1->u.i > (int) strlen (l->u.s)
373                         || i1->u.i <= 0 || i2->u.i <= 0)
374                 v = str_value ("");
375                 else {
376                         v = xmalloc (sizeof(VALUE));
377                         v->type = string;
378                         v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
379                                 l->u.s + i1->u.i - 1, i2->u.i);
380                                 v->u.s[i2->u.i] = 0;
381                 }
382                 freev (l);
383                 freev (i1);
384                 freev (i2);
385                 return v;
386         }
387         else
388                 return eval7 ();
389 }
390
391 /* Handle : operator (pattern matching).
392    Calls docolon to do the real work.  */
393
394 static VALUE *eval5 (void)
395 {
396         VALUE *l, *r, *v;
397
398         l = eval6 ();
399         while (nextarg (":")) {
400                 args++;
401                 r = eval6 ();
402                 v = docolon (l, r);
403                 freev (l);
404                 freev (r);
405                 l = v;
406         }
407         return l;
408 }
409
410 /* Handle *, /, % operators.  */
411
412 static VALUE *eval4 (void)
413 {
414         VALUE *l, *r;
415         int (*fxn) (), val;
416
417         l = eval5 ();
418         while (1) {
419                 if (nextarg ("*"))
420                         fxn = multiply;
421                 else if (nextarg ("/"))
422                         fxn = divide;
423                 else if (nextarg ("%"))
424                         fxn = mod;
425                 else
426                         return l;
427                 args++;
428                 r = eval5 ();
429                 val = (*fxn) (l, r);
430                 freev (l);
431                 freev (r);
432                 l = int_value (val);
433         }
434 }
435
436 /* Handle +, - operators.  */
437
438 static VALUE *eval3 (void)
439 {
440         VALUE *l, *r;
441         int (*fxn) (), val;
442
443         l = eval4 ();
444         while (1) {
445                 if (nextarg ("+"))
446                         fxn = plus;
447                 else if (nextarg ("-"))
448                         fxn = minus;
449                 else
450                         return l;
451                 args++;
452                 r = eval4 ();
453                 val = (*fxn) (l, r);
454                 freev (l);
455                 freev (r);
456                 l = int_value (val);
457         }
458 }
459
460 /* Handle comparisons.  */
461
462 static VALUE *eval2 (void)
463 {
464         VALUE *l, *r;
465         int (*fxn) (), val;
466
467         l = eval3 ();
468         while (1) {
469                 if (nextarg ("<"))
470                         fxn = less_than;
471                 else if (nextarg ("<="))
472                         fxn = less_equal;
473                 else if (nextarg ("=") || nextarg ("=="))
474                         fxn = equal;
475                 else if (nextarg ("!="))
476                         fxn = not_equal;
477                 else if (nextarg (">="))
478                         fxn = greater_equal;
479                 else if (nextarg (">"))
480                         fxn = greater_than;
481                 else
482                         return l;
483                 args++;
484                 r = eval3 ();
485                 toarith (l);
486                 toarith (r);
487                 val = (*fxn) (l, r);
488                 freev (l);
489                 freev (r);
490                 l = int_value (val);
491         }
492 }
493
494 /* Handle &.  */
495
496 static VALUE *eval1 (void)
497 {
498         VALUE *l, *r;
499
500         l = eval2 ();
501         while (nextarg ("&")) {
502                 args++;
503                 r = eval2 ();
504                 if (null (l) || null (r)) {
505                         freev (l);
506                         freev (r);
507                         l = int_value (0);
508                 }
509                 else
510                         freev (r);
511         }
512         return l;
513 }
514
515 /* Handle |.  */
516
517 static VALUE *eval (void)
518 {
519         VALUE *l, *r;
520
521         l = eval1 ();
522         while (nextarg ("|")) {
523                 args++;
524                 r = eval1 ();
525                 if (null (l)) {
526                         freev (l);
527                         l = r;
528                 }
529                 else
530                         freev (r);
531         }
532         return l;
533 }