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