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