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