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