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