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