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