Commit | Line | Data |
---|---|---|
b79f4fa9 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
094e80ed | 3 | * All rights reserved. The Berkeley Software License Agreement |
b79f4fa9 DF |
4 | * specifies the terms and conditions for redistribution. |
5 | */ | |
6 | ||
35371dec | 7 | #ifndef lint |
0c9317b5 | 8 | static char *sccsid = "@(#)dol.c 5.4 (Berkeley) %G%"; |
094e80ed | 9 | #endif |
efdf1379 BJ |
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 | |
35371dec | 23 | * some QUOTEing may have occurred already, so we dont "trim()" here. |
efdf1379 BJ |
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 | ||
35371dec | 33 | #define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */ |
efdf1379 BJ |
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 | ||
efdf1379 BJ |
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 | { | |
35371dec EW |
54 | register char **pp; |
55 | register char *p; | |
efdf1379 BJ |
56 | |
57 | if (noexec) | |
58 | return; | |
35371dec EW |
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 | } | |
efdf1379 BJ |
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; | |
35371dec | 217 | if (cmap(c, _SP|_NL|_Q|_Q1)) { /* sp \t\n'"` */ |
efdf1379 | 218 | unDgetC(c); |
35371dec | 219 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
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. | |
fe7a2c87 SL |
236 | * Any QUOTES character which is returned from a $ expansion is |
237 | * QUOTEd so that it will not be recognized above. | |
efdf1379 BJ |
238 | */ |
239 | DgetC(flag) | |
240 | register int flag; | |
241 | { | |
242 | register int c; | |
243 | ||
244 | top: | |
245 | if (c = Dpeekc) { | |
fe7a2c87 | 246 | Dpeekc = 0; |
efdf1379 BJ |
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: | |
35371dec | 256 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
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; | |
3d9f6a35 | 297 | bool dimen = 0, bitset = 0; |
efdf1379 BJ |
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 == '?') | |
3d9f6a35 | 307 | bitset++, c = DgetC(0); /* $? tests existence */ |
efdf1379 BJ |
308 | switch (c) { |
309 | ||
310 | case '$': | |
3d9f6a35 | 311 | if (dimen || bitset) |
efdf1379 BJ |
312 | goto syntax; /* No $?$, $#$ */ |
313 | setDolp(doldol); | |
314 | goto eatbrac; | |
315 | ||
316 | case '<'|QUOTE: | |
3d9f6a35 | 317 | if (dimen || bitset) |
efdf1379 BJ |
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 '*': | |
35371dec | 344 | (void) strcpy(name, "argv"); |
efdf1379 BJ |
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) { | |
3d9f6a35 | 363 | if (bitset) { |
efdf1379 BJ |
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 | } | |
3d9f6a35 | 372 | if (bitset) |
efdf1379 BJ |
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 | } | |
3d9f6a35 | 396 | if (bitset) { |
efdf1379 BJ |
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); | |
b14dd860 | 404 | goto eatbrac; |
efdf1379 BJ |
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: | |
35371dec | 435 | setname(vp->v_name); |
efdf1379 BJ |
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 | } | |
525 | ||
526 | unDredc(c) | |
527 | int c; | |
528 | { | |
529 | ||
530 | Dpeekrd = c; | |
531 | } | |
532 | ||
533 | Dredc() | |
534 | { | |
535 | register int c; | |
536 | ||
537 | if (c = Dpeekrd) { | |
538 | Dpeekrd = 0; | |
539 | return (c); | |
540 | } | |
541 | if (Dcp && (c = *Dcp++)) | |
542 | return (c&(QUOTE|TRIM)); | |
543 | if (*Dvp == 0) { | |
544 | Dcp = 0; | |
545 | return (DEOF); | |
546 | } | |
547 | Dcp = *Dvp++; | |
548 | return (' '); | |
549 | } | |
550 | ||
efdf1379 BJ |
551 | Dtestq(c) |
552 | register int c; | |
553 | { | |
554 | ||
35371dec | 555 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
556 | gflag = 1; |
557 | } | |
558 | ||
559 | /* | |
560 | * Form a shell temporary file (in unit 0) from the words | |
0c9317b5 | 561 | * of the shell input up to EOF or a line the same as "term". |
efdf1379 BJ |
562 | * Unit 0 should have been closed before this call. |
563 | */ | |
564 | heredoc(term) | |
565 | char *term; | |
566 | { | |
567 | register int c; | |
568 | char *Dv[2]; | |
569 | char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; | |
570 | int ocnt, lcnt, mcnt; | |
571 | register char *lbp, *obp, *mbp; | |
572 | char **vp; | |
573 | bool quoted; | |
574 | ||
575 | if (creat(shtemp, 0600) < 0) | |
576 | Perror(shtemp); | |
35371dec | 577 | (void) close(0); |
efdf1379 BJ |
578 | if (open(shtemp, 2) < 0) { |
579 | int oerrno = errno; | |
580 | ||
35371dec | 581 | (void) unlink(shtemp); |
efdf1379 BJ |
582 | errno = oerrno; |
583 | Perror(shtemp); | |
584 | } | |
35371dec | 585 | (void) unlink(shtemp); /* 0 0 inode! */ |
efdf1379 | 586 | Dv[0] = term; Dv[1] = NOSTR; gflag = 0; |
35371dec | 587 | trim(Dv); rscan(Dv, Dtestq); quoted = gflag; |
efdf1379 BJ |
588 | ocnt = BUFSIZ; obp = obuf; |
589 | for (;;) { | |
590 | /* | |
591 | * Read up a line | |
592 | */ | |
593 | lbp = lbuf; lcnt = BUFSIZ - 4; | |
594 | for (;;) { | |
595 | c = readc(1); /* 1 -> Want EOF returns */ | |
0c9317b5 | 596 | if (c < 0 || c == '\n') |
efdf1379 BJ |
597 | break; |
598 | if (c &= TRIM) { | |
599 | *lbp++ = c; | |
600 | if (--lcnt < 0) { | |
601 | setname("<<"); | |
602 | error("Line overflow"); | |
603 | } | |
604 | } | |
605 | } | |
606 | *lbp = 0; | |
607 | ||
608 | /* | |
0c9317b5 | 609 | * Check for EOF or compare to terminator -- before expansion |
efdf1379 | 610 | */ |
0c9317b5 | 611 | if (c < 0 || eq(lbuf, term)) { |
35371dec EW |
612 | (void) write(0, obuf, BUFSIZ - ocnt); |
613 | (void) lseek(0, (off_t)0, 0); | |
efdf1379 BJ |
614 | return; |
615 | } | |
616 | ||
617 | /* | |
618 | * If term was quoted or -n just pass it on | |
619 | */ | |
620 | if (quoted || noexec) { | |
621 | *lbp++ = '\n'; *lbp = 0; | |
622 | for (lbp = lbuf; c = *lbp++;) { | |
623 | *obp++ = c; | |
624 | if (--ocnt == 0) { | |
35371dec | 625 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
626 | obp = obuf; ocnt = BUFSIZ; |
627 | } | |
628 | } | |
629 | continue; | |
630 | } | |
631 | ||
632 | /* | |
633 | * Term wasn't quoted so variable and then command | |
634 | * expand the input line | |
635 | */ | |
636 | Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; | |
637 | for (;;) { | |
638 | c = DgetC(DODOL); | |
639 | if (c == DEOF) | |
640 | break; | |
641 | if ((c &= TRIM) == 0) | |
642 | continue; | |
643 | /* \ quotes \ $ ` here */ | |
644 | if (c =='\\') { | |
645 | c = DgetC(0); | |
646 | if (!any(c, "$\\`")) | |
647 | unDgetC(c | QUOTE), c = '\\'; | |
648 | else | |
649 | c |= QUOTE; | |
650 | } | |
651 | *mbp++ = c; | |
652 | if (--mcnt == 0) { | |
653 | setname("<<"); | |
654 | bferr("Line overflow"); | |
655 | } | |
656 | } | |
657 | *mbp++ = 0; | |
658 | ||
659 | /* | |
660 | * If any ` in line do command substitution | |
661 | */ | |
662 | mbp = mbuf; | |
663 | if (any('`', mbp)) { | |
664 | /* | |
665 | * 1 arg to dobackp causes substitution to be literal. | |
666 | * Words are broken only at newlines so that all blanks | |
667 | * and tabs are preserved. Blank lines (null words) | |
668 | * are not discarded. | |
669 | */ | |
670 | vp = dobackp(mbuf, 1); | |
671 | } else | |
672 | /* Setup trivial vector similar to return of dobackp */ | |
673 | Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv; | |
674 | ||
675 | /* | |
676 | * Resurrect the words from the command substitution | |
677 | * each separated by a newline. Note that the last | |
678 | * newline of a command substitution will have been | |
679 | * discarded, but we put a newline after the last word | |
680 | * because this represents the newline after the last | |
681 | * input line! | |
682 | */ | |
683 | for (; *vp; vp++) { | |
684 | for (mbp = *vp; *mbp; mbp++) { | |
685 | *obp++ = *mbp & TRIM; | |
686 | if (--ocnt == 0) { | |
35371dec | 687 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
688 | obp = obuf; ocnt = BUFSIZ; |
689 | } | |
690 | } | |
691 | *obp++ = '\n'; | |
692 | if (--ocnt == 0) { | |
35371dec | 693 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
694 | obp = obuf; ocnt = BUFSIZ; |
695 | } | |
696 | } | |
697 | if (pargv) | |
698 | blkfree(pargv), pargv = 0; | |
699 | } | |
700 | } |