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