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