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