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