tty.c revision 1.15 1 /* $NetBSD: tty.c,v 1.15 2000/04/15 13:17:05 blymn 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.15 2000/04/15 13:17:05 blymn 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
51 #include "curses.h"
52 #include "curses_private.h"
53
54 /*
55 * In general, curses should leave tty hardware settings alone (speed, parity,
56 * word size). This is most easily done in BSD by using TCSASOFT on all
57 * tcsetattr calls. On other systems, it would be better to get and restore
58 * those attributes at each change, or at least when stopped and restarted.
59 * See also the comments in getterm().
60 */
61 #ifdef TCSASOFT
62 int __tcaction = 1; /* Ignore hardware settings. */
63 #else
64 int __tcaction = 0;
65 #endif
66
67 struct termios __orig_termios, __baset;
68 int __endwin;
69 static struct termios cbreakt, rawt, *curt;
70 static int useraw;
71 static int ovmin = 1;
72 static int ovtime = 0;
73
74 #ifndef OXTABS
75 #ifdef XTABS /* SMI uses XTABS. */
76 #define OXTABS XTABS
77 #else
78 #define OXTABS 0
79 #endif
80 #endif
81
82 /*
83 * gettmode --
84 * Do terminal type initialization.
85 */
86 int
87 gettmode(void)
88 {
89 useraw = 0;
90
91 if (tcgetattr(STDIN_FILENO, &__orig_termios))
92 return (ERR);
93
94 __baset = __orig_termios;
95 __baset.c_oflag &= ~OXTABS;
96
97 GT = 0; /* historical. was used before we wired OXTABS
98 * off */
99 NONL = (__baset.c_oflag & ONLCR) == 0;
100
101 /*
102 * XXX
103 * System V and SMI systems overload VMIN and VTIME, such that
104 * VMIN is the same as the VEOF element, and VTIME is the same
105 * as the VEOL element. This means that, if VEOF was ^D, the
106 * default VMIN is 4. Majorly stupid.
107 */
108 cbreakt = __baset;
109 cbreakt.c_lflag &= ~ICANON;
110 cbreakt.c_cc[VMIN] = 1;
111 cbreakt.c_cc[VTIME] = 0;
112
113 rawt = cbreakt;
114 rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | ICRNL | IXON);
115 rawt.c_oflag &= ~OPOST;
116 rawt.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
117
118 /*
119 * In general, curses should leave hardware-related settings alone.
120 * This includes parity and word size. Older versions set the tty
121 * to 8 bits, no parity in raw(), but this is considered to be an
122 * artifact of the old tty interface. If it's desired to change
123 * parity and word size, the TCSASOFT bit has to be removed from the
124 * calls that switch to/from "raw" mode.
125 */
126 if (!__tcaction) {
127 rawt.c_iflag &= ~ISTRIP;
128 rawt.c_cflag &= ~(CSIZE | PARENB);
129 rawt.c_cflag |= CS8;
130 }
131
132 curt = &__baset;
133 return (tcsetattr(STDIN_FILENO, __tcaction ?
134 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
135 }
136
137 int
138 raw(void)
139 {
140 /* Check if we need to restart ... */
141 if (__endwin) {
142 __endwin = 0;
143 __restartwin();
144 }
145
146 useraw = __pfast = __rawmode = 1;
147 curt = &rawt;
148 return (tcsetattr(STDIN_FILENO, __tcaction ?
149 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
150 }
151
152 int
153 noraw(void)
154 {
155 /* Check if we need to restart ... */
156 if (__endwin) {
157 __endwin = 0;
158 __restartwin();
159 }
160
161 useraw = __pfast = __rawmode = 0;
162 curt = &__baset;
163 return (tcsetattr(STDIN_FILENO, __tcaction ?
164 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
165 }
166
167 int
168 cbreak(void)
169 {
170 /* Check if we need to restart ... */
171 if (__endwin) {
172 __endwin = 0;
173 __restartwin();
174 }
175
176 __rawmode = 1;
177 curt = useraw ? &rawt : &cbreakt;
178 return (tcsetattr(STDIN_FILENO, __tcaction ?
179 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
180 }
181
182 int
183 nocbreak(void)
184 {
185 /* Check if we need to restart ... */
186 if (__endwin) {
187 __endwin = 0;
188 __restartwin();
189 }
190
191 __rawmode = 0;
192 curt = useraw ? &rawt : &__baset;
193 return (tcsetattr(STDIN_FILENO, __tcaction ?
194 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
195 }
196
197 int
198 __delay(void)
199 {
200 /* Check if we need to restart ... */
201 if (__endwin) {
202 __endwin = 0;
203 __restartwin();
204 }
205
206 rawt.c_cc[VMIN] = 1;
207 rawt.c_cc[VTIME] = 0;
208 cbreakt.c_cc[VMIN] = 1;
209 cbreakt.c_cc[VTIME] = 0;
210 __baset.c_cc[VMIN] = 1;
211 __baset.c_cc[VTIME] = 0;
212
213 return (tcsetattr(STDIN_FILENO, __tcaction ?
214 TCSASOFT : TCSANOW, curt) ? ERR : OK);
215 }
216
217 int
218 __nodelay(void)
219 {
220 /* Check if we need to restart ... */
221 if (__endwin) {
222 __endwin = 0;
223 __restartwin();
224 }
225
226 rawt.c_cc[VMIN] = 0;
227 rawt.c_cc[VTIME] = 0;
228 cbreakt.c_cc[VMIN] = 0;
229 cbreakt.c_cc[VTIME] = 0;
230 __baset.c_cc[VMIN] = 0;
231 __baset.c_cc[VTIME] = 0;
232
233 return (tcsetattr(STDIN_FILENO, __tcaction ?
234 TCSASOFT : TCSANOW, curt) ? ERR : OK);
235 }
236
237 void
238 __save_termios(void)
239 {
240 /* Check if we need to restart ... */
241 if (__endwin) {
242 __endwin = 0;
243 __restartwin();
244 }
245
246 ovmin = cbreakt.c_cc[VMIN];
247 ovtime = cbreakt.c_cc[VTIME];
248 }
249
250 void
251 __restore_termios(void)
252 {
253 /* Check if we need to restart ... */
254 if (__endwin) {
255 __endwin = 0;
256 __restartwin();
257 }
258
259 rawt.c_cc[VMIN] = ovmin;
260 rawt.c_cc[VTIME] = ovtime;
261 cbreakt.c_cc[VMIN] = ovmin;
262 cbreakt.c_cc[VTIME] = ovtime;
263 __baset.c_cc[VMIN] = ovmin;
264 __baset.c_cc[VTIME] = ovtime;
265 }
266
267 int
268 __timeout(int delay)
269 {
270 /* Check if we need to restart ... */
271 if (__endwin) {
272 __endwin = 0;
273 __restartwin();
274 }
275
276 ovmin = cbreakt.c_cc[VMIN];
277 ovtime = cbreakt.c_cc[VTIME];
278 rawt.c_cc[VMIN] = 0;
279 rawt.c_cc[VTIME] = delay;
280 cbreakt.c_cc[VMIN] = 0;
281 cbreakt.c_cc[VTIME] = delay;
282 __baset.c_cc[VMIN] = 0;
283 __baset.c_cc[VTIME] = delay;
284
285 return (tcsetattr(STDIN_FILENO, __tcaction ?
286 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
287 }
288
289 int
290 __notimeout(void)
291 {
292 /* Check if we need to restart ... */
293 if (__endwin) {
294 __endwin = 0;
295 __restartwin();
296 }
297
298 rawt.c_cc[VMIN] = 1;
299 rawt.c_cc[VTIME] = 0;
300 cbreakt.c_cc[VMIN] = 1;
301 cbreakt.c_cc[VTIME] = 0;
302 __baset.c_cc[VMIN] = 1;
303 __baset.c_cc[VTIME] = 0;
304
305 return (tcsetattr(STDIN_FILENO, __tcaction ?
306 TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
307 }
308
309 int
310 echo(void)
311 {
312 /* Check if we need to restart ... */
313 if (__endwin) {
314 __endwin = 0;
315 __restartwin();
316 }
317
318 rawt.c_lflag |= ECHO;
319 cbreakt.c_lflag |= ECHO;
320 __baset.c_lflag |= ECHO;
321
322 __echoit = 1;
323 return (tcsetattr(STDIN_FILENO, __tcaction ?
324 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
325 }
326
327 int
328 noecho(void)
329 {
330 /* Check if we need to restart ... */
331 if (__endwin) {
332 __endwin = 0;
333 __restartwin();
334 }
335
336 rawt.c_lflag &= ~ECHO;
337 cbreakt.c_lflag &= ~ECHO;
338 __baset.c_lflag &= ~ECHO;
339
340 __echoit = 0;
341 return (tcsetattr(STDIN_FILENO, __tcaction ?
342 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
343 }
344
345 int
346 nl(void)
347 {
348 /* Check if we need to restart ... */
349 if (__endwin) {
350 __endwin = 0;
351 __restartwin();
352 }
353
354 rawt.c_iflag |= ICRNL;
355 rawt.c_oflag |= ONLCR;
356 cbreakt.c_iflag |= ICRNL;
357 cbreakt.c_oflag |= ONLCR;
358 __baset.c_iflag |= ICRNL;
359 __baset.c_oflag |= ONLCR;
360
361 __pfast = __rawmode;
362 return (tcsetattr(STDIN_FILENO, __tcaction ?
363 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
364 }
365
366 int
367 nonl(void)
368 {
369 /* Check if we need to restart ... */
370 if (__endwin) {
371 __endwin = 0;
372 __restartwin();
373 }
374
375 rawt.c_iflag &= ~ICRNL;
376 rawt.c_oflag &= ~ONLCR;
377 cbreakt.c_iflag &= ~ICRNL;
378 cbreakt.c_oflag &= ~ONLCR;
379 __baset.c_iflag &= ~ICRNL;
380 __baset.c_oflag &= ~ONLCR;
381
382 __pfast = 1;
383 return (tcsetattr(STDIN_FILENO, __tcaction ?
384 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
385 }
386
387 int
388 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/
389 {
390 /* Check if we need to restart ... */
391 if (__endwin) {
392 __endwin = 0;
393 __restartwin();
394 }
395
396 if (bf) {
397 rawt.c_lflag &= ~NOFLSH;
398 cbreakt.c_lflag &= ~NOFLSH;
399 __baset.c_lflag &= ~NOFLSH;
400 } else {
401 rawt.c_lflag |= NOFLSH;
402 cbreakt.c_lflag |= NOFLSH;
403 __baset.c_lflag |= NOFLSH;
404 }
405
406 __pfast = 1;
407 return (tcsetattr(STDIN_FILENO, __tcaction ?
408 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
409 }
410
411 void
412 __startwin(void)
413 {
414 static char *stdbuf;
415 static size_t len;
416
417 (void) fflush(stdout);
418
419 /*
420 * Some C libraries default to a 1K buffer when talking to a tty.
421 * With a larger screen, especially across a network, we'd like
422 * to get it to all flush in a single write. Make it twice as big
423 * as just the characters (so that we have room for cursor motions
424 * and attribute information) but no more than 8K.
425 */
426 if (stdbuf == NULL) {
427 if ((len = LINES * COLS * 2) > 8192)
428 len = 8192;
429 if ((stdbuf = malloc(len)) == NULL)
430 len = 0;
431 }
432 (void) setvbuf(stdout, stdbuf, _IOFBF, len);
433
434 tputs(TI, 0, __cputchar);
435 tputs(VS, 0, __cputchar);
436 tputs(KS, 0, __cputchar);
437 }
438
439 int
440 endwin(void)
441 {
442 __endwin = 1;
443 return __stopwin();
444 }
445
446 bool
447 isendwin(void)
448 {
449 return (__endwin ? TRUE : FALSE);
450 }
451
452 int
453 flushinp(void)
454 {
455 (void) fpurge(stdin);
456 return (OK);
457 }
458
459 int
460 def_shell_mode(void)
461 {
462 return (tcgetattr(STDIN_FILENO, &__orig_termios) ? ERR : OK);
463 }
464
465 int
466 reset_shell_mode(void)
467 {
468 return (tcsetattr(STDIN_FILENO, __tcaction ?
469 TCSASOFT | TCSADRAIN : TCSADRAIN, &__orig_termios) ? ERR : OK);
470 }
471
472 /*
473 * The following routines, savetty and resetty are completely useless and
474 * are left in only as stubs. If people actually use them they will almost
475 * certainly screw up the state of the world.
476 */
477 static struct termios savedtty;
478 int
479 savetty(void)
480 {
481 return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK);
482 }
483
484 int
485 resetty(void)
486 {
487 return (tcsetattr(STDIN_FILENO, __tcaction ?
488 TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK);
489 }
490