|
|
1.1 ! root 1: /* ! 2: * sh/eval.c ! 3: * Bourne shell. ! 4: * Evaluation of parameter substitution, command substitution, ! 5: * blank interpretation, and file name generation. ! 6: */ ! 7: ! 8: #include "sh.h" ! 9: ! 10: char *arcp; /* character position in argument */ ! 11: int argf = 1; /* First argument flag */ ! 12: int argg = 0; /* Glob seek, escape quoted glob chars */ ! 13: int argq = 0; /* Quotation flag, no blanks or glob */ ! 14: ! 15: /* ! 16: * Evaluate a string. ! 17: */ ! 18: eval(cp, f) ! 19: char *cp; ! 20: { ! 21: register int m, c; ! 22: ! 23: strp = strt; ! 24: arcp = cp; ! 25: argf = 1; ! 26: if (f==EHERE) { ! 27: m = MHERE; ! 28: argq = 2; ! 29: } else if (f==EWORD) { ! 30: m = MNQUO; ! 31: argq = 2; ! 32: } else { ! 33: m = MNQUO; ! 34: argq = 0; ! 35: } ! 36: argg = (f==EARGS || f==EPATT); ! 37: ! 38: while ((c = *arcp++) != '\0') { ! 39: if (!class(c, m)) { ! 40: add_char(c); ! 41: continue; ! 42: } ! 43: switch (c) { ! 44: case '"': /* m == MNQUO || m == MDQUO */ ! 45: m = ((argq ^= 1) & 1) ? MDQUO : MNQUO; ! 46: if (m==MDQUO && strcmp(arcp, "$@\"")!=0) ! 47: argf = 0; ! 48: continue; ! 49: case '\'': /* m == MNQUO */ ! 50: while ((c = *arcp++) != '\'') ! 51: add_quoted(c); ! 52: argf = 0; ! 53: continue; ! 54: case '\\': /* m == MDQUO || m == MNQUO */ ! 55: c = *arcp++; ! 56: if (m != MNQUO && ! class(c, m)) { ! 57: add_char('\\'); ! 58: add_char(c); ! 59: } else ! 60: add_quoted(c); ! 61: argf = 0; ! 62: continue; ! 63: case '$': /* m == MNQUO || m = MDQUO */ ! 64: variable(); ! 65: continue; ! 66: case '`': /* m == MNQUO || m = MDQUO */ ! 67: graves(); ! 68: continue; ! 69: default: ! 70: add_char(c); ! 71: continue; ! 72: } ! 73: } ! 74: if (f==EARGS) ! 75: end_arg(); ! 76: else ! 77: *strp++ = '\0'; ! 78: } ! 79: ! 80: /* ! 81: * Read the name of a shell variable and perform the appropriate substitution. ! 82: * Doesn't check for end of buffer. ! 83: */ ! 84: variable() ! 85: { ! 86: VAR *vp; ! 87: int s; ! 88: char *wp, *sav; ! 89: register int c, count, quote; ! 90: register char *cp, *pp; ! 91: ! 92: cp = strp; ! 93: s = '\0'; ! 94: c = *arcp++; ! 95: if (class(c, MSVAR)) { ! 96: special(c); ! 97: return; ! 98: } else if (class(c, MRVAR)) { ! 99: while (class(c, MRVAR)) { ! 100: *cp++ = c; ! 101: c = *arcp++; ! 102: } ! 103: --arcp; ! 104: } else if (c != '{') { ! 105: /* Not a legal variable name, put it back. */ ! 106: add_char('$'); ! 107: add_char(c); ! 108: return; ! 109: } else { ! 110: /* c == '{' */ ! 111: if (index("#?$!-@*0123456789", arcp[0]) != NULL && arcp[1] == '}') { ! 112: /* Allow specials of the form "${?}" etc. */ ! 113: special(arcp[0]); ! 114: arcp += 2; ! 115: return; ! 116: } ! 117: while (index("}-=?+", c = *arcp++) == NULL) ! 118: *cp++ = c; ! 119: if (c != '}') { ! 120: /* ${VAR [-=?+] token} */ ! 121: s = c; ! 122: if (cp[-1] == ':') ! 123: --cp; /* allow e.g. ${VAR:=foo} */ ! 124: *cp++ = '='; ! 125: wp = cp; ! 126: if ((quote = *arcp) == '"' || quote =='\'') ! 127: ++arcp; ! 128: else ! 129: quote = 0; ! 130: for (count = 1; ; ) { ! 131: c = *arcp++; ! 132: if (c == '}' && count-- == 1) ! 133: break; ! 134: else if (c == '$' && quote != '\'') { ! 135: /* ! 136: * steve 6/24/92 ! 137: * This truly sleazy hack handles e.g. "${V1-$V2}", oy. ! 138: * It doesn't do it very well, paying no attention to quotes (for example). ! 139: * The recursive call to variable() should be straightforward but is not, ! 140: * the hacky way this module uses globals like strp requires the save/restore. ! 141: */ ! 142: sav = strp; ! 143: strp = cp; ! 144: variable(); ! 145: cp = strp; ! 146: strp = sav; ! 147: continue; ! 148: } else if (c == '{') ! 149: ++count; ! 150: else if (quote != 0 && c == quote) { ! 151: quote = 0; ! 152: continue; ! 153: } ! 154: *cp++ = c; ! 155: } ! 156: } ! 157: } ! 158: *cp++ = '\0'; ! 159: if (class((c = *strp), MDIGI)) { ! 160: if ((c -= '1') >= sargc) ! 161: pp = NULL; ! 162: else ! 163: pp = sargp[c]; ! 164: } else if (namevar(strp) == 0) { ! 165: eillvar(strp); ! 166: return; ! 167: } else { ! 168: pp = NULL; ! 169: if ((vp=findvar(strp)) != NULL) { ! 170: pp = convvar(vp); ! 171: if (*pp == '\0') ! 172: pp = NULL; /* regard value "" as not set */ ! 173: } ! 174: } ! 175: switch (s) { ! 176: case '\0': ! 177: if (uflag!=0 && pp==NULL) ! 178: enotdef(strp); ! 179: break; ! 180: case '-': ! 181: if (pp == NULL) ! 182: pp = wp; ! 183: break; ! 184: case '=': ! 185: if (pp == NULL) { ! 186: pp = wp; ! 187: if (class(*strp, MDIGI)) { ! 188: printe("Illegal substitution"); ! 189: return; ! 190: } ! 191: setsvar(strp); ! 192: } ! 193: break; ! 194: case '?': ! 195: if (pp != NULL) ! 196: break; ! 197: if (*wp != '\0') ! 198: prints("%s\n", wp); ! 199: else { ! 200: *--wp = '\0'; ! 201: enotdef(strp); ! 202: } ! 203: reset(RUABORT); ! 204: NOTREACHED; ! 205: case '+': ! 206: if (pp != NULL) ! 207: pp = wp; ! 208: break; ! 209: } ! 210: if (pp == NULL) ! 211: return; ! 212: while ((c = *pp++) != '\0') ! 213: add_char(c); ! 214: } ! 215: ! 216: /* ! 217: * Return the value of the special shell variables. ! 218: * No check for end of buffer. ! 219: */ ! 220: special(n) ! 221: register int n; ! 222: { ! 223: register char *sp; ! 224: register int flag; ! 225: ! 226: sp = strp; ! 227: switch (n) { ! 228: case '#': ! 229: n = sargc; ! 230: goto maked; ! 231: case '?': ! 232: n = slret; ! 233: goto maked; ! 234: case '$': ! 235: n = shpid; ! 236: goto maked; ! 237: case '!': ! 238: n = sback; ! 239: goto maked; ! 240: maked: ! 241: sprintf(sp, "%d", n); ! 242: break; ! 243: case '-': ! 244: for (sp = &eflag; sp <= &xflag; sp += 1) ! 245: if (*sp) ! 246: add_char(*sp); ! 247: return; ! 248: case '@': ! 249: case '*': ! 250: flag = (argq == 1 && n == '@'); ! 251: for (n = 0; n < sargc; n++) { ! 252: if (n) { ! 253: argq ^= flag; ! 254: add_char(' '); ! 255: argq ^= flag; ! 256: } ! 257: sp = sargp[n]; ! 258: while (*sp) ! 259: add_char(*sp++); ! 260: } ! 261: return; ! 262: case '0': ! 263: sp = sarg0; ! 264: break; ! 265: default: ! 266: if ((n-='1') >= sargc) { ! 267: if (uflag) ! 268: printe("Unset parameter: %c", n+'1'); ! 269: return; ! 270: } ! 271: sp = sargp[n]; ! 272: break; ! 273: } ! 274: while (*sp) ! 275: add_char(*sp++); ! 276: } ! 277: ! 278: /* ! 279: * Read and evaluate a command found between graves. ! 280: */ ! 281: graves() ! 282: { ! 283: int pipev[2], f, oslret, oargf; ! 284: register FILE *fp; ! 285: register int c; ! 286: register int nnl; ! 287: char *cmdp; ! 288: ! 289: oargf = argf; ! 290: oslret = slret; ! 291: cmdp = arcp; ! 292: while ((c = *arcp++) != '`') ! 293: ; ! 294: if ((f = pipeline(pipev)) == 0) { ! 295: slret = oslret; /* in case grave command uses $? */ ! 296: dup2(pipev[1], 1); ! 297: close(pipev[0]); ! 298: close(pipev[1]); ! 299: *--arcp = '\0'; ! 300: exit(session(SARGS, cmdp)); ! 301: NOTREACHED; ! 302: } ! 303: close(pipev[1]); ! 304: if ((fp=fdopen(pipev[0], "r")) == NULL) { ! 305: close(pipev[0]); ! 306: ecantfdop(); ! 307: return; ! 308: } ! 309: argf = 1; ! 310: nnl = 0; ! 311: while ((c=getc(fp)) != EOF) { ! 312: if ( ! recover(IEVAL)) { ! 313: #ifdef VERBOSE ! 314: if (xflag) prints("Interrupt in eval\n"); ! 315: #endif ! 316: errflag++; ! 317: break; ! 318: } ! 319: if (c=='\n') ! 320: ++nnl; ! 321: else { ! 322: while (nnl) { ! 323: nnl--; ! 324: add_char('\n'); ! 325: } ! 326: add_char(c); ! 327: } ! 328: } ! 329: argf = oargf; ! 330: fclose(fp); ! 331: waitc(f); ! 332: } ! 333: ! 334: /* ! 335: * Add a character to the current argument. ! 336: * If no quotation is set, pick off blanks and globs. ! 337: */ ! 338: add_char(c) ! 339: register int c; ! 340: { ! 341: if (argq==0) { ! 342: if (index(vifs, c) != NULL) { ! 343: end_arg(); ! 344: return; ! 345: } ! 346: if (argg && class(c, MGLOB)) { ! 347: add_arg(c); ! 348: return; ! 349: } ! 350: } ! 351: add_quoted(c); ! 352: } ! 353: ! 354: /* ! 355: * Add a quoted character to the current argument. ! 356: * if argg is set, then glob characters are quoted with a \, ! 357: * as well as \ itself. ! 358: */ ! 359: add_quoted(c) register int c; ! 360: { ! 361: if (argg && (class(c, MGLOB) || c == '\\')) ! 362: add_arg('\\'); ! 363: add_arg(c); ! 364: } ! 365: ! 366: /* ! 367: * Add a character to the current argument ! 368: * and check for end of buffer. ! 369: */ ! 370: add_arg(c) register int c; ! 371: { ! 372: if (strp >= &strt[STRSIZE]) /* Should do more */ ! 373: etoolong(); ! 374: else ! 375: *strp++ = c; ! 376: argf = 0; ! 377: } ! 378: ! 379: /* ! 380: * Terminate the current argument if it is non-empty. ! 381: * If argg is set, then glob the argument to expand globs ! 382: * or to simply remove any quotes. ! 383: */ ! 384: end_arg() ! 385: { ! 386: if (argf != 0) ! 387: return; ! 388: *strp++ = '\0'; ! 389: if (argg) ! 390: glob1(duplstr(strt, 0)); ! 391: else { ! 392: nargv = addargl(nargv, duplstr(strt, 0)); ! 393: nargc += 1; ! 394: } ! 395: strp = strt; ! 396: argf = 1; ! 397: return; ! 398: } ! 399: ! 400: /* ! 401: * Evaluate a here document. ! 402: * Unevaluated document is on u2, put the evaluated document there, too. ! 403: */ ! 404: evalhere(u2) ! 405: { ! 406: register int u1; ! 407: register FILE *f2; ! 408: char buf[128]; ! 409: char *tmp; ! 410: ! 411: tmp = shtmp(); ! 412: if ((u1=creat(tmp, 0666))<0) { ! 413: ecantmake(tmp); ! 414: return -1; ! 415: } ! 416: if ((f2=fdopen(u2, "r"))==NULL) { ! 417: ecantfdop(); ! 418: close(u1); ! 419: close(u2); ! 420: return -1; ! 421: } ! 422: while (fgets(buf, 128, f2) != NULL) { ! 423: eval(buf, EHERE); ! 424: write(u1, strt, strp-1-strt); ! 425: } ! 426: close(u1); ! 427: fclose(f2); ! 428: if ((u2 = open(tmp, 0))<0) { ! 429: ecantopen(tmp); ! 430: u2 = -1; ! 431: } ! 432: unlink(tmp); ! 433: return u2; ! 434: } ! 435: ! 436: /* end of sh/eval.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.