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