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