1 /* $OpenBSD: expr.c,v 1.26 2016/10/19 18:20:25 schwarze 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 *); 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 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) 98 { 99 char *s; 100 int neg; 101 int64_t 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 int64_t 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, "%lld", 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 182 void 183 nexttoken(int pat) 184 { 185 char *p; 186 187 if ((p = *av) == NULL) { 188 token = EOI; 189 return; 190 } 191 av++; 192 193 194 if (pat == 0 && p[0] != '\0') { 195 if (p[1] == '\0') { 196 const char *x = "|&=<>+-*/%:()"; 197 char *i; /* index */ 198 199 if ((i = strchr(x, *p)) != NULL) { 200 token = i - x; 201 return; 202 } 203 } else if (p[1] == '=' && p[2] == '\0') { 204 switch (*p) { 205 case '<': 206 token = LE; 207 return; 208 case '>': 209 token = GE; 210 return; 211 case '!': 212 token = NE; 213 return; 214 } 215 } 216 } 217 tokval = make_str(p); 218 token = OPERAND; 219 return; 220 } 221 222 __dead void 223 error(void) 224 { 225 errx(2, "syntax error"); 226 } 227 228 struct val * 229 eval6(void) 230 { 231 struct val *v; 232 233 if (token == OPERAND) { 234 nexttoken(0); 235 return tokval; 236 } else if (token == RP) { 237 nexttoken(0); 238 v = eval0(); 239 if (token != LP) 240 error(); 241 nexttoken(0); 242 return v; 243 } else 244 error(); 245 } 246 247 /* Parse and evaluate match (regex) expressions */ 248 struct val * 249 eval5(void) 250 { 251 regex_t rp; 252 regmatch_t rm[2]; 253 char errbuf[256]; 254 int eval; 255 struct val *l, *r; 256 struct val *v; 257 258 l = eval6(); 259 while (token == MATCH) { 260 nexttoken(1); 261 r = eval6(); 262 263 /* coerce to both arguments to strings */ 264 to_string(l); 265 to_string(r); 266 267 /* compile regular expression */ 268 if ((eval = regcomp(&rp, r->u.s, 0)) != 0) { 269 regerror(eval, &rp, errbuf, sizeof(errbuf)); 270 errx(2, "%s", errbuf); 271 } 272 273 /* compare string against pattern -- remember that patterns 274 are anchored to the beginning of the line */ 275 if (regexec(&rp, l->u.s, 2, rm, 0) == 0 && rm[0].rm_so == 0) { 276 if (rm[1].rm_so >= 0) { 277 *(l->u.s + rm[1].rm_eo) = '\0'; 278 v = make_str(l->u.s + rm[1].rm_so); 279 280 } else { 281 v = make_int(rm[0].rm_eo - rm[0].rm_so); 282 } 283 } else { 284 if (rp.re_nsub == 0) { 285 v = make_int(0); 286 } else { 287 v = make_str(""); 288 } 289 } 290 291 /* free arguments and pattern buffer */ 292 free_value(l); 293 free_value(r); 294 regfree(&rp); 295 296 l = v; 297 } 298 299 return l; 300 } 301 302 /* Parse and evaluate multiplication and division expressions */ 303 struct val * 304 eval4(void) 305 { 306 struct val *l, *r; 307 enum token op; 308 309 l = eval5(); 310 while ((op = token) == MUL || op == DIV || op == MOD) { 311 nexttoken(0); 312 r = eval5(); 313 314 if (!to_integer(l) || !to_integer(r)) { 315 errx(2, "non-numeric argument"); 316 } 317 318 if (op == MUL) { 319 l->u.i *= r->u.i; 320 } else { 321 if (r->u.i == 0) { 322 errx(2, "division by zero"); 323 } 324 if (op == DIV) { 325 if (l->u.i != INT64_MIN || r->u.i != -1) 326 l->u.i /= r->u.i; 327 } else { 328 if (l->u.i != INT64_MIN || r->u.i != -1) 329 l->u.i %= r->u.i; 330 else 331 l->u.i = 0; 332 } 333 } 334 335 free_value(r); 336 } 337 338 return l; 339 } 340 341 /* Parse and evaluate addition and subtraction expressions */ 342 struct val * 343 eval3(void) 344 { 345 struct val *l, *r; 346 enum token op; 347 348 l = eval4(); 349 while ((op = token) == ADD || op == SUB) { 350 nexttoken(0); 351 r = eval4(); 352 353 if (!to_integer(l) || !to_integer(r)) { 354 errx(2, "non-numeric argument"); 355 } 356 357 if (op == ADD) { 358 l->u.i += r->u.i; 359 } else { 360 l->u.i -= r->u.i; 361 } 362 363 free_value(r); 364 } 365 366 return l; 367 } 368 369 /* Parse and evaluate comparison expressions */ 370 struct val * 371 eval2(void) 372 { 373 struct val *l, *r; 374 enum token op; 375 int64_t v = 0, li, ri; 376 377 l = eval3(); 378 while ((op = token) == EQ || op == NE || op == LT || op == GT || 379 op == LE || op == GE) { 380 nexttoken(0); 381 r = eval3(); 382 383 if (is_integer(l, &li) && is_integer(r, &ri)) { 384 switch (op) { 385 case GT: 386 v = (li > ri); 387 break; 388 case GE: 389 v = (li >= ri); 390 break; 391 case LT: 392 v = (li < ri); 393 break; 394 case LE: 395 v = (li <= ri); 396 break; 397 case EQ: 398 v = (li == ri); 399 break; 400 case NE: 401 v = (li != ri); 402 break; 403 default: 404 break; 405 } 406 } else { 407 to_string(l); 408 to_string(r); 409 410 switch (op) { 411 case GT: 412 v = (strcoll(l->u.s, r->u.s) > 0); 413 break; 414 case GE: 415 v = (strcoll(l->u.s, r->u.s) >= 0); 416 break; 417 case LT: 418 v = (strcoll(l->u.s, r->u.s) < 0); 419 break; 420 case LE: 421 v = (strcoll(l->u.s, r->u.s) <= 0); 422 break; 423 case EQ: 424 v = (strcoll(l->u.s, r->u.s) == 0); 425 break; 426 case NE: 427 v = (strcoll(l->u.s, r->u.s) != 0); 428 break; 429 default: 430 break; 431 } 432 } 433 434 free_value(l); 435 free_value(r); 436 l = make_int(v); 437 } 438 439 return l; 440 } 441 442 /* Parse and evaluate & expressions */ 443 struct val * 444 eval1(void) 445 { 446 struct val *l, *r; 447 448 l = eval2(); 449 while (token == AND) { 450 nexttoken(0); 451 r = eval2(); 452 453 if (is_zero_or_null(l) || is_zero_or_null(r)) { 454 free_value(l); 455 free_value(r); 456 l = make_int(0); 457 } else { 458 free_value(r); 459 } 460 } 461 462 return l; 463 } 464 465 /* Parse and evaluate | expressions */ 466 struct val * 467 eval0(void) 468 { 469 struct val *l, *r; 470 471 l = eval1(); 472 while (token == OR) { 473 nexttoken(0); 474 r = eval1(); 475 476 if (is_zero_or_null(l)) { 477 free_value(l); 478 l = r; 479 } else { 480 free_value(r); 481 } 482 } 483 484 return l; 485 } 486 487 488 int 489 main(int argc, char *argv[]) 490 { 491 struct val *vp; 492 493 if (pledge("stdio", NULL) == -1) 494 err(2, "pledge"); 495 496 if (argc > 1 && !strcmp(argv[1], "--")) 497 argv++; 498 499 av = argv + 1; 500 501 nexttoken(0); 502 vp = eval0(); 503 504 if (token != EOI) 505 error(); 506 507 if (vp->type == integer) 508 printf("%lld\n", vp->u.i); 509 else 510 printf("%s\n", vp->u.s); 511 512 return is_zero_or_null(vp); 513 } 514