|
|
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.