xref: /dragonfly/contrib/tcsh-6/sh.dol.c (revision d6ab524c)
17d8fb588SMatthias Schmidt /*
27d8fb588SMatthias Schmidt  * sh.dol.c: Variable substitutions
37d8fb588SMatthias Schmidt  */
47d8fb588SMatthias Schmidt /*-
57d8fb588SMatthias Schmidt  * Copyright (c) 1980, 1991 The Regents of the University of California.
67d8fb588SMatthias Schmidt  * All rights reserved.
77d8fb588SMatthias Schmidt  *
87d8fb588SMatthias Schmidt  * Redistribution and use in source and binary forms, with or without
97d8fb588SMatthias Schmidt  * modification, are permitted provided that the following conditions
107d8fb588SMatthias Schmidt  * are met:
117d8fb588SMatthias Schmidt  * 1. Redistributions of source code must retain the above copyright
127d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer.
137d8fb588SMatthias Schmidt  * 2. Redistributions in binary form must reproduce the above copyright
147d8fb588SMatthias Schmidt  *    notice, this list of conditions and the following disclaimer in the
157d8fb588SMatthias Schmidt  *    documentation and/or other materials provided with the distribution.
167d8fb588SMatthias Schmidt  * 3. Neither the name of the University nor the names of its contributors
177d8fb588SMatthias Schmidt  *    may be used to endorse or promote products derived from this software
187d8fb588SMatthias Schmidt  *    without specific prior written permission.
197d8fb588SMatthias Schmidt  *
207d8fb588SMatthias Schmidt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
217d8fb588SMatthias Schmidt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
227d8fb588SMatthias Schmidt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
237d8fb588SMatthias Schmidt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
247d8fb588SMatthias Schmidt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
257d8fb588SMatthias Schmidt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
267d8fb588SMatthias Schmidt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
277d8fb588SMatthias Schmidt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
287d8fb588SMatthias Schmidt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
297d8fb588SMatthias Schmidt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
307d8fb588SMatthias Schmidt  * SUCH DAMAGE.
317d8fb588SMatthias Schmidt  */
327d8fb588SMatthias Schmidt #include "sh.h"
33*d6ab524cSAntonio Huete Jimenez #include "ed.h"
34*d6ab524cSAntonio Huete Jimenez #include "tw.h"
357d8fb588SMatthias Schmidt 
367d8fb588SMatthias Schmidt /*
377d8fb588SMatthias Schmidt  * C shell
387d8fb588SMatthias Schmidt  */
397d8fb588SMatthias Schmidt 
407d8fb588SMatthias Schmidt /*
417d8fb588SMatthias Schmidt  * These routines perform variable substitution and quoting via ' and ".
427d8fb588SMatthias Schmidt  * To this point these constructs have been preserved in the divided
437d8fb588SMatthias Schmidt  * input words.  Here we expand variables and turn quoting via ' and " into
447d8fb588SMatthias Schmidt  * QUOTE bits on characters (which prevent further interpretation).
457d8fb588SMatthias Schmidt  * If the `:q' modifier was applied during history expansion, then
467d8fb588SMatthias Schmidt  * some QUOTEing may have occurred already, so we dont "trim()" here.
477d8fb588SMatthias Schmidt  */
487d8fb588SMatthias Schmidt 
4994afa86dSJohn Marino static eChar Dpeekc;		/* Peek for DgetC */
507d8fb588SMatthias Schmidt static eChar Dpeekrd;		/* Peek for Dreadc */
517d8fb588SMatthias Schmidt static Char *Dcp, *const *Dvp;	/* Input vector for Dreadc */
527d8fb588SMatthias Schmidt 
537d8fb588SMatthias Schmidt #define	DEOF	CHAR_ERR
547d8fb588SMatthias Schmidt 
557d8fb588SMatthias Schmidt #define	unDgetC(c)	Dpeekc = c
567d8fb588SMatthias Schmidt 
577d8fb588SMatthias Schmidt #define QUOTES		(_QF|_QB|_ESC)	/* \ ' " ` */
587d8fb588SMatthias Schmidt 
597d8fb588SMatthias Schmidt /*
607d8fb588SMatthias Schmidt  * The following variables give the information about the current
617d8fb588SMatthias Schmidt  * $ expansion, recording the current word position, the remaining
627d8fb588SMatthias Schmidt  * words within this expansion, the count of remaining words, and the
637d8fb588SMatthias Schmidt  * information about any : modifier which is being applied.
647d8fb588SMatthias Schmidt  */
657d8fb588SMatthias Schmidt static Char *dolp;		/* Remaining chars from this word */
667d8fb588SMatthias Schmidt static Char **dolnxt;		/* Further words */
677d8fb588SMatthias Schmidt static int dolcnt;		/* Count of further words */
687d8fb588SMatthias Schmidt static struct Strbuf dolmod; /* = Strbuf_INIT; : modifier characters */
69*d6ab524cSAntonio Huete Jimenez 
70*d6ab524cSAntonio Huete Jimenez static int ndolflags;		/* keep track of mod counts for each modifier */
71*d6ab524cSAntonio Huete Jimenez static int *dolmcnts;		/* :gx -> INT_MAX, else 1 */
72*d6ab524cSAntonio Huete Jimenez static int *dolaflags;		/* :ax -> 1, else 0 */
737d8fb588SMatthias Schmidt 
747d8fb588SMatthias Schmidt static	Char	 **Dfix2	(Char *const *);
757d8fb588SMatthias Schmidt static	int 	 Dpack		(struct Strbuf *);
767d8fb588SMatthias Schmidt static	int	 Dword		(struct blk_buf *);
777d8fb588SMatthias Schmidt static	void	 dolerror	(Char *);
787d8fb588SMatthias Schmidt static	eChar	 DgetC		(int);
797d8fb588SMatthias Schmidt static	void	 Dgetdol	(void);
807d8fb588SMatthias Schmidt static	void	 fixDolMod	(void);
817d8fb588SMatthias Schmidt static	void	 setDolp	(Char *);
827d8fb588SMatthias Schmidt static	void	 unDredc	(eChar);
837d8fb588SMatthias Schmidt static	eChar	 Dredc		(void);
847d8fb588SMatthias Schmidt static	void	 Dtestq		(Char);
857d8fb588SMatthias Schmidt 
867d8fb588SMatthias Schmidt /*
877d8fb588SMatthias Schmidt  * Fix up the $ expansions and quotations in the
887d8fb588SMatthias Schmidt  * argument list to command t.
897d8fb588SMatthias Schmidt  */
907d8fb588SMatthias Schmidt void
Dfix(struct command * t)917d8fb588SMatthias Schmidt Dfix(struct command *t)
927d8fb588SMatthias Schmidt {
937d8fb588SMatthias Schmidt     Char **pp;
947d8fb588SMatthias Schmidt     Char *p;
957d8fb588SMatthias Schmidt 
967d8fb588SMatthias Schmidt     if (noexec)
977d8fb588SMatthias Schmidt 	return;
987d8fb588SMatthias Schmidt     /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
997d8fb588SMatthias Schmidt     for (pp = t->t_dcom; (p = *pp++) != NULL;) {
1007d8fb588SMatthias Schmidt 	for (; *p; p++) {
1017d8fb588SMatthias Schmidt 	    if (cmap(*p, _DOL | QUOTES)) {	/* $, \, ', ", ` */
1027d8fb588SMatthias Schmidt 		Char **expanded;
1037d8fb588SMatthias Schmidt 
1047d8fb588SMatthias Schmidt 		expanded = Dfix2(t->t_dcom);	/* found one */
1057d8fb588SMatthias Schmidt 		blkfree(t->t_dcom);
1067d8fb588SMatthias Schmidt 		t->t_dcom = expanded;
1077d8fb588SMatthias Schmidt 		return;
1087d8fb588SMatthias Schmidt 	    }
1097d8fb588SMatthias Schmidt 	}
1107d8fb588SMatthias Schmidt     }
1117d8fb588SMatthias Schmidt }
1127d8fb588SMatthias Schmidt 
1137d8fb588SMatthias Schmidt /*
1147d8fb588SMatthias Schmidt  * $ substitute one word, for i/o redirection
1157d8fb588SMatthias Schmidt  */
1167d8fb588SMatthias Schmidt Char   *
Dfix1(Char * cp)1177d8fb588SMatthias Schmidt Dfix1(Char *cp)
1187d8fb588SMatthias Schmidt {
1197d8fb588SMatthias Schmidt     Char *Dv[2], **expanded;
1207d8fb588SMatthias Schmidt 
1217d8fb588SMatthias Schmidt     if (noexec)
1227d8fb588SMatthias Schmidt 	return (0);
1237d8fb588SMatthias Schmidt     Dv[0] = cp;
1247d8fb588SMatthias Schmidt     Dv[1] = NULL;
1257d8fb588SMatthias Schmidt     expanded = Dfix2(Dv);
1267d8fb588SMatthias Schmidt     if (expanded[0] == NULL || expanded[1] != NULL) {
1277d8fb588SMatthias Schmidt 	blkfree(expanded);
1287d8fb588SMatthias Schmidt 	setname(short2str(cp));
1297d8fb588SMatthias Schmidt 	stderror(ERR_NAME | ERR_AMBIG);
1307d8fb588SMatthias Schmidt     }
1317d8fb588SMatthias Schmidt     cp = Strsave(expanded[0]);
1327d8fb588SMatthias Schmidt     blkfree(expanded);
1337d8fb588SMatthias Schmidt     return (cp);
1347d8fb588SMatthias Schmidt }
1357d8fb588SMatthias Schmidt 
1367d8fb588SMatthias Schmidt /*
1377d8fb588SMatthias Schmidt  * Subroutine to do actual fixing after state initialization.
1387d8fb588SMatthias Schmidt  */
1397d8fb588SMatthias Schmidt static Char **
Dfix2(Char * const * v)1407d8fb588SMatthias Schmidt Dfix2(Char *const *v)
1417d8fb588SMatthias Schmidt {
14257e3f2b5SSimon 'corecode' Schubert     struct blk_buf *bb = bb_alloc();
14357e3f2b5SSimon 'corecode' Schubert     Char **vec;
1447d8fb588SMatthias Schmidt 
1457d8fb588SMatthias Schmidt     Dvp = v;
1467d8fb588SMatthias Schmidt     Dcp = STRNULL;		/* Setup input vector for Dreadc */
1477d8fb588SMatthias Schmidt     unDgetC(0);
1487d8fb588SMatthias Schmidt     unDredc(0);			/* Clear out any old peeks (at error) */
1497d8fb588SMatthias Schmidt     dolp = 0;
1507d8fb588SMatthias Schmidt     dolcnt = 0;			/* Clear out residual $ expands (...) */
15157e3f2b5SSimon 'corecode' Schubert     cleanup_push(bb, bb_free);
15257e3f2b5SSimon 'corecode' Schubert     while (Dword(bb))
1537d8fb588SMatthias Schmidt 	continue;
15457e3f2b5SSimon 'corecode' Schubert     cleanup_ignore(bb);
15557e3f2b5SSimon 'corecode' Schubert     cleanup_until(bb);
15657e3f2b5SSimon 'corecode' Schubert     vec = bb_finish(bb);
15757e3f2b5SSimon 'corecode' Schubert     xfree(bb);
15857e3f2b5SSimon 'corecode' Schubert     return vec;
1597d8fb588SMatthias Schmidt }
1607d8fb588SMatthias Schmidt 
1617d8fb588SMatthias Schmidt /*
1627d8fb588SMatthias Schmidt  * Pack up more characters in this word
1637d8fb588SMatthias Schmidt  */
1647d8fb588SMatthias Schmidt static int
Dpack(struct Strbuf * wbuf)1657d8fb588SMatthias Schmidt Dpack(struct Strbuf *wbuf)
1667d8fb588SMatthias Schmidt {
1677d8fb588SMatthias Schmidt     eChar c;
1687d8fb588SMatthias Schmidt 
1697d8fb588SMatthias Schmidt     for (;;) {
1707d8fb588SMatthias Schmidt 	c = DgetC(DODOL);
1717d8fb588SMatthias Schmidt 	if (c == '\\') {
1727d8fb588SMatthias Schmidt 	    c = DgetC(0);
1737d8fb588SMatthias Schmidt 	    if (c == DEOF) {
1747d8fb588SMatthias Schmidt 		unDredc(c);
1757d8fb588SMatthias Schmidt 		return 1;
1767d8fb588SMatthias Schmidt 	    }
1777d8fb588SMatthias Schmidt 	    if (c == '\n')
1787d8fb588SMatthias Schmidt 		c = ' ';
1797d8fb588SMatthias Schmidt 	    else
1807d8fb588SMatthias Schmidt 		c |= QUOTE;
1817d8fb588SMatthias Schmidt 	}
1827d8fb588SMatthias Schmidt 	if (c == DEOF) {
1837d8fb588SMatthias Schmidt 	    unDredc(c);
1847d8fb588SMatthias Schmidt 	    return 1;
1857d8fb588SMatthias Schmidt 	}
1867d8fb588SMatthias Schmidt 	if (cmap(c, _SP | _NL | _QF | _QB)) {	/* sp \t\n'"` */
1877d8fb588SMatthias Schmidt 	    unDgetC(c);
1887d8fb588SMatthias Schmidt 	    if (cmap(c, QUOTES))
1897d8fb588SMatthias Schmidt 		return 0;
1907d8fb588SMatthias Schmidt 	    return 1;
1917d8fb588SMatthias Schmidt 	}
1927d8fb588SMatthias Schmidt 	Strbuf_append1(wbuf, (Char) c);
1937d8fb588SMatthias Schmidt     }
1947d8fb588SMatthias Schmidt }
1957d8fb588SMatthias Schmidt 
1967d8fb588SMatthias Schmidt /*
1977d8fb588SMatthias Schmidt  * Get a word.  This routine is analogous to the routine
1987d8fb588SMatthias Schmidt  * word() in sh.lex.c for the main lexical input.  One difference
1997d8fb588SMatthias Schmidt  * here is that we don't get a newline to terminate our expansion.
2007d8fb588SMatthias Schmidt  * Rather, DgetC will return a DEOF when we hit the end-of-input.
2017d8fb588SMatthias Schmidt  */
2027d8fb588SMatthias Schmidt static int
Dword(struct blk_buf * bb)2037d8fb588SMatthias Schmidt Dword(struct blk_buf *bb)
2047d8fb588SMatthias Schmidt {
2057d8fb588SMatthias Schmidt     eChar c, c1;
20657e3f2b5SSimon 'corecode' Schubert     struct Strbuf *wbuf = Strbuf_alloc();
2077d8fb588SMatthias Schmidt     int dolflg;
2087d8fb588SMatthias Schmidt     int    sofar = 0;
20957e3f2b5SSimon 'corecode' Schubert     Char *str;
2107d8fb588SMatthias Schmidt 
21157e3f2b5SSimon 'corecode' Schubert     cleanup_push(wbuf, Strbuf_free);
2127d8fb588SMatthias Schmidt     for (;;) {
2137d8fb588SMatthias Schmidt 	c = DgetC(DODOL);
2147d8fb588SMatthias Schmidt 	switch (c) {
2157d8fb588SMatthias Schmidt 
2167d8fb588SMatthias Schmidt 	case DEOF:
2177d8fb588SMatthias Schmidt 	    if (sofar == 0) {
21857e3f2b5SSimon 'corecode' Schubert 		cleanup_until(wbuf);
2197d8fb588SMatthias Schmidt 		return (0);
2207d8fb588SMatthias Schmidt 	    }
2217d8fb588SMatthias Schmidt 	    /* finish this word and catch the code above the next time */
2227d8fb588SMatthias Schmidt 	    unDredc(c);
2237d8fb588SMatthias Schmidt 	    /*FALLTHROUGH*/
2247d8fb588SMatthias Schmidt 
2257d8fb588SMatthias Schmidt 	case '\n':
2267d8fb588SMatthias Schmidt 	    goto end;
2277d8fb588SMatthias Schmidt 
2287d8fb588SMatthias Schmidt 	case ' ':
2297d8fb588SMatthias Schmidt 	case '\t':
2307d8fb588SMatthias Schmidt 	    continue;
2317d8fb588SMatthias Schmidt 
2327d8fb588SMatthias Schmidt 	case '`':
2337d8fb588SMatthias Schmidt 	    /* We preserve ` quotations which are done yet later */
23457e3f2b5SSimon 'corecode' Schubert 	    Strbuf_append1(wbuf, (Char) c);
2357d8fb588SMatthias Schmidt 	    /*FALLTHROUGH*/
2367d8fb588SMatthias Schmidt 	case '\'':
2377d8fb588SMatthias Schmidt 	case '"':
2387d8fb588SMatthias Schmidt 	    /*
2397d8fb588SMatthias Schmidt 	     * Note that DgetC never returns a QUOTES character from an
2407d8fb588SMatthias Schmidt 	     * expansion, so only true input quotes will get us here or out.
2417d8fb588SMatthias Schmidt 	     */
2427d8fb588SMatthias Schmidt 	    c1 = c;
2437d8fb588SMatthias Schmidt 	    dolflg = c1 == '"' ? DODOL : 0;
2447d8fb588SMatthias Schmidt 	    for (;;) {
2457d8fb588SMatthias Schmidt 		c = DgetC(dolflg);
2467d8fb588SMatthias Schmidt 		if (c == c1)
2477d8fb588SMatthias Schmidt 		    break;
24857e3f2b5SSimon 'corecode' Schubert 		if (c == '\n' || c == DEOF) {
24957e3f2b5SSimon 'corecode' Schubert 		    cleanup_until(bb);
2507d8fb588SMatthias Schmidt 		    stderror(ERR_UNMATCHED, (int)c1);
25157e3f2b5SSimon 'corecode' Schubert 		}
2527d8fb588SMatthias Schmidt 		if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) {
25357e3f2b5SSimon 'corecode' Schubert 		    if (wbuf->len != 0 && (wbuf->s[wbuf->len - 1] & TRIM) == '\\')
25457e3f2b5SSimon 'corecode' Schubert 			wbuf->len--;
2557d8fb588SMatthias Schmidt 		}
2567d8fb588SMatthias Schmidt 		switch (c1) {
2577d8fb588SMatthias Schmidt 
2587d8fb588SMatthias Schmidt 		case '"':
2597d8fb588SMatthias Schmidt 		    /*
2607d8fb588SMatthias Schmidt 		     * Leave any `s alone for later. Other chars are all
2617d8fb588SMatthias Schmidt 		     * quoted, thus `...` can tell it was within "...".
2627d8fb588SMatthias Schmidt 		     */
26357e3f2b5SSimon 'corecode' Schubert 		    Strbuf_append1(wbuf, c == '`' ? '`' : c | QUOTE);
2647d8fb588SMatthias Schmidt 		    break;
2657d8fb588SMatthias Schmidt 
2667d8fb588SMatthias Schmidt 		case '\'':
2677d8fb588SMatthias Schmidt 		    /* Prevent all further interpretation */
26857e3f2b5SSimon 'corecode' Schubert 		    Strbuf_append1(wbuf, c | QUOTE);
2697d8fb588SMatthias Schmidt 		    break;
2707d8fb588SMatthias Schmidt 
2717d8fb588SMatthias Schmidt 		case '`':
2727d8fb588SMatthias Schmidt 		    /* Leave all text alone for later */
27357e3f2b5SSimon 'corecode' Schubert 		    Strbuf_append1(wbuf, (Char) c);
2747d8fb588SMatthias Schmidt 		    break;
2757d8fb588SMatthias Schmidt 
2767d8fb588SMatthias Schmidt 		default:
2777d8fb588SMatthias Schmidt 		    break;
2787d8fb588SMatthias Schmidt 		}
2797d8fb588SMatthias Schmidt 	    }
2807d8fb588SMatthias Schmidt 	    if (c1 == '`')
28157e3f2b5SSimon 'corecode' Schubert 		Strbuf_append1(wbuf, '`');
2827d8fb588SMatthias Schmidt 	    sofar = 1;
28357e3f2b5SSimon 'corecode' Schubert 	    if (Dpack(wbuf) != 0)
2847d8fb588SMatthias Schmidt 		goto end;
2857d8fb588SMatthias Schmidt 	    continue;
2867d8fb588SMatthias Schmidt 
2877d8fb588SMatthias Schmidt 	case '\\':
2887d8fb588SMatthias Schmidt 	    c = DgetC(0);	/* No $ subst! */
2897d8fb588SMatthias Schmidt 	    if (c == '\n' || c == DEOF)
2907d8fb588SMatthias Schmidt 		continue;
2917d8fb588SMatthias Schmidt 	    c |= QUOTE;
2927d8fb588SMatthias Schmidt 	    break;
2937d8fb588SMatthias Schmidt 
2947d8fb588SMatthias Schmidt 	default:
2957d8fb588SMatthias Schmidt 	    break;
2967d8fb588SMatthias Schmidt 	}
2977d8fb588SMatthias Schmidt 	unDgetC(c);
2987d8fb588SMatthias Schmidt 	sofar = 1;
29957e3f2b5SSimon 'corecode' Schubert 	if (Dpack(wbuf) != 0)
3007d8fb588SMatthias Schmidt 	    goto end;
3017d8fb588SMatthias Schmidt     }
3027d8fb588SMatthias Schmidt 
3037d8fb588SMatthias Schmidt  end:
30457e3f2b5SSimon 'corecode' Schubert     cleanup_ignore(wbuf);
30557e3f2b5SSimon 'corecode' Schubert     cleanup_until(wbuf);
30657e3f2b5SSimon 'corecode' Schubert     str = Strbuf_finish(wbuf);
30757e3f2b5SSimon 'corecode' Schubert     bb_append(bb, str);
30857e3f2b5SSimon 'corecode' Schubert     xfree(wbuf);
3097d8fb588SMatthias Schmidt     return 1;
3107d8fb588SMatthias Schmidt }
3117d8fb588SMatthias Schmidt 
3127d8fb588SMatthias Schmidt 
3137d8fb588SMatthias Schmidt /*
3147d8fb588SMatthias Schmidt  * Get a character, performing $ substitution unless flag is 0.
3157d8fb588SMatthias Schmidt  * Any QUOTES character which is returned from a $ expansion is
3167d8fb588SMatthias Schmidt  * QUOTEd so that it will not be recognized above.
3177d8fb588SMatthias Schmidt  */
3187d8fb588SMatthias Schmidt static eChar
DgetC(int flag)3197d8fb588SMatthias Schmidt DgetC(int flag)
3207d8fb588SMatthias Schmidt {
32194afa86dSJohn Marino     eChar c;
3227d8fb588SMatthias Schmidt 
3237d8fb588SMatthias Schmidt top:
3247d8fb588SMatthias Schmidt     if ((c = Dpeekc) != 0) {
3257d8fb588SMatthias Schmidt 	Dpeekc = 0;
3267d8fb588SMatthias Schmidt 	return (c);
3277d8fb588SMatthias Schmidt     }
3287d8fb588SMatthias Schmidt     if (lap < labuf.len) {
3297d8fb588SMatthias Schmidt 	c = labuf.s[lap++] & (QUOTE | TRIM);
3307d8fb588SMatthias Schmidt quotspec:
3317d8fb588SMatthias Schmidt 	if (cmap(c, QUOTES))
3327d8fb588SMatthias Schmidt 	    return (c | QUOTE);
3337d8fb588SMatthias Schmidt 	return (c);
3347d8fb588SMatthias Schmidt     }
3357d8fb588SMatthias Schmidt     if (dolp) {
3367d8fb588SMatthias Schmidt 	if ((c = *dolp++ & (QUOTE | TRIM)) != 0)
3377d8fb588SMatthias Schmidt 	    goto quotspec;
3387d8fb588SMatthias Schmidt 	if (dolcnt > 0) {
3397d8fb588SMatthias Schmidt 	    setDolp(*dolnxt++);
3407d8fb588SMatthias Schmidt 	    --dolcnt;
3417d8fb588SMatthias Schmidt 	    return (' ');
3427d8fb588SMatthias Schmidt 	}
3437d8fb588SMatthias Schmidt 	dolp = 0;
3447d8fb588SMatthias Schmidt     }
3457d8fb588SMatthias Schmidt     if (dolcnt > 0) {
3467d8fb588SMatthias Schmidt 	setDolp(*dolnxt++);
3477d8fb588SMatthias Schmidt 	--dolcnt;
3487d8fb588SMatthias Schmidt 	goto top;
3497d8fb588SMatthias Schmidt     }
3507d8fb588SMatthias Schmidt     c = Dredc();
3517d8fb588SMatthias Schmidt     if (c == '$' && flag) {
3527d8fb588SMatthias Schmidt 	Dgetdol();
3537d8fb588SMatthias Schmidt 	goto top;
3547d8fb588SMatthias Schmidt     }
3557d8fb588SMatthias Schmidt     return (c);
3567d8fb588SMatthias Schmidt }
3577d8fb588SMatthias Schmidt 
3587d8fb588SMatthias Schmidt static Char *nulvec[] = { NULL };
3597d8fb588SMatthias Schmidt static struct varent nulargv = {nulvec, STRargv, VAR_READWRITE,
3607d8fb588SMatthias Schmidt 				{ NULL, NULL, NULL }, 0 };
3617d8fb588SMatthias Schmidt 
3627d8fb588SMatthias Schmidt static void
dolerror(Char * s)3637d8fb588SMatthias Schmidt dolerror(Char *s)
3647d8fb588SMatthias Schmidt {
3657d8fb588SMatthias Schmidt     setname(short2str(s));
3667d8fb588SMatthias Schmidt     stderror(ERR_NAME | ERR_RANGE);
3677d8fb588SMatthias Schmidt }
3687d8fb588SMatthias Schmidt 
3697d8fb588SMatthias Schmidt /*
3707d8fb588SMatthias Schmidt  * Handle the multitudinous $ expansion forms.
3717d8fb588SMatthias Schmidt  * Ugh.
3727d8fb588SMatthias Schmidt  */
3737d8fb588SMatthias Schmidt static void
Dgetdol(void)3747d8fb588SMatthias Schmidt Dgetdol(void)
3757d8fb588SMatthias Schmidt {
3767d8fb588SMatthias Schmidt     Char *np;
3777d8fb588SMatthias Schmidt     struct varent *vp = NULL;
37857e3f2b5SSimon 'corecode' Schubert     struct Strbuf *name = Strbuf_alloc();
3797d8fb588SMatthias Schmidt     eChar   c, sc;
3807d8fb588SMatthias Schmidt     int     subscr = 0, lwb = 1, upb = 0;
3817d8fb588SMatthias Schmidt     int    dimen = 0, bitset = 0, length = 0;
3827d8fb588SMatthias Schmidt     static Char *dolbang = NULL;
3837d8fb588SMatthias Schmidt 
38457e3f2b5SSimon 'corecode' Schubert     cleanup_push(name, Strbuf_free);
385*d6ab524cSAntonio Huete Jimenez     dolmod.len = ndolflags = 0;
3867d8fb588SMatthias Schmidt     c = sc = DgetC(0);
3877d8fb588SMatthias Schmidt     if (c == DEOF) {
3887d8fb588SMatthias Schmidt       stderror(ERR_SYNTAX);
3897d8fb588SMatthias Schmidt       return;
3907d8fb588SMatthias Schmidt     }
391*d6ab524cSAntonio Huete Jimenez     if ((c & TRIM) == '\'') {
392*d6ab524cSAntonio Huete Jimenez 	const Char *cp;
393*d6ab524cSAntonio Huete Jimenez 	struct Strbuf *expanded = Strbuf_alloc();
394*d6ab524cSAntonio Huete Jimenez 
395*d6ab524cSAntonio Huete Jimenez 	cleanup_push(expanded, Strbuf_free);
396*d6ab524cSAntonio Huete Jimenez 	for (;;) {
397*d6ab524cSAntonio Huete Jimenez 	    c = DgetC(0);
398*d6ab524cSAntonio Huete Jimenez 	    if ((c & TRIM) == '\'')
399*d6ab524cSAntonio Huete Jimenez 		break;
400*d6ab524cSAntonio Huete Jimenez 	    if ((c & TRIM) == '\\') {
401*d6ab524cSAntonio Huete Jimenez 		Strbuf_append1(name, (Char) c);
402*d6ab524cSAntonio Huete Jimenez 		c = DgetC(0);
403*d6ab524cSAntonio Huete Jimenez 	    }
404*d6ab524cSAntonio Huete Jimenez 	    if (c == '\n' || c == DEOF) {
405*d6ab524cSAntonio Huete Jimenez 		cleanup_until(name);
406*d6ab524cSAntonio Huete Jimenez 		stderror(ERR_MISSING, '\'');
407*d6ab524cSAntonio Huete Jimenez 		return;
408*d6ab524cSAntonio Huete Jimenez 	    }
409*d6ab524cSAntonio Huete Jimenez 	    Strbuf_append1(name, (Char) c);
410*d6ab524cSAntonio Huete Jimenez 	}
411*d6ab524cSAntonio Huete Jimenez 	Strbuf_terminate(name);
412*d6ab524cSAntonio Huete Jimenez 	for (cp = name->s; (c = *cp) != 0; cp++) {
413*d6ab524cSAntonio Huete Jimenez 	    if (c == '\\' && (c = parseescape(&cp, TRUE)) == CHAR_ERR)
414*d6ab524cSAntonio Huete Jimenez 		c = '\\';
415*d6ab524cSAntonio Huete Jimenez 	    Strbuf_append1(expanded, (Char) c | QUOTE);
416*d6ab524cSAntonio Huete Jimenez 	}
417*d6ab524cSAntonio Huete Jimenez 	Strbuf_terminate(expanded);
418*d6ab524cSAntonio Huete Jimenez 	np = Strsave(expanded->s);
419*d6ab524cSAntonio Huete Jimenez 	cleanup_until(name);
420*d6ab524cSAntonio Huete Jimenez 	addla(np);
421*d6ab524cSAntonio Huete Jimenez 	return;
422*d6ab524cSAntonio Huete Jimenez     }
4237d8fb588SMatthias Schmidt     if (c == '{')
4247d8fb588SMatthias Schmidt 	c = DgetC(0);		/* sc is { to take } later */
4257d8fb588SMatthias Schmidt     if ((c & TRIM) == '#')
4267d8fb588SMatthias Schmidt 	dimen++, c = DgetC(0);	/* $# takes dimension */
4277d8fb588SMatthias Schmidt     else if (c == '?')
4287d8fb588SMatthias Schmidt 	bitset++, c = DgetC(0);	/* $? tests existence */
4297d8fb588SMatthias Schmidt     else if (c == '%')
4307d8fb588SMatthias Schmidt 	length++, c = DgetC(0); /* $% returns length in chars */
4317d8fb588SMatthias Schmidt     switch (c) {
4327d8fb588SMatthias Schmidt 
4337d8fb588SMatthias Schmidt     case '!':
4347d8fb588SMatthias Schmidt 	if (dimen || bitset || length)
4357d8fb588SMatthias Schmidt 	    stderror(ERR_SYNTAX);
4367d8fb588SMatthias Schmidt 	if (backpid != 0) {
4377d8fb588SMatthias Schmidt 	    xfree(dolbang);
43894afa86dSJohn Marino 	    setDolp(dolbang = putn((tcsh_number_t)backpid));
4397d8fb588SMatthias Schmidt 	}
44057e3f2b5SSimon 'corecode' Schubert 	cleanup_until(name);
4417d8fb588SMatthias Schmidt 	goto eatbrac;
4427d8fb588SMatthias Schmidt 
4437d8fb588SMatthias Schmidt     case '$':
4447d8fb588SMatthias Schmidt 	if (dimen || bitset || length)
4457d8fb588SMatthias Schmidt 	    stderror(ERR_SYNTAX);
4467d8fb588SMatthias Schmidt 	setDolp(doldol);
44757e3f2b5SSimon 'corecode' Schubert 	cleanup_until(name);
4487d8fb588SMatthias Schmidt 	goto eatbrac;
4497d8fb588SMatthias Schmidt 
4507d8fb588SMatthias Schmidt     case '<'|QUOTE: {
4517d8fb588SMatthias Schmidt 	static struct Strbuf wbuf; /* = Strbuf_INIT; */
4527d8fb588SMatthias Schmidt 
4537d8fb588SMatthias Schmidt 	if (bitset)
4547d8fb588SMatthias Schmidt 	    stderror(ERR_NOTALLOWED, "$?<");
4557d8fb588SMatthias Schmidt 	if (dimen)
4567d8fb588SMatthias Schmidt 	    stderror(ERR_NOTALLOWED, "$#<");
4577d8fb588SMatthias Schmidt 	if (length)
4587d8fb588SMatthias Schmidt 	    stderror(ERR_NOTALLOWED, "$%<");
4597d8fb588SMatthias Schmidt 	wbuf.len = 0;
4607d8fb588SMatthias Schmidt 	{
4617d8fb588SMatthias Schmidt 	    char cbuf[MB_LEN_MAX];
4627d8fb588SMatthias Schmidt 	    size_t cbp = 0;
4637d8fb588SMatthias Schmidt 	    int old_pintr_disabled;
4647d8fb588SMatthias Schmidt 
4657d8fb588SMatthias Schmidt 	    for (;;) {
4667d8fb588SMatthias Schmidt 	        int len;
4677d8fb588SMatthias Schmidt 		ssize_t res;
4687d8fb588SMatthias Schmidt 		Char wc;
4697d8fb588SMatthias Schmidt 
4707d8fb588SMatthias Schmidt 		pintr_push_enable(&old_pintr_disabled);
4717d8fb588SMatthias Schmidt 		res = force_read(OLDSTD, cbuf + cbp, 1);
4727d8fb588SMatthias Schmidt 		cleanup_until(&old_pintr_disabled);
4737d8fb588SMatthias Schmidt 		if (res != 1)
4747d8fb588SMatthias Schmidt 		    break;
4757d8fb588SMatthias Schmidt 		cbp++;
4767d8fb588SMatthias Schmidt 		len = normal_mbtowc(&wc, cbuf, cbp);
4777d8fb588SMatthias Schmidt 		if (len == -1) {
4787d8fb588SMatthias Schmidt 		    reset_mbtowc();
4797d8fb588SMatthias Schmidt 		    if (cbp < MB_LEN_MAX)
4807d8fb588SMatthias Schmidt 		        continue; /* Maybe a partial character */
4817d8fb588SMatthias Schmidt 		    wc = (unsigned char)*cbuf | INVALID_BYTE;
4827d8fb588SMatthias Schmidt 		}
4837d8fb588SMatthias Schmidt 		if (len <= 0)
4847d8fb588SMatthias Schmidt 		    len = 1;
4857d8fb588SMatthias Schmidt 		if (cbp != (size_t)len)
4867d8fb588SMatthias Schmidt 		    memmove(cbuf, cbuf + len, cbp - len);
4877d8fb588SMatthias Schmidt 		cbp -= len;
4887d8fb588SMatthias Schmidt 		if (wc == '\n')
4897d8fb588SMatthias Schmidt 		    break;
4907d8fb588SMatthias Schmidt 		Strbuf_append1(&wbuf, wc);
4917d8fb588SMatthias Schmidt 	    }
4927d8fb588SMatthias Schmidt 	    while (cbp != 0) {
4937d8fb588SMatthias Schmidt 		int len;
4947d8fb588SMatthias Schmidt 		Char wc;
4957d8fb588SMatthias Schmidt 
4967d8fb588SMatthias Schmidt 		len = normal_mbtowc(&wc, cbuf, cbp);
4977d8fb588SMatthias Schmidt 		if (len == -1) {
4987d8fb588SMatthias Schmidt 		    reset_mbtowc();
4997d8fb588SMatthias Schmidt 		    wc = (unsigned char)*cbuf | INVALID_BYTE;
5007d8fb588SMatthias Schmidt 		}
5017d8fb588SMatthias Schmidt 		if (len <= 0)
5027d8fb588SMatthias Schmidt 		    len = 1;
5037d8fb588SMatthias Schmidt 		if (cbp != (size_t)len)
5047d8fb588SMatthias Schmidt 		    memmove(cbuf, cbuf + len, cbp - len);
5057d8fb588SMatthias Schmidt 		cbp -= len;
5067d8fb588SMatthias Schmidt 		if (wc == '\n')
5077d8fb588SMatthias Schmidt 		    break;
5087d8fb588SMatthias Schmidt 		Strbuf_append1(&wbuf, wc);
5097d8fb588SMatthias Schmidt 	    }
5107d8fb588SMatthias Schmidt 	    Strbuf_terminate(&wbuf);
5117d8fb588SMatthias Schmidt 	}
5127d8fb588SMatthias Schmidt 
5137d8fb588SMatthias Schmidt 	fixDolMod();
5147d8fb588SMatthias Schmidt 	setDolp(wbuf.s); /* Kept allocated until next $< expansion */
51557e3f2b5SSimon 'corecode' Schubert 	cleanup_until(name);
5167d8fb588SMatthias Schmidt 	goto eatbrac;
5177d8fb588SMatthias Schmidt     }
5187d8fb588SMatthias Schmidt 
5197d8fb588SMatthias Schmidt     case '*':
52057e3f2b5SSimon 'corecode' Schubert 	Strbuf_append(name, STRargv);
52157e3f2b5SSimon 'corecode' Schubert 	Strbuf_terminate(name);
5227d8fb588SMatthias Schmidt 	vp = adrof(STRargv);
5237d8fb588SMatthias Schmidt 	subscr = -1;		/* Prevent eating [...] */
5247d8fb588SMatthias Schmidt 	break;
5257d8fb588SMatthias Schmidt 
5267d8fb588SMatthias Schmidt     case DEOF:
5277d8fb588SMatthias Schmidt     case '\n':
5287d8fb588SMatthias Schmidt 	np = dimen ? STRargv : (bitset ? STRstatus : NULL);
5297d8fb588SMatthias Schmidt 	if (np) {
5307d8fb588SMatthias Schmidt 	    bitset = 0;
53157e3f2b5SSimon 'corecode' Schubert 	    Strbuf_append(name, np);
53257e3f2b5SSimon 'corecode' Schubert 	    Strbuf_terminate(name);
5337d8fb588SMatthias Schmidt 	    vp = adrof(np);
5347d8fb588SMatthias Schmidt 	    subscr = -1;		/* Prevent eating [...] */
5357d8fb588SMatthias Schmidt 	    unDredc(c);
5367d8fb588SMatthias Schmidt 	    break;
5377d8fb588SMatthias Schmidt 	}
5387d8fb588SMatthias Schmidt 	else
5397d8fb588SMatthias Schmidt 	    stderror(ERR_SYNTAX);
5407d8fb588SMatthias Schmidt 	/*NOTREACHED*/
5417d8fb588SMatthias Schmidt 
5427d8fb588SMatthias Schmidt     default:
5437d8fb588SMatthias Schmidt 	if (Isdigit(c)) {
5447d8fb588SMatthias Schmidt 	    if (dimen)
5457d8fb588SMatthias Schmidt 		stderror(ERR_NOTALLOWED, "$#<num>");
5467d8fb588SMatthias Schmidt 	    subscr = 0;
5477d8fb588SMatthias Schmidt 	    do {
5487d8fb588SMatthias Schmidt 		subscr = subscr * 10 + c - '0';
5497d8fb588SMatthias Schmidt 		c = DgetC(0);
5507d8fb588SMatthias Schmidt 	    } while (c != DEOF && Isdigit(c));
5517d8fb588SMatthias Schmidt 	    unDredc(c);
5527d8fb588SMatthias Schmidt 	    if (subscr < 0)
5537d8fb588SMatthias Schmidt 		stderror(ERR_RANGE);
5547d8fb588SMatthias Schmidt 	    if (subscr == 0) {
5557d8fb588SMatthias Schmidt 		if (bitset) {
5567d8fb588SMatthias Schmidt 		    dolp = dolzero ? STR1 : STR0;
55757e3f2b5SSimon 'corecode' Schubert 		    cleanup_until(name);
5587d8fb588SMatthias Schmidt 		    goto eatbrac;
5597d8fb588SMatthias Schmidt 		}
5607d8fb588SMatthias Schmidt 		if (ffile == 0)
5617d8fb588SMatthias Schmidt 		    stderror(ERR_DOLZERO);
5627d8fb588SMatthias Schmidt 		if (length) {
5637d8fb588SMatthias Schmidt 		    length = Strlen(ffile);
56494afa86dSJohn Marino 		    addla(putn((tcsh_number_t)length));
5657d8fb588SMatthias Schmidt 		}
5667d8fb588SMatthias Schmidt 		else {
5677d8fb588SMatthias Schmidt 		    fixDolMod();
5687d8fb588SMatthias Schmidt 		    setDolp(ffile);
5697d8fb588SMatthias Schmidt 		}
57057e3f2b5SSimon 'corecode' Schubert 		cleanup_until(name);
5717d8fb588SMatthias Schmidt 		goto eatbrac;
5727d8fb588SMatthias Schmidt 	    }
5737d8fb588SMatthias Schmidt #if 0
5747d8fb588SMatthias Schmidt 	    if (bitset)
5757d8fb588SMatthias Schmidt 		stderror(ERR_NOTALLOWED, "$?<num>");
5767d8fb588SMatthias Schmidt 	    if (length)
5777d8fb588SMatthias Schmidt 		stderror(ERR_NOTALLOWED, "$%<num>");
5787d8fb588SMatthias Schmidt #endif
5797d8fb588SMatthias Schmidt 	    vp = adrof(STRargv);
5807d8fb588SMatthias Schmidt 	    if (vp == 0) {
5817d8fb588SMatthias Schmidt 		vp = &nulargv;
58257e3f2b5SSimon 'corecode' Schubert 		cleanup_until(name);
5837d8fb588SMatthias Schmidt 		goto eatmod;
5847d8fb588SMatthias Schmidt 	    }
5857d8fb588SMatthias Schmidt 	    break;
5867d8fb588SMatthias Schmidt 	}
5877d8fb588SMatthias Schmidt 	if (c == DEOF || !alnum(c)) {
5887d8fb588SMatthias Schmidt 	    np = dimen ? STRargv : (bitset ? STRstatus : NULL);
5897d8fb588SMatthias Schmidt 	    if (np) {
5907d8fb588SMatthias Schmidt 		bitset = 0;
59157e3f2b5SSimon 'corecode' Schubert 		Strbuf_append(name, np);
59257e3f2b5SSimon 'corecode' Schubert 		Strbuf_terminate(name);
5937d8fb588SMatthias Schmidt 		vp = adrof(np);
5947d8fb588SMatthias Schmidt 		subscr = -1;		/* Prevent eating [...] */
5957d8fb588SMatthias Schmidt 		unDredc(c);
5967d8fb588SMatthias Schmidt 		break;
5977d8fb588SMatthias Schmidt 	    }
5987d8fb588SMatthias Schmidt 	    else
5997d8fb588SMatthias Schmidt 		stderror(ERR_VARALNUM);
6007d8fb588SMatthias Schmidt 	}
6017d8fb588SMatthias Schmidt 	for (;;) {
60257e3f2b5SSimon 'corecode' Schubert 	    Strbuf_append1(name, (Char) c);
6037d8fb588SMatthias Schmidt 	    c = DgetC(0);
6047d8fb588SMatthias Schmidt 	    if (c == DEOF || !alnum(c))
6057d8fb588SMatthias Schmidt 		break;
6067d8fb588SMatthias Schmidt 	}
60757e3f2b5SSimon 'corecode' Schubert 	Strbuf_terminate(name);
6087d8fb588SMatthias Schmidt 	unDredc(c);
60957e3f2b5SSimon 'corecode' Schubert 	vp = adrof(name->s);
6107d8fb588SMatthias Schmidt     }
6117d8fb588SMatthias Schmidt     if (bitset) {
61257e3f2b5SSimon 'corecode' Schubert 	dolp = (vp || getenv(short2str(name->s))) ? STR1 : STR0;
61357e3f2b5SSimon 'corecode' Schubert 	cleanup_until(name);
6147d8fb588SMatthias Schmidt 	goto eatbrac;
6157d8fb588SMatthias Schmidt     }
6167d8fb588SMatthias Schmidt     if (vp == NULL || vp->vec == NULL) {
61757e3f2b5SSimon 'corecode' Schubert 	np = str2short(getenv(short2str(name->s)));
6187d8fb588SMatthias Schmidt 	if (np) {
6197d8fb588SMatthias Schmidt 	    static Char *env_val; /* = NULL; */
6207d8fb588SMatthias Schmidt 
62157e3f2b5SSimon 'corecode' Schubert 	    cleanup_until(name);
6227d8fb588SMatthias Schmidt 	    fixDolMod();
62357e3f2b5SSimon 'corecode' Schubert 	    if (length) {
62494afa86dSJohn Marino 		    addla(putn((tcsh_number_t)Strlen(np)));
62557e3f2b5SSimon 'corecode' Schubert 	    } else {
6267d8fb588SMatthias Schmidt 		    xfree(env_val);
6277d8fb588SMatthias Schmidt 		    env_val = Strsave(np);
6287d8fb588SMatthias Schmidt 		    setDolp(env_val);
62957e3f2b5SSimon 'corecode' Schubert 	    }
6307d8fb588SMatthias Schmidt 	    goto eatbrac;
6317d8fb588SMatthias Schmidt 	}
63257e3f2b5SSimon 'corecode' Schubert 	udvar(name->s);
6337d8fb588SMatthias Schmidt 	/* NOTREACHED */
6347d8fb588SMatthias Schmidt     }
63557e3f2b5SSimon 'corecode' Schubert     cleanup_until(name);
6367d8fb588SMatthias Schmidt     c = DgetC(0);
6377d8fb588SMatthias Schmidt     upb = blklen(vp->vec);
6387d8fb588SMatthias Schmidt     if (dimen == 0 && subscr == 0 && c == '[') {
63957e3f2b5SSimon 'corecode' Schubert 	name = Strbuf_alloc();
64057e3f2b5SSimon 'corecode' Schubert 	cleanup_push(name, Strbuf_free);
64157e3f2b5SSimon 'corecode' Schubert 	np = name->s;
6427d8fb588SMatthias Schmidt 	for (;;) {
6437d8fb588SMatthias Schmidt 	    c = DgetC(DODOL);	/* Allow $ expand within [ ] */
6447d8fb588SMatthias Schmidt 	    if (c == ']')
6457d8fb588SMatthias Schmidt 		break;
6467d8fb588SMatthias Schmidt 	    if (c == '\n' || c == DEOF)
6477d8fb588SMatthias Schmidt 		stderror(ERR_INCBR);
64857e3f2b5SSimon 'corecode' Schubert 	    Strbuf_append1(name, (Char) c);
6497d8fb588SMatthias Schmidt 	}
65057e3f2b5SSimon 'corecode' Schubert 	Strbuf_terminate(name);
65157e3f2b5SSimon 'corecode' Schubert 	np = name->s;
6527d8fb588SMatthias Schmidt 	if (dolp || dolcnt)	/* $ exp must end before ] */
6537d8fb588SMatthias Schmidt 	    stderror(ERR_EXPORD);
6547d8fb588SMatthias Schmidt 	if (!*np)
6557d8fb588SMatthias Schmidt 	    stderror(ERR_SYNTAX);
6567d8fb588SMatthias Schmidt 	if (Isdigit(*np)) {
6577d8fb588SMatthias Schmidt 	    int     i;
6587d8fb588SMatthias Schmidt 
6597d8fb588SMatthias Schmidt 	    for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
6607d8fb588SMatthias Schmidt 		continue;
66194afa86dSJohn Marino 	    if (i < 0 || (i > upb && !any("-*", *np))) {
66257e3f2b5SSimon 'corecode' Schubert 		cleanup_until(name);
6637d8fb588SMatthias Schmidt 		dolerror(vp->v_name);
6647d8fb588SMatthias Schmidt 		return;
6657d8fb588SMatthias Schmidt 	    }
6667d8fb588SMatthias Schmidt 	    lwb = i;
6677d8fb588SMatthias Schmidt 	    if (!*np)
6687d8fb588SMatthias Schmidt 		upb = lwb, np = STRstar;
6697d8fb588SMatthias Schmidt 	}
6707d8fb588SMatthias Schmidt 	if (*np == '*')
6717d8fb588SMatthias Schmidt 	    np++;
6727d8fb588SMatthias Schmidt 	else if (*np != '-')
6737d8fb588SMatthias Schmidt 	    stderror(ERR_MISSING, '-');
6747d8fb588SMatthias Schmidt 	else {
6757d8fb588SMatthias Schmidt 	    int i = upb;
6767d8fb588SMatthias Schmidt 
6777d8fb588SMatthias Schmidt 	    np++;
6787d8fb588SMatthias Schmidt 	    if (Isdigit(*np)) {
6797d8fb588SMatthias Schmidt 		i = 0;
6807d8fb588SMatthias Schmidt 		while (Isdigit(*np))
6817d8fb588SMatthias Schmidt 		    i = i * 10 + *np++ - '0';
6827d8fb588SMatthias Schmidt 		if (i < 0 || i > upb) {
68357e3f2b5SSimon 'corecode' Schubert 		    cleanup_until(name);
6847d8fb588SMatthias Schmidt 		    dolerror(vp->v_name);
6857d8fb588SMatthias Schmidt 		    return;
6867d8fb588SMatthias Schmidt 		}
6877d8fb588SMatthias Schmidt 	    }
6887d8fb588SMatthias Schmidt 	    if (i < lwb)
6897d8fb588SMatthias Schmidt 		upb = lwb - 1;
6907d8fb588SMatthias Schmidt 	    else
6917d8fb588SMatthias Schmidt 		upb = i;
6927d8fb588SMatthias Schmidt 	}
6937d8fb588SMatthias Schmidt 	if (lwb == 0) {
6947d8fb588SMatthias Schmidt 	    if (upb != 0) {
69557e3f2b5SSimon 'corecode' Schubert 		cleanup_until(name);
6967d8fb588SMatthias Schmidt 		dolerror(vp->v_name);
6977d8fb588SMatthias Schmidt 		return;
6987d8fb588SMatthias Schmidt 	    }
6997d8fb588SMatthias Schmidt 	    upb = -1;
7007d8fb588SMatthias Schmidt 	}
7017d8fb588SMatthias Schmidt 	if (*np)
7027d8fb588SMatthias Schmidt 	    stderror(ERR_SYNTAX);
70357e3f2b5SSimon 'corecode' Schubert 	cleanup_until(name);
7047d8fb588SMatthias Schmidt     }
7057d8fb588SMatthias Schmidt     else {
7067d8fb588SMatthias Schmidt 	if (subscr > 0) {
7077d8fb588SMatthias Schmidt 	    if (subscr > upb)
7087d8fb588SMatthias Schmidt 		lwb = 1, upb = 0;
7097d8fb588SMatthias Schmidt 	    else
7107d8fb588SMatthias Schmidt 		lwb = upb = subscr;
7117d8fb588SMatthias Schmidt 	}
7127d8fb588SMatthias Schmidt 	unDredc(c);
7137d8fb588SMatthias Schmidt     }
7147d8fb588SMatthias Schmidt     if (dimen) {
7157d8fb588SMatthias Schmidt 	/* this is a kludge. It prevents Dgetdol() from */
7167d8fb588SMatthias Schmidt 	/* pushing erroneous ${#<error> values into the labuf. */
7177d8fb588SMatthias Schmidt 	if (sc == '{') {
7187d8fb588SMatthias Schmidt 	    c = Dredc();
7197d8fb588SMatthias Schmidt 	    if (c != '}')
7207d8fb588SMatthias Schmidt 		stderror(ERR_MISSING, '}');
7217d8fb588SMatthias Schmidt 	    unDredc(c);
7227d8fb588SMatthias Schmidt 	}
72394afa86dSJohn Marino 	addla(putn((tcsh_number_t)(upb - lwb + 1)));
7247d8fb588SMatthias Schmidt     }
7257d8fb588SMatthias Schmidt     else if (length) {
7267d8fb588SMatthias Schmidt 	int i;
7277d8fb588SMatthias Schmidt 
7287d8fb588SMatthias Schmidt 	for (i = lwb - 1, length = 0; i < upb; i++)
7297d8fb588SMatthias Schmidt 	    length += Strlen(vp->vec[i]);
7307d8fb588SMatthias Schmidt #ifdef notdef
7317d8fb588SMatthias Schmidt 	/* We don't want that, since we can always compute it by adding $#xxx */
7327d8fb588SMatthias Schmidt 	length += i - 1;	/* Add the number of spaces in */
7337d8fb588SMatthias Schmidt #endif
73494afa86dSJohn Marino 	addla(putn((tcsh_number_t)length));
7357d8fb588SMatthias Schmidt     }
7367d8fb588SMatthias Schmidt     else {
7377d8fb588SMatthias Schmidt eatmod:
7387d8fb588SMatthias Schmidt 	fixDolMod();
7397d8fb588SMatthias Schmidt 	dolnxt = &vp->vec[lwb - 1];
7407d8fb588SMatthias Schmidt 	dolcnt = upb - lwb + 1;
7417d8fb588SMatthias Schmidt     }
7427d8fb588SMatthias Schmidt eatbrac:
7437d8fb588SMatthias Schmidt     if (sc == '{') {
7447d8fb588SMatthias Schmidt 	c = Dredc();
7457d8fb588SMatthias Schmidt 	if (c != '}')
7467d8fb588SMatthias Schmidt 	    stderror(ERR_MISSING, '}');
7477d8fb588SMatthias Schmidt     }
7487d8fb588SMatthias Schmidt }
7497d8fb588SMatthias Schmidt 
7507d8fb588SMatthias Schmidt static void
fixDolMod(void)7517d8fb588SMatthias Schmidt fixDolMod(void)
7527d8fb588SMatthias Schmidt {
7537d8fb588SMatthias Schmidt     eChar c;
7547d8fb588SMatthias Schmidt 
7557d8fb588SMatthias Schmidt     c = DgetC(0);
7567d8fb588SMatthias Schmidt     if (c == ':') {
757*d6ab524cSAntonio Huete Jimenez 	ndolflags = 0;
7587d8fb588SMatthias Schmidt 	do {
759*d6ab524cSAntonio Huete Jimenez 	    ++ndolflags;
760*d6ab524cSAntonio Huete Jimenez 	    dolmcnts = xrealloc(dolmcnts, ndolflags * sizeof(int));
761*d6ab524cSAntonio Huete Jimenez 	    dolaflags = xrealloc(dolaflags, ndolflags * sizeof(int));
762*d6ab524cSAntonio Huete Jimenez 	    c = DgetC(0), dolmcnts[ndolflags - 1] = 1, dolaflags[ndolflags - 1] = 0;
7637d8fb588SMatthias Schmidt 	    if (c == 'g' || c == 'a') {
764*d6ab524cSAntonio Huete Jimenez 		if (c == 'g') {
765*d6ab524cSAntonio Huete Jimenez 		    dolmcnts[ndolflags - 1] = INT_MAX;
766*d6ab524cSAntonio Huete Jimenez 		} else {
767*d6ab524cSAntonio Huete Jimenez 		    dolaflags[ndolflags - 1] = 1;
768*d6ab524cSAntonio Huete Jimenez 		}
7697d8fb588SMatthias Schmidt 		c = DgetC(0);
7707d8fb588SMatthias Schmidt 	    }
771*d6ab524cSAntonio Huete Jimenez 	    if ((c == 'g' && dolmcnts[ndolflags - 1] != INT_MAX) ||
772*d6ab524cSAntonio Huete Jimenez 		(c == 'a' && dolaflags[ndolflags - 1] == 0)) {
773*d6ab524cSAntonio Huete Jimenez 		if (c == 'g') {
774*d6ab524cSAntonio Huete Jimenez 		    dolmcnts[ndolflags - 1] = INT_MAX;
775*d6ab524cSAntonio Huete Jimenez 		} else {
776*d6ab524cSAntonio Huete Jimenez 		    dolaflags[ndolflags - 1] = 1;
777*d6ab524cSAntonio Huete Jimenez 		}
7787d8fb588SMatthias Schmidt 		c = DgetC(0);
7797d8fb588SMatthias Schmidt 	    }
7807d8fb588SMatthias Schmidt 
7817d8fb588SMatthias Schmidt 	    if (c == 's') {	/* [eichin:19910926.0755EST] */
7827d8fb588SMatthias Schmidt 		int delimcnt = 2;
783*d6ab524cSAntonio Huete Jimenez 		int esc = 0;
7847d8fb588SMatthias Schmidt 		eChar delim = DgetC(0);
7857d8fb588SMatthias Schmidt 		Strbuf_append1(&dolmod, (Char) c);
7867d8fb588SMatthias Schmidt 		Strbuf_append1(&dolmod, (Char) delim);
7877d8fb588SMatthias Schmidt 
7887d8fb588SMatthias Schmidt 		if (delim == DEOF || !delim || letter(delim)
7897d8fb588SMatthias Schmidt 		    || Isdigit(delim) || any(" \t\n", delim)) {
7907d8fb588SMatthias Schmidt 		    seterror(ERR_BADSUBST);
7917d8fb588SMatthias Schmidt 		    break;
7927d8fb588SMatthias Schmidt 		}
7937d8fb588SMatthias Schmidt 		while ((c = DgetC(0)) != DEOF) {
794*d6ab524cSAntonio Huete Jimenez 		    if (esc == 0 && c == '\\') {
795*d6ab524cSAntonio Huete Jimenez 			esc = 1;
796*d6ab524cSAntonio Huete Jimenez 			continue;
797*d6ab524cSAntonio Huete Jimenez 		    }
7987d8fb588SMatthias Schmidt 		    Strbuf_append1(&dolmod, (Char) c);
799*d6ab524cSAntonio Huete Jimenez 		    if (!esc && c == delim) delimcnt--;
8007d8fb588SMatthias Schmidt 		    if (!delimcnt) break;
801*d6ab524cSAntonio Huete Jimenez 		    esc = 0;
8027d8fb588SMatthias Schmidt 		}
8037d8fb588SMatthias Schmidt 		if (delimcnt) {
8047d8fb588SMatthias Schmidt 		    seterror(ERR_BADSUBST);
8057d8fb588SMatthias Schmidt 		    break;
8067d8fb588SMatthias Schmidt 		}
8077d8fb588SMatthias Schmidt 		continue;
8087d8fb588SMatthias Schmidt 	    }
809*d6ab524cSAntonio Huete Jimenez 	    if (!any(TCSH_MODIFIERS, c))
8107d8fb588SMatthias Schmidt 		stderror(ERR_BADMOD, (int)c);
8117d8fb588SMatthias Schmidt 	    Strbuf_append1(&dolmod, (Char) c);
812*d6ab524cSAntonio Huete Jimenez 	    if (c == 'q') {
813*d6ab524cSAntonio Huete Jimenez 		dolmcnts[ndolflags - 1] = INT_MAX;
814*d6ab524cSAntonio Huete Jimenez 	    }
8157d8fb588SMatthias Schmidt 	}
8167d8fb588SMatthias Schmidt 	while ((c = DgetC(0)) == ':');
8177d8fb588SMatthias Schmidt 	unDredc(c);
8187d8fb588SMatthias Schmidt     }
8197d8fb588SMatthias Schmidt     else
8207d8fb588SMatthias Schmidt 	unDredc(c);
8217d8fb588SMatthias Schmidt }
8227d8fb588SMatthias Schmidt 
823*d6ab524cSAntonio Huete Jimenez static int
all_dolmcnts_are_0(void)824*d6ab524cSAntonio Huete Jimenez all_dolmcnts_are_0(void)
825*d6ab524cSAntonio Huete Jimenez {
826*d6ab524cSAntonio Huete Jimenez     int i = 0;
827*d6ab524cSAntonio Huete Jimenez     for (; i < ndolflags; ++i) {
828*d6ab524cSAntonio Huete Jimenez 	if (dolmcnts[i] != 0)
829*d6ab524cSAntonio Huete Jimenez 	    return 0;
830*d6ab524cSAntonio Huete Jimenez     }
831*d6ab524cSAntonio Huete Jimenez     return 1;
832*d6ab524cSAntonio Huete Jimenez }
833*d6ab524cSAntonio Huete Jimenez 
8347d8fb588SMatthias Schmidt static void
setDolp(Char * cp)8357d8fb588SMatthias Schmidt setDolp(Char *cp)
8367d8fb588SMatthias Schmidt {
8377d8fb588SMatthias Schmidt     Char *dp;
8387d8fb588SMatthias Schmidt     size_t i;
839*d6ab524cSAntonio Huete Jimenez     int nthMod = 0;
8407d8fb588SMatthias Schmidt 
841*d6ab524cSAntonio Huete Jimenez     if (dolmod.len == 0 || all_dolmcnts_are_0()) {
8427d8fb588SMatthias Schmidt 	dolp = cp;
8437d8fb588SMatthias Schmidt 	return;
8447d8fb588SMatthias Schmidt     }
8457d8fb588SMatthias Schmidt     cp = Strsave(cp);
8467d8fb588SMatthias Schmidt     for (i = 0; i < dolmod.len; i++) {
8477d8fb588SMatthias Schmidt 	int didmod = 0;
8487d8fb588SMatthias Schmidt 
8497d8fb588SMatthias Schmidt 	/* handle s// [eichin:19910926.0510EST] */
8507d8fb588SMatthias Schmidt 	if (dolmod.s[i] == 's') {
8517d8fb588SMatthias Schmidt 	    Char delim;
8527d8fb588SMatthias Schmidt 	    Char *lhsub, *rhsub, *np;
8537d8fb588SMatthias Schmidt 	    size_t lhlen = 0, rhlen = 0;
854*d6ab524cSAntonio Huete Jimenez 	    /* keep track of where the last :a match hit */
855*d6ab524cSAntonio Huete Jimenez 	    ptrdiff_t last_match = 0;
8567d8fb588SMatthias Schmidt 
8577d8fb588SMatthias Schmidt 	    delim = dolmod.s[++i];
8587d8fb588SMatthias Schmidt 	    if (!delim || letter(delim)
8597d8fb588SMatthias Schmidt 		|| Isdigit(delim) || any(" \t\n", delim)) {
8607d8fb588SMatthias Schmidt 		seterror(ERR_BADSUBST);
8617d8fb588SMatthias Schmidt 		break;
8627d8fb588SMatthias Schmidt 	    }
8637d8fb588SMatthias Schmidt 	    lhsub = &dolmod.s[++i];
8647d8fb588SMatthias Schmidt 	    while (dolmod.s[i] != delim && dolmod.s[++i]) {
8657d8fb588SMatthias Schmidt 		lhlen++;
8667d8fb588SMatthias Schmidt 	    }
8677d8fb588SMatthias Schmidt 	    dolmod.s[i] = 0;
8687d8fb588SMatthias Schmidt 	    rhsub = &dolmod.s[++i];
8697d8fb588SMatthias Schmidt 	    while (dolmod.s[i] != delim && dolmod.s[++i]) {
8707d8fb588SMatthias Schmidt 		rhlen++;
8717d8fb588SMatthias Schmidt 	    }
8727d8fb588SMatthias Schmidt 	    dolmod.s[i] = 0;
8737d8fb588SMatthias Schmidt 
8747d8fb588SMatthias Schmidt 	    strip(lhsub);
87557e3f2b5SSimon 'corecode' Schubert 	    strip(rhsub);
876*d6ab524cSAntonio Huete Jimenez 	    if (dolmcnts[nthMod] != 0) {
8777d8fb588SMatthias Schmidt 	        strip(cp);
8787d8fb588SMatthias Schmidt 	        dp = cp;
8797d8fb588SMatthias Schmidt 	        do {
880*d6ab524cSAntonio Huete Jimenez 	            dp = Strstr(dp + last_match, lhsub);
8817d8fb588SMatthias Schmidt 	            if (dp) {
8827d8fb588SMatthias Schmidt 	                ptrdiff_t diff = dp - cp;
88357e3f2b5SSimon 'corecode' Schubert 	                size_t len = (Strlen(cp) + 1 - lhlen + rhlen);
88457e3f2b5SSimon 'corecode' Schubert 	                np = xmalloc(len * sizeof(Char));
8857d8fb588SMatthias Schmidt 	                (void) Strncpy(np, cp, diff);
8867d8fb588SMatthias Schmidt 	                (void) Strcpy(np + diff, rhsub);
8877d8fb588SMatthias Schmidt 	                (void) Strcpy(np + diff + rhlen, dp + lhlen);
888*d6ab524cSAntonio Huete Jimenez 			last_match = diff + rhlen;
8897d8fb588SMatthias Schmidt 
8907d8fb588SMatthias Schmidt 	                xfree(cp);
89160962bbcSJohn Marino 	                dp = cp = np;
89257e3f2b5SSimon 'corecode' Schubert 	                cp[--len] = '\0';
8937d8fb588SMatthias Schmidt 	                didmod = 1;
89494afa86dSJohn Marino 	                if (diff >= (ssize_t)len)
89557e3f2b5SSimon 'corecode' Schubert 	            	break;
8967d8fb588SMatthias Schmidt 	            } else {
8977d8fb588SMatthias Schmidt 	                /* should this do a seterror? */
8987d8fb588SMatthias Schmidt 	                break;
8997d8fb588SMatthias Schmidt 	            }
9007d8fb588SMatthias Schmidt 	        }
901*d6ab524cSAntonio Huete Jimenez 	        while (dolaflags[nthMod] != 0);
902*d6ab524cSAntonio Huete Jimenez             }
9037d8fb588SMatthias Schmidt 	    /*
9047d8fb588SMatthias Schmidt 	     * restore dolmod for additional words
9057d8fb588SMatthias Schmidt 	     */
9067d8fb588SMatthias Schmidt 	    dolmod.s[i] = rhsub[-1] = (Char) delim;
907*d6ab524cSAntonio Huete Jimenez 	} else if (dolmcnts[nthMod] != 0) {
9087d8fb588SMatthias Schmidt 
9097d8fb588SMatthias Schmidt 	    do {
9107d8fb588SMatthias Schmidt 		if ((dp = domod(cp, dolmod.s[i])) != NULL) {
9117d8fb588SMatthias Schmidt 		    didmod = 1;
9127d8fb588SMatthias Schmidt 		    if (Strcmp(cp, dp) == 0) {
9137d8fb588SMatthias Schmidt 			xfree(cp);
9147d8fb588SMatthias Schmidt 			cp = dp;
9157d8fb588SMatthias Schmidt 			break;
9167d8fb588SMatthias Schmidt 		    }
9177d8fb588SMatthias Schmidt 		    else {
9187d8fb588SMatthias Schmidt 			xfree(cp);
9197d8fb588SMatthias Schmidt 			cp = dp;
9207d8fb588SMatthias Schmidt 		    }
9217d8fb588SMatthias Schmidt 		}
9227d8fb588SMatthias Schmidt 		else
9237d8fb588SMatthias Schmidt 		    break;
9247d8fb588SMatthias Schmidt 	    }
925*d6ab524cSAntonio Huete Jimenez 	    while (dolaflags[nthMod] != 0);
9267d8fb588SMatthias Schmidt 	}
927*d6ab524cSAntonio Huete Jimenez 	if (didmod && dolmcnts[nthMod] != INT_MAX)
928*d6ab524cSAntonio Huete Jimenez 	    dolmcnts[nthMod]--;
9297d8fb588SMatthias Schmidt #ifdef notdef
9307d8fb588SMatthias Schmidt 	else
9317d8fb588SMatthias Schmidt 	    break;
9327d8fb588SMatthias Schmidt #endif
933*d6ab524cSAntonio Huete Jimenez 
934*d6ab524cSAntonio Huete Jimenez 	++nthMod;
9357d8fb588SMatthias Schmidt     }
9367d8fb588SMatthias Schmidt 
9377d8fb588SMatthias Schmidt     addla(cp);
9387d8fb588SMatthias Schmidt 
9397d8fb588SMatthias Schmidt     dolp = STRNULL;
9407d8fb588SMatthias Schmidt     if (seterr)
9417d8fb588SMatthias Schmidt 	stderror(ERR_OLD);
9427d8fb588SMatthias Schmidt }
9437d8fb588SMatthias Schmidt 
9447d8fb588SMatthias Schmidt static void
unDredc(eChar c)9457d8fb588SMatthias Schmidt unDredc(eChar c)
9467d8fb588SMatthias Schmidt {
9477d8fb588SMatthias Schmidt 
9487d8fb588SMatthias Schmidt     Dpeekrd = c;
9497d8fb588SMatthias Schmidt }
9507d8fb588SMatthias Schmidt 
9517d8fb588SMatthias Schmidt static eChar
Dredc(void)9527d8fb588SMatthias Schmidt Dredc(void)
9537d8fb588SMatthias Schmidt {
95494afa86dSJohn Marino     eChar c;
9557d8fb588SMatthias Schmidt 
9567d8fb588SMatthias Schmidt     if ((c = Dpeekrd) != 0) {
9577d8fb588SMatthias Schmidt 	Dpeekrd = 0;
9587d8fb588SMatthias Schmidt 	return (c);
9597d8fb588SMatthias Schmidt     }
9607d8fb588SMatthias Schmidt     if (Dcp && (c = *Dcp++))
9617d8fb588SMatthias Schmidt 	return (c & (QUOTE | TRIM));
9627d8fb588SMatthias Schmidt     if (*Dvp == 0) {
9637d8fb588SMatthias Schmidt 	Dcp = 0;
9647d8fb588SMatthias Schmidt 	return (DEOF);
9657d8fb588SMatthias Schmidt     }
9667d8fb588SMatthias Schmidt     Dcp = *Dvp++;
9677d8fb588SMatthias Schmidt     return (' ');
9687d8fb588SMatthias Schmidt }
9697d8fb588SMatthias Schmidt 
9707d8fb588SMatthias Schmidt static int gflag;
9717d8fb588SMatthias Schmidt 
9727d8fb588SMatthias Schmidt static void
Dtestq(Char c)9737d8fb588SMatthias Schmidt Dtestq(Char c)
9747d8fb588SMatthias Schmidt {
9757d8fb588SMatthias Schmidt 
9767d8fb588SMatthias Schmidt     if (cmap(c, QUOTES))
9777d8fb588SMatthias Schmidt 	gflag = 1;
9787d8fb588SMatthias Schmidt }
9797d8fb588SMatthias Schmidt 
9807d8fb588SMatthias Schmidt static void
inheredoc_cleanup(void * dummy)9817d8fb588SMatthias Schmidt inheredoc_cleanup(void *dummy)
9827d8fb588SMatthias Schmidt {
9837d8fb588SMatthias Schmidt     USE(dummy);
9847d8fb588SMatthias Schmidt     inheredoc = 0;
9857d8fb588SMatthias Schmidt }
9867d8fb588SMatthias Schmidt 
98760962bbcSJohn Marino Char *
randsuf(void)98860962bbcSJohn Marino randsuf(void) {
98960962bbcSJohn Marino #ifndef WINNT_NATIVE
99060962bbcSJohn Marino 	struct timeval tv;
99160962bbcSJohn Marino 	(void) gettimeofday(&tv, NULL);
99260962bbcSJohn Marino 	return putn((((tcsh_number_t)tv.tv_sec) ^
99360962bbcSJohn Marino 	    ((tcsh_number_t)tv.tv_usec) ^
99460962bbcSJohn Marino 	    ((tcsh_number_t)getpid())) & 0x00ffffff);
99560962bbcSJohn Marino #else
99660962bbcSJohn Marino     return putn(getpid());
99760962bbcSJohn Marino #endif
99860962bbcSJohn Marino }
99960962bbcSJohn Marino 
10007d8fb588SMatthias Schmidt /*
10017d8fb588SMatthias Schmidt  * Form a shell temporary file (in unit 0) from the words
10027d8fb588SMatthias Schmidt  * of the shell input up to EOF or a line the same as "term".
10037d8fb588SMatthias Schmidt  * Unit 0 should have been closed before this call.
10047d8fb588SMatthias Schmidt  */
10057d8fb588SMatthias Schmidt void
heredoc(Char * term)10067d8fb588SMatthias Schmidt heredoc(Char *term)
10077d8fb588SMatthias Schmidt {
10087d8fb588SMatthias Schmidt     eChar  c;
10097d8fb588SMatthias Schmidt     Char   *Dv[2];
10107d8fb588SMatthias Schmidt     struct Strbuf lbuf = Strbuf_INIT, mbuf = Strbuf_INIT;
10117d8fb588SMatthias Schmidt     Char    obuf[BUFSIZE + 1];
10127d8fb588SMatthias Schmidt #define OBUF_END (obuf + sizeof(obuf) / sizeof (*obuf) - 1)
10137d8fb588SMatthias Schmidt     Char *lbp, *obp, *mbp;
10147d8fb588SMatthias Schmidt     Char  **vp;
10157d8fb588SMatthias Schmidt     int    quoted;
101694afa86dSJohn Marino #ifdef HAVE_MKSTEMP
101794afa86dSJohn Marino     char   *tmp = short2str(shtemp);
101894afa86dSJohn Marino     char   *dot = strrchr(tmp, '.');
101994afa86dSJohn Marino 
102094afa86dSJohn Marino     if (!dot)
102194afa86dSJohn Marino 	stderror(ERR_NAME | ERR_NOMATCH);
102294afa86dSJohn Marino     strcpy(dot, TMP_TEMPLATE);
102394afa86dSJohn Marino 
102494afa86dSJohn Marino     xclose(0);
102594afa86dSJohn Marino     if (mkstemp(tmp) == -1)
102694afa86dSJohn Marino 	stderror(ERR_SYSTEM, tmp, strerror(errno));
102794afa86dSJohn Marino #else /* !HAVE_MKSTEMP */
10287d8fb588SMatthias Schmidt     char   *tmp;
10297d8fb588SMatthias Schmidt # ifndef WINNT_NATIVE
10307d8fb588SMatthias Schmidt 
10317d8fb588SMatthias Schmidt again:
10327d8fb588SMatthias Schmidt # endif /* WINNT_NATIVE */
10337d8fb588SMatthias Schmidt     tmp = short2str(shtemp);
103494afa86dSJohn Marino # if O_CREAT == 0
10357d8fb588SMatthias Schmidt     if (xcreat(tmp, 0600) < 0)
10367d8fb588SMatthias Schmidt 	stderror(ERR_SYSTEM, tmp, strerror(errno));
10377d8fb588SMatthias Schmidt # endif
10387d8fb588SMatthias Schmidt     xclose(0);
10397d8fb588SMatthias Schmidt     if (xopen(tmp, O_RDWR|O_CREAT|O_EXCL|O_TEMPORARY|O_LARGEFILE, 0600) ==
10407d8fb588SMatthias Schmidt 	-1) {
10417d8fb588SMatthias Schmidt 	int oerrno = errno;
10427d8fb588SMatthias Schmidt # ifndef WINNT_NATIVE
10437d8fb588SMatthias Schmidt 	if (errno == EEXIST) {
10447d8fb588SMatthias Schmidt 	    if (unlink(tmp) == -1) {
10457d8fb588SMatthias Schmidt 		xfree(shtemp);
104660962bbcSJohn Marino 		mbp = randsuf();
10477d8fb588SMatthias Schmidt 		shtemp = Strspl(STRtmpsh, mbp);
10487d8fb588SMatthias Schmidt 		xfree(mbp);
10497d8fb588SMatthias Schmidt 	    }
10507d8fb588SMatthias Schmidt 	    goto again;
10517d8fb588SMatthias Schmidt 	}
10527d8fb588SMatthias Schmidt # endif /* WINNT_NATIVE */
10537d8fb588SMatthias Schmidt 	(void) unlink(tmp);
10547d8fb588SMatthias Schmidt 	errno = oerrno;
10557d8fb588SMatthias Schmidt  	stderror(ERR_SYSTEM, tmp, strerror(errno));
10567d8fb588SMatthias Schmidt     }
105794afa86dSJohn Marino #endif /* HAVE_MKSTEMP */
10587d8fb588SMatthias Schmidt     (void) unlink(tmp);		/* 0 0 inode! */
10597d8fb588SMatthias Schmidt     Dv[0] = term;
10607d8fb588SMatthias Schmidt     Dv[1] = NULL;
10617d8fb588SMatthias Schmidt     gflag = 0;
10627d8fb588SMatthias Schmidt     trim(Dv);
10637d8fb588SMatthias Schmidt     rscan(Dv, Dtestq);
10647d8fb588SMatthias Schmidt     quoted = gflag;
10657d8fb588SMatthias Schmidt     obp = obuf;
10667d8fb588SMatthias Schmidt     obuf[BUFSIZE] = 0;
10677d8fb588SMatthias Schmidt     inheredoc = 1;
10687d8fb588SMatthias Schmidt     cleanup_push(&inheredoc, inheredoc_cleanup);
10697d8fb588SMatthias Schmidt #ifdef WINNT_NATIVE
10707d8fb588SMatthias Schmidt     __dup_stdin = 1;
10717d8fb588SMatthias Schmidt #endif /* WINNT_NATIVE */
10727d8fb588SMatthias Schmidt     cleanup_push(&lbuf, Strbuf_cleanup);
10737d8fb588SMatthias Schmidt     cleanup_push(&mbuf, Strbuf_cleanup);
10747d8fb588SMatthias Schmidt     for (;;) {
10757d8fb588SMatthias Schmidt 	Char **words;
10767d8fb588SMatthias Schmidt 
10777d8fb588SMatthias Schmidt 	/*
10787d8fb588SMatthias Schmidt 	 * Read up a line
10797d8fb588SMatthias Schmidt 	 */
10807d8fb588SMatthias Schmidt 	lbuf.len = 0;
10817d8fb588SMatthias Schmidt 	for (;;) {
10827d8fb588SMatthias Schmidt 	    c = readc(1);	/* 1 -> Want EOF returns */
10837d8fb588SMatthias Schmidt 	    if (c == CHAR_ERR || c == '\n')
10847d8fb588SMatthias Schmidt 		break;
10857d8fb588SMatthias Schmidt 	    if ((c &= TRIM) != 0)
10867d8fb588SMatthias Schmidt 		Strbuf_append1(&lbuf, (Char) c);
10877d8fb588SMatthias Schmidt 	}
10887d8fb588SMatthias Schmidt 	Strbuf_terminate(&lbuf);
10897d8fb588SMatthias Schmidt 
109094afa86dSJohn Marino 	/* Catch EOF in the middle of a line. */
109194afa86dSJohn Marino 	if (c == CHAR_ERR && lbuf.len != 0)
109294afa86dSJohn Marino 	    c = '\n';
109394afa86dSJohn Marino 
10947d8fb588SMatthias Schmidt 	/*
10957d8fb588SMatthias Schmidt 	 * Check for EOF or compare to terminator -- before expansion
10967d8fb588SMatthias Schmidt 	 */
10977d8fb588SMatthias Schmidt 	if (c == CHAR_ERR || eq(lbuf.s, term))
10987d8fb588SMatthias Schmidt 	    break;
10997d8fb588SMatthias Schmidt 
11007d8fb588SMatthias Schmidt 	/*
11017d8fb588SMatthias Schmidt 	 * If term was quoted or -n just pass it on
11027d8fb588SMatthias Schmidt 	 */
11037d8fb588SMatthias Schmidt 	if (quoted || noexec) {
11047d8fb588SMatthias Schmidt 	    Strbuf_append1(&lbuf, '\n');
11057d8fb588SMatthias Schmidt 	    Strbuf_terminate(&lbuf);
11067d8fb588SMatthias Schmidt 	    for (lbp = lbuf.s; (c = *lbp++) != 0;) {
11077d8fb588SMatthias Schmidt 		*obp++ = (Char) c;
11087d8fb588SMatthias Schmidt 		if (obp == OBUF_END) {
11097d8fb588SMatthias Schmidt 		    tmp = short2str(obuf);
11107d8fb588SMatthias Schmidt 		    (void) xwrite(0, tmp, strlen (tmp));
11117d8fb588SMatthias Schmidt 		    obp = obuf;
11127d8fb588SMatthias Schmidt 		}
11137d8fb588SMatthias Schmidt 	    }
11147d8fb588SMatthias Schmidt 	    continue;
11157d8fb588SMatthias Schmidt 	}
11167d8fb588SMatthias Schmidt 
11177d8fb588SMatthias Schmidt 	/*
11187d8fb588SMatthias Schmidt 	 * Term wasn't quoted so variable and then command expand the input
11197d8fb588SMatthias Schmidt 	 * line
11207d8fb588SMatthias Schmidt 	 */
11217d8fb588SMatthias Schmidt 	Dcp = lbuf.s;
11227d8fb588SMatthias Schmidt 	Dvp = Dv + 1;
11237d8fb588SMatthias Schmidt 	mbuf.len = 0;
11247d8fb588SMatthias Schmidt 	for (;;) {
11257d8fb588SMatthias Schmidt 	    c = DgetC(DODOL);
11267d8fb588SMatthias Schmidt 	    if (c == DEOF)
11277d8fb588SMatthias Schmidt 		break;
11287d8fb588SMatthias Schmidt 	    if ((c &= TRIM) == 0)
11297d8fb588SMatthias Schmidt 		continue;
11307d8fb588SMatthias Schmidt 	    /* \ quotes \ $ ` here */
11317d8fb588SMatthias Schmidt 	    if (c == '\\') {
11327d8fb588SMatthias Schmidt 		c = DgetC(0);
11337d8fb588SMatthias Schmidt 		if (!any("$\\`", c))
11347d8fb588SMatthias Schmidt 		    unDgetC(c | QUOTE), c = '\\';
11357d8fb588SMatthias Schmidt 		else
11367d8fb588SMatthias Schmidt 		    c |= QUOTE;
11377d8fb588SMatthias Schmidt 	    }
11387d8fb588SMatthias Schmidt 	    Strbuf_append1(&mbuf, (Char) c);
11397d8fb588SMatthias Schmidt 	}
11407d8fb588SMatthias Schmidt 	Strbuf_terminate(&mbuf);
11417d8fb588SMatthias Schmidt 
11427d8fb588SMatthias Schmidt 	/*
11437d8fb588SMatthias Schmidt 	 * If any ` in line do command substitution
11447d8fb588SMatthias Schmidt 	 */
11457d8fb588SMatthias Schmidt 	mbp = mbuf.s;
11467d8fb588SMatthias Schmidt 	if (Strchr(mbp, '`') != NULL) {
11477d8fb588SMatthias Schmidt 	    /*
11487d8fb588SMatthias Schmidt 	     * 1 arg to dobackp causes substitution to be literal. Words are
11497d8fb588SMatthias Schmidt 	     * broken only at newlines so that all blanks and tabs are
11507d8fb588SMatthias Schmidt 	     * preserved.  Blank lines (null words) are not discarded.
11517d8fb588SMatthias Schmidt 	     */
11527d8fb588SMatthias Schmidt 	    words = dobackp(mbp, 1);
11537d8fb588SMatthias Schmidt 	}
11547d8fb588SMatthias Schmidt 	else
11557d8fb588SMatthias Schmidt 	    /* Setup trivial vector similar to return of dobackp */
11567d8fb588SMatthias Schmidt 	    Dv[0] = mbp, Dv[1] = NULL, words = Dv;
11577d8fb588SMatthias Schmidt 
11587d8fb588SMatthias Schmidt 	/*
11597d8fb588SMatthias Schmidt 	 * Resurrect the words from the command substitution each separated by
11607d8fb588SMatthias Schmidt 	 * a newline.  Note that the last newline of a command substitution
11617d8fb588SMatthias Schmidt 	 * will have been discarded, but we put a newline after the last word
11627d8fb588SMatthias Schmidt 	 * because this represents the newline after the last input line!
11637d8fb588SMatthias Schmidt 	 */
11647d8fb588SMatthias Schmidt 	for (vp= words; *vp; vp++) {
11657d8fb588SMatthias Schmidt 	    for (mbp = *vp; *mbp; mbp++) {
11667d8fb588SMatthias Schmidt 		*obp++ = *mbp & TRIM;
11677d8fb588SMatthias Schmidt 		if (obp == OBUF_END) {
11687d8fb588SMatthias Schmidt 		    tmp = short2str(obuf);
11697d8fb588SMatthias Schmidt 		    (void) xwrite(0, tmp, strlen (tmp));
11707d8fb588SMatthias Schmidt 		    obp = obuf;
11717d8fb588SMatthias Schmidt 		}
11727d8fb588SMatthias Schmidt 	    }
11737d8fb588SMatthias Schmidt 	    *obp++ = '\n';
11747d8fb588SMatthias Schmidt 	    if (obp == OBUF_END) {
11757d8fb588SMatthias Schmidt 	        tmp = short2str(obuf);
11767d8fb588SMatthias Schmidt 		(void) xwrite(0, tmp, strlen (tmp));
11777d8fb588SMatthias Schmidt 		obp = obuf;
11787d8fb588SMatthias Schmidt 	    }
11797d8fb588SMatthias Schmidt 	}
11807d8fb588SMatthias Schmidt 	if (words != Dv)
11817d8fb588SMatthias Schmidt 	    blkfree(words);
11827d8fb588SMatthias Schmidt     }
11837d8fb588SMatthias Schmidt     *obp = 0;
11847d8fb588SMatthias Schmidt     tmp = short2str(obuf);
11857d8fb588SMatthias Schmidt     (void) xwrite(0, tmp, strlen (tmp));
11867d8fb588SMatthias Schmidt     (void) lseek(0, (off_t) 0, L_SET);
11877d8fb588SMatthias Schmidt     cleanup_until(&inheredoc);
11887d8fb588SMatthias Schmidt }
1189