1 /* $OpenBSD: exp.c,v 1.13 2015/10/26 15:01:15 naddy Exp $ */ 2 /* $NetBSD: exp.c,v 1.6 1995/03/21 09:02:51 cgd Exp $ */ 3 4 /*- 5 * Copyright (c) 1980, 1991, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <limits.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <stdarg.h> 39 40 #include "csh.h" 41 #include "extern.h" 42 43 #define IGNORE 1 /* in ignore, it means to ignore value, just parse */ 44 #define NOGLOB 2 /* in ignore, it means not to globone */ 45 46 #define ADDOP 1 47 #define MULOP 2 48 #define EQOP 4 49 #define RELOP 8 50 #define RESTOP 16 51 #define ANYOP 31 52 53 #define EQEQ 1 54 #define GTR 2 55 #define LSS 4 56 #define NOTEQ 6 57 #define EQMATCH 7 58 #define NOTEQMATCH 8 59 60 static int exp1(Char ***, bool); 61 static int exp2_(Char ***, bool); 62 static int exp2a(Char ***, bool); 63 static int exp2b(Char ***, bool); 64 static int exp2c(Char ***, bool); 65 static Char * exp3(Char ***, bool); 66 static Char * exp3a(Char ***, bool); 67 static Char * exp4(Char ***, bool); 68 static Char * exp5(Char ***, bool); 69 static Char * exp6(Char ***, bool); 70 static void evalav(Char **); 71 static int isa(Char *, int); 72 static int egetn(Char *); 73 74 #ifdef EDEBUG 75 static void etracc(char *, Char *, Char ***); 76 static void etraci(char *, int, Char ***); 77 #endif 78 79 int 80 expr(Char ***vp) 81 { 82 return (exp0(vp, 0)); 83 } 84 85 int 86 exp0(Char ***vp, bool ignore) 87 { 88 int p1 = exp1(vp, ignore); 89 90 #ifdef EDEBUG 91 etraci("exp0 p1", p1, vp); 92 #endif 93 if (**vp && eq(**vp, STRor2)) { 94 int p2; 95 96 (*vp)++; 97 p2 = exp0(vp, (ignore & IGNORE) || p1); 98 #ifdef EDEBUG 99 etraci("exp0 p2", p2, vp); 100 #endif 101 return (p1 || p2); 102 } 103 return (p1); 104 } 105 106 static int 107 exp1(Char ***vp, bool ignore) 108 { 109 int p1 = exp2_(vp, ignore); 110 111 #ifdef EDEBUG 112 etraci("exp1 p1", p1, vp); 113 #endif 114 if (**vp && eq(**vp, STRand2)) { 115 int p2; 116 117 (*vp)++; 118 p2 = exp1(vp, (ignore & IGNORE) || !p1); 119 #ifdef EDEBUG 120 etraci("exp1 p2", p2, vp); 121 #endif 122 return (p1 && p2); 123 } 124 return (p1); 125 } 126 127 static int 128 exp2_(Char ***vp, bool ignore) 129 { 130 int p1 = exp2a(vp, ignore); 131 132 #ifdef EDEBUG 133 etraci("exp3 p1", p1, vp); 134 #endif 135 if (**vp && eq(**vp, STRor)) { 136 int p2; 137 138 (*vp)++; 139 p2 = exp2_(vp, ignore); 140 #ifdef EDEBUG 141 etraci("exp3 p2", p2, vp); 142 #endif 143 return (p1 | p2); 144 } 145 return (p1); 146 } 147 148 static int 149 exp2a(Char ***vp, bool ignore) 150 { 151 int p1 = exp2b(vp, ignore); 152 153 #ifdef EDEBUG 154 etraci("exp2a p1", p1, vp); 155 #endif 156 if (**vp && eq(**vp, STRcaret)) { 157 int p2; 158 159 (*vp)++; 160 p2 = exp2a(vp, ignore); 161 #ifdef EDEBUG 162 etraci("exp2a p2", p2, vp); 163 #endif 164 return (p1 ^ p2); 165 } 166 return (p1); 167 } 168 169 static int 170 exp2b(Char ***vp, bool ignore) 171 { 172 int p1 = exp2c(vp, ignore); 173 174 #ifdef EDEBUG 175 etraci("exp2b p1", p1, vp); 176 #endif 177 if (**vp && eq(**vp, STRand)) { 178 int p2; 179 180 (*vp)++; 181 p2 = exp2b(vp, ignore); 182 #ifdef EDEBUG 183 etraci("exp2b p2", p2, vp); 184 #endif 185 return (p1 & p2); 186 } 187 return (p1); 188 } 189 190 static int 191 exp2c(Char ***vp, bool ignore) 192 { 193 Char *p1 = exp3(vp, ignore); 194 Char *p2; 195 int i; 196 197 #ifdef EDEBUG 198 etracc("exp2c p1", p1, vp); 199 #endif 200 if ((i = isa(**vp, EQOP)) != 0) { 201 (*vp)++; 202 if (i == EQMATCH || i == NOTEQMATCH) 203 ignore |= NOGLOB; 204 p2 = exp3(vp, ignore); 205 #ifdef EDEBUG 206 etracc("exp2c p2", p2, vp); 207 #endif 208 if (!(ignore & IGNORE)) 209 switch (i) { 210 211 case EQEQ: 212 i = eq(p1, p2); 213 break; 214 215 case NOTEQ: 216 i = !eq(p1, p2); 217 break; 218 219 case EQMATCH: 220 i = Gmatch(p1, p2); 221 break; 222 223 case NOTEQMATCH: 224 i = !Gmatch(p1, p2); 225 break; 226 } 227 xfree(p1); 228 xfree(p2); 229 return (i); 230 } 231 i = egetn(p1); 232 xfree(p1); 233 return (i); 234 } 235 236 static Char * 237 exp3(Char ***vp, bool ignore) 238 { 239 Char *p1, *p2; 240 int i; 241 242 p1 = exp3a(vp, ignore); 243 #ifdef EDEBUG 244 etracc("exp3 p1", p1, vp); 245 #endif 246 if ((i = isa(**vp, RELOP)) != 0) { 247 (*vp)++; 248 if (**vp && eq(**vp, STRequal)) 249 i |= 1, (*vp)++; 250 p2 = exp3(vp, ignore); 251 #ifdef EDEBUG 252 etracc("exp3 p2", p2, vp); 253 #endif 254 if (!(ignore & IGNORE)) 255 switch (i) { 256 257 case GTR: 258 i = egetn(p1) > egetn(p2); 259 break; 260 261 case GTR | 1: 262 i = egetn(p1) >= egetn(p2); 263 break; 264 265 case LSS: 266 i = egetn(p1) < egetn(p2); 267 break; 268 269 case LSS | 1: 270 i = egetn(p1) <= egetn(p2); 271 break; 272 } 273 xfree(p1); 274 xfree(p2); 275 return (putn(i)); 276 } 277 return (p1); 278 } 279 280 static Char * 281 exp3a(Char ***vp, bool ignore) 282 { 283 Char *p1, *p2, *op; 284 int i; 285 286 p1 = exp4(vp, ignore); 287 #ifdef EDEBUG 288 etracc("exp3a p1", p1, vp); 289 #endif 290 op = **vp; 291 if (op && any("<>", op[0]) && op[0] == op[1]) { 292 (*vp)++; 293 p2 = exp3a(vp, ignore); 294 #ifdef EDEBUG 295 etracc("exp3a p2", p2, vp); 296 #endif 297 if (op[0] == '<') 298 i = egetn(p1) << egetn(p2); 299 else 300 i = egetn(p1) >> egetn(p2); 301 xfree(p1); 302 xfree(p2); 303 return (putn(i)); 304 } 305 return (p1); 306 } 307 308 static Char * 309 exp4(Char ***vp, bool ignore) 310 { 311 Char *p1, *p2; 312 int i = 0; 313 314 p1 = exp5(vp, ignore); 315 #ifdef EDEBUG 316 etracc("exp4 p1", p1, vp); 317 #endif 318 if (isa(**vp, ADDOP)) { 319 Char *op = *(*vp)++; 320 321 p2 = exp4(vp, ignore); 322 #ifdef EDEBUG 323 etracc("exp4 p2", p2, vp); 324 #endif 325 if (!(ignore & IGNORE)) 326 switch (op[0]) { 327 328 case '+': 329 i = egetn(p1) + egetn(p2); 330 break; 331 332 case '-': 333 i = egetn(p1) - egetn(p2); 334 break; 335 } 336 xfree(p1); 337 xfree(p2); 338 return (putn(i)); 339 } 340 return (p1); 341 } 342 343 static Char * 344 exp5(Char ***vp, bool ignore) 345 { 346 Char *p1, *p2; 347 int i = 0, l; 348 349 p1 = exp6(vp, ignore); 350 #ifdef EDEBUG 351 etracc("exp5 p1", p1, vp); 352 #endif 353 if (isa(**vp, MULOP)) { 354 Char *op = *(*vp)++; 355 356 p2 = exp5(vp, ignore); 357 #ifdef EDEBUG 358 etracc("exp5 p2", p2, vp); 359 #endif 360 if (!(ignore & IGNORE)) 361 switch (op[0]) { 362 363 case '*': 364 i = egetn(p1) * egetn(p2); 365 break; 366 367 case '/': 368 i = egetn(p2); 369 if (i == 0) 370 stderror(ERR_DIV0); 371 l = egetn(p1); 372 if (l == INT_MIN && i == -1) 373 i = INT_MIN; 374 else 375 i = l / i; 376 break; 377 378 case '%': 379 i = egetn(p2); 380 if (i == 0) 381 stderror(ERR_MOD0); 382 l = egetn(p1); 383 if (l == INT_MIN && i == -1) 384 i = 0; 385 else 386 i = l % i; 387 break; 388 } 389 xfree(p1); 390 xfree(p2); 391 return (putn(i)); 392 } 393 return (p1); 394 } 395 396 static Char * 397 exp6(Char ***vp, bool ignore) 398 { 399 int ccode, i = 0; 400 Char *cp, *dp, *ep; 401 402 if (**vp == 0) 403 stderror(ERR_NAME | ERR_EXPRESSION); 404 if (eq(**vp, STRbang)) { 405 (*vp)++; 406 cp = exp6(vp, ignore); 407 #ifdef EDEBUG 408 etracc("exp6 ! cp", cp, vp); 409 #endif 410 i = egetn(cp); 411 xfree(cp); 412 return (putn(!i)); 413 } 414 if (eq(**vp, STRtilde)) { 415 (*vp)++; 416 cp = exp6(vp, ignore); 417 #ifdef EDEBUG 418 etracc("exp6 ~ cp", cp, vp); 419 #endif 420 i = egetn(cp); 421 xfree(cp); 422 return (putn(~i)); 423 } 424 if (eq(**vp, STRLparen)) { 425 (*vp)++; 426 ccode = exp0(vp, ignore); 427 #ifdef EDEBUG 428 etraci("exp6 () ccode", ccode, vp); 429 #endif 430 if (*vp == 0 || **vp == 0 || ***vp != ')') 431 stderror(ERR_NAME | ERR_EXPRESSION); 432 (*vp)++; 433 return (putn(ccode)); 434 } 435 if (eq(**vp, STRLbrace)) { 436 Char **v; 437 struct command faket; 438 Char *fakecom[2]; 439 440 faket.t_dtyp = NODE_COMMAND; 441 faket.t_dflg = 0; 442 faket.t_dcar = faket.t_dcdr = faket.t_dspr = NULL; 443 faket.t_dcom = fakecom; 444 fakecom[0] = STRfakecom; 445 fakecom[1] = NULL; 446 (*vp)++; 447 v = *vp; 448 for (;;) { 449 if (!**vp) 450 stderror(ERR_NAME | ERR_MISSING, '}'); 451 if (eq(*(*vp)++, STRRbrace)) 452 break; 453 } 454 if (ignore & IGNORE) 455 return (Strsave(STRNULL)); 456 psavejob(); 457 if (pfork(&faket, -1) == 0) { 458 *--(*vp) = 0; 459 evalav(v); 460 exitstat(); 461 } 462 pwait(); 463 prestjob(); 464 #ifdef EDEBUG 465 etraci("exp6 {} status", egetn(value(STRstatus)), vp); 466 #endif 467 return (putn(egetn(value(STRstatus)) == 0)); 468 } 469 if (isa(**vp, ANYOP)) 470 return (Strsave(STRNULL)); 471 cp = *(*vp)++; 472 if (*cp == '-' && any("erwxfdzopls", cp[1])) { 473 struct stat stb; 474 475 if (cp[2] != '\0') 476 stderror(ERR_NAME | ERR_FILEINQ); 477 /* 478 * Detect missing file names by checking for operator in the file name 479 * position. However, if an operator name appears there, we must make 480 * sure that there's no file by that name (e.g., "/") before announcing 481 * an error. Even this check isn't quite right, since it doesn't take 482 * globbing into account. 483 */ 484 if (isa(**vp, ANYOP) && stat(short2str(**vp), &stb)) 485 stderror(ERR_NAME | ERR_FILENAME); 486 487 dp = *(*vp)++; 488 if (ignore & IGNORE) 489 return (Strsave(STRNULL)); 490 ep = globone(dp, G_ERROR); 491 switch (cp[1]) { 492 493 case 'r': 494 i = !access(short2str(ep), R_OK); 495 break; 496 497 case 'w': 498 i = !access(short2str(ep), W_OK); 499 break; 500 501 case 'x': 502 i = !access(short2str(ep), X_OK); 503 break; 504 505 default: 506 if ( 507 #ifdef S_IFLNK 508 cp[1] == 'l' ? lstat(short2str(ep), &stb) : 509 #endif 510 stat(short2str(ep), &stb)) { 511 xfree(ep); 512 return (Strsave(STR0)); 513 } 514 switch (cp[1]) { 515 516 case 'f': 517 i = S_ISREG(stb.st_mode); 518 break; 519 520 case 'd': 521 i = S_ISDIR(stb.st_mode); 522 break; 523 524 case 'p': 525 #ifdef S_ISFIFO 526 i = S_ISFIFO(stb.st_mode); 527 #else 528 i = 0; 529 #endif 530 break; 531 532 case 'l': 533 #ifdef S_ISLNK 534 i = S_ISLNK(stb.st_mode); 535 #else 536 i = 0; 537 #endif 538 break; 539 540 case 's': 541 #ifdef S_ISSOCK 542 i = S_ISSOCK(stb.st_mode); 543 #else 544 i = 0; 545 #endif 546 break; 547 548 case 'z': 549 i = stb.st_size == 0; 550 break; 551 552 case 'e': 553 i = 1; 554 break; 555 556 case 'o': 557 i = stb.st_uid == uid; 558 break; 559 } 560 } 561 #ifdef EDEBUG 562 etraci("exp6 -? i", i, vp); 563 #endif 564 xfree(ep); 565 return (putn(i)); 566 } 567 #ifdef EDEBUG 568 etracc("exp6 default", cp, vp); 569 #endif 570 return (ignore & NOGLOB ? Strsave(cp) : globone(cp, G_ERROR)); 571 } 572 573 static void 574 evalav(Char **v) 575 { 576 struct wordent paraml1; 577 struct wordent *hp = ¶ml1; 578 struct command *t; 579 struct wordent *wdp = hp; 580 581 set(STRstatus, Strsave(STR0)); 582 hp->prev = hp->next = hp; 583 hp->word = STRNULL; 584 while (*v) { 585 struct wordent *new = xcalloc(1, sizeof *wdp); 586 587 new->prev = wdp; 588 new->next = hp; 589 wdp->next = new; 590 wdp = new; 591 wdp->word = Strsave(*v++); 592 } 593 hp->prev = wdp; 594 alias(¶ml1); 595 t = syntax(paraml1.next, ¶ml1, 0); 596 if (seterr) 597 stderror(ERR_OLD); 598 execute(t, -1, NULL, NULL); 599 freelex(¶ml1), freesyn(t); 600 } 601 602 static int 603 isa(Char *cp, int what) 604 { 605 if (cp == 0) 606 return ((what & RESTOP) != 0); 607 if (cp[1] == 0) { 608 if (what & ADDOP && (*cp == '+' || *cp == '-')) 609 return (1); 610 if (what & MULOP && (*cp == '*' || *cp == '/' || *cp == '%')) 611 return (1); 612 if (what & RESTOP && (*cp == '(' || *cp == ')' || *cp == '!' || 613 *cp == '~' || *cp == '^' || *cp == '"')) 614 return (1); 615 } 616 else if (cp[2] == 0) { 617 if (what & RESTOP) { 618 if (cp[0] == '|' && cp[1] == '&') 619 return (1); 620 if (cp[0] == '<' && cp[1] == '<') 621 return (1); 622 if (cp[0] == '>' && cp[1] == '>') 623 return (1); 624 } 625 if (what & EQOP) { 626 if (cp[0] == '=') { 627 if (cp[1] == '=') 628 return (EQEQ); 629 if (cp[1] == '~') 630 return (EQMATCH); 631 } 632 else if (cp[0] == '!') { 633 if (cp[1] == '=') 634 return (NOTEQ); 635 if (cp[1] == '~') 636 return (NOTEQMATCH); 637 } 638 } 639 } 640 if (what & RELOP) { 641 if (*cp == '<') 642 return (LSS); 643 if (*cp == '>') 644 return (GTR); 645 } 646 return (0); 647 } 648 649 static int 650 egetn(Char *cp) 651 { 652 if (*cp && *cp != '-' && !Isdigit(*cp)) 653 stderror(ERR_NAME | ERR_EXPRESSION); 654 return (getn(cp)); 655 } 656 657 /* Phew! */ 658 659 #ifdef EDEBUG 660 static void 661 etraci(char *str, int i, Char ***vp) 662 { 663 (void) fprintf(csherr, "%s=%d\t", str, i); 664 blkpr(csherr, *vp); 665 (void) fprintf(csherr, "\n"); 666 } 667 static void 668 etracc(char *str, Char *cp, Char ***vp) 669 { 670 (void) fprintf(csherr, "%s=%s\t", str, vis_str(cp)); 671 blkpr(csherr, *vp); 672 (void) fprintf(csherr, "\n"); 673 } 674 #endif 675