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