|
|
1.1 ! root 1: static char *sccsid = "@(#)sh.dol.c 4.1 10/9/80"; ! 2: ! 3: #include "sh.h" ! 4: ! 5: /* ! 6: * C shell ! 7: */ ! 8: ! 9: /* ! 10: * These routines perform variable substitution and quoting via ' and ". ! 11: * To this point these constructs have been preserved in the divided ! 12: * input words. Here we expand variables and turn quoting via ' and " into ! 13: * QUOTE bits on characters (which prevent further interpretation). ! 14: * If the `:q' modifier was applied during history expansion, then ! 15: * some QUOTEing may have occurred already, so we dont "scan(,&trim)" here. ! 16: */ ! 17: ! 18: int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */ ! 19: char *Dcp, **Dvp; /* Input vector for Dreadc */ ! 20: ! 21: #define DEOF -1 ! 22: ! 23: #define unDgetC(c) Dpeekc = c ! 24: ! 25: char *QUOTES = "\\'`\""; ! 26: ! 27: /* ! 28: * The following variables give the information about the current ! 29: * $ expansion, recording the current word position, the remaining ! 30: * words within this expansion, the count of remaining words, and the ! 31: * information about any : modifier which is being applied. ! 32: */ ! 33: char *dolp; /* Remaining chars from this word */ ! 34: char **dolnxt; /* Further words */ ! 35: int dolcnt; /* Count of further words */ ! 36: char dolmod; /* : modifier character */ ! 37: int dolmcnt; /* :gx -> 10000, else 1 */ ! 38: ! 39: int Dtest(); /* Test for \ " ` or ' */ ! 40: ! 41: /* ! 42: * Fix up the $ expansions and quotations in the ! 43: * argument list to command t. ! 44: */ ! 45: Dfix(t) ! 46: register struct command *t; ! 47: { ! 48: ! 49: if (noexec) ! 50: return; ! 51: gflag = 0, rscan(t->t_dcom, Dtest); ! 52: if (gflag == 0) ! 53: return; ! 54: Dfix2(t->t_dcom); ! 55: blkfree(t->t_dcom), t->t_dcom = gargv, gargv = 0; ! 56: } ! 57: ! 58: /* ! 59: * $ substitute one word, for i/o redirection ! 60: */ ! 61: char * ! 62: Dfix1(cp) ! 63: register char *cp; ! 64: { ! 65: char *Dv[2]; ! 66: ! 67: if (noexec) ! 68: return (0); ! 69: Dv[0] = cp; Dv[1] = NOSTR; ! 70: Dfix2(Dv); ! 71: if (gargc != 1) { ! 72: setname(cp); ! 73: bferr("Ambiguous"); ! 74: } ! 75: cp = savestr(gargv[0]); ! 76: blkfree(gargv), gargv = 0; ! 77: return (cp); ! 78: } ! 79: ! 80: /* ! 81: * Subroutine to do actual fixing after state initialization. ! 82: */ ! 83: Dfix2(v) ! 84: char **v; ! 85: { ! 86: char *agargv[GAVSIZ]; ! 87: ! 88: ginit(agargv); /* Initialize glob's area pointers */ ! 89: Dvp = v; Dcp = ""; /* Setup input vector for Dreadc */ ! 90: unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ ! 91: dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ ! 92: while (Dword()) ! 93: continue; ! 94: gargv = copyblk(gargv); ! 95: } ! 96: ! 97: /* ! 98: * Get a word. This routine is analogous to the routine ! 99: * word() in sh.lex.c for the main lexical input. One difference ! 100: * here is that we don't get a newline to terminate our expansion. ! 101: * Rather, DgetC will return a DEOF when we hit the end-of-input. ! 102: */ ! 103: Dword() ! 104: { ! 105: register int c, c1; ! 106: char wbuf[BUFSIZ]; ! 107: register char *wp = wbuf; ! 108: register int i = BUFSIZ - 4; ! 109: register bool dolflg; ! 110: bool sofar = 0; ! 111: ! 112: loop: ! 113: c = DgetC(DODOL); ! 114: switch (c) { ! 115: ! 116: case DEOF: ! 117: deof: ! 118: if (sofar == 0) ! 119: return (0); ! 120: /* finish this word and catch the code above the next time */ ! 121: unDredc(c); ! 122: /* fall into ... */ ! 123: ! 124: case '\n': ! 125: *wp = 0; ! 126: goto ret; ! 127: ! 128: case ' ': ! 129: case '\t': ! 130: goto loop; ! 131: ! 132: case '`': ! 133: /* We preserve ` quotations which are done yet later */ ! 134: *wp++ = c, --i; ! 135: case '\'': ! 136: case '"': ! 137: /* ! 138: * Note that DgetC never returns a QUOTES character ! 139: * from an expansion, so only true input quotes will ! 140: * get us here or out. ! 141: */ ! 142: c1 = c; ! 143: dolflg = c1 == '"' ? DODOL : 0; ! 144: for (;;) { ! 145: c = DgetC(dolflg); ! 146: if (c == c1) ! 147: break; ! 148: if (c == '\n' || c == DEOF) ! 149: error("Unmatched %c", c1); ! 150: if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE)) ! 151: --wp, ++i; ! 152: if (--i <= 0) ! 153: goto toochars; ! 154: switch (c1) { ! 155: ! 156: case '"': ! 157: /* ! 158: * Leave any `s alone for later. ! 159: * Other chars are all quoted, thus `...` ! 160: * can tell it was within "...". ! 161: */ ! 162: *wp++ = c == '`' ? '`' : c | QUOTE; ! 163: break; ! 164: ! 165: case '\'': ! 166: /* Prevent all further interpretation */ ! 167: *wp++ = c | QUOTE; ! 168: break; ! 169: ! 170: case '`': ! 171: /* Leave all text alone for later */ ! 172: *wp++ = c; ! 173: break; ! 174: } ! 175: } ! 176: if (c1 == '`') ! 177: *wp++ = '`', --i; ! 178: goto pack; /* continue the word */ ! 179: ! 180: case '\\': ! 181: c = DgetC(0); /* No $ subst! */ ! 182: if (c == '\n' || c == DEOF) ! 183: goto loop; ! 184: c |= QUOTE; ! 185: break; ! 186: } ! 187: unDgetC(c); ! 188: pack: ! 189: sofar = 1; ! 190: /* pack up more characters in this word */ ! 191: for (;;) { ! 192: c = DgetC(DODOL); ! 193: if (c == '\\') { ! 194: c = DgetC(0); ! 195: if (c == DEOF) ! 196: goto deof; ! 197: if (c == '\n') ! 198: c = ' '; ! 199: else ! 200: c |= QUOTE; ! 201: } ! 202: if (c == DEOF) ! 203: goto deof; ! 204: if (any(c, " '`\"\t\n")) { ! 205: unDgetC(c); ! 206: if (any(c, QUOTES)) ! 207: goto loop; ! 208: *wp++ = 0; ! 209: goto ret; ! 210: } ! 211: if (--i <= 0) ! 212: toochars: ! 213: error("Word too long"); ! 214: *wp++ = c; ! 215: } ! 216: ret: ! 217: Gcat("", wbuf); ! 218: return (1); ! 219: } ! 220: ! 221: /* ! 222: * Get a character, performing $ substitution unless flag is 0. ! 223: * Any QUOTES character which is returned from a $ expansion is ! 224: * QUOTEd so that it will not be recognized above. ! 225: */ ! 226: DgetC(flag) ! 227: register int flag; ! 228: { ! 229: register int c; ! 230: ! 231: top: ! 232: if (c = Dpeekc) { ! 233: Dpeekc = 0; ! 234: return (c); ! 235: } ! 236: if (lap) { ! 237: c = *lap++ & (QUOTE|TRIM); ! 238: if (c == 0) { ! 239: lap = 0; ! 240: goto top; ! 241: } ! 242: quotspec: ! 243: if (any(c, QUOTES)) ! 244: return (c | QUOTE); ! 245: return (c); ! 246: } ! 247: if (dolp) { ! 248: if (c = *dolp++ & (QUOTE|TRIM)) ! 249: goto quotspec; ! 250: if (dolcnt > 0) { ! 251: setDolp(*dolnxt++); ! 252: --dolcnt; ! 253: return (' '); ! 254: } ! 255: dolp = 0; ! 256: } ! 257: if (dolcnt > 0) { ! 258: setDolp(*dolnxt++); ! 259: --dolcnt; ! 260: goto top; ! 261: } ! 262: c = Dredc(); ! 263: if (c == '$' && flag) { ! 264: Dgetdol(); ! 265: goto top; ! 266: } ! 267: return (c); ! 268: } ! 269: ! 270: char *nulvec[] = { 0 }; ! 271: struct varent nulargv = { nulvec, "argv", 0 }; ! 272: ! 273: /* ! 274: * Handle the multitudinous $ expansion forms. ! 275: * Ugh. ! 276: */ ! 277: Dgetdol() ! 278: { ! 279: register char *np; ! 280: register struct varent *vp; ! 281: char name[20]; ! 282: int c, sc; ! 283: int subscr = 0, lwb = 1, upb = 0; ! 284: bool dimen = 0, isset = 0; ! 285: char wbuf[BUFSIZ]; ! 286: ! 287: dolmod = dolmcnt = 0; ! 288: c = sc = DgetC(0); ! 289: if (c == '{') ! 290: c = DgetC(0); /* sc is { to take } later */ ! 291: if ((c & TRIM) == '#') ! 292: dimen++, c = DgetC(0); /* $# takes dimension */ ! 293: else if (c == '?') ! 294: isset++, c = DgetC(0); /* $? tests existence */ ! 295: switch (c) { ! 296: ! 297: case '$': ! 298: if (dimen || isset) ! 299: goto syntax; /* No $?$, $#$ */ ! 300: setDolp(doldol); ! 301: goto eatbrac; ! 302: ! 303: case '<'|QUOTE: ! 304: if (dimen || isset) ! 305: goto syntax; /* No $?<, $#< */ ! 306: for (np = wbuf; read(OLDSTD, np, 1) == 1; np++) { ! 307: if (np >= &wbuf[BUFSIZ-1]) ! 308: error("$< line too long"); ! 309: if (*np <= 0 || *np == '\n') ! 310: break; ! 311: } ! 312: *np = 0; ! 313: /* ! 314: * KLUDGE: dolmod is set here because it will ! 315: * cause setDolp to call domod and thus to copy wbuf. ! 316: * Otherwise setDolp would use it directly. If we saved ! 317: * it ourselves, no one would know when to free it. ! 318: * The actual function of the 'q' causes filename ! 319: * expansion not to be done on the interpolated value. ! 320: */ ! 321: dolmod = 'q'; ! 322: dolmcnt = 10000; ! 323: setDolp(wbuf); ! 324: goto eatbrac; ! 325: ! 326: case DEOF: ! 327: case '\n': ! 328: goto syntax; ! 329: ! 330: case '*': ! 331: strcpy(name, "argv"); ! 332: vp = adrof("argv"); ! 333: subscr = -1; /* Prevent eating [...] */ ! 334: break; ! 335: ! 336: default: ! 337: np = name; ! 338: if (digit(c)) { ! 339: if (dimen) ! 340: goto syntax; /* No $#1, e.g. */ ! 341: subscr = 0; ! 342: do { ! 343: subscr = subscr * 10 + c - '0'; ! 344: c = DgetC(0); ! 345: } while (digit(c)); ! 346: unDredc(c); ! 347: if (subscr < 0) ! 348: goto oob; ! 349: if (subscr == 0) { ! 350: if (isset) { ! 351: dolp = file ? "1" : "0"; ! 352: goto eatbrac; ! 353: } ! 354: if (file == 0) ! 355: error("No file for $0"); ! 356: setDolp(file); ! 357: goto eatbrac; ! 358: } ! 359: if (isset) ! 360: goto syntax; ! 361: vp = adrof("argv"); ! 362: if (vp == 0) { ! 363: vp = &nulargv; ! 364: goto eatmod; ! 365: } ! 366: break; ! 367: } ! 368: if (!alnum(c)) ! 369: goto syntax; ! 370: for (;;) { ! 371: *np++ = c; ! 372: c = DgetC(0); ! 373: if (!alnum(c)) ! 374: break; ! 375: if (np >= &name[sizeof name - 2]) ! 376: syntax: ! 377: error("Variable syntax"); ! 378: } ! 379: *np++ = 0; ! 380: unDredc(c); ! 381: vp = adrof(name); ! 382: } ! 383: if (isset) { ! 384: dolp = (vp || getenv(name)) ? "1" : "0"; ! 385: goto eatbrac; ! 386: } ! 387: if (vp == 0) { ! 388: np = getenv(name); ! 389: if (np) { ! 390: addla(np); ! 391: return; ! 392: } ! 393: udvar(name); ! 394: /*NOTREACHED*/ ! 395: } ! 396: c = DgetC(0); ! 397: upb = blklen(vp->vec); ! 398: if (dimen == 0 && subscr == 0 && c == '[') { ! 399: np = name; ! 400: for (;;) { ! 401: c = DgetC(DODOL); /* Allow $ expand within [ ] */ ! 402: if (c == ']') ! 403: break; ! 404: if (c == '\n' || c == DEOF) ! 405: goto syntax; ! 406: if (np >= &name[sizeof name - 2]) ! 407: goto syntax; ! 408: *np++ = c; ! 409: } ! 410: *np = 0, np = name; ! 411: if (dolp || dolcnt) /* $ exp must end before ] */ ! 412: goto syntax; ! 413: if (!*np) ! 414: goto syntax; ! 415: if (digit(*np)) { ! 416: register int i = 0; ! 417: ! 418: while (digit(*np)) ! 419: i = i * 10 + *np++ - '0'; ! 420: if ((i < 0 || i > upb) && !any(*np, "-*")) { ! 421: oob: ! 422: setname(vp->name); ! 423: error("Subscript out of range"); ! 424: } ! 425: lwb = i; ! 426: if (!*np) ! 427: upb = lwb, np = "*"; ! 428: } ! 429: if (*np == '*') ! 430: np++; ! 431: else if (*np != '-') ! 432: goto syntax; ! 433: else { ! 434: register int i = upb; ! 435: ! 436: np++; ! 437: if (digit(*np)) { ! 438: i = 0; ! 439: while (digit(*np)) ! 440: i = i * 10 + *np++ - '0'; ! 441: if (i < 0 || i > upb) ! 442: goto oob; ! 443: } ! 444: if (i < lwb) ! 445: upb = lwb - 1; ! 446: else ! 447: upb = i; ! 448: } ! 449: if (lwb == 0) { ! 450: if (upb != 0) ! 451: goto oob; ! 452: upb = -1; ! 453: } ! 454: if (*np) ! 455: goto syntax; ! 456: } else { ! 457: if (subscr > 0) ! 458: if (subscr > upb) ! 459: lwb = 1, upb = 0; ! 460: else ! 461: lwb = upb = subscr; ! 462: unDredc(c); ! 463: } ! 464: if (dimen) { ! 465: char *cp = putn(upb - lwb + 1); ! 466: ! 467: addla(cp); ! 468: xfree(cp); ! 469: } else { ! 470: eatmod: ! 471: c = DgetC(0); ! 472: if (c == ':') { ! 473: c = DgetC(0), dolmcnt = 1; ! 474: if (c == 'g') ! 475: c = DgetC(0), dolmcnt = 10000; ! 476: if (!any(c, "htrqxe")) ! 477: error("Bad : mod in $"); ! 478: dolmod = c; ! 479: if (c == 'q') ! 480: dolmcnt = 10000; ! 481: } else ! 482: unDredc(c); ! 483: dolnxt = &vp->vec[lwb - 1]; ! 484: dolcnt = upb - lwb + 1; ! 485: } ! 486: eatbrac: ! 487: if (sc == '{') { ! 488: c = Dredc(); ! 489: if (c != '}') ! 490: goto syntax; ! 491: } ! 492: } ! 493: ! 494: setDolp(cp) ! 495: register char *cp; ! 496: { ! 497: register char *dp; ! 498: ! 499: if (dolmod == 0 || dolmcnt == 0) { ! 500: dolp = cp; ! 501: return; ! 502: } ! 503: dp = domod(cp, dolmod); ! 504: if (dp) { ! 505: dolmcnt--; ! 506: addla(dp); ! 507: xfree(dp); ! 508: } else ! 509: addla(cp); ! 510: dolp = ""; ! 511: } ! 512: ! 513: unDredc(c) ! 514: int c; ! 515: { ! 516: ! 517: Dpeekrd = c; ! 518: } ! 519: ! 520: Dredc() ! 521: { ! 522: register int c; ! 523: ! 524: if (c = Dpeekrd) { ! 525: Dpeekrd = 0; ! 526: return (c); ! 527: } ! 528: if (Dcp && (c = *Dcp++)) ! 529: return (c&(QUOTE|TRIM)); ! 530: if (*Dvp == 0) { ! 531: Dcp = 0; ! 532: return (DEOF); ! 533: } ! 534: Dcp = *Dvp++; ! 535: return (' '); ! 536: } ! 537: ! 538: Dtest(c) ! 539: register int c; ! 540: { ! 541: ! 542: /* Note that c isn't trimmed thus !...:q's aren't lost */ ! 543: if (any(c, "$\\'`\"")) ! 544: gflag = 1; ! 545: } ! 546: ! 547: Dtestq(c) ! 548: register int c; ! 549: { ! 550: ! 551: if (any(c, "\\'`\"")) ! 552: gflag = 1; ! 553: } ! 554: ! 555: /* ! 556: * Form a shell temporary file (in unit 0) from the words ! 557: * of the shell input up to a line the same as "term". ! 558: * Unit 0 should have been closed before this call. ! 559: */ ! 560: heredoc(term) ! 561: char *term; ! 562: { ! 563: register int c; ! 564: char *Dv[2]; ! 565: char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; ! 566: int ocnt, lcnt, mcnt; ! 567: register char *lbp, *obp, *mbp; ! 568: char **vp; ! 569: bool quoted; ! 570: ! 571: if (creat(shtemp, 0600) < 0) ! 572: Perror(shtemp); ! 573: close(0); ! 574: if (open(shtemp, 2) < 0) { ! 575: int oerrno = errno; ! 576: ! 577: unlink(shtemp); ! 578: errno = oerrno; ! 579: Perror(shtemp); ! 580: } ! 581: unlink(shtemp); /* 0 0 inode! */ ! 582: Dv[0] = term; Dv[1] = NOSTR; gflag = 0; ! 583: scan(Dv, trim); rscan(Dv, Dtestq); quoted = gflag; ! 584: ocnt = BUFSIZ; obp = obuf; ! 585: for (;;) { ! 586: /* ! 587: * Read up a line ! 588: */ ! 589: lbp = lbuf; lcnt = BUFSIZ - 4; ! 590: for (;;) { ! 591: c = readc(1); /* 1 -> Want EOF returns */ ! 592: if (c < 0) { ! 593: setname(term); ! 594: bferr("<< terminator not found"); ! 595: } ! 596: if (c == '\n') ! 597: break; ! 598: if (c &= TRIM) { ! 599: *lbp++ = c; ! 600: if (--lcnt < 0) { ! 601: setname("<<"); ! 602: error("Line overflow"); ! 603: } ! 604: } ! 605: } ! 606: *lbp = 0; ! 607: ! 608: /* ! 609: * Compare to terminator -- before expansion ! 610: */ ! 611: if (eq(lbuf, term)) { ! 612: write(0, obuf, BUFSIZ - ocnt); ! 613: lseek(0, 0l, 0); ! 614: return; ! 615: } ! 616: ! 617: /* ! 618: * If term was quoted or -n just pass it on ! 619: */ ! 620: if (quoted || noexec) { ! 621: *lbp++ = '\n'; *lbp = 0; ! 622: for (lbp = lbuf; c = *lbp++;) { ! 623: *obp++ = c; ! 624: if (--ocnt == 0) { ! 625: write(0, obuf, BUFSIZ); ! 626: obp = obuf; ocnt = BUFSIZ; ! 627: } ! 628: } ! 629: continue; ! 630: } ! 631: ! 632: /* ! 633: * Term wasn't quoted so variable and then command ! 634: * expand the input line ! 635: */ ! 636: Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; ! 637: for (;;) { ! 638: c = DgetC(DODOL); ! 639: if (c == DEOF) ! 640: break; ! 641: if ((c &= TRIM) == 0) ! 642: continue; ! 643: /* \ quotes \ $ ` here */ ! 644: if (c =='\\') { ! 645: c = DgetC(0); ! 646: if (!any(c, "$\\`")) ! 647: unDgetC(c | QUOTE), c = '\\'; ! 648: else ! 649: c |= QUOTE; ! 650: } ! 651: *mbp++ = c; ! 652: if (--mcnt == 0) { ! 653: setname("<<"); ! 654: bferr("Line overflow"); ! 655: } ! 656: } ! 657: *mbp++ = 0; ! 658: ! 659: /* ! 660: * If any ` in line do command substitution ! 661: */ ! 662: mbp = mbuf; ! 663: if (any('`', mbp)) { ! 664: /* ! 665: * 1 arg to dobackp causes substitution to be literal. ! 666: * Words are broken only at newlines so that all blanks ! 667: * and tabs are preserved. Blank lines (null words) ! 668: * are not discarded. ! 669: */ ! 670: vp = dobackp(mbuf, 1); ! 671: } else ! 672: /* Setup trivial vector similar to return of dobackp */ ! 673: Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv; ! 674: ! 675: /* ! 676: * Resurrect the words from the command substitution ! 677: * each separated by a newline. Note that the last ! 678: * newline of a command substitution will have been ! 679: * discarded, but we put a newline after the last word ! 680: * because this represents the newline after the last ! 681: * input line! ! 682: */ ! 683: for (; *vp; vp++) { ! 684: for (mbp = *vp; *mbp; mbp++) { ! 685: *obp++ = *mbp & TRIM; ! 686: if (--ocnt == 0) { ! 687: write(0, obuf, BUFSIZ); ! 688: obp = obuf; ocnt = BUFSIZ; ! 689: } ! 690: } ! 691: *obp++ = '\n'; ! 692: if (--ocnt == 0) { ! 693: write(0, obuf, BUFSIZ); ! 694: obp = obuf; ocnt = BUFSIZ; ! 695: } ! 696: } ! 697: if (pargv) ! 698: blkfree(pargv), pargv = 0; ! 699: } ! 700: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.