1 /* $NetBSD: tty.c,v 1.42 2010/02/03 15:34:40 roy 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. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)tty.c 8.6 (Berkeley) 1/10/95"; 36 #else 37 __RCSID("$NetBSD: tty.c,v 1.42 2010/02/03 15:34:40 roy Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/types.h> 42 43 #include <stdlib.h> 44 #include <termios.h> 45 #include <unistd.h> 46 #include <sys/fcntl.h> 47 #include <sys/ioctl.h> 48 49 #include "curses.h" 50 #include "curses_private.h" 51 52 /* 53 * In general, curses should leave tty hardware settings alone (speed, parity, 54 * word size). This is most easily done in BSD by using TCSASOFT on all 55 * tcsetattr calls. On other systems, it would be better to get and restore 56 * those attributes at each change, or at least when stopped and restarted. 57 * See also the comments in getterm(). 58 */ 59 #ifdef TCSASOFT 60 int __tcaction = 1; /* Ignore hardware settings. */ 61 #else 62 #define TCSASOFT 0 63 int __tcaction = 0; 64 #endif 65 66 #ifndef OXTABS 67 #ifdef XTABS /* SMI uses XTABS. */ 68 #define OXTABS XTABS 69 #else 70 #define OXTABS 0 71 #endif 72 #endif 73 74 /* 75 * baudrate -- 76 * Return the current baudrate 77 */ 78 int 79 baudrate(void) 80 { 81 if (_cursesi_screen->notty == TRUE) 82 return 0; 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 /* if the input fd is not a tty try the output */ 114 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) { 115 /* not a tty ... we will disable tty related stuff */ 116 screen->notty = TRUE; 117 __GT = 0; 118 __NONL = 0; 119 return (OK); 120 } 121 } 122 123 screen->baset = screen->orig_termios; 124 screen->baset.c_oflag &= ~OXTABS; 125 126 screen->GT = 0; /* historical. was used before we wired OXTABS off */ 127 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0; 128 129 /* 130 * XXX 131 * System V and SMI systems overload VMIN and VTIME, such that 132 * VMIN is the same as the VEOF element, and VTIME is the same 133 * as the VEOL element. This means that, if VEOF was ^D, the 134 * default VMIN is 4. Majorly stupid. 135 */ 136 screen->cbreakt = screen->baset; 137 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON); 138 screen->cbreakt.c_cc[VMIN] = 1; 139 screen->cbreakt.c_cc[VTIME] = 0; 140 141 screen->rawt = screen->cbreakt; 142 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | 143 ICRNL | IXON); 144 screen->rawt.c_oflag &= ~OPOST; 145 screen->rawt.c_lflag &= ~(ISIG | IEXTEN); 146 147 /* 148 * In general, curses should leave hardware-related settings alone. 149 * This includes parity and word size. Older versions set the tty 150 * to 8 bits, no parity in raw(), but this is considered to be an 151 * artifact of the old tty interface. If it's desired to change 152 * parity and word size, the TCSASOFT bit has to be removed from the 153 * calls that switch to/from "raw" mode. 154 */ 155 if (!__tcaction) { 156 screen->rawt.c_iflag &= ~ISTRIP; 157 screen->rawt.c_cflag &= ~(CSIZE | PARENB); 158 screen->rawt.c_cflag |= CS8; 159 } 160 161 screen->curt = &screen->baset; 162 return (tcsetattr(fileno(screen->infd), __tcaction ? 163 TCSASOFT | TCSADRAIN : TCSADRAIN, screen->curt) ? ERR : OK); 164 } 165 166 /* 167 * raw -- 168 * Put the terminal into raw mode 169 */ 170 int 171 raw(void) 172 { 173 #ifdef DEBUG 174 __CTRACE(__CTRACE_MISC, "raw()\n"); 175 #endif 176 /* Check if we need to restart ... */ 177 if (_cursesi_screen->endwin) 178 __restartwin(); 179 180 _cursesi_screen->useraw = __pfast = __rawmode = 1; 181 _cursesi_screen->curt = &_cursesi_screen->rawt; 182 if (_cursesi_screen->notty == TRUE) 183 return OK; 184 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 185 TCSASOFT | TCSADRAIN : TCSADRAIN, 186 _cursesi_screen->curt) ? ERR : OK); 187 } 188 189 /* 190 * noraw -- 191 * Put the terminal into cooked mode 192 */ 193 int 194 noraw(void) 195 { 196 #ifdef DEBUG 197 __CTRACE(__CTRACE_MISC, "noraw()\n"); 198 #endif 199 /* Check if we need to restart ... */ 200 if (_cursesi_screen->endwin) 201 __restartwin(); 202 203 _cursesi_screen->useraw = __pfast = __rawmode = 0; 204 if (_cursesi_screen->notty == TRUE) 205 return OK; 206 _cursesi_screen->curt = &_cursesi_screen->baset; 207 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 208 TCSASOFT | TCSADRAIN : TCSADRAIN, 209 _cursesi_screen->curt) ? ERR : OK); 210 } 211 212 /* 213 * cbreak -- 214 * Enable cbreak mode 215 */ 216 int 217 cbreak(void) 218 { 219 #ifdef DEBUG 220 __CTRACE(__CTRACE_MISC, "cbreak()\n"); 221 #endif 222 /* Check if we need to restart ... */ 223 if (_cursesi_screen->endwin) 224 __restartwin(); 225 226 __rawmode = 1; 227 if (_cursesi_screen->notty == TRUE) 228 return OK; 229 _cursesi_screen->curt = _cursesi_screen->useraw ? 230 &_cursesi_screen->rawt : &_cursesi_screen->cbreakt; 231 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 232 TCSASOFT | TCSADRAIN : TCSADRAIN, 233 _cursesi_screen->curt) ? ERR : OK); 234 } 235 236 /* 237 * nocbreak -- 238 * Disable cbreak mode 239 */ 240 int 241 nocbreak(void) 242 { 243 #ifdef DEBUG 244 __CTRACE(__CTRACE_MISC, "nocbreak()\n"); 245 #endif 246 /* Check if we need to restart ... */ 247 if (_cursesi_screen->endwin) 248 __restartwin(); 249 250 __rawmode = 0; 251 if (_cursesi_screen->notty == TRUE) 252 return OK; 253 /* if we were in halfdelay mode then nuke the timeout */ 254 if ((_cursesi_screen->half_delay == TRUE) && 255 (__notimeout() == ERR)) 256 return ERR; 257 258 _cursesi_screen->half_delay = FALSE; 259 _cursesi_screen->curt = _cursesi_screen->useraw ? 260 &_cursesi_screen->rawt : &_cursesi_screen->baset; 261 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 262 TCSASOFT | TCSADRAIN : TCSADRAIN, 263 _cursesi_screen->curt) ? ERR : OK); 264 } 265 266 /* 267 * halfdelay -- 268 * Put the terminal into cbreak mode with the specified timeout. 269 * 270 */ 271 int 272 halfdelay(int duration) 273 { 274 if ((duration < 1) || (duration > 255)) 275 return ERR; 276 277 if (cbreak() == ERR) 278 return ERR; 279 280 if (__timeout(duration) == ERR) 281 return ERR; 282 283 _cursesi_screen->half_delay = TRUE; 284 return OK; 285 } 286 287 int 288 __delay(void) 289 { 290 #ifdef DEBUG 291 __CTRACE(__CTRACE_MISC, "__delay()\n"); 292 #endif 293 /* Check if we need to restart ... */ 294 if (_cursesi_screen->endwin) 295 __restartwin(); 296 297 if (_cursesi_screen->notty == TRUE) 298 return OK; 299 _cursesi_screen->rawt.c_cc[VMIN] = 1; 300 _cursesi_screen->rawt.c_cc[VTIME] = 0; 301 _cursesi_screen->cbreakt.c_cc[VMIN] = 1; 302 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 303 _cursesi_screen->baset.c_cc[VMIN] = 1; 304 _cursesi_screen->baset.c_cc[VTIME] = 0; 305 306 if (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 307 TCSASOFT : TCSANOW, _cursesi_screen->curt)) { 308 __restore_termios(); 309 return ERR; 310 } 311 312 return OK; 313 } 314 315 int 316 __nodelay(void) 317 { 318 #ifdef DEBUG 319 __CTRACE(__CTRACE_MISC, "__nodelay()\n"); 320 #endif 321 /* Check if we need to restart ... */ 322 if (_cursesi_screen->endwin) 323 __restartwin(); 324 325 if (_cursesi_screen->notty == TRUE) 326 return OK; 327 _cursesi_screen->rawt.c_cc[VMIN] = 0; 328 _cursesi_screen->rawt.c_cc[VTIME] = 0; 329 _cursesi_screen->cbreakt.c_cc[VMIN] = 0; 330 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 331 _cursesi_screen->baset.c_cc[VMIN] = 0; 332 _cursesi_screen->baset.c_cc[VTIME] = 0; 333 334 if (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 335 TCSASOFT : TCSANOW, _cursesi_screen->curt)) { 336 __restore_termios(); 337 return ERR; 338 } 339 340 return OK; 341 } 342 343 void 344 __save_termios(void) 345 { 346 /* Check if we need to restart ... */ 347 if (_cursesi_screen->endwin) 348 __restartwin(); 349 350 if (_cursesi_screen->notty == TRUE) 351 return; 352 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN]; 353 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME]; 354 } 355 356 void 357 __restore_termios(void) 358 { 359 /* Check if we need to restart ... */ 360 if (_cursesi_screen->endwin) 361 __restartwin(); 362 363 if (_cursesi_screen->notty == TRUE) 364 return; 365 _cursesi_screen->rawt.c_cc[VMIN] = _cursesi_screen->ovmin; 366 _cursesi_screen->rawt.c_cc[VTIME] = _cursesi_screen->ovtime; 367 _cursesi_screen->cbreakt.c_cc[VMIN] = _cursesi_screen->ovmin; 368 _cursesi_screen->cbreakt.c_cc[VTIME] = _cursesi_screen->ovtime; 369 _cursesi_screen->baset.c_cc[VMIN] = _cursesi_screen->ovmin; 370 _cursesi_screen->baset.c_cc[VTIME] = _cursesi_screen->ovtime; 371 } 372 373 int 374 __timeout(int delay) 375 { 376 #ifdef DEBUG 377 __CTRACE(__CTRACE_MISC, "__timeout()\n"); 378 #endif 379 /* Check if we need to restart ... */ 380 if (_cursesi_screen->endwin) 381 __restartwin(); 382 383 if (_cursesi_screen->notty == TRUE) 384 return OK; 385 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN]; 386 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME]; 387 _cursesi_screen->rawt.c_cc[VMIN] = 0; 388 _cursesi_screen->rawt.c_cc[VTIME] = delay; 389 _cursesi_screen->cbreakt.c_cc[VMIN] = 0; 390 _cursesi_screen->cbreakt.c_cc[VTIME] = delay; 391 _cursesi_screen->baset.c_cc[VMIN] = 0; 392 _cursesi_screen->baset.c_cc[VTIME] = delay; 393 394 if (tcsetattr(fileno(_cursesi_screen->infd), 395 __tcaction ? TCSASOFT | TCSANOW : TCSANOW, 396 _cursesi_screen->curt)) { 397 __restore_termios(); 398 return ERR; 399 } 400 401 return OK; 402 } 403 404 int 405 __notimeout(void) 406 { 407 #ifdef DEBUG 408 __CTRACE(__CTRACE_MISC, "__notimeout()\n"); 409 #endif 410 /* Check if we need to restart ... */ 411 if (_cursesi_screen->endwin) 412 __restartwin(); 413 414 if (_cursesi_screen->notty == TRUE) 415 return OK; 416 _cursesi_screen->rawt.c_cc[VMIN] = 1; 417 _cursesi_screen->rawt.c_cc[VTIME] = 0; 418 _cursesi_screen->cbreakt.c_cc[VMIN] = 1; 419 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 420 _cursesi_screen->baset.c_cc[VMIN] = 1; 421 _cursesi_screen->baset.c_cc[VTIME] = 0; 422 423 return (tcsetattr(fileno(_cursesi_screen->infd), 424 __tcaction ? TCSASOFT | TCSANOW : TCSANOW, 425 _cursesi_screen->curt) ? ERR : OK); 426 } 427 428 int 429 echo(void) 430 { 431 #ifdef DEBUG 432 __CTRACE(__CTRACE_MISC, "echo()\n"); 433 #endif 434 /* Check if we need to restart ... */ 435 if (_cursesi_screen->endwin) 436 __restartwin(); 437 438 __echoit = 1; 439 return (OK); 440 } 441 442 int 443 noecho(void) 444 { 445 #ifdef DEBUG 446 __CTRACE(__CTRACE_MISC, "noecho()\n"); 447 #endif 448 /* Check if we need to restart ... */ 449 if (_cursesi_screen->endwin) 450 __restartwin(); 451 452 __echoit = 0; 453 return (OK); 454 } 455 456 int 457 nl(void) 458 { 459 #ifdef DEBUG 460 __CTRACE(__CTRACE_MISC, "nl()\n"); 461 #endif 462 /* Check if we need to restart ... */ 463 if (_cursesi_screen->endwin) 464 __restartwin(); 465 466 if (_cursesi_screen->notty == TRUE) 467 return OK; 468 _cursesi_screen->rawt.c_iflag |= ICRNL; 469 _cursesi_screen->rawt.c_oflag |= ONLCR; 470 _cursesi_screen->cbreakt.c_iflag |= ICRNL; 471 _cursesi_screen->cbreakt.c_oflag |= ONLCR; 472 _cursesi_screen->baset.c_iflag |= ICRNL; 473 _cursesi_screen->baset.c_oflag |= ONLCR; 474 475 _cursesi_screen->nl = 1; 476 _cursesi_screen->pfast = _cursesi_screen->rawmode; 477 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 478 TCSASOFT | TCSADRAIN : TCSADRAIN, 479 _cursesi_screen->curt) ? ERR : OK); 480 } 481 482 int 483 nonl(void) 484 { 485 #ifdef DEBUG 486 __CTRACE(__CTRACE_MISC, "nonl()\n"); 487 #endif 488 /* Check if we need to restart ... */ 489 if (_cursesi_screen->endwin) 490 __restartwin(); 491 492 if (_cursesi_screen->notty == TRUE) 493 return OK; 494 _cursesi_screen->rawt.c_iflag &= ~ICRNL; 495 _cursesi_screen->rawt.c_oflag &= ~ONLCR; 496 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL; 497 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR; 498 _cursesi_screen->baset.c_iflag &= ~ICRNL; 499 _cursesi_screen->baset.c_oflag &= ~ONLCR; 500 501 _cursesi_screen->nl = 0; 502 __pfast = 1; 503 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 504 TCSASOFT | TCSADRAIN : TCSADRAIN, 505 _cursesi_screen->curt) ? ERR : OK); 506 } 507 508 #ifndef _CURSES_USE_MACROS 509 void 510 noqiflush(void) 511 { 512 (void) intrflush(stdscr, FALSE); 513 } 514 515 void 516 qiflush(void) 517 { 518 (void) intrflush(stdscr, TRUE); 519 } 520 #endif /* _CURSES_USE_MACROS */ 521 522 int 523 intrflush(WINDOW *win, bool bf) /*ARGSUSED*/ 524 { 525 /* Check if we need to restart ... */ 526 if (_cursesi_screen->endwin) 527 __restartwin(); 528 529 if (_cursesi_screen->notty == TRUE) 530 return OK; 531 if (bf) { 532 _cursesi_screen->rawt.c_lflag &= ~NOFLSH; 533 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH; 534 _cursesi_screen->baset.c_lflag &= ~NOFLSH; 535 } else { 536 _cursesi_screen->rawt.c_lflag |= NOFLSH; 537 _cursesi_screen->cbreakt.c_lflag |= NOFLSH; 538 _cursesi_screen->baset.c_lflag |= NOFLSH; 539 } 540 541 __pfast = 1; 542 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 543 TCSASOFT | TCSADRAIN : TCSADRAIN, 544 _cursesi_screen->curt) ? ERR : OK); 545 } 546 547 void 548 __startwin(SCREEN *screen) 549 { 550 551 (void) fflush(screen->infd); 552 553 /* 554 * Some C libraries default to a 1K buffer when talking to a tty. 555 * With a larger screen, especially across a network, we'd like 556 * to get it to all flush in a single write. Make it twice as big 557 * as just the characters (so that we have room for cursor motions 558 * and attribute information) but no more than 8K. 559 */ 560 if (screen->stdbuf == NULL) { 561 screen->len = LINES * COLS * 2; 562 if (screen->len > 8192) 563 screen->len = 8192; 564 if ((screen->stdbuf = malloc(screen->len)) == NULL) 565 screen->len = 0; 566 } 567 (void) setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len); 568 569 ti_puts(screen->term, t_enter_ca_mode(screen->term), 0, 570 __cputchar_args, (void *) screen->outfd); 571 ti_puts(screen->term, t_cursor_normal(screen->term), 0, 572 __cputchar_args, (void *) screen->outfd); 573 if (screen->curscr->flags & __KEYPAD) 574 ti_puts(screen->term, t_keypad_xmit(screen->term), 0, 575 __cputchar_args, (void *) screen->outfd); 576 screen->endwin = 0; 577 } 578 579 int 580 endwin(void) 581 { 582 #ifdef DEBUG 583 __CTRACE(__CTRACE_MISC, "endwin\n"); 584 #endif 585 return __stopwin(); 586 } 587 588 bool 589 isendwin(void) 590 { 591 return (_cursesi_screen->endwin ? TRUE : FALSE); 592 } 593 594 int 595 flushinp(void) 596 { 597 (void) fpurge(_cursesi_screen->infd); 598 return (OK); 599 } 600 601 /* 602 * The following routines, savetty and resetty are completely useless and 603 * are left in only as stubs. If people actually use them they will almost 604 * certainly screw up the state of the world. 605 */ 606 /*static struct termios savedtty;*/ 607 int 608 savetty(void) 609 { 610 if (_cursesi_screen->notty == TRUE) 611 return OK; 612 return (tcgetattr(fileno(_cursesi_screen->infd), 613 &_cursesi_screen->savedtty) ? ERR : OK); 614 } 615 616 int 617 resetty(void) 618 { 619 if (_cursesi_screen->notty == TRUE) 620 return OK; 621 return (tcsetattr(fileno(_cursesi_screen->infd), __tcaction ? 622 TCSASOFT | TCSADRAIN : TCSADRAIN, 623 &_cursesi_screen->savedtty) ? ERR : OK); 624 } 625 626 /* 627 * erasechar -- 628 * Return the character of the erase key. 629 */ 630 char 631 erasechar(void) 632 { 633 if (_cursesi_screen->notty == TRUE) 634 return 0; 635 return _cursesi_screen->baset.c_cc[VERASE]; 636 } 637 638 /* 639 * killchar -- 640 * Return the character of the kill key. 641 */ 642 char 643 killchar(void) 644 { 645 if (_cursesi_screen->notty == TRUE) 646 return 0; 647 return _cursesi_screen->baset.c_cc[VKILL]; 648 } 649 650 /* 651 * erasewchar -- 652 * Return the wide character of the erase key. 653 */ 654 int 655 erasewchar( wchar_t *ch ) 656 { 657 #ifndef HAVE_WCHAR 658 return ERR; 659 #else 660 if (_cursesi_screen->notty == TRUE) 661 return ERR; 662 *ch = _cursesi_screen->baset.c_cc[VERASE]; 663 return OK; 664 #endif /* HAVE_WCHAR */ 665 } 666 667 /* 668 * killwchar -- 669 * Return the wide character of the kill key. 670 */ 671 int 672 killwchar( wchar_t *ch ) 673 { 674 #ifndef HAVE_WCHAR 675 return ERR; 676 #else 677 if (_cursesi_screen->notty == TRUE) 678 return 0; 679 *ch = _cursesi_screen->baset.c_cc[VKILL]; 680 return OK; 681 #endif /* HAVE_WCHAR */ 682 } 683