GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/csh/dol.c Lines: 0 440 0.0 %
Date: 2017-11-07 Branches: 0 362 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: dol.c,v 1.20 2015/12/26 13:48:38 mestre Exp $	*/
2
/*	$NetBSD: dol.c,v 1.8 1995/09/27 00:38:38 jtc Exp $	*/
3
4
/*-
5
 * Copyright (c) 1980, 1991, 1993
6
 *	The Regents of the University of California.  All rights reserved.
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 * 3. Neither the name of the University nor the names of its contributors
17
 *    may be used to endorse or promote products derived from this software
18
 *    without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include <sys/types.h>
34
#include <fcntl.h>
35
#include <errno.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
#include <stdarg.h>
40
41
#include "csh.h"
42
#include "extern.h"
43
44
/*
45
 * These routines perform variable substitution and quoting via ' and ".
46
 * To this point these constructs have been preserved in the divided
47
 * input words.  Here we expand variables and turn quoting via ' and " into
48
 * QUOTE bits on characters (which prevent further interpretation).
49
 * If the `:q' modifier was applied during history expansion, then
50
 * some QUOTEing may have occurred already, so we dont "trim()" here.
51
 */
52
53
static int Dpeekc, Dpeekrd;	/* Peeks for DgetC and Dreadc */
54
static Char *Dcp, **Dvp;	/* Input vector for Dreadc */
55
56
#define	DEOF	-1
57
58
#define	unDgetC(c)	Dpeekc = c
59
60
#define QUOTES		(_QF|_QB|_ESC)	/* \ ' " ` */
61
62
/*
63
 * The following variables give the information about the current
64
 * $ expansion, recording the current word position, the remaining
65
 * words within this expansion, the count of remaining words, and the
66
 * information about any : modifier which is being applied.
67
 */
68
#define MAXWLEN (BUFSIZ - 4)
69
#define MAXMOD MAXWLEN		/* This cannot overflow	*/
70
static Char *dolp;		/* Remaining chars from this word */
71
static Char **dolnxt;		/* Further words */
72
static int dolcnt;		/* Count of further words */
73
static Char dolmod[MAXMOD];	/* : modifier character */
74
static int dolnmod;		/* Number of modifiers */
75
static int dolmcnt;		/* :gx -> 10000, else 1 */
76
static int dolwcnt;		/* :wx -> 10000, else 1 */
77
78
static void	 Dfix2(Char **);
79
static Char	*Dpack(Char *, Char *);
80
static int	 Dword(void);
81
static void	 dolerror(Char *);
82
static int	 DgetC(int);
83
static void	 Dgetdol(void);
84
static void	 fixDolMod(void);
85
static void	 setDolp(Char *);
86
static void	 unDredc(int);
87
static int	 Dredc(void);
88
static void	 Dtestq(int);
89
90
91
/*
92
 * Fix up the $ expansions and quotations in the
93
 * argument list to command t.
94
 */
95
void
96
Dfix(struct command *t)
97
{
98
    Char **pp;
99
    Char *p;
100
101
    if (noexec)
102
	return;
103
    /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
104
    for (pp = t->t_dcom; (p = *pp++) != NULL;)
105
	for (; *p; p++) {
106
	    if (cmap(*p, _DOL | QUOTES)) {	/* $, \, ', ", ` */
107
		Dfix2(t->t_dcom);	/* found one */
108
		blkfree(t->t_dcom);
109
		t->t_dcom = gargv;
110
		gargv = 0;
111
		return;
112
	    }
113
	}
114
}
115
116
/*
117
 * $ substitute one word, for i/o redirection
118
 */
119
Char   *
120
Dfix1(Char *cp)
121
{
122
    Char   *Dv[2];
123
124
    if (noexec)
125
	return (0);
126
    Dv[0] = cp;
127
    Dv[1] = NULL;
128
    Dfix2(Dv);
129
    if (gargc != 1) {
130
	setname(vis_str(cp));
131
	stderror(ERR_NAME | ERR_AMBIG);
132
    }
133
    cp = Strsave(gargv[0]);
134
    blkfree(gargv), gargv = 0;
135
    return (cp);
136
}
137
138
/*
139
 * Subroutine to do actual fixing after state initialization.
140
 */
