xref: /titanic_51/usr/src/lib/libshell/common/sh/lex.c (revision f5c2e7ea56aaa46a9976476fb0cb1f02b9426f07)
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 						if(lp->lexd.warn)
1086 							errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1087 						if(!(state=lp->lexd.first))
1088 							state = fcfirst();
1089 						fcseek(state-fcseek(0));
1090 						if(lp->arg)
1091 						{
1092 							lp->arg = (struct argnod*)stkfreeze(stkp,1);
1093 							setupalias(lp,lp->arg->argval,NIL(Namval_t*));
1094 						}
1095 						lp->lexd.paren = 1;
1096 					}
1097 					return(lp->token=LPAREN);
1098 				}
1099 				if(mode==ST_NONE)
1100 					return(0);
1101 				if(c!=n)
1102 				{
1103 					lp->token = c;
1104 					sh_syntax(lp);
1105 				}
1106 				if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
1107 					goto epat;
1108 				continue;
1109 			case S_EQ:
1110 				assignment = lp->assignok;
1111 				/* FALL THRU */
1112 			case S_COLON:
1113 				if(assignment)
1114 				{
1115 					if((c=fcget())=='~')
1116 						wordflags |= ARG_MAC;
1117 					else if(c!=LPAREN && assignment==SH_COMPASSIGN)
1118 						assignment = 0;
1119 					fcseek(-1);
1120 				}
1121 				break;
1122 			case S_LABEL:
1123 				if(lp->lex.reservok && !lp->lex.incase)
1124 				{
1125 					c = fcget();
1126 					fcseek(-1);
1127 					if(state[c]==S_BREAK)
1128 					{
1129 						assignment = -1;
1130 						goto breakloop;
1131 					}
1132 				}
1133 				break;
1134 			case S_BRACT:
1135 				/* check for possible subscript */
1136 				if((n=endchar(lp))==RBRACT || n==RPAREN ||
1137 					(mode==ST_BRACE) ||
1138 					(oldmode(lp)==ST_NONE) ||
1139 					(mode==ST_NAME && (lp->assignok||lp->lexd.level)))
1140 				{
1141 					if(mode==ST_NAME)
1142 					{
1143 						fcgetc(n);
1144 						if(n>0)
1145 						{
1146 							if(n==']')
1147 								errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
1148 							fcseek(-1);
1149 						}
1150 					}
1151 					pushlevel(lp,RBRACT,mode);
1152 					wordflags |= ARG_QUOTED;
1153 					mode = ST_NESTED;
1154 					continue;
1155 				}
1156 				wordflags |= ARG_EXP;
1157 				break;
1158 			case S_BRACE:
1159 			{
1160 				int isfirst;
1161 				if(lp->lexd.dolparen)
1162 				{
1163 					if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
1164 					{
1165 						fcgetc(n);
1166 						if(n>0)
1167 							fcseek(-1);
1168 						else
1169 							n = '\n';
1170 						if(n==RBRACT || sh_lexstates[ST_NORM][n])
1171 							return(lp->token=c);
1172 					}
1173 					break;
1174 				}
1175 				else if(mode==ST_BEGIN)
1176 				{
1177 					if(lp->comsub && c==RBRACE)
1178 						return(lp->token=c);
1179 					goto do_reg;
1180 				}
1181 				isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
1182 				fcgetc(n);
1183 				/* check for {} */
1184 				if(c==LBRACE && n==RBRACE)
1185 					break;
1186 				if(n>0)
1187 					fcseek(-1);
1188 				else if(lp->lex.reservok)
1189 					break;
1190 				/* check for reserved word { or } */
1191 				if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
1192 					break;
1193 				if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
1194 					&& !lp->lex.incase && !lp->lex.intest
1195 					&& !lp->lex.skipword)
1196 				{
1197 					wordflags |= ARG_EXP;
1198 				}
1199 				if(c==RBRACE && n==LPAREN)
1200 					goto epat;
1201 				break;
1202 			}
1203 			case S_PAT:
1204 				wordflags |= ARG_EXP;
1205 				/* FALL THRU */
1206 			case S_EPAT:
1207 			epat:
1208 				if(fcgetc(n)==LPAREN)
1209 				{
1210 					if(lp->lex.incase==TEST_RE)
1211 					{
1212 						lp->lex.incase++;
1213 						pushlevel(lp,RPAREN,ST_NORM);
1214 						mode = ST_NESTED;
1215 					}
1216 					wordflags |= ARG_EXP;
1217 					pushlevel(lp,RPAREN,mode);
1218 					mode = ST_NESTED;
1219 					continue;
1220 				}
1221 				if(n>0)
1222 					fcseek(-1);
1223 				if(n=='=' && c=='+' && mode==ST_NAME)
1224 					continue;
1225 				break;
1226 		}
1227 		lp->comp_assign = 0;
1228 		if(mode==ST_NAME)
1229 			mode = ST_NORM;
1230 		else if(mode==ST_NONE)
1231 			return(0);
1232 	}
1233 breakloop:
1234 	if(lp->lexd.nocopy)
1235 	{
1236 		lp->lexd.balance = 0;
1237 		return(0);
1238 	}
1239 	if(lp->lexd.dolparen)
1240 	{
1241 		lp->lexd.balance = 0;
1242 		if(lp->lexd.docword)
1243 			nested_here(lp);
1244 		lp->lexd.message = (wordflags&ARG_MESSAGE);
1245 		return(lp->token=0);
1246 	}
1247 	if(!(state=lp->lexd.first))
1248 		state = fcfirst();
1249 	n = fcseek(0)-(char*)state;
1250 	if(!lp->arg)
1251 		lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
1252 	if(n>0)
1253 		sfwrite(stkp,state,n);
1254 	/* add balancing character if necessary */
1255 	if(lp->lexd.balance)
1256 	{
1257 		sfputc(stkp,lp->lexd.balance);
1258 		lp->lexd.balance = 0;
1259 	}
1260 	sfputc(stkp,0);
1261 	stkseek(stkp,stktell(stkp)-1);
1262 	state = stkptr(stkp,ARGVAL);
1263 	n = stktell(stkp)-ARGVAL;
1264 	lp->lexd.first=0;
1265 	if(n==1)
1266 	{
1267 		/* check for numbered redirection */
1268 		n = state[0];
1269 		if((c=='<' || c=='>') && isadigit(n))
1270 		{
1271 			c = sh_lex(lp);
1272 			lp->digits = (n-'0');
1273 			return(c);
1274 		}
1275 		if(n==LBRACT)
1276 			c = 0;
1277 		else if(n==RBRACE && lp->comsub)
1278 			return(lp->token=n);
1279 		else if(n=='~')
1280 			c = ARG_MAC;
1281 		else
1282 			c = (wordflags&ARG_EXP);
1283 		n = 1;
1284 	}
1285 	else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
1286 	{
1287 		if(!strchr(state,','))
1288 		{
1289 			stkseek(stkp,stktell(stkp)-1);
1290 			lp->arg = (struct argnod*)stkfreeze(stkp,1);
1291 			return(lp->token=IOVNAME);
1292 		}
1293 		c = wordflags;
1294 	}
1295 	else
1296 		c = wordflags;
1297 	if(assignment<0)
1298 	{
1299 		stkseek(stkp,stktell(stkp)-1);
1300 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1301 		lp->lex.reservok = 1;
1302 		return(lp->token=LABLSYM);
1303 	}
1304 	if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
1305 		c &= ~ARG_EXP;
1306 	if((c&ARG_EXP) && (c&ARG_QUOTED))
1307 		c |= ARG_MAC;
1308 	if(mode==ST_NONE)
1309 	{
1310 		/* eliminate trailing )) */
1311 		stkseek(stkp,stktell(stkp)-2);
1312 	}
1313 	if(c&ARG_MESSAGE)
1314 	{
1315 		if(sh_isoption(SH_DICTIONARY))
1316 			lp->arg = sh_endword(shp,2);
1317 		if(!sh_isoption(SH_NOEXEC))
1318 		{
1319 			lp->arg = sh_endword(shp,1);
1320 			c &= ~ARG_MESSAGE;
1321 		}
1322 	}
1323 	if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword))
1324 	{
1325 		lp->arg = (struct argnod*)stkfreeze(stkp,1);
1326 		lp->arg->argflag = (c?c:ARG_RAW);
1327 	}
1328 	else if(mode==ST_NONE)
1329 		lp->arg = sh_endword(shp,-1);
1330 	else
1331 		lp->arg = sh_endword(shp,0);
1332 	state = lp->arg->argval;
1333 	lp->comp_assign = assignment;
1334 	if(assignment)
1335 		lp->arg->argflag |= ARG_ASSIGN;
1336 	else if(!lp->lex.skipword)
1337 		lp->assignok = 0;
1338 	lp->arg->argchn.cp = 0;
1339 	lp->arg->argnxt.ap = 0;
1340 	if(mode==ST_NONE)
1341 		return(lp->token=EXPRSYM);
1342 	if(lp->lex.intest)
1343 	{
1344 		if(lp->lex.testop1)
1345 		{
1346 			lp->lex.testop1 = 0;
1347 			if(n==2 && state[0]=='-' && state[2]==0 &&
1348 				strchr(test_opchars,state[1]))
1349 			{
1350 				if(lp->lexd.warn && state[1]=='a')
1351 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
1352 				lp->digits = state[1];
1353 				lp->token = TESTUNOP;
1354 			}
1355 			else if(n==1 && state[0]=='!' && state[1]==0)
1356 			{
1357 				lp->lex.testop1 = 1;
1358 				lp->token = '!';
1359 			}
1360 			else
1361 			{
1362 				lp->lex.testop2 = 1;
1363 				lp->token = 0;
1364 			}
1365 			return(lp->token);
1366 		}
1367 		lp->lex.incase = 0;
1368 		c = sh_lookup(state,shtab_testops);
1369 		switch(c)
1370 		{
1371 		case TEST_END:
1372 			lp->lex.testop2 = lp->lex.intest = 0;
1373 			lp->lex.reservok = 1;
1374 			lp->token = ETESTSYM;
1375 			return(lp->token);
1376 
1377 		case TEST_SEQ:
1378 			if(lp->lexd.warn && state[1]==0)
1379 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
1380 			/* FALL THRU */
1381 		default:
1382 			if(lp->lex.testop2)
1383 			{
1384 				if(lp->lexd.warn && (c&TEST_ARITH))
1385 					errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
1386 				if(c&TEST_PATTERN)
1387 					lp->lex.incase = 1;
1388 				else if(c==TEST_REP)
1389 					lp->lex.incase = TEST_RE;
1390 				lp->lex.testop2 = 0;
1391 				lp->digits = c;
1392 				lp->token = TESTBINOP;
1393 				return(lp->token);
1394 			}
1395 
1396 		case TEST_OR: case TEST_AND:
1397 		case 0:
1398 			return(lp->token=0);
1399 		}
1400 	}
1401 	if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
1402 	{
1403 		/* check for {, }, ! */
1404 		c = state[0];
1405 		if(n==1 && (c=='{' || c=='}' || c=='!'))
1406 		{
1407 			if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
1408 				errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
1409 			if(lp->lex.incase==1 && c==RBRACE)
1410 				lp->lex.incase = 0;
1411 			return(lp->token=c);
1412 		}
1413 		else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
1414 		{
1415 			lp->lex.intest = lp->lex.testop1 = 1;
1416 			lp->lex.testop2 = lp->lex.reservok = 0;
1417 			return(lp->token=BTESTSYM);
1418 		}
1419 	}
1420 	c = 0;
1421 	if(!lp->lex.skipword)
1422 	{
1423 		if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
1424 			(c=sh_lookup(state,shtab_reserved)))
1425 		{
1426 			if(lp->lex.incase)
1427 			{
1428 				if(lp->lex.incase >1)
1429 					lp->lex.incase = 1;
1430 				else if(c==ESACSYM)
1431 					lp->lex.incase = 0;
1432 				else
1433 					c = 0;
1434 			}
1435 			else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
1436 			{
1437 				lp->lex.skipword = 1;
1438 				lp->lex.incase = 2*(c==CASESYM);
1439 			}
1440 			else
1441 				lp->lex.skipword = 0;
1442 			if(c==INSYM)
1443 				lp->lex.reservok = 0;
1444 			else if(c==TIMESYM)
1445 			{
1446 				/* yech - POSIX requires time -p */
1447 				while(fcgetc(n)==' ' || n=='\t');
1448 				if(n>0)
1449 					fcseek(-1);
1450 				if(n=='-')
1451 					c=0;
1452 			}
1453 			return(lp->token=c);
1454 		}
1455 		if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
1456 		{
1457 			/* check for aliases */
1458 			Namval_t* np;
1459 			if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
1460 				(np=nv_search(state,shp->alias_tree,HASH_SCOPE))
1461 				&& !nv_isattr(np,NV_NOEXPAND)
1462 #if KSHELL
1463 				&& (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
1464 #endif /* KSHELL */
1465 				&& (state=nv_getval(np)))
1466 			{
1467 				setupalias(lp,state,np);
1468 				nv_onattr(np,NV_NOEXPAND);
1469 				lp->lex.reservok = 1;
1470 				lp->assignok |= lp->lex.reservok;
1471 				return(sh_lex(lp));
1472 			}
1473 		}
1474 		lp->lex.reservok = 0;
1475 	}
1476 	lp->lex.skipword = lp->lexd.docword = 0;
1477 	return(lp->token=c);
1478 }
1479 
1480 /*
1481  * read to end of command substitution
1482  */
1483 static int comsub(register Lex_t *lp, int endtok)
1484 {
1485 	register int	n,c,count=1;
1486 	register int	line=lp->sh->inlineno;
1487 	char word[5];
1488 	int off, messages=0, assignok=lp->assignok, csub;
1489 	struct lexstate	save;
1490 	save = lp->lex;
1491 	csub = lp->comsub;
1492 	sh_lexopen(lp,lp->sh,1);
1493 	lp->lexd.dolparen++;
1494 	lp->lex.incase=0;
1495 	pushlevel(lp,0,0);
1496 	lp->comsub = (endtok==LBRACE);
1497 	off = fcseek(0) - lp->lexd.first;
1498 	if(sh_lex(lp)==endtok)
1499 	{
1500 		if(endtok==LPAREN && fcseek(0)==lp->lexd.first)
1501 		{
1502 			count++;
1503 			lp->lexd.paren = 0;
1504 			fcseek(off+2);
1505 		}
1506 		while(1)
1507 		{
1508 			/* look for case and esac */
1509 			n=0;
1510 			while(1)
1511 			{
1512 				fcgetc(c);
1513 				/* skip leading white space */
1514 				if(n==0 && !sh_lexstates[ST_BEGIN][c])
1515 					continue;
1516 				if(n==4)
1517 					break;
1518 				if(sh_lexstates[ST_NAME][c])
1519 					goto skip;
1520 				word[n++] = c;
1521 			}
1522 			if(sh_lexstates[ST_NAME][c]==S_BREAK)
1523 			{
1524 				if(memcmp(word,"case",4)==0)
1525 					lp->lex.incase=1;
1526 				else if(memcmp(word,"esac",4)==0)
1527 					lp->lex.incase=0;
1528 			}
1529 		skip:
1530 			if(c && (c!='#' || n==0))
1531 				fcseek(-1);
1532 			if(c==RBRACE && lp->lex.incase)
1533 				lp->lex.incase=0;
1534 			switch(c=sh_lex(lp))
1535 			{
1536 			    case LBRACE:
1537 				if(endtok==LBRACE && !lp->lex.incase)
1538 				{
1539 					lp->comsub = 0;
1540 					count++;
1541 				}
1542 				break;
1543 			    case RBRACE:
1544 			    rbrace:
1545 				if(endtok==LBRACE && --count<=0)
1546 					goto done;
1547 				lp->comsub = (count==1);
1548 				break;
1549 			    case IPROCSYM:	case OPROCSYM:
1550 			    case LPAREN:
1551 				if(endtok==LPAREN && !lp->lex.incase)
1552 					count++;
1553 				break;
1554 			    case RPAREN:
1555 				if(lp->lex.incase)
1556 					lp->lex.incase=0;
1557 				else if(endtok==LPAREN && --count<=0)
1558 					goto done;
1559 				break;
1560 			    case EOFSYM:
1561 				lp->lastline = line;
1562 				lp->lasttok = endtok;
1563 				sh_syntax(lp);
1564 			    case IOSEEKSYM:
1565 				if(fcgetc(c)!='#' && c>0)
1566 					fcseek(-1);
1567 				break;
1568 			    case IODOCSYM:
1569 				lp->lexd.docextra = 0;
1570 				sh_lex(lp);
1571 				break;
1572 			    case 0:
1573 				lp->lex.reservok = 0;
1574 				messages |= lp->lexd.message;
1575 				break;
1576 			    case ';':
1577 				fcgetc(c);
1578 				if(c==RBRACE && endtok==LBRACE)
1579 					goto rbrace;
1580 				if(c>0)
1581 					fcseek(-1);
1582 				/* fall through*/
1583 			    default:
1584 				lp->lex.reservok = 1;
1585 			}
1586 		}
1587 	}
1588 done:
1589 	poplevel(lp);
1590 	lp->comsub = csub;
1591 	lp->lastline = line;
1592 	lp->lexd.dolparen--;
1593 	lp->lex = save;
1594 	lp->assignok = (endchar(lp)==RBRACT?assignok:0);
1595 	return(messages);
1596 }
1597 
1598 /*
1599  * here-doc nested in $(...)
1600  * allocate ionode with delimiter filled in without disturbing stak
1601  */
1602 static void nested_here(register Lex_t *lp)
1603 {
1604 	register struct ionod	*iop;
1605 	register int		n,offset;
1606 	struct argnod		*arg = lp->arg;
1607 	Stk_t			*stkp = lp->sh->stk;
1608 	char			*base;
1609 	if(offset=stktell(stkp))
1610 		base = stkfreeze(stkp,0);
1611 	n = fcseek(0)-lp->lexd.docend;
1612 	iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
1613 	iop->iolst = lp->heredoc;
1614 	stkseek(stkp,ARGVAL);
1615 	if(lp->lexd.docextra)
1616 	{
1617 		sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
1618 		sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
1619 	}
1620 	sfwrite(stkp,lp->lexd.docend,n);
1621 	lp->arg = sh_endword(lp->sh,0);
1622 	iop->ioname = (char*)(iop+1);
1623 	strcpy(iop->ioname,lp->arg->argval);
1624 	iop->iofile = (IODOC|IORAW);
1625 	if(lp->lexd.docword>1)
1626 		iop->iofile |= IOSTRIP;
1627 	lp->heredoc = iop;
1628 	lp->arg = arg;
1629 	lp->lexd.docword = 0;
1630 	if(offset)
1631 		stkset(stkp,base,offset);
1632 	else
1633 		stkseek(stkp,0);
1634 }
1635 
1636 /*
1637  * skip to <close> character
1638  * if <copy> is non,zero, then the characters are copied to the stack
1639  * <state> is the initial lexical state
1640  */
1641 void sh_lexskip(Lex_t *lp,int close, register int copy, int  state)
1642 {
1643 	register char	*cp;
1644 	lp->lexd.nest = close;
1645 	lp->lexd.lex_state = state;
1646 	lp->lexd.noarg = 1;
1647 	if(copy)
1648 		fcnotify(lex_advance,lp);
1649 	else
1650 		lp->lexd.nocopy++;
1651 	sh_lex(lp);
1652 	lp->lexd.noarg = 0;
1653 	if(copy)
1654 	{
1655 		fcnotify(0,lp);
1656 		if(!(cp=lp->lexd.first))
1657 			cp = fcfirst();
1658 		if((copy = fcseek(0)-cp) > 0)
1659 			sfwrite(lp->sh->stk,cp,copy);
1660 	}
1661 	else
1662 		lp->lexd.nocopy--;
1663 }
1664 
1665 #if SHOPT_CRNL
1666     ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
1667     {
1668 	const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1669 	int m=0,k;
1670 	while(next = (const char*)memchr(next,'\r',ep-next))
1671 		if(*++next=='\n')
1672 		{
1673 			if(k=next-cp-1)
1674 			{
1675 				if((k=sfwrite(sp,cp,k)) < 0)
1676 					return(m>0?m:-1);
1677 				m += k;
1678 			}
1679 			cp = next;
1680 		}
1681 	if((k=sfwrite(sp,cp,ep-cp)) < 0)
1682 		return(m>0?m:-1);
1683 	return(m+k);
1684     }
1685 #   define sfwrite	_sfwrite
1686 #endif /* SHOPT_CRNL */
1687 
1688 /*
1689  * read in here-document from script
1690  * quoted here documents, and here-documents without special chars are
1691  * noted with the IOQUOTE flag
1692  * returns 1 for complete here-doc, 0 for EOF
1693  */
1694 
1695 static int here_copy(Lex_t *lp,register struct ionod *iop)
1696 {
1697 	register const char	*state;
1698 	register int		c,n;
1699 	register char		*bufp,*cp;
1700 	register Sfio_t		*sp=lp->sh->heredocs, *funlog;
1701 	int			stripcol=0,stripflg, nsave, special=0;
1702 	if(funlog=lp->sh->funlog)
1703 	{
1704 		if(fcfill()>0)
1705 			fcseek(-1);
1706 		lp->sh->funlog = 0;
1707 	}
1708 	if(iop->iolst)
1709 		here_copy(lp,iop->iolst);
1710 	iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1711 	iop->iosize = 0;
1712 	iop->iodelim=iop->ioname;
1713 	/* check for and strip quoted characters in delimiter string */
1714 	if(stripflg=iop->iofile&IOSTRIP)
1715 	{
1716 		while(*iop->iodelim=='\t')
1717 			iop->iodelim++;
1718 		/* skip over leading tabs in document */
1719 		if(iop->iofile&IOLSEEK)
1720 		{
1721 			iop->iofile &= ~IOLSEEK;
1722 			while(fcgetc(c)=='\t' || c==' ')
1723 			{
1724 				if(c==' ')
1725 					stripcol++;
1726 				else
1727 					stripcol += 8 - stripcol%8;
1728 			}
1729 		}
1730 		else
1731 			while(fcgetc(c)=='\t');
1732 		if(c>0)
1733 			fcseek(-1);
1734 	}
1735 	if(iop->iofile&IOQUOTE)
1736 		state = sh_lexstates[ST_LIT];
1737 	else
1738 		state = sh_lexstates[ST_QUOTE];
1739 	bufp = fcseek(0);
1740 	n = S_NL;
1741 	while(1)
1742 	{
1743 		if(n!=S_NL)
1744 		{
1745 			/* skip over regular characters */
1746 			while((n=STATE(state,c))==0);
1747 		}
1748 		if(n==S_EOF || !(c=fcget()))
1749 		{
1750 			if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
1751 			{
1752 				if(n==S_ESC)
1753 					c--;
1754 				if((c=sfwrite(sp,bufp,c))>0)
1755 					iop->iosize += c;
1756 			}
1757 			if((c=lexfill(lp))<=0)
1758 				break;
1759 			if(n==S_ESC)
1760 			{
1761 #if SHOPT_CRNL
1762 				if(c=='\r' && (c=fcget())!=NL)
1763 					fcseek(-1);
1764 #endif /* SHOPT_CRNL */
1765 				if(c==NL)
1766 					fcseek(1);
1767 				else
1768 					sfputc(sp,'\\');
1769 			}
1770 			bufp = fcseek(-1);
1771 		}
1772 		else
1773 			fcseek(-1);
1774 		switch(n)
1775 		{
1776 		    case S_NL:
1777 			lp->sh->inlineno++;
1778 			if((stripcol && c==' ') || (stripflg && c=='\t'))
1779 			{
1780 				if(!lp->lexd.dolparen)
1781 				{
1782 					/* write out line */
1783 					n = fcseek(0)-bufp;
1784 					if((n=sfwrite(sp,bufp,n))>0)
1785 						iop->iosize += n;
1786 				}
1787 				/* skip over tabs */
1788 				if(stripcol)
1789 				{
1790 					int col=0;
1791 					do
1792 					{
1793 						fcgetc(c);
1794 						if(c==' ')
1795 							col++;
1796 						else
1797 							col += 8 - col%8;
1798 						if(col>stripcol)
1799 							break;
1800 					}
1801 					while (c==' ' || c=='\t');
1802 				}
1803 				else while(c=='\t')
1804 					fcgetc(c);
1805 				if(c<=0)
1806 					goto done;
1807 				bufp = fcseek(-1);
1808 			}
1809 			if(c!=iop->iodelim[0])
1810 				break;
1811 			cp = fcseek(0);
1812 			nsave = n = 0;
1813 			while(1)
1814 			{
1815 				if(!(c=fcget()))
1816 				{
1817 					if(!lp->lexd.dolparen && (c=cp-bufp))
1818 					{
1819 						if((c=sfwrite(sp,cp=bufp,c))>0)
1820 							iop->iosize+=c;
1821 					}
1822 					nsave = n;
1823 					if((c=lexfill(lp))<=0)
1824 					{
1825 						c = iop->iodelim[n]==0;
1826 						goto done;
1827 					}
1828 				}
1829 #if SHOPT_CRNL
1830 				if(c=='\r' && (c=fcget())!=NL)
1831 				{
1832 					if(c)
1833 						fcseek(-1);
1834 					c='\r';
1835 				}
1836 #endif /* SHOPT_CRNL */
1837 				if(c==NL)
1838 					lp->sh->inlineno++;
1839 				if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
1840 				{
1841 					if(!lp->lexd.dolparen && (n=cp-bufp))
1842 					{
1843 						if((n=sfwrite(sp,bufp,n))>0)
1844 							iop->iosize += n;
1845 					}
1846 					lp->sh->inlineno--;
1847 					if(c==RPAREN)
1848 						fcseek(-1);
1849 					goto done;
1850 				}
1851 				if(iop->iodelim[n++]!=c)
1852 				{
1853 					/*
1854 					 * The match for delimiter failed.
1855 					 * nsave>0 only when a buffer boundary
1856 					 * was crossed while checking the
1857 					 * delimiter
1858 					 */
1859 					if(!lp->lexd.dolparen && nsave>0)
1860 					{
1861 						if((n=sfwrite(sp,bufp,nsave))>0)
1862 							iop->iosize += n;
1863 						bufp = fcfirst();
1864 					}
1865 					if(c==NL)
1866 						fcseek(-1);
1867 					break;
1868 				}
1869 			}
1870 			break;
1871 		    case S_ESC:
1872 			n=1;
1873 #if SHOPT_CRNL
1874 			if(c=='\r')
1875 			{
1876 				fcseek(1);
1877 				if(c=fcget())
1878 					fcseek(-1);
1879 				if(c==NL)
1880 					n=2;
1881 				else
1882 				{
1883 					special++;
1884 					break;
1885 				}
1886 			}
1887 #endif /* SHOPT_CRNL */
1888 			if(c==NL)
1889 			{
1890 				/* new-line joining */
1891 				lp->sh->inlineno++;
1892 				if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
1893 				{
1894 					if(n && (n=sfwrite(sp,bufp,n))>0)
1895 						iop->iosize += n;
1896 					bufp = fcseek(0)+1;
1897 				}
1898 			}
1899 			else
1900 				special++;
1901 			fcget();
1902 			break;
1903 
1904 		    case S_GRAVE:
1905 		    case S_DOL:
1906 			special++;
1907 			break;
1908 		}
1909 		n=0;
1910 	}
1911 done:
1912 	lp->sh->funlog = funlog;
1913 	if(lp->lexd.dolparen)
1914 		free((void*)iop);
1915 	else if(!special)
1916 		iop->iofile |= IOQUOTE;
1917 	return(c);
1918 }
1919 
1920 /*
1921  * generates string for given token
1922  */
1923 static char	*fmttoken(Lex_t *lp, register int sym, char *tok)
1924 {
1925 	int n=1;
1926 	if(sym < 0)
1927 		return((char*)sh_translate(e_lexzerobyte));
1928 	if(sym==0)
1929 		return(lp->arg?lp->arg->argval:"?");
1930 	if(lp->lex.intest && lp->arg && *lp->arg->argval)
1931 		return(lp->arg->argval);
1932 	if(sym&SYMRES)
1933 	{
1934 		register const Shtable_t *tp=shtab_reserved;
1935 		while(tp->sh_number && tp->sh_number!=sym)
1936 			tp++;
1937 		return((char*)tp->sh_name);
1938 	}
1939 	if(sym==EOFSYM)
1940 		return((char*)sh_translate(e_endoffile));
1941 	if(sym==NL)
1942 		return((char*)sh_translate(e_newline));
1943 	tok[0] = sym;
1944 	if(sym&SYMREP)
1945 		tok[n++] = sym;
1946 	else
1947 	{
1948 		switch(sym&SYMMASK)
1949 		{
1950 			case SYMAMP:
1951 				sym = '&';
1952 				break;
1953 			case SYMPIPE:
1954 				sym = '|';
1955 				break;
1956 			case SYMGT:
1957 				sym = '>';
1958 				break;
1959 			case SYMLPAR:
1960 				sym = LPAREN;
1961 				break;
1962 			case SYMSHARP:
1963 				sym = '#';
1964 				break;
1965 			case SYMSEMI:
1966 				if(tok[0]=='<')
1967 					tok[n++] = '>';
1968 				sym = ';';
1969 				break;
1970 			default:
1971 				sym = 0;
1972 		}
1973 		tok[n++] = sym;
1974 	}
1975 	tok[n] = 0;
1976 	return(tok);
1977 }
1978 
1979 /*
1980  * print a bad syntax message
1981  */
1982 
1983 void	sh_syntax(Lex_t *lp)
1984 {
1985 	register Shell_t *shp = lp->sh;
1986 	register const char *cp = sh_translate(e_unexpected);
1987 	register char *tokstr;
1988 	register int tok = lp->token;
1989 	char tokbuf[3];
1990 	Sfio_t *sp;
1991 	if((tok==EOFSYM) && lp->lasttok)
1992 	{
1993 		tok = lp->lasttok;
1994 		cp = sh_translate(e_unmatched);
1995 	}
1996 	else
1997 		lp->lastline = shp->inlineno;
1998 	tokstr = fmttoken(lp,tok,tokbuf);
1999 	if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
2000 	{
2001 		/* clear out any pending input */
2002 		register Sfio_t *top;
2003 		while(fcget()>0);
2004 		fcclose();
2005 		while(top=sfstack(sp,SF_POPSTACK))
2006 			sfclose(top);
2007 	}
2008 	else
2009 		fcclose();
2010 	shp->inlineno = lp->inlineno;
2011 	shp->st.firstline = lp->firstline;
2012 #if KSHELL
2013 	if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
2014 #else
2015 	if(shp->inlineno!=1)
2016 #endif
2017 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
2018 	else
2019 		errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
2020 }
2021 
2022 static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
2023 {
2024 	register char *ep;
2025 	register int offset = stktell(stkp);
2026 	register int left = offset-(sp-stkptr(stkp,0));
2027 	register int shift = (dp+1-sp);
2028 	offset += shift;
2029 	stkseek(stkp,offset);
2030 	sp = stkptr(stkp,offset);
2031 	ep = sp - shift;
2032 	while(left--)
2033 		*--sp = *--ep;
2034 	return(sp);
2035 }
2036 
2037 /*
2038  * Assumes that current word is unfrozen on top of the stak
2039  * If <mode> is zero, gets rid of quoting and consider argument as string
2040  *    and returns pointer to frozen arg
2041  * If mode==1, just replace $"..." strings with international strings
2042  *    The result is left on the stak
2043  * If mode==2, the each $"" string is printed on standard output
2044  */
2045 struct argnod *sh_endword(Shell_t *shp,int mode)
2046 {
2047 	register const char *state = sh_lexstates[ST_NESTED];
2048 	register int n;
2049 	register char *sp,*dp;
2050 	register int inquote=0, inlit=0; /* set within quoted strings */
2051 	struct argnod* argp=0;
2052 	char	*ep=0, *xp=0;
2053 	int bracket=0;
2054 	Stk_t		*stkp=shp->stk;
2055 	sfputc(stkp,0);
2056 	sp =  stkptr(stkp,ARGVAL);
2057 #if SHOPT_MULTIBYTE
2058 	if(mbwide())
2059 	{
2060 		do
2061 		{
2062 			int len;
2063 			switch(len = mbsize(sp))
2064 			{
2065 			    case -1:	/* illegal multi-byte char */
2066 			    case 0:
2067 			    case 1:
2068 				n=state[*sp++];
2069 				break;
2070 			    default:
2071 				/*
2072 				 * None of the state tables contain
2073 				 * entries for multibyte characters,
2074 				 * however, they should be treated
2075 				 * the same as any other alph
2076 				 * character.  Therefore, we'll use
2077 				 * the state of the 'a' character.
2078 				 */
2079 				n=state['a'];
2080 				sp += len;
2081 			}
2082 		}
2083 		while(n == 0);
2084 	}
2085 	else
2086 #endif /* SHOPT_MULTIBYTE */
2087 	while((n=state[*sp++])==0);
2088 	dp = sp;
2089 	if(mode<0)
2090 		inquote = 1;
2091 	while(1)
2092 	{
2093 		switch(n)
2094 		{
2095 		    case S_EOF:
2096 			stkseek(stkp,dp-stkptr(stkp,0));
2097 			if(mode<=0)
2098 			{
2099 				argp = (struct argnod*)stkfreeze(stkp,0);
2100 				argp->argflag = ARG_RAW|ARG_QUOTED;
2101 			}
2102 			return(argp);
2103 		    case S_LIT:
2104 			if(!(inquote&1))
2105 			{
2106 				inlit = !inlit;
2107 				if(mode==0 || (mode<0 && bracket))
2108 				{
2109 					dp--;
2110 					if(ep)
2111 					{
2112 						*dp = 0;
2113 						dp = ep+stresc(ep);
2114 					}
2115 					ep = 0;
2116 				}
2117 			}
2118 			break;
2119 		    case S_QUOTE:
2120 			if(mode<0 && !bracket)
2121 				break;
2122 			if(!inlit)
2123 			{
2124 				if(mode<=0)
2125 					dp--;
2126 				inquote = inquote^1;
2127 				if(ep)
2128 				{
2129 					char *msg;
2130 					if(mode==2)
2131 					{
2132 						sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2133 						ep = 0;
2134 						break;
2135 					}
2136 					*--dp = 0;
2137 #if ERROR_VERSION >= 20000317L
2138 					msg = ERROR_translate(0,error_info.id,0,ep);
2139 #else
2140 #   if ERROR_VERSION >= 20000101L
2141 					msg = ERROR_translate(error_info.id,ep);
2142 #   else
2143 					msg = ERROR_translate(ep,2);
2144 #   endif
2145 #endif
2146 					n = strlen(msg);
2147 					dp = ep+n;
2148 					if(sp-dp <= 1)
2149 					{
2150 						sp = stack_shift(stkp,sp,dp);
2151 						dp = sp-1;
2152 						ep = dp-n;
2153 					}
2154 					memmove(ep,msg,n);
2155 					*dp++ = '"';
2156 				}
2157 				ep = 0;
2158 			}
2159 			break;
2160 		    case S_DOL:	/* check for $'...'  and $"..." */
2161 			if(inlit)
2162 				break;
2163 			if(*sp==LPAREN || *sp==LBRACE)
2164 			{
2165 				inquote <<= 1;
2166 				break;
2167 			}
2168 			if(inquote&1)
2169 				break;
2170 			if(*sp=='\'' || *sp=='"')
2171 			{
2172 				if(*sp=='"')
2173 					inquote |= 1;
2174 				else
2175 					inlit = 1;
2176 				sp++;
2177 				if((mode==0||(mode<0&&bracket)) || (inquote&1))
2178 				{
2179 					if(mode==2)
2180 						ep = dp++;
2181 					else if(mode==1)
2182 						(ep=dp)[-1] = '"';
2183 					else
2184 						ep = --dp;
2185 				}
2186 			}
2187 			break;
2188 		    case S_ESC:
2189 #if SHOPT_CRNL
2190 			if(*sp=='\r' && sp[1]=='\n')
2191 				sp++;
2192 #endif /* SHOPT_CRNL */
2193 			if(inlit || mode>0)
2194 			{
2195 				if(mode<0)
2196 				{
2197 					if(dp>=sp)
2198 					{
2199 						sp = stack_shift(stkp,sp,dp+1);
2200 						dp = sp-2;
2201 					}
2202 					*dp++ = '\\';
2203 				}
2204 				if(ep)
2205 					*dp++ = *sp++;
2206 				break;
2207 			}
2208 			n = *sp;
2209 #if SHOPT_DOS
2210 			if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2211 				break;
2212 #endif /* SHOPT_DOS */
2213 			if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2214 			{
2215 				if(n=='\n')
2216 					dp--;
2217 				else
2218 					dp[-1] = n;
2219 				sp++;
2220 			}
2221 			break;
2222 		    case S_POP:
2223 			if(sp[-1]!=RBRACT)
2224 				break;
2225 			if(!inlit && !(inquote&1))
2226 			{
2227 				inquote >>= 1;
2228 				if(xp)
2229 					dp = sh_checkid(xp,dp);
2230 				xp = 0;
2231 				if(--bracket<=0 && mode<0)
2232 					inquote = 1;
2233 			}
2234 			else if((inlit||inquote) && mode<0)
2235 			{
2236 				dp[-1] = '\\';
2237 				if(dp>=sp)
2238 				{
2239 					sp = stack_shift(stkp,sp,dp);
2240 					dp = sp-1;
2241 				}
2242 				*dp++ = ']';
2243 			}
2244 			break;
2245 		    case S_BRACT:
2246 			if(dp[-2]=='.')
2247 				xp = dp;
2248 			if(mode<0)
2249 			{
2250 				if(inlit || (bracket&&inquote))
2251 				{
2252 					dp[-1] = '\\';
2253 					if(dp>=sp)
2254 					{
2255 						sp = stack_shift(stkp,sp,dp);
2256 						dp = sp-1;
2257 					}
2258 					*dp++ = '[';
2259 				}
2260 				else if(bracket++==0)
2261 					inquote = 0;
2262 			}
2263 			break;
2264 		}
2265 #if SHOPT_MULTIBYTE
2266 		if(mbwide())
2267 		{
2268 			do
2269 			{
2270 				int len;
2271 				switch(len = mbsize(sp))
2272 				{
2273 				    case -1: /* illegal multi-byte char */
2274 				    case 0:
2275 				    case 1:
2276 					n=state[*dp++ = *sp++];
2277 					break;
2278 				    default:
2279 					/*
2280 					 * None of the state tables contain
2281 					 * entries for multibyte characters,
2282 					 * however, they should be treated
2283 					 * the same as any other alph
2284 					 * character.  Therefore, we'll use
2285 					 * the state of the 'a' character.
2286 					 */
2287 					while(len--)
2288 						*dp++ = *sp++;
2289 					n=state['a'];
2290 				}
2291 			}
2292 			while(n == 0);
2293 		}
2294 		else
2295 #endif /* SHOPT_MULTIBYTE */
2296 		while((n=state[*dp++ = *sp++])==0);
2297 	}
2298 }
2299 
2300 struct alias
2301 {
2302 	Sfdisc_t	disc;
2303 	Namval_t	*np;
2304 	int		nextc;
2305 	int		line;
2306 	char		buf[2];
2307 	Lex_t		*lp;
2308 };
2309 
2310 /*
2311  * This code gets called whenever an end of string is found with alias
2312  */
2313 
2314 #ifndef SF_ATEXIT
2315 #   define SF_ATEXIT	0
2316 #endif
2317 /*
2318  * This code gets called whenever an end of string is found with alias
2319  */
2320 #ifdef SF_BUFCONST
2321 static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2322 #else
2323 static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2324 #endif
2325 {
2326 	register struct alias *ap = (struct alias*)handle;
2327 	register Namval_t *np;
2328 	register Lex_t	*lp;
2329 	if(type==0 || type==SF_ATEXIT || !ap)
2330 		return(0);
2331 	lp = ap->lp;
2332 	np = ap->np;
2333 	if(type!=SF_READ)
2334 	{
2335 		if(type==SF_CLOSING)
2336 		{
2337 			register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2338 			if(dp!=handle)
2339 				sfdisc(iop,dp);
2340 		}
2341 		else if(type==SF_FINAL)
2342 			free((void*)ap);
2343 		goto done;
2344 	}
2345 	if(ap->nextc)
2346 	{
2347 		/* if last character is a blank, then next work can be alias */
2348 		register int c = fcpeek(-1);
2349 		if(isblank(c))
2350 			lp->aliasok = 1;
2351 		*ap->buf = ap->nextc;
2352 		ap->nextc = 0;
2353 		sfsetbuf(iop,ap->buf,1);
2354 		return(1);
2355 	}
2356 done:
2357 	if(np)
2358 		nv_offattr(np,NV_NOEXPAND);
2359 	return(0);
2360 }
2361 
2362 
2363 static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2364 {
2365 	register Sfio_t *iop, *base;
2366 	struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2367 	ap->disc = alias_disc;
2368 	ap->lp = lp;
2369 	ap->buf[1] = 0;
2370 	if(ap->np = np)
2371 	{
2372 #if SHOPT_KIA
2373 		if(lp->kiafile)
2374 		{
2375 			unsigned long r;
2376 			r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
2377 			sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
2378 		}
2379 #endif /* SHOPT_KIA */
2380 		if((ap->nextc=fcget())==0)
2381 			ap->nextc = ' ';
2382 	}
2383 	else
2384 		ap->nextc = 0;
2385 	iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2386 	sfdisc(iop, &ap->disc);
2387 	lp->lexd.nocopy++;
2388 	if(!(base=fcfile()))
2389 		base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2390 	fcclose();
2391 	sfstack(base,iop);
2392 	fcfopen(base);
2393 	lp->lexd.nocopy--;
2394 }
2395 
2396 /*
2397  * grow storage stack for nested constructs by STACK_ARRAY
2398  */
2399 static int stack_grow(Lex_t *lp)
2400 {
2401 	lp->lexd.lex_max += STACK_ARRAY;
2402 	if(lp->lexd.lex_match)
2403 		lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
2404 	else
2405 		lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2406 	return(lp->lexd.lex_match!=0);
2407 }
2408 
2409