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