141
static void
142
Dfix2(Char **v)
143
{
144
    ginit();			/* Initialize glob's area pointers */
145
    Dvp = v;
146
    Dcp = STRNULL;		/* Setup input vector for Dreadc */
147
    unDgetC(0);
148
    unDredc(0);			/* Clear out any old peeks (at error) */
149
    dolp = 0;
150
    dolcnt = 0;			/* Clear out residual $ expands (...) */
151
    while (Dword())
152
	continue;
153
}
154
155
/*
156
 * Pack up more characters in this word
157
 */
158
static Char *
159
Dpack(Char *wbuf, Char *wp)
160
{
161
    int c;
162
    int i = MAXWLEN - (wp - wbuf);
163
164
    for (;;) {
165
	c = DgetC(DODOL);
166
	if (c == '\\') {
167
	    c = DgetC(0);
168
	    if (c == DEOF) {
169
		unDredc(c);
170
		*wp = 0;
171
		Gcat(STRNULL, wbuf);
172
		return (NULL);
173
	    }
174
	    if (c == '\n')
175
		c = ' ';
176
	    else
177
		c |= QUOTE;
178
	}
179
	if (c == DEOF) {
180
	    unDredc(c);
181
	    *wp = 0;
182
	    Gcat(STRNULL, wbuf);
183
	    return (NULL);
184
	}
185
	if (cmap(c, _SP | _NL | _QF | _QB)) {	/* sp \t\n'"` */
186
	    unDgetC(c);
187
	    if (cmap(c, QUOTES))
188
		return (wp);
189
	    *wp++ = 0;
190
	    Gcat(STRNULL, wbuf);
191
	    return (NULL);
192
	}
193
	if (--i <= 0)
194
	    stderror(ERR_WTOOLONG);
195
	*wp++ = c;
196
    }
197
}
198
199
/*
200
 * Get a word.  This routine is analogous to the routine
201
 * word() in sh.lex.c for the main lexical input.  One difference
202
 * here is that we don't get a newline to terminate our expansion.
203
 * Rather, DgetC will return a DEOF when we hit the end-of-input.
204
 */
205
static int
206
Dword(void)
207
{
208
    int c, c1;
209
    Char    wbuf[BUFSIZ];
210
    Char *wp = wbuf;
211
    int i = MAXWLEN;
212
    bool dolflg;
213
    bool    sofar = 0, done = 0;
214
215
    while (!done) {
216
	done = 1;
217
	c = DgetC(DODOL);
218
	switch (c) {
219
220
	case DEOF:
221
	    if (sofar == 0)
222
		return (0);
223
	    /* finish this word and catch the code above the next time */
224
	    unDredc(c);
225
	    /* fall into ... */
226
227
	case '\n':
228
	    *wp = 0;
229
	    Gcat(STRNULL, wbuf);
230
	    return (1);
231
232
	case ' ':
233
	case '\t':
234
	    done = 0;
235
	    break;
236
237
	case '`':
238
	    /* We preserve ` quotations which are done yet later */
239
	    *wp++ = c, --i;
240
	case '\'':
241
	case '"':
242
	    /*
243
	     * Note that DgetC never returns a QUOTES character from an
244
	     * expansion, so only true input quotes will get us here or out.
245
	     */
246
	    c1 = c;
247
	    dolflg = c1 == '"' ? DODOL : 0;
248
	    for (;;) {
249
		c = DgetC(dolflg);
250
		if (c == c1)
251
		    break;
252
		if (c == '\n' || c == DEOF)
253
		    stderror(ERR_UNMATCHED, c1);
254
		if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
255
		    --wp, ++i;
256
		if (--i <= 0)
257
		    stderror(ERR_WTOOLONG);
258
		switch (c1) {
259
260
		case '"':
261
		    /*
262
		     * Leave any `s alone for later. Other chars are all
263
		     * quoted, thus `...` can tell it was within "...".
264
		     */
265
		    *wp++ = c == '`' ? '`' : c | QUOTE;
266
		    break;
267
268
		case '\'':
269
		    /* Prevent all further interpretation */
270
		    *wp++ = c | QUOTE;
271
		    break;
272
273
		case '`':
274
		    /* Leave all text alone for later */
275
		    *wp++ = c;
276
		    break;
277
278
		default:
279
		    break;
280
		}
281
	    }
282
	    if (c1 == '`')
283
		*wp++ = '`' /* i--; eliminated */;
284
	    sofar = 1;
285
	    if ((wp = Dpack(wbuf, wp)) == NULL)
286
		return (1);
287
	    else {
288
		i = MAXWLEN - (wp - wbuf);
289
		done = 0;
290
	    }
291
	    break;
292
293
	case '\\':
294
	    c = DgetC(0);	/* No $ subst! */
295
	    if (c == '\n' || c == DEOF) {
296
		done = 0;
297
		break;
298
	    }
299
	    c |= QUOTE;
300
	    break;
301
302
	default:
303
	    break;
304
	}
305
	if (done) {
306
	    unDgetC(c);
307
	    sofar = 1;
308
	    if ((wp = Dpack(wbuf, wp)) == NULL)
309
		return (1);
310
	    else {
311
		i = MAXWLEN - (wp - wbuf);
312
		done = 0;
313
	    }
314
	}
315
    }
316
    /* Really NOTREACHED */
317
    return (0);
318
}
319
320
321
/*
322
 * Get a character, performing $ substitution unless flag is 0.
323
 * Any QUOTES character which is returned from a $ expansion is
324
 * QUOTEd so that it will not be recognized above.
325
 */
