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