blob: b23de8e9f8b5061125f5aa7cbe14f6e774ce75f2 [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>.
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000010 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
11 * - reduced 464 bytes.
12 * - 64 math support
Eric Andersen1b355eb2000-09-05 17:37:48 +000013 *
Eric Andersenaff114c2004-04-14 17:51:38 +000014 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
Eric Andersen1b355eb2000-09-05 17:37:48 +000017 * (at your option) any later version.
18 *
Eric Andersenaff114c2004-04-14 17:51:38 +000019 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
Eric Andersen1b355eb2000-09-05 17:37:48 +000023 *
Eric Andersenaff114c2004-04-14 17:51:38 +000024 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Eric Andersen1b355eb2000-09-05 17:37:48 +000027 *
28 */
29
30/* This program evaluates expressions. Each token (operator, operand,
Eric Andersenaff114c2004-04-14 17:51:38 +000031 * parenthesis) of the expression must be a separate argument. The
Eric Andersen1b355eb2000-09-05 17:37:48 +000032 * parser used is a reasonably general one, though any incarnation of
33 * it is language-specific. It is especially nice for expressions.
34 *
35 * No parse tree is needed; a new node is evaluated immediately.
36 * One function can handle multiple operators all of equal precedence,
37 * provided they all associate ((x op x) op x). */
38
Mark Whitley827e45c2001-03-09 23:59:51 +000039/* no getopt needed */
40
Eric Andersen1b355eb2000-09-05 17:37:48 +000041#include <stdio.h>
Eric Andersened3ef502001-01-27 08:24:39 +000042#include <string.h>
43#include <stdlib.h>
44#include <regex.h>
Eric Andersen1b355eb2000-09-05 17:37:48 +000045#include <sys/types.h>
Glenn L McGrath7b8765c2003-08-29 07:29:30 +000046#include <errno.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000047#include "busybox.h"
Eric Andersen1b355eb2000-09-05 17:37:48 +000048
Eric Andersen1b355eb2000-09-05 17:37:48 +000049
50/* The kinds of value we can have. */
51enum valtype {
52 integer,
53 string
54};
55typedef enum valtype TYPE;
56
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000057#if ENABLE_EXPR_MATH_SUPPORT_64
58typedef int64_t arith_t;
59#define PF_REZ "ll"
Eric Andersen5e678872006-01-30 19:48:23 +000060#define PF_REZ_TYPE (long long)
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000061#define STRTOL(s, e, b) strtoll(s, e, b)
62#else
63typedef long arith_t;
64#define PF_REZ "l"
Eric Andersen5e678872006-01-30 19:48:23 +000065#define PF_REZ_TYPE (long)
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000066#define STRTOL(s, e, b) strtol(s, e, b)
67#endif
68
Eric Andersen1b355eb2000-09-05 17:37:48 +000069/* A value is.... */
70struct valinfo {
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000071 TYPE type; /* Which kind. */
72 union { /* The value itself. */
73 arith_t i;
Eric Andersen1b355eb2000-09-05 17:37:48 +000074 char *s;
75 } u;
76};
77typedef struct valinfo VALUE;
78
79/* The arguments given to the program, minus the program name. */
80static char **args;
81
82static VALUE *docolon (VALUE *sv, VALUE *pv);
83static VALUE *eval (void);
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +000084static VALUE *int_value (arith_t i);
Eric Andersen1b355eb2000-09-05 17:37:48 +000085static VALUE *str_value (char *s);
86static int nextarg (char *str);
87static int null (VALUE *v);
88static int toarith (VALUE *v);
89static void freev (VALUE *v);
90static void tostring (VALUE *v);
91
92int expr_main (int argc, char **argv)
93{
94 VALUE *v;
95
96 if (argc == 1) {
Manuel Novoa III cad53642003-03-19 09:13:01 +000097 bb_error_msg_and_die("too few arguments");
Eric Andersen1b355eb2000-09-05 17:37:48 +000098 }
99
100 args = argv + 1;
101
102 v = eval ();
103 if (*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000104 bb_error_msg_and_die ("syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000105
106 if (v->type == integer)
Eric Andersen5e678872006-01-30 19:48:23 +0000107 printf ("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i);
Matt Kraai59df6f72001-05-16 14:21:09 +0000108 else
109 puts (v->u.s);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000110
111 exit (null (v));
112}
113
114/* Return a VALUE for I. */
115
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000116static VALUE *int_value (arith_t i)
Eric Andersen1b355eb2000-09-05 17:37:48 +0000117{
118 VALUE *v;
119
120 v = xmalloc (sizeof(VALUE));
121 v->type = integer;
122 v->u.i = i;
123 return v;
124}
125
126/* Return a VALUE for S. */
127
128static VALUE *str_value (char *s)
129{
130 VALUE *v;
131
132 v = xmalloc (sizeof(VALUE));
133 v->type = string;
Manuel Novoa III 08386222004-02-01 07:34:28 +0000134 v->u.s = bb_xstrdup (s);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000135 return v;
136}
137
138/* Free VALUE V, including structure components. */
139
140static void freev (VALUE *v)
141{
142 if (v->type == string)
143 free (v->u.s);
144 free (v);
145}
146
147/* Return nonzero if V is a null-string or zero-number. */
148
149static int null (VALUE *v)
150{
151 switch (v->type) {
152 case integer:
153 return v->u.i == 0;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000154 default: /* string: */
Eric Andersen1b355eb2000-09-05 17:37:48 +0000155 return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000156 }
157}
158
159/* Coerce V to a string value (can't fail). */
160
161static void tostring (VALUE *v)
162{
Eric Andersen1b355eb2000-09-05 17:37:48 +0000163 if (v->type == integer) {
Eric Andersen5e678872006-01-30 19:48:23 +0000164 v->u.s = bb_xasprintf ("%" PF_REZ "d", PF_REZ_TYPE v->u.i);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000165 v->type = string;
166 }
167}
168
169/* Coerce V to an integer value. Return 1 on success, 0 on failure. */
170
171static int toarith (VALUE *v)
172{
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000173 if(v->type == string) {
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000174 arith_t i;
Manuel Novoa III 70183852004-01-25 19:47:10 +0000175 char *e;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000176
Manuel Novoa III 70183852004-01-25 19:47:10 +0000177 /* Don't interpret the empty string as an integer. */
178 /* Currently does not worry about overflow or int/long differences. */
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000179 i = STRTOL(v->u.s, &e, 10);
Manuel Novoa III 70183852004-01-25 19:47:10 +0000180 if ((v->u.s == e) || *e)
181 return 0;
182 free (v->u.s);
183 v->u.i = i;
184 v->type = integer;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000185 }
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000186 return 1;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000187}
188
189/* Return nonzero if the next token matches STR exactly.
190 STR must not be NULL. */
191
192static int
193nextarg (char *str)
194{
195 if (*args == NULL)
196 return 0;
197 return strcmp (*args, str) == 0;
198}
199
200/* The comparison operator handling functions. */
201
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000202static int cmp_common (VALUE *l, VALUE *r, int op)
203{
204 int cmpval;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000205
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000206 if (l->type == string || r->type == string) {
207 tostring (l);
208 tostring (r);
209 cmpval = strcmp (l->u.s, r->u.s);
210 }
211 else
212 cmpval = l->u.i - r->u.i;
213 switch(op) {
214 case '<':
215 return cmpval < 0;
216 case ('L'+'E'):
217 return cmpval <= 0;
218 case '=':
219 return cmpval == 0;
220 case '!':
221 return cmpval != 0;
222 case '>':
223 return cmpval > 0;
224 default: /* >= */
225 return cmpval >= 0;
226 }
227}
Eric Andersen1b355eb2000-09-05 17:37:48 +0000228
229/* The arithmetic operator handling functions. */
230
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000231static arith_t arithmetic_common (VALUE *l, VALUE *r, int op)
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000232{
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000233 arith_t li, ri;
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000234
235 if (!toarith (l) || !toarith (r))
236 bb_error_msg_and_die ("non-numeric argument");
237 li = l->u.i;
238 ri = r->u.i;
239 if((op == '/' || op == '%') && ri == 0)
240 bb_error_msg_and_die ( "division by zero");
241 switch(op) {
242 case '+':
243 return li + ri;
244 case '-':
245 return li - ri;
246 case '*':
247 return li * ri;
248 case '/':
249 return li / ri;
250 default:
251 return li % ri;
252 }
Eric Andersen1b355eb2000-09-05 17:37:48 +0000253}
254
Eric Andersen1b355eb2000-09-05 17:37:48 +0000255/* Do the : operator.
256 SV is the VALUE for the lhs (the string),
257 PV is the VALUE for the rhs (the pattern). */
258
259static VALUE *docolon (VALUE *sv, VALUE *pv)
260{
261 VALUE *v;
Rob Landley540d3f62005-05-09 21:42:42 +0000262 regex_t re_buffer;
263 const int NMATCH = 2;
264 regmatch_t re_regs[NMATCH];
Eric Andersen1b355eb2000-09-05 17:37:48 +0000265
266 tostring (sv);
267 tostring (pv);
268
269 if (pv->u.s[0] == '^') {
270 fprintf (stderr, "\
271warning: unportable BRE: `%s': using `^' as the first character\n\
272of a basic regular expression is not portable; it is being ignored",
273 pv->u.s);
274 }
275
Eric Andersen1b355eb2000-09-05 17:37:48 +0000276 memset (&re_buffer, 0, sizeof (re_buffer));
Rob Landley540d3f62005-05-09 21:42:42 +0000277 memset (re_regs, 0, sizeof (*re_regs));
278 if( regcomp (&re_buffer, pv->u.s, 0) != 0 )
279 bb_error_msg_and_die("Invalid regular expression");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000280
Rob Landley540d3f62005-05-09 21:42:42 +0000281 /* expr uses an anchored pattern match, so check that there was a
282 * match and that the match starts at offset 0. */
283 if (regexec (&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH &&
284 re_regs[0].rm_so == 0) {
Eric Andersen1b355eb2000-09-05 17:37:48 +0000285 /* Were \(...\) used? */
Rob Landley540d3f62005-05-09 21:42:42 +0000286 if (re_buffer.re_nsub > 0) {
287 sv->u.s[re_regs[1].rm_eo] = '\0';
288 v = str_value (sv->u.s + re_regs[1].rm_so);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000289 }
290 else
Rob Landley540d3f62005-05-09 21:42:42 +0000291 v = int_value (re_regs[0].rm_eo);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000292 }
293 else {
294 /* Match failed -- return the right kind of null. */
295 if (re_buffer.re_nsub > 0)
296 v = str_value ("");
297 else
298 v = int_value (0);
299 }
Eric Andersen1b355eb2000-09-05 17:37:48 +0000300 return v;
301}
302
303/* Handle bare operands and ( expr ) syntax. */
304
305static VALUE *eval7 (void)
306{
307 VALUE *v;
308
309 if (!*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000310 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000311
312 if (nextarg ("(")) {
313 args++;
314 v = eval ();
315 if (!nextarg (")"))
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000317 args++;
318 return v;
319 }
320
321 if (nextarg (")"))
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
324 return str_value (*args++);
325}
326
327/* Handle match, substr, index, length, and quote keywords. */
328
329static VALUE *eval6 (void)
330{
331 VALUE *l, *r, *v, *i1, *i2;
332
333 if (nextarg ("quote")) {
334 args++;
335 if (!*args)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000336 bb_error_msg_and_die ( "syntax error");
Eric Andersen1b355eb2000-09-05 17:37:48 +0000337 return str_value (*args++);
338 }
339 else if (nextarg ("length")) {
340 args++;
341 r = eval6 ();
342 tostring (r);
343 v = int_value (strlen (r->u.s));
344 freev (r);
345 return v;
346 }
347 else if (nextarg ("match")) {
348 args++;
349 l = eval6 ();
350 r = eval6 ();
351 v = docolon (l, r);
352 freev (l);
353 freev (r);
354 return v;
355 }
356 else if (nextarg ("index")) {
357 args++;
358 l = eval6 ();
359 r = eval6 ();
360 tostring (l);
361 tostring (r);
362 v = int_value (strcspn (l->u.s, r->u.s) + 1);
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000363 if (v->u.i == (arith_t) strlen (l->u.s) + 1)
Eric Andersen1b355eb2000-09-05 17:37:48 +0000364 v->u.i = 0;
365 freev (l);
366 freev (r);
367 return v;
368 }
369 else if (nextarg ("substr")) {
370 args++;
371 l = eval6 ();
372 i1 = eval6 ();
373 i2 = eval6 ();
374 tostring (l);
375 if (!toarith (i1) || !toarith (i2)
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000376 || i1->u.i > (arith_t) strlen (l->u.s)
Eric Andersen1b355eb2000-09-05 17:37:48 +0000377 || i1->u.i <= 0 || i2->u.i <= 0)
378 v = str_value ("");
379 else {
380 v = xmalloc (sizeof(VALUE));
381 v->type = string;
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000382 v->u.s = bb_xstrndup(l->u.s + i1->u.i - 1, i2->u.i);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000383 }
384 freev (l);
385 freev (i1);
386 freev (i2);
387 return v;
388 }
389 else
390 return eval7 ();
391}
392
393/* Handle : operator (pattern matching).
394 Calls docolon to do the real work. */
395
396static VALUE *eval5 (void)
397{
398 VALUE *l, *r, *v;
399
400 l = eval6 ();
401 while (nextarg (":")) {
402 args++;
403 r = eval6 ();
404 v = docolon (l, r);
405 freev (l);
406 freev (r);
407 l = v;
408 }
409 return l;
410}
411
412/* Handle *, /, % operators. */
413
414static VALUE *eval4 (void)
415{
416 VALUE *l, *r;
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000417 int op;
418 arith_t val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000419
420 l = eval5 ();
421 while (1) {
422 if (nextarg ("*"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000423 op = '*';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000424 else if (nextarg ("/"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000425 op = '/';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000426 else if (nextarg ("%"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000427 op = '%';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000428 else
429 return l;
430 args++;
431 r = eval5 ();
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000432 val = arithmetic_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000433 freev (l);
434 freev (r);
435 l = int_value (val);
436 }
437}
438
439/* Handle +, - operators. */
440
441static VALUE *eval3 (void)
442{
443 VALUE *l, *r;
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000444 int op;
445 arith_t val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000446
447 l = eval4 ();
448 while (1) {
449 if (nextarg ("+"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000450 op = '+';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000451 else if (nextarg ("-"))
Glenn L McGrath07f6b952003-09-08 23:19:12 +0000452 op = '-';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000453 else
454 return l;
455 args++;
456 r = eval4 ();
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000457 val = arithmetic_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000458 freev (l);
459 freev (r);
460 l = int_value (val);
461 }
462}
463
464/* Handle comparisons. */
465
466static VALUE *eval2 (void)
467{
468 VALUE *l, *r;
"Vladimir N. Oleynik"8aa9e572006-01-25 13:56:03 +0000469 int op;
470 arith_t val;
Eric Andersen1b355eb2000-09-05 17:37:48 +0000471
472 l = eval3 ();
473 while (1) {
474 if (nextarg ("<"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000475 op = '<';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000476 else if (nextarg ("<="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000477 op = 'L'+'E';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000478 else if (nextarg ("=") || nextarg ("=="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000479 op = '=';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000480 else if (nextarg ("!="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000481 op = '!';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000482 else if (nextarg (">="))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000483 op = 'G'+'E';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000484 else if (nextarg (">"))
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000485 op = '>';
Eric Andersen1b355eb2000-09-05 17:37:48 +0000486 else
487 return l;
488 args++;
489 r = eval3 ();
490 toarith (l);
491 toarith (r);
Glenn L McGrath7b8765c2003-08-29 07:29:30 +0000492 val = cmp_common (l, r, op);
Eric Andersen1b355eb2000-09-05 17:37:48 +0000493 freev (l);
494 freev (r);
495 l = int_value (val);
496 }
497}
498
499/* Handle &. */
500
501static VALUE *eval1 (void)
502{
503 VALUE *l, *r;
504
505 l = eval2 ();
506 while (nextarg ("&")) {
507 args++;
508 r = eval2 ();
509 if (null (l) || null (r)) {
510 freev (l);
511 freev (r);
512 l = int_value (0);
513 }
514 else
515 freev (r);
516 }
517 return l;
518}
519
520/* Handle |. */
521
522static VALUE *eval (void)
523{
524 VALUE *l, *r;
525
526 l = eval1 ();
527 while (nextarg ("|")) {
528 args++;
529 r = eval1 ();
530 if (null (l)) {
531 freev (l);
532 l = r;
533 }
534 else
535 freev (r);
536 }
537 return l;
538}