326
static int
327
DgetC(int flag)
328
{
329
    int c;
330
331
top:
332
    if ((c = Dpeekc) != '\0') {
333
	Dpeekc = 0;
334
	return (c);
335
    }
336
    if (lap) {
337
	c = *lap++ & (QUOTE | TRIM);
338
	if (c == 0) {
339
	    lap = 0;
340
	    goto top;
341
	}
342
quotspec:
343
	if (cmap(c, QUOTES))
344
	    return (c | QUOTE);
345
	return (c);
346
    }
347
    if (dolp) {
348
	if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
349
	    goto quotspec;
350
	if (dolcnt > 0) {
351
	    setDolp(*dolnxt++);
352
	    --dolcnt;
353
	    return (' ');
354
	}
355
	dolp = 0;
356
    }
357
    if (dolcnt > 0) {
358
	setDolp(*dolnxt++);
359
	--dolcnt;
360
	goto top;
361
    }
362
    c = Dredc();
363
    if (c == '$' && flag) {
364
	Dgetdol();
365
	goto top;
366
    }
367
    return (c);
368
}
369
370
static Char *nulvec[] = {0};
371
static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
372
373
static void
374
dolerror(Char *s)
375
{
376
    setname(vis_str(s));
377
    stderror(ERR_NAME | ERR_RANGE);
378
}
379
380
/*
381
 * Handle the multitudinous $ expansion forms.
382
 * Ugh.
383
 */
