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