xref: /illumos-gate/usr/src/cmd/csh/sh.dol.c (revision 65b0c20e)
17c478bd9Sstevel@tonic-gate /*
26c02b4a4Smuffin  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate #include <unistd.h>		/* for lseek prototype */
187c478bd9Sstevel@tonic-gate #include "sh.h"
197c478bd9Sstevel@tonic-gate #include "sh.tconst.h"
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate /*
227c478bd9Sstevel@tonic-gate  * C shell
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * These routines perform variable substitution and quoting via ' and ".
277c478bd9Sstevel@tonic-gate  * To this point these constructs have been preserved in the divided
287c478bd9Sstevel@tonic-gate  * input words.  Here we expand variables and turn quoting via ' and " into
297c478bd9Sstevel@tonic-gate  * QUOTE bits on characters (which prevent further interpretation).
307c478bd9Sstevel@tonic-gate  * If the `:q' modifier was applied during history expansion, then
317c478bd9Sstevel@tonic-gate  * some QUOTEing may have occurred already, so we dont "trim()" here.
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate int	Dpeekc, Dpeekrd;		/* Peeks for DgetC and Dreadc */
357c478bd9Sstevel@tonic-gate tchar	*Dcp, **Dvp;			/* Input vector for Dreadc */
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #define	DEOF	-1
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #define	unDgetC(c)	Dpeekc = c
407c478bd9Sstevel@tonic-gate 
41*65b0c20eSnakanon #define	QUOTES		(_Q|_Q1|_ESC)	/* \ ' " ` */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * The following variables give the information about the current
457c478bd9Sstevel@tonic-gate  * $ expansion, recording the current word position, the remaining
467c478bd9Sstevel@tonic-gate  * words within this expansion, the count of remaining words, and the
477c478bd9Sstevel@tonic-gate  * information about any : modifier which is being applied.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate tchar	*dolp;			/* Remaining chars from this word */
507c478bd9Sstevel@tonic-gate tchar	**dolnxt;		/* Further words */
517c478bd9Sstevel@tonic-gate int	dolcnt;			/* Count of further words */
527c478bd9Sstevel@tonic-gate tchar	dolmod;			/* : modifier character */
537c478bd9Sstevel@tonic-gate int	dolmcnt;		/* :gx -> 10000, else 1 */
547c478bd9Sstevel@tonic-gate 
556c02b4a4Smuffin void	Dfix2(tchar **);
566c02b4a4Smuffin void	Dgetdol(void);
576c02b4a4Smuffin void	setDolp(tchar *);
586c02b4a4Smuffin void	unDredc(int);
596c02b4a4Smuffin 
607c478bd9Sstevel@tonic-gate /*
617c478bd9Sstevel@tonic-gate  * Fix up the $ expansions and quotations in the
627c478bd9Sstevel@tonic-gate  * argument list to command t.
637c478bd9Sstevel@tonic-gate  */
646c02b4a4Smuffin void
656c02b4a4Smuffin Dfix(struct command *t)
667c478bd9Sstevel@tonic-gate {
676c02b4a4Smuffin 	tchar **pp;
686c02b4a4Smuffin 	tchar *p;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #ifdef TRACE
717c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix()\n");
727c478bd9Sstevel@tonic-gate #endif
737c478bd9Sstevel@tonic-gate 	if (noexec)
747c478bd9Sstevel@tonic-gate 		return;
757c478bd9Sstevel@tonic-gate 	/* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
76*65b0c20eSnakanon 	for (pp = t->t_dcom; p = *pp++; )
777c478bd9Sstevel@tonic-gate 		while (*p)
787c478bd9Sstevel@tonic-gate 			if (cmap(*p++, _DOL|QUOTES)) {	/* $, \, ', ", ` */
797c478bd9Sstevel@tonic-gate 				Dfix2(t->t_dcom);	/* found one */
807c478bd9Sstevel@tonic-gate 				blkfree(t->t_dcom);
817c478bd9Sstevel@tonic-gate 				t->t_dcom = gargv;
827c478bd9Sstevel@tonic-gate 				gargv = 0;
837c478bd9Sstevel@tonic-gate 				return;
847c478bd9Sstevel@tonic-gate 			}
857c478bd9Sstevel@tonic-gate }
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * $ substitute one word, for i/o redirection
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate tchar *
916c02b4a4Smuffin Dfix1(tchar *cp)
927c478bd9Sstevel@tonic-gate {
937c478bd9Sstevel@tonic-gate 	tchar *Dv[2];
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate #ifdef TRACE
967c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix1()\n");
977c478bd9Sstevel@tonic-gate #endif
987c478bd9Sstevel@tonic-gate 	if (noexec)
997c478bd9Sstevel@tonic-gate 		return (0);
1007c478bd9Sstevel@tonic-gate 	Dv[0] = cp; Dv[1] = NOSTR;
1017c478bd9Sstevel@tonic-gate 	Dfix2(Dv);
1027c478bd9Sstevel@tonic-gate 	if (gargc != 1) {
1037c478bd9Sstevel@tonic-gate 		setname(cp);
1047c478bd9Sstevel@tonic-gate 		bferr("Ambiguous");
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 	cp = savestr(gargv[0]);
1077c478bd9Sstevel@tonic-gate 	blkfree(gargv), gargv = 0;
1087c478bd9Sstevel@tonic-gate 	return (cp);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Subroutine to do actual fixing after state initialization.
1137c478bd9Sstevel@tonic-gate  */
1146c02b4a4Smuffin void
1156c02b4a4Smuffin Dfix2(tchar **v)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	tchar *agargv[GAVSIZ];
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate #ifdef TRACE
1207c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dfix2()\n");
1217c478bd9Sstevel@tonic-gate #endif
1227c478bd9Sstevel@tonic-gate 	ginit(agargv);			/* Initialize glob's area pointers */
123*65b0c20eSnakanon 	Dvp = v; Dcp = S_ /* "" */;	/* Setup input vector for Dreadc */
1247c478bd9Sstevel@tonic-gate 	unDgetC(0); unDredc(0);		/* Clear out any old peeks (at error) */
1257c478bd9Sstevel@tonic-gate 	dolp = 0; dolcnt = 0;		/* Clear out residual $ expands (...) */
1267c478bd9Sstevel@tonic-gate 	while (Dword())
1277c478bd9Sstevel@tonic-gate 		continue;
1287c478bd9Sstevel@tonic-gate 	gargv = copyblk(gargv);
1297c478bd9Sstevel@tonic-gate }
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Get a word.  This routine is analogous to the routine
1337c478bd9Sstevel@tonic-gate  * word() in sh.lex.c for the main lexical input.  One difference
1347c478bd9Sstevel@tonic-gate  * here is that we don't get a newline to terminate our expansion.
1357c478bd9Sstevel@tonic-gate  * Rather, DgetC will return a DEOF when we hit the end-of-input.
1367c478bd9Sstevel@tonic-gate  */
1376c02b4a4Smuffin int
1386c02b4a4Smuffin Dword(void)
1397c478bd9Sstevel@tonic-gate {
1406c02b4a4Smuffin 	int c, c1;
1417c478bd9Sstevel@tonic-gate 	static tchar *wbuf = NULL;
1427c478bd9Sstevel@tonic-gate 	static int wbufsiz = BUFSIZ;
1436c02b4a4Smuffin 	int wp = 0;
1446c02b4a4Smuffin 	bool dolflg;
1457c478bd9Sstevel@tonic-gate 	bool sofar = 0;
1467c478bd9Sstevel@tonic-gate #define	DYNAMICBUFFER() \
1477c478bd9Sstevel@tonic-gate 	do { \
1487c478bd9Sstevel@tonic-gate 		if (wp >= wbufsiz) { \
1497c478bd9Sstevel@tonic-gate 			wbufsiz += BUFSIZ; \
1507c478bd9Sstevel@tonic-gate 			wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
1517c478bd9Sstevel@tonic-gate 		} \
1527c478bd9Sstevel@tonic-gate 	} while (0)
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate #ifdef TRACE
1557c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dword()\n");
1567c478bd9Sstevel@tonic-gate #endif
1577c478bd9Sstevel@tonic-gate 	if (wbuf == NULL)
1587c478bd9Sstevel@tonic-gate 		wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
1597c478bd9Sstevel@tonic-gate loop:
1607c478bd9Sstevel@tonic-gate 	c = DgetC(DODOL);
1617c478bd9Sstevel@tonic-gate 	switch (c) {
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	case DEOF:
1647c478bd9Sstevel@tonic-gate deof:
1657c478bd9Sstevel@tonic-gate 		if (sofar == 0)
1667c478bd9Sstevel@tonic-gate 			return (0);
1677c478bd9Sstevel@tonic-gate 		/* finish this word and catch the code above the next time */
1687c478bd9Sstevel@tonic-gate 		unDredc(c);
1697c478bd9Sstevel@tonic-gate 		/* fall into ... */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	case '\n':
1727c478bd9Sstevel@tonic-gate 		wbuf[wp] = 0;
1737c478bd9Sstevel@tonic-gate 		goto ret;
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	case ' ':
1767c478bd9Sstevel@tonic-gate 	case '\t':
1777c478bd9Sstevel@tonic-gate 		goto loop;
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	case '`':
1807c478bd9Sstevel@tonic-gate 		/* We preserve ` quotations which are done yet later */
1817c478bd9Sstevel@tonic-gate 		wbuf[wp++] = c;
1827c478bd9Sstevel@tonic-gate 	case '\'':
1837c478bd9Sstevel@tonic-gate 	case '"':
1847c478bd9Sstevel@tonic-gate 		/*
1857c478bd9Sstevel@tonic-gate 		 * Note that DgetC never returns a QUOTES character
1867c478bd9Sstevel@tonic-gate 		 * from an expansion, so only true input quotes will
1877c478bd9Sstevel@tonic-gate 		 * get us here or out.
1887c478bd9Sstevel@tonic-gate 		 */
1897c478bd9Sstevel@tonic-gate 		c1 = c;
1907c478bd9Sstevel@tonic-gate 		dolflg = c1 == '"' ? DODOL : 0;
1917c478bd9Sstevel@tonic-gate 		for (;;) {
1927c478bd9Sstevel@tonic-gate 			c = DgetC(dolflg);
1937c478bd9Sstevel@tonic-gate 			if (c == c1)
1947c478bd9Sstevel@tonic-gate 				break;
1957c478bd9Sstevel@tonic-gate 			if (c == '\n' || c == DEOF)
1967c478bd9Sstevel@tonic-gate 				error("Unmatched %c", (tchar) c1);
1977c478bd9Sstevel@tonic-gate 			if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
1987c478bd9Sstevel@tonic-gate 				--wp;
1997c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
2007c478bd9Sstevel@tonic-gate 			switch (c1) {
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 			case '"':
2037c478bd9Sstevel@tonic-gate 				/*
2047c478bd9Sstevel@tonic-gate 				 * Leave any `s alone for later.
2057c478bd9Sstevel@tonic-gate 				 * Other chars are all quoted, thus `...`
2067c478bd9Sstevel@tonic-gate 				 * can tell it was within "...".
2077c478bd9Sstevel@tonic-gate 				 */
2087c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
2097c478bd9Sstevel@tonic-gate 				break;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 			case '\'':
2127c478bd9Sstevel@tonic-gate 				/* Prevent all further interpretation */
2137c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c | QUOTE;
2147c478bd9Sstevel@tonic-gate 				break;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 			case '`':
2177c478bd9Sstevel@tonic-gate 				/* Leave all text alone for later */
2187c478bd9Sstevel@tonic-gate 				wbuf[wp++] = c;
2197c478bd9Sstevel@tonic-gate 				break;
2207c478bd9Sstevel@tonic-gate 			}
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 		if (c1 == '`') {
2237c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
2247c478bd9Sstevel@tonic-gate 			wbuf[wp++] = '`';
2257c478bd9Sstevel@tonic-gate 		}
2267c478bd9Sstevel@tonic-gate 		goto pack;		/* continue the word */
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	case '\\':
2297c478bd9Sstevel@tonic-gate 		c = DgetC(0);		/* No $ subst! */
2307c478bd9Sstevel@tonic-gate 		if (c == '\n' || c == DEOF)
2317c478bd9Sstevel@tonic-gate 			goto loop;
2327c478bd9Sstevel@tonic-gate 		c |= QUOTE;
2337c478bd9Sstevel@tonic-gate 		break;
2347c478bd9Sstevel@tonic-gate #ifdef MBCHAR /* Could be a space char from aux. codeset. */
2357c478bd9Sstevel@tonic-gate 	default:
2367c478bd9Sstevel@tonic-gate 		if (isauxsp(c)) goto loop;
2377c478bd9Sstevel@tonic-gate #endif /* MBCHAR */
2387c478bd9Sstevel@tonic-gate 	}
2397c478bd9Sstevel@tonic-gate 	unDgetC(c);
2407c478bd9Sstevel@tonic-gate pack:
2417c478bd9Sstevel@tonic-gate 	sofar = 1;
2427c478bd9Sstevel@tonic-gate 	/* pack up more characters in this word */
2437c478bd9Sstevel@tonic-gate 	for (;;) {
2447c478bd9Sstevel@tonic-gate 		c = DgetC(DODOL);
2457c478bd9Sstevel@tonic-gate 		if (c == '\\') {
2467c478bd9Sstevel@tonic-gate 			c = DgetC(0);
2477c478bd9Sstevel@tonic-gate 			if (c == DEOF)
2487c478bd9Sstevel@tonic-gate 				goto deof;
2497c478bd9Sstevel@tonic-gate 			if (c == '\n')
2507c478bd9Sstevel@tonic-gate 				c = ' ';
2517c478bd9Sstevel@tonic-gate 			else
2527c478bd9Sstevel@tonic-gate 				c |= QUOTE;
2537c478bd9Sstevel@tonic-gate 		}
2547c478bd9Sstevel@tonic-gate 		if (c == DEOF)
2557c478bd9Sstevel@tonic-gate 			goto deof;
2567c478bd9Sstevel@tonic-gate 		if (cmap(c, _SP|_NL|_Q|_Q1) ||
2577c478bd9Sstevel@tonic-gate 		    isauxsp(c)) {		/* sp \t\n'"` or aux. sp */
2587c478bd9Sstevel@tonic-gate 			unDgetC(c);
2597c478bd9Sstevel@tonic-gate 			if (cmap(c, QUOTES))
2607c478bd9Sstevel@tonic-gate 				goto loop;
2617c478bd9Sstevel@tonic-gate 			DYNAMICBUFFER();
2627c478bd9Sstevel@tonic-gate 			wbuf[wp++] = 0;
2637c478bd9Sstevel@tonic-gate 			goto ret;
2647c478bd9Sstevel@tonic-gate 		}
2657c478bd9Sstevel@tonic-gate 		DYNAMICBUFFER();
2667c478bd9Sstevel@tonic-gate 		wbuf[wp++] = c;
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate ret:
2697c478bd9Sstevel@tonic-gate 	Gcat(S_ /* "" */, wbuf);
2707c478bd9Sstevel@tonic-gate 	return (1);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /*
2747c478bd9Sstevel@tonic-gate  * Get a character, performing $ substitution unless flag is 0.
2757c478bd9Sstevel@tonic-gate  * Any QUOTES character which is returned from a $ expansion is
2767c478bd9Sstevel@tonic-gate  * QUOTEd so that it will not be recognized above.
2777c478bd9Sstevel@tonic-gate  */
2786c02b4a4Smuffin int
2796c02b4a4Smuffin DgetC(int flag)
2807c478bd9Sstevel@tonic-gate {
2816c02b4a4Smuffin 	int c;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate top:
2847c478bd9Sstevel@tonic-gate 	if (c = Dpeekc) {
2857c478bd9Sstevel@tonic-gate 		Dpeekc = 0;
2867c478bd9Sstevel@tonic-gate 		return (c);
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	if (lap) {
2897c478bd9Sstevel@tonic-gate 		c = *lap++ & (QUOTE|TRIM);
2907c478bd9Sstevel@tonic-gate 		if (c == 0) {
2917c478bd9Sstevel@tonic-gate 			lap = 0;
2927c478bd9Sstevel@tonic-gate 			goto top;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate quotspec:
2957c478bd9Sstevel@tonic-gate 		/*
2967c478bd9Sstevel@tonic-gate 		 *	don't quote things if there was an error (err!=0)
2977c478bd9Sstevel@tonic-gate 		 * 	the input is original, not from a substitution and
2987c478bd9Sstevel@tonic-gate 		 *	therefore should not be quoted
2997c478bd9Sstevel@tonic-gate 		 */
3007c478bd9Sstevel@tonic-gate 		if (!err && cmap(c, QUOTES))
3017c478bd9Sstevel@tonic-gate 			return (c | QUOTE);
3027c478bd9Sstevel@tonic-gate 		return (c);
3037c478bd9Sstevel@tonic-gate 	}
3047c478bd9Sstevel@tonic-gate 	if (dolp) {
3057c478bd9Sstevel@tonic-gate 		if (c = *dolp++ & (QUOTE|TRIM))
3067c478bd9Sstevel@tonic-gate 			goto quotspec;
3077c478bd9Sstevel@tonic-gate 		if (dolcnt > 0) {
3087c478bd9Sstevel@tonic-gate 			setDolp(*dolnxt++);
3097c478bd9Sstevel@tonic-gate 			--dolcnt;
3107c478bd9Sstevel@tonic-gate 			return (' ');
3117c478bd9Sstevel@tonic-gate 		}
3127c478bd9Sstevel@tonic-gate 		dolp = 0;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 	if (dolcnt > 0) {
3157c478bd9Sstevel@tonic-gate 		setDolp(*dolnxt++);
3167c478bd9Sstevel@tonic-gate 		--dolcnt;
3177c478bd9Sstevel@tonic-gate 		goto top;
3187c478bd9Sstevel@tonic-gate 	}
3197c478bd9Sstevel@tonic-gate 	c = Dredc();
3207c478bd9Sstevel@tonic-gate 	if (c == '$' && flag) {
3217c478bd9Sstevel@tonic-gate 		Dgetdol();
3227c478bd9Sstevel@tonic-gate 		goto top;
3237c478bd9Sstevel@tonic-gate 	}
3247c478bd9Sstevel@tonic-gate 	return (c);
3257c478bd9Sstevel@tonic-gate }
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate tchar *nulvec[] = { 0 };
3287c478bd9Sstevel@tonic-gate struct	varent nulargv = { nulvec, S_argv, 0 };
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Handle the multitudinous $ expansion forms.
3327c478bd9Sstevel@tonic-gate  * Ugh.
3337c478bd9Sstevel@tonic-gate  */
3346c02b4a4Smuffin void
3356c02b4a4Smuffin Dgetdol(void)
3367c478bd9Sstevel@tonic-gate {
3376c02b4a4Smuffin 	tchar *np;
3386c02b4a4Smuffin 	struct varent *vp;
3397c478bd9Sstevel@tonic-gate 	tchar name[MAX_VREF_LEN];
3407c478bd9Sstevel@tonic-gate 	int c, sc;
3417c478bd9Sstevel@tonic-gate 	int subscr = 0, lwb = 1, upb = 0;
3427c478bd9Sstevel@tonic-gate 	bool dimen = 0, bitset = 0;
343*65b0c20eSnakanon 	tchar wbuf[BUFSIZ + MB_LEN_MAX]; /* read_ may return extra bytes */
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate #ifdef TRACE
3467c478bd9Sstevel@tonic-gate 	tprintf("TRACE- Dgetdol()\n");
3477c478bd9Sstevel@tonic-gate #endif
3487c478bd9Sstevel@tonic-gate 	dolmod = dolmcnt = 0;
3497c478bd9Sstevel@tonic-gate 	c = sc = DgetC(0);
3507c478bd9Sstevel@tonic-gate 	if (c == '{')
3517c478bd9Sstevel@tonic-gate 		c = DgetC(0);		/* sc is { to take } later */
3527c478bd9Sstevel@tonic-gate 	if ((c & TRIM) == '#')
3537c478bd9Sstevel@tonic-gate 		dimen++, c = DgetC(0);		/* $# takes dimension */
3547c478bd9Sstevel@tonic-gate 	else if (c == '?')
3557c478bd9Sstevel@tonic-gate 		bitset++, c = DgetC(0);		/* $? tests existence */
3567c478bd9Sstevel@tonic-gate 	switch (c) {
357*65b0c20eSnakanon 
3587c478bd9Sstevel@tonic-gate 	case '$':
3597c478bd9Sstevel@tonic-gate 		if (dimen || bitset)
3607c478bd9Sstevel@tonic-gate syntax:
3617c478bd9Sstevel@tonic-gate 		error("Variable syntax");  /* No $?$, $#$ */
3627c478bd9Sstevel@tonic-gate 		setDolp(doldol);
3637c478bd9Sstevel@tonic-gate 		goto eatbrac;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	case '<'|QUOTE:
3667c478bd9Sstevel@tonic-gate 		if (dimen || bitset)
3677c478bd9Sstevel@tonic-gate 			goto syntax;		/* No $?<, $#< */
3687c478bd9Sstevel@tonic-gate 		for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
3697c478bd9Sstevel@tonic-gate 			if (np >= &wbuf[BUFSIZ-1])
3707c478bd9Sstevel@tonic-gate 				error("$< line too long");
3717c478bd9Sstevel@tonic-gate 			if (*np <= 0 || *np == '\n')
3727c478bd9Sstevel@tonic-gate 				break;
3737c478bd9Sstevel@tonic-gate 		}
3747c478bd9Sstevel@tonic-gate 		*np = 0;
3757c478bd9Sstevel@tonic-gate 		/*
3767c478bd9Sstevel@tonic-gate 		 * KLUDGE: dolmod is set here because it will
3777c478bd9Sstevel@tonic-gate 		 * cause setDolp to call domod and thus to copy wbuf.
3787c478bd9Sstevel@tonic-gate 		 * Otherwise setDolp would use it directly. If we saved
3797c478bd9Sstevel@tonic-gate 		 * it ourselves, no one would know when to free it.
3807c478bd9Sstevel@tonic-gate 		 * The actual function of the 'q' causes filename
3817c478bd9Sstevel@tonic-gate 		 * expansion not to be done on the interpolated value.
3827c478bd9Sstevel@tonic-gate 		 */
3837c478bd9Sstevel@tonic-gate 		dolmod = 'q';
3847c478bd9Sstevel@tonic-gate 		dolmcnt = 10000;
3857c478bd9Sstevel@tonic-gate 		setDolp(wbuf);
3867c478bd9Sstevel@tonic-gate 		goto eatbrac;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	case DEOF:
3897c478bd9Sstevel@tonic-gate 	case '\n':
3907c478bd9Sstevel@tonic-gate 		goto syntax;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	case '*':
3937c478bd9Sstevel@tonic-gate 		(void) strcpy_(name, S_argv);
3947c478bd9Sstevel@tonic-gate 		vp = adrof(S_argv);
3957c478bd9Sstevel@tonic-gate 		subscr = -1;			/* Prevent eating [...] */
3967c478bd9Sstevel@tonic-gate 		break;
3977c478bd9Sstevel@tonic-gate 
3987c478bd9Sstevel@tonic-gate 	default:
3997c478bd9Sstevel@tonic-gate 		np = name;
4007c478bd9Sstevel@tonic-gate 		if (digit(c)) {
4017c478bd9Sstevel@tonic-gate 			if (dimen)
4027c478bd9Sstevel@tonic-gate 				goto syntax;	/* No $#1, e.g. */
4037c478bd9Sstevel@tonic-gate 			subscr = 0;
4047c478bd9Sstevel@tonic-gate 			do {
4057c478bd9Sstevel@tonic-gate 				subscr = subscr * 10 + c - '0';
4067c478bd9Sstevel@tonic-gate 				c = DgetC(0);
4077c478bd9Sstevel@tonic-gate 			} while (digit(c));
4087c478bd9Sstevel@tonic-gate 			unDredc(c);
4097c478bd9Sstevel@tonic-gate 			if (subscr < 0)
4107c478bd9Sstevel@tonic-gate 				error("Subscript out of range");
4117c478bd9Sstevel@tonic-gate 			if (subscr == 0) {
4127c478bd9Sstevel@tonic-gate 				if (bitset) {
413*65b0c20eSnakanon 					dolp = file ? S_1 /* "1" */ : S_0 /* "0" */;
4147c478bd9Sstevel@tonic-gate 					goto eatbrac;
4157c478bd9Sstevel@tonic-gate 				}
4167c478bd9Sstevel@tonic-gate 				if (file == 0)
4177c478bd9Sstevel@tonic-gate 					error("No file for $0");
4187c478bd9Sstevel@tonic-gate 				setDolp(file);
4197c478bd9Sstevel@tonic-gate 				goto eatbrac;
4207c478bd9Sstevel@tonic-gate 			}
4217c478bd9Sstevel@tonic-gate 			if (bitset)
4227c478bd9Sstevel@tonic-gate 				goto syntax;
4237c478bd9Sstevel@tonic-gate 			vp = adrof(S_argv);
4247c478bd9Sstevel@tonic-gate 			if (vp == 0) {
4257c478bd9Sstevel@tonic-gate 				vp = &nulargv;
4267c478bd9Sstevel@tonic-gate 				goto eatmod;
4277c478bd9Sstevel@tonic-gate 			}
4287c478bd9Sstevel@tonic-gate 			break;
4297c478bd9Sstevel@tonic-gate 		}
4307c478bd9Sstevel@tonic-gate 		if (!alnum(c))
4317c478bd9Sstevel@tonic-gate 			goto syntax;
4327c478bd9Sstevel@tonic-gate 		for (;;) {
4337c478bd9Sstevel@tonic-gate 			*np++ = c;
4347c478bd9Sstevel@tonic-gate 			c = DgetC(0);
4357c478bd9Sstevel@tonic-gate 			if (!alnum(c))
4367c478bd9Sstevel@tonic-gate 				break;
4377c478bd9Sstevel@tonic-gate 			/* if variable name is > 20, complain */
4387c478bd9Sstevel@tonic-gate 			if (np >= &name[MAX_VAR_LEN])
4397c478bd9Sstevel@tonic-gate 				error("Variable name too long");
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 		}
4427c478bd9Sstevel@tonic-gate 		*np++ = 0;
4437c478bd9Sstevel@tonic-gate 		unDredc(c);
4447c478bd9Sstevel@tonic-gate 		vp = adrof(name);
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 	if (bitset) {
447*65b0c20eSnakanon 		/*
448*65b0c20eSnakanon 		 * getenv() to getenv_(), because 'name''s type is now tchar *
449*65b0c20eSnakanon 		 * no need to xalloc
450*65b0c20eSnakanon 		 */
451*65b0c20eSnakanon 		dolp = (vp || getenv_(name)) ? S_1 /* "1" */ : S_0 /* "0" */;
4527c478bd9Sstevel@tonic-gate 		goto eatbrac;
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 	if (vp == 0) {
455*65b0c20eSnakanon 		/*
456*65b0c20eSnakanon 		 * getenv() to getenv_(), because 'name''s type is now tchar *
457*65b0c20eSnakanon 		 * no need to xalloc
458*65b0c20eSnakanon 		 */
4597c478bd9Sstevel@tonic-gate 		np = getenv_(name);
4607c478bd9Sstevel@tonic-gate 		if (np) {
4617c478bd9Sstevel@tonic-gate 			addla(np);
4627c478bd9Sstevel@tonic-gate 			goto eatbrac;
4637c478bd9Sstevel@tonic-gate 		}
4647c478bd9Sstevel@tonic-gate 		udvar(name);
4657c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	c = DgetC(0);
4687c478bd9Sstevel@tonic-gate 	upb = blklen(vp->vec);
4697c478bd9Sstevel@tonic-gate 	if (dimen == 0 && subscr == 0 && c == '[') {
4707c478bd9Sstevel@tonic-gate 		np = name;
4717c478bd9Sstevel@tonic-gate 		for (;;) {
4727c478bd9Sstevel@tonic-gate 			c = DgetC(DODOL);	/* Allow $ expand within [ ] */
4737c478bd9Sstevel@tonic-gate 			if (c == ']')
4747c478bd9Sstevel@tonic-gate 				break;
4757c478bd9Sstevel@tonic-gate 			if (c == '\n' || c == DEOF)
4767c478bd9Sstevel@tonic-gate 				goto syntax;
4777c478bd9Sstevel@tonic-gate 			if (np >= &name[MAX_VREF_LEN])
4787c478bd9Sstevel@tonic-gate 				error("Variable reference too long");
4797c478bd9Sstevel@tonic-gate 			*np++ = c;
4807c478bd9Sstevel@tonic-gate 		}
4817c478bd9Sstevel@tonic-gate 		*np = 0, np = name;
4827c478bd9Sstevel@tonic-gate 		if (dolp || dolcnt)		/* $ exp must end before ] */
4837c478bd9Sstevel@tonic-gate 			goto syntax;
4847c478bd9Sstevel@tonic-gate 		if (!*np)
4857c478bd9Sstevel@tonic-gate 			goto syntax;
4867c478bd9Sstevel@tonic-gate 		if (digit(*np)) {
4876c02b4a4Smuffin 			int i = 0;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			while (digit(*np))
4907c478bd9Sstevel@tonic-gate 				i = i * 10 + *np++ - '0';
491*65b0c20eSnakanon /*			if ((i < 0 || i > upb) && !any(*np, "-*")) { */
492*65b0c20eSnakanon 			if ((i < 0 || i > upb) && (*np != '-') && (*np != '*')) {
4937c478bd9Sstevel@tonic-gate oob:
4947c478bd9Sstevel@tonic-gate 				setname(vp->v_name);
4957c478bd9Sstevel@tonic-gate 				error("Subscript out of range");
4967c478bd9Sstevel@tonic-gate 			}
4977c478bd9Sstevel@tonic-gate 			lwb = i;
4987c478bd9Sstevel@tonic-gate 			if (!*np)
499*65b0c20eSnakanon 				upb = lwb, np = S_AST /* "*" */;
5007c478bd9Sstevel@tonic-gate 		}
5017c478bd9Sstevel@tonic-gate 		if (*np == '*')
5027c478bd9Sstevel@tonic-gate 			np++;
5037c478bd9Sstevel@tonic-gate 		else if (*np != '-')
5047c478bd9Sstevel@tonic-gate 			goto syntax;
5057c478bd9Sstevel@tonic-gate 		else {
5066c02b4a4Smuffin 			int i = upb;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 			np++;
5097c478bd9Sstevel@tonic-gate 			if (digit(*np)) {
5107c478bd9Sstevel@tonic-gate 				i = 0;
5117c478bd9Sstevel@tonic-gate 				while (digit(*np))
5127c478bd9Sstevel@tonic-gate 					i = i * 10 + *np++ - '0';
5137c478bd9Sstevel@tonic-gate 				if (i < 0 || i > upb)
5147c478bd9Sstevel@tonic-gate 					goto oob;
5157c478bd9Sstevel@tonic-gate 			}
5167c478bd9Sstevel@tonic-gate 			if (i < lwb)
5177c478bd9Sstevel@tonic-gate 				upb = lwb - 1;
5187c478bd9Sstevel@tonic-gate 			else
5197c478bd9Sstevel@tonic-gate 				upb = i;
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 		if (lwb == 0) {
5227c478bd9Sstevel@tonic-gate 			if (upb != 0)
5237c478bd9Sstevel@tonic-gate 				goto oob;
5247c478bd9Sstevel@tonic-gate 			upb = -1;
5257c478bd9Sstevel@tonic-gate 		}
5267c478bd9Sstevel@tonic-gate 		if (*np)
5277c478bd9Sstevel@tonic-gate 			goto syntax;
5287c478bd9Sstevel@tonic-gate 	} else {
5297c478bd9Sstevel@tonic-gate 		if (subscr > 0)
5307c478bd9Sstevel@tonic-gate 			if (subscr > upb)
5317c478bd9Sstevel@tonic-gate 				lwb = 1, upb = 0;
5327c478bd9Sstevel@tonic-gate 			else
5337c478bd9Sstevel@tonic-gate 				lwb = upb = subscr;
5347c478bd9Sstevel@tonic-gate 		unDredc(c);
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 	if (dimen) {
5377c478bd9Sstevel@tonic-gate 		tchar *cp = putn(upb - lwb + 1);
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		addla(cp);
5407c478bd9Sstevel@tonic-gate 		xfree(cp);
5417c478bd9Sstevel@tonic-gate 	} else {
5427c478bd9Sstevel@tonic-gate eatmod:
5437c478bd9Sstevel@tonic-gate 		c = DgetC(0);
5447c478bd9Sstevel@tonic-gate 		if (c == ':') {
5457c478bd9Sstevel@tonic-gate 			c = DgetC(0), dolmcnt = 1;
5467c478bd9Sstevel@tonic-gate 			if (c == 'g')
5477c478bd9Sstevel@tonic-gate 				c = DgetC(0), dolmcnt = 10000;
5487c478bd9Sstevel@tonic-gate 			if (!any(c, S_htrqxe))
5497c478bd9Sstevel@tonic-gate 				error("Bad : mod in $");
5507c478bd9Sstevel@tonic-gate 			dolmod = c;
5517c478bd9Sstevel@tonic-gate 			if (c == 'q')
5527c478bd9Sstevel@tonic-gate 				dolmcnt = 10000;
5537c478bd9Sstevel@tonic-gate 		} else
5547c478bd9Sstevel@tonic-gate 			unDredc(c);
5557c478bd9Sstevel@tonic-gate 		dolnxt = &vp->vec[lwb - 1];
5567c478bd9Sstevel@tonic-gate 		dolcnt = upb - lwb + 1;
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate eatbrac:
5597c478bd9Sstevel@tonic-gate 	if (sc == '{') {
5607c478bd9Sstevel@tonic-gate 		c = Dredc();
5617c478bd9Sstevel@tonic-gate 		if (c != '}')
5627c478bd9Sstevel@tonic-gate 			goto syntax;
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5666c02b4a4Smuffin void
5676c02b4a4Smuffin setDolp(tchar *cp)
5687c478bd9Sstevel@tonic-gate {
5696c02b4a4Smuffin 	tchar *dp;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate #ifdef TRACE
5727c478bd9Sstevel@tonic-gate 	tprintf("TRACE- setDolp()\n");
5737c478bd9Sstevel@tonic-gate #endif
5747c478bd9Sstevel@tonic-gate 	if (dolmod == 0 || dolmcnt == 0) {
5757c478bd9Sstevel@tonic-gate 		dolp = cp;
5767c478bd9Sstevel@tonic-gate 		return;
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 	dp = domod(cp, dolmod);
5797c478bd9Sstevel@tonic-gate 	if (dp) {
5807c478bd9Sstevel@tonic-gate 		dolmcnt--;
5817c478bd9Sstevel@tonic-gate 		addla(dp);
5827c478bd9Sstevel@tonic-gate 		xfree(dp);
5837c478bd9Sstevel@tonic-gate 	} else
5847c478bd9Sstevel@tonic-gate 		addla(cp);
585*65b0c20eSnakanon 	dolp = S_ /* "" */;
5867c478bd9Sstevel@tonic-gate }
5877c478bd9Sstevel@tonic-gate 
5886c02b4a4Smuffin void
5896c02b4a4Smuffin unDredc(int c)
5907c478bd9Sstevel@tonic-gate {
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	Dpeekrd = c;
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5956c02b4a4Smuffin int
5967c478bd9Sstevel@tonic-gate Dredc()
5977c478bd9Sstevel@tonic-gate {
5986c02b4a4Smuffin 	int c;
5997c478bd9Sstevel@tonic-gate 
6007c478bd9Sstevel@tonic-gate 	if (c = Dpeekrd) {
6017c478bd9Sstevel@tonic-gate 		Dpeekrd = 0;
6027c478bd9Sstevel@tonic-gate 		return (c);
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 	if (Dcp && (c = *Dcp++))
6057c478bd9Sstevel@tonic-gate 		return (c&(QUOTE|TRIM));
6067c478bd9Sstevel@tonic-gate 	if (*Dvp == 0) {
6077c478bd9Sstevel@tonic-gate 		Dcp = 0;
6087c478bd9Sstevel@tonic-gate 		return (DEOF);
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 	Dcp = *Dvp++;
6117c478bd9Sstevel@tonic-gate 	return (' ');
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6146c02b4a4Smuffin void
6156c02b4a4Smuffin Dtestq(int c)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if (cmap(c, QUOTES))
6197c478bd9Sstevel@tonic-gate 		gflag = 1;
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate /*
6237c478bd9Sstevel@tonic-gate  * Form a shell temporary file (in unit 0) from the words
6247c478bd9Sstevel@tonic-gate  * of the shell input up to a line the same as "term".
6257c478bd9Sstevel@tonic-gate  * Unit 0 should have been closed before this call.
6267c478bd9Sstevel@tonic-gate  */
6276c02b4a4Smuffin void
6286c02b4a4Smuffin heredoc(tchar *term)
6297c478bd9Sstevel@tonic-gate {
6306c02b4a4Smuffin 	int c;
6317c478bd9Sstevel@tonic-gate 	tchar *Dv[2];
6327c478bd9Sstevel@tonic-gate 	tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
6337c478bd9Sstevel@tonic-gate 	int ocnt, lcnt, mcnt;
6346c02b4a4Smuffin 	tchar *lbp, *obp, *mbp;
6357c478bd9Sstevel@tonic-gate 	tchar **vp;
6367c478bd9Sstevel@tonic-gate 	bool quoted;
6377c478bd9Sstevel@tonic-gate 	tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
6387c478bd9Sstevel@tonic-gate 'X', 'X', 'X', 0};
6397c478bd9Sstevel@tonic-gate 	int fd1;
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate #ifdef TRACE
6427c478bd9Sstevel@tonic-gate 	tprintf("TRACE- heredoc()\n");
6437c478bd9Sstevel@tonic-gate #endif
6447c478bd9Sstevel@tonic-gate 	if ((fd1 = mkstemp_(shtemp)) < 0)
6457c478bd9Sstevel@tonic-gate 		Perror(shtemp);
6467c478bd9Sstevel@tonic-gate 	(void) unlink_(shtemp);			/* 0 0 inode! */
6477c478bd9Sstevel@tonic-gate 	unsetfd(fd1);
6487c478bd9Sstevel@tonic-gate 	Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
6497c478bd9Sstevel@tonic-gate 	trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
6507c478bd9Sstevel@tonic-gate 	ocnt = BUFSIZ; obp = obuf;
6517c478bd9Sstevel@tonic-gate 	for (;;) {
6527c478bd9Sstevel@tonic-gate 		/*
6537c478bd9Sstevel@tonic-gate 		 * Read up a line
6547c478bd9Sstevel@tonic-gate 		 */
6557c478bd9Sstevel@tonic-gate 		lbp = lbuf; lcnt = BUFSIZ - 4;
6567c478bd9Sstevel@tonic-gate 		for (;;) {
6577c478bd9Sstevel@tonic-gate 			c = readc(1);		/* 1 -> Want EOF returns */
6587c478bd9Sstevel@tonic-gate 			if (c < 0) {
6597c478bd9Sstevel@tonic-gate 				setname(term);
6607c478bd9Sstevel@tonic-gate 				bferr("<< terminator not found");
6617c478bd9Sstevel@tonic-gate 			}
6627c478bd9Sstevel@tonic-gate 			if (c == '\n')
6637c478bd9Sstevel@tonic-gate 				break;
6647c478bd9Sstevel@tonic-gate 			if (c &= TRIM) {
6657c478bd9Sstevel@tonic-gate 				*lbp++ = c;
6667c478bd9Sstevel@tonic-gate 				if (--lcnt < 0) {
667*65b0c20eSnakanon 					setname(S_LESLES /* "<<" */);
6687c478bd9Sstevel@tonic-gate 					error("Line overflow");
669*65b0c20eSnakanon 				}
6707c478bd9Sstevel@tonic-gate 			}
6717c478bd9Sstevel@tonic-gate 		}
6727c478bd9Sstevel@tonic-gate 		*lbp = 0;
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		/*
6757c478bd9Sstevel@tonic-gate 		 * Compare to terminator -- before expansion
6767c478bd9Sstevel@tonic-gate 		 */
6777c478bd9Sstevel@tonic-gate 		if (eq(lbuf, term)) {
6787c478bd9Sstevel@tonic-gate 			(void) write_(0, obuf, BUFSIZ - ocnt);
6797c478bd9Sstevel@tonic-gate 			(void) lseek(0, (off_t)0, 0);
6807c478bd9Sstevel@tonic-gate 			return;
6817c478bd9Sstevel@tonic-gate 		}
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 		/*
6847c478bd9Sstevel@tonic-gate 		 * If term was quoted or -n just pass it on
6857c478bd9Sstevel@tonic-gate 		 */
6867c478bd9Sstevel@tonic-gate 		if (quoted || noexec) {
6877c478bd9Sstevel@tonic-gate 			*lbp++ = '\n'; *lbp = 0;
688*65b0c20eSnakanon 			for (lbp = lbuf; c = *lbp++; ) {
6897c478bd9Sstevel@tonic-gate 				*obp++ = c;
6907c478bd9Sstevel@tonic-gate 				if (--ocnt == 0) {
6917c478bd9Sstevel@tonic-gate 					(void) write_(0, obuf, BUFSIZ);
6927c478bd9Sstevel@tonic-gate 					obp = obuf; ocnt = BUFSIZ;
6937c478bd9Sstevel@tonic-gate 				}
6947c478bd9Sstevel@tonic-gate 			}
6957c478bd9Sstevel@tonic-gate 			continue;
6967c478bd9Sstevel@tonic-gate 		}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		/*
6997c478bd9Sstevel@tonic-gate 		 * Term wasn't quoted so variable and then command
7007c478bd9Sstevel@tonic-gate 		 * expand the input line
7017c478bd9Sstevel@tonic-gate 		 */
7027c478bd9Sstevel@tonic-gate 		Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
7037c478bd9Sstevel@tonic-gate 		for (;;) {
7047c478bd9Sstevel@tonic-gate 			c = DgetC(DODOL);
7057c478bd9Sstevel@tonic-gate 			if (c == DEOF)
7067c478bd9Sstevel@tonic-gate 				break;
7077c478bd9Sstevel@tonic-gate 			if ((c &= TRIM) == 0)
7087c478bd9Sstevel@tonic-gate 				continue;
7097c478bd9Sstevel@tonic-gate 			/* \ quotes \ $ ` here */
710*65b0c20eSnakanon 			if (c == '\\') {
7117c478bd9Sstevel@tonic-gate 				c = DgetC(0);
712*65b0c20eSnakanon /*				if (!any(c, "$\\`")) */
713*65b0c20eSnakanon 				if ((c != '$') && (c != '\\') && (c != '`'))
7147c478bd9Sstevel@tonic-gate 					unDgetC(c | QUOTE), c = '\\';
7157c478bd9Sstevel@tonic-gate 				else
7167c478bd9Sstevel@tonic-gate 					c |= QUOTE;
7177c478bd9Sstevel@tonic-gate 			}
7187c478bd9Sstevel@tonic-gate 			*mbp++ = c;
7197c478bd9Sstevel@tonic-gate 			if (--mcnt == 0) {
720*65b0c20eSnakanon 				setname(S_LESLES /* "<<" */);
7217c478bd9Sstevel@tonic-gate 				bferr("Line overflow");
7227c478bd9Sstevel@tonic-gate 			}
7237c478bd9Sstevel@tonic-gate 		}
7247c478bd9Sstevel@tonic-gate 		*mbp++ = 0;
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 		/*
7277c478bd9Sstevel@tonic-gate 		 * If any ` in line do command substitution
7287c478bd9Sstevel@tonic-gate 		 */
7297c478bd9Sstevel@tonic-gate 		mbp = mbuf;
7307c478bd9Sstevel@tonic-gate 		if (any('`', mbp)) {
7317c478bd9Sstevel@tonic-gate 			/*
7327c478bd9Sstevel@tonic-gate 			 * 1 arg to dobackp causes substitution to be literal.
7337c478bd9Sstevel@tonic-gate 			 * Words are broken only at newlines so that all blanks
7347c478bd9Sstevel@tonic-gate 			 * and tabs are preserved.  Blank lines (null words)
7357c478bd9Sstevel@tonic-gate 			 * are not discarded.
7367c478bd9Sstevel@tonic-gate 			 */
7377c478bd9Sstevel@tonic-gate 			vp = dobackp(mbuf, 1);
7387c478bd9Sstevel@tonic-gate 		} else
7397c478bd9Sstevel@tonic-gate 			/* Setup trivial vector similar to return of dobackp */
7407c478bd9Sstevel@tonic-gate 			Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 		/*
7437c478bd9Sstevel@tonic-gate 		 * Resurrect the words from the command substitution
7447c478bd9Sstevel@tonic-gate 		 * each separated by a newline.  Note that the last
7457c478bd9Sstevel@tonic-gate 		 * newline of a command substitution will have been
7467c478bd9Sstevel@tonic-gate 		 * discarded, but we put a newline after the last word
7477c478bd9Sstevel@tonic-gate 		 * because this represents the newline after the last
7487c478bd9Sstevel@tonic-gate 		 * input line!
7497c478bd9Sstevel@tonic-gate 		 */
7507c478bd9Sstevel@tonic-gate 		for (; *vp; vp++) {
7517c478bd9Sstevel@tonic-gate 			for (mbp = *vp; *mbp; mbp++) {
7527c478bd9Sstevel@tonic-gate 				*obp++ = *mbp & TRIM;
7537c478bd9Sstevel@tonic-gate 				if (--ocnt == 0) {
7547c478bd9Sstevel@tonic-gate 					(void) write_(0, obuf, BUFSIZ);
7557c478bd9Sstevel@tonic-gate 					obp = obuf; ocnt = BUFSIZ;
7567c478bd9Sstevel@tonic-gate 				}
7577c478bd9Sstevel@tonic-gate 			}
7587c478bd9Sstevel@tonic-gate 			*obp++ = '\n';
7597c478bd9Sstevel@tonic-gate 			if (--ocnt == 0) {
7607c478bd9Sstevel@tonic-gate 				(void) write_(0, obuf, BUFSIZ);
7617c478bd9Sstevel@tonic-gate 				obp = obuf; ocnt = BUFSIZ;
7627c478bd9Sstevel@tonic-gate 			}
7637c478bd9Sstevel@tonic-gate 		}
7647c478bd9Sstevel@tonic-gate 		if (pargv)
7657c478bd9Sstevel@tonic-gate 			blkfree(pargv), pargv = 0;
7667c478bd9Sstevel@tonic-gate 	}
7677c478bd9Sstevel@tonic-gate }
768