blob: 3f052d92a74f301e56206343629d70b9cce525ee [file] [log] [blame]
Eric Andersen1b355eb2000-09-05 17:37:48 +00001/* 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 *
Eric Andersenc7bda1c2004-03-15 08:29:22 +00008 * Busybox modifications
Eric Andersen1b355eb2000-09-05 17:37:48 +00009 * Copyright (c) 2000 Edward Betts <edward@debian.org>.
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000010 * Aug 2003 Vladimir Oleynik - reduced 464 bytes.
Eric Andersen1b355eb2000-09-05 17:37:48 +000011 *
Eric Andersenaff114c2004-04-14 17:51:38 +000012 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
Eric Andersen1b355eb2000-09-05 17:37:48 +000015 * (at your option) any later version.
16 *
Eric Andersenaff114c2004-04-14 17:51:38 +000017 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
Eric Andersen1b355eb2000-09-05 17:37:48 +000021 *
Eric Andersenaff114c2004-04-14 17:51:38 +000022 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Eric Andersen1b355eb2000-09-05 17:37:48 +000025 *
26 */
27
28/* This program evaluates expressions. Each token (operator, operand,
Eric Andersenaff114c2004-04-14 17:51:38 +000029 * parenthesis) of the expression must be a separate argument. The
Eric Andersen1b355eb2000-09-05 17:37:48 +000030 * parser used is a reasonably general one, though any incarnation of
31 * it is language-specific. It is especially nice for expressions.
32 *
33 * No parse tree is needed; a new node is evaluated immediately.
34 * One function can handle multiple operators all of equal precedence,
35 * provided they all associate ((x op x) op x). */
36
Mark Whitley827e45c2001-03-09 23:59:51 +000037/* no getopt needed */
38
Eric Andersen1b355eb2000-09-05 17:37:48 +000039#include <stdio.h>
Eric Andersened3ef502001-01-27 08:24:39 +000040#include <string.h>
41#include <stdlib.h>
42#include <regex.h>
Eric Andersen1b355eb2000-09-05 17:37:48 +000043#include <sys/types.h>
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000044#include <errno.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000045#include "busybox.h"
Eric Andersen1b355eb2000-09-05 17:37:48 +000046
Eric Andersen1b355eb2000-09-05 17:37:48 +000047
48/* The kinds of value we can have. */
49enum valtype {
50 integer,
51 string
52};
53typedef enum valtype TYPE;
54
55/* A value is.... */
56struct valinfo {
57 TYPE type; /* Which kind. */
58 union { /* The value itself. */
59 int i;
60 char *s;
61 } u;
62};
63typedef struct valinfo VALUE;
64
65/* The arguments given to the program, minus the program name. */
66static char **args;
67
68static VALUE *docolon (VALUE *sv, VALUE *pv);
69static VALUE *eval (void);
70static VALUE *int_value (int i);
71static VALUE *str_value (char *s);
72static int nextarg (char *str);
73static int null (VALUE *v);
74static int toarith (VALUE *v);
75static void freev (VALUE *v);
76static void tostring (VALUE *v);
77
78int expr_main (int argc, char **argv)
79{
80 VALUE *v;
81
82 if (argc == 1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000083 bb_error_msg_and_die("too few arguments");
Eric Andersen1b355eb2000-09-05 17:37:48 +000084 }
85
86 args = argv + 1;
87
88 v = eval ();
89 if (*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +000090 bb_error_msg_and_die ("syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +000091
92 if (v->type == integer)
93 printf ("%d\n", v->u.i);
Matt Kraai59df6f72001-05-16 14:21:09 +000094 else
95 puts (v->u.s);
Eric Andersen1b355eb2000-09-05 17:37:48 +000096
97 exit (null (v));
98}
99
100/* Return a VALUE for I. */
101
102static VALUE *int_value (int i)
103{
104 VALUE *v;
105
106 v = xmalloc (sizeof(VALUE));
107 v->type = integer;
108 v->u.i = i;
109 return v;
110}
111
112/* Return a VALUE for S. */
113
114static VALUE *str_value (char *s)
115{
116 VALUE *v;
117
118 v = xmalloc (sizeof(VALUE));
119 v->type = string;
Manuel Novoa III 08386222004-02-01 07:34:28 +0000120 v->u.s = bb_xstrdup (s);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000121 return v;
122}
123
124/* Free VALUE V, including structure components. */
125
126static void freev (VALUE *v)
127{
128 if (v->type == string)
129 free (v->u.s);
130 free (v);
131}
132
133/* Return nonzero if V is a null-string or zero-number. */
134
135static int null (VALUE *v)
136{
137 switch (v->type) {
138 case integer:
139 return v->u.i == 0;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000140 default: /* string: */
Eric Andersen1b355eb2000-09-05 17:37:48 +0000141 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000142 }
143}
144
145/* Coerce V to a string value (can't fail). */
146
147static void tostring (VALUE *v)
148{
Eric Andersen1b355eb2000-09-05 17:37:48 +0000149 if (v->type == integer) {
Manuel Novoa III cad53642003-03-19 09:13:01 +0000150 bb_xasprintf (&(v->u.s), "%d", v->u.i);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000151 v->type = string;
152 }
153}
154
155/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
156
157static int toarith (VALUE *v)
158{
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000159 if(v->type == string) {
Manuel Novoa III 70183852004-01-25 19:47:10 +0000160 int i;
161 char *e;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000162
Manuel Novoa III 70183852004-01-25 19:47:10 +0000163 /* Don't interpret the empty string as an integer. */
164 /* Currently does not worry about overflow or int/long differences. */
165 i = (int) strtol(v->u.s, &e, 10);
166 if ((v->u.s == e) || *e)
167 return 0;
168 free (v->u.s);
169 v->u.i = i;
170 v->type = integer;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000171 }
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000172 return 1;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000173}
174
175/* Return nonzero if the next token matches STR exactly.
176 STR must not be NULL. */
177
178static int
179nextarg (char *str)
180{
181 if (*args == NULL)
182 return 0;
183 return strcmp (*args, str) == 0;
184}
185
186/* The comparison operator handling functions. */
187
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000188static int cmp_common (VALUE *l, VALUE *r, int op)
189{
190 int cmpval;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000191
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000192 if (l->type == string || r->type == string) {
193 tostring (l);
194 tostring (r);
195 cmpval = strcmp (l->u.s, r->u.s);
196 }
197 else
198 cmpval = l->u.i - r->u.i;
199 switch(op) {
200 case '<':
201 return cmpval < 0;
202 case ('L'+'E'):
203 return cmpval <= 0;
204 case '=':
205 return cmpval == 0;
206 case '!':
207 return cmpval != 0;
208 case '>':
209 return cmpval > 0;
210 default: /* >= */
211 return cmpval >= 0;
212 }
213}
Eric Andersen1b355eb2000-09-05 17:37:48 +0000214
215/* The arithmetic operator handling functions. */
216
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000217static int arithmetic_common (VALUE *l, VALUE *r, int op)
218{
219 int li, ri;
220
221 if (!toarith (l) || !toarith (r))
222 bb_error_msg_and_die ("non-numeric argument");
223 li = l->u.i;
224 ri = r->u.i;
225 if((op == '/' || op == '%') && ri == 0)
226 bb_error_msg_and_die ( "division by zero");
227 switch(op) {
228 case '+':
229 return li + ri;
230 case '-':
231 return li - ri;
232 case '*':
233 return li * ri;
234 case '/':
235 return li / ri;
236 default:
237 return li % ri;
238 }
Eric Andersen1b355eb2000-09-05 17:37:48 +0000239}
240
Eric Andersen1b355eb2000-09-05 17:37:48 +0000241/* Do the : operator.
242 SV is the VALUE for the lhs (the string),
243 PV is the VALUE for the rhs (the pattern). */
244
245static VALUE *docolon (VALUE *sv, VALUE *pv)
246{
247 VALUE *v;
Rob Landley540d3f62005-05-09 21:42:42 +0000248 regex_t re_buffer;
249 const int NMATCH = 2;
250 regmatch_t re_regs[NMATCH];
Eric Andersen1b355eb2000-09-05 17:37:48 +0000251
252 tostring (sv);
253 tostring (pv);
254
255 if (pv->u.s[0] == '^') {
256 fprintf (stderr, "\
257warning: unportable BRE: `%s': using `^' as the first character\n\
258of a basic regular expression is not portable; it is being ignored",
259 pv->u.s);
260 }
261
Eric Andersen1b355eb2000-09-05 17:37:48 +0000262 memset (&re_buffer, 0, sizeof (re_buffer));
Rob Landley540d3f62005-05-09 21:42:42 +0000263 memset (re_regs, 0, sizeof (*re_regs));
264 if( regcomp (&re_buffer, pv->u.s, 0) != 0 )
265 bb_error_msg_and_die("Invalid regular expression");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000266
Rob Landley540d3f62005-05-09 21:42:42 +0000267 /* expr uses an anchored pattern match, so check that there was a
268 * match and that the match starts at offset 0. */
269 if (regexec (&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH &&
270 re_regs[0].rm_so == 0) {
Eric Andersen1b355eb2000-09-05 17:37:48 +0000271 /* Were \(...\) used? */
Rob Landley540d3f62005-05-09 21:42:42 +0000272 if (re_buffer.re_nsub > 0) {
273 sv->u.s[re_regs[1].rm_eo] = '\0';
274 v = str_value (sv->u.s + re_regs[1].rm_so);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000275 }
276 else
Rob Landley540d3f62005-05-09 21:42:42 +0000277 v = int_value (re_regs[0].rm_eo);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000278 }
279 else {
280 /* Match failed -- return the right kind of null. */
281 if (re_buffer.re_nsub > 0)
282 v = str_value ("");
283 else
284 v = int_value (0);
285 }
Eric Andersen1b355eb2000-09-05 17:37:48 +0000286 return v;
287}
288
289/* Handle bare operands and ( expr ) syntax. */
290
291static VALUE *eval7 (void)
292{
293 VALUE *v;
294
295 if (!*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000296 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000297
298 if (nextarg ("(")) {
299 args++;
300 v = eval ();
301 if (!nextarg (")"))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000302 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000303 args++;
304 return v;
305 }
306
307 if (nextarg (")"))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000308 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000309
310 return str_value (*args++);
311}
312
313/* Handle match, substr, index, length, and quote keywords. */
314
315static VALUE *eval6 (void)
316{
317 VALUE *l, *r, *v, *i1, *i2;
318
319 if (nextarg ("quote")) {
320 args++;
321 if (!*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000322 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000323 return str_value (*args++);
324 }
325 else if (nextarg ("length")) {
326 args++;
327 r = eval6 ();
328 tostring (r);
329 v = int_value (strlen (r->u.s));
330 freev (r);
331 return v;
332 }
333 else if (nextarg ("match")) {
334 args++;
335 l = eval6 ();
336 r = eval6 ();
337 v = docolon (l, r);
338 freev (l);
339 freev (r);
340 return v;
341 }
342 else if (nextarg ("index")) {
343 args++;
344 l = eval6 ();
345 r = eval6 ();
346 tostring (l);
347 tostring (r);
348 v = int_value (strcspn (l->u.s, r->u.s) + 1);
349 if (v->u.i == (int) strlen (l->u.s) + 1)
350 v->u.i = 0;
351 freev (l);
352 freev (r);
353 return v;
354 }
355 else if (nextarg ("substr")) {
356 args++;
357 l = eval6 ();
358 i1 = eval6 ();
359 i2 = eval6 ();
360 tostring (l);
361 if (!toarith (i1) || !toarith (i2)
362 || i1->u.i > (int) strlen (l->u.s)
363 || i1->u.i <= 0 || i2->u.i <= 0)
364 v = str_value ("");
365 else {
366 v = xmalloc (sizeof(VALUE));
367 v->type = string;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000368 v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000369 }
370 freev (l);
371 freev (i1);
372 freev (i2);
373 return v;
374 }
375 else
376 return eval7 ();
377}
378
379/* Handle : operator (pattern matching).
380 Calls docolon to do the real work. */
381
382static VALUE *eval5 (void)
383{
384 VALUE *l, *r, *v;
385
386 l = eval6 ();
387 while (nextarg (":")) {
388 args++;
389 r = eval6 ();
390 v = docolon (l, r);
391 freev (l);
392 freev (r);
393 l = v;
394 }
395 return l;
396}
397
398/* Handle *, /, % operators. */
399
400static VALUE *eval4 (void)
401{
402 VALUE *l, *r;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000403 int op, val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000404
405 l = eval5 ();
406 while (1) {
407 if (nextarg ("*"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000408 op = '*';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000409 else if (nextarg ("/"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000410 op = '/';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000411 else if (nextarg ("%"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000412 op = '%';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000413 else
414 return l;
415 args++;
416 r = eval5 ();
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000417 val = arithmetic_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000418 freev (l);
419 freev (r);
420 l = int_value (val);
421 }
422}
423
424/* Handle +, - operators. */
425
426static VALUE *eval3 (void)
427{
428 VALUE *l, *r;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000429 int op, val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000430
431 l = eval4 ();
432 while (1) {
433 if (nextarg ("+"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000434 op = '+';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000435 else if (nextarg ("-"))
Glenn L McGrath07f6b952003-09-08 23:19:12 +0000436 op = '-';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000437 else
438 return l;
439 args++;
440 r = eval4 ();
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000441 val = arithmetic_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000442 freev (l);
443 freev (r);
444 l = int_value (val);
445 }
446}
447
448/* Handle comparisons. */
449
450static VALUE *eval2 (void)
451{
452 VALUE *l, *r;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000453 int op, val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000454
455 l = eval3 ();
456 while (1) {
457 if (nextarg ("<"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000458 op = '<';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000459 else if (nextarg ("<="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000460 op = 'L'+'E';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000461 else if (nextarg ("=") || nextarg ("=="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000462 op = '=';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000463 else if (nextarg ("!="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000464 op = '!';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000465 else if (nextarg (">="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000466 op = 'G'+'E';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000467 else if (nextarg (">"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000468 op = '>';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000469 else
470 return l;
471 args++;
472 r = eval3 ();
473 toarith (l);
474 toarith (r);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000475 val = cmp_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000476 freev (l);
477 freev (r);
478 l = int_value (val);
479 }
480}
481
482/* Handle &. */
483
484static VALUE *eval1 (void)
485{
486 VALUE *l, *r;
487
488 l = eval2 ();
489 while (nextarg ("&")) {
490 args++;
491 r = eval2 ();
492 if (null (l) || null (r)) {
493 freev (l);
494 freev (r);
495 l = int_value (0);
496 }
497 else
498 freev (r);
499 }
500 return l;
501}
502
503/* Handle |. */
504
505static VALUE *eval (void)
506{
507 VALUE *l, *r;
508
509 l = eval1 ();
510 while (nextarg ("|")) {
511 args++;
512 r = eval1 ();
513 if (null (l)) {
514 freev (l);
515 l = r;
516 }
517 else
518 freev (r);
519 }
520 return l;
521}