384
static void
385
Dgetdol(void)
386
{
387
    Char *np;
388
    struct varent *vp = NULL;
389
    Char    name[4 * MAXVARLEN + 1];
390
    int     c, sc;
391
    int     subscr = 0, lwb = 1, upb = 0;
392
    bool    dimen = 0, bitset = 0;
393
    char    tnp;
394
    Char    wbuf[BUFSIZ];
395
    static Char *dolbang = NULL;
396
397
    dolnmod = dolmcnt = dolwcnt = 0;
398
    c = sc = DgetC(0);
399
    if (c == '{')
400
	c = DgetC(0);		/* sc is { to take } later */
401
    if ((c & TRIM) == '#')
402
	dimen++, c = DgetC(0);	/* $# takes dimension */
403
    else if (c == '?')
404
	bitset++, c = DgetC(0);	/* $? tests existence */
405
    switch (c) {
406
407
    case '!':
408
	if (dimen || bitset)
409
	    stderror(ERR_SYNTAX);
410
	if (backpid != 0) {
411
	    if (dolbang)
412
		free(dolbang);
413
	    setDolp(dolbang = putn(backpid));
414
	}
415
	goto eatbrac;
416
417
    case '$':
418
	if (dimen || bitset)
419
	    stderror(ERR_SYNTAX);
420
	setDolp(doldol);
421
	goto eatbrac;
422
423
    case '<' | QUOTE:
424
	if (bitset)
425
	    stderror(ERR_NOTALLOWED, "$?<");
426
	if (dimen)
427
	    stderror(ERR_NOTALLOWED, "$?#");
428
	for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
429
	    *np = (unsigned char) tnp;
430
	    if (np >= &wbuf[BUFSIZ - 1])
431
		stderror(ERR_LTOOLONG);
432
	    if (tnp == '\n')
433
		break;
434
	}
435
	*np = 0;
436
	/*
437
	 * KLUDGE: dolmod is set here because it will cause setDolp to call
438
	 * domod and thus to copy wbuf. Otherwise setDolp would use it
439
	 * directly. If we saved it ourselves, no one would know when to free
440
	 * it. The actual function of the 'q' causes filename expansion not to
441
	 * be done on the interpolated value.
442
	 */
443
	dolmod[dolnmod++] = 'q';
444
	dolmcnt = 10000;
445
	setDolp(wbuf);
446
	goto eatbrac;
447
448
    case DEOF:
449
    case '\n':
450
	stderror(ERR_SYNTAX);
451
	/* NOTREACHED */
452
	break;
453
454
    case '*':
455
	(void) Strlcpy(name, STRargv, sizeof name/sizeof(Char));
456
	vp = adrof(STRargv);
457
	subscr = -1;		/* Prevent eating [...] */
458
	break;
459
460
    default:
461
	np = name;
462
	if (Isdigit(c)) {
463
	    if (dimen)
464
		stderror(ERR_NOTALLOWED, "$#<num>");
465
	    subscr = 0;
466
	    do {
467
		subscr = subscr * 10 + c - '0';
468
		c = DgetC(0);
469
	    } while (Isdigit(c));
470
	    unDredc(c);
471
	    if (subscr < 0)
472
		stderror(ERR_RANGE);
473
	    if (subscr == 0) {
474
		if (bitset) {
475
		    dolp = ffile ? STR1 : STR0;
476
		    goto eatbrac;
477
		}
478
		if (ffile == 0)
479
		    stderror(ERR_DOLZERO);
480
		fixDolMod();
481
		setDolp(ffile);
482
		goto eatbrac;
483
	    }
484
	    if (bitset)
485
		stderror(ERR_DOLQUEST);
486
	    vp = adrof(STRargv);
487
	    if (vp == 0) {
488
		vp = &nulargv;
489
		goto eatmod;
490
	    }
491
	    break;
492
	}
493
	if (!alnum(c))
494
	    stderror(ERR_VARALNUM);
495
	for (;;) {
496
	    *np++ = c;
497
	    c = DgetC(0);
498
	    if (!alnum(c))
499
		break;
500
	    if (np >= &name[MAXVARLEN])
501
		stderror(ERR_VARTOOLONG);
502
	}
503
	*np++ = 0;
504
	unDredc(c);
505
	vp = adrof(name);
506
    }
507
    if (bitset) {
508
	dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
509
	goto eatbrac;
510
    }
511
    if (vp == 0) {
512
	np = str2short(getenv(short2str(name)));
513
	if (np) {
514
	    fixDolMod();
515
	    setDolp(np);
516
	    goto eatbrac;
517
	}
518
	udvar(name);
519
	/* NOTREACHED */
520
    }
521
    c = DgetC(0);
522
    upb = blklen(vp->vec);
