|
|
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 character of 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: /* ! 47: * POSIX.2 says: If there are no positional ! 48: * parameters, the expansion of $@ shall generate ! 49: * zero fields, even when double-quoted. ! 50: */ ! 51: #if 1 ! 52: if (m == MDQUO && strcmp (arcp, "\"") == 0) ! 53: argf = 0; ! 54: #else ! 55: if (m==MDQUO && strcmp(arcp, "$@\"")!=0) ! 56: argf = 0; ! 57: #endif ! 58: continue; ! 59: case '\'': /* m == MNQUO */ ! 60: while ((c = *arcp++) != '\'') ! 61: add_quoted(c); ! 62: argf = 0; ! 63: continue; ! 64: case '\\': /* m == MDQUO || m == MNQUO */ ! 65: c = *arcp++; ! 66: if (m != MNQUO && ! class(c, m)) { ! 67: add_char('\\'); ! 68: add_char(c); ! 69: } else ! 70: add_quoted(c); ! 71: argf = 0; ! 72: continue; ! 73: case '$': /* m == MNQUO || m = MDQUO */ ! 74: variable(); ! 75: continue; ! 76: case '`': /* m == MNQUO || m = MDQUO */ ! 77: graves (m); ! 78: continue; ! 79: default: ! 80: add_char(c); ! 81: continue; ! 82: } ! 83: } ! 84: if (f==EARGS) ! 85: end_arg(); ! 86: else ! 87: *strp++ = '\0'; ! 88: } ! 89: ! 90: /* ! 91: * Read the name of a shell variable and perform the appropriate substitution. ! 92: * Doesn't check for end of buffer. ! 93: */ ! 94: variable() ! 95: { ! 96: VAR *vp; ! 97: int s; ! 98: char *wp, *sav; ! 99: register int c, count, quote; ! 100: register char *cp, *pp; ! 101: ! 102: cp = strp; ! 103: s = '\0'; ! 104: c = *arcp++; ! 105: if (class(c, MSVAR)) { ! 106: special(c); ! 107: return; ! 108: } else if (class(c, MRVAR)) { ! 109: while (class(c, MRVAR)) { ! 110: *cp++ = c; ! 111: c = *arcp++; ! 112: } ! 113: --arcp; ! 114: } else if (c != '{') { ! 115: /* Not a legal variable name, put it back. */ ! 116: add_char('$'); ! 117: add_char(c); ! 118: return; ! 119: } else { ! 120: /* c == '{' */ ! 121: if (index("#?$!-@*0123456789", arcp[0]) != NULL && arcp[1] == '}') { ! 122: /* Allow specials of the form "${?}" etc. */ ! 123: special(arcp[0]); ! 124: arcp += 2; ! 125: return; ! 126: } ! 127: while (index("}-=?+", c = *arcp++) == NULL) ! 128: *cp++ = c; ! 129: if (c != '}') { ! 130: /* ${VAR [-=?+] token} */ ! 131: s = c; ! 132: if (cp[-1] == ':') ! 133: --cp; /* allow e.g. ${VAR:=foo} */ ! 134: *cp++ = '='; ! 135: wp = cp; ! 136: if ((quote = *arcp) == '"' || quote =='\'') ! 137: ++arcp; ! 138: else ! 139: quote = 0; ! 140: for (count = 1; ; ) { ! 141: c = *arcp++; ! 142: if (c == '}' && count-- == 1) ! 143: break; ! 144: else if (c == '$' && quote != '\'') { ! 145: /* ! 146: * steve 6/24/92 ! 147: * This truly sleazy hack handles e.g. "${V1-$V2}", oy. ! 148: * It doesn't do it very well, paying no attention to quotes (for example). ! 149: * The recursive call to variable() should be straightforward but is not, ! 150: * the hacky way this module uses globals like strp requires the save/restore. ! 151: */ ! 152: sav = strp; ! 153: strp = cp; ! 154: variable(); ! 155: cp = strp; ! 156: strp = sav; ! 157: continue; ! 158: } else if (c == '{') ! 159: ++count; ! 160: else if (quote != 0 && c == quote) { ! 161: quote = 0; ! 162: continue; ! 163: } ! 164: *cp++ = c; ! 165: } ! 166: } ! 167: } ! 168: *cp++ = '\0'; ! 169: if (class((c = *strp), MDIGI)) { ! 170: if ((c -= '1') >= sargc) ! 171: pp = NULL; ! 172: else ! 173: pp = sargp[c]; ! 174: } else if (namevar(strp) == 0) { ! 175: eillvar(strp); ! 176: return; ! 177: } else { ! 178: pp = NULL; ! 179: if ((vp=findvar(strp)) != NULL) { ! 180: pp = convvar(vp); ! 181: if (*pp == '\0') ! 182: pp = NULL; /* regard value "" as not set */ ! 183: } ! 184: } ! 185: switch (s) { ! 186: case '\0': ! 187: if (uflag!=0 && pp==NULL) ! 188: enotdef(strp); ! 189: break; ! 190: case '-': ! 191: if (pp == NULL) ! 192: pp = wp; ! 193: break; ! 194: case '=': ! 195: if (pp == NULL) { ! 196: pp = wp; ! 197: if (class(*strp, MDIGI)) { ! 198: printe("Illegal substitution"); ! 199: return; ! 200: } ! 201: setsvar(strp); ! 202: } ! 203: break; ! 204: case '?': ! 205: if (pp != NULL) ! 206: break; ! 207: if (*wp != '\0') ! 208: prints("%s\n", wp); ! 209: else { ! 210: *--wp = '\0'; ! 211: enotdef(strp); ! 212: } ! 213: reset(RUABORT); ! 214: NOTREACHED; ! 215: case '+': ! 216: if (pp != NULL) ! 217: pp = wp; ! 218: break; ! 219: } ! 220: if (pp != NULL) ! 221: while ((c = *pp++) != '\0') ! 222: add_char(c); ! 223: argf &= ~ argq; ! 224: } ! 225: ! 226: /* ! 227: * Return the value of the special shell variables. ! 228: * No check for end of buffer. ! 229: */ ! 230: special(n) ! 231: register int n; ! 232: { ! 233: register char *sp; ! 234: register int flag; ! 235: ! 236: sp = strp; ! 237: switch (n) { ! 238: case '#': ! 239: n = sargc; ! 240: goto maked; ! 241: case '?': ! 242: n = slret; ! 243: goto maked; ! 244: case '$': ! 245: n = shpid; ! 246: goto maked; ! 247: case '!': ! 248: n = sback; ! 249: goto maked; ! 250: maked: ! 251: sprintf(sp, "%d", n); ! 252: break; ! 253: case '-': ! 254: for (sp = &eflag; sp <= &xflag; sp += 1) ! 255: if (*sp) ! 256: add_char(*sp); ! 257: argf &= ~ argq; ! 258: return; ! 259: case '@': ! 260: case '*': ! 261: flag = (argq == 1 && n == '@'); ! 262: for (n = 0; n < sargc; n++) { ! 263: if (n) { ! 264: argq ^= flag; ! 265: add_char(' '); ! 266: argq ^= flag; ! 267: } ! 268: sp = sargp[n]; ! 269: while (*sp) ! 270: add_char(*sp++); ! 271: /* ! 272: * Make sure that arguments like "" get handled ! 273: * properly when expanding "$@" ! 274: */ ! 275: if (flag) ! 276: argf &= ~ argq; ! 277: } ! 278: return; ! 279: case '0': ! 280: sp = sarg0; ! 281: break; ! 282: default: ! 283: if ((n-='1') >= sargc) { ! 284: if (uflag) ! 285: printe("Unset parameter: %c", n+'1'); ! 286: argf &= ~ argq; ! 287: return; ! 288: } ! 289: sp = sargp[n]; ! 290: break; ! 291: } ! 292: while (*sp) ! 293: add_char(*sp++); ! 294: argf &= ~ argq; ! 295: } ! 296: ! 297: /* ! 298: * Read and evaluate a command found between graves. ! 299: * ! 300: * NB : The code below relating to saving/restoring the global variable ! 301: * "argf" has been removed; it was not clear what the intended effect was, ! 302: * but it caused expansions into single words (eg, "echo `pwd`") to vanish ! 303: * and caused the word-break algorithm to perform in an unintuitive (and ! 304: * incorrect according to POSIX.2) manner. ! 305: * ! 306: * NB : Backslash-quoting inside graves was not supported properly before, ! 307: * and I'm not sure that I've got it right. The idea is that before passing ! 308: * things off to session (), we process the appropriate backslash-escapes. ! 309: * What consists of an "appropriate" escape depends on whether the graves ! 310: * appeared within a double-quoted section (in which case we recognise the ! 311: * specials appropriate to that) or not (in which case we recognised the ! 312: * characters $`\ as specials. We also process '$'-expansions in graves now, ! 313: * but not globs. ! 314: * ! 315: * Since we are removing some bashslashes here, we should be building into ! 316: * a temporary buffer. We append our work onto the global "strp" buffer and ! 317: * cut it back once we have finished. ! 318: */ ! 319: graves (quotemode) ! 320: int quotemode; ! 321: { ! 322: int pipev[2], f, oslret; ! 323: int oargf; ! 324: char * ostrp; ! 325: register FILE *fp; ! 326: register int c; ! 327: register int nnl; ! 328: char *cmdp; ! 329: ! 330: oargf = argf; ! 331: ostrp = strp; ! 332: oslret = slret; ! 333: ! 334: cmdp = strp; ! 335: while ((c = *arcp++) != '`') { ! 336: if (c != '\\') { ! 337: add_arg (c); ! 338: continue; ! 339: } ! 340: c = * arcp ++; ! 341: ! 342: if (! (quotemode == MDQUO && class (c, MDQUO)) && ! 343: (c != '$' && c != '\\' && c != '`')) ! 344: add_arg ('\\'); ! 345: add_arg (c); ! 346: } ! 347: * strp = 0; ! 348: ! 349: if ((f = pipeline(pipev)) == 0) { ! 350: slret = oslret; /* in case grave command uses $? */ ! 351: dup2(pipev[1], 1); ! 352: close(pipev[0]); ! 353: close(pipev[1]); ! 354: exit(session(SARGS, cmdp)); ! 355: NOTREACHED; ! 356: } ! 357: ! 358: close(pipev[1]); ! 359: if ((fp=fdopen(pipev[0], "r")) == NULL) { ! 360: close(pipev[0]); ! 361: ecantfdop(); ! 362: return; ! 363: } ! 364: strp = ostrp; ! 365: argf = oargf; ! 366: nnl = 0; ! 367: while ((c=getc(fp)) != EOF) { ! 368: if ( ! recover(IEVAL)) { ! 369: #ifdef VERBOSE ! 370: if (xflag) prints("Interrupt in eval\n"); ! 371: #endif ! 372: errflag++; ! 373: break; ! 374: } ! 375: if (c=='\n') ! 376: ++nnl; ! 377: else { ! 378: while (nnl) { ! 379: nnl--; ! 380: add_char('\n'); ! 381: } ! 382: add_char(c); ! 383: } ! 384: } ! 385: ! 386: /* ! 387: * If we expanded to something, we have an arg. If we are in double- ! 388: * quotes, we have an arg. Otherwise, we have an arg if we had an arg ! 389: * before. ! 390: */ ! 391: ! 392: if (argf) ! 393: argf = argq ? 0 : oargf; ! 394: ! 395: fclose(fp); ! 396: waitc(f); ! 397: } ! 398: ! 399: /* ! 400: * Add a character to the current argument. ! 401: * If no quotation is set, pick off blanks and globs. ! 402: */ ! 403: add_char(c) ! 404: register int c; ! 405: { ! 406: if (argq==0) { ! 407: if (index(vifs, c) != NULL) { ! 408: end_arg(); ! 409: return; ! 410: } ! 411: if (argg && class(c, MGLOB)) { ! 412: add_arg(c); ! 413: return; ! 414: } ! 415: } ! 416: add_quoted(c); ! 417: } ! 418: ! 419: /* ! 420: * Add a quoted character to the current argument. ! 421: * if argg is set, then glob characters are quoted with a \, ! 422: * as well as \ itself. ! 423: */ ! 424: add_quoted(c) register int c; ! 425: { ! 426: if (argg && (class(c, MGLOB) || c == '\\')) ! 427: add_arg('\\'); ! 428: add_arg(c); ! 429: } ! 430: ! 431: /* ! 432: * Add a character to the current argument ! 433: * and check for end of buffer. ! 434: */ ! 435: add_arg(c) register int c; ! 436: { ! 437: if (strp >= &strt[STRSIZE]) /* Should do more */ ! 438: etoolong(); ! 439: else ! 440: *strp++ = c; ! 441: argf = 0; ! 442: } ! 443: ! 444: /* ! 445: * Terminate the current argument if it is non-empty. ! 446: * If argg is set, then glob the argument to expand globs ! 447: * or to simply remove any quotes. ! 448: */ ! 449: end_arg() ! 450: { ! 451: if (argf != 0) ! 452: return; ! 453: *strp++ = '\0'; ! 454: if (argg) ! 455: glob1(duplstr(strt, 0)); ! 456: else { ! 457: nargv = addargl(nargv, duplstr(strt, 0)); ! 458: nargc += 1; ! 459: } ! 460: strp = strt; ! 461: argf = 1; ! 462: return; ! 463: } ! 464: ! 465: /* ! 466: * Evaluate a here document. ! 467: * Unevaluated document is on u2, put the evaluated document there, too. ! 468: */ ! 469: evalhere(u2) ! 470: { ! 471: register int u1; ! 472: register FILE *f2; ! 473: char buf[128]; ! 474: char *tmp; ! 475: ! 476: tmp = shtmp(); ! 477: if ((u1=creat(tmp, 0666))<0) { ! 478: ecantmake(tmp); ! 479: return -1; ! 480: } ! 481: if ((f2=fdopen(u2, "r"))==NULL) { ! 482: ecantfdop(); ! 483: close(u1); ! 484: close(u2); ! 485: return -1; ! 486: } ! 487: while (fgets(buf, 128, f2) != NULL) { ! 488: eval(buf, EHERE); ! 489: write(u1, strt, strp-1-strt); ! 490: } ! 491: close(u1); ! 492: fclose(f2); ! 493: if ((u2 = open(tmp, 0))<0) { ! 494: ecantopen(tmp); ! 495: u2 = -1; ! 496: } ! 497: unlink(tmp); ! 498: return u2; ! 499: } ! 500: ! 501: /* end of sh/eval.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.