tty.c revision 1.24 1 /* $NetBSD: tty.c,v 1.24 2000/12/19 21:34:24 jdc Exp $ */
2
3 /*-
4 * Copyright (c) 1992, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)tty.c 8.6 (Berkeley) 1/10/95";
40 #else
41 __RCSID("$NetBSD: tty.c,v 1.24 2000/12/19 21:34:24 jdc Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <sys/types.h>
46
47 #include <stdlib.h>
48 #include <termios.h>
49 #include <unistd.h>
50 #include <sys/fcntl.h>
51 #include <sys/ioctl.h>
52
53 #include "curses.h"
54 #include "curses_private.h"
55
56 /*
57 * In general, curses should leave tty hardware settings alone (speed, parity,
58 * word size). This is most easily done in BSD by using TCSASOFT on all
59 * tcsetattr calls. On other systems, it would be better to get and restore
60 * those attributes at each change, or at least when stopped and restarted.
61 * See also the comments in getterm().
62 */
63 #ifdef TCSASOFT
64 int __tcaction = 1; /* Ignore hardware settings. */
65 #else
66 int __tcaction = 0;
67 #endif
68
69 struct termios __orig_termios, __baset;
70 int __endwin;
71 static struct termios cbreakt, rawt, *curt;
72 static int useraw;
73 static int ovmin = 1;
74 static int ovtime = 0;
75
76 #ifndef OXTABS
77 #ifdef XTABS /* SMI uses XTABS. */
78 #define OXTABS XTABS
79 #else
80 #define OXTABS 0
81 #endif
82 #endif
83
84 /*
85 * gettmode --
86 * Do terminal type initialization.
87 */
88 int
89 gettmode(void)
90 {
91 useraw = 0;
92
93 if (tcgetattr(STDIN_FILENO, &__orig_termios))
94 return (ERR);
95
96 __baset = __orig_termios;
97 __baset.c_oflag &= ~OXTABS;
98
99 __GT = 0; /* historical. was used before we wired OXTABS off */
100 __NONL = (__baset.c_oflag & ONLCR) == 0;
101
102 /*
103 * XXX
104 * System V and SMI systems overload VMIN and VTIME, such that
105 * VMIN is the same as the VEOF element, and VTIME is the same
106 * as the VEOL element. This means that, if VEOF was ^D, the
107 * default VMIN is 4. Majorly stupid.
108 */
109 cbreakt = __baset;
110 cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON);
111 cbreakt.c_cc[VMIN] = 1;
112 cbreakt.c_cc[VTIME] = 0;
113
114 rawt = cbreakt;
115 rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
116 rawt.c_oflag &= ~OPOST;
117 rawt.c_lflag &= ~(ISIG | IEXTEN);
118
119 /*
120 * In general, curses should leave hardware-related settings alone.
121 * This includes parity and word size. Older versions set the tty
122 * to 8 bits, no parity in raw(), but this is considered to be an
123 * artifact of the old tty interface. If it's desired to change
124 * parity and word size, the TCSASOFT bit has to be removed from the
125 * calls that switch to/from "raw" mode.
126 */
127 if (!__tcaction) {
128 rawt.c_iflag &= ~ISTRIP;
129 rawt.c_cflag &= ~(CSIZE | PARENB);
130 rawt.c_cflag |= CS8;
131 }
132
133 curt = &__baset;
134 return (tcsetattr(STDIN_FILENO, __tcaction ?
135 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
136 }
137
138 int
139 raw(void)
140 {
141 /* Check if we need to restart ... */
142 if (__endwin)
143 __restartwin();
144
145 useraw = __pfast = __rawmode = 1;
146 curt = &rawt;
147 return (tcsetattr(STDIN_FILENO, __tcaction ?
148 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
149 }
150
151 int
152 noraw(void)
153 {
154 /* Check if we need to restart ... */
155 if (__endwin)
156 __restartwin();
157
158 useraw = __pfast = __rawmode = 0;
159 curt = &__baset;
160 return (tcsetattr(STDIN_FILENO, __tcaction ?
161 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
162 }
163
164 int
165 cbreak(void)
166 {
167 /* Check if we need to restart ... */
168 if (__endwin)
169 __restartwin();
170
171 __rawmode = 1;
172 curt = useraw ? &rawt : &cbreakt;
173 return (tcsetattr(STDIN_FILENO, __tcaction ?
174 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
175 }
176
177 int
178 nocbreak(void)
179 {
180 /* Check if we need to restart ... */
181 if (__endwin)
182 __restartwin();
183
184 __rawmode = 0;
185 curt = useraw ? &rawt : &__baset;
186 return (tcsetattr(STDIN_FILENO, __tcaction ?
187 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
188 }
189
190 int
191 __delay(void)
192 {
193 /* Check if we need to restart ... */
194 if (__endwin)
195 __restartwin();
196
197 rawt.c_cc[VMIN] = 1;
198 rawt.c_cc[VTIME] = 0;
199 cbreakt.c_cc[VMIN] = 1;
200 cbreakt.c_cc[VTIME] = 0;
201 __baset.c_cc[VMIN] = 1;
202 __baset.c_cc[VTIME] = 0;
203
204 return (tcsetattr(STDIN_FILENO, __tcaction ?
205 TCSASOFT : TCSANOW, curt) ? ERR : OK);
206 }
207
208 int
209 __nodelay(void)
210 {
211 /* Check if we need to restart ... */
212 if (__endwin)
213 __restartwin();
214
215 rawt.c_cc[VMIN] = 0;
216 rawt.c_cc[VTIME] = 0;
217 cbreakt.c_cc[VMIN] = 0;
218 cbreakt.c_cc[VTIME] = 0;
219 __baset.c_cc[VMIN] = 0;
220 __baset.c_cc[VTIME] = 0;
221
222 return (tcsetattr(STDIN_FILENO, __tcaction ?
223 TCSASOFT : TCSANOW, curt) ? ERR : OK);
224 }
225
226 void
227 __save_termios(void)
228 {
229 /* Check if we need to restart ... */
230 if (__endwin)
231 __restartwin();
232
233 ovmin = cbreakt.c_cc[VMIN];
234 ovtime = cbreakt.c_cc[VTIME];
235 }
236
237 void
238 __restore_termios(void)
239 {
240 /* Check if we need to restart ... */
241 if (__endwin)
242 __restartwin();
243
244 rawt.c_cc[VMIN] = ovmin;
245 rawt.c_cc[VTIME] = ovtime;
246 cbreakt.c_cc[VMIN] = ovmin;
247 cbreakt.c_cc[VTIME] = ovtime;
248 __baset.c_cc[VMIN] = ovmin;
249 __baset.c_cc[VTIME] = ovtime;
250 }
251
252 int
253 __timeout(int delay)
254 {
255 /* Check if we need to restart ... */
256 if (__endwin)
257 __restartwin();
258
259 ovmin = cbreakt.c_cc[VMIN];
260 ovtime = cbreakt.c_cc[VTIME];
261 rawt.c_cc[VMIN] = 0;
262 rawt.c_cc[VTIME] = delay;
263 cbreakt.c_cc[VMIN] = 0;
264 cbreakt.c_cc[VTIME] = delay;
265 __baset.c_cc[VMIN] = 0;
266 __baset.c_cc[VTIME] = delay;
267
268 return (tcsetattr(STDIN_FILENO, __tcaction ?
269 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
270 }
271
272 int
273 __notimeout(void)
274 {
275 /* Check if we need to restart ... */
276 if (__endwin)
277 __restartwin();
278
279 rawt.c_cc[VMIN] = 1;
280 rawt.c_cc[VTIME] = 0;
281 cbreakt.c_cc[VMIN] = 1;
282 cbreakt.c_cc[VTIME] = 0;
283 __baset.c_cc[VMIN] = 1;
284 __baset.c_cc[VTIME] = 0;
285
286 return (tcsetattr(STDIN_FILENO, __tcaction ?
287 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
288 }
289
290 int
291 echo(void)
292 {
293 /* Check if we need to restart ... */
294 if (__endwin)
295 __restartwin();
296
297 __echoit = 1;
298 return (OK);
299 }
300
301 int
302 noecho(void)
303 {
304 /* Check if we need to restart ... */
305 if (__endwin)
306 __restartwin();
307
308 __echoit = 0;
309 return (OK);
310 }
311
312 int
313 nl(void)
314 {
315 /* Check if we need to restart ... */
316 if (__endwin)
317 __restartwin();
318
319 rawt.c_iflag |= ICRNL;
320 rawt.c_oflag |= ONLCR;
321 cbreakt.c_iflag |= ICRNL;
322 cbreakt.c_oflag |= ONLCR;
323 __baset.c_iflag |= ICRNL;
324 __baset.c_oflag |= ONLCR;
325
326 __pfast = __rawmode;
327 return (tcsetattr(STDIN_FILENO, __tcaction ?
328 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
329 }
330
331 int
332 nonl(void)
333 {
334 /* Check if we need to restart ... */
335 if (__endwin)
336 __restartwin();
337
338 rawt.c_iflag &= ~ICRNL;
339 rawt.c_oflag &= ~ONLCR;
340 cbreakt.c_iflag &= ~ICRNL;
341 cbreakt.c_oflag &= ~ONLCR;
342 __baset.c_iflag &= ~ICRNL;
343 __baset.c_oflag &= ~ONLCR;
344
345 __pfast = 1;
346 return (tcsetattr(STDIN_FILENO, __tcaction ?
347 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
348 }
349
350 int
351 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/
352 {
353 /* Check if we need to restart ... */
354 if (__endwin)
355 __restartwin();
356
357 if (bf) {
358 rawt.c_lflag &= ~NOFLSH;
359 cbreakt.c_lflag &= ~NOFLSH;
360 __baset.c_lflag &= ~NOFLSH;
361 } else {
362 rawt.c_lflag |= NOFLSH;
363 cbreakt.c_lflag |= NOFLSH;
364 __baset.c_lflag |= NOFLSH;
365 }
366
367 __pfast = 1;
368 return (tcsetattr(STDIN_FILENO, __tcaction ?
369 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
370 }
371
372 void
373 __startwin(void)
374 {
375 static char *stdbuf;
376 static size_t len;
377
378 (void) fflush(stdout);
379
380 /*
381 * Some C libraries default to a 1K buffer when talking to a tty.
382 * With a larger screen, especially across a network, we'd like
383 * to get it to all flush in a single write. Make it twice as big
384 * as just the characters (so that we have room for cursor motions
385 * and attribute information) but no more than 8K.
386 */
387 if (stdbuf == NULL) {
388 if ((len = LINES * COLS * 2) > 8192)
389 len = 8192;
390 if ((stdbuf = malloc(len)) == NULL)
391 len = 0;
392 }
393 (void) setvbuf(stdout, stdbuf, _IOFBF, len);
394
395 tputs(__tc_ti, 0, __cputchar);
396 tputs(__tc_vs, 0, __cputchar);
397 if (curscr->flags & __KEYPAD)
398 tputs(__tc_ks, 0, __cputchar);
399 __endwin = 0;
400 }
401
402 int
403 endwin(void)
404 {
405 return __stopwin();
406 }
407
408 bool
409 isendwin(void)
410 {
411 return (__endwin ? TRUE : FALSE);
412 }
413
414 int
415 flushinp(void)
416 {
417 (void) fpurge(stdin);
418 return (OK);
419 }
420
421 /*
422 * The following routines, savetty and resetty are completely useless and
423 * are left in only as stubs. If people actually use them they will almost
424 * certainly screw up the state of the world.
425 */
426 static struct termios savedtty;
427 int
428 savetty(void)
429 {
430 return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK);
431 }
432
433 int
434 resetty(void)
435 {
436 return (tcsetattr(STDIN_FILENO, __tcaction ?
437 TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK);
438 }
439
440 /*
441 * erasechar --
442 * Return the character of the erase key.
443 *
444 */
445 char
446 erasechar(void)
447 {
448 return __baset.c_cc[VERASE];
449 }
450
451 /*
452 * killchar --
453 * Return the character of the kill key.
454 */
455 char
456 killchar(void)
457 {
458 return __baset.c_cc[VKILL];
459 }
460