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