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 |
094e80ed EW |
8 | static char *sccsid = "@(#)dol.c 5.2 (Berkeley) %G%"; |
9 | #endif | |
efdf1379 BJ |
10 | |
11 | #include "sh.h" | |
35371dec | 12 | #include "sh.char.h" |
efdf1379 BJ |
13 | |
14 | /* | |
15 | * C shell | |
16 | */ | |
17 | ||
18 | /* | |
19 | * These routines perform variable substitution and quoting via ' and ". | |
20 | * To this point these constructs have been preserved in the divided | |
21 | * input words. Here we expand variables and turn quoting via ' and " into | |
22 | * QUOTE bits on characters (which prevent further interpretation). | |
23 | * If the `:q' modifier was applied during history expansion, then | |
35371dec | 24 | * some QUOTEing may have occurred already, so we dont "trim()" here. |
efdf1379 BJ |
25 | */ |
26 | ||
27 | int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */ | |
28 | char *Dcp, **Dvp; /* Input vector for Dreadc */ | |
29 | ||
30 | #define DEOF -1 | |
31 | ||
32 | #define unDgetC(c) Dpeekc = c | |
33 | ||
35371dec | 34 | #define QUOTES (_Q|_Q1|_ESC) /* \ ' " ` */ |
efdf1379 BJ |
35 | |
36 | /* | |
37 | * The following variables give the information about the current | |
38 | * $ expansion, recording the current word position, the remaining | |
39 | * words within this expansion, the count of remaining words, and the | |
40 | * information about any : modifier which is being applied. | |
41 | */ | |
42 | char *dolp; /* Remaining chars from this word */ | |
43 | char **dolnxt; /* Further words */ | |
44 | int dolcnt; /* Count of further words */ | |
45 | char dolmod; /* : modifier character */ | |
46 | int dolmcnt; /* :gx -> 10000, else 1 */ | |
47 | ||
efdf1379 BJ |
48 | /* |
49 | * Fix up the $ expansions and quotations in the | |
50 | * argument list to command t. | |
51 | */ | |
52 | Dfix(t) | |
53 | register struct command *t; | |
54 | { | |
35371dec EW |
55 | register char **pp; |
56 | register char *p; | |
efdf1379 BJ |
57 | |
58 | if (noexec) | |
59 | return; | |
35371dec EW |
60 | /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */ |
61 | for (pp = t->t_dcom; p = *pp++;) | |
62 | while (*p) | |
63 | if (cmap(*p++, _DOL|QUOTES)) { /* $, \, ', ", ` */ | |
64 | Dfix2(t->t_dcom); /* found one */ | |
65 | blkfree(t->t_dcom); | |
66 | t->t_dcom = gargv; | |
67 | gargv = 0; | |
68 | return; | |
69 | } | |
efdf1379 BJ |
70 | } |
71 | ||
72 | /* | |
73 | * $ substitute one word, for i/o redirection | |
74 | */ | |
75 | char * | |
76 | Dfix1(cp) | |
77 | register char *cp; | |
78 | { | |
79 | char *Dv[2]; | |
80 | ||
81 | if (noexec) | |
82 | return (0); | |
83 | Dv[0] = cp; Dv[1] = NOSTR; | |
84 | Dfix2(Dv); | |
85 | if (gargc != 1) { | |
86 | setname(cp); | |
87 | bferr("Ambiguous"); | |
88 | } | |
89 | cp = savestr(gargv[0]); | |
90 | blkfree(gargv), gargv = 0; | |
91 | return (cp); | |
92 | } | |
93 | ||
94 | /* | |
95 | * Subroutine to do actual fixing after state initialization. | |
96 | */ | |
97 | Dfix2(v) | |
98 | char **v; | |
99 | { | |
100 | char *agargv[GAVSIZ]; | |
101 | ||
102 | ginit(agargv); /* Initialize glob's area pointers */ | |
103 | Dvp = v; Dcp = ""; /* Setup input vector for Dreadc */ | |
104 | unDgetC(0); unDredc(0); /* Clear out any old peeks (at error) */ | |
105 | dolp = 0; dolcnt = 0; /* Clear out residual $ expands (...) */ | |
106 | while (Dword()) | |
107 | continue; | |
108 | gargv = copyblk(gargv); | |
109 | } | |
110 | ||
111 | /* | |
112 | * Get a word. This routine is analogous to the routine | |
113 | * word() in sh.lex.c for the main lexical input. One difference | |
114 | * here is that we don't get a newline to terminate our expansion. | |
115 | * Rather, DgetC will return a DEOF when we hit the end-of-input. | |
116 | */ | |
117 | Dword() | |
118 | { | |
119 | register int c, c1; | |
120 | char wbuf[BUFSIZ]; | |
121 | register char *wp = wbuf; | |
122 | register int i = BUFSIZ - 4; | |
123 | register bool dolflg; | |
124 | bool sofar = 0; | |
125 | ||
126 | loop: | |
127 | c = DgetC(DODOL); | |
128 | switch (c) { | |
129 | ||
130 | case DEOF: | |
131 | deof: | |
132 | if (sofar == 0) | |
133 | return (0); | |
134 | /* finish this word and catch the code above the next time */ | |
135 | unDredc(c); | |
136 | /* fall into ... */ | |
137 | ||
138 | case '\n': | |
139 | *wp = 0; | |
140 | goto ret; | |
141 | ||
142 | case ' ': | |
143 | case '\t': | |
144 | goto loop; | |
145 | ||
146 | case '`': | |
147 | /* We preserve ` quotations which are done yet later */ | |
148 | *wp++ = c, --i; | |
149 | case '\'': | |
150 | case '"': | |
151 | /* | |
152 | * Note that DgetC never returns a QUOTES character | |
153 | * from an expansion, so only true input quotes will | |
154 | * get us here or out. | |
155 | */ | |
156 | c1 = c; | |
157 | dolflg = c1 == '"' ? DODOL : 0; | |
158 | for (;;) { | |
159 | c = DgetC(dolflg); | |
160 | if (c == c1) | |
161 | break; | |
162 | if (c == '\n' || c == DEOF) | |
163 | error("Unmatched %c", c1); | |
164 | if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE)) | |
165 | --wp, ++i; | |
166 | if (--i <= 0) | |
167 | goto toochars; | |
168 | switch (c1) { | |
169 | ||
170 | case '"': | |
171 | /* | |
172 | * Leave any `s alone for later. | |
173 | * Other chars are all quoted, thus `...` | |
174 | * can tell it was within "...". | |
175 | */ | |
176 | *wp++ = c == '`' ? '`' : c | QUOTE; | |
177 | break; | |
178 | ||
179 | case '\'': | |
180 | /* Prevent all further interpretation */ | |
181 | *wp++ = c | QUOTE; | |
182 | break; | |
183 | ||
184 | case '`': | |
185 | /* Leave all text alone for later */ | |
186 | *wp++ = c; | |
187 | break; | |
188 | } | |
189 | } | |
190 | if (c1 == '`') | |
191 | *wp++ = '`', --i; | |
192 | goto pack; /* continue the word */ | |
193 | ||
194 | case '\\': | |
195 | c = DgetC(0); /* No $ subst! */ | |
196 | if (c == '\n' || c == DEOF) | |
197 | goto loop; | |
198 | c |= QUOTE; | |
199 | break; | |
200 | } | |
201 | unDgetC(c); | |
202 | pack: | |
203 | sofar = 1; | |
204 | /* pack up more characters in this word */ | |
205 | for (;;) { | |
206 | c = DgetC(DODOL); | |
207 | if (c == '\\') { | |
208 | c = DgetC(0); | |
209 | if (c == DEOF) | |
210 | goto deof; | |
211 | if (c == '\n') | |
212 | c = ' '; | |
213 | else | |
214 | c |= QUOTE; | |
215 | } | |
216 | if (c == DEOF) | |
217 | goto deof; | |
35371dec | 218 | if (cmap(c, _SP|_NL|_Q|_Q1)) { /* sp \t\n'"` */ |
efdf1379 | 219 | unDgetC(c); |
35371dec | 220 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
221 | goto loop; |
222 | *wp++ = 0; | |
223 | goto ret; | |
224 | } | |
225 | if (--i <= 0) | |
226 | toochars: | |
227 | error("Word too long"); | |
228 | *wp++ = c; | |
229 | } | |
230 | ret: | |
231 | Gcat("", wbuf); | |
232 | return (1); | |
233 | } | |
234 | ||
235 | /* | |
236 | * Get a character, performing $ substitution unless flag is 0. | |
fe7a2c87 SL |
237 | * Any QUOTES character which is returned from a $ expansion is |
238 | * QUOTEd so that it will not be recognized above. | |
efdf1379 BJ |
239 | */ |
240 | DgetC(flag) | |
241 | register int flag; | |
242 | { | |
243 | register int c; | |
244 | ||
245 | top: | |
246 | if (c = Dpeekc) { | |
fe7a2c87 | 247 | Dpeekc = 0; |
efdf1379 BJ |
248 | return (c); |
249 | } | |
250 | if (lap) { | |
251 | c = *lap++ & (QUOTE|TRIM); | |
252 | if (c == 0) { | |
253 | lap = 0; | |
254 | goto top; | |
255 | } | |
256 | quotspec: | |
35371dec | 257 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
258 | return (c | QUOTE); |
259 | return (c); | |
260 | } | |
261 | if (dolp) { | |
262 | if (c = *dolp++ & (QUOTE|TRIM)) | |
263 | goto quotspec; | |
264 | if (dolcnt > 0) { | |
265 | setDolp(*dolnxt++); | |
266 | --dolcnt; | |
267 | return (' '); | |
268 | } | |
269 | dolp = 0; | |
270 | } | |
271 | if (dolcnt > 0) { | |
272 | setDolp(*dolnxt++); | |
273 | --dolcnt; | |
274 | goto top; | |
275 | } | |
276 | c = Dredc(); | |
277 | if (c == '$' && flag) { | |
278 | Dgetdol(); | |
279 | goto top; | |
280 | } | |
281 | return (c); | |
282 | } | |
283 | ||
284 | char *nulvec[] = { 0 }; | |
285 | struct varent nulargv = { nulvec, "argv", 0 }; | |
286 | ||
287 | /* | |
288 | * Handle the multitudinous $ expansion forms. | |
289 | * Ugh. | |
290 | */ | |
291 | Dgetdol() | |
292 | { | |
293 | register char *np; | |
294 | register struct varent *vp; | |
295 | char name[20]; | |
296 | int c, sc; | |
297 | int subscr = 0, lwb = 1, upb = 0; | |
3d9f6a35 | 298 | bool dimen = 0, bitset = 0; |
efdf1379 BJ |
299 | char wbuf[BUFSIZ]; |
300 | ||
301 | dolmod = dolmcnt = 0; | |
302 | c = sc = DgetC(0); | |
303 | if (c == '{') | |
304 | c = DgetC(0); /* sc is { to take } later */ | |
305 | if ((c & TRIM) == '#') | |
306 | dimen++, c = DgetC(0); /* $# takes dimension */ | |
307 | else if (c == '?') | |
3d9f6a35 | 308 | bitset++, c = DgetC(0); /* $? tests existence */ |
efdf1379 BJ |
309 | switch (c) { |
310 | ||
311 | case '$': | |
3d9f6a35 | 312 | if (dimen || bitset) |
efdf1379 BJ |
313 | goto syntax; /* No $?$, $#$ */ |
314 | setDolp(doldol); | |
315 | goto eatbrac; | |
316 | ||
317 | case '<'|QUOTE: | |
3d9f6a35 | 318 | if (dimen || bitset) |
efdf1379 BJ |
319 | goto syntax; /* No $?<, $#< */ |
320 | for (np = wbuf; read(OLDSTD, np, 1) == 1; np++) { | |
321 | if (np >= &wbuf[BUFSIZ-1]) | |
322 | error("$< line too long"); | |
323 | if (*np <= 0 || *np == '\n') | |
324 | break; | |
325 | } | |
326 | *np = 0; | |
327 | /* | |
328 | * KLUDGE: dolmod is set here because it will | |
329 | * cause setDolp to call domod and thus to copy wbuf. | |
330 | * Otherwise setDolp would use it directly. If we saved | |
331 | * it ourselves, no one would know when to free it. | |
332 | * The actual function of the 'q' causes filename | |
333 | * expansion not to be done on the interpolated value. | |
334 | */ | |
335 | dolmod = 'q'; | |
336 | dolmcnt = 10000; | |
337 | setDolp(wbuf); | |
338 | goto eatbrac; | |
339 | ||
340 | case DEOF: | |
341 | case '\n': | |
342 | goto syntax; | |
343 | ||
344 | case '*': | |
35371dec | 345 | (void) strcpy(name, "argv"); |
efdf1379 BJ |
346 | vp = adrof("argv"); |
347 | subscr = -1; /* Prevent eating [...] */ | |
348 | break; | |
349 | ||
350 | default: | |
351 | np = name; | |
352 | if (digit(c)) { | |
353 | if (dimen) | |
354 | goto syntax; /* No $#1, e.g. */ | |
355 | subscr = 0; | |
356 | do { | |
357 | subscr = subscr * 10 + c - '0'; | |
358 | c = DgetC(0); | |
359 | } while (digit(c)); | |
360 | unDredc(c); | |
361 | if (subscr < 0) | |
362 | goto oob; | |
363 | if (subscr == 0) { | |
3d9f6a35 | 364 | if (bitset) { |
efdf1379 BJ |
365 | dolp = file ? "1" : "0"; |
366 | goto eatbrac; | |
367 | } | |
368 | if (file == 0) | |
369 | error("No file for $0"); | |
370 | setDolp(file); | |
371 | goto eatbrac; | |
372 | } | |
3d9f6a35 | 373 | if (bitset) |
efdf1379 BJ |
374 | goto syntax; |
375 | vp = adrof("argv"); | |
376 | if (vp == 0) { | |
377 | vp = &nulargv; | |
378 | goto eatmod; | |
379 | } | |
380 | break; | |
381 | } | |
382 | if (!alnum(c)) | |
383 | goto syntax; | |
384 | for (;;) { | |
385 | *np++ = c; | |
386 | c = DgetC(0); | |
387 | if (!alnum(c)) | |
388 | break; | |
389 | if (np >= &name[sizeof name - 2]) | |
390 | syntax: | |
391 | error("Variable syntax"); | |
392 | } | |
393 | *np++ = 0; | |
394 | unDredc(c); | |
395 | vp = adrof(name); | |
396 | } | |
3d9f6a35 | 397 | if (bitset) { |
efdf1379 BJ |
398 | dolp = (vp || getenv(name)) ? "1" : "0"; |
399 | goto eatbrac; | |
400 | } | |
401 | if (vp == 0) { | |
402 | np = getenv(name); | |
403 | if (np) { | |
404 | addla(np); | |
b14dd860 | 405 | goto eatbrac; |
efdf1379 BJ |
406 | } |
407 | udvar(name); | |
408 | /*NOTREACHED*/ | |
409 | } | |
410 | c = DgetC(0); | |
411 | upb = blklen(vp->vec); | |
412 | if (dimen == 0 && subscr == 0 && c == '[') { | |
413 | np = name; | |
414 | for (;;) { | |
415 | c = DgetC(DODOL); /* Allow $ expand within [ ] */ | |
416 | if (c == ']') | |
417 | break; | |
418 | if (c == '\n' || c == DEOF) | |
419 | goto syntax; | |
420 | if (np >= &name[sizeof name - 2]) | |
421 | goto syntax; | |
422 | *np++ = c; | |
423 | } | |
424 | *np = 0, np = name; | |
425 | if (dolp || dolcnt) /* $ exp must end before ] */ | |
426 | goto syntax; | |
427 | if (!*np) | |
428 | goto syntax; | |
429 | if (digit(*np)) { | |
430 | register int i = 0; | |
431 | ||
432 | while (digit(*np)) | |
433 | i = i * 10 + *np++ - '0'; | |
434 | if ((i < 0 || i > upb) && !any(*np, "-*")) { | |
435 | oob: | |
35371dec | 436 | setname(vp->v_name); |
efdf1379 BJ |
437 | error("Subscript out of range"); |
438 | } | |
439 | lwb = i; | |
440 | if (!*np) | |
441 | upb = lwb, np = "*"; | |
442 | } | |
443 | if (*np == '*') | |
444 | np++; | |
445 | else if (*np != '-') | |
446 | goto syntax; | |
447 | else { | |
448 | register int i = upb; | |
449 | ||
450 | np++; | |
451 | if (digit(*np)) { | |
452 | i = 0; | |
453 | while (digit(*np)) | |
454 | i = i * 10 + *np++ - '0'; | |
455 | if (i < 0 || i > upb) | |
456 | goto oob; | |
457 | } | |
458 | if (i < lwb) | |
459 | upb = lwb - 1; | |
460 | else | |
461 | upb = i; | |
462 | } | |
463 | if (lwb == 0) { | |
464 | if (upb != 0) | |
465 | goto oob; | |
466 | upb = -1; | |
467 | } | |
468 | if (*np) | |
469 | goto syntax; | |
470 | } else { | |
471 | if (subscr > 0) | |
472 | if (subscr > upb) | |
473 | lwb = 1, upb = 0; | |
474 | else | |
475 | lwb = upb = subscr; | |
476 | unDredc(c); | |
477 | } | |
478 | if (dimen) { | |
479 | char *cp = putn(upb - lwb + 1); | |
480 | ||
481 | addla(cp); | |
482 | xfree(cp); | |
483 | } else { | |
484 | eatmod: | |
485 | c = DgetC(0); | |
486 | if (c == ':') { | |
487 | c = DgetC(0), dolmcnt = 1; | |
488 | if (c == 'g') | |
489 | c = DgetC(0), dolmcnt = 10000; | |
490 | if (!any(c, "htrqxe")) | |
491 | error("Bad : mod in $"); | |
492 | dolmod = c; | |
493 | if (c == 'q') | |
494 | dolmcnt = 10000; | |
495 | } else | |
496 | unDredc(c); | |
497 | dolnxt = &vp->vec[lwb - 1]; | |
498 | dolcnt = upb - lwb + 1; | |
499 | } | |
500 | eatbrac: | |
501 | if (sc == '{') { | |
502 | c = Dredc(); | |
503 | if (c != '}') | |
504 | goto syntax; | |
505 | } | |
506 | } | |
507 | ||
508 | setDolp(cp) | |
509 | register char *cp; | |
510 | { | |
511 | register char *dp; | |
512 | ||
513 | if (dolmod == 0 || dolmcnt == 0) { | |
514 | dolp = cp; | |
515 | return; | |
516 | } | |
517 | dp = domod(cp, dolmod); | |
518 | if (dp) { | |
519 | dolmcnt--; | |
520 | addla(dp); | |
521 | xfree(dp); | |
522 | } else | |
523 | addla(cp); | |
524 | dolp = ""; | |
525 | } | |
526 | ||
527 | unDredc(c) | |
528 | int c; | |
529 | { | |
530 | ||
531 | Dpeekrd = c; | |
532 | } | |
533 | ||
534 | Dredc() | |
535 | { | |
536 | register int c; | |
537 | ||
538 | if (c = Dpeekrd) { | |
539 | Dpeekrd = 0; | |
540 | return (c); | |
541 | } | |
542 | if (Dcp && (c = *Dcp++)) | |
543 | return (c&(QUOTE|TRIM)); | |
544 | if (*Dvp == 0) { | |
545 | Dcp = 0; | |
546 | return (DEOF); | |
547 | } | |
548 | Dcp = *Dvp++; | |
549 | return (' '); | |
550 | } | |
551 | ||
efdf1379 BJ |
552 | Dtestq(c) |
553 | register int c; | |
554 | { | |
555 | ||
35371dec | 556 | if (cmap(c, QUOTES)) |
efdf1379 BJ |
557 | gflag = 1; |
558 | } | |
559 | ||
560 | /* | |
561 | * Form a shell temporary file (in unit 0) from the words | |
562 | * of the shell input up to a line the same as "term". | |
563 | * Unit 0 should have been closed before this call. | |
564 | */ | |
565 | heredoc(term) | |
566 | char *term; | |
567 | { | |
568 | register int c; | |
569 | char *Dv[2]; | |
570 | char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ]; | |
571 | int ocnt, lcnt, mcnt; | |
572 | register char *lbp, *obp, *mbp; | |
573 | char **vp; | |
574 | bool quoted; | |
575 | ||
576 | if (creat(shtemp, 0600) < 0) | |
577 | Perror(shtemp); | |
35371dec | 578 | (void) close(0); |
efdf1379 BJ |
579 | if (open(shtemp, 2) < 0) { |
580 | int oerrno = errno; | |
581 | ||
35371dec | 582 | (void) unlink(shtemp); |
efdf1379 BJ |
583 | errno = oerrno; |
584 | Perror(shtemp); | |
585 | } | |
35371dec | 586 | (void) unlink(shtemp); /* 0 0 inode! */ |
efdf1379 | 587 | Dv[0] = term; Dv[1] = NOSTR; gflag = 0; |
35371dec | 588 | trim(Dv); rscan(Dv, Dtestq); quoted = gflag; |
efdf1379 BJ |
589 | ocnt = BUFSIZ; obp = obuf; |
590 | for (;;) { | |
591 | /* | |
592 | * Read up a line | |
593 | */ | |
594 | lbp = lbuf; lcnt = BUFSIZ - 4; | |
595 | for (;;) { | |
596 | c = readc(1); /* 1 -> Want EOF returns */ | |
597 | if (c < 0) { | |
598 | setname(term); | |
599 | bferr("<< terminator not found"); | |
600 | } | |
601 | if (c == '\n') | |
602 | break; | |
603 | if (c &= TRIM) { | |
604 | *lbp++ = c; | |
605 | if (--lcnt < 0) { | |
606 | setname("<<"); | |
607 | error("Line overflow"); | |
608 | } | |
609 | } | |
610 | } | |
611 | *lbp = 0; | |
612 | ||
613 | /* | |
614 | * Compare to terminator -- before expansion | |
615 | */ | |
616 | if (eq(lbuf, term)) { | |
35371dec EW |
617 | (void) write(0, obuf, BUFSIZ - ocnt); |
618 | (void) lseek(0, (off_t)0, 0); | |
efdf1379 BJ |
619 | return; |
620 | } | |
621 | ||
622 | /* | |
623 | * If term was quoted or -n just pass it on | |
624 | */ | |
625 | if (quoted || noexec) { | |
626 | *lbp++ = '\n'; *lbp = 0; | |
627 | for (lbp = lbuf; c = *lbp++;) { | |
628 | *obp++ = c; | |
629 | if (--ocnt == 0) { | |
35371dec | 630 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
631 | obp = obuf; ocnt = BUFSIZ; |
632 | } | |
633 | } | |
634 | continue; | |
635 | } | |
636 | ||
637 | /* | |
638 | * Term wasn't quoted so variable and then command | |
639 | * expand the input line | |
640 | */ | |
641 | Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4; | |
642 | for (;;) { | |
643 | c = DgetC(DODOL); | |
644 | if (c == DEOF) | |
645 | break; | |
646 | if ((c &= TRIM) == 0) | |
647 | continue; | |
648 | /* \ quotes \ $ ` here */ | |
649 | if (c =='\\') { | |
650 | c = DgetC(0); | |
651 | if (!any(c, "$\\`")) | |
652 | unDgetC(c | QUOTE), c = '\\'; | |
653 | else | |
654 | c |= QUOTE; | |
655 | } | |
656 | *mbp++ = c; | |
657 | if (--mcnt == 0) { | |
658 | setname("<<"); | |
659 | bferr("Line overflow"); | |
660 | } | |
661 | } | |
662 | *mbp++ = 0; | |
663 | ||
664 | /* | |
665 | * If any ` in line do command substitution | |
666 | */ | |
667 | mbp = mbuf; | |
668 | if (any('`', mbp)) { | |
669 | /* | |
670 | * 1 arg to dobackp causes substitution to be literal. | |
671 | * Words are broken only at newlines so that all blanks | |
672 | * and tabs are preserved. Blank lines (null words) | |
673 | * are not discarded. | |
674 | */ | |
675 | vp = dobackp(mbuf, 1); | |
676 | } else | |
677 | /* Setup trivial vector similar to return of dobackp */ | |
678 | Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv; | |
679 | ||
680 | /* | |
681 | * Resurrect the words from the command substitution | |
682 | * each separated by a newline. Note that the last | |
683 | * newline of a command substitution will have been | |
684 | * discarded, but we put a newline after the last word | |
685 | * because this represents the newline after the last | |
686 | * input line! | |
687 | */ | |
688 | for (; *vp; vp++) { | |
689 | for (mbp = *vp; *mbp; mbp++) { | |
690 | *obp++ = *mbp & TRIM; | |
691 | if (--ocnt == 0) { | |
35371dec | 692 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
693 | obp = obuf; ocnt = BUFSIZ; |
694 | } | |
695 | } | |
696 | *obp++ = '\n'; | |
697 | if (--ocnt == 0) { | |
35371dec | 698 | (void) write(0, obuf, BUFSIZ); |
efdf1379 BJ |
699 | obp = obuf; ocnt = BUFSIZ; |
700 | } | |
701 | } | |
702 | if (pargv) | |
703 | blkfree(pargv), pargv = 0; | |
704 | } | |
705 | } |