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