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