Annotation of src/usr.bin/mg/ttyio.c, Revision 1.4
1.1 deraadt 1: /*
2: * Name: MicroEMACS
1.4 ! millert 3: * POSIX terminal I/O.
1.1 deraadt 4: * Version: 0
5: * Last edit: Tue Aug 26 23:57:57 PDT 1986
6: * By: gonzo!daveb
7: * {sun, amdahl, mtxinu}!rtech!gonzo!daveb
8: *
9: * The functions in this file
10: * negotiate with the operating system for
11: * keyboard characters, and write characters to
12: * the display in a barely buffered fashion.
13: *
1.4 ! millert 14: * This version goes along with the terminfo tty.c.
1.1 deraadt 15: */
16: #include "def.h"
17:
18: #include <sys/types.h>
19: #include <fcntl.h>
1.2 deraadt 20: #include <termios.h>
1.4 ! millert 21: #include <term.h>
1.1 deraadt 22:
23: #define NOBUF 512 /* Output buffer size. */
24:
25: char obuf[NOBUF]; /* Output buffer. */
26: int nobuf; /* buffer count */
27:
1.2 deraadt 28: static struct termios ot; /* entry state of the terminal */
29: static struct termios nt; /* editor's terminal state */
1.1 deraadt 30:
31: static int ttyactivep = FALSE; /* terminal in editor mode? */
32: static int ttysavedp = FALSE; /* terminal state saved? */
33:
34: int nrow; /* Terminal size, rows. */
35: int ncol; /* Terminal size, columns. */
36:
37: /* These are used to implement typeahead on System V */
38:
39: int kbdflgs; /* saved keyboard fd flags */
40: int kbdpoll; /* in O_NDELAY mode */
41: int kbdqp; /* there is a char in kbdq */
42: char kbdq; /* char we've already read */
43:
44: /*
45: * This function gets called once, to set up
46: * the terminal channel. This version turns off flow
47: * control. This may be wrong for your system, but no
48: * good solution has really been found (daveb).
49: */
50: ttopen()
51: {
52: register char *cp;
53:
54: if (ttyactivep)
55: return;
56:
57: if( !ttysavedp )
58: {
1.2 deraadt 59: if (tcgetattr(0, &ot) < 0)
1.1 deraadt 60: abort();
61: nt = ot; /* save entry state */
62: nt.c_cc[VMIN] = 1; /* one character read is OK */
63: nt.c_cc[VTIME] = 0; /* Never time out. */
64: nt.c_iflag |= IGNBRK;
65: nt.c_iflag &= ~( ICRNL | INLCR | ISTRIP | IXON | IXOFF );
66: nt.c_oflag &= ~OPOST;
67: nt.c_cflag |= CS8; /* allow 8th bit on input */
68: nt.c_cflag &= ~PARENB; /* Don't check parity */
69: nt.c_lflag &= ~( ECHO | ICANON | ISIG );
70:
71: kbdpoll = (((kbdflgs = fcntl(0, F_GETFL, 0)) & O_NDELAY) != 0);
72:
73: ttysavedp = TRUE;
74: }
75:
1.2 deraadt 76: if (tcsetattr(0, TCSAFLUSH, &nt) < 0)
1.1 deraadt 77: abort();
78:
1.4 ! millert 79: setttysize();
1.1 deraadt 80:
81: ttyactivep = TRUE;
82: }
83:
84: /*
85: * This function gets called just
86: * before we go back home to the shell. Put all of
87: * the terminal parameters back.
88: */
89: ttclose()
90: {
91: if(!ttysavedp || !ttyactivep)
92: return;
93: ttflush();
1.2 deraadt 94: if (tcsetattr(0, TCSAFLUSH, &ot) < 0 ||
95: fcntl( 0, F_SETFL, kbdflgs ) < 0)
1.1 deraadt 96: abort();
97: ttyactivep = FALSE;
98: }
99:
100: /*
101: * Write character to the display.
102: * Characters are buffered up, to make things
103: * a little bit more efficient.
104: */
105: ttputc(c)
106: {
107: if (nobuf >= NOBUF)
108: ttflush();
109: obuf[nobuf++] = c;
110: }
111:
112: /*
113: * Flush output.
114: */
115: ttflush()
116: {
117: if (nobuf != 0) {
118: write(1, obuf, nobuf);
119: nobuf = 0;
120: }
121: }
122:
123: /*
124: * Read character from terminal.
125: * All 8 bits are returned, so that you can use
126: * a multi-national terminal.
127: *
128: * If keyboard 'queue' already has typeahead from a typeahead() call,
129: * just return it. Otherwise, make sure we are in blocking i/o mode
130: * and read a character.
131: */
132: ttgetc()
133: {
134: if( kbdqp )
135: kbdqp = FALSE;
136: else
137: {
138: if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
139: abort();
140: kbdpoll = FALSE;
141: while (read(0, &kbdq, 1) != 1)
142: ;
143: }
144: return ( kbdq & 0xff );
145: }
146:
147: /*
148: * Return non-FALSE if typeahead is pending.
149: *
150: * If already got unread typeahead, do nothing.
151: * Otherwise, set keyboard to O_NDELAY if not already, and try
152: * a one character read.
153: */
154: typeahead()
155: {
156: if( !kbdqp )
157: {
158: if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
159: abort();
160: kbdpoll = TRUE;
161: kbdqp = (1 == read( 0, &kbdq, 1 ));
162: }
163: return ( kbdqp );
164: }
165:
166:
167: /*
168: * panic: print error and die, leaving core file.
169: * Don't know why this is needed (daveb).
170: */
171: panic(s)
172: char *s;
173: {
174: fprintf(stderr, "%s\r\n", s);
175: abort();
176: }
177:
178:
179: /*
180: ** This should check the size of the window, and reset if needed.
181: */
182:
183: setttysize()
184: {
185: #ifdef TIOCGWINSZ
186: struct winsize winsize;
187: if (ioctl(0, TIOCGWINSZ, (char *) &winsize) == 0) {
188: nrow = winsize . ws_row;
189: ncol = winsize . ws_col;
190: } else
191: #endif
1.4 ! millert 192: if ((nrow = lines) <= 0 || (ncol = columns) <= 0) {
1.1 deraadt 193: nrow = 24;
194: ncol = 80;
195: }
1.4 ! millert 196:
! 197: /* Enforce maximum screen size. */
! 198: if (nrow > NROW)
! 199: nrow = NROW;
! 200: if (ncol > NCOL)
1.1 deraadt 201: ncol = NCOL;
202: }
203:
204: #ifndef NO_DPROMPT
205: #include <signal.h>
206: #include <setjmp.h>
207:
208: static jmp_buf tohere;
209:
210: static void alrm()
211: {
212: longjmp(tohere, -1);
213: }
214:
215: /*
216: * Return TRUE if we wait without doing anything, else return FALSE.
217: */
218:
219: ttwait()
220: {
221: if (kbdqp)
222: return FALSE; /* already pending input */
223: if (setjmp(tohere))
224: return TRUE; /* timeout on read if here */
225: signal(SIGALRM, alrm); alarm(2);
226: kbdqp = (1 == read(0, &kbdq, 1));
227: alarm(0);
228: return FALSE; /* successful read if here */
229: }
230: #endif NO_DPROMPT