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