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