1 /* $OpenBSD: expr.c,v 1.15 2003/06/11 23:42:12 deraadt Exp $ */
2 /* $NetBSD: expr.c,v 1.3.6.1 1996/06/04 20:41:47 cgd Exp $ */
3
4 /*
5 * Written by J.T. Conklin <jtc@netbsd.org>.
6 * Public domain.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <locale.h>
13 #include <ctype.h>
14 #include <regex.h>
15 #include <err.h>
16
17 __RCSID("$MirOS: src/bin/expr/expr.c,v 1.3 2007/07/05 23:16:48 tg Exp $");
18
19 struct val *make_int(int);
20 struct val *make_str(char *);
21 void free_value(struct val *);
22 int is_integer(struct val *, int *);
23 int to_integer(struct val *);
24 void to_string(struct val *);
25 int is_zero_or_null(struct val *);
26 void nexttoken(int);
27 __dead void error(void);
28 struct val *eval6(void);
29 struct val *eval5(void);
30 struct val *eval4(void);
31 struct val *eval3(void);
32 struct val *eval2(void);
33 struct val *eval1(void);
34 struct val *eval0(void);
35
36 enum token {
37 OR, AND, EQ, LT, GT, ADD, SUB, MUL, DIV, MOD, MATCH, RP, LP,
38 NE, LE, GE, OPERAND, EOI
39 };
40
41 struct val {
42 enum {
43 integer,
44 string
45 } type;
46
47 union {
48 char *s;
49 int i;
50 } u;
51 };
52
53 enum token token;
54 struct val *tokval;
55 char **av;
56
57 struct val *
make_int(int i)58 make_int(int i)
59 {
60 struct val *vp;
61
62 vp = (struct val *) malloc(sizeof(*vp));
63 if (vp == NULL) {
64 err(3, NULL);
65 }
66 vp->type = integer;
67 vp->u.i = i;
68 return vp;
69 }
70
71
72 struct val *
make_str(char * s)73 make_str(char *s)
74 {
75 struct val *vp;
76
77 vp = (struct val *) malloc(sizeof(*vp));
78 if (vp == NULL || ((vp->u.s = strdup(s)) == NULL)) {
79 err(3, NULL);
80 }
81 vp->type = string;
82 return vp;
83 }
84
85
86 void
free_value(struct val * vp)87 free_value(struct val *vp)
88 {
89 if (vp->type == string)
90 free(vp->u.s);
91 free(vp);
92 }
93
94
95 /* determine if vp is an integer; if so, return it's value in *r */
96 int
is_integer(struct val * vp,int * r)97 is_integer(struct val *vp, int *r)
98 {
99 char *s;
100 int neg;
101 int i;
102
103 if (vp->type == integer) {
104 *r = vp->u.i;
105 return 1;
106 }
107
108 /*
109 * POSIX.2 defines an "integer" as an optional unary minus
110 * followed by digits.
111 */
112 s = vp->u.s;
113 i = 0;
114
115 neg = (*s == '-');
116 if (neg)
117 s++;
118
119 while (*s) {
120 if (!isdigit(*s))
121 return 0;
122
123 i *= 10;
124 i += *s - '0';
125
126 s++;
127 }
128
129 if (neg)
130 i *= -1;
131
132 *r = i;
133 return 1;
134 }
135
136
137 /* coerce to vp to an integer */
138 int
to_integer(struct val * vp)139 to_integer(struct val *vp)
140 {
141 int r;
142
143 if (vp->type == integer)
144 return 1;
145
146 if (is_integer(vp, &r)) {
147 free(vp->u.s);
148 vp->u.i = r;
149 vp->type = integer;
150 return 1;
151 }
152
153 return 0;
154 }
155
156
157 /* coerce to vp to an string */
158 void
to_string(struct val * vp)159 to_string(struct val *vp)
160 {
161 char *tmp;
162 size_t len;
163
164 if (vp->type == string)
165 return;
166
167 len = 25;
168 tmp = malloc(len);
169 if (tmp == NULL) {
170 err(3, NULL);
171 }
172 snprintf(tmp, len, "%d", vp->u.i);
173 vp->type = string;
174 vp->u.s = tmp;
175 }
176
177 int
is_zero_or_null(struct val * vp)178 is_zero_or_null(struct val *vp)
179 {
180 if (vp->type == integer) {
181 return (vp->u.i == 0);
182 } else {
183 return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
184 }
185 /* NOTREACHED */
186 }
187
188 void
nexttoken(int pat)189 nexttoken(int pat)
190 {
191 char *p;
192
193 if ((p = *av) == NULL) {
194 token = EOI;
195 return;
196 }
197 av++;
198
199
200 if (pat == 0 && p[0] != '\0') {
201 if (p[1] == '\0') {
202 const char *x = "|&=<>+-*/%:()";
203 char *i; /* index */
204
205 if ((i = strchr(x, *p)) != NULL) {
206 token = i - x;
207 return;
208 }
209 } else if (p[1] == '=' && p[2] == '\0') {
210 switch (*p) {
211 case '<':
212 token = LE;
213 return;
214 case '>':
215 token = GE;
216 return;
217 case '!':
218 token = NE;
219 return;
220 }
221 }
222 }
223 tokval = make_str(p);
224 token = OPERAND;
225 return;
226 }
227
228 __dead void
error(void)229 error(void)
230 {
231 errx(2, "syntax error");
232 /* NOTREACHED */
233 }
234
235 struct val *
eval6(void)236 eval6(void)
237 {
238 struct val *v;
239
240 if (token == OPERAND) {
241 nexttoken(0);
242 return tokval;
243
244 } else if (token == RP) {
245 nexttoken(0);
246 v = eval0();
247
248 if (token != LP) {
249 error();
250 /* NOTREACHED */
251 }
252 nexttoken(0);
253 return v;
254 } else {
255 error();
256 }
257 /* NOTREACHED */
258 }
259
260 /* Parse and evaluate match (regex) expressions */
261 struct val *
eval5(void)262 eval5(void)
263 {
264 regex_t rp;
265 regmatch_t rm[2];
266 char errbuf[256];
267 int eval;
268 struct val *l, *r;
269 struct val *v;
270
271 l = eval6();
272 while (token == MATCH) {
273 nexttoken(1);
274 r = eval6();
275
276 /* coerce to both arguments to strings */
277 to_string(l);
278 to_string(r);
279
280 /* compile regular expression */
281 if ((eval = regcomp(&rp, r->u.s, 0)) != 0) {
282 regerror(eval, &rp, errbuf, sizeof(errbuf));
283 errx(2, "%s", errbuf);
284 }
285
286 /* compare string against pattern -- remember that patterns
287 are anchored to the beginning of the line */
288 if (regexec(&rp, l->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
289 if (rm[1].rm_so >= 0) {
290 *(l->u.s + rm[1].rm_eo) = '\0';
291 v = make_str(l->u.s + rm[1].rm_so);
292
293 } else {
294 v = make_int((int)(rm[0].rm_eo - rm[0].rm_so));
295 }
296 } else {
297 if (rp.re_nsub == 0) {
298 v = make_int(0);
299 } else {
300 v = make_str("");
301 }
302 }
303
304 /* free arguments and pattern buffer */
305 free_value(l);
306 free_value(r);
307 regfree(&rp);
308
309 l = v;
310 }
311
312 return l;
313 }
314
315 /* Parse and evaluate multiplication and division expressions */
316 struct val *
eval4(void)317 eval4(void)
318 {
319 struct val *l, *r;
320 enum token op;
321
322 l = eval5();
323 while ((op = token) == MUL || op == DIV || op == MOD) {
324 nexttoken(0);
325 r = eval5();
326
327 if (!to_integer(l) || !to_integer(r)) {
328 errx(2, "non-numeric argument");
329 }
330
331 if (op == MUL) {
332 l->u.i *= r->u.i;
333 } else {
334 if (r->u.i == 0) {
335 errx(2, "division by zero");
336 }
337 if (op == DIV) {
338 l->u.i /= r->u.i;
339 } else {
340 l->u.i %= r->u.i;
341 }
342 }
343
344 free_value(r);
345 }
346
347 return l;
348 }
349
350 /* Parse and evaluate addition and subtraction expressions */
351 struct val *
eval3(void)352 eval3(void)
353 {
354 struct val *l, *r;
355 enum token op;
356
357 l = eval4();
358 while ((op = token) == ADD || op == SUB) {
359 nexttoken(0);
360 r = eval4();
361
362 if (!to_integer(l) || !to_integer(r)) {
363 errx(2, "non-numeric argument");
364 }
365
366 if (op == ADD) {
367 l->u.i += r->u.i;
368 } else {
369 l->u.i -= r->u.i;
370 }
371
372 free_value(r);
373 }
374
375 return l;
376 }
377
378 #ifdef __MirBSD__
379 #define strcoll strcmp
380 #endif
381
382 /* Parse and evaluate comparison expressions */
383 struct val *
eval2(void)384 eval2(void)
385 {
386 struct val *l, *r;
387 enum token op;
388 int v = 0, li, ri;
389
390 l = eval3();
391 while ((op = token) == EQ || op == NE || op == LT || op == GT ||
392 op == LE || op == GE) {
393 nexttoken(0);
394 r = eval3();
395
396 if (is_integer(l, &li) && is_integer(r, &ri)) {
397 switch (op) {
398 case GT:
399 v = (li > ri);
400 break;
401 case GE:
402 v = (li >= ri);
403 break;
404 case LT:
405 v = (li < ri);
406 break;
407 case LE:
408 v = (li <= ri);
409 break;
410 case EQ:
411 v = (li == ri);
412 break;
413 case NE:
414 v = (li != ri);
415 break;
416 default:
417 break;
418 }
419 } else {
420 to_string(l);
421 to_string(r);
422
423 switch (op) {
424 case GT:
425 v = (strcoll(l->u.s, r->u.s) > 0);
426 break;
427 case GE:
428 v = (strcoll(l->u.s, r->u.s) >= 0);
429 break;
430 case LT:
431 v = (strcoll(l->u.s, r->u.s) < 0);
432 break;
433 case LE:
434 v = (strcoll(l->u.s, r->u.s) <= 0);
435 break;
436 case EQ:
437 v = (strcoll(l->u.s, r->u.s) == 0);
438 break;
439 case NE:
440 v = (strcoll(l->u.s, r->u.s) != 0);
441 break;
442 default:
443 break;
444 }
445 }
446
447 free_value(l);
448 free_value(r);
449 l = make_int(v);
450 }
451
452 return l;
453 }
454
455 /* Parse and evaluate & expressions */
456 struct val *
eval1(void)457 eval1(void)
458 {
459 struct val *l, *r;
460
461 l = eval2();
462 while (token == AND) {
463 nexttoken(0);
464 r = eval2();
465
466 if (is_zero_or_null(l) || is_zero_or_null(r)) {
467 free_value(l);
468 free_value(r);
469 l = make_int(0);
470 } else {
471 free_value(r);
472 }
473 }
474
475 return l;
476 }
477
478 /* Parse and evaluate | expressions */
479 struct val *
eval0(void)480 eval0(void)
481 {
482 struct val *l, *r;
483
484 l = eval1();
485 while (token == OR) {
486 nexttoken(0);
487 r = eval1();
488
489 if (is_zero_or_null(l)) {
490 free_value(l);
491 l = r;
492 } else {
493 free_value(r);
494 }
495 }
496
497 return l;
498 }
499
500
501 int
main(int argc,char * argv[])502 main(int argc, char *argv[])
503 {
504 struct val *vp;
505
506 #ifndef __MirBSD__
507 (void) setlocale(LC_ALL, "");
508 #endif
509 av = argv + 1;
510
511 nexttoken(0);
512 vp = eval0();
513
514 if (token != EOI) {
515 error();
516 /* NOTREACHED */
517 }
518
519 if (vp->type == integer)
520 printf("%d\n", vp->u.i);
521 else
522 printf("%s\n", vp->u.s);
523
524 exit(is_zero_or_null(vp));
525 }
526