xref: /netbsd-src/lib/libcurses/tty.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
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