xref: /netbsd-src/lib/libcurses/tty.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: tty.c,v 1.23 2000/06/16 06:32:19 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.23 2000/06/16 06:32:19 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 		__restartwin();
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 		__restartwin();
158 
159 	useraw = __pfast = __rawmode = 0;
160 	curt = &__baset;
161 	return (tcsetattr(STDIN_FILENO, __tcaction ?
162 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
163 }
164 
165 int
166 cbreak(void)
167 {
168 	/* Check if we need to restart ... */
169 	if (__endwin)
170 		__restartwin();
171 
172 	__rawmode = 1;
173 	curt = useraw ? &rawt : &cbreakt;
174 	return (tcsetattr(STDIN_FILENO, __tcaction ?
175 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
176 }
177 
178 int
179 nocbreak(void)
180 {
181 	/* Check if we need to restart ... */
182 	if (__endwin)
183 		__restartwin();
184 
185 	__rawmode = 0;
186 	curt = useraw ? &rawt : &__baset;
187 	return (tcsetattr(STDIN_FILENO, __tcaction ?
188 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
189 }
190 
191 int
192 __delay(void)
193  {
194 	/* Check if we need to restart ... */
195 	if (__endwin)
196 		__restartwin();
197 
198 	rawt.c_cc[VMIN] = 1;
199 	rawt.c_cc[VTIME] = 0;
200 	cbreakt.c_cc[VMIN] = 1;
201 	cbreakt.c_cc[VTIME] = 0;
202 	__baset.c_cc[VMIN] = 1;
203 	__baset.c_cc[VTIME] = 0;
204 
205 	return (tcsetattr(STDIN_FILENO, __tcaction ?
206 		TCSASOFT : TCSANOW, curt) ? ERR : OK);
207 }
208 
209 int
210 __nodelay(void)
211 {
212 	/* Check if we need to restart ... */
213 	if (__endwin)
214 		__restartwin();
215 
216 	rawt.c_cc[VMIN] = 0;
217 	rawt.c_cc[VTIME] = 0;
218 	cbreakt.c_cc[VMIN] = 0;
219 	cbreakt.c_cc[VTIME] = 0;
220 	__baset.c_cc[VMIN] = 0;
221 	__baset.c_cc[VTIME] = 0;
222 
223 	return (tcsetattr(STDIN_FILENO, __tcaction ?
224 		TCSASOFT : TCSANOW, curt) ? ERR : OK);
225 }
226 
227 void
228 __save_termios(void)
229 {
230 	/* Check if we need to restart ... */
231 	if (__endwin)
232 		__restartwin();
233 
234 	ovmin = cbreakt.c_cc[VMIN];
235 	ovtime = cbreakt.c_cc[VTIME];
236 }
237 
238 void
239 __restore_termios(void)
240 {
241 	/* Check if we need to restart ... */
242 	if (__endwin)
243 		__restartwin();
244 
245 	rawt.c_cc[VMIN] = ovmin;
246 	rawt.c_cc[VTIME] = ovtime;
247 	cbreakt.c_cc[VMIN] = ovmin;
248 	cbreakt.c_cc[VTIME] = ovtime;
249 	__baset.c_cc[VMIN] = ovmin;
250 	__baset.c_cc[VTIME] = ovtime;
251 }
252 
253 int
254 __timeout(int delay)
255 {
256 	/* Check if we need to restart ... */
257 	if (__endwin)
258 		__restartwin();
259 
260 	ovmin = cbreakt.c_cc[VMIN];
261 	ovtime = cbreakt.c_cc[VTIME];
262 	rawt.c_cc[VMIN] = 0;
263 	rawt.c_cc[VTIME] = delay;
264 	cbreakt.c_cc[VMIN] = 0;
265 	cbreakt.c_cc[VTIME] = delay;
266 	__baset.c_cc[VMIN] = 0;
267 	__baset.c_cc[VTIME] = delay;
268 
269 	return (tcsetattr(STDIN_FILENO, __tcaction ?
270 		TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
271 }
272 
273 int
274 __notimeout(void)
275 {
276 	/* Check if we need to restart ... */
277 	if (__endwin)
278 		__restartwin();
279 
280 	rawt.c_cc[VMIN] = 1;
281 	rawt.c_cc[VTIME] = 0;
282 	cbreakt.c_cc[VMIN] = 1;
283 	cbreakt.c_cc[VTIME] = 0;
284 	__baset.c_cc[VMIN] = 1;
285 	__baset.c_cc[VTIME] = 0;
286 
287 	return (tcsetattr(STDIN_FILENO, __tcaction ?
288 		TCSASOFT | TCSANOW : TCSANOW, curt) ? ERR : OK);
289 }
290 
291 int
292 echo(void)
293 {
294 	/* Check if we need to restart ... */
295 	if (__endwin)
296 		__restartwin();
297 
298 	__echoit = 1;
299 	return (OK);
300 }
301 
302 int
303 noecho(void)
304 {
305 	/* Check if we need to restart ... */
306 	if (__endwin)
307 		__restartwin();
308 
309 	__echoit = 0;
310 	return (OK);
311 }
312 
313 int
314 nl(void)
315 {
316 	/* Check if we need to restart ... */
317 	if (__endwin)
318 		__restartwin();
319 
320 	rawt.c_iflag |= ICRNL;
321 	rawt.c_oflag |= ONLCR;
322 	cbreakt.c_iflag |= ICRNL;
323 	cbreakt.c_oflag |= ONLCR;
324 	__baset.c_iflag |= ICRNL;
325 	__baset.c_oflag |= ONLCR;
326 
327 	__pfast = __rawmode;
328 	return (tcsetattr(STDIN_FILENO, __tcaction ?
329 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
330 }
331 
332 int
333 nonl(void)
334 {
335 	/* Check if we need to restart ... */
336 	if (__endwin)
337 		__restartwin();
338 
339 	rawt.c_iflag &= ~ICRNL;
340 	rawt.c_oflag &= ~ONLCR;
341 	cbreakt.c_iflag &= ~ICRNL;
342 	cbreakt.c_oflag &= ~ONLCR;
343 	__baset.c_iflag &= ~ICRNL;
344 	__baset.c_oflag &= ~ONLCR;
345 
346 	__pfast = 1;
347 	return (tcsetattr(STDIN_FILENO, __tcaction ?
348 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
349 }
350 
351 int
352 intrflush(WINDOW *win, bool bf)	/*ARGSUSED*/
353 {
354 	/* Check if we need to restart ... */
355 	if (__endwin)
356 		__restartwin();
357 
358 	if (bf) {
359 		rawt.c_lflag &= ~NOFLSH;
360 		cbreakt.c_lflag &= ~NOFLSH;
361 		__baset.c_lflag &= ~NOFLSH;
362 	} else {
363 		rawt.c_lflag |= NOFLSH;
364 		cbreakt.c_lflag |= NOFLSH;
365 		__baset.c_lflag |= NOFLSH;
366 	}
367 
368 	__pfast = 1;
369 	return (tcsetattr(STDIN_FILENO, __tcaction ?
370 	    TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK);
371 }
372 
373 void
374 __startwin(void)
375 {
376 	static char *stdbuf;
377 	static size_t len;
378 
379 	(void) fflush(stdout);
380 
381 	/*
382 	 * Some C libraries default to a 1K buffer when talking to a tty.
383 	 * With a larger screen, especially across a network, we'd like
384 	 * to get it to all flush in a single write.  Make it twice as big
385 	 * as just the characters (so that we have room for cursor motions
386 	 * and attribute information) but no more than 8K.
387 	 */
388 	if (stdbuf == NULL) {
389 		if ((len = LINES * COLS * 2) > 8192)
390 			len = 8192;
391 		if ((stdbuf = malloc(len)) == NULL)
392 			len = 0;
393 	}
394 	(void) setvbuf(stdout, stdbuf, _IOFBF, len);
395 
396 	tputs(TI, 0, __cputchar);
397 	tputs(VS, 0, __cputchar);
398 	if (curscr->flags & __KEYPAD)
399 		tputs(KS, 0, __cputchar);
400 	__endwin = 0;
401 }
402 
403 int
404 endwin(void)
405 {
406 	return __stopwin();
407 }
408 
409 bool
410 isendwin(void)
411 {
412 	return (__endwin ? TRUE : FALSE);
413 }
414 
415 int
416 flushinp(void)
417 {
418 	(void) fpurge(stdin);
419 	return (OK);
420 }
421 
422 /*
423  * The following routines, savetty and resetty are completely useless and
424  * are left in only as stubs.  If people actually use them they will almost
425  * certainly screw up the state of the world.
426  */
427 static struct termios savedtty;
428 int
429 savetty(void)
430 {
431 	return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK);
432 }
433 
434 int
435 resetty(void)
436 {
437 	return (tcsetattr(STDIN_FILENO, __tcaction ?
438 	    TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK);
439 }
440 
441 /*
442  * erasechar --
443  *     Return the character of the erase key.
444  *
445  */
446 char
447 erasechar(void)
448 {
449 	return __baset.c_cc[VERASE];
450 }
451 
452 /*
453  * killchar --
454  *     Return the character of the kill key.
455  */
456 char
457 killchar(void)
458 {
459 	return __baset.c_cc[VKILL];
460 }
461