1/***********************************************************************
2*                                                                      *
3*               This software is part of the ast package               *
4*          Copyright (c) 1982-2012 AT&T Intellectual Property          *
5*                      and is licensed under the                       *
6*                 Eclipse Public License, Version 1.0                  *
7*                    by AT&T Intellectual Property                     *
8*                                                                      *
9*                A copy of the License is available at                 *
10*          http://www.eclipse.org/org/documents/epl-v10.html           *
11*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12*                                                                      *
13*              Information and Software Systems Research               *
14*                            AT&T Research                             *
15*                           Florham Park NJ                            *
16*                                                                      *
17*                  David Korn <dgk@research.att.com>                   *
18*                                                                      *
19***********************************************************************/
20#pragma prototyped
21/*
22 * KornShell  lexical analyzer
23 *
24 * Written by David Korn
25 * AT&T Labs
26 *
27 */
28
29#include	<ast.h>
30#include	<stak.h>
31#include	<fcin.h>
32#include	<nval.h>
33#include	"FEATURE/options"
34
35#if KSHELL
36#   include	"defs.h"
37#else
38#   include	<shell.h>
39#   define	nv_getval(np)	((np)->nvalue)
40    Shell_t sh  =  {1};
41#endif /* KSHELL */
42
43#include	"argnod.h"
44#include	"test.h"
45#include	"lexstates.h"
46#include	"io.h"
47
48#define TEST_RE		3
49#define SYNBAD		3	/* exit value for syntax errors */
50#define STACK_ARRAY	3	/* size of depth match stack growth */
51
52#if _lib_iswblank < 0	/* set in lexstates.h to enable this code */
53
54int
55local_iswblank(wchar_t wc)
56{
57	static int      initialized;
58	static wctype_t wt;
59
60	if (!initialized)
61	{
62		initialized = 1;
63		wt = wctype("blank");
64	}
65	return(iswctype(wc, wt));
66}
67
68#endif
69
70/*
71 * This structure allows for arbitrary depth nesting of (...), {...}, [...]
72 */
73struct lexstate
74{
75	char		incase;		/* 1 for case pattern, 2 after case */
76	char		intest;		/* 1 inside [[...]] */
77	char		testop1;	/* 1 when unary test op legal */
78	char		testop2;	/* 1 when binary test op legal */
79	char		reservok;	/* >0 for reserved word legal */
80	char		skipword;	/* next word can't be reserved */
81	char		last_quote;	/* last multi-line quote character */
82	char		nestedbrace;	/* ${var op {...}} */
83};
84
85struct lexdata
86{
87	char		nocopy;
88	char		paren;
89	char		dolparen;
90	char		nest;
91	char		docword;
92	char		nested_tilde;
93	char 		*docend;
94	char		noarg;
95	char		balance;
96	char		warn;
97	char		message;
98	char		arith;
99	char 		*first;
100	int		level;
101	int		lastc;
102	int		lex_max;
103	int		*lex_match;
104	int		lex_state;
105	int		docextra;
106#if SHOPT_KIA
107	off_t		kiaoff;
108#endif
109};
110
111#define _SHLEX_PRIVATE \
112	struct lexdata  lexd; \
113	struct lexstate  lex;
114
115#include	"shlex.h"
116
117
118#define	pushlevel(lp,c,s)	((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
119				((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
120				lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
121#define oldmode(lp)	(lp->lexd.lastc>>CHAR_BIT)
122#define endchar(lp)	(lp->lexd.lastc&0xff)
123#define setchar(lp,c)	(lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
124#define poplevel(lp)	(lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
125
126static char		*fmttoken(Lex_t*, int, char*);
127#ifdef SF_BUFCONST
128    static int          alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
129#else
130    static int 		alias_exceptf(Sfio_t*, int, Sfdisc_t*);
131#endif
132static void		setupalias(Lex_t*,const char*, Namval_t*);
133static int		comsub(Lex_t*,int);
134static void		nested_here(Lex_t*);
135static int		here_copy(Lex_t*, struct ionod*);
136static int 		stack_grow(Lex_t*);
137static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
138
139#if SHOPT_KIA
140
141static void refvar(Lex_t *lp, int type)
142{
143	register Shell_t *shp = lp->sh;
144	register Stk_t	*stkp = shp->stk;
145	off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
146	unsigned long r;
147	if(lp->lexd.first)
148	{
149		off = (fcseek(0)-(type+1)) - lp->lexd.first;
150		r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
151	}
152	else
153	{
154		int n,offset = stktell(stkp);
155		char *savptr,*begin;
156		off = offset + (fcseek(0)-(type+1)) - fcfirst();
157		if(lp->lexd.kiaoff < offset)
158		{
159			/* variable starts on stak, copy remainder */
160			if(off>offset)
161				sfwrite(stkp,fcfirst()+type,off-offset);
162			n = stktell(stkp)-lp->lexd.kiaoff;
163			begin = stkptr(stkp,lp->lexd.kiaoff);
164		}
165		else
166		{
167			/* variable in data buffer */
168			begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
169			n = off-lp->lexd.kiaoff;
170		}
171		savptr = stkfreeze(stkp,0);
172		r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
173		stkset(stkp,savptr,offset);
174	}
175	sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
176}
177#endif /* SHOPT_KIA */
178
179/*
180 * This routine gets called when reading across a buffer boundary
181 * If lexd.nocopy is off, then current token is saved on the stack
182 */
183static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
184{
185	register Lex_t		*lp = (Lex_t*)context;
186	register Shell_t	*shp = lp->sh;
187	register Sfio_t		*log= shp->funlog;
188	Stk_t			*stkp = shp->stk;
189#if KSHELL
190	/* write to history file and to stderr if necessary */
191	if(iop && !sfstacked(iop))
192	{
193		if(sh_isstate(SH_HISTORY) && shp->gd->hist_ptr)
194			log = shp->gd->hist_ptr->histfp;
195		sfwrite(log, (void*)buff, size);
196		if(sh_isstate(SH_VERBOSE))
197			sfwrite(sfstderr, buff, size);
198	}
199#endif
200	if(lp->lexd.nocopy)
201		return;
202	if(lp->lexd.dolparen && lp->lexd.docword && lp->lexd.docend)
203	{
204		int n = size - (lp->lexd.docend-(char*)buff);
205		sfwrite(shp->strbuf,lp->lexd.docend,n);
206		lp->lexd.docextra  += n;
207		if(sffileno(iop)>=0)
208			lp->lexd.docend = sfsetbuf(iop,(Void_t*)iop,0);
209		else
210			lp->lexd.docend = fcfirst();
211	}
212	if(lp->lexd.first)
213	{
214		size -= (lp->lexd.first-(char*)buff);
215		buff = lp->lexd.first;
216		if(!lp->lexd.noarg)
217			lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
218#if SHOPT_KIA
219		lp->lexd.kiaoff += ARGVAL;
220#endif /* SHOPT_KIA */
221	}
222	if(size>0 && (lp->arg||lp->lexd.noarg))
223	{
224		sfwrite(stkp,buff,size);
225		lp->lexd.first = 0;
226	}
227}
228
229/*
230 * fill up another input buffer
231 * preserves lexical state
232 */
233static int lexfill(Lex_t *lp)
234{
235	register int c;
236	Lex_t savelex;
237	struct argnod *ap;
238	int aok,docextra;
239	savelex = *lp;
240	ap = lp->arg;
241	c = fcfill();
242	if(ap)
243		lp->arg = ap;
244	docextra = lp->lexd.docextra;
245	lp->lex = savelex.lex;
246	lp->lexd = savelex.lexd;
247	if(fcfile() ||  c)
248		lp->lexd.first = 0;
249	aok= lp->aliasok;
250	ap = lp->arg;
251	memcpy(lp, &savelex, offsetof(Lex_t,lexd));
252	lp->arg = ap;
253	lp->aliasok = aok;
254	if(lp->lexd.docword && docextra)
255	{
256		lp->lexd.docextra = docextra;
257		lp->lexd.docend = fcseek(0)-1;
258	}
259	return(c);
260}
261
262/*
263 * mode=1 for reinitialization
264 */
265Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
266{
267	if(!lp)
268	{
269		lp = (Lex_t*)newof(0,Lex_t,1,0);
270		lp->sh = sp;
271	}
272	fcnotify(lex_advance,lp);
273	lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
274	lp->comp_assign = 0;
275	lp->lex.reservok = 1;
276	if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
277		lp->lexd.warn=1;
278	if(!mode)
279	{
280		lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
281		lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
282		lp->lexd.lex_state = lp->lexd.lastc=0;
283		lp->lexd.docend = 0;
284		lp->lexd.nested_tilde = 0;
285	}
286	lp->comsub = 0;
287	return(lp);
288}
289
290#ifdef DBUG
291extern int lextoken(Lex_t*);
292int sh_lex(Lex_t *lp)
293{
294	Shell_t *shp = lp->sh;
295	register int flag;
296	char *quoted, *macro, *split, *expand;
297	char tokstr[3];
298	register int tok = lextoken(lp);
299	quoted = macro = split = expand = "";
300	if(tok==0 && (flag=lp->arg->argflag))
301	{
302		if(flag&ARG_MAC)
303			macro = "macro:";
304		if(flag&ARG_EXP)
305			expand = "expand:";
306		if(flag&ARG_QUOTED)
307			quoted = "quoted:";
308	}
309	sfprintf(sfstderr,"%d: line %d: %o:%s%s%s%s %s\n",getpid(),shp->inlineno,tok,quoted,
310		macro, split, expand, fmttoken(lp,tok,tokstr));
311	return(tok);
312}
313#define sh_lex	lextoken
314#endif
315
316/*
317 * Get the next word and put it on the top of the stak
318 * A pointer to the current word is stored in lp->arg
319 * Returns the token type
320 */
321int sh_lex(Lex_t* lp)
322{
323	register Shell_t *shp = lp->sh;
324	register const char	*state;
325	register int		n, c, mode=ST_BEGIN, wordflags=0;
326	Stk_t			*stkp = shp->stk;
327	int		inlevel=lp->lexd.level, assignment=0, ingrave=0;
328	int		epatchar=0;
329	Sfio_t *sp;
330#if SHOPT_MULTIBYTE
331	LEN=1;
332#endif /* SHOPT_MULTIBYTE */
333	if(lp->lexd.paren)
334	{
335		lp->lexd.paren = 0;
336		return(lp->token=LPAREN);
337	}
338	if(lp->noreserv)
339	{
340		lp->lex.reservok = 0;
341		while((fcgetc(c)) && c==' ' || c== '\t' || c=='\n');
342		fcseek(-LEN);
343		if(c=='[')
344			lp->assignok = SH_ASSIGN;
345	}
346	if(lp->lex.incase)
347		lp->assignok = 0;
348	else
349		lp->assignok |= lp->lex.reservok;
350	if(lp->comp_assign==2)
351		lp->comp_assign = lp->lex.reservok = 0;
352	lp->lexd.arith = (lp->lexd.nest==1);
353	if(lp->lexd.nest)
354	{
355		pushlevel(lp,lp->lexd.nest,ST_NONE);
356		lp->lexd.nest = 0;
357		mode = lp->lexd.lex_state;
358	}
359	else if(lp->lexd.docword)
360	{
361		if(fcgetc(c)=='-' || c=='#')
362		{
363			lp->lexd.docword++;
364			lp->digits=(c=='#'?3:1);
365		}
366		else if(c=='<')
367		{
368			lp->digits=2;
369			lp->lexd.docword=0;
370		}
371		else if(c>0)
372			fcseek(-LEN);
373	}
374	if(!lp->lexd.dolparen)
375	{
376		lp->arg = 0;
377		if(mode!=ST_BEGIN)
378			lp->lexd.first = fcseek(0);
379		else
380			lp->lexd.first = 0;
381	}
382	lp->lastline = lp->sh->inlineno;
383	while(1)
384	{
385		/* skip over characters in the current state */
386		state = sh_lexstates[mode];
387		while((n=STATE(state,c))==0);
388		switch(n)
389		{
390			case S_BREAK:
391				fcseek(-LEN);
392				goto breakloop;
393			case S_EOF:
394				sp = fcfile();
395				if((n=lexfill(lp)) > 0)
396				{
397					fcseek(-1);
398					continue;
399				}
400				/* check for zero byte in file */
401				if(n==0 && fcfile())
402				{
403					if(shp->readscript)
404					{
405						char *cp = error_info.id;
406						errno = ENOEXEC;
407						error_info.id = shp->readscript;
408						errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
409					}
410					else
411					{
412						lp->token = -1;
413						sh_syntax(lp);
414					}
415				}
416				/* end-of-file */
417				if(mode==ST_BEGIN)
418					return(lp->token=EOFSYM);
419				if(mode >ST_NORM && lp->lexd.level>0)
420				{
421					switch(c=endchar(lp))
422					{
423						case '$':
424							if(mode==ST_LIT)
425							{
426								c = '\'';
427								break;
428							}
429							mode = oldmode(lp);
430							poplevel(lp);
431							continue;
432						case RBRACT:
433							c = LBRACT;
434							break;
435						case 1:	/* for ((...)) */
436						case RPAREN:
437							c = LPAREN;
438							break;
439						default:
440							c = LBRACE;
441							break;
442						case '"': case '`': case '\'':
443							lp->lexd.balance = c;
444							break;
445					}
446					if(sp && !(sfset(sp,0,0)&SF_STRING))
447					{
448						lp->lasttok = c;
449						lp->token = EOFSYM;
450						sh_syntax(lp);
451					}
452					lp->lexd.balance = c;
453				}
454				goto breakloop;
455			case S_COM:
456				/* skip one or more comment line(s) */
457				lp->lex.reservok = !lp->lex.intest;
458				if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
459					lp->lexd.nocopy--;
460				do
461				{
462					while(fcgetc(c)>0 && c!='\n');
463					if(c<=0 || lp->heredoc)
464					{
465						shp->inlineno++;
466						break;
467					}
468					while(shp->inlineno++,fcpeek(0)=='\n')
469						fcseek(1);
470					while(state[c=fcpeek(0)]==0)
471						fcseek(1);
472				}
473				while(c=='#');
474				lp->lexd.nocopy = n;
475				if(c<0)
476					return(lp->token=EOFSYM);
477				n = S_NLTOK;
478				shp->inlineno--;
479				/* FALL THRU */
480			case S_NLTOK:
481				/* check for here-document */
482				if(lp->heredoc)
483				{
484					if(!lp->lexd.dolparen)
485						lp->lexd.nocopy++;
486					c = shp->inlineno;
487					if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
488					{
489						lp->lasttok = IODOCSYM;
490						lp->token = EOFSYM;
491						lp->lastline = c;
492						sh_syntax(lp);
493					}
494					if(!lp->lexd.dolparen)
495						lp->lexd.nocopy--;
496					lp->heredoc = 0;
497				}
498				lp->lex.reservok = !lp->lex.intest;
499				lp->lex.skipword = 0;
500				/* FALL THRU */
501			case S_NL:
502				/* skip over new-lines */
503				lp->lex.last_quote = 0;
504				while(shp->inlineno++,fcget()=='\n');
505				fcseek(-LEN);
506				if(n==S_NLTOK)
507				{
508					lp->comp_assign = 0;
509					return(lp->token='\n');
510				}
511			case S_BLNK:
512				if(lp->lex.incase<=TEST_RE)
513					continue;
514				/* implicit RPAREN for =~ test operator */
515				if(inlevel+1==lp->lexd.level)
516				{
517					if(lp->lex.intest)
518						fcseek(-LEN);
519					c = RPAREN;
520					goto do_pop;
521				}
522				continue;
523			case S_OP:
524				/* return operator token */
525				if(c=='<' || c=='>')
526				{
527					if(lp->lex.testop2)
528						lp->lex.testop2 = 0;
529					else
530					{
531						lp->digits = (c=='>');
532						lp->lex.skipword = 1;
533						lp->aliasok = lp->lex.reservok;
534						if(lp->lex.incase<2)
535							lp->lex.reservok = 0;
536					}
537				}
538				else
539				{
540					lp->lex.reservok = !lp->lex.intest;
541					if(c==RPAREN)
542					{
543						if(!lp->lexd.dolparen)
544							lp->lex.incase = 0;
545						return(lp->token=c);
546					}
547					lp->lex.testop1 = lp->lex.intest;
548				}
549				if(fcgetc(n)>0)
550					fcseek(-LEN);
551				if(state[n]==S_OP || n=='#')
552				{
553					if(n==c)
554					{
555						if(c=='<')
556							lp->lexd.docword=1;
557						else if(n==LPAREN)
558						{
559							if(lp->lex.intest)
560								return(c);
561							lp->lexd.nest=1;
562							lp->lastline = shp->inlineno;
563							lp->lexd.lex_state = ST_NESTED;
564							fcseek(1);
565							return(sh_lex(lp));
566						}
567						c  |= SYMREP;
568					}
569					else if(c=='(' || c==')')
570						return(lp->token=c);
571					else if(c=='&')
572					{
573						if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE)))
574						{
575							if(!sh_isoption(SH_BASH) && !lp->nonstandard)
576							{
577								lp->nonstandard = 1;
578								errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno);
579							}
580							lp->digits = -1;
581							c = '>';
582						}
583						else if(n=='|')
584							c |= SYMPIPE;
585						else
586							n = 0;
587					}
588					else if(n=='&')
589						c  |= SYMAMP;
590					else if(c!='<' && c!='>')
591						n = 0;
592					else if(n==LPAREN)
593					{
594						c  |= SYMLPAR;
595						lp->lex.reservok = 1;
596						lp->lex.skipword = 0;
597					}
598					else if(n=='|')
599						c  |= SYMPIPE;
600					else if(c=='<' && n=='>')
601					{
602						lp->digits = 1;
603						c = IORDWRSYM;
604						fcgetc(n);
605						if(fcgetc(n)==';')
606						{
607							lp->token = c = IORDWRSYMT;
608							if(lp->inexec)
609								sh_syntax(lp);
610						}
611						else if(n>0)
612							fcseek(-LEN);
613						n= 0;
614					}
615					else if(n=='#' && (c=='<'||c=='>'))
616						c |= SYMSHARP;
617					else if(n==';' && c=='>')
618					{
619						c |= SYMSEMI;
620						if(lp->inexec)
621						{
622							lp->token = c;
623							sh_syntax(lp);
624						}
625					}
626					else
627						n = 0;
628					if(n)
629					{
630						fcseek(1);
631						lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
632					}
633					else
634					{
635						if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t')
636							errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
637					}
638				}
639				if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
640					lp->comp_assign = 2;
641				else
642					lp->comp_assign = 0;
643				return(lp->token=c);
644			case S_ESC:
645				/* check for \<new-line> */
646				fcgetc(n);
647				c=2;
648#if SHOPT_CRNL
649				if(n=='\r')
650				{
651					if(fcgetc(n)=='\n')
652						c=3;
653					else
654					{
655						n='\r';
656						fcseek(-LEN);
657					}
658				}
659#endif /* SHOPT_CRNL */
660				if(n=='\n')
661				{
662					Sfio_t *sp;
663					struct argnod *ap;
664					shp->inlineno++;
665					/* synchronize */
666					if(!(sp=fcfile()))
667						state=fcseek(0);
668					fcclose();
669					ap = lp->arg;
670					if(sp)
671						fcfopen(sp);
672					else
673						fcsopen((char*)state);
674					/* remove \new-line */
675					n = stktell(stkp)-c;
676					stkseek(stkp,n);
677					lp->arg = ap;
678					if(n<=ARGVAL)
679					{
680						mode = 0;
681						lp->lexd.first = 0;
682					}
683					continue;
684				}
685				wordflags |= ARG_QUOTED;
686				if(mode==ST_DOL)
687					goto err;
688#ifndef STR_MAXIMAL
689				else if(mode==ST_NESTED && lp->lexd.warn &&
690					endchar(lp)==RBRACE &&
691					sh_lexstates[ST_DOL][n]==S_DIG
692				)
693					errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
694#endif /* STR_MAXIMAL */
695				break;
696			case S_NAME:
697				if(!lp->lex.skipword)
698					lp->lex.reservok *= 2;
699				/* FALL THRU */
700			case S_TILDE:
701				if(c=='~' && mode==ST_NESTED)
702				{
703					if(endchar(lp)==RBRACE)
704					{
705						lp->lexd.nested_tilde++;
706						goto tilde;
707					}
708					continue;
709				}
710			case S_RES:
711				if(!lp->lexd.dolparen)
712					lp->lexd.first = fcseek(0)-LEN;
713				else if(lp->lexd.docword)
714					lp->lexd.docend = fcseek(0)-LEN;
715				mode = ST_NAME;
716				if(c=='.')
717					fcseek(-LEN);
718				if(n!=S_TILDE)
719					continue;
720			tilde:
721				fcgetc(n);
722				if(n>0)
723				{
724					if(c=='~' && n==LPAREN)
725					{
726						if(lp->lexd.nested_tilde)
727							lp->lexd.nested_tilde++;
728						else if(lp->lex.incase)
729							lp->lex.incase = TEST_RE;
730					}
731					fcseek(-LEN);
732					if(lp->lexd.nested_tilde)
733					{
734						lp->lexd.nested_tilde--;
735						continue;
736					}
737				}
738				if(n==LPAREN)
739					goto epat;
740				wordflags = ARG_MAC;
741				mode = ST_NORM;
742				continue;
743			case S_REG:
744				if(mode==ST_BEGIN)
745				{
746				do_reg:
747					/* skip new-line joining */
748					if(c=='\\' && fcpeek(0)=='\n')
749					{
750						shp->inlineno++;
751						fcseek(1);
752						continue;
753					}
754					fcseek(-LEN);
755					if(!lp->lexd.dolparen)
756						lp->lexd.first = fcseek(0);
757					else if(lp->lexd.docword)
758						lp->lexd.docend = fcseek(0);
759					if(c=='[' && lp->assignok>=SH_ASSIGN)
760					{
761						mode = ST_NAME;
762						continue;
763					}
764				}
765				mode = ST_NORM;
766				continue;
767			case S_LIT:
768				if(oldmode(lp)==ST_NONE && !lp->lexd.noarg)	/*  in ((...)) */
769				{
770					if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
771					{
772						if(fcpeek(1)=='\'')
773							fcseek(2);
774					}
775					continue;
776				}
777				wordflags |= ARG_QUOTED;
778				if(mode==ST_DOL)
779				{
780					if(endchar(lp)!='$')
781						goto err;
782					if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
783					{
784						if(lp->lexd.warn)
785							errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
786						mode = ST_LIT;
787					}
788				}
789				if(mode!=ST_LIT)
790				{
791					if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline && fcpeek(-2)!='$')
792						errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
793					lp->lex.last_quote = 0;
794					lp->lastline = shp->inlineno;
795					if(mode!=ST_DOL)
796						pushlevel(lp,'\'',mode);
797					mode = ST_LIT;
798					continue;
799				}
800				/* check for multi-line single-quoted string */
801				else if(shp->inlineno > lp->lastline)
802					lp->lex.last_quote = '\'';
803				mode = oldmode(lp);
804				poplevel(lp);
805				break;
806			case S_ESC2:
807				/* \ inside '' */
808				if(endchar(lp)=='$')
809				{
810					fcgetc(n);
811					if(n=='\n')
812						shp->inlineno++;
813				}
814				continue;
815			case S_GRAVE:
816				if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
817					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
818				wordflags |=(ARG_MAC|ARG_EXP);
819				if(mode==ST_QUOTE)
820					ingrave = !ingrave;
821				/* FALL THRU */
822			case S_QUOTE:
823				if(oldmode(lp)==ST_NONE && lp->lexd.arith)	/*  in ((...)) */
824				{
825					if(n!=S_GRAVE || fcpeek(0)=='\'')
826						continue;
827				}
828				if(n==S_QUOTE)
829					wordflags |=ARG_QUOTED;
830				if(mode!=ST_QUOTE)
831				{
832					if(c!='"' || mode!=ST_QNEST)
833					{
834						if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
835							errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
836						lp->lex.last_quote=0;
837						lp->lastline = shp->inlineno;
838						pushlevel(lp,c,mode);
839					}
840					ingrave ^= (c=='`');
841					mode = ST_QUOTE;
842					continue;
843				}
844				else if((n=endchar(lp))==c)
845				{
846					if(shp->inlineno > lp->lastline)
847						lp->lex.last_quote = c;
848					mode = oldmode(lp);
849					poplevel(lp);
850				}
851				else if(c=='"' && n==RBRACE)
852					mode = ST_QNEST;
853				break;
854			case S_DOL:
855				/* don't check syntax inside `` */
856				if(mode==ST_QUOTE && ingrave)
857					continue;
858#if SHOPT_KIA
859				if(lp->lexd.first)
860					lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
861				else
862					lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
863#endif /* SHOPT_KIA */
864				pushlevel(lp,'$',mode);
865				mode = ST_DOL;
866				continue;
867			case S_PAR:
868			do_comsub:
869				wordflags |= ARG_MAC;
870				mode = oldmode(lp);
871				poplevel(lp);
872				fcseek(-LEN);
873				n = lp->digits;
874				wordflags |= comsub(lp,c);
875				lp->digits = n;
876				continue;
877			case S_RBRA:
878				if((n=endchar(lp)) == '$')
879					goto err;
880				if(mode!=ST_QUOTE || n==RBRACE)
881				{
882					mode = oldmode(lp);
883					poplevel(lp);
884				}
885				break;
886			case S_EDOL:
887				/* end $identifier */
888#if SHOPT_KIA
889				if(lp->kiafile)
890					refvar(lp,0);
891#endif /* SHOPT_KIA */
892				if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
893					errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
894				fcseek(-LEN);
895				mode = oldmode(lp);
896				poplevel(lp);
897				break;
898			case S_DOT:
899				/* make sure next character is alpha */
900				if(fcgetc(n)>0)
901				{
902					if(n=='.')
903						fcgetc(n);
904					if(n>0)
905						fcseek(-LEN);
906				}
907				if(isaletter(n) || n==LBRACT)
908					continue;
909				if(mode==ST_NAME)
910				{
911					if(n=='=')
912						continue;
913					break;
914				}
915				else if(n==RBRACE)
916					continue;
917				if(isastchar(n))
918					continue;
919				goto err;
920			case S_SPC1:
921				wordflags |= ARG_MAC;
922				if(endchar(lp)==RBRACE)
923				{
924					setchar(lp,c);
925					continue;
926				}
927				/* FALL THRU */
928			case S_ALP:
929				if(c=='.' && endchar(lp)=='$')
930					goto err;
931			case S_SPC2:
932			case S_DIG:
933				wordflags |= ARG_MAC;
934				switch(endchar(lp))
935				{
936					case '$':
937						if(n==S_ALP) /* $identifier */
938							mode = ST_DOLNAME;
939						else
940						{
941							mode = oldmode(lp);
942							poplevel(lp);
943						}
944						break;
945#if SHOPT_TYPEDEF
946					case '@':
947#endif /* SHOPT_TYPEDEF */
948					case '!':
949						if(n!=S_ALP)
950							goto dolerr;
951					case '#':
952						if(c=='#')
953							n = S_ALP;
954					case RBRACE:
955						if(n==S_ALP)
956						{
957							setchar(lp,RBRACE);
958							if(c=='.')
959								fcseek(-LEN);
960							mode = ST_BRACE;
961						}
962						else
963						{
964							if(fcgetc(c)>0)
965								fcseek(-LEN);
966							if(state[c]==S_ALP)
967								goto err;
968							if(n==S_DIG)
969								setchar(lp,'0');
970							else
971								setchar(lp,'!');
972						}
973						break;
974					case '0':
975						if(n==S_DIG)
976							break;
977					default:
978						goto dolerr;
979				}
980				break;
981			dolerr:
982			case S_ERR:
983				if((n=endchar(lp)) == '$')
984					goto err;
985				if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
986				{
987					/* see whether inside `...` */
988					mode = oldmode(lp);
989					poplevel(lp);
990					if((n = endchar(lp)) != '`')
991						goto err;
992					pushlevel(lp,RBRACE,mode);
993				}
994				else
995					setchar(lp,RBRACE);
996				mode = ST_NESTED;
997				continue;
998			case S_MOD1:
999				if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
1000				{
1001					/* allow ' inside "${...}" */
1002					if(c==':' && fcgetc(n)>0)
1003					{
1004						n = state[n];
1005						fcseek(-LEN);
1006					}
1007					if(n==S_MOD1)
1008					{
1009						mode = ST_QUOTE;
1010						continue;
1011					}
1012				}
1013				/* FALL THRU */
1014			case S_MOD2:
1015#if SHOPT_KIA
1016				if(lp->kiafile)
1017					refvar(lp,1);
1018#endif /* SHOPT_KIA */
1019				if(c!=':' && fcgetc(n)>0)
1020				{
1021					if(n!=c)
1022						c = 0;
1023					if(!c || (fcgetc(n)>0))
1024					{
1025						fcseek(-LEN);
1026						if(n==LPAREN)
1027						{
1028							if(c!='%')
1029							{
1030								lp->token = n;
1031								sh_syntax(lp);
1032							}
1033							else if(lp->lexd.warn)
1034								errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
1035						}
1036					}
1037				}
1038				lp->lex.nestedbrace = 0;
1039				mode = ST_NESTED;
1040				continue;
1041			case S_LBRA:
1042				if((c=endchar(lp)) == '$')
1043				{
1044					if(fcgetc(c)>0)
1045						fcseek(-LEN);
1046					setchar(lp,RBRACE);
1047					if(state[c]!=S_ERR && c!=RBRACE)
1048						continue;
1049					if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
1050					{
1051						c = LBRACE;
1052						goto do_comsub;
1053					}
1054				}
1055			err:
1056				if(iswalpha(c))
1057					continue;
1058				n = endchar(lp);
1059				mode = oldmode(lp);
1060				poplevel(lp);
1061				if(n!='$')
1062				{
1063					lp->token = c;
1064					sh_syntax(lp);
1065				}
1066				else
1067				{
1068					if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
1069						errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
1070					else if(c=='"' && mode!=ST_QUOTE && !ingrave)
1071						wordflags |= ARG_MESSAGE;
1072					fcseek(-LEN);
1073				}
1074				continue;
1075			case S_META:
1076				if(lp->lexd.warn && endchar(lp)==RBRACE && !lp->lexd.nested_tilde)
1077					errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1078				continue;
1079			case S_PUSH:
1080				fcgetc(n);
1081				if(n==RPAREN)
1082					continue;
1083				else
1084					fcseek(-LEN);
1085				pushlevel(lp,RPAREN,mode);
1086				mode = ST_NESTED;
1087				continue;
1088			case S_POP:
1089			do_pop:
1090				if(c==RBRACE && mode==ST_NESTED && lp->lex.nestedbrace)
1091				{
1092					lp->lex.nestedbrace--;
1093					continue;
1094				}
1095				if(lp->lexd.level <= inlevel)
1096					break;
1097				if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
1098				{
1099					fcseek(-LEN);
1100					goto breakloop;
1101				}
1102				n = endchar(lp);
1103				if(c==RBRACT  && !(n==RBRACT || n==RPAREN))
1104					continue;
1105				if((c==RBRACE||c==RPAREN) && n==RPAREN)
1106				{
1107					if(fcgetc(n)==LPAREN)
1108					{
1109						if(c!=RPAREN)
1110							fcseek(-LEN);
1111						continue;
1112					}
1113					if(n>0)
1114						fcseek(-LEN);
1115					n = RPAREN;
1116				}
1117				if(c==RBRACE)
1118					lp->lexd.nested_tilde = 0;
1119				if(c==';' && n!=';')
1120				{
1121					if(lp->lexd.warn && n==RBRACE)
1122						errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1123					continue;
1124				}
1125				if(mode==ST_QNEST)
1126				{
1127					if(lp->lexd.warn)
1128						errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
1129					continue;
1130				}
1131				mode = oldmode(lp);
1132				poplevel(lp);
1133				if(epatchar!='~')
1134					epatchar = '@';
1135				/* quotes in subscript need expansion */
1136				if(mode==ST_NAME && (wordflags&ARG_QUOTED))
1137					wordflags |= ARG_MAC;
1138				/* check for ((...)) */
1139				if(n==1 && c==RPAREN)
1140				{
1141					if(fcgetc(n)==RPAREN)
1142					{
1143						if(mode==ST_NONE && !lp->lexd.dolparen)
1144							goto breakloop;
1145						lp->lex.reservok = 1;
1146						lp->lex.skipword = 0;
1147						return(lp->token=EXPRSYM);
1148					}
1149					/* backward compatibility */
1150					{
1151						if(lp->lexd.warn)
1152							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1153						if(!(state=lp->lexd.first))
1154							state = fcfirst();
1155						else
1156						{
1157							n = state-fcseek(0);
1158							fcseek(n);
1159						}
1160						lp->lexd.paren = 1;
1161					}
1162					return(lp->token=LPAREN);
1163				}
1164				if(mode==ST_NONE)
1165					return(0);
1166				if(c!=n)
1167				{
1168					lp->token = c;
1169					sh_syntax(lp);
1170				}
1171				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
1172					goto epat;
1173				continue;
1174			case S_EQ:
1175				assignment = lp->assignok;
1176				/* FALL THRU */
1177			case S_COLON:
1178				if(assignment)
1179				{
1180					if(fcgetc(c)=='~')
1181						wordflags |= ARG_MAC;
1182					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
1183						assignment = 0;
1184					if(c!=EOF)
1185						fcseek(-LEN);
1186				}
1187				break;
1188			case S_LABEL:
1189				if(lp->lex.reservok && !lp->lex.incase)
1190				{
1191					c = fcget();
1192					fcseek(-LEN);
1193					if(state[c]==S_BREAK)
1194					{
1195						assignment = -1;
1196						goto breakloop;
1197					}
1198				}
1199				break;
1200			case S_BRACT:
1201				/* check for possible subscript */
1202				if((n=endchar(lp))==RBRACT || n==RPAREN ||
1203					(mode==ST_BRACE) ||
1204					(oldmode(lp)==ST_NONE) ||
1205					(mode==ST_NAME && (lp->assignok||lp->lexd.level)))
1206				{
1207					fcgetc(n);
1208					if(n>0 && n==']')
1209					{
1210						if(mode==ST_NAME)
1211							errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
1212						if(!epatchar || epatchar=='%')
1213							continue;
1214					}
1215					else
1216						fcseek(-LEN);
1217					pushlevel(lp,RBRACT,mode);
1218					wordflags |= ARG_QUOTED;
1219					mode = ST_NESTED;
1220					continue;
1221				}
1222				wordflags |= ARG_EXP;
1223				break;
1224			case S_BRACE:
1225			{
1226				int isfirst;
1227				if(lp->lexd.dolparen)
1228				{
1229					if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
1230					{
1231						if(lp->comsub)
1232							return(lp->token=c);
1233						fcgetc(n);
1234						if(n>0)
1235							fcseek(-LEN);
1236						else
1237							n = '\n';
1238						if(n==RBRACT || sh_lexstates[ST_NORM][n])
1239							return(lp->token=c);
1240					}
1241					break;
1242				}
1243				else if(mode==ST_NESTED && endchar(lp)==RBRACE)
1244				{
1245					lp->lex.nestedbrace++;
1246					continue;
1247				}
1248				else if(mode==ST_BEGIN)
1249				{
1250					if(lp->comsub && c==RBRACE)
1251						return(lp->token=c);
1252					goto do_reg;
1253				}
1254				isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
1255				fcgetc(n);
1256				/* check for {} */
1257				if(c==LBRACE && n==RBRACE)
1258					break;
1259				if(n>0)
1260					fcseek(-LEN);
1261				else if(lp->lex.reservok)
1262					break;
1263				/* check for reserved word { or } */
1264				if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
1265					break;
1266				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
1267					&& !lp->lex.incase && !lp->lex.intest
1268					&& !lp->lex.skipword)
1269				{
1270					wordflags |= ARG_EXP;
1271				}
1272				if(c==RBRACE && n==LPAREN)
1273					goto epat;
1274				break;
1275			}
1276			case S_PAT:
1277				wordflags |= ARG_EXP;
1278				/* FALL THRU */
1279			case S_EPAT:
1280			epat:
1281				if(fcgetc(n)==LPAREN && c!='[')
1282				{
1283					epatchar = c;
1284					if(lp->lex.incase==TEST_RE)
1285					{
1286						lp->lex.incase++;
1287						pushlevel(lp,RPAREN,ST_NORM);
1288						mode = ST_NESTED;
1289					}
1290					wordflags |= ARG_EXP;
1291					pushlevel(lp,RPAREN,mode);
1292					mode = ST_NESTED;
1293					continue;
1294				}
1295				if(lp->lexd.warn && c=='[' && n=='^')
1296					errormsg(SH_DICT,ERROR_warn(0),e_lexcharclass,shp->inlineno);
1297				if(n>0)
1298					fcseek(-LEN);
1299				if(n=='=' && c=='+' && mode==ST_NAME)
1300					continue;
1301				break;
1302		}
1303		lp->comp_assign = 0;
1304		if(mode==ST_NAME)
1305			mode = ST_NORM;
1306		else if(mode==ST_NONE)
1307			return(0);
1308	}
1309breakloop:
1310	if(lp->lexd.nocopy)
1311	{
1312		lp->lexd.balance = 0;
1313		return(0);
1314	}
1315	if(lp->lexd.dolparen)
1316	{
1317		lp->lexd.balance = 0;
1318		if(lp->lexd.docword)
1319			nested_here(lp);
1320		lp->lexd.message = (wordflags&ARG_MESSAGE);
1321		return(lp->token=0);
1322	}
1323	if(!(state=lp->lexd.first))
1324		state = fcfirst();
1325	n = fcseek(0)-(char*)state;
1326	if(!lp->arg)
1327		lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
1328	if(n>0)
1329		sfwrite(stkp,state,n);
1330	/* add balancing character if necessary */
1331	if(lp->lexd.balance)
1332	{
1333		sfputc(stkp,lp->lexd.balance);
1334		lp->lexd.balance = 0;
1335	}
1336	sfputc(stkp,0);
1337	stkseek(stkp,stktell(stkp)-1);
1338	state = stkptr(stkp,ARGVAL);
1339	n = stktell(stkp)-ARGVAL;
1340	lp->lexd.first=0;
1341	if(n==1)
1342	{
1343		/* check for numbered redirection */
1344		n = state[0];
1345		if((c=='<' || c=='>') && isadigit(n))
1346		{
1347			c = sh_lex(lp);
1348			lp->digits = (n-'0');
1349			return(c);
1350		}
1351		if(n==LBRACT)
1352			c = 0;
1353		else if(n==RBRACE && lp->comsub)
1354			return(lp->token=n);
1355		else if(n=='~')
1356			c = ARG_MAC;
1357		else
1358			c = (wordflags&ARG_EXP);
1359		n = 1;
1360	}
1361	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
1362	{
1363		if(!strchr(state,','))
1364		{
1365			stkseek(stkp,stktell(stkp)-1);
1366			lp->arg = (struct argnod*)stkfreeze(stkp,1);
1367			return(lp->token=IOVNAME);
1368		}
1369		c = wordflags;
1370	}
1371	else
1372		c = wordflags;
1373	if(assignment<0)
1374	{
1375		stkseek(stkp,stktell(stkp)-1);
1376		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1377		lp->lex.reservok = 1;
1378		return(lp->token=LABLSYM);
1379	}
1380	if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
1381		c &= ~ARG_EXP;
1382	if((c&ARG_EXP) && (c&ARG_QUOTED))
1383		c |= ARG_MAC;
1384	if(mode==ST_NONE)
1385	{
1386		/* eliminate trailing )) */
1387		stkseek(stkp,stktell(stkp)-2);
1388	}
1389	if(c&ARG_MESSAGE)
1390	{
1391		if(sh_isoption(SH_DICTIONARY))
1392			lp->arg = sh_endword(shp,2);
1393		c |= ARG_MAC;
1394	}
1395	if(c==0 || (c&(ARG_MAC|ARG_EXP|ARG_MESSAGE)))
1396	{
1397		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1398		lp->arg->argflag = (c?c:ARG_RAW);
1399	}
1400	else if(mode==ST_NONE)
1401		lp->arg = sh_endword(shp,-1);
1402	else
1403		lp->arg = sh_endword(shp,0);
1404	state = lp->arg->argval;
1405	lp->comp_assign = assignment;
1406	if(assignment)
1407		lp->arg->argflag |= ARG_ASSIGN;
1408	else if(!lp->lex.skipword)
1409		lp->assignok = 0;
1410	lp->arg->argchn.cp = 0;
1411	lp->arg->argnxt.ap = 0;
1412	if(mode==ST_NONE)
1413		return(lp->token=EXPRSYM);
1414	if(lp->lex.intest)
1415	{
1416		if(lp->lex.testop1)
1417		{
1418			lp->lex.testop1 = 0;
1419			if(n==2 && state[0]=='-' && state[2]==0 &&
1420				strchr(test_opchars,state[1]))
1421			{
1422				if(lp->lexd.warn && state[1]=='a')
1423					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
1424				lp->digits = state[1];
1425				lp->token = TESTUNOP;
1426			}
1427			else if(n==1 && state[0]=='!' && state[1]==0)
1428			{
1429				lp->lex.testop1 = 1;
1430				lp->token = '!';
1431			}
1432			else
1433			{
1434				lp->lex.testop2 = 1;
1435				lp->token = 0;
1436			}
1437			return(lp->token);
1438		}
1439		lp->lex.incase = 0;
1440		c = sh_lookup(state,shtab_testops);
1441		switch(c)
1442		{
1443		case TEST_END:
1444			lp->lex.testop2 = lp->lex.intest = 0;
1445			lp->lex.reservok = 1;
1446			lp->token = ETESTSYM;
1447			return(lp->token);
1448
1449		case TEST_SEQ:
1450			if(lp->lexd.warn && state[1]==0)
1451				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
1452			/* FALL THRU */
1453		default:
1454			if(lp->lex.testop2)
1455			{
1456				if(lp->lexd.warn && (c&TEST_ARITH))
1457					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
1458				if(c&TEST_PATTERN)
1459					lp->lex.incase = 1;
1460				else if(c==TEST_REP)
1461					lp->lex.incase = TEST_RE;
1462				lp->lex.testop2 = 0;
1463				lp->digits = c;
1464				lp->token = TESTBINOP;
1465				return(lp->token);
1466			}
1467
1468		case TEST_OR: case TEST_AND:
1469		case 0:
1470			return(lp->token=0);
1471		}
1472	}
1473	if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
1474	{
1475		/* check for {, }, ! */
1476		c = state[0];
1477		if(n==1 && (c=='{' || c=='}' || c=='!'))
1478		{
1479			if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
1480				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
1481			if(lp->lex.incase==1 && c==RBRACE)
1482				lp->lex.incase = 0;
1483			return(lp->token=c);
1484		}
1485		else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
1486		{
1487			lp->lex.intest = lp->lex.testop1 = 1;
1488			lp->lex.testop2 = lp->lex.reservok = 0;
1489			return(lp->token=BTESTSYM);
1490		}
1491	}
1492	c = 0;
1493	if(!lp->lex.skipword)
1494	{
1495		if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
1496			(c=sh_lookup(state,shtab_reserved)))
1497		{
1498			if(lp->lex.incase)
1499			{
1500				if(lp->lex.incase >1)
1501					lp->lex.incase = 1;
1502				else if(c==ESACSYM)
1503					lp->lex.incase = 0;
1504				else
1505					c = 0;
1506			}
1507			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
1508			{
1509				lp->lex.skipword = 1;
1510				lp->lex.incase = 2*(c==CASESYM);
1511			}
1512			else
1513				lp->lex.skipword = 0;
1514			if(c==INSYM)
1515				lp->lex.reservok = 0;
1516			else if(c==TIMESYM)
1517			{
1518				/* yech - POSIX requires time -p */
1519				while(fcgetc(n)==' ' || n=='\t');
1520				if(n>0)
1521					fcseek(-LEN);
1522				if(n=='-')
1523					c=0;
1524			}
1525			return(lp->token=c);
1526		}
1527		if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
1528		{
1529			/* check for aliases */
1530			Namval_t* np;
1531			if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
1532				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
1533				&& !nv_isattr(np,NV_NOEXPAND)
1534#if KSHELL
1535				&& (lp->aliasok!=2 || nv_isattr(np,BLT_DCL))
1536				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
1537#endif /* KSHELL */
1538				&& (state=nv_getval(np)))
1539			{
1540				setupalias(lp,state,np);
1541				nv_onattr(np,NV_NOEXPAND);
1542				lp->lex.reservok = 1;
1543				lp->assignok |= lp->lex.reservok;
1544				return(sh_lex(lp));
1545			}
1546		}
1547		lp->lex.reservok = 0;
1548	}
1549	lp->lex.skipword = lp->lexd.docword = 0;
1550	return(lp->token=c);
1551}
1552
1553/*
1554 * read to end of command substitution
1555 */
1556static int comsub(register Lex_t *lp, int endtok)
1557{
1558	register int	n,c,count=1;
1559	register int	line=lp->sh->inlineno;
1560	char *first,*cp=fcseek(0),word[5];
1561	int off, messages=0, assignok=lp->assignok, csub;
1562	struct lexstate	save;
1563	save = lp->lex;
1564	csub = lp->comsub;
1565	sh_lexopen(lp,lp->sh,1);
1566	lp->lexd.dolparen++;
1567	lp->lex.incase=0;
1568	pushlevel(lp,0,0);
1569	lp->comsub = (endtok==LBRACE);
1570	if(first=lp->lexd.first)
1571		off = cp-first;
1572	else
1573		off = cp-fcfirst();
1574	if(off<0)
1575		c=*cp, *cp=0;
1576	n = sh_lex(lp);
1577	if(off<0)
1578		*cp = c;
1579	if(n==endtok || off<0)
1580	{
1581		if(endtok==LPAREN && lp->lexd.paren)
1582		{
1583
1584			if(first==lp->lexd.first)
1585			{
1586				n = cp+1-(char*)fcseek(0);
1587				fcseek(n);
1588			}
1589			count++;
1590			lp->lexd.paren = 0;
1591			fcgetc(c);
1592		}
1593		while(1)
1594		{
1595			/* look for case and esac */
1596			n=0;
1597			while(1)
1598			{
1599				fcgetc(c);
1600				/* skip leading white space */
1601				if(n==0 && !sh_lexstates[ST_BEGIN][c])
1602					continue;
1603				if(n==4)
1604					break;
1605				if(sh_lexstates[ST_NAME][c])
1606					goto skip;
1607				word[n++] = c;
1608			}
1609			if(sh_lexstates[ST_NAME][c]==S_BREAK)
1610			{
1611				if(memcmp(word,"case",4)==0)
1612					lp->lex.incase=1;
1613				else if(memcmp(word,"esac",4)==0)
1614					lp->lex.incase=0;
1615			}
1616		skip:
1617			if(c && (c!='#' || n==0))
1618				fcseek(-LEN);
1619			if(c==RBRACE && lp->lex.incase)
1620				lp->lex.incase=0;
1621			c=sh_lex(lp);
1622			switch(c)
1623			{
1624			    case LBRACE:
1625				if(endtok==LBRACE && !lp->lex.incase)
1626				{
1627					lp->comsub = 0;
1628					count++;
1629				}
1630				break;
1631			    case RBRACE:
1632			    rbrace:
1633				if(endtok==LBRACE && --count<=0)
1634					goto done;
1635				if(count==1)
1636					lp->comsub = endtok==LBRACE;
1637				break;
1638			    case IPROCSYM:	case OPROCSYM:
1639			    case LPAREN:
1640				if(endtok==LPAREN && !lp->lex.incase)
1641					count++;
1642				break;
1643			    case RPAREN:
1644				if(lp->lex.incase)
1645					lp->lex.incase=0;
1646				else if(endtok==LPAREN && --count<=0)
1647					goto done;
1648				break;
1649			    case EOFSYM:
1650				lp->lastline = line;
1651				lp->lasttok = endtok;
1652				sh_syntax(lp);
1653			    case IOSEEKSYM:
1654				if(fcgetc(c)!='#' && c>0)
1655					fcseek(-LEN);
1656				break;
1657			    case IODOCSYM:
1658				lp->lexd.docextra = 0;
1659				sh_lex(lp);
1660				break;
1661			    case 0:
1662				lp->lex.reservok = 0;
1663				messages |= lp->lexd.message;
1664				break;
1665			    case ';':
1666				do
1667					fcgetc(c);
1668				while(!sh_lexstates[ST_BEGIN][c]);
1669				if(c==RBRACE && endtok==LBRACE)
1670					goto rbrace;
1671				if(c>0)
1672					fcseek(-LEN);
1673				/* fall through*/
1674			    default:
1675				lp->lex.reservok = 1;
1676			}
1677		}
1678	}
1679done:
1680	poplevel(lp);
1681	lp->comsub = csub;
1682	lp->lastline = line;
1683	lp->lexd.dolparen--;
1684	lp->lex = save;
1685	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
1686	if(lp->heredoc)
1687		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax5,lp->sh->inlineno,lp->heredoc->ioname);
1688	return(messages);
1689}
1690
1691/*
1692 * here-doc nested in $(...)
1693 * allocate ionode with delimiter filled in without disturbing stak
1694 */
1695static void nested_here(register Lex_t *lp)
1696{
1697	register struct ionod	*iop;
1698	register int		n=0,offset;
1699	struct argnod		*arg = lp->arg;
1700	Stk_t			*stkp = lp->sh->stk;
1701	char			*base;
1702	if(offset=stktell(stkp))
1703		base = stkfreeze(stkp,0);
1704	if(lp->lexd.docend)
1705		n = fcseek(0)-lp->lexd.docend;
1706	iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
1707	iop->iolst = lp->heredoc;
1708	stkseek(stkp,ARGVAL);
1709	if(lp->lexd.docextra)
1710	{
1711		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
1712		sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
1713		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
1714	}
1715	sfwrite(stkp,lp->lexd.docend,n);
1716	lp->arg = sh_endword(lp->sh,0);
1717	iop->ioname = (char*)(iop+1);
1718	strcpy(iop->ioname,lp->arg->argval);
1719	iop->iofile = (IODOC|IORAW);
1720	if(lp->lexd.docword>1)
1721		iop->iofile |= IOSTRIP;
1722	lp->heredoc = iop;
1723	lp->arg = arg;
1724	lp->lexd.docword = 0;
1725	if(offset)
1726		stkset(stkp,base,offset);
1727	else
1728		stkseek(stkp,0);
1729}
1730
1731/*
1732 * skip to <close> character
1733 * if <copy> is non,zero, then the characters are copied to the stack
1734 * <state> is the initial lexical state
1735 */
1736void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
1737{
1738	register char	*cp;
1739	lp->lexd.nest = close;
1740	lp->lexd.lex_state = state;
1741	lp->lexd.noarg = 1;
1742	if(copy)
1743		fcnotify(lex_advance,lp);
1744	else
1745		lp->lexd.nocopy++;
1746	sh_lex(lp);
1747	lp->lexd.noarg = 0;
1748	if(copy)
1749	{
1750		fcnotify(0,lp);
1751		if(!(cp=lp->lexd.first))
1752			cp = fcfirst();
1753		if((copy = fcseek(0)-cp) > 0)
1754			sfwrite(lp->sh->stk,cp,copy);
1755	}
1756	else
1757		lp->lexd.nocopy--;
1758}
1759
1760#if SHOPT_CRNL
1761    ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
1762    {
1763	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1764	int m=0,k;
1765	while(next = (const char*)memchr(next,'\r',ep-next))
1766		if(*++next=='\n')
1767		{
1768			if(k=next-cp-1)
1769			{
1770				if((k=sfwrite(sp,cp,k)) < 0)
1771					return(m>0?m:-1);
1772				m += k;
1773			}
1774			cp = next;
1775		}
1776	if((k=sfwrite(sp,cp,ep-cp)) < 0)
1777		return(m>0?m:-1);
1778	return(m+k);
1779    }
1780#   define sfwrite	_sfwrite
1781#endif /* SHOPT_CRNL */
1782
1783/*
1784 * read in here-document from script
1785 * quoted here documents, and here-documents without special chars are
1786 * noted with the IOQUOTE flag
1787 * returns 1 for complete here-doc, 0 for EOF
1788 */
1789
1790static int here_copy(Lex_t *lp,register struct ionod *iop)
1791{
1792	register const char	*state;
1793	register int		c,n;
1794	register char		*bufp,*cp;
1795	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
1796	int			stripcol=0,stripflg, nsave, special=0;
1797	if(funlog=lp->sh->funlog)
1798	{
1799		if(fcfill()>0)
1800			fcseek(-LEN);
1801		lp->sh->funlog = 0;
1802	}
1803	if(iop->iolst)
1804		here_copy(lp,iop->iolst);
1805	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1806	iop->iosize = 0;
1807	iop->iodelim=iop->ioname;
1808	/* check for and strip quoted characters in delimiter string */
1809	if(stripflg=iop->iofile&IOSTRIP)
1810	{
1811		while(*iop->iodelim=='\t')
1812			iop->iodelim++;
1813		/* skip over leading tabs in document */
1814		if(iop->iofile&IOLSEEK)
1815		{
1816			iop->iofile &= ~IOLSEEK;
1817			while(fcgetc(c)=='\t' || c==' ')
1818			{
1819				if(c==' ')
1820					stripcol++;
1821				else
1822					stripcol += 8 - stripcol%8;
1823			}
1824		}
1825		else
1826			while(fcgetc(c)=='\t');
1827		if(c>0)
1828			fcseek(-LEN);
1829	}
1830	if(iop->iofile&IOQUOTE)
1831		state = sh_lexstates[ST_LIT];
1832	else
1833		state = sh_lexstates[ST_QUOTE];
1834	bufp = fcseek(0);
1835	n = S_NL;
1836	while(1)
1837	{
1838		if(n!=S_NL)
1839		{
1840			/* skip over regular characters */
1841#if SHOPT_MULTIBYTE
1842			do
1843			{
1844				if(fcleft()< MB_LEN_MAX && mbsize(fcseek(0))<0)
1845				{
1846					n = S_EOF;
1847					LEN = -fcleft();
1848					break;
1849				}
1850			}
1851#endif /* SHOPT_MULTIBYTE */
1852
1853			while((n=STATE(state,c))==0);
1854		}
1855		if(n==S_EOF || !(c=fcget()))
1856		{
1857			if(LEN < 0)
1858				c = fclast()-bufp;
1859			else
1860				c= (fcseek(0)-1)-bufp;
1861			if(!lp->lexd.dolparen && c)
1862			{
1863				if(n==S_ESC)
1864					c--;
1865				if(!lp->lexd.dolparen && (c=sfwrite(sp,bufp,c))>0)
1866					iop->iosize += c;
1867			}
1868#if SHOPT_MULTIBYTE
1869			if(LEN==0)
1870				LEN=1;
1871			if(LEN < 0)
1872			{
1873				n = LEN;
1874				c = fcmbget(&LEN);
1875				LEN += n;
1876			}
1877			else
1878#endif /* SHOPT_MULTIBYTE */
1879				c = lexfill(lp);
1880			if(c<0)
1881				break;
1882			if(n==S_ESC)
1883			{
1884#if SHOPT_CRNL
1885				if(c=='\r' && (c=fcget())!=NL)
1886					fcseek(-LEN);
1887#endif /* SHOPT_CRNL */
1888				if(c==NL)
1889					fcseek(1);
1890				else if(!lp->lexd.dolparen)
1891				{
1892					iop->iosize++;
1893					sfputc(sp,'\\');
1894				}
1895			}
1896			bufp = fcseek(-LEN);
1897		}
1898		else
1899			fcseek(-LEN);
1900		switch(n)
1901		{
1902		    case S_NL:
1903			lp->sh->inlineno++;
1904			if((stripcol && c==' ') || (stripflg && c=='\t'))
1905			{
1906				if(!lp->lexd.dolparen)
1907				{
1908					/* write out line */
1909					n = fcseek(0)-bufp;
1910					if((n=sfwrite(sp,bufp,n))>0)
1911						iop->iosize += n;
1912				}
1913				/* skip over tabs */
1914				if(stripcol)
1915				{
1916					int col=0;
1917					do
1918					{
1919						fcgetc(c);
1920						if(c==' ')
1921							col++;
1922						else
1923							col += 8 - col%8;
1924						if(col>stripcol)
1925							break;
1926					}
1927					while (c==' ' || c=='\t');
1928				}
1929				else while(c=='\t')
1930					fcgetc(c);
1931				if(c<=0)
1932					goto done;
1933				bufp = fcseek(-LEN);
1934			}
1935			if(c!=iop->iodelim[0])
1936				break;
1937			cp = fcseek(0);
1938			nsave = n = 0;
1939			while(1)
1940			{
1941				if(!(c=fcget()))
1942				{
1943					if(!lp->lexd.dolparen && (c=cp-bufp))
1944					{
1945						if((c=sfwrite(sp,cp=bufp,c))>0)
1946							iop->iosize+=c;
1947					}
1948					nsave = n;
1949					if((c=lexfill(lp))<=0)
1950					{
1951						c = iop->iodelim[n]==0;
1952						goto done;
1953					}
1954				}
1955#if SHOPT_CRNL
1956				if(c=='\r' && (c=fcget())!=NL)
1957				{
1958					if(c)
1959						fcseek(-LEN);
1960					c='\r';
1961				}
1962#endif /* SHOPT_CRNL */
1963				if(c==NL)
1964					lp->sh->inlineno++;
1965				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
1966				{
1967					if(!lp->lexd.dolparen && (n=cp-bufp))
1968					{
1969						if((n=sfwrite(sp,bufp,n))>0)
1970							iop->iosize += n;
1971					}
1972					lp->sh->inlineno--;
1973					if(c==RPAREN)
1974						fcseek(-LEN);
1975					goto done;
1976				}
1977				if(iop->iodelim[n++]!=c)
1978				{
1979					/*
1980					 * The match for delimiter failed.
1981					 * nsave>0 only when a buffer boundary
1982					 * was crossed while checking the
1983					 * delimiter
1984					 */
1985					if(!lp->lexd.dolparen && nsave>0)
1986					{
1987						if((n=sfwrite(sp,iop->iodelim,nsave))>0)
1988							iop->iosize += n;
1989						bufp = fcfirst();
1990					}
1991					if(c==NL)
1992						fcseek(-LEN);
1993					break;
1994				}
1995			}
1996			break;
1997		    case S_ESC:
1998			n=1;
1999#if SHOPT_CRNL
2000			if(c=='\r')
2001			{
2002				fcseek(1);
2003				if(c=fcget())
2004					fcseek(-LEN);
2005				if(c==NL)
2006					n=2;
2007				else
2008				{
2009					special++;
2010					break;
2011				}
2012			}
2013#endif /* SHOPT_CRNL */
2014			if(c==NL)
2015			{
2016				/* new-line joining */
2017				lp->sh->inlineno++;
2018				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
2019				{
2020					if(n && (n=sfwrite(sp,bufp,n))>0)
2021						iop->iosize += n;
2022					bufp = fcseek(0)+1;
2023				}
2024			}
2025			else
2026				special++;
2027			fcget();
2028			break;
2029
2030		    case S_GRAVE:
2031		    case S_DOL:
2032			special++;
2033			break;
2034		}
2035		n=0;
2036	}
2037done:
2038	lp->sh->funlog = funlog;
2039	if(lp->lexd.dolparen)
2040		free((void*)iop);
2041	else if(!special)
2042		iop->iofile |= IOQUOTE;
2043	return(c);
2044}
2045
2046/*
2047 * generates string for given token
2048 */
2049static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
2050{
2051	int n=1;
2052	if(sym < 0)
2053		return((char*)sh_translate(e_lexzerobyte));
2054	if(sym==0)
2055		return(lp->arg?lp->arg->argval:"?");
2056	if(lp->lex.intest && lp->arg && *lp->arg->argval)
2057		return(lp->arg->argval);
2058	if(sym&SYMRES)
2059	{
2060		register const Shtable_t *tp=shtab_reserved;
2061		while(tp->sh_number && tp->sh_number!=sym)
2062			tp++;
2063		return((char*)tp->sh_name);
2064	}
2065	if(sym==EOFSYM)
2066		return((char*)sh_translate(e_endoffile));
2067	if(sym==NL)
2068		return((char*)sh_translate(e_newline));
2069	tok[0] = sym;
2070	if(sym&SYMREP)
2071		tok[n++] = sym;
2072	else
2073	{
2074		switch(sym&SYMMASK)
2075		{
2076			case SYMAMP:
2077				sym = '&';
2078				break;
2079			case SYMPIPE:
2080				sym = '|';
2081				break;
2082			case SYMGT:
2083				sym = '>';
2084				break;
2085			case SYMLPAR:
2086				sym = LPAREN;
2087				break;
2088			case SYMSHARP:
2089				sym = '#';
2090				break;
2091			case SYMSEMI:
2092				if(tok[0]=='<')
2093					tok[n++] = '>';
2094				sym = ';';
2095				break;
2096			default:
2097				sym = 0;
2098		}
2099		tok[n++] = sym;
2100	}
2101	tok[n] = 0;
2102	return(tok);
2103}
2104
2105/*
2106 * print a bad syntax message
2107 */
2108
2109void	sh_syntax(Lex_t *lp)
2110{
2111	register Shell_t *shp = lp->sh;
2112	register const char *cp = sh_translate(e_unexpected);
2113	register char *tokstr;
2114	register int tok = lp->token;
2115	char tokbuf[3];
2116	Sfio_t *sp;
2117	if((tok==EOFSYM) && lp->lasttok)
2118	{
2119		tok = lp->lasttok;
2120		cp = sh_translate(e_unmatched);
2121	}
2122	else
2123		lp->lastline = shp->inlineno;
2124	tokstr = fmttoken(lp,tok,tokbuf);
2125	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
2126	{
2127		/* clear out any pending input */
2128		register Sfio_t *top;
2129		while(fcget()>0);
2130		fcclose();
2131		while(top=sfstack(sp,SF_POPSTACK))
2132			sfclose(top);
2133	}
2134	else
2135		fcclose();
2136	shp->inlineno = lp->inlineno;
2137	shp->st.firstline = lp->firstline;
2138#if KSHELL
2139	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
2140#else
2141	if(shp->inlineno!=1)
2142#endif
2143		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
2144	else
2145		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
2146}
2147
2148static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
2149{
2150	register char *ep;
2151	register int offset = stktell(stkp);
2152	register int left = offset-(sp-stkptr(stkp,0));
2153	register int shift = (dp+1-sp);
2154	offset += shift;
2155	stkseek(stkp,offset);
2156	sp = stkptr(stkp,offset);
2157	ep = sp - shift;
2158	while(left--)
2159		*--sp = *--ep;
2160	return(sp);
2161}
2162
2163/*
2164 * Assumes that current word is unfrozen on top of the stak
2165 * If <mode> is zero, gets rid of quoting and consider argument as string
2166 *    and returns pointer to frozen arg
2167 * If mode==1, just replace $"..." strings with international strings
2168 *    The result is left on the stak
2169 * If mode==2, the each $"" string is printed on standard output
2170 */
2171struct argnod *sh_endword(Shell_t *shp,int mode)
2172{
2173	register const char *state = sh_lexstates[ST_NESTED];
2174	register int n;
2175	register char *sp,*dp;
2176	register int inquote=0, inlit=0; /* set within quoted strings */
2177	struct argnod* argp=0;
2178	char	*ep=0, *xp=0;
2179	int bracket=0;
2180	Stk_t		*stkp=shp->stk;
2181	sfputc(stkp,0);
2182	sp =  stkptr(stkp,ARGVAL);
2183#if SHOPT_MULTIBYTE
2184	if(mbwide())
2185	{
2186		do
2187		{
2188			int len;
2189			switch(len = mbsize(sp))
2190			{
2191			    case -1:	/* illegal multi-byte char */
2192			    case 0:
2193			    case 1:
2194				n=state[*sp++];
2195				break;
2196			    default:
2197				/*
2198				 * None of the state tables contain
2199				 * entries for multibyte characters,
2200				 * however, they should be treated
2201				 * the same as any other alph
2202				 * character.  Therefore, we'll use
2203				 * the state of the 'a' character.
2204				 */
2205				n=state['a'];
2206				sp += len;
2207			}
2208		}
2209		while(n == 0);
2210	}
2211	else
2212#endif /* SHOPT_MULTIBYTE */
2213	while((n=state[*sp++])==0);
2214	dp = sp;
2215	if(mode<0)
2216		inquote = 1;
2217	while(1)
2218	{
2219		switch(n)
2220		{
2221		    case S_EOF:
2222			stkseek(stkp,dp-stkptr(stkp,0));
2223			if(mode<=0)
2224			{
2225				argp = (struct argnod*)stkfreeze(stkp,0);
2226				argp->argflag = ARG_RAW|ARG_QUOTED;
2227			}
2228			return(argp);
2229		    case S_LIT:
2230			if(!(inquote&1))
2231			{
2232				inlit = !inlit;
2233				if(mode==0 || (mode<0 && bracket))
2234				{
2235					dp--;
2236					if(ep)
2237					{
2238						*dp = 0;
2239						stresc(ep);
2240						dp = ep+ strlen(ep);
2241					}
2242					ep = 0;
2243				}
2244			}
2245			break;
2246		    case S_QUOTE:
2247			if(mode<0 && !bracket)
2248				break;
2249			if(!inlit)
2250			{
2251				if(mode<=0)
2252					dp--;
2253				inquote = inquote^1;
2254				if(ep)
2255				{
2256					char *msg;
2257					if(mode==2)
2258					{
2259						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2260						ep = 0;
2261						break;
2262					}
2263					*--dp = 0;
2264#if ERROR_VERSION >= 20000317L
2265					msg = ERROR_translate(0,error_info.id,0,ep);
2266#else
2267#   if ERROR_VERSION >= 20000101L
2268					msg = ERROR_translate(error_info.id,ep);
2269#   else
2270					msg = ERROR_translate(ep,2);
2271#   endif
2272#endif
2273					n = strlen(msg);
2274					dp = ep+n;
2275					if(sp-dp <= 1)
2276					{
2277						sp = stack_shift(stkp,sp,dp);
2278						dp = sp-1;
2279						ep = dp-n;
2280					}
2281					memmove(ep,msg,n);
2282					*dp++ = '"';
2283				}
2284				ep = 0;
2285			}
2286			break;
2287		    case S_DOL:	/* check for $'...'  and $"..." */
2288			if(inlit)
2289				break;
2290			if(*sp==LPAREN || *sp==LBRACE)
2291			{
2292				inquote <<= 1;
2293				break;
2294			}
2295			if(inquote&1)
2296				break;
2297			if(*sp=='\'' || *sp=='"')
2298			{
2299				if(*sp=='"')
2300					inquote |= 1;
2301				else
2302					inlit = 1;
2303				sp++;
2304				if((mode==0||(mode<0&&bracket)) || (inquote&1))
2305				{
2306					if(mode==2)
2307						ep = dp++;
2308					else if(mode==1)
2309						(ep=dp)[-1] = '"';
2310					else
2311						ep = --dp;
2312				}
2313			}
2314			break;
2315		    case S_ESC:
2316#if SHOPT_CRNL
2317			if(*sp=='\r' && sp[1]=='\n')
2318				sp++;
2319#endif /* SHOPT_CRNL */
2320			if(inlit || mode>0)
2321			{
2322				if(mode<0)
2323				{
2324					if(dp>=sp)
2325					{
2326						sp = stack_shift(stkp,sp,dp+1);
2327						dp = sp-2;
2328					}
2329					*dp++ = '\\';
2330				}
2331				if(ep)
2332					*dp++ = *sp++;
2333				break;
2334			}
2335			n = *sp;
2336#if SHOPT_DOS
2337			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2338				break;
2339#endif /* SHOPT_DOS */
2340			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2341			{
2342				if(n=='\n')
2343					dp--;
2344				else
2345					dp[-1] = n;
2346				sp++;
2347			}
2348			break;
2349		    case S_POP:
2350			if(sp[-1]!=RBRACT)
2351				break;
2352			if(!inlit && !(inquote&1))
2353			{
2354				inquote >>= 1;
2355				if(xp)
2356					dp = sh_checkid(xp,dp);
2357				xp = 0;
2358				if(--bracket<=0 && mode<0)
2359					inquote = 1;
2360			}
2361			else if((inlit||inquote) && mode<0)
2362			{
2363				dp[-1] = '\\';
2364				if(dp>=sp)
2365				{
2366					sp = stack_shift(stkp,sp,dp);
2367					dp = sp-1;
2368				}
2369				*dp++ = ']';
2370			}
2371			break;
2372		    case S_BRACT:
2373			if(dp[-2]=='.')
2374				xp = dp;
2375			if(mode<0)
2376			{
2377				if(inlit || (bracket&&inquote))
2378				{
2379					dp[-1] = '\\';
2380					if(dp>=sp)
2381					{
2382						sp = stack_shift(stkp,sp,dp);
2383						dp = sp-1;
2384					}
2385					*dp++ = '[';
2386				}
2387				else if(bracket++==0)
2388					inquote = 0;
2389			}
2390			break;
2391		}
2392#if SHOPT_MULTIBYTE
2393		if(mbwide())
2394		{
2395			do
2396			{
2397				int len;
2398				switch(len = mbsize(sp))
2399				{
2400				    case -1: /* illegal multi-byte char */
2401				    case 0:
2402				    case 1:
2403					n=state[*dp++ = *sp++];
2404					break;
2405				    default:
2406					/*
2407					 * None of the state tables contain
2408					 * entries for multibyte characters,
2409					 * however, they should be treated
2410					 * the same as any other alph
2411					 * character.  Therefore, we'll use
2412					 * the state of the 'a' character.
2413					 */
2414					while(len--)
2415						*dp++ = *sp++;
2416					n=state['a'];
2417				}
2418			}
2419			while(n == 0);
2420		}
2421		else
2422#endif /* SHOPT_MULTIBYTE */
2423		while((n=state[*dp++ = *sp++])==0);
2424	}
2425}
2426
2427struct alias
2428{
2429	Sfdisc_t	disc;
2430	Namval_t	*np;
2431	int		nextc;
2432	int		line;
2433	char		buf[2];
2434	Lex_t		*lp;
2435};
2436
2437/*
2438 * This code gets called whenever an end of string is found with alias
2439 */
2440
2441#ifndef SF_ATEXIT
2442#   define SF_ATEXIT	0
2443#endif
2444/*
2445 * This code gets called whenever an end of string is found with alias
2446 */
2447#ifdef SF_BUFCONST
2448static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2449#else
2450static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2451#endif
2452{
2453	register struct alias *ap = (struct alias*)handle;
2454	register Namval_t *np;
2455	register Lex_t	*lp;
2456	if(type==0 || type==SF_ATEXIT || !ap)
2457		return(0);
2458	lp = ap->lp;
2459	np = ap->np;
2460	if(type!=SF_READ)
2461	{
2462		if(type==SF_CLOSING)
2463		{
2464			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2465			if(dp!=handle)
2466				sfdisc(iop,dp);
2467		}
2468		else if(type==SF_FINAL)
2469			free((void*)ap);
2470		goto done;
2471	}
2472	if(ap->nextc)
2473	{
2474		/* if last character is a blank, then next work can be alias */
2475		register int c = fcpeek(-1);
2476		if(isblank(c))
2477			lp->aliasok = 1;
2478		*ap->buf = ap->nextc;
2479		ap->nextc = 0;
2480		sfsetbuf(iop,ap->buf,1);
2481		return(1);
2482	}
2483done:
2484	if(np)
2485		nv_offattr(np,NV_NOEXPAND);
2486	return(0);
2487}
2488
2489
2490static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2491{
2492	register Sfio_t *iop, *base;
2493	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2494	ap->disc = alias_disc;
2495	ap->lp = lp;
2496	ap->buf[1] = 0;
2497	if(ap->np = np)
2498	{
2499#if SHOPT_KIA
2500		if(lp->kiafile)
2501		{
2502			unsigned long r;
2503			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
2504			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
2505		}
2506#endif /* SHOPT_KIA */
2507		if((ap->nextc=fcget())==0)
2508			ap->nextc = ' ';
2509	}
2510	else
2511		ap->nextc = 0;
2512	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2513	sfdisc(iop, &ap->disc);
2514	lp->lexd.nocopy++;
2515	if(!(base=fcfile()))
2516		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2517	fcclose();
2518	sfstack(base,iop);
2519	fcfopen(base);
2520	lp->lexd.nocopy--;
2521}
2522
2523/*
2524 * grow storage stack for nested constructs by STACK_ARRAY
2525 */
2526static int stack_grow(Lex_t *lp)
2527{
2528	lp->lexd.lex_max += STACK_ARRAY;
2529	if(lp->lexd.lex_match)
2530		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
2531	else
2532		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2533	return(lp->lexd.lex_match!=0);
2534}
2535
2536