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