|
|
1.1 root 1: /*
2:
1.1.1.3 root 3: Copyright 1990,1991,1992 Eric R. Smith.
4:
1.1.1.5 ! root 5: Copyright 1992,1993 Atari Corporation.
1.1.1.3 root 6:
7: All rights reserved.
1.1 root 8:
9: */
10:
11:
12:
13: /*
14:
15: * read/write routines for TTY devices
16:
17: */
18:
19:
20:
21: #include "mint.h"
22:
23:
24:
25: static void _erase P_((FILEPTR *, int));
26:
27: static int escseq P_((struct tty *, int));
28:
29:
30:
31: /* setting a special character to this value disables it */
32:
33: #define UNDEF 0
34:
35:
36:
37:
38:
39: /* default terminal characteristics */
40:
41:
42:
43: struct tty default_tty = {
44:
45: 0, /* process group */
46:
47: 0, /* state */
48:
49: 0, /* use_cnt */
50:
51: 0, /* reserved short */
52:
53: {
54:
55: 13, 13, /* input speed == output speed == 9600 baud */
56:
57: CTRL('H'), /* erase */
58:
59: CTRL('U'), /* kill */
60:
61: T_ECHO|T_CRMOD|T_TOSTOP|T_XKEY, /* flags */
62:
63: },
64:
65: {
66:
67: CTRL('C'), /* interrupt */
68:
69: CTRL('\\'), /* quit */
70:
71: CTRL('Q'), /* start */
72:
73: CTRL('S'), /* stop */
74:
75: CTRL('D'), /* EOF */
76:
77: '\r' /* alternate end of line */
78:
79: },
80:
81: {
82:
83: CTRL('Z'), /* suspend */
84:
85: CTRL('Y'), /* suspend after read */
86:
87: CTRL('R'), /* reprint */
88:
89: UNDEF, /* flush output */
90:
1.1.1.2 root 91: CTRL('W'), /* erase word */
1.1 root 92:
1.1.1.2 root 93: CTRL('V') /* quote next char */
1.1 root 94:
95: },
96:
97: {
98:
99: 0, 0, 0, 0 /* window size is unknown */
100:
101: },
102:
103: 0, /* no process is selecting us for reading */
104:
105: 0, /* or for writing */
106:
107: 0 /* use default XKEY map */
108:
109: };
110:
111:
112:
113: #define _put(f, c) (tty_putchar((f), (c), RAW))
114:
115:
116:
117: static void
118:
119: _erase(f, c)
120:
121: FILEPTR *f;
122:
123: int c;
124:
125: {
126:
127: _put(f, '\010');
128:
129: _put(f, ' ');
130:
131: _put(f, '\010');
132:
133: /* watch out for control characters -- they're printed as e.g. "^C" */
134:
1.1.1.2 root 135: /* BUG: \t is messed up. We really need to keep track of the output
136:
137: * column
138:
139: */
140:
141: if (c >= 0 && c < ' ' && c != '\t') {
1.1 root 142:
143: _put(f, '\010'); _put(f, ' '); _put(f, '\010');
144:
145: }
146:
147: }
148:
149:
150:
151: #define put(f, c) { if (mode & T_ECHO) _put(f, c); }
152:
153: #define erase(f, c) { if (mode & T_ECHO) _erase(f, c); }
154:
155:
156:
157: long
158:
159: tty_read(f, buf, nbytes)
160:
161: FILEPTR *f;
162:
163: void *buf;
164:
165: long nbytes;
166:
167: {
168:
169: long r;
170:
171: long bytes_read = 0;
172:
173: unsigned char ch, *ptr;
174:
175: int rdmode, mode;
176:
177: struct tty *tty;
178:
179:
180:
181: tty = (struct tty *)f->devinfo;
182:
183: assert(tty != 0);
184:
185:
186:
187: if (f->flags & O_HEAD) { /* pty server side? */
188:
189: rdmode = RAW; /* yes -- always raw mode */
190:
191: mode = T_RAW;
192:
193: }
194:
195: else if (curproc->domain == DOM_MINT) { /* MiNT domain process? */
196:
197: mode = tty->sg.sg_flags;
198:
199: rdmode = COOKED|NOECHO;
200:
201: if ( mode & (T_RAW | T_CBREAK) ) {
202:
203: rdmode = (mode & T_RAW) ? RAW : COOKED;
204:
205: }
206:
207: if (mode & T_XKEY)
208:
209: rdmode |= ESCSEQ;
210:
211: }
212:
213: else {
214:
215: rdmode = COOKED|NOECHO;
216:
217: mode = T_TOS | T_ECHO;
218:
219: }
220:
221:
222:
223: ptr = buf;
224:
225:
226:
227: while (bytes_read < nbytes) {
228:
229: r = tty_getchar(f, rdmode);
230:
231: if (r < 0) {
232:
1.1.1.2 root 233: tty_error:
234:
235: DEBUG(("tty_read: tty_getchar returned %ld", r));
1.1 root 236:
237: return (bytes_read) ? bytes_read : r;
238:
239: }
240:
241: else if (r == MiNTEOF)
242:
243: return bytes_read;
244:
245: ch = r & 0xff;
246:
247:
248:
249: if ( (mode & T_CRMOD) && (ch == '\r') )
250:
251: ch = '\n';
252:
253:
254:
255: /* 1 character reads in TOS mode are always raw */
256:
257: if (nbytes == 1 && (mode & T_TOS)) {
258:
259: put(f, ch);
260:
261: *ptr = ch;
262:
263: return 1;
264:
265: }
266:
267:
268:
269: /* T_CBREAK mode doesn't do erase or kill processing */
270:
271: /* also note that setting a special character to UNDEF disables it */
272:
273:
274:
275: if (rdmode & COOKED && !(mode & T_CBREAK) && ch != UNDEF) {
276:
277: if ((char)ch == tty->sg.sg_erase) { /* backspace */
278:
279: if (bytes_read > 0) {
280:
281: --ptr;
282:
283: erase(f, *ptr);
284:
285: bytes_read--;
286:
287: }
288:
289: continue;
290:
291: }
292:
1.1.1.2 root 293: else if ((mode & T_TOS) && ch == CTRL('X')) {
1.1 root 294:
295: while (bytes_read > 0) {
296:
297: --ptr;
298:
299: erase(f, *ptr);
300:
301: bytes_read--;
302:
303: }
304:
305: continue;
306:
307: }
308:
309: else if ((char)ch ==tty->ltc.t_rprntc ||
310:
311: (char)ch == tty->sg.sg_kill) {
312:
313: if (mode & T_TOS)
314:
315: put(f, '#');
316:
317: put(f, '\r');
318:
319: put(f, '\n');
320:
321: ptr = buf;
322:
323: if ((char)ch == tty->sg.sg_kill) {
324:
325: bytes_read = 0;
326:
327: }
328:
329: else {
330:
331: for (r = 0; r < bytes_read; r++, ptr++)
332:
333: put(f, *ptr);
334:
335: }
336:
337: continue;
338:
339: }
340:
1.1.1.2 root 341: else if ((char)ch == tty->ltc.t_werasc) {
342:
343: while (bytes_read > 0 &&
344:
345: !(ptr[-1] == ' ' || ptr[-1] == '\t')) {
346:
347: ptr--;
348:
349: erase(f, *ptr);
350:
351: bytes_read--;
352:
353: }
354:
355: continue;
356:
357: }
358:
359: else if ((char)ch == tty->ltc.t_lnextc) {
360:
361: put(f, '^');
362:
363: put(f, '\b');
364:
365: r = tty_getchar(f, RAW);
366:
367: if (r < 0)
368:
369: goto tty_error;
370:
371: else if (r == MiNTEOF)
372:
373: return bytes_read;
374:
375: ch = r & 0xff;
376:
377: goto stuff_it;
378:
379: }
380:
1.1 root 381: else if ((char)ch == tty->tc.t_eofc && !(mode & T_TOS))
382:
383: return bytes_read;
384:
385: }
386:
387:
388:
389: /* both T_CBREAK and T_COOKED modes have to do signals, though */
390:
391: if ((rdmode & COOKED) && ch != UNDEF) {
392:
393: if ((char)ch == tty->tc.t_intrc
394:
395: || (char)ch == tty->tc.t_quitc
396:
397: || (char)ch == tty->ltc.t_dsuspc
398:
399: || (char)ch == tty->ltc.t_suspc
400:
401: ) {
402:
403: /* the device driver raised the appropriate signal; if we get here, the
404:
405: signal was caught by the user (or ignored). flush buffers and continue
406:
407: */
408:
409: if (!(tty->sg.sg_flags & T_NOFLSH)) {
410:
1.1.1.2 root 411: DEBUG(("tty_read: flushing input"));
1.1 root 412:
413: bytes_read = 0;
414:
415: ptr = buf;
416:
417: }
418:
419: continue;
420:
421: }
422:
423: else if (ch == '\n' || (char)ch == tty->tc.t_brkc) {
424:
425: put(f, '\r');
426:
427: if (!(mode & T_TOS)) {
428:
1.1.1.2 root 429: *ptr = ch;
1.1 root 430:
431: put(f, '\n');
432:
433: bytes_read++;
434:
435: }
436:
437: return bytes_read;
438:
439: }
440:
441:
442:
443: }
444:
445:
446:
447: /* do the following for both RAW and COOKED mode */
448:
1.1.1.2 root 449: stuff_it:
450:
1.1 root 451: *ptr++ = ch;
452:
1.1.1.2 root 453: if (ch < ' ' && ch != '\t') { /* ch is unsigned */
1.1 root 454:
455: put(f, '^'); put(f, ch+'@');
456:
457: }
458:
459: else
460:
461: put(f, ch);
462:
463: bytes_read++;
464:
465:
466:
467: /* for RAW mode, if there are no more characters then break */
468:
469: if ( (mode & (T_RAW|T_CBREAK)) &&
470:
471: !((rdmode & ESCSEQ) && (tty->state & TS_ESC))) {
472:
473: r = 1;
474:
475: (void)(*f->dev->ioctl)(f, FIONREAD, &r);
476:
477: if (r <= 0) break;
478:
479: }
480:
481: }
482:
483:
484:
485: return bytes_read;
486:
487: }
488:
489:
490:
491: long
492:
493: tty_write(f, buf, nbytes)
494:
495: FILEPTR *f;
496:
497: const void *buf;
498:
499: long nbytes;
500:
501: {
502:
503: unsigned const char *ptr;
504:
505: long c;
506:
507: long bytes_written;
508:
509: int mode, rwmode;
510:
511: struct tty *tty;
512:
513: int use_putchar = 0;
514:
515: static long cr_char = '\r';
516:
517: #define LBUFSIZ 128
518:
519: long lbuf[LBUFSIZ];
520:
521:
522:
523: tty = (struct tty *)f->devinfo;
524:
525: assert(tty != 0);
526:
527:
528:
529: ptr = buf;
530:
531: if (f->flags & O_HEAD) {
532:
533: use_putchar = 1;
534:
535: mode = T_RAW;
536:
537: }
538:
539: else if (curproc->domain == DOM_TOS)
540:
541: /* for TOS programs, 1 byte writes are always in raw mode */
542:
543: mode = (nbytes == 1) ? T_RAW : T_TOS;
544:
545: else
546:
547: mode = tty->sg.sg_flags;
548:
549:
550:
551: rwmode = (mode & T_RAW) ? RAW : COOKED;
552:
553:
554:
555: bytes_written = 0;
556:
557:
558:
559: /*
560:
561: * "mode" can now be reduced to just T_CRMODE or not
562:
563: */
564:
565: if ((curproc->domain == DOM_MINT) && (mode & T_CRMOD) &&
566:
567: !(mode & T_RAW))
568:
569: mode = T_CRMOD;
570:
571: else
572:
573: mode = 0;
574:
575:
576:
577: /*
578:
579: * we always write at least 1 byte with tty_putchar, since that takes
580:
581: * care of job control and terminal states. After that, we may be able
582:
583: * to use (*f->dev->write) directly.
584:
585: */
586:
587:
588:
589:
590:
591: if (nbytes == 0) return bytes_written;
592:
593: c = *ptr++;
594:
595:
596:
597: if (c == '\n' && mode) { /* remember, "mode" now means CRMOD */
598:
599: tty_putchar(f, cr_char, rwmode);
600:
601: }
602:
603: tty_putchar(f, c, rwmode);
604:
605: nbytes--;
606:
607: bytes_written++;
608:
609:
610:
611: if (use_putchar) {
612:
613: while (nbytes-- > 0) {
614:
615: c = *ptr++;
616:
617: if (c == '\n' && mode)
618:
619: tty_putchar(f, cr_char, rwmode);
620:
621: tty_putchar(f, c, rwmode);
622:
623: bytes_written++;
624:
625: }
626:
627: } else {
628:
629: /* write in big chunks if possible; but never more than 1 line
630:
631: * (so that ^S/^Q can happen reasonably quickly for the user)
632:
633: */
634:
635: long bytes_to_write = 0;
636:
637: long *s = lbuf;
638:
639:
640:
641: while (nbytes-- > 0) {
642:
643: c = *ptr++;
644:
645: if (c == '\n') {
646:
647: if (bytes_to_write) {
648:
649: (*f->dev->write)(f, (char *)lbuf,
650:
651: bytes_to_write);
652:
653: bytes_to_write = 0;
654:
655: s = lbuf;
656:
657: }
658:
659: if (mode) /* i.e. T_CRMODE */
660:
661: tty_putchar(f, cr_char, rwmode);
662:
663: tty_putchar(f, (long)c, rwmode);
664:
665: bytes_written++;
666:
667: } else {
668:
669: *s++ = c;
670:
671: bytes_written++;
672:
673: bytes_to_write += 4;
674:
675: if (bytes_to_write >= LBUFSIZ*4) {
676:
677: (*f->dev->write)(f, (char *)lbuf,
678:
679: bytes_to_write);
680:
681: bytes_to_write = 0;
682:
683: s = lbuf;
684:
685: }
686:
687: }
688:
689: }
690:
691: if (bytes_to_write) {
692:
693: (*f->dev->write)(f, (char *)lbuf, bytes_to_write);
694:
695: }
696:
697: }
698:
699:
700:
701: return bytes_written;
702:
703: }
704:
705:
706:
707: /* some notable scan codes */
708:
709: #define K_INSERT 0x52
710:
711: #define K_HOME 0x47
712:
713: #define K_UNDO 0x61
714:
715: #define K_HELP 0x62
716:
717: #define CURS_UP 0x48
718:
719: #define CURS_DN 0x50
720:
721: #define CURS_RT 0x4d
722:
723: #define CURS_LF 0x4b
724:
725: #define F_1 0x3b
726:
727: #define F_10 0x44
728:
729: #define F_11 0x54
730:
731: #define F_20 0x5d
732:
733: #define ALT_1 0x78
734:
735: #define ALT_0 0x81
736:
737:
738:
739: /* Default function key table:
740:
741: * entries: 0-9 are F1-F10
742:
743: * 10-19 are F11-F20
744:
745: * 20-23 are cursor up, down, right, and left
746:
747: * 24-27 are help, undo, insert, and home
748:
749: * 28-31 are shift+cursor up, down, right, and left
750:
751: */
752:
753:
754:
755: static char vt52xkey[256] = {
756:
757: '\033', 'P', 0, 0, 0, 0, 0, 0,
758:
759: '\033', 'Q', 0, 0, 0, 0, 0, 0,
760:
761: '\033', 'R', 0, 0, 0, 0, 0, 0,
762:
763: '\033', 'S', 0, 0, 0, 0, 0, 0,
764:
765: '\033', 'T', 0, 0, 0, 0, 0, 0,
766:
767: '\033', 'U', 0, 0, 0, 0, 0, 0,
768:
769: '\033', 'V', 0, 0, 0, 0, 0, 0,
770:
771: '\033', 'W', 0, 0, 0, 0, 0, 0,
772:
773: '\033', 'X', 0, 0, 0, 0, 0, 0,
774:
775: '\033', 'Y', 0, 0, 0, 0, 0, 0,
776:
777: '\033', 'p', 0, 0, 0, 0, 0, 0,
778:
779: '\033', 'q', 0, 0, 0, 0, 0, 0,
780:
781: '\033', 'r', 0, 0, 0, 0, 0, 0,
782:
783: '\033', 's', 0, 0, 0, 0, 0, 0,
784:
785: '\033', 't', 0, 0, 0, 0, 0, 0,
786:
787: '\033', 'u', 0, 0, 0, 0, 0, 0,
788:
789: '\033', 'v', 0, 0, 0, 0, 0, 0,
790:
791: '\033', 'w', 0, 0, 0, 0, 0, 0,
792:
793: '\033', 'x', 0, 0, 0, 0, 0, 0,
794:
795: '\033', 'y', 0, 0, 0, 0, 0, 0,
796:
797: '\033', 'A', 0, 0, 0, 0, 0, 0,
798:
799: '\033', 'B', 0, 0, 0, 0, 0, 0,
800:
801: '\033', 'C', 0, 0, 0, 0, 0, 0,
802:
803: '\033', 'D', 0, 0, 0, 0, 0, 0,
804:
805: '\033', 'H', 0, 0, 0, 0, 0, 0,
806:
807: '\033', 'K', 0, 0, 0, 0, 0, 0,
808:
809: '\033', 'I', 0, 0, 0, 0, 0, 0,
810:
811: '\033', 'E', 0, 0, 0, 0, 0, 0,
812:
813: '\033', 'a', 0, 0, 0, 0, 0, 0,
814:
815: '\033', 'b', 0, 0, 0, 0, 0, 0,
816:
817: '\033', 'c', 0, 0, 0, 0, 0, 0,
818:
819: '\033', 'd', 0, 0, 0, 0, 0, 0,
820:
821: };
822:
823:
824:
825: static char unxbaud P_((long));
826:
827:
828:
829: /* convert a number describing the baud rate into a Unix
830:
831: * style baud rate number. Returns the Unix baud rate,
832:
833: * or 16 (EXTA) if the rate is unknown
834:
835: */
836:
837:
838:
839: #define EXTA 16
840:
841:
842:
843: static long ubaud[EXTA] = {
844:
845: 0L, 50L, 75L, 110L, 134L, 150L, 200L, 300L,
846:
847: 600L, 1200L, 1800L, 2400L, 4800L, 9600L, 19200L, 38400L
848:
849: };
850:
851:
852:
853: static char
854:
855: unxbaud(baud)
856:
857: long baud;
858:
859: {
860:
861: int i;
862:
863: for (i = 1; i < EXTA; i++) {
864:
865: if (ubaud[i] == baud)
866:
867: break;
868:
869: }
870:
871: return i;
872:
873: }
874:
875:
876:
1.1.1.2 root 877: #define tosbaud(c) ( ((c) < 0 || (c) >= EXTA) ? -1L : ubaud[(unsigned)c] )
1.1 root 878:
879:
880:
881: long
882:
883: tty_ioctl(f, mode, arg)
884:
885: FILEPTR *f;
886:
887: int mode;
888:
889: void *arg;
890:
891: {
892:
893: struct sgttyb *sg;
894:
895: struct tchars *tc;
896:
897: struct ltchars *ltc;
898:
899: struct tty *tty;
900:
901: struct winsize *sz;
902:
903: struct xkey *xk;
904:
905: char *xktab;
906:
907: int i;
908:
909: long baud;
910:
911: short flags;
912:
913:
914:
915: if (!is_terminal(f)) {
916:
1.1.1.2 root 917: DEBUG(("tty_ioctl(mode %x): file is not a tty", mode));
1.1 root 918:
919: return EINVFN;
920:
921: }
922:
923: tty = (struct tty *)f->devinfo;
924:
925: assert(tty != 0);
926:
927:
928:
929: switch(mode) {
930:
931: case TIOCGETP:
932:
933: sg = (struct sgttyb *)arg;
934:
935: /* get input and output baud rates from the terminal device */
936:
937: baud = -1L;
938:
939: (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
940:
941: tty->sg.sg_ispeed = unxbaud(baud);
942:
943: baud = -1L;
944:
945: (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
946:
947: tty->sg.sg_ospeed = unxbaud(baud);
948:
949: /* get terminal flags */
950:
951: flags = 0;
952:
953: if ((*f->dev->ioctl)(f, TIOCGFLAGS, &flags) == 0) {
954:
955: tty->sg.sg_flags &= ~TF_FLAGS;
956:
957: tty->sg.sg_flags |= (flags & TF_FLAGS);
958:
959: }
960:
961: *sg = tty->sg;
962:
963: return 0;
964:
965: case TIOCSETP:
966:
967: sg = (struct sgttyb *)arg;
968:
969: tty->sg = *sg;
970:
971: /* set baud rates */
972:
973: baud = tosbaud(sg->sg_ispeed);
974:
975: (*f->dev->ioctl)(f, TIOCIBAUD, &baud);
976:
977: baud = tosbaud(sg->sg_ospeed);
978:
979: (*f->dev->ioctl)(f, TIOCOBAUD, &baud);
980:
981: /* set parity, etc. */
982:
983: flags = TF_8BIT;
984:
985: if (sg->sg_flags & (T_EVENP|T_ODDP)) {
986:
987: flags = TF_7BIT;
988:
989: }
990:
991: flags |= (sg->sg_flags & TF_FLAGS);
992:
993: (*f->dev->ioctl)(f, TIOCSFLAGS, &flags);
994:
995: return 0;
996:
997: case TIOCGETC:
998:
999: tc = (struct tchars *)arg;
1000:
1001: *tc = tty->tc;
1002:
1003: return 0;
1004:
1005: case TIOCSETC:
1006:
1007: tc = (struct tchars *)arg;
1008:
1009: tty->tc = *tc;
1010:
1011: return 0;
1012:
1013: case TIOCGLTC:
1014:
1015: ltc = (struct ltchars *)arg;
1016:
1017: *ltc = tty->ltc;
1018:
1019: return 0;
1020:
1021: case TIOCSLTC:
1022:
1023: ltc = (struct ltchars *)arg;
1024:
1025: tty->ltc = *ltc;
1026:
1027: return 0;
1028:
1029: case TIOCGWINSZ:
1030:
1031: sz = (struct winsize *)arg;
1032:
1033: *sz = tty->wsiz;
1034:
1035: return 0;
1036:
1037: case TIOCSWINSZ:
1038:
1039: sz = (struct winsize *)arg;
1040:
1041: tty->wsiz = *sz;
1042:
1043: return 0;
1044:
1045: case TIOCGPGRP:
1046:
1047: *((long *)arg) = tty->pgrp;
1048:
1049: return 0;
1050:
1051: case TIOCSPGRP:
1052:
1053: tty->pgrp = (*((long *)arg) & 0x00007fffL);
1054:
1055: return 0;
1056:
1057: case TIOCSTART:
1058:
1059: tty->state &= ~TS_HOLD;
1060:
1061: return 0;
1062:
1063: case TIOCSTOP:
1064:
1065: tty->state |= TS_HOLD;
1066:
1067: return 0;
1068:
1069: case TIOCGXKEY:
1070:
1071: xk = (struct xkey *)arg;
1072:
1073: i = xk->xk_num;
1074:
1075: if (i < 0 || i > 31) return ERANGE;
1076:
1077: xktab = tty->xkey;
1078:
1079: if (!xktab) xktab = vt52xkey;
1080:
1081: xktab += i*8;
1082:
1083: for (i = 0; i < 8; i++)
1084:
1085: xk->xk_def[i] = *xktab++;
1086:
1087: return 0;
1088:
1089: case TIOCSXKEY:
1090:
1091: xk = (struct xkey *)arg;
1092:
1093: xktab = tty->xkey;
1094:
1095: if (!xktab) {
1096:
1097: xktab = kmalloc((long)256);
1098:
1099: if (!xktab) return ENSMEM;
1100:
1101: for (i = 0; i < 256; i++)
1102:
1103: xktab[i] = vt52xkey[i];
1104:
1105: tty->xkey = xktab;
1106:
1107: }
1108:
1109: i = xk->xk_num;
1110:
1111: if (i < 0 || i > 31) return ERANGE;
1112:
1113: xktab += i*8;
1114:
1115: for (i = 0; i < 7; i++)
1116:
1117: xktab[i] = xk->xk_def[i];
1118:
1119: xktab[7] = 0;
1120:
1121: return 0;
1122:
1123: default:
1124:
1.1.1.2 root 1125: DEBUG(("tty_ioctl: bad function call"));
1.1 root 1126:
1127: return EINVFN;
1128:
1129: }
1130:
1131: }
1132:
1133:
1134:
1135: /*
1136:
1137: * function for translating extended characters (e.g. cursor keys, or
1138:
1139: * ALT+key sequences) into either escape sequences or meta characters.
1140:
1141: * for escape sequences, we return the the first character of the
1142:
1143: * sequence (normally ESC) and set the tty's state so that subsequent
1144:
1145: * calls to tty_getchar will pick up the remaining characters.
1146:
1147: * Note that escape sequences are limited to 7 characters at most.
1148:
1149: */
1150:
1151:
1152:
1153: static int
1154:
1155: escseq(tty, scan)
1156:
1157: struct tty *tty;
1158:
1159: int scan;
1160:
1161: {
1162:
1163: char *tab;
1164:
1165: int i;
1166:
1167:
1168:
1169: switch(scan) {
1170:
1171: case CURS_UP: i = 20; break;
1172:
1173: case CURS_DN: i = 21; break;
1174:
1175: case CURS_RT: i = 22; break;
1176:
1177: case CURS_LF: i = 23; break;
1178:
1179: case K_HELP: i = 24; break;
1180:
1181: case K_UNDO: i = 25; break;
1182:
1183: case K_INSERT:i = 26; break;
1184:
1185: case K_HOME: i = 27; break;
1186:
1187: case CURS_UP+0x100: i = 28; break;
1188:
1189: case CURS_DN+0x100: i = 29; break;
1190:
1191: case CURS_RT+0x100: i = 30; break;
1192:
1193: case CURS_LF+0x100: i = 31; break;
1194:
1195: default:
1196:
1197: if (scan >= F_1 && scan <= F_10) {
1198:
1199: i = scan - F_1;
1200:
1201: } else if (scan >= F_11 && scan <= F_20) {
1202:
1203: i = 10 + scan - F_11;
1204:
1205: } else
1206:
1207: i = -1;
1208:
1209: }
1210:
1211:
1212:
1213: if (i >= 0) { /* an extended escape sequence */
1214:
1215: tab = tty->xkey;
1216:
1217: if (!tab) tab = vt52xkey;
1218:
1219: i *= 8;
1220:
1221: scan = tab[i++];
1222:
1223: if (scan) {
1224:
1225: if (tab[i] == 0) i = 0;
1226:
1227: tty->state = (tty->state & ~TS_ESC) | i;
1228:
1229: }
1230:
1231: return scan;
1232:
1233: }
1234:
1235:
1236:
1237: if (scan >= ALT_1 && scan <= ALT_0) {
1238:
1239: scan -= (ALT_1-1);
1240:
1241: if (scan == 10) scan = 0;
1242:
1243: return (scan + '0') | 0x80;
1244:
1245: }
1246:
1247:
1248:
1.1.1.2 root 1249: tab = *( ((char **)Keytbl((void *)-1UL, (void *)-1UL, (void *)-1UL)) + 2 ); /* gratuitous (void *) for Lattice */
1.1 root 1250:
1251: scan = tab[scan];
1252:
1253: if (scan >= 'A' && scan <= 'Z') return scan | 0x80;
1254:
1255: return 0;
1256:
1257: }
1258:
1259:
1260:
1261: long
1262:
1263: tty_getchar(f, mode)
1264:
1265: FILEPTR *f;
1266:
1267: int mode;
1268:
1269: {
1270:
1271: struct tty *tty = (struct tty *)f->devinfo;
1272:
1273: char c, *tab;
1274:
1275: long r, ret;
1276:
1277: int scan;
1278:
1279: int master = f->flags & O_HEAD;
1280:
1281:
1282:
1283: assert(tty);
1284:
1285:
1286:
1287: /* pty masters never worry about job control and always read in raw mode */
1288:
1289: if (master) {
1290:
1291: ret = (*f->dev->read)(f, (char *)&r, 4L);
1292:
1293: return (ret != 4L) ? MiNTEOF : r;
1294:
1295: }
1296:
1297:
1298:
1299: /* job control check */
1300:
1.1.1.3 root 1301:
1302:
1.1.1.4 root 1303: if (tty->pgrp && tty->pgrp != curproc->pgrp) {
1.1 root 1304:
1.1.1.2 root 1305: TRACE(("job control: tty pgrp is %d proc pgrp is %d",
1.1 root 1306:
1.1.1.2 root 1307: tty->pgrp, curproc->pgrp));
1.1 root 1308:
1309: killgroup(curproc->pgrp, SIGTTIN);
1310:
1311: }
1312:
1313:
1314:
1315: if (mode & COOKED)
1316:
1317: tty->state |= TS_COOKED;
1318:
1319: else
1320:
1321: tty->state &= ~TS_COOKED;
1322:
1323:
1324:
1325: c = UNDEF+1; /* set to UNDEF when we successfully read a character */
1326:
1327:
1328:
1329: /* we may be in the middle of an escape sequence */
1330:
1.1.1.2 root 1331: scan = (tty->state & TS_ESC);
1332:
1333: if (scan != 0) {
1.1 root 1334:
1335: if (mode & ESCSEQ) {
1336:
1337: tab = tty->xkey ? tty->xkey : vt52xkey;
1338:
1339: r = (unsigned char) tab[scan++];
1340:
1341: if (r) {
1342:
1343: c = UNDEF;
1344:
1345: if (tab[scan] == 0) scan = 0;
1346:
1347: }
1348:
1349: else
1350:
1351: scan = 0;
1352:
1353: tty->state = (tty->state & ~TS_ESC) | scan;
1354:
1355: }
1356:
1357: else
1358:
1359: tty->state &= ~TS_ESC;
1360:
1361: }
1362:
1363:
1364:
1365: while (c != UNDEF) {
1366:
1367: ret = (*f->dev->read)(f, (char *)&r, 4L);
1368:
1369: if (ret != 4L) {
1370:
1.1.1.2 root 1371: DEBUG(("EOF on tty device"));
1.1 root 1372:
1373: return MiNTEOF;
1374:
1375: }
1376:
1377: c = r & 0x00ff;
1378:
1.1.1.2 root 1379: scan = (int)((r & 0x00ff0000L) >> 16);
1.1 root 1380:
1381: if ( (c == 0) && (mode & ESCSEQ) && scan) {
1382:
1383: c = UNDEF;
1384:
1385: /* translate cursor keys, etc. into escape sequences or
1386:
1387: * META characters
1388:
1389: */
1390:
1391: r = escseq(tty, scan);
1392:
1393: } else if ((mode & ESCSEQ) && ((scan == CURS_UP && c == '8') ||
1394:
1395: (scan == CURS_DN && c == '2') ||
1396:
1397: (scan == CURS_RT && c == '6') ||
1398:
1399: (scan == CURS_LF && c == '4'))) {
1400:
1401: c = UNDEF;
1402:
1403: r = escseq(tty, scan+0x100);
1404:
1405: } else if (mode & COOKED) {
1406:
1407: if (c == UNDEF)
1408:
1409: ; /* do nothing */
1410:
1411: else if (c == tty->ltc.t_dsuspc)
1412:
1413: killgroup(curproc->pgrp, SIGTSTP);
1414:
1415: else if (c == tty->tc.t_intrc)
1416:
1417: killgroup(curproc->pgrp, SIGINT);
1418:
1.1.1.5 ! root 1419: else if (c == tty->tc.t_quitc)
! 1420:
! 1421: killgroup(curproc->pgrp, SIGQUIT);
! 1422:
1.1 root 1423: else if (c == tty->tc.t_stopc)
1424:
1425: tty->state |= TS_HOLD;
1426:
1.1.1.3 root 1427: else if (c == tty->tc.t_startc)
1.1 root 1428:
1429: tty->state &= ~TS_HOLD;
1430:
1431: else
1432:
1433: c = UNDEF;
1434:
1435: }
1436:
1437: else
1438:
1439: c = UNDEF;
1440:
1441: }
1442:
1443:
1444:
1445: if (mode & ECHO)
1446:
1447: tty_putchar(f, r, mode);
1448:
1449:
1450:
1451: return r;
1452:
1453: }
1454:
1455:
1456:
1457: /*
1458:
1459: * tty_putchar: returns number of bytes successfully written
1460:
1461: */
1462:
1463:
1464:
1465: long
1466:
1467: tty_putchar(f, data, mode)
1468:
1469: FILEPTR *f;
1470:
1471: long data;
1472:
1473: int mode;
1474:
1475: {
1476:
1477: struct tty *tty;
1478:
1479: int master; /* file is pty master side */
1480:
1481: char ch;
1482:
1483:
1484:
1485: tty = (struct tty *)f->devinfo;
1486:
1487:
1488:
1489: master = f->flags & O_HEAD;
1490:
1491:
1492:
1493: /* pty masters don't need to worry about job control */
1494:
1495: if (master) {
1496:
1497: ch = data & 0xff;
1498:
1499:
1500:
1501: if ( (tty->state & TS_COOKED) && ch != UNDEF) {
1502:
1503: /* see if we're putting control characters into the buffer */
1504:
1505: if (ch == tty->tc.t_intrc) {
1506:
1507: tty->state &= ~TS_HOLD;
1508:
1509: killgroup(tty->pgrp, SIGINT);
1510:
1511: return 4L;
1512:
1513: }
1514:
1515: else if (ch == tty->tc.t_quitc) {
1516:
1517: tty->state &= ~TS_HOLD;
1518:
1519: killgroup(tty->pgrp, SIGQUIT);
1520:
1521: return 4L;
1522:
1523: }
1524:
1525: else if (ch == tty->ltc.t_suspc) {
1526:
1527: tty->state &= ~TS_HOLD;
1528:
1529: killgroup(tty->pgrp, SIGTSTP);
1530:
1531: return 4L;
1532:
1533: }
1534:
1535: else if (ch == tty->tc.t_stopc) {
1536:
1537: tty->state |= TS_HOLD;
1538:
1539: return 4L;
1540:
1541: }
1542:
1543: else if (ch == tty->tc.t_startc) {
1544:
1545: tty->state &= ~TS_HOLD;
1546:
1547: return 4L;
1548:
1549: }
1550:
1551: else if (tty->state & TS_HOLD) {
1552:
1553: return 0;
1554:
1555: }
1556:
1557: }
1558:
1559: goto do_putchar;
1560:
1561: }
1562:
1563: /* job control checks */
1564:
1565: /* AKP: added T_TOSTOP; don't stop BG output if T_TOSTOP is clear */
1566:
1.1.1.3 root 1567: if (tty->pgrp && tty->pgrp != curproc->pgrp &&
1.1 root 1568:
1.1.1.3 root 1569: (tty->sg.sg_flags & T_TOSTOP)) {
1.1 root 1570:
1.1.1.2 root 1571: TRACE(("job control: tty pgrp is %d proc pgrp is %d",
1.1 root 1572:
1.1.1.2 root 1573: tty->pgrp, curproc->pgrp));
1.1 root 1574:
1575: killgroup(curproc->pgrp, SIGTTOU);
1576:
1577: }
1578:
1579:
1580:
1581: if (mode & COOKED) {
1582:
1583: tty->state |= TS_COOKED;
1584:
1.1.1.5 ! root 1585: while (tty->state & TS_HOLD) {
! 1586:
! 1587: #if 1
! 1588:
! 1589: /* hack: BIOS devices != console never reset TS_HOLD themselves
! 1590:
! 1591: unless another process happens to call tty_getchar on them while
! 1592:
! 1593: we're here. someone has a better fix? :-( -nox
! 1594:
! 1595: */
! 1596:
! 1597: /* BIOS device definitions */
! 1598:
! 1599: #define CONSDEV 2
! 1600:
! 1601: short bdev;
! 1602:
! 1603: extern DEVDRV bios_tdevice;
! 1604:
! 1605:
! 1606:
! 1607: if (f->dev == &bios_tdevice &&
! 1608:
! 1609: (bdev=f->fc.aux) != CONSDEV && bconstat(bdev)) {
! 1610:
! 1611: long c = bconin(bdev) & 0x7fffffffL;
! 1612:
! 1613:
! 1614:
! 1615: if (c == UNDEF)
! 1616:
! 1617: ; /* do nothing */
! 1618:
! 1619: else if (c == tty->ltc.t_suspc) {
! 1620:
! 1621: tty->state &= ~TS_HOLD;
! 1622:
! 1623: killgroup(tty->pgrp, SIGTSTP);
! 1624:
! 1625: } else if (c == tty->tc.t_intrc) {
! 1626:
! 1627: tty->state &= ~TS_HOLD;
! 1628:
! 1629: killgroup(tty->pgrp, SIGINT);
! 1630:
! 1631: } else if (c == tty->tc.t_quitc) {
! 1632:
! 1633: tty->state &= ~TS_HOLD;
! 1634:
! 1635: killgroup(tty->pgrp, SIGQUIT);
! 1636:
! 1637: } else if (c == tty->tc.t_startc)
! 1638:
! 1639: tty->state &= ~TS_HOLD;
! 1640:
! 1641: }
! 1642:
! 1643: #endif
1.1 root 1644:
1645: nap(60); /* sleep for 60 milliseconds */
1646:
1.1.1.5 ! root 1647: }
! 1648:
1.1 root 1649: }
1650:
1651: else
1652:
1653: tty->state &= ~TS_COOKED;
1654:
1655:
1656:
1657: do_putchar:
1658:
1659: return (*f->dev->write)(f, (char *)&data, 4L);
1660:
1661: }
1662:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.