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