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