diff options
Diffstat (limited to 'expr.c')
-rw-r--r-- | expr.c | 535 |
1 files changed, 0 insertions, 535 deletions
diff --git a/expr.c b/expr.c deleted file mode 100644 index d6cc82e3e..000000000 --- a/expr.c +++ /dev/null | |||
@@ -1,535 +0,0 @@ | |||
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 | /* no getopt needed */ | ||
37 | |||
38 | #include <stdio.h> | ||
39 | #include <string.h> | ||
40 | #include <stdlib.h> | ||
41 | #include <regex.h> | ||
42 | #include <sys/types.h> | ||
43 | #include "busybox.h" | ||
44 | |||
45 | |||
46 | /* The kinds of value we can have. */ | ||
47 | enum valtype { | ||
48 | integer, | ||
49 | string | ||
50 | }; | ||
51 | typedef enum valtype TYPE; | ||
52 | |||
53 | /* A value is.... */ | ||
54 | struct valinfo { | ||
55 | TYPE type; /* Which kind. */ | ||
56 | union { /* The value itself. */ | ||
57 | int i; | ||
58 | char *s; | ||
59 | } u; | ||
60 | }; | ||
61 | typedef struct valinfo VALUE; | ||
62 | |||
63 | /* The arguments given to the program, minus the program name. */ | ||
64 | static char **args; | ||
65 | |||
66 | static VALUE *docolon (VALUE *sv, VALUE *pv); | ||
67 | static VALUE *eval (void); | ||
68 | static VALUE *int_value (int i); | ||
69 | static VALUE *str_value (char *s); | ||
70 | static int nextarg (char *str); | ||
71 | static int null (VALUE *v); | ||
72 | static int toarith (VALUE *v); | ||
73 | static void freev (VALUE *v); | ||
74 | static void tostring (VALUE *v); | ||
75 | |||
76 | int expr_main (int argc, char **argv) | ||
77 | { | ||
78 | VALUE *v; | ||
79 | |||
80 | if (argc == 1) { | ||
81 | error_msg_and_die("too few arguments"); | ||
82 | } | ||
83 | |||
84 | args = argv + 1; | ||
85 | |||
86 | v = eval (); | ||
87 | if (*args) | ||
88 | error_msg_and_die ("syntax error"); | ||
89 | |||
90 | if (v->type == integer) | ||
91 | printf ("%d\n", v->u.i); | ||
92 | else | ||
93 | puts (v->u.s); | ||
94 | |||
95 | exit (null (v)); | ||
96 | } | ||
97 | |||
98 | /* Return a VALUE for I. */ | ||
99 | |||
100 | static VALUE *int_value (int i) | ||
101 | { | ||
102 | VALUE *v; | ||
103 | |||
104 | v = xmalloc (sizeof(VALUE)); | ||
105 | v->type = integer; | ||
106 | v->u.i = i; | ||
107 | return v; | ||
108 | } | ||
109 | |||
110 | /* Return a VALUE for S. */ | ||
111 | |||
112 | static VALUE *str_value (char *s) | ||
113 | { | ||
114 | VALUE *v; | ||
115 | |||
116 | v = xmalloc (sizeof(VALUE)); | ||
117 | v->type = string; | ||
118 | v->u.s = strdup (s); | ||
119 | return v; | ||
120 | } | ||
121 | |||
122 | /* Free VALUE V, including structure components. */ | ||
123 | |||
124 | static void freev (VALUE *v) | ||
125 | { | ||
126 | if (v->type == string) | ||
127 | free (v->u.s); | ||
128 | free (v); | ||
129 | } | ||
130 | |||
131 | /* Return nonzero if V is a null-string or zero-number. */ | ||
132 | |||
133 | static int null (VALUE *v) | ||
134 | { | ||
135 | switch (v->type) { | ||
136 | case integer: | ||
137 | return v->u.i == 0; | ||
138 | case string: | ||
139 | return v->u.s[0] == '\0' || strcmp (v->u.s, "0") == 0; | ||
140 | default: | ||
141 | abort (); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | /* Coerce V to a string value (can't fail). */ | ||
146 | |||
147 | static void tostring (VALUE *v) | ||
148 | { | ||
149 | char *temp; | ||
150 | |||
151 | if (v->type == integer) { | ||
152 | temp = xmalloc (4 * (sizeof (int) / sizeof (char))); | ||
153 | sprintf (temp, "%d", v->u.i); | ||
154 | v->u.s = temp; | ||
155 | v->type = string; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* Coerce V to an integer value. Return 1 on success, 0 on failure. */ | ||
160 | |||
161 | static int toarith (VALUE *v) | ||
162 | { | ||
163 | int i; | ||
164 | |||
165 | switch (v->type) { | ||
166 | case integer: | ||
167 | return 1; | ||
168 | case string: | ||
169 | i = 0; | ||
170 | /* Don't interpret the empty string as an integer. */ | ||
171 | if (v->u.s == 0) | ||
172 | return 0; | ||
173 | i = atoi(v->u.s); | ||
174 | free (v->u.s); | ||
175 | v->u.i = i; | ||
176 | v->type = integer; | ||
177 | return 1; | ||
178 | default: | ||
179 | abort (); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | /* Return nonzero if the next token matches STR exactly. | ||
184 | STR must not be NULL. */ | ||
185 | |||
186 | static int | ||
187 | nextarg (char *str) | ||
188 | { | ||
189 | if (*args == NULL) | ||
190 | return 0; | ||
191 | return strcmp (*args, str) == 0; | ||
192 | } | ||
193 | |||
194 | /* The comparison operator handling functions. */ | ||
195 | |||
196 | #define cmpf(name, rel) \ | ||
197 | static int name (l, r) VALUE *l; VALUE *r; \ | ||
198 | { \ | ||
199 | if (l->type == string || r->type == string) { \ | ||
200 | tostring (l); \ | ||
201 | tostring (r); \ | ||
202 | return strcmp (l->u.s, r->u.s) rel 0; \ | ||
203 | } \ | ||
204 | else \ | ||
205 | return l->u.i rel r->u.i; \ | ||
206 | } | ||
207 | cmpf (less_than, <) | ||
208 | cmpf (less_equal, <=) | ||
209 | cmpf (equal, ==) | ||
210 | cmpf (not_equal, !=) | ||
211 | cmpf (greater_equal, >=) | ||
212 | cmpf (greater_than, >) | ||
213 | |||
214 | #undef cmpf | ||
215 | |||
216 | /* The arithmetic operator handling functions. */ | ||
217 | |||
218 | #define arithf(name, op) \ | ||
219 | static \ | ||
220 | int name (l, r) VALUE *l; VALUE *r; \ | ||
221 | { \ | ||
222 | if (!toarith (l) || !toarith (r)) \ | ||
223 | error_msg_and_die ("non-numeric argument"); \ | ||
224 | return l->u.i op r->u.i; \ | ||
225 | } | ||
226 | |||
227 | #define arithdivf(name, op) \ | ||
228 | static int name (l, r) VALUE *l; VALUE *r; \ | ||
229 | { \ | ||
230 | if (!toarith (l) || !toarith (r)) \ | ||
231 | error_msg_and_die ( "non-numeric argument"); \ | ||
232 | if (r->u.i == 0) \ | ||
233 | error_msg_and_die ( "division by zero"); \ | ||
234 | return l->u.i op r->u.i; \ | ||
235 | } | ||
236 | |||
237 | arithf (plus, +) | ||
238 | arithf (minus, -) | ||
239 | arithf (multiply, *) | ||
240 | arithdivf (divide, /) | ||
241 | arithdivf (mod, %) | ||
242 | |||
243 | #undef arithf | ||
244 | #undef arithdivf | ||
245 | |||
246 | /* Do the : operator. | ||
247 | SV is the VALUE for the lhs (the string), | ||
248 | PV is the VALUE for the rhs (the pattern). */ | ||
249 | |||
250 | static VALUE *docolon (VALUE *sv, VALUE *pv) | ||
251 | { | ||
252 | VALUE *v; | ||
253 | const char *errmsg; | ||
254 | struct re_pattern_buffer re_buffer; | ||
255 | struct re_registers re_regs; | ||
256 | int len; | ||
257 | |||
258 | tostring (sv); | ||
259 | tostring (pv); | ||
260 | |||
261 | if (pv->u.s[0] == '^') { | ||
262 | fprintf (stderr, "\ | ||
263 | warning: unportable BRE: `%s': using `^' as the first character\n\ | ||
264 | of a basic regular expression is not portable; it is being ignored", | ||
265 | pv->u.s); | ||
266 | } | ||
267 | |||
268 | len = strlen (pv->u.s); | ||
269 | memset (&re_buffer, 0, sizeof (re_buffer)); | ||
270 | memset (&re_regs, 0, sizeof (re_regs)); | ||
271 | re_buffer.allocated = 2 * len; | ||
272 | re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated); | ||
273 | re_buffer.translate = 0; | ||
274 | re_syntax_options = RE_SYNTAX_POSIX_BASIC; | ||
275 | errmsg = re_compile_pattern (pv->u.s, len, &re_buffer); | ||
276 | if (errmsg) { | ||
277 | error_msg_and_die("%s", errmsg); | ||
278 | } | ||
279 | |||
280 | len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs); | ||
281 | if (len >= 0) { | ||
282 | /* Were \(...\) used? */ | ||
283 | if (re_buffer.re_nsub > 0) { /* was (re_regs.start[1] >= 0) */ | ||
284 | sv->u.s[re_regs.end[1]] = '\0'; | ||
285 | v = str_value (sv->u.s + re_regs.start[1]); | ||
286 | } | ||
287 | else | ||
288 | v = int_value (len); | ||
289 | } | ||
290 | else { | ||
291 | /* Match failed -- return the right kind of null. */ | ||
292 | if (re_buffer.re_nsub > 0) | ||
293 | v = str_value (""); | ||
294 | else | ||
295 | v = int_value (0); | ||
296 | } | ||
297 | free (re_buffer.buffer); | ||
298 | return v; | ||
299 | } | ||
300 | |||
301 | /* Handle bare operands and ( expr ) syntax. */ | ||
302 | |||
303 | static VALUE *eval7 (void) | ||
304 | { | ||
305 | VALUE *v; | ||
306 | |||
307 | if (!*args) | ||
308 | error_msg_and_die ( "syntax error"); | ||
309 | |||
310 | if (nextarg ("(")) { | ||
311 | args++; | ||
312 | v = eval (); | ||
313 | if (!nextarg (")")) | ||
314 | error_msg_and_die ( "syntax error"); | ||
315 | args++; | ||
316 | return v; | ||
317 | } | ||
318 | |||
319 | if (nextarg (")")) | ||
320 | error_msg_and_die ( "syntax error"); | ||
321 | |||
322 | return str_value (*args++); | ||
323 | } | ||
324 | |||
325 | /* Handle match, substr, index, length, and quote keywords. */ | ||
326 | |||
327 | static VALUE *eval6 (void) | ||
328 | { | ||
329 | VALUE *l, *r, *v, *i1, *i2; | ||
330 | |||
331 | if (nextarg ("quote")) { | ||
332 | args++; | ||
333 | if (!*args) | ||
334 | error_msg_and_die ( "syntax error"); | ||
335 | return str_value (*args++); | ||
336 | } | ||
337 | else if (nextarg ("length")) { | ||
338 | args++; | ||
339 | r = eval6 (); | ||
340 | tostring (r); | ||
341 | v = int_value (strlen (r->u.s)); | ||
342 | freev (r); | ||
343 | return v; | ||
344 | } | ||
345 | else if (nextarg ("match")) { | ||
346 | args++; | ||
347 | l = eval6 (); | ||
348 | r = eval6 (); | ||
349 | v = docolon (l, r); | ||
350 | freev (l); | ||
351 | freev (r); | ||
352 | return v; | ||
353 | } | ||
354 | else if (nextarg ("index")) { | ||
355 | args++; | ||
356 | l = eval6 (); | ||
357 | r = eval6 (); | ||
358 | tostring (l); | ||
359 | tostring (r); | ||
360 | v = int_value (strcspn (l->u.s, r->u.s) + 1); | ||
361 | if (v->u.i == (int) strlen (l->u.s) + 1) | ||
362 | v->u.i = 0; | ||
363 | freev (l); | ||
364 | freev (r); | ||
365 | return v; | ||
366 | } | ||
367 | else if (nextarg ("substr")) { | ||
368 | args++; | ||
369 | l = eval6 (); | ||
370 | i1 = eval6 (); | ||
371 | i2 = eval6 (); | ||
372 | tostring (l); | ||
373 | if (!toarith (i1) || !toarith (i2) | ||
374 | || i1->u.i > (int) strlen (l->u.s) | ||
375 | || i1->u.i <= 0 || i2->u.i <= 0) | ||
376 | v = str_value (""); | ||
377 | else { | ||
378 | v = xmalloc (sizeof(VALUE)); | ||
379 | v->type = string; | ||
380 | v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1), | ||
381 | l->u.s + i1->u.i - 1, i2->u.i); | ||
382 | v->u.s[i2->u.i] = 0; | ||
383 | } | ||
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 | |||
396 | static 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 | |||
414 | static VALUE *eval4 (void) | ||
415 | { | ||
416 | VALUE *l, *r; | ||
417 | int (*fxn) (), val; | ||
418 | |||
419 | l = eval5 (); | ||
420 | while (1) { | ||
421 | if (nextarg ("*")) | ||
422 | fxn = multiply; | ||
423 | else if (nextarg ("/")) | ||
424 | fxn = divide; | ||
425 | else if (nextarg ("%")) | ||
426 | fxn = mod; | ||
427 | else | ||
428 | return l; | ||
429 | args++; | ||
430 | r = eval5 (); | ||
431 | val = (*fxn) (l, r); | ||
432 | freev (l); | ||
433 | freev (r); | ||
434 | l = int_value (val); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | /* Handle +, - operators. */ | ||
439 | |||
440 | static VALUE *eval3 (void) | ||
441 | { | ||
442 | VALUE *l, *r; | ||
443 | int (*fxn) (), val; | ||
444 | |||
445 | l = eval4 (); | ||
446 | while (1) { | ||
447 | if (nextarg ("+")) | ||
448 | fxn = plus; | ||
449 | else if (nextarg ("-")) | ||
450 | fxn = minus; | ||
451 | else | ||
452 | return l; | ||
453 | args++; | ||
454 | r = eval4 (); | ||
455 | val = (*fxn) (l, r); | ||
456 | freev (l); | ||
457 | freev (r); | ||
458 | l = int_value (val); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | /* Handle comparisons. */ | ||
463 | |||
464 | static VALUE *eval2 (void) | ||
465 | { | ||
466 | VALUE *l, *r; | ||
467 | int (*fxn) (), val; | ||
468 | |||
469 | l = eval3 (); | ||
470 | while (1) { | ||
471 | if (nextarg ("<")) | ||
472 | fxn = less_than; | ||
473 | else if (nextarg ("<=")) | ||
474 | fxn = less_equal; | ||
475 | else if (nextarg ("=") || nextarg ("==")) | ||
476 | fxn = equal; | ||
477 | else if (nextarg ("!=")) | ||
478 | fxn = not_equal; | ||
479 | else if (nextarg (">=")) | ||
480 | fxn = greater_equal; | ||
481 | else if (nextarg (">")) | ||
482 | fxn = greater_than; | ||
483 | else | ||
484 | return l; | ||
485 | args++; | ||
486 | r = eval3 (); | ||
487 | toarith (l); | ||
488 | toarith (r); | ||
489 | val = (*fxn) (l, r); | ||
490 | freev (l); | ||
491 | freev (r); | ||
492 | l = int_value (val); | ||
493 | } | ||
494 | } | ||
495 | |||
496 | /* Handle &. */ | ||
497 | |||
498 | static VALUE *eval1 (void) | ||
499 | { | ||
500 | VALUE *l, *r; | ||
501 | |||
502 | l = eval2 (); | ||
503 | while (nextarg ("&")) { | ||
504 | args++; | ||
505 | r = eval2 (); | ||
506 | if (null (l) || null (r)) { | ||
507 | freev (l); | ||
508 | freev (r); | ||
509 | l = int_value (0); | ||
510 | } | ||
511 | else | ||
512 | freev (r); | ||
513 | } | ||
514 | return l; | ||
515 | } | ||
516 | |||
517 | /* Handle |. */ | ||
518 | |||
519 | static VALUE *eval (void) | ||
520 | { | ||
521 | VALUE *l, *r; | ||
522 | |||
523 | l = eval1 (); | ||
524 | while (nextarg ("|")) { | ||
525 | args++; | ||
526 | r = eval1 (); | ||
527 | if (null (l)) { | ||
528 | freev (l); | ||
529 | l = r; | ||
530 | } | ||
531 | else | ||
532 | freev (r); | ||
533 | } | ||
534 | return l; | ||
535 | } | ||