xref: /titanic_51/usr/src/lib/libshell/common/sh/lex.c (revision 8ddde5afbc73594c66a4a0a32d45b9e7f0aae4e4)
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 
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 		lp->lexd.lex_state = lp->lexd.lastc=0;
277 	}
278 	lp->comsub = 0;
279 	return(lp);
280 }
281 
282 #ifdef DBUG
283 extern int lextoken(Lex_t*);
284 int 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  */
313 int 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 						char *tmp;
1086 						if(lp->lexd.warn)
1087 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1088 						if(!(state=lp->lexd.first))
1089 							state = fcfirst();
1090 						tmp = fcseek(0);
1091 						fcseek(state - tmp);
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 off, 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 	off = fcseek(0) - lp->lexd.first;
1500 	if(sh_lex(lp)==endtok)
1501 	{
1502 		if(endtok==LPAREN && fcseek(0)==lp->lexd.first)
1503 		{
1504 			count++;
1505 			lp->lexd.paren = 0;
1506 			fcseek(off+2);
1507 		}
1508 		while(1)
1509 		{
1510 			/* look for case and esac */
1511 			n=0;
1512 			while(1)
1513 			{
1514 				fcgetc(c);
1515 				/* skip leading white space */
1516 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
1517 					continue;
1518 				if(n==4)
1519 					break;
1520 				if(sh_lexstates[ST_NAME][c])
1521 					goto skip;
1522 				word[n++] = c;
1523 			}
1524 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
1525 			{
1526 				if(memcmp(word,"case",4)==0)
1527 					lp->lex.incase=1;
1528 				else if(memcmp(word,"esac",4)==0)
1529 					lp->lex.incase=0;
1530 			}
1531 		skip:
1532 			if(c && (c!='#' || n==0))
1533 				fcseek(-1);
1534 			if(c==RBRACE && lp->lex.incase)
1535 				lp->lex.incase=0;
1536 			switch(c=sh_lex(lp))
1537 			{
1538 			    case LBRACE:
1539 				if(endtok==LBRACE && !lp->lex.incase)
1540 				{
1541 					lp->comsub = 0;
1542 					count++;
1543 				}
1544 				break;
1545 			    case RBRACE:
1546 			    rbrace:
1547 				if(endtok==LBRACE && --count<=0)
1548 					goto done;
1549 				lp->comsub = (count==1);
1550 				break;
1551 			    case IPROCSYM:	case OPROCSYM:
1552 			    case LPAREN:
1553 				if(endtok==LPAREN && !lp->lex.incase)
1554 					count++;
1555 				break;
1556 			    case RPAREN:
1557 				if(lp->lex.incase)
1558 					lp->lex.incase=0;
1559 				else if(endtok==LPAREN && --count<=0)
1560 					goto done;
1561 				break;
1562 			    case EOFSYM:
1563 				lp->lastline = line;
1564 				lp->lasttok = endtok;
1565 				sh_syntax(lp);
1566 			    case IOSEEKSYM:
1567 				if(fcgetc(c)!='#' && c>0)
1568 					fcseek(-1);
1569 				break;
1570 			    case IODOCSYM:
1571 				lp->lexd.docextra = 0;
1572 				sh_lex(lp);
1573 				break;
1574 			    case 0:
1575 				lp->lex.reservok = 0;
1576 				messages |= lp->lexd.message;
1577 				break;
1578 			    case ';':
1579 				fcgetc(c);
1580 				if(c==RBRACE && endtok==LBRACE)
1581 					goto rbrace;
1582 				if(c>0)
1583 					fcseek(-1);
1584 				/* fall through*/
1585 			    default:
1586 				lp->lex.reservok = 1;
1587 			}
1588 		}
1589 	}
1590 done:
1591 	poplevel(lp);
1592 	lp->comsub = csub;
1593 	lp->lastline = line;
1594 	lp->lexd.dolparen--;
1595 	lp->lex = save;
1596 	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
1597 	return(messages);
1598 }
1599 
1600 /*
1601  * here-doc nested in $(...)
1602  * allocate ionode with delimiter filled in without disturbing stak
1603  */
1604 static void nested_here(register Lex_t *lp)
1605 {
1606 	register struct ionod	*iop;
1607 	register int		n,offset;
1608 	struct argnod		*arg = lp->arg;
1609 	Stk_t			*stkp = lp->sh->stk;
1610 	char			*base;
1611 	if(offset=stktell(stkp))
1612 		base = stkfreeze(stkp,0);
1613 	n = fcseek(0)-lp->lexd.docend;
1614 	iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
1615 	iop->iolst = lp->heredoc;
1616 	stkseek(stkp,ARGVAL);
1617 	if(lp->lexd.docextra)
1618 	{
1619 		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
1620 		sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
1621 	}
1622 	sfwrite(stkp,lp->lexd.docend,n);
1623 	lp->arg = sh_endword(lp->sh,0);
1624 	iop->ioname = (char*)(iop+1);
1625 	strcpy(iop->ioname,lp->arg->argval);
1626 	iop->iofile = (IODOC|IORAW);
1627 	if(lp->lexd.docword>1)
1628 		iop->iofile |= IOSTRIP;
1629 	lp->heredoc = iop;
1630 	lp->arg = arg;
1631 	lp->lexd.docword = 0;
1632 	if(offset)
1633 		stkset(stkp,base,offset);
1634 	else
1635 		stkseek(stkp,0);
1636 }
1637 
1638 /*
1639  * skip to <close> character
1640  * if <copy> is non,zero, then the characters are copied to the stack
1641  * <state> is the initial lexical state
1642  */
1643 void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
1644 {
1645 	register char	*cp;
1646 	lp->lexd.nest = close;
1647 	lp->lexd.lex_state = state;
1648 	lp->lexd.noarg = 1;
1649 	if(copy)
1650 		fcnotify(lex_advance,lp);
1651 	else
1652 		lp->lexd.nocopy++;
1653 	sh_lex(lp);
1654 	lp->lexd.noarg = 0;
1655 	if(copy)
1656 	{
1657 		fcnotify(0,lp);
1658 		if(!(cp=lp->lexd.first))
1659 			cp = fcfirst();
1660 		if((copy = fcseek(0)-cp) > 0)
1661 			sfwrite(lp->sh->stk,cp,copy);
1662 	}
1663 	else
1664 		lp->lexd.nocopy--;
1665 }
1666 
1667 #if SHOPT_CRNL
1668     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
1669     {
1670 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1671 	int m=0,k;
1672 	while(next = (const char*)memchr(next,'\r',ep-next))
1673 		if(*++next=='\n')
1674 		{
1675 			if(k=next-cp-1)
1676 			{
1677 				if((k=sfwrite(sp,cp,k)) < 0)
1678 					return(m>0?m:-1);
1679 				m += k;
1680 			}
1681 			cp = next;
1682 		}
1683 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
1684 		return(m>0?m:-1);
1685 	return(m+k);
1686     }
1687 #   define sfwrite	_sfwrite
1688 #endif /* SHOPT_CRNL */
1689 
1690 /*
1691  * read in here-document from script
1692  * quoted here documents, and here-documents without special chars are
1693  * noted with the IOQUOTE flag
1694  * returns 1 for complete here-doc, 0 for EOF
1695  */
1696 
1697 static int here_copy(Lex_t *lp,register struct ionod *iop)
1698 {
1699 	register const char	*state;
1700 	register int		c,n;
1701 	register char		*bufp,*cp;
1702 	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
1703 	int			stripcol=0,stripflg, nsave, special=0;
1704 	if(funlog=lp->sh->funlog)
1705 	{
1706 		if(fcfill()>0)
1707 			fcseek(-1);
1708 		lp->sh->funlog = 0;
1709 	}
1710 	if(iop->iolst)
1711 		here_copy(lp,iop->iolst);
1712 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1713 	iop->iosize = 0;
1714 	iop->iodelim=iop->ioname;
1715 	/* check for and strip quoted characters in delimiter string */
1716 	if(stripflg=iop->iofile&IOSTRIP)
1717 	{
1718 		while(*iop->iodelim=='\t')
1719 			iop->iodelim++;
1720 		/* skip over leading tabs in document */
1721 		if(iop->iofile&IOLSEEK)
1722 		{
1723 			iop->iofile &= ~IOLSEEK;
1724 			while(fcgetc(c)=='\t' || c==' ')
1725 			{
1726 				if(c==' ')
1727 					stripcol++;
1728 				else
1729 					stripcol += 8 - stripcol%8;
1730 			}
1731 		}
1732 		else
1733 			while(fcgetc(c)=='\t');
1734 		if(c>0)
1735 			fcseek(-1);
1736 	}
1737 	if(iop->iofile&IOQUOTE)
1738 		state = sh_lexstates[ST_LIT];
1739 	else
1740 		state = sh_lexstates[ST_QUOTE];
1741 	bufp = fcseek(0);
1742 	n = S_NL;
1743 	while(1)
1744 	{
1745 		if(n!=S_NL)
1746 		{
1747 			/* skip over regular characters */
1748 			while((n=STATE(state,c))==0);
1749 		}
1750 		if(n==S_EOF || !(c=fcget()))
1751 		{
1752 			if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
1753 			{
1754 				if(n==S_ESC)
1755 					c--;
1756 				if((c=sfwrite(sp,bufp,c))>0)
1757 					iop->iosize += c;
1758 			}
1759 			if((c=lexfill(lp))<=0)
1760 				break;
1761 			if(n==S_ESC)
1762 			{
1763 #if SHOPT_CRNL
1764 				if(c=='\r' && (c=fcget())!=NL)
1765 					fcseek(-1);
1766 #endif /* SHOPT_CRNL */
1767 				if(c==NL)
1768 					fcseek(1);
1769 				else
1770 					sfputc(sp,'\\');
1771 			}
1772 			bufp = fcseek(-1);
1773 		}
1774 		else
1775 			fcseek(-1);
1776 		switch(n)
1777 		{
1778 		    case S_NL:
1779 			lp->sh->inlineno++;
1780 			if((stripcol && c==' ') || (stripflg && c=='\t'))
1781 			{
1782 				if(!lp->lexd.dolparen)
1783 				{
1784 					/* write out line */
1785 					n = fcseek(0)-bufp;
1786 					if((n=sfwrite(sp,bufp,n))>0)
1787 						iop->iosize += n;
1788 				}
1789 				/* skip over tabs */
1790 				if(stripcol)
1791 				{
1792 					int col=0;
1793 					do
1794 					{
1795 						fcgetc(c);
1796 						if(c==' ')
1797 							col++;
1798 						else
1799 							col += 8 - col%8;
1800 						if(col>stripcol)
1801 							break;
1802 					}
1803 					while (c==' ' || c=='\t');
1804 				}
1805 				else while(c=='\t')
1806 					fcgetc(c);
1807 				if(c<=0)
1808 					goto done;
1809 				bufp = fcseek(-1);
1810 			}
1811 			if(c!=iop->iodelim[0])
1812 				break;
1813 			cp = fcseek(0);
1814 			nsave = n = 0;
1815 			while(1)
1816 			{
1817 				if(!(c=fcget()))
1818 				{
1819 					if(!lp->lexd.dolparen && (c=cp-bufp))
1820 					{
1821 						if((c=sfwrite(sp,cp=bufp,c))>0)
1822 							iop->iosize+=c;
1823 					}
1824 					nsave = n;
1825 					if((c=lexfill(lp))<=0)
1826 					{
1827 						c = iop->iodelim[n]==0;
1828 						goto done;
1829 					}
1830 				}
1831 #if SHOPT_CRNL
1832 				if(c=='\r' && (c=fcget())!=NL)
1833 				{
1834 					if(c)
1835 						fcseek(-1);
1836 					c='\r';
1837 				}
1838 #endif /* SHOPT_CRNL */
1839 				if(c==NL)
1840 					lp->sh->inlineno++;
1841 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
1842 				{
1843 					if(!lp->lexd.dolparen && (n=cp-bufp))
1844 					{
1845 						if((n=sfwrite(sp,bufp,n))>0)
1846 							iop->iosize += n;
1847 					}
1848 					lp->sh->inlineno--;
1849 					if(c==RPAREN)
1850 						fcseek(-1);
1851 					goto done;
1852 				}
1853 				if(iop->iodelim[n++]!=c)
1854 				{
1855 					/*
1856 					 * The match for delimiter failed.
1857 					 * nsave>0 only when a buffer boundary
1858 					 * was crossed while checking the
1859 					 * delimiter
1860 					 */
1861 					if(!lp->lexd.dolparen && nsave>0)
1862 					{
1863 						if((n=sfwrite(sp,bufp,nsave))>0)
1864 							iop->iosize += n;
1865 						bufp = fcfirst();
1866 					}
1867 					if(c==NL)
1868 						fcseek(-1);
1869 					break;
1870 				}
1871 			}
1872 			break;
1873 		    case S_ESC:
1874 			n=1;
1875 #if SHOPT_CRNL
1876 			if(c=='\r')
1877 			{
1878 				fcseek(1);
1879 				if(c=fcget())
1880 					fcseek(-1);
1881 				if(c==NL)
1882 					n=2;
1883 				else
1884 				{
1885 					special++;
1886 					break;
1887 				}
1888 			}
1889 #endif /* SHOPT_CRNL */
1890 			if(c==NL)
1891 			{
1892 				/* new-line joining */
1893 				lp->sh->inlineno++;
1894 				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
1895 				{
1896 					if(n && (n=sfwrite(sp,bufp,n))>0)
1897 						iop->iosize += n;
1898 					bufp = fcseek(0)+1;
1899 				}
1900 			}
1901 			else
1902 				special++;
1903 			fcget();
1904 			break;
1905 
1906 		    case S_GRAVE:
1907 		    case S_DOL:
1908 			special++;
1909 			break;
1910 		}
1911 		n=0;
1912 	}
1913 done:
1914 	lp->sh->funlog = funlog;
1915 	if(lp->lexd.dolparen)
1916 		free((void*)iop);
1917 	else if(!special)
1918 		iop->iofile |= IOQUOTE;
1919 	return(c);
1920 }
1921 
1922 /*
1923  * generates string for given token
1924  */
1925 static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
1926 {
1927 	int n=1;
1928 	if(sym < 0)
1929 		return((char*)sh_translate(e_lexzerobyte));
1930 	if(sym==0)
1931 		return(lp->arg?lp->arg->argval:"?");
1932 	if(lp->lex.intest && lp->arg && *lp->arg->argval)
1933 		return(lp->arg->argval);
1934 	if(sym&SYMRES)
1935 	{
1936 		register const Shtable_t *tp=shtab_reserved;
1937 		while(tp->sh_number && tp->sh_number!=sym)
1938 			tp++;
1939 		return((char*)tp->sh_name);
1940 	}
1941 	if(sym==EOFSYM)
1942 		return((char*)sh_translate(e_endoffile));
1943 	if(sym==NL)
1944 		return((char*)sh_translate(e_newline));
1945 	tok[0] = sym;
1946 	if(sym&SYMREP)
1947 		tok[n++] = sym;
1948 	else
1949 	{
1950 		switch(sym&SYMMASK)
1951 		{
1952 			case SYMAMP:
1953 				sym = '&';
1954 				break;
1955 			case SYMPIPE:
1956 				sym = '|';
1957 				break;
1958 			case SYMGT:
1959 				sym = '>';
1960 				break;
1961 			case SYMLPAR:
1962 				sym = LPAREN;
1963 				break;
1964 			case SYMSHARP:
1965 				sym = '#';
1966 				break;
1967 			case SYMSEMI:
1968 				if(tok[0]=='<')
1969 					tok[n++] = '>';
1970 				sym = ';';
1971 				break;
1972 			default:
1973 				sym = 0;
1974 		}
1975 		tok[n++] = sym;
1976 	}
1977 	tok[n] = 0;
1978 	return(tok);
1979 }
1980 
1981 /*
1982  * print a bad syntax message
1983  */
1984 
1985 void	sh_syntax(Lex_t *lp)
1986 {
1987 	register Shell_t *shp = lp->sh;
1988 	register const char *cp = sh_translate(e_unexpected);
1989 	register char *tokstr;
1990 	register int tok = lp->token;
1991 	char tokbuf[3];
1992 	Sfio_t *sp;
1993 	if((tok==EOFSYM) && lp->lasttok)
1994 	{
1995 		tok = lp->lasttok;
1996 		cp = sh_translate(e_unmatched);
1997 	}
1998 	else
1999 		lp->lastline = shp->inlineno;
2000 	tokstr = fmttoken(lp,tok,tokbuf);
2001 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
2002 	{
2003 		/* clear out any pending input */
2004 		register Sfio_t *top;
2005 		while(fcget()>0);
2006 		fcclose();
2007 		while(top=sfstack(sp,SF_POPSTACK))
2008 			sfclose(top);
2009 	}
2010 	else
2011 		fcclose();
2012 	shp->inlineno = lp->inlineno;
2013 	shp->st.firstline = lp->firstline;
2014 #if KSHELL
2015 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
2016 #else
2017 	if(shp->inlineno!=1)
2018 #endif
2019 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
2020 	else
2021 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
2022 }
2023 
2024 static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
2025 {
2026 	register char *ep;
2027 	register int offset = stktell(stkp);
2028 	register int left = offset-(sp-stkptr(stkp,0));
2029 	register int shift = (dp+1-sp);
2030 	offset += shift;
2031 	stkseek(stkp,offset);
2032 	sp = stkptr(stkp,offset);
2033 	ep = sp - shift;
2034 	while(left--)
2035 		*--sp = *--ep;
2036 	return(sp);
2037 }
2038 
2039 /*
2040  * Assumes that current word is unfrozen on top of the stak
2041  * If <mode> is zero, gets rid of quoting and consider argument as string
2042  *    and returns pointer to frozen arg
2043  * If mode==1, just replace $"..." strings with international strings
2044  *    The result is left on the stak
2045  * If mode==2, the each $"" string is printed on standard output
2046  */
2047 struct argnod *sh_endword(Shell_t *shp,int mode)
2048 {
2049 	register const char *state = sh_lexstates[ST_NESTED];
2050 	register int n;
2051 	register char *sp,*dp;
2052 	register int inquote=0, inlit=0; /* set within quoted strings */
2053 	struct argnod* argp=0;
2054 	char	*ep=0, *xp=0;
2055 	int bracket=0;
2056 	Stk_t		*stkp=shp->stk;
2057 	sfputc(stkp,0);
2058 	sp =  stkptr(stkp,ARGVAL);
2059 #if SHOPT_MULTIBYTE
2060 	if(mbwide())
2061 	{
2062 		do
2063 		{
2064 			int len;
2065 			switch(len = mbsize(sp))
2066 			{
2067 			    case -1:	/* illegal multi-byte char */
2068 			    case 0:
2069 			    case 1:
2070 				n=state[*sp++];
2071 				break;
2072 			    default:
2073 				/*
2074 				 * None of the state tables contain
2075 				 * entries for multibyte characters,
2076 				 * however, they should be treated
2077 				 * the same as any other alph
2078 				 * character.  Therefore, we'll use
2079 				 * the state of the 'a' character.
2080 				 */
2081 				n=state['a'];
2082 				sp += len;
2083 			}
2084 		}
2085 		while(n == 0);
2086 	}
2087 	else
2088 #endif /* SHOPT_MULTIBYTE */
2089 	while((n=state[*sp++])==0);
2090 	dp = sp;
2091 	if(mode<0)
2092 		inquote = 1;
2093 	while(1)
2094 	{
2095 		switch(n)
2096 		{
2097 		    case S_EOF:
2098 			stkseek(stkp,dp-stkptr(stkp,0));
2099 			if(mode<=0)
2100 			{
2101 				argp = (struct argnod*)stkfreeze(stkp,0);
2102 				argp->argflag = ARG_RAW|ARG_QUOTED;
2103 			}
2104 			return(argp);
2105 		    case S_LIT:
2106 			if(!(inquote&1))
2107 			{
2108 				inlit = !inlit;
2109 				if(mode==0 || (mode<0 && bracket))
2110 				{
2111 					dp--;
2112 					if(ep)
2113 					{
2114 						*dp = 0;
2115 						dp = ep+stresc(ep);
2116 					}
2117 					ep = 0;
2118 				}
2119 			}
2120 			break;
2121 		    case S_QUOTE:
2122 			if(mode<0 && !bracket)
2123 				break;
2124 			if(!inlit)
2125 			{
2126 				if(mode<=0)
2127 					dp--;
2128 				inquote = inquote^1;
2129 				if(ep)
2130 				{
2131 					char *msg;
2132 					if(mode==2)
2133 					{
2134 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2135 						ep = 0;
2136 						break;
2137 					}
2138 					*--dp = 0;
2139 #if ERROR_VERSION >= 20000317L
2140 					msg = ERROR_translate(0,error_info.id,0,ep);
2141 #else
2142 #   if ERROR_VERSION >= 20000101L
2143 					msg = ERROR_translate(error_info.id,ep);
2144 #   else
2145 					msg = ERROR_translate(ep,2);
2146 #   endif
2147 #endif
2148 					n = strlen(msg);
2149 					dp = ep+n;
2150 					if(sp-dp <= 1)
2151 					{
2152 						sp = stack_shift(stkp,sp,dp);
2153 						dp = sp-1;
2154 						ep = dp-n;
2155 					}
2156 					memmove(ep,msg,n);
2157 					*dp++ = '"';
2158 				}
2159 				ep = 0;
2160 			}
2161 			break;
2162 		    case S_DOL:	/* check for $'...'  and $"..." */
2163 			if(inlit)
2164 				break;
2165 			if(*sp==LPAREN || *sp==LBRACE)
2166 			{
2167 				inquote <<= 1;
2168 				break;
2169 			}
2170 			if(inquote&1)
2171 				break;
2172 			if(*sp=='\'' || *sp=='"')
2173 			{
2174 				if(*sp=='"')
2175 					inquote |= 1;
2176 				else
2177 					inlit = 1;
2178 				sp++;
2179 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
2180 				{
2181 					if(mode==2)
2182 						ep = dp++;
2183 					else if(mode==1)
2184 						(ep=dp)[-1] = '"';
2185 					else
2186 						ep = --dp;
2187 				}
2188 			}
2189 			break;
2190 		    case S_ESC:
2191 #if SHOPT_CRNL
2192 			if(*sp=='\r' && sp[1]=='\n')
2193 				sp++;
2194 #endif /* SHOPT_CRNL */
2195 			if(inlit || mode>0)
2196 			{
2197 				if(mode<0)
2198 				{
2199 					if(dp>=sp)
2200 					{
2201 						sp = stack_shift(stkp,sp,dp+1);
2202 						dp = sp-2;
2203 					}
2204 					*dp++ = '\\';
2205 				}
2206 				if(ep)
2207 					*dp++ = *sp++;
2208 				break;
2209 			}
2210 			n = *sp;
2211 #if SHOPT_DOS
2212 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2213 				break;
2214 #endif /* SHOPT_DOS */
2215 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2216 			{
2217 				if(n=='\n')
2218 					dp--;
2219 				else
2220 					dp[-1] = n;
2221 				sp++;
2222 			}
2223 			break;
2224 		    case S_POP:
2225 			if(sp[-1]!=RBRACT)
2226 				break;
2227 			if(!inlit && !(inquote&1))
2228 			{
2229 				inquote >>= 1;
2230 				if(xp)
2231 					dp = sh_checkid(xp,dp);
2232 				xp = 0;
2233 				if(--bracket<=0 && mode<0)
2234 					inquote = 1;
2235 			}
2236 			else if((inlit||inquote) && mode<0)
2237 			{
2238 				dp[-1] = '\\';
2239 				if(dp>=sp)
2240 				{
2241 					sp = stack_shift(stkp,sp,dp);
2242 					dp = sp-1;
2243 				}
2244 				*dp++ = ']';
2245 			}
2246 			break;
2247 		    case S_BRACT:
2248 			if(dp[-2]=='.')
2249 				xp = dp;
2250 			if(mode<0)
2251 			{
2252 				if(inlit || (bracket&&inquote))
2253 				{
2254 					dp[-1] = '\\';
2255 					if(dp>=sp)
2256 					{
2257 						sp = stack_shift(stkp,sp,dp);
2258 						dp = sp-1;
2259 					}
2260 					*dp++ = '[';
2261 				}
2262 				else if(bracket++==0)
2263 					inquote = 0;
2264 			}
2265 			break;
2266 		}
2267 #if SHOPT_MULTIBYTE
2268 		if(mbwide())
2269 		{
2270 			do
2271 			{
2272 				int len;
2273 				switch(len = mbsize(sp))
2274 				{
2275 				    case -1: /* illegal multi-byte char */
2276 				    case 0:
2277 				    case 1:
2278 					n=state[*dp++ = *sp++];
2279 					break;
2280 				    default:
2281 					/*
2282 					 * None of the state tables contain
2283 					 * entries for multibyte characters,
2284 					 * however, they should be treated
2285 					 * the same as any other alph
2286 					 * character.  Therefore, we'll use
2287 					 * the state of the 'a' character.
2288 					 */
2289 					while(len--)
2290 						*dp++ = *sp++;
2291 					n=state['a'];
2292 				}
2293 			}
2294 			while(n == 0);
2295 		}
2296 		else
2297 #endif /* SHOPT_MULTIBYTE */
2298 		while((n=state[*dp++ = *sp++])==0);
2299 	}
2300 }
2301 
2302 struct alias
2303 {
2304 	Sfdisc_t	disc;
2305 	Namval_t	*np;
2306 	int		nextc;
2307 	int		line;
2308 	char		buf[2];
2309 	Lex_t		*lp;
2310 };
2311 
2312 /*
2313  * This code gets called whenever an end of string is found with alias
2314  */
2315 
2316 #ifndef SF_ATEXIT
2317 #   define SF_ATEXIT	0
2318 #endif
2319 /*
2320  * This code gets called whenever an end of string is found with alias
2321  */
2322 #ifdef SF_BUFCONST
2323 static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2324 #else
2325 static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2326 #endif
2327 {
2328 	register struct alias *ap = (struct alias*)handle;
2329 	register Namval_t *np;
2330 	register Lex_t	*lp;
2331 	if(type==0 || type==SF_ATEXIT || !ap)
2332 		return(0);
2333 	lp = ap->lp;
2334 	np = ap->np;
2335 	if(type!=SF_READ)
2336 	{
2337 		if(type==SF_CLOSING)
2338 		{
2339 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2340 			if(dp!=handle)
2341 				sfdisc(iop,dp);
2342 		}
2343 		else if(type==SF_FINAL)
2344 			free((void*)ap);
2345 		goto done;
2346 	}
2347 	if(ap->nextc)
2348 	{
2349 		/* if last character is a blank, then next work can be alias */
2350 		register int c = fcpeek(-1);
2351 		if(isblank(c))
2352 			lp->aliasok = 1;
2353 		*ap->buf = ap->nextc;
2354 		ap->nextc = 0;
2355 		sfsetbuf(iop,ap->buf,1);
2356 		return(1);
2357 	}
2358 done:
2359 	if(np)
2360 		nv_offattr(np,NV_NOEXPAND);
2361 	return(0);
2362 }
2363 
2364 
2365 static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2366 {
2367 	register Sfio_t *iop, *base;
2368 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2369 	ap->disc = alias_disc;
2370 	ap->lp = lp;
2371 	ap->buf[1] = 0;
2372 	if(ap->np = np)
2373 	{
2374 #if SHOPT_KIA
2375 		if(lp->kiafile)
2376 		{
2377 			unsigned long r;
2378 			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
2379 			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
2380 		}
2381 #endif /* SHOPT_KIA */
2382 		if((ap->nextc=fcget())==0)
2383 			ap->nextc = ' ';
2384 	}
2385 	else
2386 		ap->nextc = 0;
2387 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2388 	sfdisc(iop, &ap->disc);
2389 	lp->lexd.nocopy++;
2390 	if(!(base=fcfile()))
2391 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2392 	fcclose();
2393 	sfstack(base,iop);
2394 	fcfopen(base);
2395 	lp->lexd.nocopy--;
2396 }
2397 
2398 /*
2399  * grow storage stack for nested constructs by STACK_ARRAY
2400  */
2401 static int stack_grow(Lex_t *lp)
2402 {
2403 	lp->lexd.lex_max += STACK_ARRAY;
2404 	if(lp->lexd.lex_match)
2405 		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
2406 	else
2407 		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2408 	return(lp->lexd.lex_match!=0);
2409 }
2410 
2411