xref: /netbsd-src/lib/libcurses/tty.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: tty.c,v 1.21 2000/05/22 05:54:37 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.21 2000/05/22 05:54:37 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 /*
453  * The following routines, savetty and resetty are completely useless and
454  * are left in only as stubs.  If people actually use them they will almost
455  * certainly screw up the state of the world.
456  */
457 static struct termios savedtty;
458 int
459 savetty(void)
460 {
461 	return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK);
462 }
463 
464 int
465 resetty(void)
466 {
467 	return (tcsetattr(STDIN_FILENO, __tcaction ?
468 	    TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK);
469 }
470 
471 /*
472  * erasechar --
473  *     Return the character of the erase key.
474  *
475  */
476 char
477 erasechar(void)
478 {
479 	return __baset.c_cc[VERASE];
480 }
481 
482 /*
483  * killchar --
484  *     Return the character of the kill key.
485  */
486 char
487 killchar(void)
488 {
489 	return __baset.c_cc[VKILL];
490 }
491