lex.c revision 1.1.1.2 1 /*
2 * lexical analysis and source input
3 */
4
5 #include "sh.h"
6 #include <ctype.h>
7
8 static void readhere ARGS((struct ioword *iop));
9 static int getsc_ ARGS((void));
10 static void getsc_line ARGS((Source *s));
11 static char *get_brace_var ARGS((XString *wsp, char *wp));
12 static int arraysub ARGS((char **strp));
13 static const char *ungetsc_ ARGS((int c));
14 static int getsc_bn_ ARGS((void));
15
16 static void gethere ARGS((void));
17
18 /* optimized getsc_() */
19 #define getsc() ((*source->str != '\0') ? *source->str++ : getsc_())
20 #define getsc_bn() (*source->str != '\0' && *source->str != '\\' \
21 ? *source->str++ : getsc_bn_())
22 #define ungetsc(c) (source->str > source->start ? source->str-- : ungetsc_(c))
23
24
25 /*
26 * Lexical analyzer
27 *
28 * tokens are not regular expressions, they are LL(1).
29 * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
30 * hence the state stack.
31 */
32
33 int
34 yylex(cf)
35 int cf;
36 {
37 register int c, state;
38 char states [64], *statep = states; /* XXX overflow check */
39 XString ws; /* expandable output word */
40 register char *wp; /* output word pointer */
41 register char *sp, *dp;
42 char UNINITIALIZED(*ddparen_start);
43 int istate;
44 int UNINITIALIZED(c2);
45 int UNINITIALIZED(nparen), UNINITIALIZED(csstate);
46 int UNINITIALIZED(ndparen);
47 int UNINITIALIZED(indquotes);
48
49
50 Again:
51 Xinit(ws, wp, 64, ATEMP);
52
53 if (cf&ONEWORD)
54 istate = SWORD;
55 #ifdef KSH
56 else if (cf&LETEXPR) {
57 *wp++ = OQUOTE; /* enclose arguments in (double) quotes */
58 istate = SDPAREN;
59 ndparen = 0;
60 }
61 #endif /* KSH */
62 else { /* normal lexing */
63 istate = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
64 while ((c = getsc()) == ' ' || c == '\t')
65 ;
66 if (c == '#')
67 while ((c = getsc()) != '\0' && c != '\n')
68 ;
69 ungetsc(c);
70 }
71 if (source->flags & SF_ALIAS) { /* trailing ' ' in alias definition */
72 source->flags &= ~SF_ALIAS;
73 /* In POSIX mode, a trailing space only counts if we are
74 * parsing a simple command
75 */
76 if (!Flag(FPOSIX) || (cf & CMDWORD))
77 cf |= ALIAS;
78 }
79
80 /* collect non-special or quoted characters to form word */
81 for (*statep = state = istate;
82 !((c = getsc()) == 0 || ((state == SBASE || state == SHEREDELIM)
83 && ctype(c, C_LEX1))); )
84 {
85 Xcheck(ws, wp);
86 switch (state) {
87 case SBASE:
88 if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
89 *wp = EOS; /* temporary */
90 if (is_wdvarname(Xstring(ws, wp), FALSE))
91 {
92 char *p, *tmp;
93
94 if (arraysub(&tmp)) {
95 *wp++ = CHAR;
96 *wp++ = c;
97 for (p = tmp; *p; ) {
98 Xcheck(ws, wp);
99 *wp++ = CHAR;
100 *wp++ = *p++;
101 }
102 afree(tmp, ATEMP);
103 break;
104 } else {
105 Source *s;
106
107 s = pushs(SREREAD,
108 source->areap);
109 s->start = s->str
110 = s->u.freeme = tmp;
111 s->next = source;
112 source = s;
113 }
114 }
115 *wp++ = CHAR;
116 *wp++ = c;
117 break;
118 }
119 /* fall through.. */
120 Sbase1: /* includes *(...|...) pattern (*+?@!) */
121 #ifdef KSH
122 if (c == '*' || c == '@' || c == '+' || c == '?'
123 || c == '!')
124 {
125 c2 = getsc();
126 if (c2 == '(' /*)*/ ) {
127 *wp++ = OPAT;
128 *wp++ = c;
129 *++statep = state = SPATTERN;
130 break;
131 }
132 ungetsc(c2);
133 }
134 #endif /* KSH */
135 /* fall through.. */
136 Sbase2: /* doesn't include *(...|...) pattern (*+?@!) */
137 switch (c) {
138 case '\\':
139 c = getsc();
140 if (c != '\n') {
141 #ifdef OS2
142 if (isalnum(c)) {
143 *wp++ = CHAR, *wp++ = '\\';
144 *wp++ = CHAR, *wp++ = c;
145 } else
146 #endif
147 *wp++ = QCHAR, *wp++ = c;
148 } else
149 if (wp == Xstring(ws, wp)) {
150 Xfree(ws, wp); /* free word */
151 goto Again;
152 }
153 break;
154 case '\'':
155 *++statep = state = SSQUOTE;
156 *wp++ = OQUOTE;
157 break;
158 case '"':
159 *++statep = state = SDQUOTE;
160 *wp++ = OQUOTE;
161 break;
162 default:
163 goto Subst;
164 }
165 break;
166
167 Subst:
168 switch (c) {
169 case '\\':
170 c = getsc();
171 switch (c) {
172 case '\n':
173 break;
174 case '"': case '\\':
175 case '$': case '`':
176 *wp++ = QCHAR, *wp++ = c;
177 break;
178 default:
179 Xcheck(ws, wp);
180 *wp++ = CHAR, *wp++ = '\\';
181 *wp++ = CHAR, *wp++ = c;
182 break;
183 }
184 break;
185 case '$':
186 c = getsc();
187 if (c == '(') /*)*/ {
188 c = getsc();
189 if (c == '(') /*)*/ {
190 *++statep = state = SDDPAREN;
191 nparen = 2;
192 ddparen_start = wp;
193 *wp++ = EXPRSUB;
194 } else {
195 ungetsc(c);
196 *++statep = state = SPAREN;
197 nparen = 1;
198 csstate = 0;
199 *wp++ = COMSUB;
200 }
201 } else if (c == '{') /*}*/ {
202 *wp++ = OSUBST;
203 wp = get_brace_var(&ws, wp);
204 /* If this is a trim operation,
205 * wrap @(...) around the pattern
206 * (allows easy handling of ${a#b|c})
207 */
208 c = getsc_bn();
209 if (c == '#' || c == '%') {
210 *wp++ = CHAR, *wp++ = c;
211 if ((c2 = getsc_bn()) == c)
212 *wp++ = CHAR, *wp++ = c;
213 else
214 ungetsc(c2);
215 *wp++ = OPAT, *wp++ = '@';
216 *++statep = state = STBRACE;
217 } else {
218 ungetsc(c);
219 *++statep = state = SBRACE;
220 }
221 } else if (ctype(c, C_ALPHA)) {
222 *wp++ = OSUBST;
223 do {
224 Xcheck(ws, wp);
225 *wp++ = c;
226 c = getsc();
227 } while (ctype(c, C_ALPHA|C_DIGIT));
228 *wp++ = '\0';
229 *wp++ = CSUBST;
230 ungetsc(c);
231 } else if (ctype(c, C_DIGIT|C_VAR1)) {
232 Xcheck(ws, wp);
233 *wp++ = OSUBST;
234 *wp++ = c;
235 *wp++ = '\0';
236 *wp++ = CSUBST;
237 } else {
238 *wp++ = CHAR, *wp++ = '$';
239 ungetsc(c);
240 }
241 break;
242 case '`':
243 *++statep = state = SBQUOTE;
244 *wp++ = COMSUB;
245 /* Need to know if we are inside double quotes
246 * since sh/at&t-ksh translate the \" to " in
247 * "`..\"..`".
248 */
249 indquotes = 0;
250 if (!Flag(FPOSIX))
251 for (sp = statep; sp > states; --sp)
252 if (*sp == SDQUOTE)
253 indquotes = 1;
254 break;
255 default:
256 *wp++ = CHAR, *wp++ = c;
257 }
258 break;
259
260 case SSQUOTE:
261 if (c == '\'') {
262 state = *--statep;
263 *wp++ = CQUOTE;
264 } else
265 *wp++ = QCHAR, *wp++ = c;
266 break;
267
268 case SDQUOTE:
269 if (c == '"') {
270 state = *--statep;
271 *wp++ = CQUOTE;
272 } else
273 goto Subst;
274 break;
275
276 case SPAREN: /* $( .. ) */
277 /* todo: deal with $(...) quoting properly
278 * kludge to partly fake quoting inside $(..): doesn't
279 * really work because nested $(..) or ${..} inside
280 * double quotes aren't dealt with.
281 */
282 switch (csstate) {
283 case 0: /* normal */
284 switch (c) {
285 case '(':
286 nparen++;
287 break;
288 case ')':
289 nparen--;
290 break;
291 case '\\':
292 csstate = 1;
293 break;
294 case '"':
295 csstate = 2;
296 break;
297 case '\'':
298 csstate = 4;
299 break;
300 }
301 break;
302
303 case 1: /* backslash in normal mode */
304 case 3: /* backslash in double quotes */
305 --csstate;
306 break;
307
308 case 2: /* double quotes */
309 if (c == '"')
310 csstate = 0;
311 else if (c == '\\')
312 csstate = 3;
313 break;
314
315 case 4: /* single quotes */
316 if (c == '\'')
317 csstate = 0;
318 break;
319 }
320 if (nparen == 0) {
321 state = *--statep;
322 *wp++ = 0; /* end of COMSUB */
323 } else
324 *wp++ = c;
325 break;
326
327 case SDDPAREN: /* $(( .. )) */
328 /* todo: deal with $((...); (...)) properly */
329 /* XXX should nest using existing state machine
330 * (embed "..", $(...), etc.) */
331 if (c == '(')
332 nparen++;
333 else if (c == ')') {
334 nparen--;
335 if (nparen == 1) {
336 /*(*/
337 if ((c2 = getsc()) == ')') {
338 state = *--statep;
339 *wp++ = 0; /* end of EXPRSUB */
340 break;
341 } else {
342 ungetsc(c2);
343 /* mismatched parenthesis -
344 * assume we were really
345 * parsing a $(..) expression
346 */
347 memmove(ddparen_start + 1,
348 ddparen_start,
349 wp - ddparen_start);
350 *ddparen_start++ = COMSUB;
351 *ddparen_start = '('; /*)*/
352 wp++;
353 csstate = 0;
354 *statep = state = SPAREN;
355 }
356 }
357 }
358 *wp++ = c;
359 break;
360
361 case SBRACE:
362 /*{*/
363 if (c == '}') {
364 state = *--statep;
365 *wp++ = CSUBST;
366 } else
367 goto Sbase1;
368 break;
369
370 case STBRACE:
371 /* same as SBRACE, except | is saved as SPAT and
372 * CPAT is added at the end.
373 */
374 /*{*/
375 if (c == '}') {
376 state = *--statep;
377 *wp++ = CPAT;
378 *wp++ = CSUBST;
379 } else if (c == '|') {
380 *wp++ = SPAT;
381 } else
382 goto Sbase1;
383 break;
384
385 case SBQUOTE:
386 if (c == '`') {
387 *wp++ = 0;
388 state = *--statep;
389 } else if (c == '\\') {
390 switch (c = getsc()) {
391 case '\n':
392 break;
393 case '\\':
394 case '$': case '`':
395 *wp++ = c;
396 break;
397 case '"':
398 if (indquotes) {
399 *wp++ = c;
400 break;
401 }
402 /* fall through.. */
403 default:
404 *wp++ = '\\';
405 *wp++ = c;
406 break;
407 }
408 } else
409 *wp++ = c;
410 break;
411
412 case SWORD: /* ONEWORD */
413 goto Subst;
414
415 #ifdef KSH
416 case SDPAREN: /* LETEXPR: (( ... )) */
417 /*(*/
418 if (c == ')') {
419 if (ndparen > 0)
420 --ndparen;
421 /*(*/
422 else if ((c2 = getsc()) == ')') {
423 c = 0;
424 *wp++ = CQUOTE;
425 goto Done;
426 } else
427 ungetsc(c2);
428 } else if (c == '(')
429 /* parenthesis inside quotes and backslashes
430 * are lost, but at&t ksh doesn't count them
431 * either
432 */
433 ++ndparen;
434 goto Sbase2;
435 #endif /* KSH */
436
437 case SHEREDELIM: /* <<,<<- delimiter */
438 /* XXX chuck this state (and the next) - use
439 * the existing states ($ and \`..` should be
440 * stripped of their specialness after the
441 * fact).
442 */
443 /* here delimiters need a special case since
444 * $ and `..` are not to be treated specially
445 */
446 if (c == '\\') {
447 c = getsc();
448 if (c != '\n') {
449 *wp++ = QCHAR;
450 *wp++ = c;
451 }
452 } else if (c == '\'') {
453 *++statep = state = SSQUOTE;
454 *wp++ = OQUOTE;
455 } else if (c == '"') {
456 state = SHEREDQUOTE;
457 *wp++ = OQUOTE;
458 } else {
459 *wp++ = CHAR;
460 *wp++ = c;
461 }
462 break;
463
464 case SHEREDQUOTE: /* " in <<,<<- delimiter */
465 if (c == '"') {
466 *wp++ = CQUOTE;
467 state = SHEREDELIM;
468 } else {
469 if (c == '\\' && (c = getsc()) == '\n')
470 break;
471 *wp++ = CHAR;
472 *wp++ = c;
473 }
474 break;
475
476 case SPATTERN: /* in *(...|...) pattern (*+?@!) */
477 if ( /*(*/ c == ')') {
478 *wp++ = CPAT;
479 state = *--statep;
480 } else if (c == '|')
481 *wp++ = SPAT;
482 else
483 goto Sbase1;
484 break;
485 }
486 }
487 Done:
488 Xcheck(ws, wp);
489 if (state != istate)
490 yyerror("no closing quote\n");
491
492 /* This done to avoid tests for SHEREDELIM wherever SBASE tested */
493 if (state == SHEREDELIM)
494 state = SBASE;
495
496 if ((c == '<' || c == '>') && state == SBASE) {
497 char *cp = Xstring(ws, wp);
498 if (Xlength(ws, wp) == 2 && cp[0] == CHAR && digit(cp[1])) {
499 wp = cp; /* throw away word */
500 c2/*unit*/ = cp[1] - '0';
501 } else
502 c2/*unit*/ = c == '>'; /* 0 for <, 1 for > */
503 }
504
505 if (wp == Xstring(ws, wp) && state == SBASE) {
506 Xfree(ws, wp); /* free word */
507 /* no word, process LEX1 character */
508 switch (c) {
509 default:
510 return c;
511
512 case '|':
513 case '&':
514 case ';':
515 if ((c2 = getsc()) == c)
516 c = (c == ';') ? BREAK :
517 (c == '|') ? LOGOR :
518 (c == '&') ? LOGAND :
519 YYERRCODE;
520 #ifdef KSH
521 else if (c == '|' && c2 == '&')
522 c = COPROC;
523 #endif /* KSH */
524 else
525 ungetsc(c2);
526 return c;
527
528 case '>':
529 case '<': {
530 register struct ioword *iop;
531
532 iop = (struct ioword *) alloc(sizeof(*iop), ATEMP);
533 iop->unit = c2/*unit*/;
534
535 c2 = getsc();
536 /* <<, >>, <> are ok, >< is not */
537 if (c == c2 || (c == '<' && c2 == '>')) {
538 iop->flag = c == c2 ?
539 (c == '>' ? IOCAT : IOHERE) : IORDWR;
540 if (iop->flag == IOHERE)
541 if (getsc() == '-')
542 iop->flag |= IOSKIP;
543 else
544 ungetsc(c2);
545 } else if (c2 == '&')
546 iop->flag = IODUP | (c == '<' ? IORDUP : 0);
547 else {
548 iop->flag = c == '>' ? IOWRITE : IOREAD;
549 if (c == '>' && c2 == '|')
550 iop->flag |= IOCLOB;
551 else
552 ungetsc(c2);
553 }
554
555 iop->name = (char *) 0;
556 iop->delim = (char *) 0;
557 yylval.iop = iop;
558 return REDIR;
559 }
560 case '\n':
561 gethere();
562 if (cf & CONTIN)
563 goto Again;
564 return c;
565
566 case '(': /*)*/
567 #ifdef KSH
568 if ((c2 = getsc()) == '(') /*)*/
569 c = MDPAREN;
570 else
571 ungetsc(c2);
572 #endif /* KSH */
573 return c;
574 /*(*/
575 case ')':
576 return c;
577 }
578 }
579
580 *wp++ = EOS; /* terminate word */
581 yylval.cp = Xclose(ws, wp);
582 if (state == SWORD
583 #ifdef KSH
584 || state == SDPAREN
585 #endif /* KSH */
586 ) /* ONEWORD? */
587 return LWORD;
588 ungetsc(c); /* unget terminator */
589
590 /* copy word to unprefixed string ident */
591 for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
592 *dp++ = *sp++;
593 /* Make sure the ident array stays '\0' paded */
594 memset(dp, 0, (ident+IDENT) - dp + 1);
595 if (c != EOS)
596 *ident = '\0'; /* word is not unquoted */
597
598 if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
599 struct tbl *p;
600 int h = hash(ident);
601
602 /* { */
603 if ((cf & KEYWORD) && (p = tsearch(&keywords, ident, h))
604 && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}'))
605 {
606 afree(yylval.cp, ATEMP);
607 return p->val.i;
608 }
609 if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h))
610 && (p->flag & ISSET))
611 {
612 register Source *s;
613
614 for (s = source; s->type == SALIAS; s = s->next)
615 if (s->u.tblp == p)
616 return LWORD;
617 /* push alias expansion */
618 s = pushs(SALIAS, source->areap);
619 s->start = s->str = p->val.s;
620 s->u.tblp = p;
621 s->next = source;
622 source = s;
623 afree(yylval.cp, ATEMP);
624 goto Again;
625 }
626 }
627
628 return LWORD;
629 }
630
631 static void
632 gethere()
633 {
634 register struct ioword **p;
635
636 for (p = heres; p < herep; p++)
637 readhere(*p);
638 herep = heres;
639 }
640
641 /*
642 * read "<<word" text into temp file
643 */
644
645 static void
646 readhere(iop)
647 register struct ioword *iop;
648 {
649 struct shf *volatile shf;
650 struct temp *h;
651 register int c;
652 char *volatile eof;
653 char *eofp;
654 int skiptabs, bn;
655 int i;
656
657 eof = evalstr(iop->delim, 0);
658
659 if (e->flags & EF_FUNC_PARSE) {
660 h = maketemp(APERM);
661 h->next = func_heredocs;
662 func_heredocs = h;
663 } else {
664 h = maketemp(ATEMP);
665 h->next = e->temps;
666 e->temps = h;
667 }
668 iop->name = h->name;
669 if (!(shf = h->shf))
670 yyerror("cannot create temporary file %s - %s\n",
671 h->name, strerror(errno));
672
673 newenv(E_ERRH);
674 i = ksh_sigsetjmp(e->jbuf, 0);
675 if (i) {
676 quitenv();
677 shf_close(shf);
678 unwind(i);
679 }
680
681 bn = iop->flag & IOEVAL;
682 for (;;) {
683 eofp = eof;
684 skiptabs = iop->flag & IOSKIP;
685 while ((c = (bn ? getsc_bn() : getsc())) != 0) {
686 if (skiptabs) {
687 if (c == '\t')
688 continue;
689 skiptabs = 0;
690 }
691 if (c != *eofp)
692 break;
693 eofp++;
694 }
695 /* Allow EOF here so commands with out trailing newlines
696 * will work (eg, ksh -c '...', $(...), etc).
697 */
698 if (*eofp == '\0' && (c == 0 || c == '\n'))
699 break;
700 ungetsc(c);
701 shf_write(eof, eofp - eof, shf);
702 while ((c = (bn ? getsc_bn() : getsc())) != '\n') {
703 if (c == 0)
704 yyerror("here document `%s' unclosed\n", eof);
705 shf_putc(c, shf);
706 }
707 shf_putc(c, shf);
708 }
709 shf_flush(shf);
710 if (shf_error(shf))
711 yyerror("error saving here document `%s': %s\n",
712 eof, strerror(shf_errno(shf)));
713 /*XXX add similar checks for write errors everywhere */
714 quitenv();
715 shf_close(shf);
716 }
717
718 void
719 #ifdef HAVE_PROTOTYPES
720 yyerror(const char *fmt, ...)
721 #else
722 yyerror(fmt, va_alist)
723 const char *fmt;
724 va_dcl
725 #endif
726 {
727 va_list va;
728
729 yynerrs++;
730 /* pop aliases and re-reads */
731 while (source->type == SALIAS || source->type == SREREAD)
732 source = source->next;
733 source->str = null; /* zap pending input */
734
735 error_prefix(TRUE);
736 SH_VA_START(va, fmt);
737 shf_vfprintf(shl_out, fmt, va);
738 va_end(va);
739 errorf(null);
740 }
741
742 /*
743 * input for yylex with alias expansion
744 */
745
746 Source *
747 pushs(type, areap)
748 int type;
749 Area *areap;
750 {
751 register Source *s;
752
753 s = (Source *) alloc(sizeof(Source), areap);
754 s->type = type;
755 s->str = null;
756 s->start = NULL;
757 s->line = 0;
758 s->errline = 0;
759 s->file = NULL;
760 s->flags = 0;
761 s->next = NULL;
762 s->areap = areap;
763 if (type == SFILE || type == SSTDIN) {
764 char *dummy;
765 Xinit(s->xs, dummy, 256, s->areap);
766 } else
767 memset(&s->xs, 0, sizeof(s->xs));
768 return s;
769 }
770
771 static int
772 getsc_()
773 {
774 register Source *s = source;
775 register int c;
776
777 while ((c = *s->str++) == 0) {
778 s->str = NULL; /* return 0 for EOF by default */
779 switch (s->type) {
780 case SEOF:
781 s->str = null;
782 return 0;
783
784 case SSTDIN:
785 case SFILE:
786 getsc_line(s);
787 break;
788
789 case SWSTR:
790 break;
791
792 case SSTRING:
793 break;
794
795 case SWORDS:
796 s->start = s->str = *s->u.strv++;
797 s->type = SWORDSEP;
798 break;
799
800 case SWORDSEP:
801 if (*s->u.strv == NULL) {
802 s->start = s->str = newline;
803 s->type = SEOF;
804 } else {
805 s->start = s->str = space;
806 s->type = SWORDS;
807 }
808 break;
809
810 case SALIAS:
811 if (s->flags & SF_ALIASEND) {
812 /* pass on an unused SF_ALIAS flag */
813 source = s->next;
814 source->flags |= s->flags & SF_ALIAS;
815 s = source;
816 } else if (*s->u.tblp->val.s
817 && isspace(strchr(s->u.tblp->val.s, 0)[-1]))
818 {
819 source = s = s->next; /* pop source stack */
820 s->flags |= SF_ALIAS;
821 } else {
822 /* put a fake space at the end of the alias.
823 * This keeps the current alias in the source
824 * list so recursive aliases can be detected.
825 * The addition of a space after an alias
826 * never affects anything (I think).
827 */
828 s->flags |= SF_ALIASEND;
829 s->start = s->str = space;
830 }
831 continue;
832
833 case SREREAD:
834 if (s->start != s->u.ugbuf) /* yuck */
835 afree(s->u.freeme, ATEMP);
836 source = s = s->next;
837 continue;
838 }
839 if (s->str == NULL) {
840 s->type = SEOF;
841 s->start = s->str = null;
842 return '\0';
843 }
844 if (s->flags & SF_ECHO) {
845 shf_puts(s->str, shl_out);
846 shf_flush(shl_out);
847 }
848 }
849 return c;
850 }
851
852 static void
853 getsc_line(s)
854 Source *s;
855 {
856 char *xp = Xstring(s->xs, xp);
857 int interactive = Flag(FTALKING) && s->type == SSTDIN;
858 int have_tty = interactive && (s->flags & SF_TTY);
859
860 /* Done here to ensure nothing odd happens when a timeout occurs */
861 XcheckN(s->xs, xp, LINE);
862 *xp = '\0';
863 s->start = s->str = xp;
864
865 #ifdef KSH
866 if (have_tty && ksh_tmout) {
867 ksh_tmout_state = TMOUT_READING;
868 alarm(ksh_tmout);
869 }
870 #endif /* KSH */
871 #ifdef EDIT
872 if (have_tty && (0
873 # ifdef VI
874 || Flag(FVI)
875 # endif /* VI */
876 # ifdef EMACS
877 || Flag(FEMACS) || Flag(FGMACS)
878 # endif /* EMACS */
879 ))
880 {
881 int nread;
882
883 nread = x_read(xp, LINE);
884 if (nread < 0) /* read error */
885 nread = 0;
886 xp[nread] = '\0';
887 xp += nread;
888 }
889 else
890 #endif /* EDIT */
891 {
892 if (interactive) {
893 pprompt(prompt, 0);
894 #ifdef OS2
895 setmode (0, O_TEXT);
896 #endif /* OS2 */
897 } else
898 s->line++;
899
900 while (1) {
901 char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
902
903 if (!p && shf_error(s->u.shf)
904 && shf_errno(s->u.shf) == EINTR)
905 {
906 shf_clearerr(s->u.shf);
907 if (trap)
908 runtraps(0);
909 continue;
910 }
911 if (!p || (xp = p, xp[-1] == '\n'))
912 break;
913 /* double buffer size */
914 xp++; /* move past null so doubling works... */
915 XcheckN(s->xs, xp, Xlength(s->xs, xp));
916 xp--; /* ...and move back again */
917 }
918 #ifdef OS2
919 setmode(0, O_BINARY);
920 #endif /* OS2 */
921 /* flush any unwanted input so other programs/builtins
922 * can read it. Not very optimal, but less error prone
923 * than flushing else where, dealing with redirections,
924 * etc..
925 * todo: reduce size of shf buffer (~128?) if SSTDIN
926 */
927 if (s->type == SSTDIN)
928 shf_flush(s->u.shf);
929 }
930 /* XXX: temporary kludge to restore source after a
931 * trap may have been executed.
932 */
933 source = s;
934 #ifdef KSH
935 if (have_tty && ksh_tmout)
936 {
937 ksh_tmout_state = TMOUT_EXECUTING;
938 alarm(0);
939 }
940 #endif /* KSH */
941 s->start = s->str = Xstring(s->xs, xp);
942 strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
943 /* Note: if input is all nulls, this is not eof */
944 if (Xlength(s->xs, xp) == 0) { /* EOF */
945 if (s->type == SFILE)
946 shf_fdclose(s->u.shf);
947 s->str = NULL;
948 } else if (interactive) {
949 #ifdef HISTORY
950 char *p = Xstring(s->xs, xp);
951 if (cur_prompt == PS1)
952 while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
953 p++;
954 if (*p) {
955 # ifdef EASY_HISTORY
956 if (cur_prompt == PS2)
957 histappend(Xstring(s->xs, xp), 1);
958 else
959 # endif /* EASY_HISTORY */
960 {
961 s->line++;
962 histsave(s->line, s->str, 1);
963 }
964 }
965 #endif /* HISTORY */
966 }
967 if (interactive)
968 set_prompt(PS2, (Source *) 0);
969 }
970
971 void
972 set_prompt(to, s)
973 int to;
974 Source *s;
975 {
976 cur_prompt = to;
977
978 switch (to) {
979 case PS1: /* command */
980 #ifdef KSH
981 /* Substitute ! and !! here, before substitutions are done
982 * so ! in expanded variables are not expanded.
983 * NOTE: this is not what at&t ksh does (it does it after
984 * substitutions, POSIX doesn't say which is to be done.
985 */
986 {
987 struct shf *shf;
988 char *ps1;
989 Area *saved_atemp;
990
991 ps1 = str_val(global("PS1"));
992 shf = shf_sopen((char *) 0, strlen(ps1) * 2,
993 SHF_WR | SHF_DYNAMIC, (struct shf *) 0);
994 while (*ps1) {
995 if (*ps1 != '!' || *++ps1 == '!')
996 shf_putchar(*ps1++, shf);
997 else
998 shf_fprintf(shf, "%d",
999 s ? s->line + 1 : 0);
1000 }
1001 ps1 = shf_sclose(shf);
1002 saved_atemp = ATEMP;
1003 newenv(E_ERRH);
1004 if (ksh_sigsetjmp(e->jbuf, 0)) {
1005 prompt = safe_prompt;
1006 /* Don't print an error - assume it has already
1007 * been printed. Reason is we may have forked
1008 * to run a command and the child may be
1009 * unwinding its stack through this code as it
1010 * exits.
1011 */
1012 } else
1013 prompt = str_save(substitute(ps1, 0),
1014 saved_atemp);
1015 quitenv();
1016 }
1017 #else /* KSH */
1018 prompt = str_val(global("PS1"));
1019 #endif /* KSH */
1020 break;
1021
1022 case PS2: /* command continuation */
1023 prompt = str_val(global("PS2"));
1024 break;
1025 }
1026 }
1027
1028 /* See also related routine, promptlen() in edit.c */
1029 void
1030 pprompt(cp, ntruncate)
1031 const char *cp;
1032 int ntruncate;
1033 {
1034 #if 0
1035 char nbuf[32];
1036 int c;
1037
1038 while (*cp != 0) {
1039 if (*cp != '!')
1040 c = *cp++;
1041 else if (*++cp == '!')
1042 c = *cp++;
1043 else {
1044 int len;
1045 char *p;
1046
1047 shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
1048 source->line + 1);
1049 len = strlen(nbuf);
1050 if (ntruncate) {
1051 if (ntruncate >= len) {
1052 ntruncate -= len;
1053 continue;
1054 }
1055 p += ntruncate;
1056 len -= ntruncate;
1057 ntruncate = 0;
1058 }
1059 shf_write(p, len, shl_out);
1060 continue;
1061 }
1062 if (ntruncate)
1063 --ntruncate;
1064 else
1065 shf_putc(c, shl_out);
1066 }
1067 #endif /* 0 */
1068 shf_puts(cp + ntruncate, shl_out);
1069 shf_flush(shl_out);
1070 }
1071
1072 /* Read the variable part of a ${...} expression (ie, up to but not including
1073 * the :[-+?=#%] or close-brace.
1074 */
1075 static char *
1076 get_brace_var(wsp, wp)
1077 XString *wsp;
1078 char *wp;
1079 {
1080 enum parse_state {
1081 PS_INITIAL, PS_SAW_HASH, PS_IDENT,
1082 PS_NUMBER, PS_VAR1, PS_END
1083 }
1084 state;
1085 char c;
1086
1087 state = PS_INITIAL;
1088 while (1) {
1089 c = getsc_bn();
1090 /* State machine to figure out where the variable part ends. */
1091 switch (state) {
1092 case PS_INITIAL:
1093 if (c == '#') {
1094 state = PS_SAW_HASH;
1095 break;
1096 }
1097 /* fall through.. */
1098 case PS_SAW_HASH:
1099 if (letter(c))
1100 state = PS_IDENT;
1101 else if (digit(c))
1102 state = PS_NUMBER;
1103 else if (ctype(c, C_VAR1))
1104 state = PS_VAR1;
1105 else
1106 state = PS_END;
1107 break;
1108 case PS_IDENT:
1109 if (!letnum(c)) {
1110 state = PS_END;
1111 if (c == '[') {
1112 char *tmp, *p;
1113
1114 if (!arraysub(&tmp))
1115 yyerror("missing ]\n");
1116 *wp++ = c;
1117 for (p = tmp; *p; ) {
1118 Xcheck(*wsp, wp);
1119 *wp++ = *p++;
1120 }
1121 afree(tmp, ATEMP);
1122 c = getsc();
1123 }
1124 }
1125 break;
1126 case PS_NUMBER:
1127 if (!digit(c))
1128 state = PS_END;
1129 break;
1130 case PS_VAR1:
1131 state = PS_END;
1132 break;
1133 case PS_END: /* keep gcc happy */
1134 break;
1135 }
1136 if (state == PS_END) {
1137 *wp++ = '\0'; /* end of variable part */
1138 ungetsc(c);
1139 break;
1140 }
1141 Xcheck(*wsp, wp);
1142 *wp++ = c;
1143 }
1144 return wp;
1145 }
1146
1147 /*
1148 * Save an array subscript - returns true if matching bracket found, false
1149 * if eof or newline was found.
1150 * (Returned string double null terminated)
1151 */
1152 static int
1153 arraysub(strp)
1154 char **strp;
1155 {
1156 XString ws;
1157 char *wp;
1158 char c;
1159 int depth = 1; /* we are just past the initial [ */
1160
1161 Xinit(ws, wp, 32, ATEMP);
1162
1163 do {
1164 c = getsc_bn();
1165 Xcheck(ws, wp);
1166 *wp++ = c;
1167 if (c == '[')
1168 depth++;
1169 else if (c == ']')
1170 depth--;
1171 } while (depth > 0 && c && c != '\n');
1172
1173 *wp++ = '\0';
1174 *strp = Xclose(ws, wp);
1175
1176 return depth == 0 ? 1 : 0;
1177 }
1178
1179 /* Unget a char: handles case when we are already at the start of the buffer */
1180 static const char *
1181 ungetsc_(c)
1182 int c;
1183 {
1184 /* Don't unget eof... */
1185 if (source->str == null && c == '\0')
1186 return source->str;
1187 if (source->str > source->start)
1188 source->str--;
1189 else {
1190 Source *s;
1191
1192 s = pushs(SREREAD, source->areap);
1193 s->u.ugbuf[0] = c; s->u.ugbuf[1] = '\0';
1194 s->start = s->str = s->u.ugbuf;
1195 s->next = source;
1196 source = s;
1197 }
1198 return source->str;
1199 }
1200
1201 /* Called to get a char that isn't a \newline sequence. */
1202 static int
1203 getsc_bn_ ARGS((void))
1204 {
1205 int c;
1206
1207 while (1) {
1208 c = getsc_();
1209 if (c != '\\')
1210 return c;
1211 c = getsc();
1212 if (c != '\n') {
1213 ungetsc(c);
1214 return '\\';
1215 }
1216 /* ignore the \newline; get the next char... */
1217 }
1218 }
1219