1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
43e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * KornShell lexical analyzer
23da2e3ebdSchin *
24da2e3ebdSchin * Written by David Korn
25da2e3ebdSchin * AT&T Labs
26da2e3ebdSchin *
27da2e3ebdSchin */
28da2e3ebdSchin
29da2e3ebdSchin #include <ast.h>
30da2e3ebdSchin #include <stak.h>
31da2e3ebdSchin #include <fcin.h>
32da2e3ebdSchin #include <nval.h>
33da2e3ebdSchin #include "FEATURE/options"
34da2e3ebdSchin
35da2e3ebdSchin #if KSHELL
36da2e3ebdSchin # include "defs.h"
37da2e3ebdSchin #else
38da2e3ebdSchin # include <shell.h>
39da2e3ebdSchin # define nv_getval(np) ((np)->nvalue)
40da2e3ebdSchin Shell_t sh = {1};
41da2e3ebdSchin #endif /* KSHELL */
42da2e3ebdSchin
43da2e3ebdSchin #include "argnod.h"
44da2e3ebdSchin #include "test.h"
45da2e3ebdSchin #include "lexstates.h"
46da2e3ebdSchin #include "io.h"
47da2e3ebdSchin
48da2e3ebdSchin #define TEST_RE 3
49da2e3ebdSchin #define SYNBAD 3 /* exit value for syntax errors */
50da2e3ebdSchin #define STACK_ARRAY 3 /* size of depth match stack growth */
51da2e3ebdSchin
52da2e3ebdSchin #if _lib_iswblank < 0 /* set in lexstates.h to enable this code */
53da2e3ebdSchin
54da2e3ebdSchin int
local_iswblank(wchar_t wc)55da2e3ebdSchin local_iswblank(wchar_t wc)
56da2e3ebdSchin {
57da2e3ebdSchin static int initialized;
58da2e3ebdSchin static wctype_t wt;
59da2e3ebdSchin
60da2e3ebdSchin if (!initialized)
61da2e3ebdSchin {
62da2e3ebdSchin initialized = 1;
63da2e3ebdSchin wt = wctype("blank");
64da2e3ebdSchin }
65da2e3ebdSchin return(iswctype(wc, wt));
66da2e3ebdSchin }
67da2e3ebdSchin
68da2e3ebdSchin #endif
69da2e3ebdSchin
70da2e3ebdSchin /*
71da2e3ebdSchin * This structure allows for arbitrary depth nesting of (...), {...}, [...]
72da2e3ebdSchin */
73da2e3ebdSchin struct lexstate
74da2e3ebdSchin {
75da2e3ebdSchin char incase; /* 1 for case pattern, 2 after case */
76da2e3ebdSchin char intest; /* 1 inside [[...]] */
77da2e3ebdSchin char testop1; /* 1 when unary test op legal */
78da2e3ebdSchin char testop2; /* 1 when binary test op legal */
79da2e3ebdSchin char reservok; /* >0 for reserved word legal */
80da2e3ebdSchin char skipword; /* next word can't be reserved */
81da2e3ebdSchin char last_quote; /* last multi-line quote character */
82da2e3ebdSchin };
83da2e3ebdSchin
84da2e3ebdSchin struct lexdata
85da2e3ebdSchin {
86da2e3ebdSchin char nocopy;
87da2e3ebdSchin char paren;
88da2e3ebdSchin char dolparen;
89da2e3ebdSchin char nest;
90da2e3ebdSchin char docword;
91da2e3ebdSchin char *docend;
92da2e3ebdSchin char noarg;
93da2e3ebdSchin char balance;
94da2e3ebdSchin char warn;
95da2e3ebdSchin char message;
96da2e3ebdSchin char arith;
97da2e3ebdSchin char *first;
98da2e3ebdSchin int level;
99da2e3ebdSchin int lastc;
100da2e3ebdSchin int lex_max;
101da2e3ebdSchin int *lex_match;
102da2e3ebdSchin int lex_state;
10334f9b3eeSRoland Mainz int docextra;
104da2e3ebdSchin #if SHOPT_KIA
105da2e3ebdSchin off_t kiaoff;
106da2e3ebdSchin #endif
107da2e3ebdSchin };
108da2e3ebdSchin
109da2e3ebdSchin #define _SHLEX_PRIVATE \
1107c2fbfb3SApril Chin struct lexdata lexd; \
1117c2fbfb3SApril Chin struct lexstate lex;
112da2e3ebdSchin
113da2e3ebdSchin #include "shlex.h"
114da2e3ebdSchin
115da2e3ebdSchin
1167c2fbfb3SApril Chin #define pushlevel(lp,c,s) ((lp->lexd.level>=lp->lexd.lex_max?stack_grow(lp):1) &&\
1177c2fbfb3SApril Chin ((lp->lexd.lex_match[lp->lexd.level++]=lp->lexd.lastc),\
1187c2fbfb3SApril Chin lp->lexd.lastc=(((s)<<CHAR_BIT)|(c))))
1197c2fbfb3SApril Chin #define oldmode(lp) (lp->lexd.lastc>>CHAR_BIT)
1207c2fbfb3SApril Chin #define endchar(lp) (lp->lexd.lastc&0xff)
1217c2fbfb3SApril Chin #define setchar(lp,c) (lp->lexd.lastc = ((lp->lexd.lastc&~0xff)|(c)))
1227c2fbfb3SApril Chin #define poplevel(lp) (lp->lexd.lastc=lp->lexd.lex_match[--lp->lexd.level])
123da2e3ebdSchin
124da2e3ebdSchin static char *fmttoken(Lex_t*, int, char*);
125da2e3ebdSchin #ifdef SF_BUFCONST
126da2e3ebdSchin static int alias_exceptf(Sfio_t*, int, void*, Sfdisc_t*);
127da2e3ebdSchin #else
128da2e3ebdSchin static int alias_exceptf(Sfio_t*, int, Sfdisc_t*);
129da2e3ebdSchin #endif
130da2e3ebdSchin static void setupalias(Lex_t*,const char*, Namval_t*);
1317c2fbfb3SApril Chin static int comsub(Lex_t*,int);
132da2e3ebdSchin static void nested_here(Lex_t*);
133da2e3ebdSchin static int here_copy(Lex_t*, struct ionod*);
134da2e3ebdSchin static int stack_grow(Lex_t*);
135da2e3ebdSchin static const Sfdisc_t alias_disc = { NULL, NULL, NULL, alias_exceptf, NULL };
136da2e3ebdSchin
137da2e3ebdSchin #if SHOPT_KIA
138da2e3ebdSchin
refvar(Lex_t * lp,int type)1397c2fbfb3SApril Chin static void refvar(Lex_t *lp, int type)
140da2e3ebdSchin {
1417c2fbfb3SApril Chin register Shell_t *shp = lp->sh;
1427c2fbfb3SApril Chin register Stk_t *stkp = shp->stk;
1437c2fbfb3SApril Chin off_t off = (fcseek(0)-(type+1))-(lp->lexd.first?lp->lexd.first:fcfirst());
144da2e3ebdSchin unsigned long r;
1457c2fbfb3SApril Chin if(lp->lexd.first)
146da2e3ebdSchin {
1477c2fbfb3SApril Chin off = (fcseek(0)-(type+1)) - lp->lexd.first;
1487c2fbfb3SApril Chin r=kiaentity(lp,lp->lexd.first+lp->lexd.kiaoff+type,off-lp->lexd.kiaoff,'v',-1,-1,lp->current,'v',0,"");
149da2e3ebdSchin }
150da2e3ebdSchin else
151da2e3ebdSchin {
1527c2fbfb3SApril Chin int n,offset = stktell(stkp);
153da2e3ebdSchin char *savptr,*begin;
154da2e3ebdSchin off = offset + (fcseek(0)-(type+1)) - fcfirst();
1557c2fbfb3SApril Chin if(lp->lexd.kiaoff < offset)
156da2e3ebdSchin {
157da2e3ebdSchin /* variable starts on stak, copy remainder */
158da2e3ebdSchin if(off>offset)
1597c2fbfb3SApril Chin sfwrite(stkp,fcfirst()+type,off-offset);
1607c2fbfb3SApril Chin n = stktell(stkp)-lp->lexd.kiaoff;
1617c2fbfb3SApril Chin begin = stkptr(stkp,lp->lexd.kiaoff);
162da2e3ebdSchin }
163da2e3ebdSchin else
164da2e3ebdSchin {
165da2e3ebdSchin /* variable in data buffer */
1667c2fbfb3SApril Chin begin = fcfirst()+(type+lp->lexd.kiaoff-offset);
1677c2fbfb3SApril Chin n = off-lp->lexd.kiaoff;
168da2e3ebdSchin }
1697c2fbfb3SApril Chin savptr = stkfreeze(stkp,0);
1707c2fbfb3SApril Chin r=kiaentity(lp,begin,n,'v',-1,-1,lp->current,'v',0,"");
1717c2fbfb3SApril Chin stkset(stkp,savptr,offset);
172da2e3ebdSchin }
1737c2fbfb3SApril Chin sfprintf(lp->kiatmp,"p;%..64d;v;%..64d;%d;%d;r;\n",lp->current,r,shp->inlineno,shp->inlineno);
174da2e3ebdSchin }
175da2e3ebdSchin #endif /* SHOPT_KIA */
176da2e3ebdSchin
177da2e3ebdSchin /*
178da2e3ebdSchin * This routine gets called when reading across a buffer boundary
179da2e3ebdSchin * If lexd.nocopy is off, then current token is saved on the stack
180da2e3ebdSchin */
lex_advance(Sfio_t * iop,const char * buff,register int size,void * context)1817c2fbfb3SApril Chin static void lex_advance(Sfio_t *iop, const char *buff, register int size, void *context)
182da2e3ebdSchin {
1837c2fbfb3SApril Chin register Lex_t *lp = (Lex_t*)context;
1847c2fbfb3SApril Chin register Shell_t *shp = lp->sh;
185da2e3ebdSchin register Sfio_t *log= shp->funlog;
1867c2fbfb3SApril Chin Stk_t *stkp = shp->stk;
187da2e3ebdSchin #if KSHELL
188da2e3ebdSchin /* write to history file and to stderr if necessary */
189da2e3ebdSchin if(iop && !sfstacked(iop))
190da2e3ebdSchin {
191da2e3ebdSchin if(sh_isstate(SH_HISTORY) && shp->hist_ptr)
192da2e3ebdSchin log = shp->hist_ptr->histfp;
193da2e3ebdSchin sfwrite(log, (void*)buff, size);
194da2e3ebdSchin if(sh_isstate(SH_VERBOSE))
195da2e3ebdSchin sfwrite(sfstderr, buff, size);
196da2e3ebdSchin }
197da2e3ebdSchin #endif
1987c2fbfb3SApril Chin if(lp->lexd.nocopy)
199da2e3ebdSchin return;
20034f9b3eeSRoland Mainz if(lp->lexd.dolparen && lp->lexd.docword)
20134f9b3eeSRoland Mainz {
20234f9b3eeSRoland Mainz int n = size - (lp->lexd.docend-(char*)buff);
20334f9b3eeSRoland Mainz sfwrite(shp->strbuf,lp->lexd.docend,n);
20434f9b3eeSRoland Mainz lp->lexd.docextra += n;
20534f9b3eeSRoland Mainz }
2067c2fbfb3SApril Chin if(lp->lexd.first)
207da2e3ebdSchin {
2087c2fbfb3SApril Chin size -= (lp->lexd.first-(char*)buff);
2097c2fbfb3SApril Chin buff = lp->lexd.first;
2107c2fbfb3SApril Chin if(!lp->lexd.noarg)
2117c2fbfb3SApril Chin lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
212da2e3ebdSchin #if SHOPT_KIA
2137c2fbfb3SApril Chin lp->lexd.kiaoff += ARGVAL;
214da2e3ebdSchin #endif /* SHOPT_KIA */
215da2e3ebdSchin }
2167c2fbfb3SApril Chin if(size>0 && (lp->arg||lp->lexd.noarg))
217da2e3ebdSchin {
2187c2fbfb3SApril Chin sfwrite(stkp,buff,size);
2197c2fbfb3SApril Chin lp->lexd.first = 0;
220da2e3ebdSchin }
221da2e3ebdSchin }
222da2e3ebdSchin
223da2e3ebdSchin /*
224da2e3ebdSchin * fill up another input buffer
225da2e3ebdSchin * preserves lexical state
226da2e3ebdSchin */
lexfill(Lex_t * lp)2277c2fbfb3SApril Chin static int lexfill(Lex_t *lp)
228da2e3ebdSchin {
229da2e3ebdSchin register int c;
2307c2fbfb3SApril Chin Lex_t savelex;
231da2e3ebdSchin struct argnod *ap;
23234f9b3eeSRoland Mainz int aok,docextra;
2337c2fbfb3SApril Chin savelex = *lp;
2347c2fbfb3SApril Chin ap = lp->arg;
235da2e3ebdSchin c = fcfill();
236da2e3ebdSchin if(ap)
2377c2fbfb3SApril Chin lp->arg = ap;
23834f9b3eeSRoland Mainz docextra = lp->lexd.docextra;
2397c2fbfb3SApril Chin lp->lex = savelex.lex;
2407c2fbfb3SApril Chin lp->lexd = savelex.lexd;
2417c2fbfb3SApril Chin if(fcfile() || c)
2427c2fbfb3SApril Chin lp->lexd.first = 0;
2437c2fbfb3SApril Chin aok= lp->aliasok;
2447c2fbfb3SApril Chin ap = lp->arg;
2457c2fbfb3SApril Chin memcpy(lp, &savelex, offsetof(Lex_t,lexd));
2467c2fbfb3SApril Chin lp->arg = ap;
2477c2fbfb3SApril Chin lp->aliasok = aok;
24834f9b3eeSRoland Mainz if(lp->lexd.docword && docextra)
24934f9b3eeSRoland Mainz {
25034f9b3eeSRoland Mainz lp->lexd.docextra = docextra;
25134f9b3eeSRoland Mainz lp->lexd.docend = fcseek(0)-1;
25234f9b3eeSRoland Mainz }
253da2e3ebdSchin return(c);
254da2e3ebdSchin }
255da2e3ebdSchin
256da2e3ebdSchin /*
257da2e3ebdSchin * mode=1 for reinitialization
258da2e3ebdSchin */
sh_lexopen(Lex_t * lp,Shell_t * sp,int mode)259da2e3ebdSchin Lex_t *sh_lexopen(Lex_t *lp, Shell_t *sp, int mode)
260da2e3ebdSchin {
261da2e3ebdSchin if(!lp)
262da2e3ebdSchin {
263da2e3ebdSchin lp = (Lex_t*)newof(0,Lex_t,1,0);
2647c2fbfb3SApril Chin lp->sh = sp;
265da2e3ebdSchin }
2667c2fbfb3SApril Chin fcnotify(lex_advance,lp);
2677c2fbfb3SApril Chin lp->lex.intest = lp->lex.incase = lp->lex.skipword = lp->lexd.warn = 0;
2687c2fbfb3SApril Chin lp->comp_assign = 0;
2697c2fbfb3SApril Chin lp->lex.reservok = 1;
270da2e3ebdSchin if(!sh_isoption(SH_DICTIONARY) && sh_isoption(SH_NOEXEC))
2717c2fbfb3SApril Chin lp->lexd.warn=1;
272da2e3ebdSchin if(!mode)
273da2e3ebdSchin {
2747c2fbfb3SApril Chin lp->lexd.noarg = lp->lexd.level= lp->lexd.dolparen = lp->lexd.balance = 0;
2757c2fbfb3SApril Chin lp->lexd.nocopy = lp->lexd.docword = lp->lexd.nest = lp->lexd.paren = 0;
2763e14f97fSRoger A. Faulkner lp->lexd.lex_state = lp->lexd.lastc=0;
277da2e3ebdSchin }
2787c2fbfb3SApril Chin lp->comsub = 0;
279da2e3ebdSchin return(lp);
280da2e3ebdSchin }
281da2e3ebdSchin
282da2e3ebdSchin #ifdef DBUG
2837c2fbfb3SApril Chin extern int lextoken(Lex_t*);
sh_lex(Lex_t * lp)2847c2fbfb3SApril Chin int sh_lex(Lex_t *lp)
285da2e3ebdSchin {
2867c2fbfb3SApril Chin Shell_t *shp = lp->sh;
287da2e3ebdSchin register int flag;
288da2e3ebdSchin char *quoted, *macro, *split, *expand;
289da2e3ebdSchin char tokstr[3];
290da2e3ebdSchin register int tok = lextoken();
291da2e3ebdSchin quoted = macro = split = expand = "";
2927c2fbfb3SApril Chin if(tok==0 && (flag=lp->arg->argflag))
293da2e3ebdSchin {
294da2e3ebdSchin if(flag&ARG_MAC)
295da2e3ebdSchin macro = "macro:";
296da2e3ebdSchin if(flag&ARG_EXP)
297da2e3ebdSchin expand = "expand:";
298da2e3ebdSchin if(flag&ARG_QUOTED)
299da2e3ebdSchin quoted = "quoted:";
300da2e3ebdSchin }
301da2e3ebdSchin sfprintf(sfstderr,"line %d: %o:%s%s%s%s %s\n",shp->inlineno,tok,quoted,
302da2e3ebdSchin macro, split, expand, fmttoken(lp,tok,tokstr));
303da2e3ebdSchin return(tok);
304da2e3ebdSchin }
305da2e3ebdSchin #define sh_lex lextoken
306da2e3ebdSchin #endif
307da2e3ebdSchin
308da2e3ebdSchin /*
309da2e3ebdSchin * Get the next word and put it on the top of the stak
3107c2fbfb3SApril Chin * A pointer to the current word is stored in lp->arg
311da2e3ebdSchin * Returns the token type
312da2e3ebdSchin */
sh_lex(Lex_t * lp)3137c2fbfb3SApril Chin int sh_lex(Lex_t* lp)
314da2e3ebdSchin {
3157c2fbfb3SApril Chin register Shell_t *shp = lp->sh;
316da2e3ebdSchin register const char *state;
317da2e3ebdSchin register int n, c, mode=ST_BEGIN, wordflags=0;
3187c2fbfb3SApril Chin Stk_t *stkp = shp->stk;
3197c2fbfb3SApril Chin int inlevel=lp->lexd.level, assignment=0, ingrave=0;
320da2e3ebdSchin Sfio_t *sp;
321da2e3ebdSchin #if SHOPT_MULTIBYTE
322da2e3ebdSchin LEN=1;
323da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
3247c2fbfb3SApril Chin if(lp->lexd.paren)
325da2e3ebdSchin {
3267c2fbfb3SApril Chin lp->lexd.paren = 0;
3277c2fbfb3SApril Chin return(lp->token=LPAREN);
328da2e3ebdSchin }
3297c2fbfb3SApril Chin if(lp->lex.incase)
3307c2fbfb3SApril Chin lp->assignok = 0;
331da2e3ebdSchin else
3327c2fbfb3SApril Chin lp->assignok |= lp->lex.reservok;
3337c2fbfb3SApril Chin if(lp->comp_assign==2)
3347c2fbfb3SApril Chin lp->comp_assign = lp->lex.reservok = 0;
3357c2fbfb3SApril Chin lp->lexd.arith = (lp->lexd.nest==1);
3367c2fbfb3SApril Chin if(lp->lexd.nest)
337da2e3ebdSchin {
3387c2fbfb3SApril Chin pushlevel(lp,lp->lexd.nest,ST_NONE);
3397c2fbfb3SApril Chin lp->lexd.nest = 0;
3407c2fbfb3SApril Chin mode = lp->lexd.lex_state;
341da2e3ebdSchin }
3427c2fbfb3SApril Chin else if(lp->lexd.docword)
343da2e3ebdSchin {
344da2e3ebdSchin if(fcgetc(c)=='-' || c=='#')
345da2e3ebdSchin {
3467c2fbfb3SApril Chin lp->lexd.docword++;
3477c2fbfb3SApril Chin lp->digits=(c=='#'?3:1);
348da2e3ebdSchin }
349da2e3ebdSchin else if(c=='<')
350da2e3ebdSchin {
3517c2fbfb3SApril Chin lp->digits=2;
3527c2fbfb3SApril Chin lp->lexd.docword=0;
353da2e3ebdSchin }
354da2e3ebdSchin else if(c>0)
355da2e3ebdSchin fcseek(-1);
356da2e3ebdSchin }
3577c2fbfb3SApril Chin if(!lp->lexd.dolparen)
358da2e3ebdSchin {
3597c2fbfb3SApril Chin lp->arg = 0;
360da2e3ebdSchin if(mode!=ST_BEGIN)
3617c2fbfb3SApril Chin lp->lexd.first = fcseek(0);
362da2e3ebdSchin else
3637c2fbfb3SApril Chin lp->lexd.first = 0;
364da2e3ebdSchin }
3657c2fbfb3SApril Chin lp->lastline = lp->sh->inlineno;
366da2e3ebdSchin while(1)
367da2e3ebdSchin {
368da2e3ebdSchin /* skip over characters in the current state */
369da2e3ebdSchin state = sh_lexstates[mode];
370da2e3ebdSchin while((n=STATE(state,c))==0);
371da2e3ebdSchin switch(n)
372da2e3ebdSchin {
373da2e3ebdSchin case S_BREAK:
374da2e3ebdSchin fcseek(-1);
375da2e3ebdSchin goto breakloop;
376da2e3ebdSchin case S_EOF:
377da2e3ebdSchin sp = fcfile();
3787c2fbfb3SApril Chin if((n=lexfill(lp)) > 0)
379da2e3ebdSchin {
380da2e3ebdSchin fcseek(-1);
381da2e3ebdSchin continue;
382da2e3ebdSchin }
383da2e3ebdSchin /* check for zero byte in file */
384da2e3ebdSchin if(n==0 && fcfile())
385da2e3ebdSchin {
386da2e3ebdSchin if(shp->readscript)
387da2e3ebdSchin {
388da2e3ebdSchin char *cp = error_info.id;
389da2e3ebdSchin errno = ENOEXEC;
390da2e3ebdSchin error_info.id = shp->readscript;
391da2e3ebdSchin errormsg(SH_DICT,ERROR_system(ERROR_NOEXEC),e_exec,cp);
392da2e3ebdSchin }
393da2e3ebdSchin else
394da2e3ebdSchin {
3957c2fbfb3SApril Chin lp->token = -1;
3967c2fbfb3SApril Chin sh_syntax(lp);
397da2e3ebdSchin }
398da2e3ebdSchin }
399da2e3ebdSchin /* end-of-file */
400da2e3ebdSchin if(mode==ST_BEGIN)
4017c2fbfb3SApril Chin return(lp->token=EOFSYM);
4027c2fbfb3SApril Chin if(mode >ST_NORM && lp->lexd.level>0)
403da2e3ebdSchin {
4047c2fbfb3SApril Chin switch(c=endchar(lp))
405da2e3ebdSchin {
406da2e3ebdSchin case '$':
407da2e3ebdSchin if(mode==ST_LIT)
408da2e3ebdSchin {
409da2e3ebdSchin c = '\'';
410da2e3ebdSchin break;
411da2e3ebdSchin }
4127c2fbfb3SApril Chin mode = oldmode(lp);
4137c2fbfb3SApril Chin poplevel(lp);
414da2e3ebdSchin continue;
415da2e3ebdSchin case RBRACT:
416da2e3ebdSchin c = LBRACT;
417da2e3ebdSchin break;
418da2e3ebdSchin case 1: /* for ((...)) */
419da2e3ebdSchin case RPAREN:
420da2e3ebdSchin c = LPAREN;
421da2e3ebdSchin break;
422da2e3ebdSchin default:
423da2e3ebdSchin c = LBRACE;
424da2e3ebdSchin break;
425da2e3ebdSchin case '"': case '`': case '\'':
4267c2fbfb3SApril Chin lp->lexd.balance = c;
427da2e3ebdSchin break;
428da2e3ebdSchin }
429da2e3ebdSchin if(sp && !(sfset(sp,0,0)&SF_STRING))
430da2e3ebdSchin {
4317c2fbfb3SApril Chin lp->lasttok = c;
4327c2fbfb3SApril Chin lp->token = EOFSYM;
4337c2fbfb3SApril Chin sh_syntax(lp);
434da2e3ebdSchin }
4357c2fbfb3SApril Chin lp->lexd.balance = c;
436da2e3ebdSchin }
437da2e3ebdSchin goto breakloop;
438da2e3ebdSchin case S_COM:
439da2e3ebdSchin /* skip one or more comment line(s) */
4407c2fbfb3SApril Chin lp->lex.reservok = !lp->lex.intest;
4417c2fbfb3SApril Chin if((n=lp->lexd.nocopy) && lp->lexd.dolparen)
4427c2fbfb3SApril Chin lp->lexd.nocopy--;
443da2e3ebdSchin do
444da2e3ebdSchin {
445da2e3ebdSchin while(fcgetc(c)>0 && c!='\n');
4467c2fbfb3SApril Chin if(c<=0 || lp->heredoc)
447da2e3ebdSchin break;
448da2e3ebdSchin while(shp->inlineno++,fcpeek(0)=='\n')
449da2e3ebdSchin fcseek(1);
450da2e3ebdSchin while(state[c=fcpeek(0)]==0)
451da2e3ebdSchin fcseek(1);
452da2e3ebdSchin }
453da2e3ebdSchin while(c=='#');
4547c2fbfb3SApril Chin lp->lexd.nocopy = n;
455da2e3ebdSchin if(c<0)
4567c2fbfb3SApril Chin return(lp->token=EOFSYM);
457da2e3ebdSchin n = S_NLTOK;
458da2e3ebdSchin shp->inlineno--;
459da2e3ebdSchin /* FALL THRU */
460da2e3ebdSchin case S_NLTOK:
461da2e3ebdSchin /* check for here-document */
4627c2fbfb3SApril Chin if(lp->heredoc)
463da2e3ebdSchin {
4647c2fbfb3SApril Chin if(!lp->lexd.dolparen)
4657c2fbfb3SApril Chin lp->lexd.nocopy++;
466da2e3ebdSchin c = shp->inlineno;
4677c2fbfb3SApril Chin if(here_copy(lp,lp->heredoc)<=0 && lp->lasttok)
468da2e3ebdSchin {
4697c2fbfb3SApril Chin lp->lasttok = IODOCSYM;
4707c2fbfb3SApril Chin lp->token = EOFSYM;
4717c2fbfb3SApril Chin lp->lastline = c;
4727c2fbfb3SApril Chin sh_syntax(lp);
473da2e3ebdSchin }
4747c2fbfb3SApril Chin if(!lp->lexd.dolparen)
4757c2fbfb3SApril Chin lp->lexd.nocopy--;
4767c2fbfb3SApril Chin lp->heredoc = 0;
477da2e3ebdSchin }
4787c2fbfb3SApril Chin lp->lex.reservok = !lp->lex.intest;
4797c2fbfb3SApril Chin lp->lex.skipword = 0;
480*3ce7283dSToomas Soome /* FALL THRU */
481da2e3ebdSchin case S_NL:
482da2e3ebdSchin /* skip over new-lines */
4837c2fbfb3SApril Chin lp->lex.last_quote = 0;
484da2e3ebdSchin while(shp->inlineno++,fcget()=='\n');
485da2e3ebdSchin fcseek(-1);
486da2e3ebdSchin if(n==S_NLTOK)
487da2e3ebdSchin {
4887c2fbfb3SApril Chin lp->comp_assign = 0;
4897c2fbfb3SApril Chin return(lp->token='\n');
490da2e3ebdSchin }
491*3ce7283dSToomas Soome case S_BLNK:
492da2e3ebdSchin if(lp->lex.incase<=TEST_RE)
4937c2fbfb3SApril Chin continue;
494da2e3ebdSchin /* implicit RPAREN for =~ test operator */
495da2e3ebdSchin if(inlevel+1==lp->lexd.level)
4967c2fbfb3SApril Chin {
497da2e3ebdSchin if(lp->lex.intest)
4987c2fbfb3SApril Chin fcseek(-1);
499da2e3ebdSchin c = RPAREN;
500da2e3ebdSchin goto do_pop;
501da2e3ebdSchin }
502da2e3ebdSchin continue;
503da2e3ebdSchin case S_OP:
504da2e3ebdSchin /* return operator token */
505da2e3ebdSchin if(c=='<' || c=='>')
506da2e3ebdSchin {
507da2e3ebdSchin if(lp->lex.testop2)
5087c2fbfb3SApril Chin lp->lex.testop2 = 0;
5097c2fbfb3SApril Chin else
510da2e3ebdSchin {
511da2e3ebdSchin lp->digits = (c=='>');
5127c2fbfb3SApril Chin lp->lex.skipword = 1;
5137c2fbfb3SApril Chin lp->aliasok = lp->lex.reservok;
5147c2fbfb3SApril Chin lp->lex.reservok = 0;
5157c2fbfb3SApril Chin }
516da2e3ebdSchin }
517da2e3ebdSchin else
518da2e3ebdSchin {
519da2e3ebdSchin lp->lex.reservok = !lp->lex.intest;
5207c2fbfb3SApril Chin if(c==RPAREN)
521da2e3ebdSchin {
522da2e3ebdSchin if(!lp->lexd.dolparen)
5237c2fbfb3SApril Chin lp->lex.incase = 0;
5247c2fbfb3SApril Chin return(lp->token=c);
5257c2fbfb3SApril Chin }
526da2e3ebdSchin lp->lex.testop1 = lp->lex.intest;
5277c2fbfb3SApril Chin }
528da2e3ebdSchin if(fcgetc(n)>0)
529da2e3ebdSchin fcseek(-1);
530da2e3ebdSchin if(state[n]==S_OP || n=='#')
531da2e3ebdSchin {
532da2e3ebdSchin if(n==c)
533da2e3ebdSchin {
534da2e3ebdSchin if(c=='<')
535da2e3ebdSchin lp->lexd.docword=1;
5367c2fbfb3SApril Chin else if(n==LPAREN)
537da2e3ebdSchin {
538da2e3ebdSchin lp->lexd.nest=1;
5397c2fbfb3SApril Chin lp->lastline = shp->inlineno;
5407c2fbfb3SApril Chin lp->lexd.lex_state = ST_NESTED;
5417c2fbfb3SApril Chin fcseek(1);
542da2e3ebdSchin return(sh_lex(lp));
5437c2fbfb3SApril Chin }
544da2e3ebdSchin c |= SYMREP;
545da2e3ebdSchin }
546da2e3ebdSchin else if(c=='(' || c==')')
547da2e3ebdSchin return(lp->token=c);
5487c2fbfb3SApril Chin else if(c=='&')
549da2e3ebdSchin {
550da2e3ebdSchin if(!sh_isoption(SH_POSIX) && n=='>' && (sh_isoption(SH_BASH) || sh_isstate(SH_PROFILE)))
55134f9b3eeSRoland Mainz {
552da2e3ebdSchin if(!sh_isoption(SH_BASH) && !lp->nonstandard)
55334f9b3eeSRoland Mainz {
55434f9b3eeSRoland Mainz lp->nonstandard = 1;
55534f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_warn(0),e_lexnonstandard,shp->inlineno);
55634f9b3eeSRoland Mainz }
55734f9b3eeSRoland Mainz lp->digits = -1;
5587c2fbfb3SApril Chin c = '>';
559da2e3ebdSchin }
560da2e3ebdSchin else
561da2e3ebdSchin n = 0;
562da2e3ebdSchin }
563da2e3ebdSchin else if(n=='&')
564da2e3ebdSchin c |= SYMAMP;
565da2e3ebdSchin else if(c!='<' && c!='>')
566da2e3ebdSchin n = 0;
567da2e3ebdSchin else if(n==LPAREN)
568da2e3ebdSchin {
569da2e3ebdSchin c |= SYMLPAR;
570da2e3ebdSchin lp->lex.reservok = 1;
5717c2fbfb3SApril Chin lp->lex.skipword = 0;
5727c2fbfb3SApril Chin }
573da2e3ebdSchin else if(n=='|')
574da2e3ebdSchin c |= SYMPIPE;
575da2e3ebdSchin else if(c=='<' && n=='>')
576da2e3ebdSchin {
57734f9b3eeSRoland Mainz lp->digits = 1;
57834f9b3eeSRoland Mainz c = IORDWRSYM;
579da2e3ebdSchin fcgetc(n);
58034f9b3eeSRoland Mainz if(fcgetc(n)==';')
58134f9b3eeSRoland Mainz {
58234f9b3eeSRoland Mainz lp->token = c = IORDWRSYMT;
58334f9b3eeSRoland Mainz if(lp->inexec)
58434f9b3eeSRoland Mainz sh_syntax(lp);
58534f9b3eeSRoland Mainz }
58634f9b3eeSRoland Mainz else if(n>0)
58734f9b3eeSRoland Mainz fcseek(-1);
58834f9b3eeSRoland Mainz n= 0;
58934f9b3eeSRoland Mainz }
59034f9b3eeSRoland Mainz else if(n=='#' && (c=='<'||c=='>'))
591da2e3ebdSchin c |= SYMSHARP;
592da2e3ebdSchin else if(n==';' && c=='>')
5937c2fbfb3SApril Chin {
5947c2fbfb3SApril Chin c |= SYMSEMI;
5957c2fbfb3SApril Chin if(lp->inexec)
5967c2fbfb3SApril Chin {
5977c2fbfb3SApril Chin lp->token = c;
5987c2fbfb3SApril Chin sh_syntax(lp);
5997c2fbfb3SApril Chin }
6007c2fbfb3SApril Chin }
6017c2fbfb3SApril Chin else
602da2e3ebdSchin n = 0;
603da2e3ebdSchin if(n)
604da2e3ebdSchin {
605da2e3ebdSchin fcseek(1);
606da2e3ebdSchin lp->lex.incase = (c==BREAKCASESYM || c==FALLTHRUSYM);
6077c2fbfb3SApril Chin }
608da2e3ebdSchin else
609da2e3ebdSchin {
610da2e3ebdSchin if(lp->lexd.warn && (n=fcpeek(0))!=RPAREN && n!=' ' && n!='\t')
61134f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_warn(0),e_lexspace,shp->inlineno,c,n);
612da2e3ebdSchin }
613da2e3ebdSchin }
614da2e3ebdSchin if(c==LPAREN && lp->comp_assign && !lp->lex.intest && !lp->lex.incase)
6157c2fbfb3SApril Chin lp->comp_assign = 2;
6167c2fbfb3SApril Chin else
617da2e3ebdSchin lp->comp_assign = 0;
6187c2fbfb3SApril Chin return(lp->token=c);
6197c2fbfb3SApril Chin case S_ESC:
620da2e3ebdSchin /* check for \<new-line> */
621da2e3ebdSchin fcgetc(n);
622da2e3ebdSchin c=2;
623da2e3ebdSchin #if SHOPT_CRNL
624da2e3ebdSchin if(n=='\r')
625da2e3ebdSchin {
626da2e3ebdSchin if(fcgetc(n)=='\n')
627da2e3ebdSchin c=3;
628da2e3ebdSchin else
629da2e3ebdSchin {
630da2e3ebdSchin n='\r';
631da2e3ebdSchin fcseek(-1);
632da2e3ebdSchin }
633da2e3ebdSchin }
634da2e3ebdSchin #endif /* SHOPT_CRNL */
635da2e3ebdSchin if(n=='\n')
636da2e3ebdSchin {
637da2e3ebdSchin Sfio_t *sp;
638da2e3ebdSchin struct argnod *ap;
639da2e3ebdSchin shp->inlineno++;
640da2e3ebdSchin /* synchronize */
641da2e3ebdSchin if(!(sp=fcfile()))
642da2e3ebdSchin state=fcseek(0);
643da2e3ebdSchin fcclose();
644da2e3ebdSchin ap = lp->arg;
6457c2fbfb3SApril Chin if(sp)
646da2e3ebdSchin fcfopen(sp);
647da2e3ebdSchin else
648da2e3ebdSchin fcsopen((char*)state);
649da2e3ebdSchin /* remove \new-line */
650da2e3ebdSchin n = stktell(stkp)-c;
6517c2fbfb3SApril Chin stkseek(stkp,n);
6527c2fbfb3SApril Chin lp->arg = ap;
6537c2fbfb3SApril Chin if(n<=ARGVAL)
654da2e3ebdSchin {
655da2e3ebdSchin mode = 0;
656da2e3ebdSchin lp->lexd.first = 0;
6577c2fbfb3SApril Chin }
658da2e3ebdSchin continue;
659da2e3ebdSchin }
660da2e3ebdSchin wordflags |= ARG_QUOTED;
661da2e3ebdSchin if(mode==ST_DOL)
662da2e3ebdSchin goto err;
663da2e3ebdSchin #ifndef STR_MAXIMAL
664da2e3ebdSchin else if(mode==ST_NESTED && lp->lexd.warn &&
6657c2fbfb3SApril Chin endchar(lp)==RBRACE &&
6667c2fbfb3SApril Chin sh_lexstates[ST_DOL][n]==S_DIG
667da2e3ebdSchin )
668da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexfuture,shp->inlineno,n);
669da2e3ebdSchin #endif /* STR_MAXIMAL */
670da2e3ebdSchin break;
671da2e3ebdSchin case S_NAME:
672da2e3ebdSchin if(!lp->lex.skipword)
6737c2fbfb3SApril Chin lp->lex.reservok *= 2;
6747c2fbfb3SApril Chin /* FALL THRU */
675da2e3ebdSchin case S_TILDE:
676da2e3ebdSchin case S_RES:
677da2e3ebdSchin if(!lp->lexd.dolparen)
6787c2fbfb3SApril Chin lp->lexd.first = fcseek(0)-LEN;
6797c2fbfb3SApril Chin else if(lp->lexd.docword)
6807c2fbfb3SApril Chin lp->lexd.docend = fcseek(0)-LEN;
6817c2fbfb3SApril Chin mode = ST_NAME;
682da2e3ebdSchin if(c=='.')
683da2e3ebdSchin fcseek(-1);
684da2e3ebdSchin if(n!=S_TILDE)
685da2e3ebdSchin continue;
686da2e3ebdSchin fcgetc(n);
687da2e3ebdSchin if(n>0)
688da2e3ebdSchin {
6897c2fbfb3SApril Chin if(c=='~' && n==LPAREN && lp->lex.incase)
6907c2fbfb3SApril Chin lp->lex.incase = TEST_RE;
6917c2fbfb3SApril Chin fcseek(-1);
692da2e3ebdSchin }
6937c2fbfb3SApril Chin if(n==LPAREN)
694da2e3ebdSchin goto epat;
695da2e3ebdSchin wordflags = ARG_MAC;
696da2e3ebdSchin mode = ST_NORM;
697da2e3ebdSchin continue;
698da2e3ebdSchin case S_REG:
699da2e3ebdSchin if(mode==ST_BEGIN)
700da2e3ebdSchin {
701da2e3ebdSchin do_reg:
7027c2fbfb3SApril Chin /* skip new-line joining */
703da2e3ebdSchin if(c=='\\' && fcpeek(0)=='\n')
704da2e3ebdSchin {
705da2e3ebdSchin shp->inlineno++;
706da2e3ebdSchin fcseek(1);
707da2e3ebdSchin continue;
708da2e3ebdSchin }
709da2e3ebdSchin fcseek(-1);
710da2e3ebdSchin if(!lp->lexd.dolparen)
7117c2fbfb3SApril Chin lp->lexd.first = fcseek(0);
7127c2fbfb3SApril Chin else if(lp->lexd.docword)
7137c2fbfb3SApril Chin lp->lexd.docend = fcseek(0);
7147c2fbfb3SApril Chin if(c=='[' && lp->assignok>=SH_ASSIGN)
7157c2fbfb3SApril Chin {
716da2e3ebdSchin mode = ST_NAME;
717da2e3ebdSchin continue;
718da2e3ebdSchin }
719da2e3ebdSchin }
720da2e3ebdSchin mode = ST_NORM;
721da2e3ebdSchin continue;
722da2e3ebdSchin case S_LIT:
723da2e3ebdSchin if(oldmode(lp)==ST_NONE && !lp->lexd.noarg) /* in ((...)) */
7247c2fbfb3SApril Chin {
725da2e3ebdSchin if((c=fcpeek(0))==LPAREN || c==RPAREN || c=='$' || c==LBRACE || c==RBRACE || c=='[' || c==']')
726da2e3ebdSchin {
727da2e3ebdSchin if(fcpeek(1)=='\'')
728da2e3ebdSchin fcseek(2);
729da2e3ebdSchin }
730da2e3ebdSchin continue;
731da2e3ebdSchin }
732da2e3ebdSchin wordflags |= ARG_QUOTED;
733da2e3ebdSchin if(mode==ST_DOL)
734da2e3ebdSchin {
735da2e3ebdSchin if(endchar(lp)!='$')
7367c2fbfb3SApril Chin goto err;
737da2e3ebdSchin if(oldmode(lp)==ST_QUOTE) /* $' within "" or `` */
7387c2fbfb3SApril Chin {
739da2e3ebdSchin if(lp->lexd.warn)
7407c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
741da2e3ebdSchin mode = ST_LIT;
742da2e3ebdSchin }
743da2e3ebdSchin }
744da2e3ebdSchin if(mode!=ST_LIT)
745da2e3ebdSchin {
746da2e3ebdSchin if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7477c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7487c2fbfb3SApril Chin lp->lex.last_quote = 0;
7497c2fbfb3SApril Chin lp->lastline = shp->inlineno;
7507c2fbfb3SApril Chin if(mode!=ST_DOL)
751da2e3ebdSchin pushlevel(lp,'\'',mode);
7527c2fbfb3SApril Chin mode = ST_LIT;
753da2e3ebdSchin continue;
754da2e3ebdSchin }
755da2e3ebdSchin /* check for multi-line single-quoted string */
756da2e3ebdSchin else if(shp->inlineno > lp->lastline)
7577c2fbfb3SApril Chin lp->lex.last_quote = '\'';
7587c2fbfb3SApril Chin mode = oldmode(lp);
7597c2fbfb3SApril Chin poplevel(lp);
7607c2fbfb3SApril Chin break;
761da2e3ebdSchin case S_ESC2:
762da2e3ebdSchin /* \ inside '' */
763da2e3ebdSchin if(endchar(lp)=='$')
7647c2fbfb3SApril Chin {
765da2e3ebdSchin fcgetc(n);
766da2e3ebdSchin if(n=='\n')
767da2e3ebdSchin shp->inlineno++;
768da2e3ebdSchin }
769da2e3ebdSchin continue;
770da2e3ebdSchin case S_GRAVE:
771da2e3ebdSchin if(lp->lexd.warn && (mode!=ST_QUOTE || endchar(lp)!='`'))
7727c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete1,shp->inlineno);
773da2e3ebdSchin wordflags |=(ARG_MAC|ARG_EXP);
774da2e3ebdSchin if(mode==ST_QUOTE)
775da2e3ebdSchin ingrave = !ingrave;
776da2e3ebdSchin /* FALL THRU */
777da2e3ebdSchin case S_QUOTE:
778da2e3ebdSchin if(oldmode(lp)==ST_NONE && lp->lexd.arith) /* in ((...)) */
7797c2fbfb3SApril Chin {
7807c2fbfb3SApril Chin if(n!=S_GRAVE || fcpeek(0)=='\'')
7817c2fbfb3SApril Chin continue;
782da2e3ebdSchin }
7837c2fbfb3SApril Chin if(n==S_QUOTE)
784da2e3ebdSchin wordflags |=ARG_QUOTED;
785da2e3ebdSchin if(mode!=ST_QUOTE)
786da2e3ebdSchin {
787da2e3ebdSchin if(c!='"' || mode!=ST_QNEST)
788da2e3ebdSchin {
789da2e3ebdSchin if(lp->lexd.warn && lp->lex.last_quote && shp->inlineno > lp->lastline)
7907c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexlongquote,lp->lastline,lp->lex.last_quote);
7917c2fbfb3SApril Chin lp->lex.last_quote=0;
7927c2fbfb3SApril Chin lp->lastline = shp->inlineno;
7937c2fbfb3SApril Chin pushlevel(lp,c,mode);
7947c2fbfb3SApril Chin }
795da2e3ebdSchin ingrave ^= (c=='`');
79634f9b3eeSRoland Mainz mode = ST_QUOTE;
797da2e3ebdSchin continue;
798da2e3ebdSchin }
799da2e3ebdSchin else if((n=endchar(lp))==c)
8007c2fbfb3SApril Chin {
801da2e3ebdSchin if(shp->inlineno > lp->lastline)
8027c2fbfb3SApril Chin lp->lex.last_quote = c;
8037c2fbfb3SApril Chin mode = oldmode(lp);
8047c2fbfb3SApril Chin poplevel(lp);
8057c2fbfb3SApril Chin }
806da2e3ebdSchin else if(c=='"' && n==RBRACE)
807da2e3ebdSchin mode = ST_QNEST;
808da2e3ebdSchin break;
809da2e3ebdSchin case S_DOL:
810da2e3ebdSchin /* don't check syntax inside `` */
811da2e3ebdSchin if(mode==ST_QUOTE && ingrave)
812da2e3ebdSchin continue;
813da2e3ebdSchin #if SHOPT_KIA
814da2e3ebdSchin if(lp->lexd.first)
8157c2fbfb3SApril Chin lp->lexd.kiaoff = fcseek(0)-lp->lexd.first;
8167c2fbfb3SApril Chin else
817da2e3ebdSchin lp->lexd.kiaoff = stktell(stkp)+fcseek(0)-fcfirst();
8187c2fbfb3SApril Chin #endif /* SHOPT_KIA */
819da2e3ebdSchin pushlevel(lp,'$',mode);
8207c2fbfb3SApril Chin mode = ST_DOL;
821da2e3ebdSchin continue;
822da2e3ebdSchin case S_PAR:
823da2e3ebdSchin do_comsub:
8247c2fbfb3SApril Chin wordflags |= ARG_MAC;
825da2e3ebdSchin mode = oldmode(lp);
8267c2fbfb3SApril Chin poplevel(lp);
8277c2fbfb3SApril Chin fcseek(-1);
828da2e3ebdSchin wordflags |= comsub(lp,c);
8297c2fbfb3SApril Chin continue;
830da2e3ebdSchin case S_RBRA:
831da2e3ebdSchin if((n=endchar(lp)) == '$')
8327c2fbfb3SApril Chin goto err;
833da2e3ebdSchin if(mode!=ST_QUOTE || n==RBRACE)
834da2e3ebdSchin {
835da2e3ebdSchin mode = oldmode(lp);
8367c2fbfb3SApril Chin poplevel(lp);
8377c2fbfb3SApril Chin }
838da2e3ebdSchin break;
839da2e3ebdSchin case S_EDOL:
840da2e3ebdSchin /* end $identifier */
841da2e3ebdSchin #if SHOPT_KIA
842da2e3ebdSchin if(lp->kiafile)
8437c2fbfb3SApril Chin refvar(lp,0);
8447c2fbfb3SApril Chin #endif /* SHOPT_KIA */
845da2e3ebdSchin if(lp->lexd.warn && c==LBRACT && !lp->lex.intest && !lp->lexd.arith && oldmode(lp)!= ST_NESTED)
8467c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexusebrace,shp->inlineno);
847da2e3ebdSchin fcseek(-1);
848da2e3ebdSchin mode = oldmode(lp);
8497c2fbfb3SApril Chin poplevel(lp);
8507c2fbfb3SApril Chin break;
851da2e3ebdSchin case S_DOT:
852da2e3ebdSchin /* make sure next character is alpha */
853da2e3ebdSchin if(fcgetc(n)>0)
854da2e3ebdSchin {
8557c2fbfb3SApril Chin if(n=='.')
8567c2fbfb3SApril Chin fcgetc(n);
8577c2fbfb3SApril Chin if(n>0)
8587c2fbfb3SApril Chin fcseek(-1);
859da2e3ebdSchin }
8607c2fbfb3SApril Chin if(isaletter(n) || n==LBRACT)
861da2e3ebdSchin continue;
862da2e3ebdSchin if(mode==ST_NAME)
863da2e3ebdSchin {
864da2e3ebdSchin if(n=='=')
865da2e3ebdSchin continue;
866da2e3ebdSchin break;
867da2e3ebdSchin }
868da2e3ebdSchin else if(n==RBRACE)
869da2e3ebdSchin continue;
870da2e3ebdSchin if(isastchar(n))
871da2e3ebdSchin continue;
872da2e3ebdSchin goto err;
873da2e3ebdSchin case S_SPC1:
874da2e3ebdSchin wordflags |= ARG_MAC;
875da2e3ebdSchin if(endchar(lp)==RBRACE)
8767c2fbfb3SApril Chin {
877da2e3ebdSchin setchar(lp,c);
8787c2fbfb3SApril Chin continue;
879da2e3ebdSchin }
880da2e3ebdSchin /* FALL THRU */
881da2e3ebdSchin case S_ALP:
882da2e3ebdSchin if(c=='.' && endchar(lp)=='$')
8837c2fbfb3SApril Chin goto err;
884da2e3ebdSchin case S_SPC2:
885*3ce7283dSToomas Soome case S_DIG:
886da2e3ebdSchin wordflags |= ARG_MAC;
887da2e3ebdSchin switch(endchar(lp))
888da2e3ebdSchin {
8897c2fbfb3SApril Chin case '$':
890da2e3ebdSchin if(n==S_ALP) /* $identifier */
891da2e3ebdSchin mode = ST_DOLNAME;
892da2e3ebdSchin else
893da2e3ebdSchin {
894da2e3ebdSchin mode = oldmode(lp);
895da2e3ebdSchin poplevel(lp);
8967c2fbfb3SApril Chin }
8977c2fbfb3SApril Chin break;
898da2e3ebdSchin #if SHOPT_TYPEDEF
899da2e3ebdSchin case '@':
900*3ce7283dSToomas Soome #endif /* SHOPT_TYPEDEF */
901da2e3ebdSchin case '!':
902da2e3ebdSchin if(n!=S_ALP)
903da2e3ebdSchin goto dolerr;
904da2e3ebdSchin case '#':
905da2e3ebdSchin case RBRACE:
906da2e3ebdSchin if(n==S_ALP)
907*3ce7283dSToomas Soome {
908da2e3ebdSchin setchar(lp,RBRACE);
909da2e3ebdSchin if(c=='.')
910da2e3ebdSchin fcseek(-1);
911da2e3ebdSchin mode = ST_BRACE;
9127c2fbfb3SApril Chin }
913da2e3ebdSchin else
914da2e3ebdSchin {
915da2e3ebdSchin if(fcgetc(c)>0)
916da2e3ebdSchin fcseek(-1);
917da2e3ebdSchin if(state[c]==S_ALP)
918da2e3ebdSchin goto err;
919da2e3ebdSchin if(n==S_DIG)
920da2e3ebdSchin setchar(lp,'0');
921da2e3ebdSchin else
922da2e3ebdSchin setchar(lp,'!');
923da2e3ebdSchin }
9247c2fbfb3SApril Chin break;
925da2e3ebdSchin case '0':
9267c2fbfb3SApril Chin if(n==S_DIG)
927da2e3ebdSchin break;
928da2e3ebdSchin default:
929da2e3ebdSchin goto dolerr;
930da2e3ebdSchin }
931da2e3ebdSchin break;
932da2e3ebdSchin dolerr:
933da2e3ebdSchin case S_ERR:
934da2e3ebdSchin if((n=endchar(lp)) == '$')
935da2e3ebdSchin goto err;
936da2e3ebdSchin if(c=='*' || (n=sh_lexstates[ST_BRACE][c])!=S_MOD1 && n!=S_MOD2)
937da2e3ebdSchin {
9387c2fbfb3SApril Chin /* see whether inside `...` */
939da2e3ebdSchin mode = oldmode(lp);
940da2e3ebdSchin poplevel(lp);
941da2e3ebdSchin if((n = endchar(lp)) != '`')
942da2e3ebdSchin goto err;
9437c2fbfb3SApril Chin pushlevel(lp,RBRACE,mode);
9447c2fbfb3SApril Chin }
9457c2fbfb3SApril Chin else
946da2e3ebdSchin setchar(lp,RBRACE);
9477c2fbfb3SApril Chin mode = ST_NESTED;
948da2e3ebdSchin continue;
949da2e3ebdSchin case S_MOD1:
9507c2fbfb3SApril Chin if(oldmode(lp)==ST_QUOTE || oldmode(lp)==ST_NONE)
951da2e3ebdSchin {
952da2e3ebdSchin /* allow ' inside "${...}" */
953da2e3ebdSchin if(c==':' && fcgetc(n)>0)
9547c2fbfb3SApril Chin {
955da2e3ebdSchin n = state[n];
956da2e3ebdSchin fcseek(-1);
957da2e3ebdSchin }
958da2e3ebdSchin if(n==S_MOD1)
959da2e3ebdSchin {
960da2e3ebdSchin mode = ST_QUOTE;
961da2e3ebdSchin continue;
962da2e3ebdSchin }
963da2e3ebdSchin }
964da2e3ebdSchin /* FALL THRU */
965da2e3ebdSchin case S_MOD2:
966da2e3ebdSchin #if SHOPT_KIA
967da2e3ebdSchin if(lp->kiafile)
968da2e3ebdSchin refvar(lp,1);
969da2e3ebdSchin #endif /* SHOPT_KIA */
970da2e3ebdSchin if(c!=':' && fcgetc(n)>0)
9717c2fbfb3SApril Chin {
9727c2fbfb3SApril Chin if(n!=c)
973da2e3ebdSchin c = 0;
974da2e3ebdSchin if(!c || (fcgetc(n)>0))
975da2e3ebdSchin {
976da2e3ebdSchin fcseek(-1);
977da2e3ebdSchin if(n==LPAREN)
978da2e3ebdSchin {
979da2e3ebdSchin if(c!='%')
980da2e3ebdSchin {
981da2e3ebdSchin lp->token = n;
982da2e3ebdSchin sh_syntax(lp);
983da2e3ebdSchin }
984da2e3ebdSchin else if(lp->lexd.warn)
9857c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexquote,shp->inlineno,'%');
9867c2fbfb3SApril Chin }
987da2e3ebdSchin }
9887c2fbfb3SApril Chin }
989da2e3ebdSchin mode = ST_NESTED;
990da2e3ebdSchin continue;
991da2e3ebdSchin case S_LBRA:
992da2e3ebdSchin if((c=endchar(lp)) == '$')
993da2e3ebdSchin {
994da2e3ebdSchin if(fcgetc(c)>0)
995da2e3ebdSchin fcseek(-1);
9967c2fbfb3SApril Chin setchar(lp,RBRACE);
997da2e3ebdSchin if(state[c]!=S_ERR && c!=RBRACE)
998da2e3ebdSchin continue;
999da2e3ebdSchin if((n=sh_lexstates[ST_BEGIN][c])==0 || n==S_OP || n==S_NLTOK)
10007c2fbfb3SApril Chin {
1001da2e3ebdSchin c = LBRACE;
1002da2e3ebdSchin goto do_comsub;
10037c2fbfb3SApril Chin }
10047c2fbfb3SApril Chin }
10057c2fbfb3SApril Chin err:
10067c2fbfb3SApril Chin n = endchar(lp);
10077c2fbfb3SApril Chin mode = oldmode(lp);
1008da2e3ebdSchin poplevel(lp);
1009da2e3ebdSchin if(n!='$')
10107c2fbfb3SApril Chin {
10117c2fbfb3SApril Chin lp->token = c;
10127c2fbfb3SApril Chin sh_syntax(lp);
1013da2e3ebdSchin }
1014da2e3ebdSchin else
10157c2fbfb3SApril Chin {
10167c2fbfb3SApril Chin if(lp->lexd.warn && c!='/' && sh_lexstates[ST_NORM][c]!=S_BREAK && (c!='"' || mode==ST_QUOTE))
1017da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexslash,shp->inlineno);
1018da2e3ebdSchin else if(c=='"' && mode!=ST_QUOTE && !ingrave)
1019da2e3ebdSchin wordflags |= ARG_MESSAGE;
10207c2fbfb3SApril Chin fcseek(-1);
1021da2e3ebdSchin }
102234f9b3eeSRoland Mainz continue;
1023da2e3ebdSchin case S_META:
1024da2e3ebdSchin if(lp->lexd.warn && endchar(lp)==RBRACE)
1025da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1026da2e3ebdSchin continue;
1027da2e3ebdSchin case S_PUSH:
10287c2fbfb3SApril Chin pushlevel(lp,RPAREN,mode);
1029da2e3ebdSchin mode = ST_NESTED;
1030da2e3ebdSchin continue;
1031da2e3ebdSchin case S_POP:
10327c2fbfb3SApril Chin do_pop:
1033da2e3ebdSchin if(lp->lexd.level <= inlevel)
1034da2e3ebdSchin break;
1035da2e3ebdSchin if(lp->lexd.level==inlevel+1 && lp->lex.incase>=TEST_RE && !lp->lex.intest)
1036da2e3ebdSchin {
10377c2fbfb3SApril Chin fcseek(-1);
1038da2e3ebdSchin goto breakloop;
10397c2fbfb3SApril Chin }
10407c2fbfb3SApril Chin n = endchar(lp);
10417c2fbfb3SApril Chin if(c==RBRACT && !(n==RBRACT || n==RPAREN))
10427c2fbfb3SApril Chin continue;
10437c2fbfb3SApril Chin if((c==RBRACE||c==RPAREN) && n==RPAREN)
10447c2fbfb3SApril Chin {
1045da2e3ebdSchin if(fcgetc(n)==LPAREN)
1046da2e3ebdSchin {
1047da2e3ebdSchin if(c!=RPAREN)
1048da2e3ebdSchin fcseek(-1);
1049da2e3ebdSchin continue;
1050da2e3ebdSchin }
1051da2e3ebdSchin if(n>0)
1052da2e3ebdSchin fcseek(-1);
1053da2e3ebdSchin n = RPAREN;
1054da2e3ebdSchin }
1055da2e3ebdSchin if(c==';' && n!=';')
1056da2e3ebdSchin {
1057da2e3ebdSchin if(lp->lexd.warn && n==RBRACE)
1058da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexusequote,shp->inlineno,c);
1059da2e3ebdSchin continue;
1060da2e3ebdSchin }
10617c2fbfb3SApril Chin if(mode==ST_QNEST)
1062da2e3ebdSchin {
1063da2e3ebdSchin if(lp->lexd.warn)
1064da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexescape,shp->inlineno,c);
1065da2e3ebdSchin continue;
1066da2e3ebdSchin }
10677c2fbfb3SApril Chin mode = oldmode(lp);
1068da2e3ebdSchin poplevel(lp);
1069da2e3ebdSchin /* quotes in subscript need expansion */
1070da2e3ebdSchin if(mode==ST_NAME && (wordflags&ARG_QUOTED))
10717c2fbfb3SApril Chin wordflags |= ARG_MAC;
10727c2fbfb3SApril Chin /* check for ((...)) */
1073da2e3ebdSchin if(n==1 && c==RPAREN)
1074da2e3ebdSchin {
1075da2e3ebdSchin if(fcgetc(n)==RPAREN)
1076da2e3ebdSchin {
1077da2e3ebdSchin if(mode==ST_NONE && !lp->lexd.dolparen)
1078da2e3ebdSchin goto breakloop;
1079da2e3ebdSchin lp->lex.reservok = 1;
1080da2e3ebdSchin lp->lex.skipword = 0;
10817c2fbfb3SApril Chin return(lp->token=EXPRSYM);
1082da2e3ebdSchin }
10837c2fbfb3SApril Chin /* backward compatibility */
10847c2fbfb3SApril Chin {
10857c2fbfb3SApril Chin if(lp->lexd.warn)
1086da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexnested,shp->inlineno);
1087da2e3ebdSchin if(!(state=lp->lexd.first))
1088da2e3ebdSchin state = fcfirst();
108942194fd4SToomas Soome fcseek(state-fcseek(0));
10907c2fbfb3SApril Chin if(lp->arg)
1091da2e3ebdSchin {
10927c2fbfb3SApril Chin lp->arg = (struct argnod*)stkfreeze(stkp,1);
1093da2e3ebdSchin setupalias(lp,lp->arg->argval,NIL(Namval_t*));
109442194fd4SToomas Soome }
109542194fd4SToomas Soome lp->lexd.paren = 1;
10967c2fbfb3SApril Chin }
1097da2e3ebdSchin return(lp->token=LPAREN);
10987c2fbfb3SApril Chin }
10997c2fbfb3SApril Chin if(mode==ST_NONE)
1100da2e3ebdSchin return(0);
11017c2fbfb3SApril Chin if(c!=n)
1102da2e3ebdSchin {
11037c2fbfb3SApril Chin lp->token = c;
1104da2e3ebdSchin sh_syntax(lp);
1105da2e3ebdSchin }
1106da2e3ebdSchin if(c==RBRACE && (mode==ST_NAME||mode==ST_NORM))
1107da2e3ebdSchin goto epat;
1108da2e3ebdSchin continue;
11097c2fbfb3SApril Chin case S_EQ:
11107c2fbfb3SApril Chin assignment = lp->assignok;
1111da2e3ebdSchin /* FALL THRU */
1112da2e3ebdSchin case S_COLON:
1113da2e3ebdSchin if(assignment)
1114da2e3ebdSchin {
1115da2e3ebdSchin if((c=fcget())=='~')
11167c2fbfb3SApril Chin wordflags |= ARG_MAC;
1117da2e3ebdSchin else if(c!=LPAREN && assignment==SH_COMPASSIGN)
1118da2e3ebdSchin assignment = 0;
1119da2e3ebdSchin fcseek(-1);
1120da2e3ebdSchin }
1121da2e3ebdSchin break;
1122da2e3ebdSchin case S_LABEL:
1123da2e3ebdSchin if(lp->lex.reservok && !lp->lex.incase)
1124da2e3ebdSchin {
1125da2e3ebdSchin c = fcget();
1126da2e3ebdSchin fcseek(-1);
1127da2e3ebdSchin if(state[c]==S_BREAK)
1128da2e3ebdSchin {
11297c2fbfb3SApril Chin assignment = -1;
1130da2e3ebdSchin goto breakloop;
1131da2e3ebdSchin }
1132da2e3ebdSchin }
1133da2e3ebdSchin break;
1134da2e3ebdSchin case S_BRACT:
1135da2e3ebdSchin /* check for possible subscript */
1136da2e3ebdSchin if((n=endchar(lp))==RBRACT || n==RPAREN ||
1137da2e3ebdSchin (mode==ST_BRACE) ||
1138da2e3ebdSchin (oldmode(lp)==ST_NONE) ||
1139da2e3ebdSchin (mode==ST_NAME && (lp->assignok||lp->lexd.level)))
1140da2e3ebdSchin {
1141da2e3ebdSchin if(mode==ST_NAME)
11427c2fbfb3SApril Chin {
1143da2e3ebdSchin fcgetc(n);
11447c2fbfb3SApril Chin if(n>0)
11457c2fbfb3SApril Chin {
1146da2e3ebdSchin if(n==']')
114734f9b3eeSRoland Mainz errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1, shp->inlineno, "[]", "empty subscript");
114834f9b3eeSRoland Mainz fcseek(-1);
114934f9b3eeSRoland Mainz }
115034f9b3eeSRoland Mainz }
115134f9b3eeSRoland Mainz pushlevel(lp,RBRACT,mode);
115234f9b3eeSRoland Mainz wordflags |= ARG_QUOTED;
115334f9b3eeSRoland Mainz mode = ST_NESTED;
115434f9b3eeSRoland Mainz continue;
115534f9b3eeSRoland Mainz }
115634f9b3eeSRoland Mainz wordflags |= ARG_EXP;
11577c2fbfb3SApril Chin break;
1158da2e3ebdSchin case S_BRACE:
1159da2e3ebdSchin {
1160da2e3ebdSchin int isfirst;
1161da2e3ebdSchin if(lp->lexd.dolparen)
1162da2e3ebdSchin {
1163da2e3ebdSchin if(mode==ST_BEGIN && (lp->lex.reservok||lp->comsub))
1164da2e3ebdSchin {
1165da2e3ebdSchin fcgetc(n);
1166da2e3ebdSchin if(n>0)
11677c2fbfb3SApril Chin fcseek(-1);
11687c2fbfb3SApril Chin else
11697c2fbfb3SApril Chin n = '\n';
11707c2fbfb3SApril Chin if(n==RBRACT || sh_lexstates[ST_NORM][n])
11717c2fbfb3SApril Chin return(lp->token=c);
11727c2fbfb3SApril Chin }
11737c2fbfb3SApril Chin break;
11747c2fbfb3SApril Chin }
11757c2fbfb3SApril Chin else if(mode==ST_BEGIN)
11767c2fbfb3SApril Chin {
11777c2fbfb3SApril Chin if(lp->comsub && c==RBRACE)
11787c2fbfb3SApril Chin return(lp->token=c);
1179da2e3ebdSchin goto do_reg;
11807c2fbfb3SApril Chin }
11817c2fbfb3SApril Chin isfirst = (lp->lexd.first&&fcseek(0)==lp->lexd.first+1);
11827c2fbfb3SApril Chin fcgetc(n);
11837c2fbfb3SApril Chin /* check for {} */
11847c2fbfb3SApril Chin if(c==LBRACE && n==RBRACE)
11857c2fbfb3SApril Chin break;
11867c2fbfb3SApril Chin if(n>0)
11877c2fbfb3SApril Chin fcseek(-1);
1188da2e3ebdSchin else if(lp->lex.reservok)
1189da2e3ebdSchin break;
1190da2e3ebdSchin /* check for reserved word { or } */
1191da2e3ebdSchin if(lp->lex.reservok && state[n]==S_BREAK && isfirst)
1192da2e3ebdSchin break;
1193da2e3ebdSchin if(sh_isoption(SH_BRACEEXPAND) && c==LBRACE && !assignment && state[n]!=S_BREAK
11947c2fbfb3SApril Chin && !lp->lex.incase && !lp->lex.intest
1195da2e3ebdSchin && !lp->lex.skipword)
1196da2e3ebdSchin {
11977c2fbfb3SApril Chin wordflags |= ARG_EXP;
1198da2e3ebdSchin }
1199da2e3ebdSchin if(c==RBRACE && n==LPAREN)
12007c2fbfb3SApril Chin goto epat;
12017c2fbfb3SApril Chin break;
1202da2e3ebdSchin }
1203da2e3ebdSchin case S_PAT:
1204da2e3ebdSchin wordflags |= ARG_EXP;
1205da2e3ebdSchin /* FALL THRU */
1206da2e3ebdSchin case S_EPAT:
1207da2e3ebdSchin epat:
1208da2e3ebdSchin if(fcgetc(n)==LPAREN)
1209da2e3ebdSchin {
1210da2e3ebdSchin if(lp->lex.incase==TEST_RE)
1211da2e3ebdSchin {
1212da2e3ebdSchin lp->lex.incase++;
1213da2e3ebdSchin pushlevel(lp,RPAREN,ST_NORM);
1214da2e3ebdSchin mode = ST_NESTED;
1215da2e3ebdSchin }
12167c2fbfb3SApril Chin wordflags |= ARG_EXP;
1217da2e3ebdSchin pushlevel(lp,RPAREN,mode);
12187c2fbfb3SApril Chin mode = ST_NESTED;
12197c2fbfb3SApril Chin continue;
1220da2e3ebdSchin }
1221da2e3ebdSchin if(n>0)
1222da2e3ebdSchin fcseek(-1);
12237c2fbfb3SApril Chin if(n=='=' && c=='+' && mode==ST_NAME)
1224da2e3ebdSchin continue;
1225da2e3ebdSchin break;
1226da2e3ebdSchin }
1227da2e3ebdSchin lp->comp_assign = 0;
1228da2e3ebdSchin if(mode==ST_NAME)
1229da2e3ebdSchin mode = ST_NORM;
1230da2e3ebdSchin else if(mode==ST_NONE)
1231da2e3ebdSchin return(0);
1232da2e3ebdSchin }
12337c2fbfb3SApril Chin breakloop:
1234da2e3ebdSchin if(lp->lexd.nocopy)
1235da2e3ebdSchin {
1236da2e3ebdSchin lp->lexd.balance = 0;
1237da2e3ebdSchin return(0);
1238da2e3ebdSchin }
1239da2e3ebdSchin if(lp->lexd.dolparen)
12407c2fbfb3SApril Chin {
1241da2e3ebdSchin lp->lexd.balance = 0;
12427c2fbfb3SApril Chin if(lp->lexd.docword)
12437c2fbfb3SApril Chin nested_here(lp);
1244da2e3ebdSchin lp->lexd.message = (wordflags&ARG_MESSAGE);
12457c2fbfb3SApril Chin return(lp->token=0);
12467c2fbfb3SApril Chin }
12477c2fbfb3SApril Chin if(!(state=lp->lexd.first))
12487c2fbfb3SApril Chin state = fcfirst();
12497c2fbfb3SApril Chin n = fcseek(0)-(char*)state;
12507c2fbfb3SApril Chin if(!lp->arg)
12517c2fbfb3SApril Chin lp->arg = (struct argnod*)stkseek(stkp,ARGVAL);
12527c2fbfb3SApril Chin if(n>0)
12537c2fbfb3SApril Chin sfwrite(stkp,state,n);
1254da2e3ebdSchin /* add balancing character if necessary */
1255da2e3ebdSchin if(lp->lexd.balance)
12567c2fbfb3SApril Chin {
12577c2fbfb3SApril Chin sfputc(stkp,lp->lexd.balance);
1258da2e3ebdSchin lp->lexd.balance = 0;
12597c2fbfb3SApril Chin }
1260da2e3ebdSchin sfputc(stkp,0);
12617c2fbfb3SApril Chin stkseek(stkp,stktell(stkp)-1);
1262da2e3ebdSchin state = stkptr(stkp,ARGVAL);
12637c2fbfb3SApril Chin n = stktell(stkp)-ARGVAL;
12647c2fbfb3SApril Chin lp->lexd.first=0;
1265da2e3ebdSchin if(n==1)
12667c2fbfb3SApril Chin {
12677c2fbfb3SApril Chin /* check for numbered redirection */
12687c2fbfb3SApril Chin n = state[0];
12697c2fbfb3SApril Chin if((c=='<' || c=='>') && isadigit(n))
12707c2fbfb3SApril Chin {
1271da2e3ebdSchin c = sh_lex(lp);
1272da2e3ebdSchin lp->digits = (n-'0');
1273da2e3ebdSchin return(c);
1274da2e3ebdSchin }
1275da2e3ebdSchin if(n==LBRACT)
1276da2e3ebdSchin c = 0;
12777c2fbfb3SApril Chin else if(n==RBRACE && lp->comsub)
12787c2fbfb3SApril Chin return(lp->token=n);
1279da2e3ebdSchin else if(n=='~')
1280da2e3ebdSchin c = ARG_MAC;
1281da2e3ebdSchin else
1282da2e3ebdSchin c = (wordflags&ARG_EXP);
12837c2fbfb3SApril Chin n = 1;
12847c2fbfb3SApril Chin }
1285da2e3ebdSchin else if(n>2 && state[0]=='{' && state[n-1]=='}' && !lp->lex.intest && !lp->lex.incase && (c=='<' || c== '>') && sh_isoption(SH_BRACEEXPAND))
1286da2e3ebdSchin {
1287da2e3ebdSchin if(!strchr(state,','))
1288da2e3ebdSchin {
1289da2e3ebdSchin stkseek(stkp,stktell(stkp)-1);
1290da2e3ebdSchin lp->arg = (struct argnod*)stkfreeze(stkp,1);
12917c2fbfb3SApril Chin return(lp->token=IOVNAME);
1292da2e3ebdSchin }
1293da2e3ebdSchin c = wordflags;
1294da2e3ebdSchin }
12957c2fbfb3SApril Chin else
12967c2fbfb3SApril Chin c = wordflags;
12977c2fbfb3SApril Chin if(assignment<0)
1298da2e3ebdSchin {
1299da2e3ebdSchin stkseek(stkp,stktell(stkp)-1);
1300da2e3ebdSchin lp->arg = (struct argnod*)stkfreeze(stkp,1);
1301da2e3ebdSchin lp->lex.reservok = 1;
1302da2e3ebdSchin return(lp->token=LABLSYM);
1303da2e3ebdSchin }
1304da2e3ebdSchin if(assignment || (lp->lex.intest&&!lp->lex.incase) || mode==ST_NONE)
13057c2fbfb3SApril Chin c &= ~ARG_EXP;
13067c2fbfb3SApril Chin if((c&ARG_EXP) && (c&ARG_QUOTED))
13077c2fbfb3SApril Chin c |= ARG_MAC;
13087c2fbfb3SApril Chin if(mode==ST_NONE)
1309da2e3ebdSchin {
13107c2fbfb3SApril Chin /* eliminate trailing )) */
1311da2e3ebdSchin stkseek(stkp,stktell(stkp)-2);
1312da2e3ebdSchin }
1313da2e3ebdSchin if(c&ARG_MESSAGE)
1314da2e3ebdSchin {
1315da2e3ebdSchin if(sh_isoption(SH_DICTIONARY))
1316da2e3ebdSchin lp->arg = sh_endword(shp,2);
13177c2fbfb3SApril Chin if(!sh_isoption(SH_NOEXEC))
1318da2e3ebdSchin {
1319da2e3ebdSchin lp->arg = sh_endword(shp,1);
1320da2e3ebdSchin c &= ~ARG_MESSAGE;
1321da2e3ebdSchin }
13227c2fbfb3SApril Chin }
1323da2e3ebdSchin if(c==0 || (c&(ARG_MAC|ARG_EXP)) || (lp->lexd.warn && !lp->lexd.docword))
1324da2e3ebdSchin {
13257c2fbfb3SApril Chin lp->arg = (struct argnod*)stkfreeze(stkp,1);
1326da2e3ebdSchin lp->arg->argflag = (c?c:ARG_RAW);
1327da2e3ebdSchin }
1328da2e3ebdSchin else if(mode==ST_NONE)
13297c2fbfb3SApril Chin lp->arg = sh_endword(shp,-1);
1330da2e3ebdSchin else
13317c2fbfb3SApril Chin lp->arg = sh_endword(shp,0);
13327c2fbfb3SApril Chin state = lp->arg->argval;
1333da2e3ebdSchin lp->comp_assign = assignment;
1334da2e3ebdSchin if(assignment)
13357c2fbfb3SApril Chin lp->arg->argflag |= ARG_ASSIGN;
1336da2e3ebdSchin else if(!lp->lex.skipword)
13377c2fbfb3SApril Chin lp->assignok = 0;
13387c2fbfb3SApril Chin lp->arg->argchn.cp = 0;
13397c2fbfb3SApril Chin lp->arg->argnxt.ap = 0;
1340da2e3ebdSchin if(mode==ST_NONE)
13417c2fbfb3SApril Chin return(lp->token=EXPRSYM);
13427c2fbfb3SApril Chin if(lp->lex.intest)
13437c2fbfb3SApril Chin {
13447c2fbfb3SApril Chin if(lp->lex.testop1)
13457c2fbfb3SApril Chin {
1346da2e3ebdSchin lp->lex.testop1 = 0;
13477c2fbfb3SApril Chin if(n==2 && state[0]=='-' && state[2]==0 &&
13487c2fbfb3SApril Chin strchr(test_opchars,state[1]))
1349da2e3ebdSchin {
13507c2fbfb3SApril Chin if(lp->lexd.warn && state[1]=='a')
1351da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete2,shp->inlineno);
13527c2fbfb3SApril Chin lp->digits = state[1];
1353da2e3ebdSchin lp->token = TESTUNOP;
1354da2e3ebdSchin }
1355da2e3ebdSchin else if(n==1 && state[0]=='!' && state[1]==0)
13567c2fbfb3SApril Chin {
1357da2e3ebdSchin lp->lex.testop1 = 1;
13587c2fbfb3SApril Chin lp->token = '!';
13597c2fbfb3SApril Chin }
1360da2e3ebdSchin else
1361da2e3ebdSchin {
1362da2e3ebdSchin lp->lex.testop2 = 1;
13637c2fbfb3SApril Chin lp->token = 0;
13647c2fbfb3SApril Chin }
1365da2e3ebdSchin return(lp->token);
1366da2e3ebdSchin }
1367da2e3ebdSchin lp->lex.incase = 0;
13687c2fbfb3SApril Chin c = sh_lookup(state,shtab_testops);
13697c2fbfb3SApril Chin switch(c)
1370da2e3ebdSchin {
13717c2fbfb3SApril Chin case TEST_END:
1372da2e3ebdSchin lp->lex.testop2 = lp->lex.intest = 0;
13737c2fbfb3SApril Chin lp->lex.reservok = 1;
1374da2e3ebdSchin lp->token = ETESTSYM;
1375da2e3ebdSchin return(lp->token);
1376da2e3ebdSchin
1377da2e3ebdSchin case TEST_SEQ:
13787c2fbfb3SApril Chin if(lp->lexd.warn && state[1]==0)
13797c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete3,shp->inlineno);
13807c2fbfb3SApril Chin /* FALL THRU */
13817c2fbfb3SApril Chin default:
1382da2e3ebdSchin if(lp->lex.testop2)
1383da2e3ebdSchin {
13847c2fbfb3SApril Chin if(lp->lexd.warn && (c&TEST_ARITH))
1385da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete4,shp->inlineno,state);
1386*3ce7283dSToomas Soome if(c&TEST_PATTERN)
1387da2e3ebdSchin lp->lex.incase = 1;
13887c2fbfb3SApril Chin else if(c==TEST_REP)
1389da2e3ebdSchin lp->lex.incase = TEST_RE;
13907c2fbfb3SApril Chin lp->lex.testop2 = 0;
1391da2e3ebdSchin lp->digits = c;
1392da2e3ebdSchin lp->token = TESTBINOP;
13937c2fbfb3SApril Chin return(lp->token);
1394da2e3ebdSchin }
13957c2fbfb3SApril Chin
13967c2fbfb3SApril Chin case TEST_OR: case TEST_AND:
13977c2fbfb3SApril Chin case 0:
13987c2fbfb3SApril Chin return(lp->token=0);
13997c2fbfb3SApril Chin }
1400da2e3ebdSchin }
1401da2e3ebdSchin if(lp->lex.reservok /* && !lp->lex.incase*/ && n<=2)
1402*3ce7283dSToomas Soome {
1403da2e3ebdSchin /* check for {, }, ! */
1404da2e3ebdSchin c = state[0];
14057c2fbfb3SApril Chin if(n==1 && (c=='{' || c=='}' || c=='!'))
1406da2e3ebdSchin {
1407da2e3ebdSchin if(lp->lexd.warn && c=='{' && lp->lex.incase==2)
14087c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_warn(0),e_lexobsolete6,shp->inlineno);
1409da2e3ebdSchin if(lp->lex.incase==1 && c==RBRACE)
1410da2e3ebdSchin lp->lex.incase = 0;
1411da2e3ebdSchin return(lp->token=c);
1412da2e3ebdSchin }
1413da2e3ebdSchin else if(!lp->lex.incase && c==LBRACT && state[1]==LBRACT)
14147c2fbfb3SApril Chin {
1415da2e3ebdSchin lp->lex.intest = lp->lex.testop1 = 1;
14167c2fbfb3SApril Chin lp->lex.testop2 = lp->lex.reservok = 0;
14177c2fbfb3SApril Chin return(lp->token=BTESTSYM);
14187c2fbfb3SApril Chin }
1419da2e3ebdSchin }
14207c2fbfb3SApril Chin c = 0;
1421da2e3ebdSchin if(!lp->lex.skipword)
14227c2fbfb3SApril Chin {
14237c2fbfb3SApril Chin if(n>1 && lp->lex.reservok==1 && mode==ST_NAME &&
14247c2fbfb3SApril Chin (c=sh_lookup(state,shtab_reserved)))
1425da2e3ebdSchin {
1426da2e3ebdSchin if(lp->lex.incase)
1427da2e3ebdSchin {
14287c2fbfb3SApril Chin if(lp->lex.incase >1)
1429da2e3ebdSchin lp->lex.incase = 1;
14307c2fbfb3SApril Chin else if(c==ESACSYM)
1431da2e3ebdSchin lp->lex.incase = 0;
1432da2e3ebdSchin else
14337c2fbfb3SApril Chin c = 0;
1434da2e3ebdSchin }
14357c2fbfb3SApril Chin else if(c==FORSYM || c==CASESYM || c==SELECTSYM || c==FUNCTSYM || c==NSPACESYM)
14367c2fbfb3SApril Chin {
1437da2e3ebdSchin lp->lex.skipword = 1;
14387c2fbfb3SApril Chin lp->lex.incase = 2*(c==CASESYM);
1439da2e3ebdSchin }
1440da2e3ebdSchin else
1441da2e3ebdSchin lp->lex.skipword = 0;
1442da2e3ebdSchin if(c==INSYM)
1443da2e3ebdSchin lp->lex.reservok = 0;
14447c2fbfb3SApril Chin else if(c==TIMESYM)
14457c2fbfb3SApril Chin {
1446da2e3ebdSchin /* yech - POSIX requires time -p */
1447da2e3ebdSchin while(fcgetc(n)==' ' || n=='\t');
14487c2fbfb3SApril Chin if(n>0)
1449da2e3ebdSchin fcseek(-1);
14507c2fbfb3SApril Chin if(n=='-')
1451da2e3ebdSchin c=0;
1452da2e3ebdSchin }
1453da2e3ebdSchin return(lp->token=c);
1454da2e3ebdSchin }
1455da2e3ebdSchin if(!(wordflags&ARG_QUOTED) && (lp->lex.reservok||lp->aliasok))
1456da2e3ebdSchin {
1457da2e3ebdSchin /* check for aliases */
1458da2e3ebdSchin Namval_t* np;
1459da2e3ebdSchin if(!lp->lex.incase && !assignment && fcpeek(0)!=LPAREN &&
14607c2fbfb3SApril Chin (np=nv_search(state,shp->alias_tree,HASH_SCOPE))
1461da2e3ebdSchin && !nv_isattr(np,NV_NOEXPAND)
14627c2fbfb3SApril Chin #if KSHELL
1463da2e3ebdSchin && (!sh_isstate(SH_NOALIAS) || nv_isattr(np,NV_NOFREE))
1464da2e3ebdSchin #endif /* KSHELL */
1465da2e3ebdSchin && (state=nv_getval(np)))
14667c2fbfb3SApril Chin {
1467da2e3ebdSchin setupalias(lp,state,np);
1468da2e3ebdSchin nv_onattr(np,NV_NOEXPAND);
1469da2e3ebdSchin lp->lex.reservok = 1;
1470da2e3ebdSchin lp->assignok |= lp->lex.reservok;
1471da2e3ebdSchin return(sh_lex(lp));
1472da2e3ebdSchin }
1473da2e3ebdSchin }
1474da2e3ebdSchin lp->lex.reservok = 0;
1475da2e3ebdSchin }
14767c2fbfb3SApril Chin lp->lex.skipword = lp->lexd.docword = 0;
14777c2fbfb3SApril Chin return(lp->token=c);
14787c2fbfb3SApril Chin }
1479da2e3ebdSchin
1480da2e3ebdSchin /*
14817c2fbfb3SApril Chin * read to end of command substitution
1482da2e3ebdSchin */
comsub(register Lex_t * lp,int endtok)14837c2fbfb3SApril Chin static int comsub(register Lex_t *lp, int endtok)
14847c2fbfb3SApril Chin {
1485da2e3ebdSchin register int n,c,count=1;
1486da2e3ebdSchin register int line=lp->sh->inlineno;
1487da2e3ebdSchin char word[5];
1488da2e3ebdSchin int off, messages=0, assignok=lp->assignok, csub;
1489da2e3ebdSchin struct lexstate save;
14907c2fbfb3SApril Chin save = lp->lex;
1491da2e3ebdSchin csub = lp->comsub;
1492da2e3ebdSchin sh_lexopen(lp,lp->sh,1);
14937c2fbfb3SApril Chin lp->lexd.dolparen++;
1494da2e3ebdSchin lp->lex.incase=0;
14953e14f97fSRoger A. Faulkner pushlevel(lp,0,0);
1496da2e3ebdSchin lp->comsub = (endtok==LBRACE);
14977c2fbfb3SApril Chin off = fcseek(0) - lp->lexd.first;
14987c2fbfb3SApril Chin if(sh_lex(lp)==endtok)
14997c2fbfb3SApril Chin {
15007c2fbfb3SApril Chin if(endtok==LPAREN && fcseek(0)==lp->lexd.first)
15017c2fbfb3SApril Chin {
15027c2fbfb3SApril Chin count++;
15037c2fbfb3SApril Chin lp->lexd.paren = 0;
15043e14f97fSRoger A. Faulkner fcseek(off+2);
15057c2fbfb3SApril Chin }
1506da2e3ebdSchin while(1)
15073e14f97fSRoger A. Faulkner {
15083e14f97fSRoger A. Faulkner /* look for case and esac */
15093e14f97fSRoger A. Faulkner n=0;
15103e14f97fSRoger A. Faulkner while(1)
15113e14f97fSRoger A. Faulkner {
15123e14f97fSRoger A. Faulkner fcgetc(c);
1513da2e3ebdSchin /* skip leading white space */
1514da2e3ebdSchin if(n==0 && !sh_lexstates[ST_BEGIN][c])
1515da2e3ebdSchin continue;
1516da2e3ebdSchin if(n==4)
1517da2e3ebdSchin break;
1518da2e3ebdSchin if(sh_lexstates[ST_NAME][c])
1519da2e3ebdSchin goto skip;
1520da2e3ebdSchin word[n++] = c;
1521da2e3ebdSchin }
1522da2e3ebdSchin if(sh_lexstates[ST_NAME][c]==S_BREAK)
1523da2e3ebdSchin {
1524da2e3ebdSchin if(memcmp(word,"case",4)==0)
1525da2e3ebdSchin lp->lex.incase=1;
1526da2e3ebdSchin else if(memcmp(word,"esac",4)==0)
1527da2e3ebdSchin lp->lex.incase=0;
1528da2e3ebdSchin }
1529da2e3ebdSchin skip:
1530da2e3ebdSchin if(c && (c!='#' || n==0))
1531da2e3ebdSchin fcseek(-1);
15327c2fbfb3SApril Chin if(c==RBRACE && lp->lex.incase)
1533da2e3ebdSchin lp->lex.incase=0;
15347c2fbfb3SApril Chin switch(c=sh_lex(lp))
1535da2e3ebdSchin {
1536da2e3ebdSchin case LBRACE:
1537da2e3ebdSchin if(endtok==LBRACE && !lp->lex.incase)
1538da2e3ebdSchin {
15397c2fbfb3SApril Chin lp->comsub = 0;
15407c2fbfb3SApril Chin count++;
15417c2fbfb3SApril Chin }
1542da2e3ebdSchin break;
15437c2fbfb3SApril Chin case RBRACE:
15447c2fbfb3SApril Chin rbrace:
15457c2fbfb3SApril Chin if(endtok==LBRACE && --count<=0)
15467c2fbfb3SApril Chin goto done;
15477c2fbfb3SApril Chin lp->comsub = (count==1);
15487c2fbfb3SApril Chin break;
15497c2fbfb3SApril Chin case IPROCSYM: case OPROCSYM:
15507c2fbfb3SApril Chin case LPAREN:
15517c2fbfb3SApril Chin if(endtok==LPAREN && !lp->lex.incase)
15527c2fbfb3SApril Chin count++;
15537c2fbfb3SApril Chin break;
15547c2fbfb3SApril Chin case RPAREN:
15557c2fbfb3SApril Chin if(lp->lex.incase)
15567c2fbfb3SApril Chin lp->lex.incase=0;
15577c2fbfb3SApril Chin else if(endtok==LPAREN && --count<=0)
15587c2fbfb3SApril Chin goto done;
1559da2e3ebdSchin break;
1560da2e3ebdSchin case EOFSYM:
1561da2e3ebdSchin lp->lastline = line;
15627c2fbfb3SApril Chin lp->lasttok = endtok;
15637c2fbfb3SApril Chin sh_syntax(lp);
15647c2fbfb3SApril Chin case IOSEEKSYM:
1565da2e3ebdSchin if(fcgetc(c)!='#' && c>0)
1566da2e3ebdSchin fcseek(-1);
1567da2e3ebdSchin break;
15687c2fbfb3SApril Chin case IODOCSYM:
15697c2fbfb3SApril Chin lp->lexd.docextra = 0;
15707c2fbfb3SApril Chin sh_lex(lp);
1571*3ce7283dSToomas Soome break;
1572da2e3ebdSchin case 0:
1573da2e3ebdSchin lp->lex.reservok = 0;
1574da2e3ebdSchin messages |= lp->lexd.message;
1575da2e3ebdSchin break;
1576da2e3ebdSchin case ';':
157734f9b3eeSRoland Mainz fcgetc(c);
15787c2fbfb3SApril Chin if(c==RBRACE && endtok==LBRACE)
1579da2e3ebdSchin goto rbrace;
1580da2e3ebdSchin if(c>0)
15817c2fbfb3SApril Chin fcseek(-1);
15827c2fbfb3SApril Chin /* fall through*/
15837c2fbfb3SApril Chin default:
15847c2fbfb3SApril Chin lp->lex.reservok = 1;
15857c2fbfb3SApril Chin }
15867c2fbfb3SApril Chin }
15877c2fbfb3SApril Chin }
15887c2fbfb3SApril Chin done:
15897c2fbfb3SApril Chin poplevel(lp);
15907c2fbfb3SApril Chin lp->comsub = csub;
15917c2fbfb3SApril Chin lp->lastline = line;
15927c2fbfb3SApril Chin lp->lexd.dolparen--;
1593da2e3ebdSchin lp->lex = save;
1594da2e3ebdSchin lp->assignok = (endchar(lp)==RBRACT?assignok:0);
1595da2e3ebdSchin return(messages);
1596da2e3ebdSchin }
15977c2fbfb3SApril Chin
15987c2fbfb3SApril Chin /*
15997c2fbfb3SApril Chin * here-doc nested in $(...)
16007c2fbfb3SApril Chin * allocate ionode with delimiter filled in without disturbing stak
16017c2fbfb3SApril Chin */
nested_here(register Lex_t * lp)16027c2fbfb3SApril Chin static void nested_here(register Lex_t *lp)
1603da2e3ebdSchin {
1604da2e3ebdSchin register struct ionod *iop;
1605da2e3ebdSchin register int n,offset;
1606da2e3ebdSchin struct argnod *arg = lp->arg;
1607da2e3ebdSchin Stk_t *stkp = lp->sh->stk;
1608da2e3ebdSchin char *base;
1609da2e3ebdSchin if(offset=stktell(stkp))
1610da2e3ebdSchin base = stkfreeze(stkp,0);
1611da2e3ebdSchin n = fcseek(0)-lp->lexd.docend;
1612da2e3ebdSchin iop = newof(0,struct ionod,1,lp->lexd.docextra+n+ARGVAL);
1613da2e3ebdSchin iop->iolst = lp->heredoc;
16147c2fbfb3SApril Chin stkseek(stkp,ARGVAL);
16157c2fbfb3SApril Chin if(lp->lexd.docextra)
1616da2e3ebdSchin {
16177c2fbfb3SApril Chin sfseek(lp->sh->strbuf,(Sfoff_t)0, SEEK_SET);
16187c2fbfb3SApril Chin sfmove(lp->sh->strbuf,stkp,lp->lexd.docextra,-1);
16197c2fbfb3SApril Chin }
162034f9b3eeSRoland Mainz sfwrite(stkp,lp->lexd.docend,n);
16217c2fbfb3SApril Chin lp->arg = sh_endword(lp->sh,0);
16227c2fbfb3SApril Chin iop->ioname = (char*)(iop+1);
162334f9b3eeSRoland Mainz strcpy(iop->ioname,lp->arg->argval);
162434f9b3eeSRoland Mainz iop->iofile = (IODOC|IORAW);
162534f9b3eeSRoland Mainz if(lp->lexd.docword>1)
162634f9b3eeSRoland Mainz iop->iofile |= IOSTRIP;
162734f9b3eeSRoland Mainz lp->heredoc = iop;
16287c2fbfb3SApril Chin lp->arg = arg;
16297c2fbfb3SApril Chin lp->lexd.docword = 0;
1630da2e3ebdSchin if(offset)
16317c2fbfb3SApril Chin stkset(stkp,base,offset);
1632da2e3ebdSchin else
16337c2fbfb3SApril Chin stkseek(stkp,0);
1634da2e3ebdSchin }
16357c2fbfb3SApril Chin
16367c2fbfb3SApril Chin /*
16377c2fbfb3SApril Chin * skip to <close> character
1638da2e3ebdSchin * if <copy> is non,zero, then the characters are copied to the stack
16397c2fbfb3SApril Chin * <state> is the initial lexical state
1640da2e3ebdSchin */
sh_lexskip(Lex_t * lp,int close,register int copy,int state)16417c2fbfb3SApril Chin void sh_lexskip(Lex_t *lp,int close, register int copy, int state)
1642da2e3ebdSchin {
1643da2e3ebdSchin register char *cp;
1644da2e3ebdSchin lp->lexd.nest = close;
1645da2e3ebdSchin lp->lexd.lex_state = state;
1646da2e3ebdSchin lp->lexd.noarg = 1;
1647da2e3ebdSchin if(copy)
1648da2e3ebdSchin fcnotify(lex_advance,lp);
16497c2fbfb3SApril Chin else
1650da2e3ebdSchin lp->lexd.nocopy++;
1651da2e3ebdSchin sh_lex(lp);
16527c2fbfb3SApril Chin lp->lexd.noarg = 0;
16537c2fbfb3SApril Chin if(copy)
16547c2fbfb3SApril Chin {
1655da2e3ebdSchin fcnotify(0,lp);
16567c2fbfb3SApril Chin if(!(cp=lp->lexd.first))
1657da2e3ebdSchin cp = fcfirst();
16587c2fbfb3SApril Chin if((copy = fcseek(0)-cp) > 0)
16597c2fbfb3SApril Chin sfwrite(lp->sh->stk,cp,copy);
16607c2fbfb3SApril Chin }
1661da2e3ebdSchin else
1662da2e3ebdSchin lp->lexd.nocopy--;
16637c2fbfb3SApril Chin }
16647c2fbfb3SApril Chin
1665da2e3ebdSchin #if SHOPT_CRNL
_sfwrite(Sfio_t * sp,const Void_t * buff,size_t n)1666da2e3ebdSchin ssize_t _sfwrite(Sfio_t *sp, const Void_t *buff, size_t n)
16677c2fbfb3SApril Chin {
1668da2e3ebdSchin const char *cp = (const char*)buff, *next=cp, *ep = cp + n;
1669da2e3ebdSchin int m=0,k;
16707c2fbfb3SApril Chin while(next = (const char*)memchr(next,'\r',ep-next))
1671da2e3ebdSchin if(*++next=='\n')
1672da2e3ebdSchin {
1673da2e3ebdSchin if(k=next-cp-1)
1674da2e3ebdSchin {
1675da2e3ebdSchin if((k=sfwrite(sp,cp,k)) < 0)
1676da2e3ebdSchin return(m>0?m:-1);
1677da2e3ebdSchin m += k;
1678da2e3ebdSchin }
1679da2e3ebdSchin cp = next;
1680da2e3ebdSchin }
1681da2e3ebdSchin if((k=sfwrite(sp,cp,ep-cp)) < 0)
1682da2e3ebdSchin return(m>0?m:-1);
1683da2e3ebdSchin return(m+k);
1684da2e3ebdSchin }
1685da2e3ebdSchin # define sfwrite _sfwrite
1686da2e3ebdSchin #endif /* SHOPT_CRNL */
1687da2e3ebdSchin
1688da2e3ebdSchin /*
1689da2e3ebdSchin * read in here-document from script
1690da2e3ebdSchin * quoted here documents, and here-documents without special chars are
1691da2e3ebdSchin * noted with the IOQUOTE flag
1692da2e3ebdSchin * returns 1 for complete here-doc, 0 for EOF
1693da2e3ebdSchin */
1694da2e3ebdSchin
here_copy(Lex_t * lp,register struct ionod * iop)1695da2e3ebdSchin static int here_copy(Lex_t *lp,register struct ionod *iop)
1696da2e3ebdSchin {
1697da2e3ebdSchin register const char *state;
1698da2e3ebdSchin register int c,n;
1699da2e3ebdSchin register char *bufp,*cp;
1700da2e3ebdSchin register Sfio_t *sp=lp->sh->heredocs, *funlog;
1701da2e3ebdSchin int stripcol=0,stripflg, nsave, special=0;
1702da2e3ebdSchin if(funlog=lp->sh->funlog)
1703da2e3ebdSchin {
1704da2e3ebdSchin if(fcfill()>0)
1705da2e3ebdSchin fcseek(-1);
1706da2e3ebdSchin lp->sh->funlog = 0;
1707da2e3ebdSchin }
17087c2fbfb3SApril Chin if(iop->iolst)
1709da2e3ebdSchin here_copy(lp,iop->iolst);
17107c2fbfb3SApril Chin iop->iooffset = sfseek(sp,(off_t)0,SEEK_END);
1711da2e3ebdSchin iop->iosize = 0;
1712da2e3ebdSchin iop->iodelim=iop->ioname;
1713da2e3ebdSchin /* check for and strip quoted characters in delimiter string */
17147c2fbfb3SApril Chin if(stripflg=iop->iofile&IOSTRIP)
1715da2e3ebdSchin {
1716da2e3ebdSchin while(*iop->iodelim=='\t')
1717da2e3ebdSchin iop->iodelim++;
1718da2e3ebdSchin /* skip over leading tabs in document */
1719da2e3ebdSchin if(iop->iofile&IOLSEEK)
1720da2e3ebdSchin {
1721da2e3ebdSchin iop->iofile &= ~IOLSEEK;
1722da2e3ebdSchin while(fcgetc(c)=='\t' || c==' ')
1723da2e3ebdSchin {
1724da2e3ebdSchin if(c==' ')
1725da2e3ebdSchin stripcol++;
1726da2e3ebdSchin else
1727da2e3ebdSchin stripcol += 8 - stripcol%8;
1728da2e3ebdSchin }
1729da2e3ebdSchin }
1730da2e3ebdSchin else
1731da2e3ebdSchin while(fcgetc(c)=='\t');
1732da2e3ebdSchin if(c>0)
1733da2e3ebdSchin fcseek(-1);
1734da2e3ebdSchin }
1735da2e3ebdSchin if(iop->iofile&IOQUOTE)
1736da2e3ebdSchin state = sh_lexstates[ST_LIT];
1737da2e3ebdSchin else
1738da2e3ebdSchin state = sh_lexstates[ST_QUOTE];
1739da2e3ebdSchin bufp = fcseek(0);
1740da2e3ebdSchin n = S_NL;
1741da2e3ebdSchin while(1)
1742da2e3ebdSchin {
1743da2e3ebdSchin if(n!=S_NL)
1744da2e3ebdSchin {
1745da2e3ebdSchin /* skip over regular characters */
1746da2e3ebdSchin while((n=STATE(state,c))==0);
1747da2e3ebdSchin }
1748da2e3ebdSchin if(n==S_EOF || !(c=fcget()))
1749da2e3ebdSchin {
1750da2e3ebdSchin if(!lp->lexd.dolparen && (c=(fcseek(0)-1)-bufp))
1751da2e3ebdSchin {
1752da2e3ebdSchin if(n==S_ESC)
1753da2e3ebdSchin c--;
1754da2e3ebdSchin if((c=sfwrite(sp,bufp,c))>0)
1755da2e3ebdSchin iop->iosize += c;
1756da2e3ebdSchin }
1757da2e3ebdSchin if((c=lexfill(lp))<=0)
17587c2fbfb3SApril Chin break;
1759da2e3ebdSchin if(n==S_ESC)
1760da2e3ebdSchin {
1761da2e3ebdSchin #if SHOPT_CRNL
1762da2e3ebdSchin if(c=='\r' && (c=fcget())!=NL)
1763da2e3ebdSchin fcseek(-1);
1764da2e3ebdSchin #endif /* SHOPT_CRNL */
17657c2fbfb3SApril Chin if(c==NL)
1766da2e3ebdSchin fcseek(1);
1767da2e3ebdSchin else
1768da2e3ebdSchin sfputc(sp,'\\');
1769da2e3ebdSchin }
1770da2e3ebdSchin bufp = fcseek(-1);
1771da2e3ebdSchin }
1772da2e3ebdSchin else
1773da2e3ebdSchin fcseek(-1);
1774da2e3ebdSchin switch(n)
1775da2e3ebdSchin {
1776da2e3ebdSchin case S_NL:
1777da2e3ebdSchin lp->sh->inlineno++;
1778da2e3ebdSchin if((stripcol && c==' ') || (stripflg && c=='\t'))
1779da2e3ebdSchin {
1780da2e3ebdSchin if(!lp->lexd.dolparen)
1781da2e3ebdSchin {
1782da2e3ebdSchin /* write out line */
1783da2e3ebdSchin n = fcseek(0)-bufp;
1784da2e3ebdSchin if((n=sfwrite(sp,bufp,n))>0)
17857c2fbfb3SApril Chin iop->iosize += n;
1786da2e3ebdSchin }
1787da2e3ebdSchin /* skip over tabs */
17887c2fbfb3SApril Chin if(stripcol)
1789da2e3ebdSchin {
1790da2e3ebdSchin int col=0;
1791da2e3ebdSchin do
1792da2e3ebdSchin {
1793da2e3ebdSchin fcgetc(c);
1794da2e3ebdSchin if(c==' ')
1795da2e3ebdSchin col++;
1796da2e3ebdSchin else
1797da2e3ebdSchin col += 8 - col%8;
1798da2e3ebdSchin if(col>stripcol)
1799da2e3ebdSchin break;
1800da2e3ebdSchin }
1801da2e3ebdSchin while (c==' ' || c=='\t');
1802da2e3ebdSchin }
1803da2e3ebdSchin else while(c=='\t')
1804da2e3ebdSchin fcgetc(c);
1805da2e3ebdSchin if(c<=0)
1806da2e3ebdSchin goto done;
1807da2e3ebdSchin bufp = fcseek(-1);
1808da2e3ebdSchin }
1809da2e3ebdSchin if(c!=iop->iodelim[0])
1810da2e3ebdSchin break;
1811da2e3ebdSchin cp = fcseek(0);
1812da2e3ebdSchin nsave = n = 0;
1813da2e3ebdSchin while(1)
1814da2e3ebdSchin {
1815da2e3ebdSchin if(!(c=fcget()))
1816da2e3ebdSchin {
1817da2e3ebdSchin if(!lp->lexd.dolparen && (c=cp-bufp))
1818da2e3ebdSchin {
1819da2e3ebdSchin if((c=sfwrite(sp,cp=bufp,c))>0)
1820da2e3ebdSchin iop->iosize+=c;
1821da2e3ebdSchin }
1822da2e3ebdSchin nsave = n;
1823da2e3ebdSchin if((c=lexfill(lp))<=0)
1824da2e3ebdSchin {
18257c2fbfb3SApril Chin c = iop->iodelim[n]==0;
1826da2e3ebdSchin goto done;
1827da2e3ebdSchin }
1828da2e3ebdSchin }
1829da2e3ebdSchin #if SHOPT_CRNL
1830da2e3ebdSchin if(c=='\r' && (c=fcget())!=NL)
18317c2fbfb3SApril Chin {
1832da2e3ebdSchin if(c)
1833da2e3ebdSchin fcseek(-1);
1834da2e3ebdSchin c='\r';
1835da2e3ebdSchin }
1836da2e3ebdSchin #endif /* SHOPT_CRNL */
1837da2e3ebdSchin if(c==NL)
1838da2e3ebdSchin lp->sh->inlineno++;
1839da2e3ebdSchin if(iop->iodelim[n]==0 && (c==NL||c==RPAREN))
1840da2e3ebdSchin {
1841da2e3ebdSchin if(!lp->lexd.dolparen && (n=cp-bufp))
1842da2e3ebdSchin {
1843da2e3ebdSchin if((n=sfwrite(sp,bufp,n))>0)
1844da2e3ebdSchin iop->iosize += n;
1845da2e3ebdSchin }
18467c2fbfb3SApril Chin lp->sh->inlineno--;
1847da2e3ebdSchin if(c==RPAREN)
1848da2e3ebdSchin fcseek(-1);
18497c2fbfb3SApril Chin goto done;
1850da2e3ebdSchin }
1851da2e3ebdSchin if(iop->iodelim[n++]!=c)
1852da2e3ebdSchin {
1853da2e3ebdSchin /*
18547c2fbfb3SApril Chin * The match for delimiter failed.
1855da2e3ebdSchin * nsave>0 only when a buffer boundary
1856da2e3ebdSchin * was crossed while checking the
1857da2e3ebdSchin * delimiter
1858da2e3ebdSchin */
1859da2e3ebdSchin if(!lp->lexd.dolparen && nsave>0)
1860da2e3ebdSchin {
1861da2e3ebdSchin if((n=sfwrite(sp,bufp,nsave))>0)
1862da2e3ebdSchin iop->iosize += n;
1863da2e3ebdSchin bufp = fcfirst();
1864da2e3ebdSchin }
1865da2e3ebdSchin if(c==NL)
1866da2e3ebdSchin fcseek(-1);
18677c2fbfb3SApril Chin break;
1868da2e3ebdSchin }
1869da2e3ebdSchin }
1870da2e3ebdSchin break;
1871da2e3ebdSchin case S_ESC:
1872da2e3ebdSchin n=1;
1873da2e3ebdSchin #if SHOPT_CRNL
1874da2e3ebdSchin if(c=='\r')
1875da2e3ebdSchin {
1876da2e3ebdSchin fcseek(1);
1877da2e3ebdSchin if(c=fcget())
1878da2e3ebdSchin fcseek(-1);
1879da2e3ebdSchin if(c==NL)
1880da2e3ebdSchin n=2;
1881da2e3ebdSchin else
1882da2e3ebdSchin {
1883da2e3ebdSchin special++;
1884da2e3ebdSchin break;
1885da2e3ebdSchin }
1886da2e3ebdSchin }
1887da2e3ebdSchin #endif /* SHOPT_CRNL */
1888da2e3ebdSchin if(c==NL)
1889da2e3ebdSchin {
1890da2e3ebdSchin /* new-line joining */
1891da2e3ebdSchin lp->sh->inlineno++;
1892da2e3ebdSchin if(!lp->lexd.dolparen && (n=(fcseek(0)-bufp)-n)>=0)
1893da2e3ebdSchin {
1894da2e3ebdSchin if(n && (n=sfwrite(sp,bufp,n))>0)
1895da2e3ebdSchin iop->iosize += n;
1896da2e3ebdSchin bufp = fcseek(0)+1;
1897da2e3ebdSchin }
1898da2e3ebdSchin }
18997c2fbfb3SApril Chin else
190034f9b3eeSRoland Mainz special++;
1901da2e3ebdSchin fcget();
190234f9b3eeSRoland Mainz break;
1903da2e3ebdSchin
1904da2e3ebdSchin case S_GRAVE:
1905da2e3ebdSchin case S_DOL:
1906da2e3ebdSchin special++;
1907da2e3ebdSchin break;
1908da2e3ebdSchin }
1909da2e3ebdSchin n=0;
1910da2e3ebdSchin }
1911da2e3ebdSchin done:
1912da2e3ebdSchin lp->sh->funlog = funlog;
1913da2e3ebdSchin if(lp->lexd.dolparen)
1914da2e3ebdSchin free((void*)iop);
1915da2e3ebdSchin else if(!special)
1916da2e3ebdSchin iop->iofile |= IOQUOTE;
1917da2e3ebdSchin return(c);
1918da2e3ebdSchin }
1919da2e3ebdSchin
19207c2fbfb3SApril Chin /*
19217c2fbfb3SApril Chin * generates string for given token
1922da2e3ebdSchin */
fmttoken(Lex_t * lp,register int sym,char * tok)1923da2e3ebdSchin static char *fmttoken(Lex_t *lp, register int sym, char *tok)
1924da2e3ebdSchin {
1925da2e3ebdSchin int n=1;
1926da2e3ebdSchin if(sym < 0)
1927da2e3ebdSchin return((char*)sh_translate(e_lexzerobyte));
1928da2e3ebdSchin if(sym==0)
1929da2e3ebdSchin return(lp->arg?lp->arg->argval:"?");
1930da2e3ebdSchin if(lp->lex.intest && lp->arg && *lp->arg->argval)
1931da2e3ebdSchin return(lp->arg->argval);
1932da2e3ebdSchin if(sym&SYMRES)
193334f9b3eeSRoland Mainz {
1934da2e3ebdSchin register const Shtable_t *tp=shtab_reserved;
1935da2e3ebdSchin while(tp->sh_number && tp->sh_number!=sym)
1936da2e3ebdSchin tp++;
19377c2fbfb3SApril Chin return((char*)tp->sh_name);
19387c2fbfb3SApril Chin }
19397c2fbfb3SApril Chin if(sym==EOFSYM)
1940da2e3ebdSchin return((char*)sh_translate(e_endoffile));
1941da2e3ebdSchin if(sym==NL)
1942da2e3ebdSchin return((char*)sh_translate(e_newline));
1943da2e3ebdSchin tok[0] = sym;
1944da2e3ebdSchin if(sym&SYMREP)
1945da2e3ebdSchin tok[n++] = sym;
1946da2e3ebdSchin else
1947da2e3ebdSchin {
1948da2e3ebdSchin switch(sym&SYMMASK)
1949da2e3ebdSchin {
1950da2e3ebdSchin case SYMAMP:
1951da2e3ebdSchin sym = '&';
1952da2e3ebdSchin break;
195334f9b3eeSRoland Mainz case SYMPIPE:
1954da2e3ebdSchin sym = '|';
1955da2e3ebdSchin break;
1956da2e3ebdSchin case SYMGT:
1957da2e3ebdSchin sym = '>';
1958da2e3ebdSchin break;
1959da2e3ebdSchin case SYMLPAR:
1960da2e3ebdSchin sym = LPAREN;
1961da2e3ebdSchin break;
1962da2e3ebdSchin case SYMSHARP:
1963da2e3ebdSchin sym = '#';
1964da2e3ebdSchin break;
1965da2e3ebdSchin case SYMSEMI:
1966da2e3ebdSchin if(tok[0]=='<')
1967da2e3ebdSchin tok[n++] = '>';
1968da2e3ebdSchin sym = ';';
1969da2e3ebdSchin break;
1970da2e3ebdSchin default:
1971da2e3ebdSchin sym = 0;
1972da2e3ebdSchin }
19737c2fbfb3SApril Chin tok[n++] = sym;
197434f9b3eeSRoland Mainz }
197534f9b3eeSRoland Mainz tok[n] = 0;
19767c2fbfb3SApril Chin return(tok);
19777c2fbfb3SApril Chin }
1978da2e3ebdSchin
1979da2e3ebdSchin /*
1980da2e3ebdSchin * print a bad syntax message
198134f9b3eeSRoland Mainz */
1982da2e3ebdSchin
sh_syntax(Lex_t * lp)198334f9b3eeSRoland Mainz void sh_syntax(Lex_t *lp)
1984da2e3ebdSchin {
1985da2e3ebdSchin register Shell_t *shp = lp->sh;
1986da2e3ebdSchin register const char *cp = sh_translate(e_unexpected);
1987da2e3ebdSchin register char *tokstr;
1988da2e3ebdSchin register int tok = lp->token;
1989da2e3ebdSchin char tokbuf[3];
1990da2e3ebdSchin Sfio_t *sp;
19917c2fbfb3SApril Chin if((tok==EOFSYM) && lp->lasttok)
1992da2e3ebdSchin {
19937c2fbfb3SApril Chin tok = lp->lasttok;
1994da2e3ebdSchin cp = sh_translate(e_unmatched);
1995da2e3ebdSchin }
19967c2fbfb3SApril Chin else
1997da2e3ebdSchin lp->lastline = shp->inlineno;
1998da2e3ebdSchin tokstr = fmttoken(lp,tok,tokbuf);
19997c2fbfb3SApril Chin if((sp=fcfile()) || (shp->infd>=0 && (sp=shp->sftable[shp->infd])))
2000da2e3ebdSchin {
20017c2fbfb3SApril Chin /* clear out any pending input */
2002da2e3ebdSchin register Sfio_t *top;
2003da2e3ebdSchin while(fcget()>0);
2004da2e3ebdSchin fcclose();
20057c2fbfb3SApril Chin while(top=sfstack(sp,SF_POPSTACK))
2006da2e3ebdSchin sfclose(top);
2007da2e3ebdSchin }
2008da2e3ebdSchin else
2009da2e3ebdSchin fcclose();
2010da2e3ebdSchin shp->inlineno = lp->inlineno;
2011da2e3ebdSchin shp->st.firstline = lp->firstline;
2012da2e3ebdSchin #if KSHELL
2013da2e3ebdSchin if(!sh_isstate(SH_INTERACTIVE) && !sh_isstate(SH_PROFILE))
2014da2e3ebdSchin #else
2015da2e3ebdSchin if(shp->inlineno!=1)
2016da2e3ebdSchin #endif
2017da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax1,lp->lastline,tokstr,cp);
20187c2fbfb3SApril Chin else
20197c2fbfb3SApril Chin errormsg(SH_DICT,ERROR_exit(SYNBAD),e_lexsyntax2,tokstr,cp);
2020da2e3ebdSchin }
2021da2e3ebdSchin
stack_shift(Stk_t * stkp,register char * sp,char * dp)2022da2e3ebdSchin static char *stack_shift(Stk_t *stkp, register char *sp,char *dp)
2023da2e3ebdSchin {
2024da2e3ebdSchin register char *ep;
20257c2fbfb3SApril Chin register int offset = stktell(stkp);
2026da2e3ebdSchin register int left = offset-(sp-stkptr(stkp,0));
2027da2e3ebdSchin register int shift = (dp+1-sp);
2028da2e3ebdSchin offset += shift;
2029da2e3ebdSchin stkseek(stkp,offset);
20307c2fbfb3SApril Chin sp = stkptr(stkp,offset);
2031da2e3ebdSchin ep = sp - shift;
2032da2e3ebdSchin while(left--)
20337c2fbfb3SApril Chin *--sp = *--ep;
20347c2fbfb3SApril Chin return(sp);
2035da2e3ebdSchin }
2036da2e3ebdSchin
20377c2fbfb3SApril Chin /*
20387c2fbfb3SApril Chin * Assumes that current word is unfrozen on top of the stak
2039da2e3ebdSchin * If <mode> is zero, gets rid of quoting and consider argument as string
2040da2e3ebdSchin * and returns pointer to frozen arg
2041da2e3ebdSchin * If mode==1, just replace $"..." strings with international strings
2042da2e3ebdSchin * The result is left on the stak
2043da2e3ebdSchin * If mode==2, the each $"" string is printed on standard output
2044da2e3ebdSchin */
sh_endword(Shell_t * shp,int mode)2045da2e3ebdSchin struct argnod *sh_endword(Shell_t *shp,int mode)
2046da2e3ebdSchin {
2047da2e3ebdSchin register const char *state = sh_lexstates[ST_NESTED];
2048da2e3ebdSchin register int n;
2049da2e3ebdSchin register char *sp,*dp;
2050da2e3ebdSchin register int inquote=0, inlit=0; /* set within quoted strings */
2051da2e3ebdSchin struct argnod* argp=0;
2052da2e3ebdSchin char *ep=0, *xp=0;
20537c2fbfb3SApril Chin int bracket=0;
2054da2e3ebdSchin Stk_t *stkp=shp->stk;
2055da2e3ebdSchin sfputc(stkp,0);
2056da2e3ebdSchin sp = stkptr(stkp,ARGVAL);
2057da2e3ebdSchin #if SHOPT_MULTIBYTE
2058da2e3ebdSchin if(mbwide())
2059da2e3ebdSchin {
2060da2e3ebdSchin do
2061da2e3ebdSchin {
20627c2fbfb3SApril Chin int len;
20637c2fbfb3SApril Chin switch(len = mbsize(sp))
20647c2fbfb3SApril Chin {
2065da2e3ebdSchin case -1: /* illegal multi-byte char */
2066da2e3ebdSchin case 0:
2067da2e3ebdSchin case 1:
2068da2e3ebdSchin n=state[*sp++];
2069da2e3ebdSchin break;
2070da2e3ebdSchin default:
2071da2e3ebdSchin /*
2072da2e3ebdSchin * None of the state tables contain
2073da2e3ebdSchin * entries for multibyte characters,
2074da2e3ebdSchin * however, they should be treated
2075da2e3ebdSchin * the same as any other alph
2076da2e3ebdSchin * character. Therefore, we'll use
2077da2e3ebdSchin * the state of the 'a' character.
2078da2e3ebdSchin */
2079da2e3ebdSchin n=state['a'];
2080da2e3ebdSchin sp += len;
2081da2e3ebdSchin }
2082da2e3ebdSchin }
2083da2e3ebdSchin while(n == 0);
2084da2e3ebdSchin }
2085da2e3ebdSchin else
2086da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2087da2e3ebdSchin while((n=state[*sp++])==0);
2088da2e3ebdSchin dp = sp;
2089da2e3ebdSchin if(mode<0)
2090da2e3ebdSchin inquote = 1;
2091da2e3ebdSchin while(1)
2092da2e3ebdSchin {
2093da2e3ebdSchin switch(n)
2094da2e3ebdSchin {
2095da2e3ebdSchin case S_EOF:
2096da2e3ebdSchin stkseek(stkp,dp-stkptr(stkp,0));
2097da2e3ebdSchin if(mode<=0)
2098da2e3ebdSchin {
2099da2e3ebdSchin argp = (struct argnod*)stkfreeze(stkp,0);
2100da2e3ebdSchin argp->argflag = ARG_RAW|ARG_QUOTED;
2101da2e3ebdSchin }
2102da2e3ebdSchin return(argp);
2103da2e3ebdSchin case S_LIT:
21047c2fbfb3SApril Chin if(!(inquote&1))
2105da2e3ebdSchin {
2106da2e3ebdSchin inlit = !inlit;
21077c2fbfb3SApril Chin if(mode==0 || (mode<0 && bracket))
2108da2e3ebdSchin {
2109da2e3ebdSchin dp--;
2110da2e3ebdSchin if(ep)
2111da2e3ebdSchin {
2112da2e3ebdSchin *dp = 0;
2113da2e3ebdSchin dp = ep+stresc(ep);
2114da2e3ebdSchin }
2115da2e3ebdSchin ep = 0;
2116da2e3ebdSchin }
2117da2e3ebdSchin }
2118da2e3ebdSchin break;
2119da2e3ebdSchin case S_QUOTE:
2120da2e3ebdSchin if(mode<0 && !bracket)
2121da2e3ebdSchin break;
2122da2e3ebdSchin if(!inlit)
2123da2e3ebdSchin {
2124da2e3ebdSchin if(mode<=0)
2125da2e3ebdSchin dp--;
2126da2e3ebdSchin inquote = inquote^1;
2127da2e3ebdSchin if(ep)
2128da2e3ebdSchin {
2129da2e3ebdSchin char *msg;
2130da2e3ebdSchin if(mode==2)
2131da2e3ebdSchin {
2132da2e3ebdSchin sfprintf(sfstdout,"%.*s\n",dp-ep,ep);
2133da2e3ebdSchin ep = 0;
2134da2e3ebdSchin break;
2135da2e3ebdSchin }
2136da2e3ebdSchin *--dp = 0;
2137da2e3ebdSchin #if ERROR_VERSION >= 20000317L
2138da2e3ebdSchin msg = ERROR_translate(0,error_info.id,0,ep);
2139da2e3ebdSchin #else
2140da2e3ebdSchin # if ERROR_VERSION >= 20000101L
2141da2e3ebdSchin msg = ERROR_translate(error_info.id,ep);
2142da2e3ebdSchin # else
2143da2e3ebdSchin msg = ERROR_translate(ep,2);
2144da2e3ebdSchin # endif
2145da2e3ebdSchin #endif
2146da2e3ebdSchin n = strlen(msg);
2147da2e3ebdSchin dp = ep+n;
2148da2e3ebdSchin if(sp-dp <= 1)
2149da2e3ebdSchin {
2150da2e3ebdSchin sp = stack_shift(stkp,sp,dp);
2151da2e3ebdSchin dp = sp-1;
2152da2e3ebdSchin ep = dp-n;
2153da2e3ebdSchin }
2154da2e3ebdSchin memmove(ep,msg,n);
2155da2e3ebdSchin *dp++ = '"';
2156da2e3ebdSchin }
2157da2e3ebdSchin ep = 0;
21587c2fbfb3SApril Chin }
2159da2e3ebdSchin break;
2160da2e3ebdSchin case S_DOL: /* check for $'...' and $"..." */
2161da2e3ebdSchin if(inlit)
2162da2e3ebdSchin break;
2163da2e3ebdSchin if(*sp==LPAREN || *sp==LBRACE)
2164da2e3ebdSchin {
2165da2e3ebdSchin inquote <<= 1;
2166da2e3ebdSchin break;
2167da2e3ebdSchin }
2168da2e3ebdSchin if(inquote&1)
2169da2e3ebdSchin break;
2170da2e3ebdSchin if(*sp=='\'' || *sp=='"')
2171da2e3ebdSchin {
2172da2e3ebdSchin if(*sp=='"')
2173da2e3ebdSchin inquote |= 1;
2174da2e3ebdSchin else
2175da2e3ebdSchin inlit = 1;
2176da2e3ebdSchin sp++;
2177da2e3ebdSchin if((mode==0||(mode<0&&bracket)) || (inquote&1))
2178da2e3ebdSchin {
2179da2e3ebdSchin if(mode==2)
2180da2e3ebdSchin ep = dp++;
2181da2e3ebdSchin else if(mode==1)
2182da2e3ebdSchin (ep=dp)[-1] = '"';
2183da2e3ebdSchin else
2184da2e3ebdSchin ep = --dp;
2185da2e3ebdSchin }
2186da2e3ebdSchin }
2187da2e3ebdSchin break;
2188da2e3ebdSchin case S_ESC:
2189da2e3ebdSchin #if SHOPT_CRNL
2190da2e3ebdSchin if(*sp=='\r' && sp[1]=='\n')
2191da2e3ebdSchin sp++;
2192da2e3ebdSchin #endif /* SHOPT_CRNL */
2193da2e3ebdSchin if(inlit || mode>0)
2194da2e3ebdSchin {
2195da2e3ebdSchin if(mode<0)
2196da2e3ebdSchin {
2197da2e3ebdSchin if(dp>=sp)
2198da2e3ebdSchin {
2199da2e3ebdSchin sp = stack_shift(stkp,sp,dp+1);
2200da2e3ebdSchin dp = sp-2;
2201da2e3ebdSchin }
2202da2e3ebdSchin *dp++ = '\\';
2203da2e3ebdSchin }
2204da2e3ebdSchin if(ep)
2205da2e3ebdSchin *dp++ = *sp++;
2206da2e3ebdSchin break;
22077c2fbfb3SApril Chin }
2208da2e3ebdSchin n = *sp;
2209da2e3ebdSchin #if SHOPT_DOS
2210da2e3ebdSchin if(!(inquote&1) && sh_lexstates[ST_NORM][n]==0)
2211da2e3ebdSchin break;
2212da2e3ebdSchin #endif /* SHOPT_DOS */
2213da2e3ebdSchin if(!(inquote&1) || (sh_lexstates[ST_QUOTE][n] && n!=RBRACE))
2214da2e3ebdSchin {
2215da2e3ebdSchin if(n=='\n')
2216da2e3ebdSchin dp--;
2217da2e3ebdSchin else
2218da2e3ebdSchin dp[-1] = n;
2219da2e3ebdSchin sp++;
2220da2e3ebdSchin }
2221da2e3ebdSchin break;
2222da2e3ebdSchin case S_POP:
2223da2e3ebdSchin if(sp[-1]!=RBRACT)
2224da2e3ebdSchin break;
2225da2e3ebdSchin if(!inlit && !(inquote&1))
2226da2e3ebdSchin {
2227da2e3ebdSchin inquote >>= 1;
2228da2e3ebdSchin if(xp)
2229da2e3ebdSchin dp = sh_checkid(xp,dp);
2230da2e3ebdSchin xp = 0;
2231da2e3ebdSchin if(--bracket<=0 && mode<0)
2232da2e3ebdSchin inquote = 1;
2233da2e3ebdSchin }
2234da2e3ebdSchin else if((inlit||inquote) && mode<0)
2235da2e3ebdSchin {
2236da2e3ebdSchin dp[-1] = '\\';
2237da2e3ebdSchin if(dp>=sp)
2238da2e3ebdSchin {
2239da2e3ebdSchin sp = stack_shift(stkp,sp,dp);
2240da2e3ebdSchin dp = sp-1;
2241da2e3ebdSchin }
2242da2e3ebdSchin *dp++ = ']';
2243da2e3ebdSchin }
2244da2e3ebdSchin break;
2245da2e3ebdSchin case S_BRACT:
2246da2e3ebdSchin if(dp[-2]=='.')
22477c2fbfb3SApril Chin xp = dp;
2248da2e3ebdSchin if(mode<0)
2249da2e3ebdSchin {
2250da2e3ebdSchin if(inlit || (bracket&&inquote))
2251da2e3ebdSchin {
2252da2e3ebdSchin dp[-1] = '\\';
2253da2e3ebdSchin if(dp>=sp)
2254da2e3ebdSchin {
2255da2e3ebdSchin sp = stack_shift(stkp,sp,dp);
2256da2e3ebdSchin dp = sp-1;
2257da2e3ebdSchin }
2258da2e3ebdSchin *dp++ = '[';
2259da2e3ebdSchin }
2260da2e3ebdSchin else if(bracket++==0)
2261da2e3ebdSchin inquote = 0;
2262da2e3ebdSchin }
22637c2fbfb3SApril Chin break;
2264da2e3ebdSchin }
2265da2e3ebdSchin #if SHOPT_MULTIBYTE
2266da2e3ebdSchin if(mbwide())
2267da2e3ebdSchin {
2268da2e3ebdSchin do
2269da2e3ebdSchin {
2270da2e3ebdSchin int len;
2271da2e3ebdSchin switch(len = mbsize(sp))
2272da2e3ebdSchin {
2273da2e3ebdSchin case -1: /* illegal multi-byte char */
2274da2e3ebdSchin case 0:
2275da2e3ebdSchin case 1:
2276da2e3ebdSchin n=state[*dp++ = *sp++];
2277da2e3ebdSchin break;
2278da2e3ebdSchin default:
2279da2e3ebdSchin /*
2280da2e3ebdSchin * None of the state tables contain
2281da2e3ebdSchin * entries for multibyte characters,
2282da2e3ebdSchin * however, they should be treated
2283da2e3ebdSchin * the same as any other alph
2284da2e3ebdSchin * character. Therefore, we'll use
2285da2e3ebdSchin * the state of the 'a' character.
2286da2e3ebdSchin */
2287da2e3ebdSchin while(len--)
2288da2e3ebdSchin *dp++ = *sp++;
2289da2e3ebdSchin n=state['a'];
2290da2e3ebdSchin }
2291da2e3ebdSchin }
2292da2e3ebdSchin while(n == 0);
2293da2e3ebdSchin }
2294da2e3ebdSchin else
2295da2e3ebdSchin #endif /* SHOPT_MULTIBYTE */
2296da2e3ebdSchin while((n=state[*dp++ = *sp++])==0);
2297da2e3ebdSchin }
2298da2e3ebdSchin }
2299da2e3ebdSchin
2300da2e3ebdSchin struct alias
2301da2e3ebdSchin {
2302da2e3ebdSchin Sfdisc_t disc;
2303da2e3ebdSchin Namval_t *np;
2304da2e3ebdSchin int nextc;
2305da2e3ebdSchin int line;
2306da2e3ebdSchin char buf[2];
2307da2e3ebdSchin Lex_t *lp;
2308da2e3ebdSchin };
2309da2e3ebdSchin
2310da2e3ebdSchin /*
2311da2e3ebdSchin * This code gets called whenever an end of string is found with alias
2312da2e3ebdSchin */
2313da2e3ebdSchin
2314da2e3ebdSchin #ifndef SF_ATEXIT
2315da2e3ebdSchin # define SF_ATEXIT 0
2316da2e3ebdSchin #endif
2317da2e3ebdSchin /*
2318da2e3ebdSchin * This code gets called whenever an end of string is found with alias
2319da2e3ebdSchin */
2320da2e3ebdSchin #ifdef SF_BUFCONST
alias_exceptf(Sfio_t * iop,int type,void * data,Sfdisc_t * handle)2321da2e3ebdSchin static int alias_exceptf(Sfio_t *iop,int type,void *data, Sfdisc_t *handle)
2322da2e3ebdSchin #else
2323da2e3ebdSchin static int alias_exceptf(Sfio_t *iop,int type,Sfdisc_t *handle)
2324da2e3ebdSchin #endif
2325da2e3ebdSchin {
2326da2e3ebdSchin register struct alias *ap = (struct alias*)handle;
2327da2e3ebdSchin register Namval_t *np;
2328da2e3ebdSchin register Lex_t *lp;
2329da2e3ebdSchin if(type==0 || type==SF_ATEXIT || !ap)
2330da2e3ebdSchin return(0);
2331da2e3ebdSchin lp = ap->lp;
2332da2e3ebdSchin np = ap->np;
2333da2e3ebdSchin if(type!=SF_READ)
2334da2e3ebdSchin {
2335da2e3ebdSchin if(type==SF_CLOSING)
2336da2e3ebdSchin {
2337da2e3ebdSchin register Sfdisc_t *dp = sfdisc(iop,SF_POPDISC);
2338da2e3ebdSchin if(dp!=handle)
2339da2e3ebdSchin sfdisc(iop,dp);
2340da2e3ebdSchin }
2341da2e3ebdSchin else if(type==SF_FINAL)
2342da2e3ebdSchin free((void*)ap);
2343da2e3ebdSchin goto done;
2344da2e3ebdSchin }
2345da2e3ebdSchin if(ap->nextc)
2346da2e3ebdSchin {
2347da2e3ebdSchin /* if last character is a blank, then next work can be alias */
2348da2e3ebdSchin register int c = fcpeek(-1);
2349da2e3ebdSchin if(isblank(c))
2350da2e3ebdSchin lp->aliasok = 1;
2351da2e3ebdSchin *ap->buf = ap->nextc;
2352da2e3ebdSchin ap->nextc = 0;
2353da2e3ebdSchin sfsetbuf(iop,ap->buf,1);
2354da2e3ebdSchin return(1);
2355da2e3ebdSchin }
2356da2e3ebdSchin done:
2357da2e3ebdSchin if(np)
23587c2fbfb3SApril Chin nv_offattr(np,NV_NOEXPAND);
2359da2e3ebdSchin return(0);
2360da2e3ebdSchin }
2361da2e3ebdSchin
2362da2e3ebdSchin
setupalias(Lex_t * lp,const char * string,Namval_t * np)2363da2e3ebdSchin static void setupalias(Lex_t *lp, const char *string,Namval_t *np)
2364da2e3ebdSchin {
2365da2e3ebdSchin register Sfio_t *iop, *base;
2366da2e3ebdSchin struct alias *ap = (struct alias*)malloc(sizeof(struct alias));
2367da2e3ebdSchin ap->disc = alias_disc;
2368da2e3ebdSchin ap->lp = lp;
2369da2e3ebdSchin ap->buf[1] = 0;
2370da2e3ebdSchin if(ap->np = np)
2371da2e3ebdSchin {
2372da2e3ebdSchin #if SHOPT_KIA
2373da2e3ebdSchin if(lp->kiafile)
2374da2e3ebdSchin {
2375da2e3ebdSchin unsigned long r;
2376da2e3ebdSchin r=kiaentity(lp,nv_name(np),-1,'p',0,0,lp->current,'a',0,"");
2377da2e3ebdSchin sfprintf(lp->kiatmp,"p;%..64d;p;%..64d;%d;%d;e;\n",lp->current,r,lp->sh->inlineno,lp->sh->inlineno);
2378da2e3ebdSchin }
2379da2e3ebdSchin #endif /* SHOPT_KIA */
2380da2e3ebdSchin if((ap->nextc=fcget())==0)
23817c2fbfb3SApril Chin ap->nextc = ' ';
2382da2e3ebdSchin }
2383da2e3ebdSchin else
23847c2fbfb3SApril Chin ap->nextc = 0;
23857c2fbfb3SApril Chin iop = sfopen(NIL(Sfio_t*),(char*)string,"s");
2386da2e3ebdSchin sfdisc(iop, &ap->disc);
2387da2e3ebdSchin lp->lexd.nocopy++;
2388da2e3ebdSchin if(!(base=fcfile()))
2389da2e3ebdSchin base = sfopen(NIL(Sfio_t*),fcseek(0),"s");
2390da2e3ebdSchin fcclose();
2391da2e3ebdSchin sfstack(base,iop);
2392da2e3ebdSchin fcfopen(base);
2393da2e3ebdSchin lp->lexd.nocopy--;
2394da2e3ebdSchin }
23957c2fbfb3SApril Chin
2396da2e3ebdSchin /*
2397da2e3ebdSchin * grow storage stack for nested constructs by STACK_ARRAY
2398da2e3ebdSchin */
stack_grow(Lex_t * lp)2399da2e3ebdSchin static int stack_grow(Lex_t *lp)
2400da2e3ebdSchin {
24017c2fbfb3SApril Chin lp->lexd.lex_max += STACK_ARRAY;
2402da2e3ebdSchin if(lp->lexd.lex_match)
2403da2e3ebdSchin lp->lexd.lex_match = (int*)realloc((char*)lp->lexd.lex_match,sizeof(int)*lp->lexd.lex_max);
2404da2e3ebdSchin else
2405da2e3ebdSchin lp->lexd.lex_match = (int*)malloc(sizeof(int)*STACK_ARRAY);
2406da2e3ebdSchin return(lp->lexd.lex_match!=0);
2407da2e3ebdSchin }
2408da2e3ebdSchin
24097c2fbfb3SApril Chin