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