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