523
    if (dimen == 0 && subscr == 0 && c == '[') {
524
	np = name;
525
	for (;;) {
526
	    c = DgetC(DODOL);	/* Allow $ expand within [ ] */
527
	    if (c == ']')
528
		break;
529
	    if (c == '\n' || c == DEOF)
530
		stderror(ERR_INCBR);
531
	    if (np >= &name[sizeof(name) / sizeof(Char) - 2])
532
		stderror(ERR_VARTOOLONG);
533
	    *np++ = c;
534
	}
535
	*np = 0, np = name;
536
	if (dolp || dolcnt)	/* $ exp must end before ] */
537
	    stderror(ERR_EXPORD);
538
	if (!*np)
539
	    stderror(ERR_SYNTAX);
540
	if (Isdigit(*np)) {
541
	    int     i;
542
543
	    for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
544
		continue;
545
	    if ((i < 0 || i > upb) && !any("-*", *np)) {
546
		dolerror(vp->v_name);
547
		return;
548
	    }
549
	    lwb = i;
550
	    if (!*np)
551
		upb = lwb, np = STRstar;
552
	}
553
	if (*np == '*')
554
	    np++;
555
	else if (*np != '-')
556
	    stderror(ERR_MISSING, '-');
557
	else {
558
	    int i = upb;
559
560
	    np++;
561
	    if (Isdigit(*np)) {
562
		i = 0;
563
		while (Isdigit(*np))
564
		    i = i * 10 + *np++ - '0';
565
		if (i < 0 || i > upb) {
566
		    dolerror(vp->v_name);
567
		    return;
568
		}
569
	    }
570
	    if (i < lwb)
571
		upb = lwb - 1;
572
	    else
573
		upb = i;
574
	}
575
	if (lwb == 0) {
576
	    if (upb != 0) {
577
		dolerror(vp->v_name);
578
		return;
579
	    }
580
	    upb = -1;
581
	}
582
	if (*np)
583
	    stderror(ERR_SYNTAX);
584
    }
585
    else {
586
	if (subscr > 0) {
587
	    if (subscr > upb)
588
		lwb = 1, upb = 0;
589
	    else
590
		lwb = upb = subscr;
591
	}
592
	unDredc(c);
593
    }
594
    if (dimen) {
595
	Char   *cp = putn(upb - lwb + 1);
596
597
	addla(cp);
598
	free(cp);
599
    }
600
    else {
601
eatmod:
602
	fixDolMod();
603
	dolnxt = &vp->vec[lwb - 1];
604
	dolcnt = upb - lwb + 1;
605
    }
606
eatbrac:
607
    if (sc == '{') {
608
	c = Dredc();
609
	if (c != '}')
610
	    stderror(ERR_MISSING, '}');
611
    }
