Blob


1 #include "rc.h"
2 #include "exec.h"
3 #include "io.h"
4 #include "getflags.h"
5 #include "fns.h"
6 int getnext(void);
8 int
9 wordchr(int c)
10 {
11 return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
12 }
14 int
15 idchr(int c)
16 {
17 /*
18 * Formerly:
19 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
20 * || c=='_' || c=='*';
21 */
22 return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
23 }
24 int future = EOF;
25 int doprompt = 1;
26 int inquote;
27 int incomm;
28 /*
29 * Look ahead in the input stream
30 */
32 int
33 nextc(void)
34 {
35 if(future==EOF)
36 future = getnext();
37 return future;
38 }
39 /*
40 * Consume the lookahead character.
41 */
43 int
44 advance(void)
45 {
46 int c = nextc();
47 lastc = future;
48 future = EOF;
49 return c;
50 }
51 /*
52 * read a character from the input stream
53 */
55 int
56 getnext(void)
57 {
58 int c;
59 static int peekc = EOF;
60 if(peekc!=EOF){
61 c = peekc;
62 peekc = EOF;
63 return c;
64 }
65 if(runq->eof)
66 return EOF;
67 if(doprompt)
68 pprompt();
69 c = rchr(runq->cmdfd);
70 if(!inquote && c=='\\'){
71 c = rchr(runq->cmdfd);
72 if(c=='\n' && !incomm){ /* don't continue a comment */
73 doprompt = 1;
74 c=' ';
75 }
76 else{
77 peekc = c;
78 c='\\';
79 }
80 }
81 doprompt = doprompt || c=='\n' || c==EOF;
82 if(c==EOF)
83 runq->eof++;
84 else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
85 return c;
86 }
88 void
89 pprompt(void)
90 {
91 var *prompt;
92 if(runq->iflag){
93 pstr(err, promptstr);
94 flush(err);
95 prompt = vlook("prompt");
96 if(prompt->val && prompt->val->next)
97 promptstr = prompt->val->next->word;
98 else
99 promptstr="\t";
101 runq->lineno++;
102 doprompt = 0;
105 void
106 skipwhite(void)
108 int c;
109 for(;;){
110 c = nextc();
111 /* Why did this used to be if(!inquote && c=='#') ?? */
112 if(c=='#'){
113 incomm = 1;
114 for(;;){
115 c = nextc();
116 if(c=='\n' || c==EOF) {
117 incomm = 0;
118 break;
120 advance();
123 if(c==' ' || c=='\t')
124 advance();
125 else return;
129 void
130 skipnl(void)
132 int c;
133 for(;;){
134 skipwhite();
135 c = nextc();
136 if(c!='\n')
137 return;
138 advance();
142 int
143 nextis(int c)
145 if(nextc()==c){
146 advance();
147 return 1;
149 return 0;
152 char*
153 addtok(char *p, int val)
155 if(p==0)
156 return 0;
157 if(p==&tok[NTOK-1]){
158 *p = 0;
159 yyerror("token buffer too short");
160 return 0;
162 *p++=val;
163 return p;
166 char*
167 addutf(char *p, int c)
169 p = addtok(p, c);
170 if(twobyte(c)) /* 2-byte escape */
171 return addtok(p, advance());
172 if(threebyte(c)){ /* 3-byte escape */
173 p = addtok(p, advance());
174 return addtok(p, advance());
176 if(fourbyte(c)){ /* 4-byte escape */
177 p = addtok(p, advance());
178 p = addtok(p, advance());
179 return addtok(p, advance());
181 return p;
183 int lastdol; /* was the last token read '$' or '$#' or '"'? */
184 int lastword; /* was the last token read a word or compound word terminator? */
186 int
187 yylex(void)
189 int c, d = nextc();
190 char *w = tok;
191 struct tree *t;
192 yylval.tree = 0;
193 /*
194 * Embarassing sneakiness: if the last token read was a quoted or unquoted
195 * WORD then we alter the meaning of what follows. If the next character
196 * is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
197 * if the next character is the first character of a simple or compound word,
198 * we insert a `^' before it.
199 */
200 if(lastword){
201 lastword = 0;
202 if(d=='('){
203 advance();
204 strcpy(tok, "( [SUB]");
205 return SUB;
207 if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
208 strcpy(tok, "^");
209 return '^';
212 inquote = 0;
213 skipwhite();
214 switch(c = advance()){
215 case EOF:
216 lastdol = 0;
217 strcpy(tok, "EOF");
218 return EOF;
219 case '$':
220 lastdol = 1;
221 if(nextis('#')){
222 strcpy(tok, "$#");
223 return COUNT;
225 if(nextis('"')){
226 strcpy(tok, "$\"");
227 return '"';
229 strcpy(tok, "$");
230 return '$';
231 case '&':
232 lastdol = 0;
233 if(nextis('&')){
234 skipnl();
235 strcpy(tok, "&&");
236 return ANDAND;
238 strcpy(tok, "&");
239 return '&';
240 case '|':
241 lastdol = 0;
242 if(nextis(c)){
243 skipnl();
244 strcpy(tok, "||");
245 return OROR;
247 case '<':
248 case '>':
249 lastdol = 0;
250 /*
251 * funny redirection tokens:
252 * redir: arrow | arrow '[' fd ']'
253 * arrow: '<' | '<<' | '>' | '>>' | '|'
254 * fd: digit | digit '=' | digit '=' digit
255 * digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
256 * some possibilities are nonsensical and get a message.
257 */
258 *w++=c;
259 t = newtree();
260 switch(c){
261 case '|':
262 t->type = PIPE;
263 t->fd0 = 1;
264 t->fd1 = 0;
265 break;
266 case '>':
267 t->type = REDIR;
268 if(nextis(c)){
269 t->rtype = APPEND;
270 *w++=c;
272 else t->rtype = WRITE;
273 t->fd0 = 1;
274 break;
275 case '<':
276 t->type = REDIR;
277 if(nextis(c)){
278 t->rtype = HERE;
279 *w++=c;
280 } else if (nextis('>')){
281 t->rtype = RDWR;
282 *w++=c;
283 } else t->rtype = READ;
284 t->fd0 = 0;
285 break;
287 if(nextis('[')){
288 *w++='[';
289 c = advance();
290 *w++=c;
291 if(c<'0' || '9'<c){
292 RedirErr:
293 *w = 0;
294 yyerror(t->type==PIPE?"pipe syntax"
295 :"redirection syntax");
296 return EOF;
298 t->fd0 = 0;
299 do{
300 t->fd0 = t->fd0*10+c-'0';
301 *w++=c;
302 c = advance();
303 }while('0'<=c && c<='9');
304 if(c=='='){
305 *w++='=';
306 if(t->type==REDIR)
307 t->type = DUP;
308 c = advance();
309 if('0'<=c && c<='9'){
310 t->rtype = DUPFD;
311 t->fd1 = t->fd0;
312 t->fd0 = 0;
313 do{
314 t->fd0 = t->fd0*10+c-'0';
315 *w++=c;
316 c = advance();
317 }while('0'<=c && c<='9');
319 else{
320 if(t->type==PIPE)
321 goto RedirErr;
322 t->rtype = CLOSE;
325 if(c!=']'
326 || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
327 goto RedirErr;
328 *w++=']';
330 *w='\0';
331 yylval.tree = t;
332 if(t->type==PIPE)
333 skipnl();
334 return t->type;
335 case '\'':
336 lastdol = 0;
337 lastword = 1;
338 inquote = 1;
339 for(;;){
340 c = advance();
341 if(c==EOF)
342 break;
343 if(c=='\''){
344 if(nextc()!='\'')
345 break;
346 advance();
348 w = addutf(w, c);
350 if(w!=0)
351 *w='\0';
352 t = token(tok, WORD);
353 t->quoted = 1;
354 yylval.tree = t;
355 return t->type;
357 if(!wordchr(c)){
358 lastdol = 0;
359 tok[0] = c;
360 tok[1]='\0';
361 return c;
363 for(;;){
364 /* next line should have (char)c==GLOB, but ken's compiler is broken */
365 if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
366 w = addtok(w, GLOB);
367 w = addutf(w, c);
368 c = nextc();
369 if(lastdol?!idchr(c):!wordchr(c)) break;
370 advance();
373 lastword = 1;
374 lastdol = 0;
375 if(w!=0)
376 *w='\0';
377 t = klook(tok);
378 if(t->type!=WORD)
379 lastword = 0;
380 t->quoted = 0;
381 yylval.tree = t;
382 return t->type;