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