612
}
613
614
static void
615
fixDolMod(void)
616
{
617
    int c;
618
619
    c = DgetC(0);
620
    if (c == ':') {
621
	do {
622
	    c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
623
	    if (c == 'g' || c == 'a') {
624
		if (c == 'g')
625
		    dolmcnt = 10000;
626
		else
627
		    dolwcnt = 10000;
628
		c = DgetC(0);
629
	    }
630
	    if ((c == 'g' && dolmcnt != 10000) ||
631
		(c == 'a' && dolwcnt != 10000)) {
632
		if (c == 'g')
633
		    dolmcnt = 10000;
634
		else
635
		    dolwcnt = 10000;
636
		c = DgetC(0);
637
	    }
638
639
	    if (c == 's') {	/* [eichin:19910926.0755EST] */
640
		int delimcnt = 2;
641
		int delim = DgetC(0);
642
		dolmod[dolnmod++] = c;
643
		dolmod[dolnmod++] = delim;
644
645
		if (!delim || letter(delim)
646
		    || Isdigit(delim) || any(" \t\n", delim)) {
647
		    seterror(ERR_BADSUBST);
648
		    break;
649
		}
650
		while ((c = DgetC(0)) != (-1)) {
651
		    dolmod[dolnmod++] = c;
652
		    if(c == delim) delimcnt--;
653
		    if(!delimcnt) break;
654
		}
655
		if(delimcnt) {
656
		    seterror(ERR_BADSUBST);
657
		    break;
658
		}
659
		continue;
660
	    }
661
	    if (!any("htrqxes", c))
662
		stderror(ERR_BADMOD, c);
663
	    dolmod[dolnmod++] = c;
664
	    if (c == 'q')
665
		dolmcnt = 10000;
666
	}
667
	while ((c = DgetC(0)) == ':');
668
	unDredc(c);
669
    }
670
    else
671
	unDredc(c);
672
}
673
674
static void
675
setDolp(Char *cp)
676
{
677
    Char *dp;
678
    int i;
679
680
    if (dolnmod == 0 || dolmcnt == 0) {
681
	dolp = cp;
682
	return;
683
    }
684
    dp = cp = Strsave(cp);
685
    for (i = 0; i < dolnmod; i++) {
686
	/* handle s// [eichin:19910926.0510EST] */
687
	if(dolmod[i] == 's') {
688
	    int delim;
689
	    Char *lhsub, *rhsub, *np;
690
	    size_t lhlen = 0, rhlen = 0;
691
	    int didmod = 0;
692
693
	    delim = dolmod[++i];
694
	    if (!delim || letter(delim)
695
		|| Isdigit(delim) || any(" \t\n", delim)) {
696
		seterror(ERR_BADSUBST);
697
		break;
698
	    }
699
	    lhsub = &dolmod[++i];
700
	    while(dolmod[i] != delim && dolmod[++i]) {
701
		lhlen++;
702
	    }
703
	    dolmod[i] = 0;
704
	    rhsub = &dolmod[++i];
705
	    while(dolmod[i] != delim && dolmod[++i]) {
706
		rhlen++;
707
	    }
708
	    dolmod[i] = 0;
709
710
	    do {
711
		dp = Strstr(cp, lhsub);
712
		if (dp) {
713
		    size_t len = Strlen(cp) + 1 - lhlen + rhlen;
714
715
		    np = xreallocarray(NULL, len, sizeof(Char));
716
		    *dp = 0;
717
		    (void) Strlcpy(np, cp, len);
718
		    (void) Strlcat(np, rhsub, len);
719
		    (void) Strlcat(np, dp + lhlen, len);
720
721
		    free(cp);
722
		    dp = cp = np;
723
		    didmod = 1;
724
		} else {
725
		    /* should this do a seterror? */
726
		    break;
727
		}
728
	    }
729
	    while (dolwcnt == 10000);
730
	    /*
731
	     * restore dolmod for additional words
732
	     */
733
	    dolmod[i] = rhsub[-1] = delim;
734
	    if (didmod)
735
		dolmcnt--;
736
	    else
737
		break;
738
	} else {
739
	    int didmod = 0;
740
741
	    do {
742
		if ((dp = domod(cp, dolmod[i]))) {
743
		    didmod = 1;
744
		    if (Strcmp(cp, dp) == 0) {
745
			free(cp);
746
			cp = dp;
747
			break;
748
		    }
749
		    else {
750
			free(cp);
751
			cp = dp;
752
		    }
753
		}
754
		else
755
		    break;
756
	    }
757
	    while (dolwcnt == 10000);
758
	    dp = cp;
759
	    if (didmod)
760
		dolmcnt--;
761
	    else
762
		break;
763
	}
764
    }
765
766
    if (dp) {
767
	addla(dp);
768
	free(dp);
769
    }
770
    else
771
	addla(cp);
772
773
    dolp = STRNULL;
774
    if (seterr)
775
	stderror(ERR_OLD);
776
}
777
778
static void
779
unDredc(int c)
780
{
781
782
    Dpeekrd = c;
783
}
784
785
static int
786
Dredc(void)
787
{
788
    int c;
789
790
    if ((c = Dpeekrd) != '\0') {
791
	Dpeekrd = 0;
792
	return (c);
793
    }
794
    if (Dcp && (c = *Dcp++))
795
	return (c & (QUOTE | TRIM));
796
    if (*Dvp == 0) {
797
	Dcp = 0;
798
	return (DEOF);
799
    }
800
    Dcp = *Dvp++;
801
    return (' ');
802
}
803
804
static void
805
Dtestq(int c)
806
{
807
808
    if (cmap(c, QUOTES))
809
	gflag = 1;
810
}
811
812
/*
813
 * Form a shell temporary file (in unit 0) from the words
814
 * of the shell input up to EOF or a line the same as "term".
815
 * Unit 0 should have been closed before this call.
816
 */
