|
1 // lex.c - lexical analysis |
|
2 // |
|
3 // © Portions Copyright (c) Symbian Software Ltd 2007-2008. All rights reserved. |
|
4 // |
|
5 /* |
|
6 * This file is part of zsh, the Z shell. |
|
7 * |
|
8 * Copyright (c) 1992-1997 Paul Falstad |
|
9 * All rights reserved. |
|
10 * |
|
11 * Permission is hereby granted, without written agreement and without |
|
12 * license or royalty fees, to use, copy, modify, and distribute this |
|
13 * software and to distribute modified versions of this software for any |
|
14 * purpose, provided that the above copyright notice and the following |
|
15 * two paragraphs appear in all copies of this software. |
|
16 * |
|
17 * In no event shall Paul Falstad or the Zsh Development Group be liable |
|
18 * to any party for direct, indirect, special, incidental, or consequential |
|
19 * damages arising out of the use of this software and its documentation, |
|
20 * even if Paul Falstad and the Zsh Development Group have been advised of |
|
21 * the possibility of such damage. |
|
22 * |
|
23 * Paul Falstad and the Zsh Development Group specifically disclaim any |
|
24 * warranties, including, but not limited to, the implied warranties of |
|
25 * merchantability and fitness for a particular purpose. The software |
|
26 * provided hereunder is on an "as is" basis, and Paul Falstad and the |
|
27 * Zsh Development Group have no obligation to provide maintenance, |
|
28 * support, updates, enhancements, or modifications. |
|
29 * |
|
30 */ |
|
31 |
|
32 #include "zsh.mdh" |
|
33 #include "lex.pro" |
|
34 |
|
35 #ifdef __SYMBIAN32__ |
|
36 #ifdef __WINSCW__ |
|
37 #pragma warn_unusedarg off |
|
38 #pragma warn_possunwant off |
|
39 #endif//__WINSCW__ |
|
40 #endif//__SYMBIAN32__ |
|
41 |
|
42 /* tokens */ |
|
43 |
|
44 /**/ |
|
45 mod_export char ztokens[] = "#$^*()$=|{}[]`<>?~`,'\"\\"; |
|
46 |
|
47 /* parts of the current token */ |
|
48 |
|
49 /**/ |
|
50 char *yytext; |
|
51 /**/ |
|
52 mod_export char *tokstr; |
|
53 /**/ |
|
54 mod_export int tok; |
|
55 /**/ |
|
56 mod_export int tokfd; |
|
57 |
|
58 /* lexical analyzer error flag */ |
|
59 |
|
60 /**/ |
|
61 mod_export int lexstop; |
|
62 |
|
63 /* if != 0, this is the first line of the command */ |
|
64 |
|
65 /**/ |
|
66 mod_export int isfirstln; |
|
67 |
|
68 /* if != 0, this is the first char of the command (not including white space) */ |
|
69 |
|
70 /**/ |
|
71 int isfirstch; |
|
72 |
|
73 /* flag that an alias should be expanded after expansion ending in space */ |
|
74 |
|
75 /**/ |
|
76 int inalmore; |
|
77 |
|
78 /* don't do spelling correction */ |
|
79 |
|
80 /**/ |
|
81 int nocorrect; |
|
82 |
|
83 /* the line buffer */ |
|
84 |
|
85 /**/ |
|
86 mod_export unsigned char *line; |
|
87 |
|
88 /* cursor position and line length */ |
|
89 /* N.B.: must use the real names here, for the .export file */ |
|
90 |
|
91 /**/ |
|
92 mod_export int zshcs, zshll; |
|
93 |
|
94 /* inwhat says what exactly we are in * |
|
95 * (its value is one of the IN_* things). */ |
|
96 |
|
97 /**/ |
|
98 mod_export int inwhat; |
|
99 |
|
100 /* 1 if x added to complete in a blank between words */ |
|
101 |
|
102 /**/ |
|
103 mod_export int addedx; |
|
104 |
|
105 /* wb and we hold the beginning/end position of the word we are completing. */ |
|
106 |
|
107 /**/ |
|
108 mod_export int wb, we; |
|
109 |
|
110 /* 1 if aliases should not be expanded */ |
|
111 |
|
112 /**/ |
|
113 mod_export int noaliases; |
|
114 |
|
115 /* we are parsing a line sent to use by the editor */ |
|
116 |
|
117 /**/ |
|
118 mod_export int zleparse; |
|
119 |
|
120 /**/ |
|
121 mod_export int wordbeg; |
|
122 |
|
123 /**/ |
|
124 mod_export int parbegin; |
|
125 |
|
126 /**/ |
|
127 mod_export int parend; |
|
128 |
|
129 /* don't recognize comments */ |
|
130 |
|
131 /**/ |
|
132 mod_export int nocomments; |
|
133 |
|
134 /* text of punctuation tokens */ |
|
135 |
|
136 /**/ |
|
137 mod_export char *tokstrings[WHILE + 1] = { |
|
138 NULL, /* NULLTOK 0 */ |
|
139 ";", /* SEPER */ |
|
140 "\\n", /* NEWLIN */ |
|
141 ";", /* SEMI */ |
|
142 ";;", /* DSEMI */ |
|
143 "&", /* AMPER 5 */ |
|
144 "(", /* INPAR */ |
|
145 ")", /* OUTPAR */ |
|
146 "||", /* DBAR */ |
|
147 "&&", /* DAMPER */ |
|
148 ">", /* OUTANG 10 */ |
|
149 ">|", /* OUTANGBANG */ |
|
150 ">>", /* DOUTANG */ |
|
151 ">>|", /* DOUTANGBANG */ |
|
152 "<", /* INANG */ |
|
153 "<>", /* INOUTANG 15 */ |
|
154 "<<", /* DINANG */ |
|
155 "<<-", /* DINANGDASH */ |
|
156 "<&", /* INANGAMP */ |
|
157 ">&", /* OUTANGAMP */ |
|
158 "&>", /* AMPOUTANG 20 */ |
|
159 "&>|", /* OUTANGAMPBANG */ |
|
160 ">>&", /* DOUTANGAMP */ |
|
161 ">>&|", /* DOUTANGAMPBANG */ |
|
162 "<<<", /* TRINANG */ |
|
163 "|", /* BAR 25 */ |
|
164 "|&", /* BARAMP */ |
|
165 "()", /* INOUTPAR */ |
|
166 "((", /* DINPAR */ |
|
167 "))", /* DOUTPAR */ |
|
168 "&|", /* AMPERBANG 30 */ |
|
169 ";&", /* SEMIAMP */ |
|
170 }; |
|
171 |
|
172 /* lexical state */ |
|
173 |
|
174 static int dbparens; |
|
175 static int len = 0, bsiz = 256; |
|
176 static char *bptr; |
|
177 |
|
178 struct lexstack { |
|
179 struct lexstack *next; |
|
180 |
|
181 int incmdpos; |
|
182 int incond; |
|
183 int incasepat; |
|
184 int dbparens; |
|
185 int isfirstln; |
|
186 int isfirstch; |
|
187 int histactive; |
|
188 int histdone; |
|
189 int stophist; |
|
190 int hlinesz; |
|
191 char *hline; |
|
192 char *hptr; |
|
193 int tok; |
|
194 int isnewlin; |
|
195 char *tokstr; |
|
196 char *yytext; |
|
197 char *bptr; |
|
198 int bsiz; |
|
199 int len; |
|
200 short *chwords; |
|
201 int chwordlen; |
|
202 int chwordpos; |
|
203 int hwgetword; |
|
204 int lexstop; |
|
205 struct heredocs *hdocs; |
|
206 int (*hgetc) _((void)); |
|
207 void (*hungetc) _((int)); |
|
208 void (*hwaddc) _((int)); |
|
209 void (*hwbegin) _((int)); |
|
210 void (*hwend) _((void)); |
|
211 void (*addtoline) _((int)); |
|
212 |
|
213 int eclen, ecused, ecnpats; |
|
214 Wordcode ecbuf; |
|
215 Eccstr ecstrs; |
|
216 int ecsoffs, ecssub, ecnfunc; |
|
217 |
|
218 unsigned char *cstack; |
|
219 int csp; |
|
220 }; |
|
221 |
|
222 static struct lexstack *lstack = NULL; |
|
223 |
|
224 /* save the lexical state */ |
|
225 |
|
226 /* is this a hack or what? */ |
|
227 |
|
228 /**/ |
|
229 mod_export void |
|
230 lexsave(void) |
|
231 { |
|
232 struct lexstack *ls; |
|
233 |
|
234 ls = (struct lexstack *)malloc(sizeof(struct lexstack)); |
|
235 |
|
236 ls->incmdpos = incmdpos; |
|
237 ls->incond = incond; |
|
238 ls->incasepat = incasepat; |
|
239 ls->dbparens = dbparens; |
|
240 ls->isfirstln = isfirstln; |
|
241 ls->isfirstch = isfirstch; |
|
242 ls->histactive = histactive; |
|
243 ls->histdone = histdone; |
|
244 ls->stophist = stophist; |
|
245 ls->hline = chline; |
|
246 ls->hptr = hptr; |
|
247 ls->hlinesz = hlinesz; |
|
248 ls->cstack = cmdstack; |
|
249 ls->csp = cmdsp; |
|
250 cmdstack = (unsigned char *)zalloc(CMDSTACKSZ); |
|
251 ls->tok = tok; |
|
252 ls->isnewlin = isnewlin; |
|
253 ls->tokstr = tokstr; |
|
254 ls->yytext = yytext; |
|
255 ls->bptr = bptr; |
|
256 ls->bsiz = bsiz; |
|
257 ls->len = len; |
|
258 ls->chwords = chwords; |
|
259 ls->chwordlen = chwordlen; |
|
260 ls->chwordpos = chwordpos; |
|
261 ls->hwgetword = hwgetword; |
|
262 ls->lexstop = lexstop; |
|
263 ls->hdocs = hdocs; |
|
264 ls->hgetc = hgetc; |
|
265 ls->hungetc = hungetc; |
|
266 ls->hwaddc = hwaddc; |
|
267 ls->hwbegin = hwbegin; |
|
268 ls->hwend = hwend; |
|
269 ls->addtoline = addtoline; |
|
270 ls->eclen = eclen; |
|
271 ls->ecused = ecused; |
|
272 ls->ecnpats = ecnpats; |
|
273 ls->ecbuf = ecbuf; |
|
274 ls->ecstrs = ecstrs; |
|
275 ls->ecsoffs = ecsoffs; |
|
276 ls->ecssub = ecssub; |
|
277 ls->ecnfunc = ecnfunc; |
|
278 cmdsp = 0; |
|
279 inredir = 0; |
|
280 hdocs = NULL; |
|
281 histactive = 0; |
|
282 ecbuf = NULL; |
|
283 |
|
284 ls->next = lstack; |
|
285 lstack = ls; |
|
286 } |
|
287 |
|
288 /* restore lexical state */ |
|
289 |
|
290 /**/ |
|
291 mod_export void |
|
292 lexrestore(void) |
|
293 { |
|
294 struct lexstack *ln; |
|
295 |
|
296 DPUTS(!lstack, "BUG: lexrestore() without lexsave()"); |
|
297 incmdpos = lstack->incmdpos; |
|
298 incond = lstack->incond; |
|
299 incasepat = lstack->incasepat; |
|
300 dbparens = lstack->dbparens; |
|
301 isfirstln = lstack->isfirstln; |
|
302 isfirstch = lstack->isfirstch; |
|
303 histactive = lstack->histactive; |
|
304 histdone = lstack->histdone; |
|
305 stophist = lstack->stophist; |
|
306 chline = lstack->hline; |
|
307 hptr = lstack->hptr; |
|
308 if (cmdstack) |
|
309 free(cmdstack); |
|
310 cmdstack = lstack->cstack; |
|
311 cmdsp = lstack->csp; |
|
312 tok = lstack->tok; |
|
313 isnewlin = lstack->isnewlin; |
|
314 tokstr = lstack->tokstr; |
|
315 yytext = lstack->yytext; |
|
316 bptr = lstack->bptr; |
|
317 bsiz = lstack->bsiz; |
|
318 len = lstack->len; |
|
319 chwords = lstack->chwords; |
|
320 chwordlen = lstack->chwordlen; |
|
321 chwordpos = lstack->chwordpos; |
|
322 hwgetword = lstack->hwgetword; |
|
323 lexstop = lstack->lexstop; |
|
324 hdocs = lstack->hdocs; |
|
325 hgetc = lstack->hgetc; |
|
326 hungetc = lstack->hungetc; |
|
327 hwaddc = lstack->hwaddc; |
|
328 hwbegin = lstack->hwbegin; |
|
329 hwend = lstack->hwend; |
|
330 addtoline = lstack->addtoline; |
|
331 if (ecbuf) |
|
332 zfree(ecbuf, eclen); |
|
333 eclen = lstack->eclen; |
|
334 ecused = lstack->ecused; |
|
335 ecnpats = lstack->ecnpats; |
|
336 ecbuf = lstack->ecbuf; |
|
337 ecstrs = lstack->ecstrs; |
|
338 ecsoffs = lstack->ecsoffs; |
|
339 ecssub = lstack->ecssub; |
|
340 ecnfunc = lstack->ecnfunc; |
|
341 hlinesz = lstack->hlinesz; |
|
342 errflag = 0; |
|
343 |
|
344 ln = lstack->next; |
|
345 free(lstack); |
|
346 lstack = ln; |
|
347 } |
|
348 |
|
349 /**/ |
|
350 void |
|
351 yylex(void) |
|
352 { |
|
353 if (tok == LEXERR) |
|
354 return; |
|
355 do |
|
356 tok = gettok(); |
|
357 while (tok != ENDINPUT && exalias()); |
|
358 if (tok == NEWLIN || tok == ENDINPUT) { |
|
359 while (hdocs) { |
|
360 struct heredocs *next = hdocs->next; |
|
361 char *name; |
|
362 |
|
363 hwbegin(0); |
|
364 cmdpush(hdocs->type == REDIR_HEREDOC ? CS_HEREDOC : CS_HEREDOCD); |
|
365 STOPHIST |
|
366 name = gethere(hdocs->str, hdocs->type); |
|
367 ALLOWHIST |
|
368 cmdpop(); |
|
369 hwend(); |
|
370 setheredoc(hdocs->pc, REDIR_HERESTR, name); |
|
371 zfree(hdocs, sizeof(struct heredocs)); |
|
372 hdocs = next; |
|
373 } |
|
374 } |
|
375 if (tok != NEWLIN) |
|
376 isnewlin = 0; |
|
377 else |
|
378 isnewlin = (inbufct) ? -1 : 1; |
|
379 if (tok == SEMI || tok == NEWLIN) |
|
380 tok = SEPER; |
|
381 } |
|
382 |
|
383 /**/ |
|
384 mod_export void |
|
385 ctxtlex(void) |
|
386 { |
|
387 static int oldpos; |
|
388 |
|
389 yylex(); |
|
390 switch (tok) { |
|
391 case SEPER: |
|
392 case NEWLIN: |
|
393 case SEMI: |
|
394 case DSEMI: |
|
395 case SEMIAMP: |
|
396 case AMPER: |
|
397 case AMPERBANG: |
|
398 case INPAR: |
|
399 case INBRACE: |
|
400 case DBAR: |
|
401 case DAMPER: |
|
402 case BAR: |
|
403 case BARAMP: |
|
404 case INOUTPAR: |
|
405 case DOLOOP: |
|
406 case THEN: |
|
407 case ELIF: |
|
408 case ELSE: |
|
409 case DOUTBRACK: |
|
410 incmdpos = 1; |
|
411 break; |
|
412 case STRING: |
|
413 /* case ENVSTRING: */ |
|
414 case ENVARRAY: |
|
415 case OUTPAR: |
|
416 case CASE: |
|
417 case DINBRACK: |
|
418 incmdpos = 0; |
|
419 break; |
|
420 } |
|
421 if (tok != DINPAR) |
|
422 infor = tok == FOR ? 2 : 0; |
|
423 if (IS_REDIROP(tok) || tok == FOR || tok == FOREACH || tok == SELECT) { |
|
424 inredir = 1; |
|
425 oldpos = incmdpos; |
|
426 incmdpos = 0; |
|
427 } else if (inredir) { |
|
428 incmdpos = oldpos; |
|
429 inredir = 0; |
|
430 } |
|
431 } |
|
432 |
|
433 #define LX1_BKSLASH 0 |
|
434 #define LX1_COMMENT 1 |
|
435 #define LX1_NEWLIN 2 |
|
436 #define LX1_SEMI 3 |
|
437 #define LX1_AMPER 5 |
|
438 #define LX1_BAR 6 |
|
439 #define LX1_INPAR 7 |
|
440 #define LX1_OUTPAR 8 |
|
441 #define LX1_INANG 13 |
|
442 #define LX1_OUTANG 14 |
|
443 #define LX1_OTHER 15 |
|
444 |
|
445 #define LX2_BREAK 0 |
|
446 #define LX2_OUTPAR 1 |
|
447 #define LX2_BAR 2 |
|
448 #define LX2_STRING 3 |
|
449 #define LX2_INBRACK 4 |
|
450 #define LX2_OUTBRACK 5 |
|
451 #define LX2_TILDE 6 |
|
452 #define LX2_INPAR 7 |
|
453 #define LX2_INBRACE 8 |
|
454 #define LX2_OUTBRACE 9 |
|
455 #define LX2_OUTANG 10 |
|
456 #define LX2_INANG 11 |
|
457 #define LX2_EQUALS 12 |
|
458 #define LX2_BKSLASH 13 |
|
459 #define LX2_QUOTE 14 |
|
460 #define LX2_DQUOTE 15 |
|
461 #define LX2_BQUOTE 16 |
|
462 #define LX2_COMMA 17 |
|
463 #define LX2_OTHER 18 |
|
464 #define LX2_META 19 |
|
465 |
|
466 static unsigned char lexact1[256], lexact2[256], lextok2[256]; |
|
467 |
|
468 /**/ |
|
469 void |
|
470 initlextabs(void) |
|
471 { |
|
472 int t0; |
|
473 static char *lx1 = "\\q\n;!&|(){}[]<>"; |
|
474 static char *lx2 = ";)|$[]~({}><=\\\'\"`,"; |
|
475 |
|
476 for (t0 = 0; t0 != 256; t0++) { |
|
477 lexact1[t0] = LX1_OTHER; |
|
478 lexact2[t0] = LX2_OTHER; |
|
479 lextok2[t0] = t0; |
|
480 } |
|
481 for (t0 = 0; lx1[t0]; t0++) |
|
482 lexact1[(int)lx1[t0]] = t0; |
|
483 for (t0 = 0; lx2[t0]; t0++) |
|
484 lexact2[(int)lx2[t0]] = t0; |
|
485 lexact2['&'] = LX2_BREAK; |
|
486 lexact2[STOUC(Meta)] = LX2_META; |
|
487 lextok2['*'] = Star; |
|
488 lextok2['?'] = Quest; |
|
489 lextok2['{'] = Inbrace; |
|
490 lextok2['['] = Inbrack; |
|
491 lextok2['$'] = String; |
|
492 lextok2['~'] = Tilde; |
|
493 lextok2['#'] = Pound; |
|
494 lextok2['^'] = Hat; |
|
495 } |
|
496 |
|
497 /* initialize lexical state */ |
|
498 |
|
499 /**/ |
|
500 void |
|
501 lexinit(void) |
|
502 { |
|
503 incond = incasepat = nocorrect = |
|
504 infor = dbparens = lexstop = 0; |
|
505 incmdpos = 1; |
|
506 tok = ENDINPUT; |
|
507 } |
|
508 |
|
509 /* add a char to the string buffer */ |
|
510 |
|
511 /**/ |
|
512 void |
|
513 add(int c) |
|
514 { |
|
515 *bptr++ = c; |
|
516 if (bsiz == ++len) { |
|
517 #if 0 |
|
518 int newbsiz; |
|
519 |
|
520 newbsiz = bsiz * 8; |
|
521 while (newbsiz < inbufct) |
|
522 newbsiz *= 2; |
|
523 bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz)); |
|
524 bsiz = newbsiz; |
|
525 #endif |
|
526 |
|
527 int newbsiz = bsiz * 2; |
|
528 |
|
529 if (newbsiz > inbufct && inbufct > bsiz) |
|
530 newbsiz = inbufct; |
|
531 |
|
532 bptr = len + (tokstr = (char *)hrealloc(tokstr, bsiz, newbsiz)); |
|
533 bsiz = newbsiz; |
|
534 } |
|
535 } |
|
536 |
|
537 #define SETPARBEGIN {if (zleparse && !(inbufflags & INP_ALIAS) && cs >= ll+1-inbufct) parbegin = inbufct;} |
|
538 #define SETPAREND {\ |
|
539 if (zleparse && !(inbufflags & INP_ALIAS) && parbegin != -1 && parend == -1) {\ |
|
540 if (cs >= ll + 1 - inbufct)\ |
|
541 parbegin = -1;\ |
|
542 else\ |
|
543 parend = inbufct;} } |
|
544 |
|
545 static int |
|
546 cmd_or_math(int cs_type) |
|
547 { |
|
548 int oldlen = len; |
|
549 int c; |
|
550 |
|
551 cmdpush(cs_type); |
|
552 c = dquote_parse(')', 0); |
|
553 cmdpop(); |
|
554 *bptr = '\0'; |
|
555 if (!c) { |
|
556 c = hgetc(); |
|
557 if (c == ')') |
|
558 return 1; |
|
559 hungetc(c); |
|
560 lexstop = 0; |
|
561 c = ')'; |
|
562 } |
|
563 hungetc(c); |
|
564 lexstop = 0; |
|
565 while (len > oldlen) { |
|
566 len--; |
|
567 hungetc(itok(*--bptr) ? ztokens[*bptr - Pound] : *bptr); |
|
568 } |
|
569 hungetc('('); |
|
570 return 0; |
|
571 } |
|
572 |
|
573 static int |
|
574 cmd_or_math_sub(void) |
|
575 { |
|
576 int c = hgetc(); |
|
577 |
|
578 if (c == '(') { |
|
579 add(Inpar); |
|
580 add('('); |
|
581 if (cmd_or_math(CS_MATHSUBST)) { |
|
582 add(')'); |
|
583 return 0; |
|
584 } |
|
585 bptr -= 2; |
|
586 len -= 2; |
|
587 } else { |
|
588 hungetc(c); |
|
589 lexstop = 0; |
|
590 } |
|
591 return skipcomm(); |
|
592 } |
|
593 |
|
594 /* Check whether we're looking at valid numeric globbing syntax * |
|
595 * (/\<[0-9]*-[0-9]*\>/). Call pointing just after the opening "<". * |
|
596 * Leaves the input in the same place, returning 0 or 1. */ |
|
597 |
|
598 /**/ |
|
599 static int |
|
600 isnumglob(void) |
|
601 { |
|
602 int c, ec = '-', ret = 0; |
|
603 int tbs = 256, n = 0; |
|
604 char *tbuf = (char *)zalloc(tbs); |
|
605 |
|
606 while(1) { |
|
607 c = hgetc(); |
|
608 if(lexstop) { |
|
609 lexstop = 0; |
|
610 break; |
|
611 } |
|
612 tbuf[n++] = c; |
|
613 if(!idigit(c)) { |
|
614 if(c != ec) |
|
615 break; |
|
616 if(ec == '>') { |
|
617 ret = 1; |
|
618 break; |
|
619 } |
|
620 ec = '>'; |
|
621 } |
|
622 if(n == tbs) |
|
623 tbuf = (char *)realloc(tbuf, tbs *= 2); |
|
624 } |
|
625 while(n--) |
|
626 hungetc(tbuf[n]); |
|
627 zfree(tbuf, tbs); |
|
628 return ret; |
|
629 } |
|
630 |
|
631 /**/ |
|
632 int |
|
633 gettok(void) |
|
634 { |
|
635 int c, d; |
|
636 int peekfd = -1, peek; |
|
637 |
|
638 beginning: |
|
639 tokstr = NULL; |
|
640 while (iblank(c = hgetc()) && !lexstop); |
|
641 if (lexstop) |
|
642 return (errflag) ? LEXERR : ENDINPUT; |
|
643 isfirstln = 0; |
|
644 wordbeg = inbufct - (qbang && c == bangchar); |
|
645 hwbegin(-1-(qbang && c == bangchar)); |
|
646 /* word includes the last character read and possibly \ before ! */ |
|
647 if (dbparens) { |
|
648 len = 0; |
|
649 bptr = tokstr = (char *) hcalloc(bsiz = 32); |
|
650 hungetc(c); |
|
651 cmdpush(CS_MATH); |
|
652 c = dquote_parse(infor ? ';' : ')', 0); |
|
653 cmdpop(); |
|
654 *bptr = '\0'; |
|
655 if (!c && infor) { |
|
656 infor--; |
|
657 return DINPAR; |
|
658 } |
|
659 if (c || (c = hgetc()) != ')') { |
|
660 hungetc(c); |
|
661 return LEXERR; |
|
662 } |
|
663 dbparens = 0; |
|
664 return DOUTPAR; |
|
665 } else if (idigit(c)) { /* handle 1< foo */ |
|
666 d = hgetc(); |
|
667 if(d == '&') { |
|
668 d = hgetc(); |
|
669 if(d == '>') { |
|
670 peekfd = c - '0'; |
|
671 hungetc('>'); |
|
672 c = '&'; |
|
673 } else { |
|
674 hungetc(d); |
|
675 lexstop = 0; |
|
676 hungetc('&'); |
|
677 } |
|
678 } else if (d == '>' || d == '<') { |
|
679 peekfd = c - '0'; |
|
680 c = d; |
|
681 } else { |
|
682 hungetc(d); |
|
683 lexstop = 0; |
|
684 } |
|
685 } |
|
686 |
|
687 /* chars in initial position in word */ |
|
688 |
|
689 if (c == hashchar && !nocomments && |
|
690 (isset(INTERACTIVECOMMENTS) || |
|
691 (!zleparse && !expanding && |
|
692 (!interact || unset(SHINSTDIN) || strin)))) { |
|
693 /* History is handled here to prevent extra * |
|
694 * newlines being inserted into the history. */ |
|
695 |
|
696 while ((c = ingetc()) != '\n' && !lexstop) { |
|
697 hwaddc(c); |
|
698 addtoline(c); |
|
699 } |
|
700 |
|
701 if (errflag) |
|
702 peek = LEXERR; |
|
703 else { |
|
704 hwend(); |
|
705 hwbegin(0); |
|
706 hwaddc('\n'); |
|
707 addtoline('\n'); |
|
708 peek = NEWLIN; |
|
709 } |
|
710 return peek; |
|
711 } |
|
712 switch (lexact1[STOUC(c)]) { |
|
713 case LX1_BKSLASH: |
|
714 d = hgetc(); |
|
715 if (d == '\n') |
|
716 goto beginning; |
|
717 hungetc(d); |
|
718 lexstop = 0; |
|
719 break; |
|
720 case LX1_NEWLIN: |
|
721 return NEWLIN; |
|
722 case LX1_SEMI: |
|
723 d = hgetc(); |
|
724 if(d == ';') |
|
725 return DSEMI; |
|
726 else if(d == '&') |
|
727 return SEMIAMP; |
|
728 hungetc(d); |
|
729 lexstop = 0; |
|
730 return SEMI; |
|
731 case LX1_AMPER: |
|
732 d = hgetc(); |
|
733 if (d == '&') |
|
734 return DAMPER; |
|
735 else if (d == '!' || d == '|') |
|
736 return AMPERBANG; |
|
737 else if (d == '>') { |
|
738 tokfd = peekfd; |
|
739 d = hgetc(); |
|
740 if (d == '!' || d == '|') |
|
741 return OUTANGAMPBANG; |
|
742 else if (d == '>') { |
|
743 d = hgetc(); |
|
744 if (d == '!' || d == '|') |
|
745 return DOUTANGAMPBANG; |
|
746 hungetc(d); |
|
747 lexstop = 0; |
|
748 return DOUTANGAMP; |
|
749 } |
|
750 hungetc(d); |
|
751 lexstop = 0; |
|
752 return AMPOUTANG; |
|
753 } |
|
754 hungetc(d); |
|
755 lexstop = 0; |
|
756 return AMPER; |
|
757 case LX1_BAR: |
|
758 d = hgetc(); |
|
759 if (d == '|') |
|
760 return DBAR; |
|
761 else if (d == '&') |
|
762 return BARAMP; |
|
763 hungetc(d); |
|
764 lexstop = 0; |
|
765 return BAR; |
|
766 case LX1_INPAR: |
|
767 d = hgetc(); |
|
768 if (d == '(') { |
|
769 if (infor) { |
|
770 dbparens = 1; |
|
771 return DINPAR; |
|
772 } |
|
773 if (incmdpos) { |
|
774 len = 0; |
|
775 bptr = tokstr = (char *) hcalloc(bsiz = 32); |
|
776 return cmd_or_math(CS_MATH) ? DINPAR : INPAR; |
|
777 } |
|
778 } else if (d == ')') |
|
779 return INOUTPAR; |
|
780 hungetc(d); |
|
781 lexstop = 0; |
|
782 if (!(incond == 1 || incmdpos)) |
|
783 break; |
|
784 return INPAR; |
|
785 case LX1_OUTPAR: |
|
786 return OUTPAR; |
|
787 case LX1_INANG: |
|
788 d = hgetc(); |
|
789 if (!incmdpos && d == '(') { |
|
790 hungetc(d); |
|
791 lexstop = 0; |
|
792 unpeekfd: |
|
793 if(peekfd != -1) { |
|
794 hungetc(c); |
|
795 c = '0' + peekfd; |
|
796 } |
|
797 break; |
|
798 } |
|
799 if (d == '>') { |
|
800 peek = INOUTANG; |
|
801 } else if (d == '<') { |
|
802 int e = hgetc(); |
|
803 |
|
804 if (e == '(') { |
|
805 hungetc(e); |
|
806 hungetc(d); |
|
807 peek = INANG; |
|
808 } else if (e == '<') |
|
809 peek = TRINANG; |
|
810 else if (e == '-') |
|
811 peek = DINANGDASH; |
|
812 else { |
|
813 hungetc(e); |
|
814 lexstop = 0; |
|
815 peek = DINANG; |
|
816 } |
|
817 } else if (d == '&') { |
|
818 peek = INANGAMP; |
|
819 } else { |
|
820 hungetc(d); |
|
821 if(isnumglob()) |
|
822 goto unpeekfd; |
|
823 peek = INANG; |
|
824 } |
|
825 tokfd = peekfd; |
|
826 return peek; |
|
827 case LX1_OUTANG: |
|
828 d = hgetc(); |
|
829 if (d == '(') { |
|
830 hungetc(d); |
|
831 goto unpeekfd; |
|
832 } else if (d == '&') { |
|
833 d = hgetc(); |
|
834 if (d == '!' || d == '|') |
|
835 peek = OUTANGAMPBANG; |
|
836 else { |
|
837 hungetc(d); |
|
838 lexstop = 0; |
|
839 peek = OUTANGAMP; |
|
840 } |
|
841 } else if (d == '!' || d == '|') |
|
842 peek = OUTANGBANG; |
|
843 else if (d == '>') { |
|
844 d = hgetc(); |
|
845 if (d == '&') { |
|
846 d = hgetc(); |
|
847 if (d == '!' || d == '|') |
|
848 peek = DOUTANGAMPBANG; |
|
849 else { |
|
850 hungetc(d); |
|
851 lexstop = 0; |
|
852 peek = DOUTANGAMP; |
|
853 } |
|
854 } else if (d == '!' || d == '|') |
|
855 peek = DOUTANGBANG; |
|
856 else if (d == '(') { |
|
857 hungetc(d); |
|
858 hungetc('>'); |
|
859 peek = OUTANG; |
|
860 } else { |
|
861 hungetc(d); |
|
862 lexstop = 0; |
|
863 peek = DOUTANG; |
|
864 if (isset(HISTALLOWCLOBBER)) |
|
865 hwaddc('|'); |
|
866 } |
|
867 } else { |
|
868 hungetc(d); |
|
869 lexstop = 0; |
|
870 peek = OUTANG; |
|
871 if (!incond && isset(HISTALLOWCLOBBER)) |
|
872 hwaddc('|'); |
|
873 } |
|
874 tokfd = peekfd; |
|
875 return peek; |
|
876 } |
|
877 |
|
878 /* we've started a string, now get the * |
|
879 * rest of it, performing tokenization */ |
|
880 return gettokstr(c, 0); |
|
881 } |
|
882 |
|
883 /**/ |
|
884 static int |
|
885 gettokstr(int c, int sub) |
|
886 { |
|
887 int bct = 0, pct = 0, brct = 0, fdpar = 0; |
|
888 int intpos = 1, in_brace_param = 0; |
|
889 int peek, inquote, unmatched = 0; |
|
890 char endchar='"'; |
|
891 #ifdef DEBUG |
|
892 int ocmdsp = cmdsp; |
|
893 #endif |
|
894 |
|
895 peek = STRING; |
|
896 if (!sub) { |
|
897 len = 0; |
|
898 bptr = tokstr = (char *) hcalloc(bsiz = 32); |
|
899 } |
|
900 for (;;) { |
|
901 int act; |
|
902 int e; |
|
903 int inbl = inblank(c); |
|
904 |
|
905 if (fdpar && !inbl && c != ')') |
|
906 fdpar = 0; |
|
907 |
|
908 if (inbl && !in_brace_param && !pct) |
|
909 act = LX2_BREAK; |
|
910 else { |
|
911 act = lexact2[STOUC(c)]; |
|
912 c = lextok2[STOUC(c)]; |
|
913 } |
|
914 switch (act) { |
|
915 case LX2_BREAK: |
|
916 if (!in_brace_param && !sub) |
|
917 goto brk; |
|
918 break; |
|
919 case LX2_META: |
|
920 c = hgetc(); |
|
921 #ifdef DEBUG |
|
922 if (lexstop) { |
|
923 fputs("BUG: input terminated by Meta\n", stderr); |
|
924 fflush(stderr); |
|
925 goto brk; |
|
926 } |
|
927 #endif |
|
928 add(Meta); |
|
929 break; |
|
930 case LX2_OUTPAR: |
|
931 if (fdpar) { |
|
932 /* this is a single word `( )', treat as INOUTPAR */ |
|
933 add(c); |
|
934 *bptr = '\0'; |
|
935 return INOUTPAR; |
|
936 } |
|
937 if ((sub || in_brace_param) && isset(SHGLOB)) |
|
938 break; |
|
939 if (!in_brace_param && !pct--) { |
|
940 if (sub) { |
|
941 pct = 0; |
|
942 break; |
|
943 } else |
|
944 goto brk; |
|
945 } |
|
946 c = Outpar; |
|
947 break; |
|
948 case LX2_BAR: |
|
949 if (!pct && !in_brace_param) { |
|
950 if (sub) |
|
951 break; |
|
952 else |
|
953 goto brk; |
|
954 } |
|
955 if (unset(SHGLOB) || (!sub && !in_brace_param)) |
|
956 c = Bar; |
|
957 break; |
|
958 case LX2_STRING: |
|
959 e = hgetc(); |
|
960 if (e == '[') { |
|
961 cmdpush(CS_MATHSUBST); |
|
962 add(String); |
|
963 add(Inbrack); |
|
964 c = dquote_parse(']', sub); |
|
965 cmdpop(); |
|
966 if (c) { |
|
967 peek = LEXERR; |
|
968 goto brk; |
|
969 } |
|
970 c = Outbrack; |
|
971 } else if (e == '(') { |
|
972 add(String); |
|
973 c = cmd_or_math_sub(); |
|
974 if (c) { |
|
975 peek = LEXERR; |
|
976 goto brk; |
|
977 } |
|
978 c = Outpar; |
|
979 } else { |
|
980 if (e == '{') { |
|
981 add(c); |
|
982 c = Inbrace; |
|
983 ++bct; |
|
984 cmdpush(CS_BRACEPAR); |
|
985 if (!in_brace_param) |
|
986 in_brace_param = bct; |
|
987 } else { |
|
988 hungetc(e); |
|
989 lexstop = 0; |
|
990 } |
|
991 } |
|
992 break; |
|
993 case LX2_INBRACK: |
|
994 if (!in_brace_param) |
|
995 brct++; |
|
996 c = Inbrack; |
|
997 break; |
|
998 case LX2_OUTBRACK: |
|
999 if (!in_brace_param) |
|
1000 brct--; |
|
1001 if (brct < 0) |
|
1002 brct = 0; |
|
1003 c = Outbrack; |
|
1004 break; |
|
1005 case LX2_INPAR: |
|
1006 if (isset(SHGLOB)) { |
|
1007 if (sub || in_brace_param) |
|
1008 break; |
|
1009 if (incasepat && !len) |
|
1010 return INPAR; |
|
1011 } |
|
1012 if (!in_brace_param) { |
|
1013 if (!sub) { |
|
1014 e = hgetc(); |
|
1015 hungetc(e); |
|
1016 lexstop = 0; |
|
1017 /* For command words, parentheses are only |
|
1018 * special at the start. But now we're tokenising |
|
1019 * the remaining string. So I don't see what |
|
1020 * the old incmdpos test here is for. |
|
1021 * pws 1999/6/8 |
|
1022 * |
|
1023 * Oh, no. |
|
1024 * func1( ) |
|
1025 * is a valid function definition in [k]sh. The best |
|
1026 * thing we can do, without really nasty lookahead tricks, |
|
1027 * is break if we find a blank after a parenthesis. At |
|
1028 * least this can't happen inside braces or brackets. We |
|
1029 * only allow this with SHGLOB (set for both sh and ksh). |
|
1030 * |
|
1031 * Things like `print @( |foo)' should still |
|
1032 * work, because [k]sh don't allow multiple words |
|
1033 * in a function definition, so we only do this |
|
1034 * in command position. |
|
1035 * pws 1999/6/14 |
|
1036 */ |
|
1037 if (e == ')' || (isset(SHGLOB) && inblank(e) && !bct && |
|
1038 !brct && !intpos && incmdpos)) |
|
1039 goto brk; |
|
1040 } |
|
1041 /* |
|
1042 * This also handles the [k]sh `foo( )' function definition. |
|
1043 * Maintain a variable fdpar, set as long as a single set of |
|
1044 * parentheses contains only space. Then if we get to the |
|
1045 * closing parenthesis and it is still set, we can assume we |
|
1046 * have a function definition. Only do this at the start of |
|
1047 * the word, since the (...) must be a separate token. |
|
1048 */ |
|
1049 if (!pct++ && isset(SHGLOB) && intpos && !bct && !brct) |
|
1050 fdpar = 1; |
|
1051 } |
|
1052 c = Inpar; |
|
1053 break; |
|
1054 case LX2_INBRACE: |
|
1055 if (isset(IGNOREBRACES) || sub) |
|
1056 c = '{'; |
|
1057 else { |
|
1058 if (!len && incmdpos) { |
|
1059 add('{'); |
|
1060 *bptr = '\0'; |
|
1061 return STRING; |
|
1062 } |
|
1063 if (in_brace_param) { |
|
1064 cmdpush(CS_BRACE); |
|
1065 } |
|
1066 bct++; |
|
1067 } |
|
1068 break; |
|
1069 case LX2_OUTBRACE: |
|
1070 if ((isset(IGNOREBRACES) || sub) && !in_brace_param) |
|
1071 break; |
|
1072 if (!bct) |
|
1073 break; |
|
1074 if (in_brace_param) { |
|
1075 cmdpop(); |
|
1076 } |
|
1077 if (bct-- == in_brace_param) |
|
1078 in_brace_param = 0; |
|
1079 c = Outbrace; |
|
1080 break; |
|
1081 case LX2_COMMA: |
|
1082 if (unset(IGNOREBRACES) && !sub && bct > in_brace_param) |
|
1083 c = Comma; |
|
1084 break; |
|
1085 case LX2_OUTANG: |
|
1086 if (!intpos) { |
|
1087 if (in_brace_param || sub) |
|
1088 break; |
|
1089 else |
|
1090 goto brk; |
|
1091 } |
|
1092 e = hgetc(); |
|
1093 if (e != '(') { |
|
1094 hungetc(e); |
|
1095 lexstop = 0; |
|
1096 goto brk; |
|
1097 } |
|
1098 add(Outang); |
|
1099 if (skipcomm()) { |
|
1100 peek = LEXERR; |
|
1101 goto brk; |
|
1102 } |
|
1103 c = Outpar; |
|
1104 break; |
|
1105 case LX2_INANG: |
|
1106 if (isset(SHGLOB) && sub) |
|
1107 break; |
|
1108 e = hgetc(); |
|
1109 if(e == '(' && intpos) { |
|
1110 add(Inang); |
|
1111 if (skipcomm()) { |
|
1112 peek = LEXERR; |
|
1113 goto brk; |
|
1114 } |
|
1115 c = Outpar; |
|
1116 break; |
|
1117 } |
|
1118 hungetc(e); |
|
1119 if(isnumglob()) { |
|
1120 add(Inang); |
|
1121 while ((c = hgetc()) != '>') |
|
1122 add(c); |
|
1123 c = Outang; |
|
1124 break; |
|
1125 } |
|
1126 lexstop = 0; |
|
1127 if (in_brace_param || sub) |
|
1128 break; |
|
1129 goto brk; |
|
1130 case LX2_EQUALS: |
|
1131 if (intpos) { |
|
1132 e = hgetc(); |
|
1133 if (e != '(') { |
|
1134 hungetc(e); |
|
1135 lexstop = 0; |
|
1136 c = Equals; |
|
1137 } else { |
|
1138 add(Equals); |
|
1139 if (skipcomm()) { |
|
1140 peek = LEXERR; |
|
1141 goto brk; |
|
1142 } |
|
1143 c = Outpar; |
|
1144 } |
|
1145 } else if (!sub && peek != ENVSTRING && |
|
1146 incmdpos && !bct && !brct) { |
|
1147 char *t = tokstr; |
|
1148 if (idigit(*t)) |
|
1149 while (++t < bptr && idigit(*t)); |
|
1150 else { |
|
1151 while (iident(*t) && ++t < bptr); |
|
1152 if (t < bptr) { |
|
1153 *bptr = '\0'; |
|
1154 skipparens(Inbrack, Outbrack, &t); |
|
1155 } |
|
1156 } |
|
1157 if (*t == '+') |
|
1158 t++; |
|
1159 if (t == bptr) { |
|
1160 e = hgetc(); |
|
1161 if (e == '(' && incmdpos) { |
|
1162 *bptr = '\0'; |
|
1163 return ENVARRAY; |
|
1164 } |
|
1165 hungetc(e); |
|
1166 lexstop = 0; |
|
1167 peek = ENVSTRING; |
|
1168 intpos = 2; |
|
1169 } else |
|
1170 c = Equals; |
|
1171 } else |
|
1172 c = Equals; |
|
1173 break; |
|
1174 #ifndef __SYMBIAN32__ |
|
1175 case LX2_BKSLASH: |
|
1176 c = hgetc(); |
|
1177 if (c == '\n') { |
|
1178 c = hgetc(); |
|
1179 if (!lexstop) |
|
1180 continue; |
|
1181 } else |
|
1182 add(Bnull); |
|
1183 if (lexstop) |
|
1184 goto brk; |
|
1185 break; |
|
1186 #endif |
|
1187 case LX2_QUOTE: { |
|
1188 int strquote = (len && bptr[-1] == String); |
|
1189 |
|
1190 add(Snull); |
|
1191 cmdpush(CS_QUOTE); |
|
1192 for (;;) { |
|
1193 STOPHIST |
|
1194 while ((c = hgetc()) != '\'' && !lexstop) { |
|
1195 if (strquote && c == '\\') { |
|
1196 add(c); |
|
1197 c = hgetc(); |
|
1198 if (lexstop) |
|
1199 break; |
|
1200 } else if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { |
|
1201 if (bptr[-1] == '\\') |
|
1202 bptr--, len--; |
|
1203 else |
|
1204 break; |
|
1205 } |
|
1206 add(c); |
|
1207 } |
|
1208 ALLOWHIST |
|
1209 if (c != '\'') { |
|
1210 unmatched = '\''; |
|
1211 peek = LEXERR; |
|
1212 cmdpop(); |
|
1213 goto brk; |
|
1214 } |
|
1215 e = hgetc(); |
|
1216 if (e != '\'' || unset(RCQUOTES) || strquote) |
|
1217 break; |
|
1218 add(c); |
|
1219 } |
|
1220 cmdpop(); |
|
1221 hungetc(e); |
|
1222 lexstop = 0; |
|
1223 c = Snull; |
|
1224 break; |
|
1225 } |
|
1226 case LX2_DQUOTE: |
|
1227 add(Dnull); |
|
1228 cmdpush(CS_DQUOTE); |
|
1229 c = dquote_parse('"', sub); |
|
1230 cmdpop(); |
|
1231 if (c) { |
|
1232 unmatched = '"'; |
|
1233 peek = LEXERR; |
|
1234 goto brk; |
|
1235 } |
|
1236 c = Dnull; |
|
1237 break; |
|
1238 case LX2_BQUOTE: |
|
1239 add(Tick); |
|
1240 cmdpush(CS_BQUOTE); |
|
1241 SETPARBEGIN |
|
1242 inquote = 0; |
|
1243 while ((c = hgetc()) != '`' && !lexstop) { |
|
1244 if (c == '\\') { |
|
1245 c = hgetc(); |
|
1246 if (c != '\n') { |
|
1247 add(c == '`' || c == '\\' || c == '$' ? Bnull : '\\'); |
|
1248 add(c); |
|
1249 } |
|
1250 else if (!sub && isset(CSHJUNKIEQUOTES)) |
|
1251 add(c); |
|
1252 } else { |
|
1253 if (!sub && isset(CSHJUNKIEQUOTES) && c == '\n') { |
|
1254 break; |
|
1255 } |
|
1256 add(c); |
|
1257 if (c == '\'') { |
|
1258 if ((inquote = !inquote)) |
|
1259 STOPHIST |
|
1260 else |
|
1261 ALLOWHIST |
|
1262 } |
|
1263 } |
|
1264 } |
|
1265 if (inquote) |
|
1266 ALLOWHIST |
|
1267 cmdpop(); |
|
1268 if (c != '`') { |
|
1269 unmatched = '`'; |
|
1270 peek = LEXERR; |
|
1271 goto brk; |
|
1272 } |
|
1273 c = Tick; |
|
1274 SETPAREND |
|
1275 break; |
|
1276 } |
|
1277 #ifdef __SYMBIAN32__ |
|
1278 if(c=='\\') |
|
1279 { |
|
1280 c = hgetc(); |
|
1281 if (c != '\n') { |
|
1282 if (c == endchar) |
|
1283 add(Bnull); |
|
1284 else { |
|
1285 /* lexstop is implicitly handled here */ |
|
1286 add('\\'); |
|
1287 |
|
1288 } |
|
1289 } |
|
1290 } |
|
1291 #endif |
|
1292 add(c); |
|
1293 c = hgetc(); |
|
1294 if (intpos) |
|
1295 intpos--; |
|
1296 if (lexstop) |
|
1297 break; |
|
1298 } |
|
1299 brk: |
|
1300 hungetc(c); |
|
1301 if (unmatched) |
|
1302 zerr("unmatched %c", NULL, unmatched); |
|
1303 if (in_brace_param) { |
|
1304 while(bct-- >= in_brace_param) |
|
1305 cmdpop(); |
|
1306 zerr("closing brace expected", NULL, 0); |
|
1307 } else if (unset(IGNOREBRACES) && !sub && len > 1 && |
|
1308 peek == STRING && bptr[-1] == '}' && bptr[-2] != Bnull) { |
|
1309 /* hack to get {foo} command syntax work */ |
|
1310 bptr--; |
|
1311 len--; |
|
1312 lexstop = 0; |
|
1313 hungetc('}'); |
|
1314 } |
|
1315 *bptr = '\0'; |
|
1316 DPUTS(cmdsp != ocmdsp, "BUG: gettok: cmdstack changed."); |
|
1317 return peek; |
|
1318 } |
|
1319 |
|
1320 /**/ |
|
1321 static int |
|
1322 dquote_parse(char endchar, int sub) |
|
1323 { |
|
1324 int pct = 0, brct = 0, bct = 0, intick = 0, err = 0; |
|
1325 int c; |
|
1326 int math = endchar == ')' || endchar == ']'; |
|
1327 int zlemath = math && cs > ll + addedx - inbufct; |
|
1328 |
|
1329 while (((c = hgetc()) != endchar || bct || |
|
1330 (math && ((pct > 0) || (brct > 0))) || |
|
1331 intick) && !lexstop) { |
|
1332 cont: |
|
1333 switch (c) { |
|
1334 case '\\': |
|
1335 c = hgetc(); |
|
1336 if (c != '\n') { |
|
1337 if (c == '$' || c == '\\' || (c == '}' && !intick && bct) || |
|
1338 c == endchar || c == '`' || |
|
1339 (endchar == ']' && (c == '[' || c == ']' || |
|
1340 c == '(' || c == ')' || |
|
1341 c == '{' || c == '}' || |
|
1342 (c == '"' && sub)))) |
|
1343 add(Bnull); |
|
1344 else { |
|
1345 /* lexstop is implicitly handled here */ |
|
1346 add('\\'); |
|
1347 goto cont; |
|
1348 } |
|
1349 } else if (sub || unset(CSHJUNKIEQUOTES) || endchar != '"') |
|
1350 continue; |
|
1351 break; |
|
1352 case '\n': |
|
1353 err = !sub && isset(CSHJUNKIEQUOTES) && endchar == '"'; |
|
1354 break; |
|
1355 case '$': |
|
1356 if (intick) |
|
1357 break; |
|
1358 c = hgetc(); |
|
1359 if (c == '(') { |
|
1360 add(Qstring); |
|
1361 err = cmd_or_math_sub(); |
|
1362 c = Outpar; |
|
1363 } else if (c == '[') { |
|
1364 add(String); |
|
1365 add(Inbrack); |
|
1366 cmdpush(CS_MATHSUBST); |
|
1367 err = dquote_parse(']', sub); |
|
1368 cmdpop(); |
|
1369 c = Outbrack; |
|
1370 } else if (c == '{') { |
|
1371 add(Qstring); |
|
1372 c = Inbrace; |
|
1373 cmdpush(CS_BRACEPAR); |
|
1374 bct++; |
|
1375 } else if (c == '$') |
|
1376 add(Qstring); |
|
1377 else { |
|
1378 hungetc(c); |
|
1379 lexstop = 0; |
|
1380 c = Qstring; |
|
1381 } |
|
1382 break; |
|
1383 case '}': |
|
1384 if (intick || !bct) |
|
1385 break; |
|
1386 c = Outbrace; |
|
1387 bct--; |
|
1388 cmdpop(); |
|
1389 break; |
|
1390 case '`': |
|
1391 c = Qtick; |
|
1392 if (intick == 2) |
|
1393 ALLOWHIST |
|
1394 if ((intick = !intick)) { |
|
1395 SETPARBEGIN |
|
1396 cmdpush(CS_BQUOTE); |
|
1397 } else { |
|
1398 SETPAREND |
|
1399 cmdpop(); |
|
1400 } |
|
1401 break; |
|
1402 case '\'': |
|
1403 if (!intick) |
|
1404 break; |
|
1405 if (intick == 1) |
|
1406 intick = 2, STOPHIST |
|
1407 else |
|
1408 intick = 1, ALLOWHIST |
|
1409 break; |
|
1410 case '(': |
|
1411 if (!math || !bct) |
|
1412 pct++; |
|
1413 break; |
|
1414 case ')': |
|
1415 if (!math || !bct) |
|
1416 err = (!pct-- && math); |
|
1417 break; |
|
1418 case '[': |
|
1419 if (!math || !bct) |
|
1420 brct++; |
|
1421 break; |
|
1422 case ']': |
|
1423 if (!math || !bct) |
|
1424 err = (!brct-- && math); |
|
1425 break; |
|
1426 case '"': |
|
1427 if (intick || ((endchar == ']' || !endchar) && !bct)) |
|
1428 break; |
|
1429 if (bct) { |
|
1430 add(Dnull); |
|
1431 cmdpush(CS_DQUOTE); |
|
1432 err = dquote_parse('"', sub); |
|
1433 cmdpop(); |
|
1434 c = Dnull; |
|
1435 } else |
|
1436 err = 1; |
|
1437 break; |
|
1438 } |
|
1439 if (err || lexstop) |
|
1440 break; |
|
1441 add(c); |
|
1442 } |
|
1443 if (intick == 2) |
|
1444 ALLOWHIST |
|
1445 if (intick) { |
|
1446 cmdpop(); |
|
1447 } |
|
1448 while (bct--) |
|
1449 cmdpop(); |
|
1450 if (lexstop) |
|
1451 err = intick || endchar || err; |
|
1452 else if (err == 1) |
|
1453 err = c; |
|
1454 if (zlemath && cs <= ll + 1 - inbufct) |
|
1455 inwhat = IN_MATH; |
|
1456 return err; |
|
1457 } |
|
1458 |
|
1459 /* Tokenize a string given in s. Parsing is done as in double * |
|
1460 * quotes. This is usually called before singsub(). */ |
|
1461 |
|
1462 /**/ |
|
1463 mod_export int |
|
1464 parsestr(char *s) |
|
1465 { |
|
1466 int err; |
|
1467 |
|
1468 if ((err = parsestrnoerr(s))) { |
|
1469 untokenize(s); |
|
1470 if (err > 32 && err < 127) |
|
1471 zerr("parse error near `%c'", NULL, err); |
|
1472 else |
|
1473 zerr("parse error", NULL, 0); |
|
1474 } |
|
1475 return err; |
|
1476 } |
|
1477 |
|
1478 /**/ |
|
1479 mod_export int |
|
1480 parsestrnoerr(char *s) |
|
1481 { |
|
1482 int l = strlen(s), err; |
|
1483 |
|
1484 lexsave(); |
|
1485 untokenize(s); |
|
1486 inpush(dupstring(s), 0, NULL); |
|
1487 strinbeg(0); |
|
1488 len = 0; |
|
1489 bptr = tokstr = s; |
|
1490 bsiz = l + 1; |
|
1491 err = dquote_parse('\0', 1); |
|
1492 *bptr = '\0'; |
|
1493 strinend(); |
|
1494 inpop(); |
|
1495 DPUTS(cmdsp, "BUG: parsestr: cmdstack not empty."); |
|
1496 lexrestore(); |
|
1497 return err; |
|
1498 } |
|
1499 |
|
1500 /**/ |
|
1501 mod_export char * |
|
1502 parse_subscript(char *s, int sub) |
|
1503 { |
|
1504 int l = strlen(s), err; |
|
1505 char *t; |
|
1506 |
|
1507 if (!*s || *s == ']') |
|
1508 return 0; |
|
1509 lexsave(); |
|
1510 untokenize(t = dupstring(s)); |
|
1511 inpush(t, 0, NULL); |
|
1512 strinbeg(0); |
|
1513 len = 0; |
|
1514 bptr = tokstr = s; |
|
1515 bsiz = l + 1; |
|
1516 err = dquote_parse(']', sub); |
|
1517 if (err) { |
|
1518 err = *bptr; |
|
1519 *bptr = 0; |
|
1520 untokenize(s); |
|
1521 *bptr = err; |
|
1522 s = 0; |
|
1523 } else |
|
1524 s = bptr; |
|
1525 strinend(); |
|
1526 inpop(); |
|
1527 DPUTS(cmdsp, "BUG: parse_subscript: cmdstack not empty."); |
|
1528 lexrestore(); |
|
1529 return s; |
|
1530 } |
|
1531 |
|
1532 /* Tokenize a string given in s. Parsing is done as if s were a normal * |
|
1533 * command-line argument but it may contain separators. This is used * |
|
1534 * to parse the right-hand side of ${...%...} substitutions. */ |
|
1535 |
|
1536 /**/ |
|
1537 mod_export int |
|
1538 parse_subst_string(char *s) |
|
1539 { |
|
1540 int c, l = strlen(s), err, olen, lexstop_ret; |
|
1541 |
|
1542 if (!*s || !strcmp(s, nulstring)) |
|
1543 return 0; |
|
1544 lexsave(); |
|
1545 untokenize(s); |
|
1546 inpush(dupstring(s), 0, NULL); |
|
1547 strinbeg(0); |
|
1548 len = 0; |
|
1549 bptr = tokstr = s; |
|
1550 bsiz = l + 1; |
|
1551 c = hgetc(); |
|
1552 lexstop_ret = lexstop; |
|
1553 c = gettokstr(c, 1); |
|
1554 err = errflag; |
|
1555 strinend(); |
|
1556 inpop(); |
|
1557 DPUTS(cmdsp, "BUG: parse_subst_string: cmdstack not empty."); |
|
1558 olen = len; |
|
1559 lexrestore(); |
|
1560 errflag = err; |
|
1561 if (c == LEXERR) { |
|
1562 untokenize(s); |
|
1563 return 1; |
|
1564 } |
|
1565 #ifdef DEBUG |
|
1566 if (c != STRING || olen != l || errflag) { |
|
1567 fprintf(stderr, "Oops. Bug in parse_subst_string: %s\n", |
|
1568 olen < l ? "len < l" : errflag ? "errflag" : "c != STRING"); |
|
1569 fflush(stderr); |
|
1570 untokenize(s); |
|
1571 return 1; |
|
1572 } |
|
1573 #endif |
|
1574 return 0; |
|
1575 } |
|
1576 |
|
1577 /* Called below to report word positions. */ |
|
1578 |
|
1579 /**/ |
|
1580 mod_export void |
|
1581 gotword(void) |
|
1582 { |
|
1583 we = ll + 1 - inbufct + (addedx == 2 ? 1 : 0); |
|
1584 if (cs <= we) { |
|
1585 wb = ll - wordbeg + addedx; |
|
1586 zleparse = 0; |
|
1587 } |
|
1588 } |
|
1589 |
|
1590 /* expand aliases and reserved words */ |
|
1591 |
|
1592 /**/ |
|
1593 int |
|
1594 exalias(void) |
|
1595 { |
|
1596 Alias an; |
|
1597 Reswd rw; |
|
1598 |
|
1599 hwend(); |
|
1600 if (interact && isset(SHINSTDIN) && !strin && !incasepat && |
|
1601 tok == STRING && !nocorrect && !(inbufflags & INP_ALIAS) && |
|
1602 (isset(CORRECTALL) || (isset(CORRECT) && incmdpos))) |
|
1603 spckword(&tokstr, 1, incmdpos, 1); |
|
1604 |
|
1605 if (!tokstr) { |
|
1606 yytext = tokstrings[tok]; |
|
1607 |
|
1608 return 0; |
|
1609 } else { |
|
1610 VARARR(char, copy, (strlen(tokstr) + 1)); |
|
1611 |
|
1612 if (has_token(tokstr)) { |
|
1613 char *p, *t; |
|
1614 |
|
1615 yytext = p = copy; |
|
1616 for (t = tokstr; |
|
1617 (*p++ = itok(*t) ? ztokens[*t++ - Pound] : *t++);); |
|
1618 } else |
|
1619 yytext = tokstr; |
|
1620 |
|
1621 if (zleparse && !(inbufflags & INP_ALIAS)) { |
|
1622 int zp = zleparse; |
|
1623 |
|
1624 gotword(); |
|
1625 if (zp == 1 && !zleparse) { |
|
1626 if (yytext == copy) |
|
1627 yytext = tokstr; |
|
1628 return 0; |
|
1629 } |
|
1630 } |
|
1631 |
|
1632 if (tok == STRING) { |
|
1633 /* Check for an alias */ |
|
1634 if (!noaliases && isset(ALIASESOPT)) { |
|
1635 char *suf; |
|
1636 |
|
1637 an = (Alias) aliastab->getnode(aliastab, yytext); |
|
1638 if (an && !an->inuse && |
|
1639 ((an->flags & ALIAS_GLOBAL) || incmdpos || inalmore)) { |
|
1640 inpush(an->text, INP_ALIAS, an); |
|
1641 if (an->text[0] == ' ') |
|
1642 aliasspaceflag = 1; |
|
1643 lexstop = 0; |
|
1644 if (yytext == copy) |
|
1645 yytext = tokstr; |
|
1646 return 1; |
|
1647 } |
|
1648 if ((suf = strrchr(yytext, '.')) && suf[1] && |
|
1649 suf > yytext && suf[-1] != Meta && |
|
1650 (an = (Alias)sufaliastab->getnode(sufaliastab, suf+1)) && |
|
1651 !an->inuse && incmdpos) { |
|
1652 inpush(dupstring(yytext), INP_ALIAS, NULL); |
|
1653 inpush(" ", INP_ALIAS, NULL); |
|
1654 inpush(an->text, INP_ALIAS, an); |
|
1655 lexstop = 0; |
|
1656 if (yytext == copy) |
|
1657 yytext = tokstr; |
|
1658 return 1; |
|
1659 } |
|
1660 } |
|
1661 |
|
1662 /* Then check for a reserved word */ |
|
1663 if ((incmdpos || |
|
1664 (unset(IGNOREBRACES) && yytext[0] == '}' && !yytext[1])) && |
|
1665 (rw = (Reswd) reswdtab->getnode(reswdtab, yytext))) { |
|
1666 tok = rw->token; |
|
1667 if (tok == DINBRACK) |
|
1668 incond = 1; |
|
1669 } else if (incond && !strcmp(yytext, "]]")) { |
|
1670 tok = DOUTBRACK; |
|
1671 incond = 0; |
|
1672 } else if (incond == 1 && yytext[0] == '!' && !yytext[1]) |
|
1673 tok = BANG; |
|
1674 } |
|
1675 inalmore = 0; |
|
1676 if (yytext == copy) |
|
1677 yytext = tokstr; |
|
1678 } |
|
1679 return 0; |
|
1680 } |
|
1681 |
|
1682 /* skip (...) */ |
|
1683 |
|
1684 /**/ |
|
1685 static int |
|
1686 skipcomm(void) |
|
1687 { |
|
1688 int pct = 1, c; |
|
1689 |
|
1690 cmdpush(CS_CMDSUBST); |
|
1691 SETPARBEGIN |
|
1692 c = Inpar; |
|
1693 do { |
|
1694 add(c); |
|
1695 c = hgetc(); |
|
1696 if (itok(c) || lexstop) |
|
1697 break; |
|
1698 switch (c) { |
|
1699 case '(': |
|
1700 pct++; |
|
1701 break; |
|
1702 case ')': |
|
1703 pct--; |
|
1704 break; |
|
1705 case '\\': |
|
1706 add(c); |
|
1707 c = hgetc(); |
|
1708 break; |
|
1709 case '\'': { |
|
1710 int strquote = bptr[-1] == '$'; |
|
1711 add(c); |
|
1712 STOPHIST |
|
1713 while ((c = hgetc()) != '\'' && !lexstop) { |
|
1714 if (c == '\\' && strquote) { |
|
1715 add(c); |
|
1716 c = hgetc(); |
|
1717 } |
|
1718 add(c); |
|
1719 } |
|
1720 ALLOWHIST |
|
1721 break; |
|
1722 } |
|
1723 case '\"': |
|
1724 add(c); |
|
1725 while ((c = hgetc()) != '\"' && !lexstop) |
|
1726 if (c == '\\') { |
|
1727 add(c); |
|
1728 add(hgetc()); |
|
1729 } else |
|
1730 add(c); |
|
1731 break; |
|
1732 case '`': |
|
1733 add(c); |
|
1734 while ((c = hgetc()) != '`' && !lexstop) |
|
1735 if (c == '\\') |
|
1736 add(c), add(hgetc()); |
|
1737 else |
|
1738 add(c); |
|
1739 break; |
|
1740 } |
|
1741 } |
|
1742 while (pct); |
|
1743 if (!lexstop) |
|
1744 SETPAREND |
|
1745 cmdpop(); |
|
1746 return lexstop; |
|
1747 } |