Home | History | Annotate | Line # | Download | only in libcurses
tty.c revision 1.24
      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