VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/expr.c@ 2113

最後變更 在這個檔案從2113是 2113,由 bird 提交於 16 年 前

kmkbuiltin: include config.h

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette