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