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