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