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