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