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