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