1 /* $NetBSD: tty.c,v 1.12 1999/06/28 13:32:43 simonb 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.12 1999/06/28 13:32:43 simonb Exp $"); 42 #endif 43 #endif /* not lint */ 44 45 #include <sys/types.h> 46 #include <sys/fcntl.h> 47 #include <sys/ioctl.h> 48 49 #include <stdlib.h> 50 #include <termios.h> 51 #include <unistd.h> 52 53 #include "curses.h" 54 55 /* 56 * In general, curses should leave tty hardware settings alone (speed, parity, 57 * word size). This is most easily done in BSD by using TCSASOFT on all 58 * tcsetattr calls. On other systems, it would be better to get and restore 59 * those attributes at each change, or at least when stopped and restarted. 60 * See also the comments in getterm(). 61 */ 62 #ifdef TCSASOFT 63 int __tcaction = 1; /* Ignore hardware settings. */ 64 #else 65 int __tcaction = 0; 66 #endif 67 68 struct termios __orig_termios, __baset; 69 int __endwin; 70 static struct termios cbreakt, rawt, *curt; 71 static int useraw; 72 static int ovmin = 1; 73 static int ovtime = 0; 74 75 #ifndef OXTABS 76 #ifdef XTABS /* SMI uses XTABS. */ 77 #define OXTABS XTABS 78 #else 79 #define OXTABS 0 80 #endif 81 #endif 82 83 /* 84 * gettmode -- 85 * Do terminal type initialization. 86 */ 87 int 88 gettmode() 89 { 90 useraw = 0; 91 92 if (tcgetattr(STDIN_FILENO, &__orig_termios)) 93 return (ERR); 94 95 __baset = __orig_termios; 96 __baset.c_oflag &= ~OXTABS; 97 98 GT = 0; /* historical. was used before we wired OXTABS 99 * 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 &= ~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 &= ~(ECHO | ECHONL | ICANON | 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() 140 { 141 /* Check if we need to restart ... */ 142 if (__endwin) { 143 __endwin = 0; 144 __restartwin(); 145 } 146 147 useraw = __pfast = __rawmode = 1; 148 curt = &rawt; 149 return (tcsetattr(STDIN_FILENO, __tcaction ? 150 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 151 } 152 153 int 154 noraw() 155 { 156 /* Check if we need to restart ... */ 157 if (__endwin) { 158 __endwin = 0; 159 __restartwin(); 160 } 161 162 useraw = __pfast = __rawmode = 0; 163 curt = &__baset; 164 return (tcsetattr(STDIN_FILENO, __tcaction ? 165 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 166 } 167 168 int 169 cbreak() 170 { 171 /* Check if we need to restart ... */ 172 if (__endwin) { 173 __endwin = 0; 174 __restartwin(); 175 } 176 177 __rawmode = 1; 178 curt = useraw ? &rawt : &cbreakt; 179 return (tcsetattr(STDIN_FILENO, __tcaction ? 180 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 181 } 182 183 int 184 nocbreak() 185 { 186 /* Check if we need to restart ... */ 187 if (__endwin) { 188 __endwin = 0; 189 __restartwin(); 190 } 191 192 __rawmode = 0; 193 curt = useraw ? &rawt : &__baset; 194 return (tcsetattr(STDIN_FILENO, __tcaction ? 195 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 196 } 197 198 int 199 __delay() 200 { 201 /* Check if we need to restart ... */ 202 if (__endwin) { 203 __endwin = 0; 204 __restartwin(); 205 } 206 207 rawt.c_cc[VMIN] = 1; 208 rawt.c_cc[VTIME] = 0; 209 cbreakt.c_cc[VMIN] = 1; 210 cbreakt.c_cc[VTIME] = 0; 211 __baset.c_cc[VMIN] = 1; 212 __baset.c_cc[VTIME] = 0; 213 214 return (tcsetattr(STDIN_FILENO, __tcaction ? 215 TCSASOFT : TCSANOW, curt) ? ERR : OK); 216 } 217 218 int 219 __nodelay() 220 { 221 /* Check if we need to restart ... */ 222 if (__endwin) { 223 __endwin = 0; 224 __restartwin(); 225 } 226 227 rawt.c_cc[VMIN] = 0; 228 rawt.c_cc[VTIME] = 0; 229 cbreakt.c_cc[VMIN] = 0; 230 cbreakt.c_cc[VTIME] = 0; 231 __baset.c_cc[VMIN] = 0; 232 __baset.c_cc[VTIME] = 0; 233 234 return (tcsetattr(STDIN_FILENO, __tcaction ? 235 TCSASOFT : TCSANOW, curt) ? ERR : OK); 236 } 237 238 void 239 __save_termios() 240 { 241 /* Check if we need to restart ... */ 242 if (__endwin) { 243 __endwin = 0; 244 __restartwin(); 245 } 246 247 ovmin = cbreakt.c_cc[VMIN]; 248 ovtime = cbreakt.c_cc[VTIME]; 249 } 250 251 void 252 __restore_termios() 253 { 254 /* Check if we need to restart ... */ 255 if (__endwin) { 256 __endwin = 0; 257 __restartwin(); 258 } 259 260 rawt.c_cc[VMIN] = ovmin; 261 rawt.c_cc[VTIME] = ovtime; 262 cbreakt.c_cc[VMIN] = ovmin; 263 cbreakt.c_cc[VTIME] = ovtime; 264 __baset.c_cc[VMIN] = ovmin; 265 __baset.c_cc[VTIME] = ovtime; 266 } 267 268 int 269 __timeout(delay) 270 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() 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() 313 { 314 /* Check if we need to restart ... */ 315 if (__endwin) { 316 __endwin = 0; 317 __restartwin(); 318 } 319 320 rawt.c_lflag |= ECHO; 321 cbreakt.c_lflag |= ECHO; 322 __baset.c_lflag |= ECHO; 323 324 __echoit = 1; 325 return (tcsetattr(STDIN_FILENO, __tcaction ? 326 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 327 } 328 329 int 330 noecho() 331 { 332 /* Check if we need to restart ... */ 333 if (__endwin) { 334 __endwin = 0; 335 __restartwin(); 336 } 337 338 rawt.c_lflag &= ~ECHO; 339 cbreakt.c_lflag &= ~ECHO; 340 __baset.c_lflag &= ~ECHO; 341 342 __echoit = 0; 343 return (tcsetattr(STDIN_FILENO, __tcaction ? 344 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 345 } 346 347 int 348 nl() 349 { 350 /* Check if we need to restart ... */ 351 if (__endwin) { 352 __endwin = 0; 353 __restartwin(); 354 } 355 356 rawt.c_iflag |= ICRNL; 357 rawt.c_oflag |= ONLCR; 358 cbreakt.c_iflag |= ICRNL; 359 cbreakt.c_oflag |= ONLCR; 360 __baset.c_iflag |= ICRNL; 361 __baset.c_oflag |= ONLCR; 362 363 __pfast = __rawmode; 364 return (tcsetattr(STDIN_FILENO, __tcaction ? 365 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 366 } 367 368 int 369 nonl() 370 { 371 /* Check if we need to restart ... */ 372 if (__endwin) { 373 __endwin = 0; 374 __restartwin(); 375 } 376 377 rawt.c_iflag &= ~ICRNL; 378 rawt.c_oflag &= ~ONLCR; 379 cbreakt.c_iflag &= ~ICRNL; 380 cbreakt.c_oflag &= ~ONLCR; 381 __baset.c_iflag &= ~ICRNL; 382 __baset.c_oflag &= ~ONLCR; 383 384 __pfast = 1; 385 return (tcsetattr(STDIN_FILENO, __tcaction ? 386 TCSASOFT | TCSADRAIN : TCSADRAIN, curt) ? ERR : OK); 387 } 388 389 void 390 __startwin() 391 { 392 static char *stdbuf; 393 static size_t len; 394 395 (void) fflush(stdout); 396 397 /* 398 * Some C libraries default to a 1K buffer when talking to a tty. 399 * With a larger screen, especially across a network, we'd like 400 * to get it to all flush in a single write. Make it twice as big 401 * as just the characters (so that we have room for cursor motions 402 * and attribute information) but no more than 8K. 403 */ 404 if (stdbuf == NULL) { 405 if ((len = LINES * COLS * 2) > 8192) 406 len = 8192; 407 if ((stdbuf = malloc(len)) == NULL) 408 len = 0; 409 } 410 (void) setvbuf(stdout, stdbuf, _IOFBF, len); 411 412 tputs(TI, 0, __cputchar); 413 tputs(VS, 0, __cputchar); 414 tputs(KS, 0, __cputchar); 415 } 416 417 int 418 endwin() 419 { 420 __endwin = 1; 421 return __stopwin(); 422 } 423 424 int 425 isendwin() 426 { 427 return (__endwin); 428 } 429 430 int 431 flushinp() 432 { 433 int what = FREAD; 434 (void) ioctl(STDIN_FILENO, TIOCFLUSH, &what); 435 return (OK); 436 } 437 438 /* 439 * The following routines, savetty and resetty are completely useless and 440 * are left in only as stubs. If people actually use them they will almost 441 * certainly screw up the state of the world. 442 */ 443 static struct termios savedtty; 444 int 445 savetty() 446 { 447 return (tcgetattr(STDIN_FILENO, &savedtty) ? ERR : OK); 448 } 449 450 int 451 resetty() 452 { 453 return (tcsetattr(STDIN_FILENO, __tcaction ? 454 TCSASOFT | TCSADRAIN : TCSADRAIN, &savedtty) ? ERR : OK); 455 } 456