1 /* $NetBSD: tty.c,v 1.28 2002/01/02 10:38:29 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.28 2002/01/02 10:38:29 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