1 /* $NetBSD: tty.c,v 1.48 2018/11/16 10:12:00 blymn 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.48 2018/11/16 10:12:00 blymn Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/fcntl.h> 42 #include <sys/ioctl.h> 43 #include <sys/param.h> 44 #include <sys/types.h> 45 46 #include <stdlib.h> 47 #include <termios.h> 48 #include <unistd.h> 49 50 #include "curses.h" 51 #include "curses_private.h" 52 53 /* 54 * In general, curses should leave tty hardware settings alone (speed, parity, 55 * word size). This is most easily done in BSD by using TCSASOFT on all 56 * tcsetattr calls. On other systems, it would be better to get and restore 57 * those attributes at each change, or at least when stopped and restarted. 58 * See also the comments in getterm(). 59 */ 60 #ifndef TCSASOFT 61 #define TCSASOFT 0 62 #endif 63 64 int __tcaction = TCSASOFT != 0; /* Ignore hardware settings */ 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 82 if (_cursesi_screen->notty == TRUE) 83 return 0; 84 85 return cfgetospeed(&_cursesi_screen->baset); 86 } 87 88 /* 89 * gettmode -- 90 * Do terminal type initialization. 91 */ 92 int 93 gettmode(void) 94 { 95 96 if (_cursesi_gettmode(_cursesi_screen) == ERR) 97 return ERR; 98 99 __GT = _cursesi_screen->GT; 100 __NONL = _cursesi_screen->NONL; 101 return OK; 102 } 103 104 /* 105 * _cursesi_gettmode -- 106 * Do the terminal type initialisation for the tty attached to the 107 * given screen. 108 */ 109 int 110 _cursesi_gettmode(SCREEN *screen) 111 { 112 screen->useraw = 0; 113 114 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) { 115 /* if the input fd is not a tty try the output */ 116 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) { 117 /* not a tty ... we will disable tty related stuff */ 118 screen->notty = TRUE; 119 __GT = 0; 120 __NONL = 0; 121 return OK; 122 } 123 } 124 125 screen->baset = screen->orig_termios; 126 screen->baset.c_oflag &= ~OXTABS; 127 128 screen->GT = 0; /* historical. was used before we wired OXTABS off */ 129 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0; 130 131 /* 132 * XXX 133 * System V and SMI systems overload VMIN and VTIME, such that 134 * VMIN is the same as the VEOF element, and VTIME is the same 135 * as the VEOL element. This means that, if VEOF was ^D, the 136 * default VMIN is 4. Majorly stupid. 137 */ 138 screen->cbreakt = screen->baset; 139 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON); 140 screen->cbreakt.c_cc[VMIN] = 1; 141 screen->cbreakt.c_cc[VTIME] = 0; 142 143 screen->rawt = screen->cbreakt; 144 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | 145 ICRNL | IXON); 146 screen->rawt.c_oflag &= ~OPOST; 147 screen->rawt.c_lflag &= ~(ISIG | IEXTEN); 148 149 #if TCSASOFT == 0 150 /* 151 * In general, curses should leave hardware-related settings alone. 152 * This includes parity and word size. Older versions set the tty 153 * to 8 bits, no parity in raw(), but this is considered to be an 154 * artifact of the old tty interface. If it's desired to change 155 * parity and word size, the TCSASOFT bit has to be removed from the 156 * calls that switch to/from "raw" mode. 157 */ 158 screen->rawt.c_iflag &= ~ISTRIP; 159 screen->rawt.c_cflag &= ~(CSIZE | PARENB); 160 screen->rawt.c_cflag |= CS8; 161 #endif 162 163 screen->curt = &screen->baset; 164 return tcsetattr(fileno(screen->infd), TCSASOFT | TCSADRAIN, 165 screen->curt) ? ERR : OK; 166 } 167 168 /* 169 * raw -- 170 * Put the terminal into raw mode 171 */ 172 int 173 raw(void) 174 { 175 #ifdef DEBUG 176 __CTRACE(__CTRACE_MISC, "raw()\n"); 177 #endif 178 /* Check if we need to restart ... */ 179 if (_cursesi_screen->endwin) 180 __restartwin(); 181 182 _cursesi_screen->useraw = __pfast = __rawmode = 1; 183 _cursesi_screen->curt = &_cursesi_screen->rawt; 184 if (_cursesi_screen->notty == TRUE) 185 return OK; 186 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 187 _cursesi_screen->curt) ? ERR : OK; 188 } 189 190 /* 191 * noraw -- 192 * Put the terminal into cooked mode 193 */ 194 int 195 noraw(void) 196 { 197 #ifdef DEBUG 198 __CTRACE(__CTRACE_MISC, "noraw()\n"); 199 #endif 200 /* Check if we need to restart ... */ 201 if (_cursesi_screen->endwin) 202 __restartwin(); 203 204 _cursesi_screen->useraw = __pfast = __rawmode = 0; 205 if (_cursesi_screen->notty == TRUE) 206 return OK; 207 _cursesi_screen->curt = &_cursesi_screen->baset; 208 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | 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), TCSASOFT | TCSADRAIN, 232 _cursesi_screen->curt) ? ERR : OK; 233 } 234 235 /* 236 * nocbreak -- 237 * Disable cbreak mode 238 */ 239 int 240 nocbreak(void) 241 { 242 #ifdef DEBUG 243 __CTRACE(__CTRACE_MISC, "nocbreak()\n"); 244 #endif 245 /* Check if we need to restart ... */ 246 if (_cursesi_screen->endwin) 247 __restartwin(); 248 249 __rawmode = 0; 250 if (_cursesi_screen->notty == TRUE) 251 return OK; 252 /* if we were in halfdelay mode then nuke the timeout */ 253 if ((stdscr->flags & __HALFDELAY) && 254 (__notimeout() == ERR)) 255 return ERR; 256 257 stdscr->flags &= ~__HALFDELAY; 258 _cursesi_screen->curt = _cursesi_screen->useraw ? 259 &_cursesi_screen->rawt : &_cursesi_screen->baset; 260 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 261 _cursesi_screen->curt) ? ERR : OK; 262 } 263 264 /* 265 * halfdelay -- 266 * Put the terminal into cbreak mode with the specified timeout. 267 * 268 */ 269 int 270 halfdelay(int duration) 271 { 272 if ((duration < 1) || (duration > 255)) 273 return ERR; 274 275 if (cbreak() == ERR) 276 return ERR; 277 278 if (duration > 255) 279 stdscr->delay = 255; 280 else 281 stdscr->delay = duration; 282 283 stdscr->flags |= __HALFDELAY; 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), TCSASOFT | TCSANOW, 307 _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), TCSASOFT | TCSANOW, 335 _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), TCSASOFT | TCSANOW, 395 _cursesi_screen->curt)) { 396 __restore_termios(); 397 return ERR; 398 } 399 400 return OK; 401 } 402 403 int 404 __notimeout(void) 405 { 406 #ifdef DEBUG 407 __CTRACE(__CTRACE_MISC, "__notimeout()\n"); 408 #endif 409 /* Check if we need to restart ... */ 410 if (_cursesi_screen->endwin) 411 __restartwin(); 412 413 if (_cursesi_screen->notty == TRUE) 414 return OK; 415 _cursesi_screen->rawt.c_cc[VMIN] = 1; 416 _cursesi_screen->rawt.c_cc[VTIME] = 0; 417 _cursesi_screen->cbreakt.c_cc[VMIN] = 1; 418 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 419 _cursesi_screen->baset.c_cc[VMIN] = 1; 420 _cursesi_screen->baset.c_cc[VTIME] = 0; 421 422 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW, 423 _cursesi_screen->curt) ? ERR : OK; 424 } 425 426 int 427 echo(void) 428 { 429 #ifdef DEBUG 430 __CTRACE(__CTRACE_MISC, "echo()\n"); 431 #endif 432 /* Check if we need to restart ... */ 433 if (_cursesi_screen->endwin) 434 __restartwin(); 435 436 __echoit = 1; 437 return OK; 438 } 439 440 int 441 noecho(void) 442 { 443 #ifdef DEBUG 444 __CTRACE(__CTRACE_MISC, "noecho()\n"); 445 #endif 446 /* Check if we need to restart ... */ 447 if (_cursesi_screen->endwin) 448 __restartwin(); 449 450 __echoit = 0; 451 return OK; 452 } 453 454 int 455 nl(void) 456 { 457 #ifdef DEBUG 458 __CTRACE(__CTRACE_MISC, "nl()\n"); 459 #endif 460 /* Check if we need to restart ... */ 461 if (_cursesi_screen->endwin) 462 __restartwin(); 463 464 if (_cursesi_screen->notty == TRUE) 465 return OK; 466 _cursesi_screen->rawt.c_iflag |= ICRNL; 467 _cursesi_screen->rawt.c_oflag |= ONLCR; 468 _cursesi_screen->cbreakt.c_iflag |= ICRNL; 469 _cursesi_screen->cbreakt.c_oflag |= ONLCR; 470 _cursesi_screen->baset.c_iflag |= ICRNL; 471 _cursesi_screen->baset.c_oflag |= ONLCR; 472 473 _cursesi_screen->nl = 1; 474 _cursesi_screen->pfast = _cursesi_screen->rawmode; 475 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 476 _cursesi_screen->curt) ? ERR : OK; 477 } 478 479 int 480 nonl(void) 481 { 482 #ifdef DEBUG 483 __CTRACE(__CTRACE_MISC, "nonl()\n"); 484 #endif 485 /* Check if we need to restart ... */ 486 if (_cursesi_screen->endwin) 487 __restartwin(); 488 489 if (_cursesi_screen->notty == TRUE) 490 return OK; 491 _cursesi_screen->rawt.c_iflag &= ~ICRNL; 492 _cursesi_screen->rawt.c_oflag &= ~ONLCR; 493 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL; 494 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR; 495 _cursesi_screen->baset.c_iflag &= ~ICRNL; 496 _cursesi_screen->baset.c_oflag &= ~ONLCR; 497 498 _cursesi_screen->nl = 0; 499 __pfast = 1; 500 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 501 _cursesi_screen->curt) ? ERR : OK; 502 } 503 504 #ifndef _CURSES_USE_MACROS 505 void 506 noqiflush(void) 507 { 508 509 (void)intrflush(stdscr, FALSE); 510 } 511 512 void 513 qiflush(void) 514 { 515 516 (void)intrflush(stdscr, TRUE); 517 } 518 #endif /* _CURSES_USE_MACROS */ 519 520 /*ARGSUSED*/ 521 int 522 intrflush(WINDOW *win, bool bf) 523 { 524 /* Check if we need to restart ... */ 525 if (_cursesi_screen->endwin) 526 __restartwin(); 527 528 if (_cursesi_screen->notty == TRUE) 529 return OK; 530 if (bf) { 531 _cursesi_screen->rawt.c_lflag &= ~NOFLSH; 532 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH; 533 _cursesi_screen->baset.c_lflag &= ~NOFLSH; 534 } else { 535 _cursesi_screen->rawt.c_lflag |= NOFLSH; 536 _cursesi_screen->cbreakt.c_lflag |= NOFLSH; 537 _cursesi_screen->baset.c_lflag |= NOFLSH; 538 } 539 540 __pfast = 1; 541 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 542 _cursesi_screen->curt) ? ERR : OK; 543 } 544 545 void 546 __startwin(SCREEN *screen) 547 { 548 549 (void)fflush(screen->infd); 550 551 #ifdef BSD 552 /* 553 * Some C libraries default to a 1K buffer when talking to a tty. 554 * With a larger screen, especially across a network, we'd like 555 * to get it to all flush in a single write. Make it twice as big 556 * as just the characters (so that we have room for cursor motions 557 * and attribute information) but no more than 8K. 558 * 559 * However, setvbuf may only be used after opening a stream and 560 * before any operations have been performed on it. 561 * This means we cannot work portably if an application wants 562 * to stop curses and start curses after a resize. 563 * Curses resizing is not standard, and thus not strictly portable 564 * even though all curses today support it. 565 * The BSD systems do not suffer from this limitation on setvbuf. 566 */ 567 if (screen->stdbuf == NULL) { 568 screen->len = LINES * COLS * 2; 569 if (screen->len > 8192) 570 screen->len = 8192; 571 if ((screen->stdbuf = malloc(screen->len)) == NULL) 572 screen->len = 0; 573 } 574 (void)setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len); 575 #endif 576 577 ti_puts(screen->term, t_enter_ca_mode(screen->term), 0, 578 __cputchar_args, (void *) screen->outfd); 579 ti_puts(screen->term, t_cursor_normal(screen->term), 0, 580 __cputchar_args, (void *) screen->outfd); 581 if (screen->curscr->flags & __KEYPAD) 582 ti_puts(screen->term, t_keypad_xmit(screen->term), 0, 583 __cputchar_args, (void *) screen->outfd); 584 screen->endwin = 0; 585 } 586 587 int 588 endwin(void) 589 { 590 #ifdef DEBUG 591 __CTRACE(__CTRACE_MISC, "endwin\n"); 592 #endif 593 return __stopwin(); 594 } 595 596 bool 597 isendwin(void) 598 { 599 600 return _cursesi_screen->endwin ? TRUE : FALSE; 601 } 602 603 int 604 flushinp(void) 605 { 606 607 (void)fpurge(_cursesi_screen->infd); 608 return OK; 609 } 610 611 /* 612 * The following routines, savetty and resetty are completely useless and 613 * are left in only as stubs. If people actually use them they will almost 614 * certainly screw up the state of the world. 615 */ 616 /*static struct termios savedtty;*/ 617 int 618 savetty(void) 619 { 620 621 if (_cursesi_screen->notty == TRUE) 622 return OK; 623 return tcgetattr(fileno(_cursesi_screen->infd), 624 &_cursesi_screen->savedtty) ? ERR : OK; 625 } 626 627 int 628 resetty(void) 629 { 630 631 if (_cursesi_screen->notty == TRUE) 632 return OK; 633 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 634 &_cursesi_screen->savedtty) ? ERR : OK; 635 } 636 637 /* 638 * erasechar -- 639 * Return the character of the erase key. 640 */ 641 char 642 erasechar(void) 643 { 644 645 if (_cursesi_screen->notty == TRUE) 646 return 0; 647 return _cursesi_screen->baset.c_cc[VERASE]; 648 } 649 650 /* 651 * killchar -- 652 * Return the character of the kill key. 653 */ 654 char 655 killchar(void) 656 { 657 658 if (_cursesi_screen->notty == TRUE) 659 return 0; 660 return _cursesi_screen->baset.c_cc[VKILL]; 661 } 662 663 /* 664 * erasewchar -- 665 * Return the wide character of the erase key. 666 */ 667 int 668 erasewchar(wchar_t *ch) 669 { 670 671 #ifndef HAVE_WCHAR 672 return ERR; 673 #else 674 if (_cursesi_screen->notty == TRUE) 675 return ERR; 676 *ch = _cursesi_screen->baset.c_cc[VERASE]; 677 return OK; 678 #endif /* HAVE_WCHAR */ 679 } 680 681 /* 682 * killwchar -- 683 * Return the wide character of the kill key. 684 */ 685 int 686 killwchar( wchar_t *ch ) 687 { 688 689 #ifndef HAVE_WCHAR 690 return ERR; 691 #else 692 if (_cursesi_screen->notty == TRUE) 693 return 0; 694 *ch = _cursesi_screen->baset.c_cc[VKILL]; 695 return OK; 696 #endif /* HAVE_WCHAR */ 697 } 698 699 int 700 typeahead(int filedes) 701 { 702 703 _cursesi_screen->checkfd = filedes; 704 return OK; 705 } 706