817
void
818
/*ARGSUSED*/
819
heredoc(Char *term)
820
{
821
    int c;
822
    Char   *Dv[2];
823
    Char    obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
824
    int     ocnt, lcnt, mcnt;
825
    Char *lbp, *obp, *mbp;
826
    Char  **vp;
827
    bool    quoted;
828
    char   tmp[] = "/tmp/sh.XXXXXXXX";
829
830
    if (mkstemp(tmp) < 0)
831
	stderror(ERR_SYSTEM, tmp, strerror(errno));
832
    (void) unlink(tmp);		/* 0 0 inode! */
833
    Dv[0] = term;
834
    Dv[1] = NULL;
835
    gflag = 0;
836
    trim(Dv);
837
    rscan(Dv, Dtestq);
838
    quoted = gflag;
839
    ocnt = BUFSIZ;
840
    obp = obuf;
841
    for (;;) {
842
	/*
843
	 * Read up a line
844
	 */
845
	lbp = lbuf;
846
	lcnt = BUFSIZ - 4;
847
	for (;;) {
848
	    c = readc(1);	/* 1 -> Want EOF returns */
849
	    if (c < 0 || c == '\n')
850
		break;
851
	    if ((c &= TRIM) != '\0') {
852
		*lbp++ = c;
853
		if (--lcnt < 0) {
854
		    setname("<<");
855
		    stderror(ERR_NAME | ERR_OVERFLOW);
856
		}
857
	    }
858
	}
859
	*lbp = 0;
860
861
	/*
862
	 * Check for EOF or compare to terminator -- before expansion
863
	 */
864
	if (c < 0 || eq(lbuf, term)) {
865
	    (void) write(STDIN_FILENO, short2str(obuf),
866
	        (size_t) (BUFSIZ - ocnt));
867
	    (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET);
868
	    return;
869
	}
870
871
	/*
872
	 * If term was quoted or -n just pass it on
873
	 */
874
	if (quoted || noexec) {
875
	    *lbp++ = '\n';
876
	    *lbp = 0;
877
	    for (lbp = lbuf; (c = *lbp++) != '\0';) {
878
		*obp++ = c;
879
		if (--ocnt == 0) {
880
		    (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
881
		    obp = obuf;
882
		    ocnt = BUFSIZ;
883
		}
884
	    }
885
	    continue;
886
	}
887
888
	/*
889
	 * Term wasn't quoted so variable and then command expand the input
890
	 * line
891
	 */
892
	Dcp = lbuf;
893
	Dvp = Dv + 1;
894
	mbp = mbuf;
895
	mcnt = BUFSIZ - 4;
896
	for (;;) {
897
	    c = DgetC(DODOL);
898
	    if (c == DEOF)
899
		break;
900
	    if ((c &= TRIM) == 0)
901
		continue;
902
	    /* \ quotes \ $ ` here */
903
	    if (c == '\\') {
904
		c = DgetC(0);
905
		if (!any("$\\`", c))
906
		    unDgetC(c | QUOTE), c = '\\';
907
		else
908
		    c |= QUOTE;
909
	    }
910
	    *mbp++ = c;
911
	    if (--mcnt == 0) {
912
		setname("<<");
913
		stderror(ERR_NAME | ERR_OVERFLOW);
914
	    }
915
	}
916
	*mbp++ = 0;
917
918
	/*
919
	 * If any ` in line do command substitution
920
	 */
921
	mbp = mbuf;
922
	if (any(short2str(mbp), '`')) {
923
	    /*
924
	     * 1 arg to dobackp causes substitution to be literal. Words are
925
	     * broken only at newlines so that all blanks and tabs are
926
	     * preserved.  Blank lines (null words) are not discarded.
927
	     */
928
	    vp = dobackp(mbuf, 1);
929
	}
930
	else
931
	    /* Setup trivial vector similar to return of dobackp */
932
	    Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
933
934
	/*
935
	 * Resurrect the words from the command substitution each separated by
936
	 * a newline.  Note that the last newline of a command substitution
937
	 * will have been discarded, but we put a newline after the last word
938
	 * because this represents the newline after the last input line!
939
	 */
940
	for (; *vp; vp++) {
941
	    for (mbp = *vp; *mbp; mbp++) {
942
		*obp++ = *mbp & TRIM;
943
		if (--ocnt == 0) {
944
		    (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
945
		    obp = obuf;
946
		    ocnt = BUFSIZ;
947
		}
948
	    }
949
	    *obp++ = '\n';
950
	    if (--ocnt == 0) {
951
		(void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
952
		obp = obuf;
953
		ocnt = BUFSIZ;
954
	    }
955
	}
956
	if (pargv)
957
	    blkfree(pargv), pargv = 0;
958
    }
959
}