1 /* $NetBSD: tty.c,v 1.46 2017/01/06 13:53:18 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.46 2017/01/06 13:53:18 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 #ifndef TCSASOFT 60 #define TCSASOFT 0 61 #endif 62 63 int __tcaction = TCSASOFT != 0; /* Ignore hardware settings */ 64 65 #ifndef OXTABS 66 #ifdef XTABS /* SMI uses XTABS. */ 67 #define OXTABS XTABS 68 #else 69 #define OXTABS 0 70 #endif 71 #endif 72 73 /* 74 * baudrate -- 75 * Return the current baudrate 76 */ 77 int 78 baudrate(void) 79 { 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 95 if (_cursesi_gettmode(_cursesi_screen) == ERR) 96 return ERR; 97 98 __GT = _cursesi_screen->GT; 99 __NONL = _cursesi_screen->NONL; 100 return OK; 101 } 102 103 /* 104 * _cursesi_gettmode -- 105 * Do the terminal type initialisation for the tty attached to the 106 * given screen. 107 */ 108 int 109 _cursesi_gettmode(SCREEN *screen) 110 { 111 screen->useraw = 0; 112 113 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) { 114 /* if the input fd is not a tty try the output */ 115 if (tcgetattr(fileno(screen->infd), &screen->orig_termios)) { 116 /* not a tty ... we will disable tty related stuff */ 117 screen->notty = TRUE; 118 __GT = 0; 119 __NONL = 0; 120 return OK; 121 } 122 } 123 124 screen->baset = screen->orig_termios; 125 screen->baset.c_oflag &= ~OXTABS; 126 127 screen->GT = 0; /* historical. was used before we wired OXTABS off */ 128 screen->NONL = (screen->baset.c_oflag & ONLCR) == 0; 129 130 /* 131 * XXX 132 * System V and SMI systems overload VMIN and VTIME, such that 133 * VMIN is the same as the VEOF element, and VTIME is the same 134 * as the VEOL element. This means that, if VEOF was ^D, the 135 * default VMIN is 4. Majorly stupid. 136 */ 137 screen->cbreakt = screen->baset; 138 screen->cbreakt.c_lflag &= ~(ECHO | ECHONL | ICANON); 139 screen->cbreakt.c_cc[VMIN] = 1; 140 screen->cbreakt.c_cc[VTIME] = 0; 141 142 screen->rawt = screen->cbreakt; 143 screen->rawt.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | INLCR | IGNCR | 144 ICRNL | IXON); 145 screen->rawt.c_oflag &= ~OPOST; 146 screen->rawt.c_lflag &= ~(ISIG | IEXTEN); 147 148 #if TCSASOFT == 0 149 /* 150 * In general, curses should leave hardware-related settings alone. 151 * This includes parity and word size. Older versions set the tty 152 * to 8 bits, no parity in raw(), but this is considered to be an 153 * artifact of the old tty interface. If it's desired to change 154 * parity and word size, the TCSASOFT bit has to be removed from the 155 * calls that switch to/from "raw" mode. 156 */ 157 screen->rawt.c_iflag &= ~ISTRIP; 158 screen->rawt.c_cflag &= ~(CSIZE | PARENB); 159 screen->rawt.c_cflag |= CS8; 160 #endif 161 162 screen->curt = &screen->baset; 163 return tcsetattr(fileno(screen->infd), TCSASOFT | TCSADRAIN, 164 screen->curt) ? ERR : OK; 165 } 166 167 /* 168 * raw -- 169 * Put the terminal into raw mode 170 */ 171 int 172 raw(void) 173 { 174 #ifdef DEBUG 175 __CTRACE(__CTRACE_MISC, "raw()\n"); 176 #endif 177 /* Check if we need to restart ... */ 178 if (_cursesi_screen->endwin) 179 __restartwin(); 180 181 _cursesi_screen->useraw = __pfast = __rawmode = 1; 182 _cursesi_screen->curt = &_cursesi_screen->rawt; 183 if (_cursesi_screen->notty == TRUE) 184 return OK; 185 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | 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), TCSASOFT | TCSADRAIN, 208 _cursesi_screen->curt) ? ERR : OK; 209 } 210 211 /* 212 * cbreak -- 213 * Enable cbreak mode 214 */ 215 int 216 cbreak(void) 217 { 218 #ifdef DEBUG 219 __CTRACE(__CTRACE_MISC, "cbreak()\n"); 220 #endif 221 /* Check if we need to restart ... */ 222 if (_cursesi_screen->endwin) 223 __restartwin(); 224 225 __rawmode = 1; 226 if (_cursesi_screen->notty == TRUE) 227 return OK; 228 _cursesi_screen->curt = _cursesi_screen->useraw ? 229 &_cursesi_screen->rawt : &_cursesi_screen->cbreakt; 230 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 231 _cursesi_screen->curt) ? ERR : OK; 232 } 233 234 /* 235 * nocbreak -- 236 * Disable cbreak mode 237 */ 238 int 239 nocbreak(void) 240 { 241 #ifdef DEBUG 242 __CTRACE(__CTRACE_MISC, "nocbreak()\n"); 243 #endif 244 /* Check if we need to restart ... */ 245 if (_cursesi_screen->endwin) 246 __restartwin(); 247 248 __rawmode = 0; 249 if (_cursesi_screen->notty == TRUE) 250 return OK; 251 /* if we were in halfdelay mode then nuke the timeout */ 252 if ((_cursesi_screen->half_delay == TRUE) && 253 (__notimeout() == ERR)) 254 return ERR; 255 256 _cursesi_screen->half_delay = FALSE; 257 _cursesi_screen->curt = _cursesi_screen->useraw ? 258 &_cursesi_screen->rawt : &_cursesi_screen->baset; 259 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 260 _cursesi_screen->curt) ? ERR : OK; 261 } 262 263 /* 264 * halfdelay -- 265 * Put the terminal into cbreak mode with the specified timeout. 266 * 267 */ 268 int 269 halfdelay(int duration) 270 { 271 if ((duration < 1) || (duration > 255)) 272 return ERR; 273 274 if (cbreak() == ERR) 275 return ERR; 276 277 if (__timeout(duration) == ERR) 278 return ERR; 279 280 _cursesi_screen->half_delay = TRUE; 281 return OK; 282 } 283 284 int 285 __delay(void) 286 { 287 #ifdef DEBUG 288 __CTRACE(__CTRACE_MISC, "__delay()\n"); 289 #endif 290 /* Check if we need to restart ... */ 291 if (_cursesi_screen->endwin) 292 __restartwin(); 293 294 if (_cursesi_screen->notty == TRUE) 295 return OK; 296 _cursesi_screen->rawt.c_cc[VMIN] = 1; 297 _cursesi_screen->rawt.c_cc[VTIME] = 0; 298 _cursesi_screen->cbreakt.c_cc[VMIN] = 1; 299 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 300 _cursesi_screen->baset.c_cc[VMIN] = 1; 301 _cursesi_screen->baset.c_cc[VTIME] = 0; 302 303 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW, 304 _cursesi_screen->curt)) { 305 __restore_termios(); 306 return ERR; 307 } 308 309 return OK; 310 } 311 312 int 313 __nodelay(void) 314 { 315 #ifdef DEBUG 316 __CTRACE(__CTRACE_MISC, "__nodelay()\n"); 317 #endif 318 /* Check if we need to restart ... */ 319 if (_cursesi_screen->endwin) 320 __restartwin(); 321 322 if (_cursesi_screen->notty == TRUE) 323 return OK; 324 _cursesi_screen->rawt.c_cc[VMIN] = 0; 325 _cursesi_screen->rawt.c_cc[VTIME] = 0; 326 _cursesi_screen->cbreakt.c_cc[VMIN] = 0; 327 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 328 _cursesi_screen->baset.c_cc[VMIN] = 0; 329 _cursesi_screen->baset.c_cc[VTIME] = 0; 330 331 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW, 332 _cursesi_screen->curt)) { 333 __restore_termios(); 334 return ERR; 335 } 336 337 return OK; 338 } 339 340 void 341 __save_termios(void) 342 { 343 /* Check if we need to restart ... */ 344 if (_cursesi_screen->endwin) 345 __restartwin(); 346 347 if (_cursesi_screen->notty == TRUE) 348 return; 349 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN]; 350 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME]; 351 } 352 353 void 354 __restore_termios(void) 355 { 356 /* Check if we need to restart ... */ 357 if (_cursesi_screen->endwin) 358 __restartwin(); 359 360 if (_cursesi_screen->notty == TRUE) 361 return; 362 _cursesi_screen->rawt.c_cc[VMIN] = _cursesi_screen->ovmin; 363 _cursesi_screen->rawt.c_cc[VTIME] = _cursesi_screen->ovtime; 364 _cursesi_screen->cbreakt.c_cc[VMIN] = _cursesi_screen->ovmin; 365 _cursesi_screen->cbreakt.c_cc[VTIME] = _cursesi_screen->ovtime; 366 _cursesi_screen->baset.c_cc[VMIN] = _cursesi_screen->ovmin; 367 _cursesi_screen->baset.c_cc[VTIME] = _cursesi_screen->ovtime; 368 } 369 370 int 371 __timeout(int delay) 372 { 373 #ifdef DEBUG 374 __CTRACE(__CTRACE_MISC, "__timeout()\n"); 375 #endif 376 /* Check if we need to restart ... */ 377 if (_cursesi_screen->endwin) 378 __restartwin(); 379 380 if (_cursesi_screen->notty == TRUE) 381 return OK; 382 _cursesi_screen->ovmin = _cursesi_screen->cbreakt.c_cc[VMIN]; 383 _cursesi_screen->ovtime = _cursesi_screen->cbreakt.c_cc[VTIME]; 384 _cursesi_screen->rawt.c_cc[VMIN] = 0; 385 _cursesi_screen->rawt.c_cc[VTIME] = delay; 386 _cursesi_screen->cbreakt.c_cc[VMIN] = 0; 387 _cursesi_screen->cbreakt.c_cc[VTIME] = delay; 388 _cursesi_screen->baset.c_cc[VMIN] = 0; 389 _cursesi_screen->baset.c_cc[VTIME] = delay; 390 391 if (tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW, 392 _cursesi_screen->curt)) { 393 __restore_termios(); 394 return ERR; 395 } 396 397 return OK; 398 } 399 400 int 401 __notimeout(void) 402 { 403 #ifdef DEBUG 404 __CTRACE(__CTRACE_MISC, "__notimeout()\n"); 405 #endif 406 /* Check if we need to restart ... */ 407 if (_cursesi_screen->endwin) 408 __restartwin(); 409 410 if (_cursesi_screen->notty == TRUE) 411 return OK; 412 _cursesi_screen->rawt.c_cc[VMIN] = 1; 413 _cursesi_screen->rawt.c_cc[VTIME] = 0; 414 _cursesi_screen->cbreakt.c_cc[VMIN] = 1; 415 _cursesi_screen->cbreakt.c_cc[VTIME] = 0; 416 _cursesi_screen->baset.c_cc[VMIN] = 1; 417 _cursesi_screen->baset.c_cc[VTIME] = 0; 418 419 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSANOW, 420 _cursesi_screen->curt) ? ERR : OK; 421 } 422 423 int 424 echo(void) 425 { 426 #ifdef DEBUG 427 __CTRACE(__CTRACE_MISC, "echo()\n"); 428 #endif 429 /* Check if we need to restart ... */ 430 if (_cursesi_screen->endwin) 431 __restartwin(); 432 433 __echoit = 1; 434 return OK; 435 } 436 437 int 438 noecho(void) 439 { 440 #ifdef DEBUG 441 __CTRACE(__CTRACE_MISC, "noecho()\n"); 442 #endif 443 /* Check if we need to restart ... */ 444 if (_cursesi_screen->endwin) 445 __restartwin(); 446 447 __echoit = 0; 448 return OK; 449 } 450 451 int 452 nl(void) 453 { 454 #ifdef DEBUG 455 __CTRACE(__CTRACE_MISC, "nl()\n"); 456 #endif 457 /* Check if we need to restart ... */ 458 if (_cursesi_screen->endwin) 459 __restartwin(); 460 461 if (_cursesi_screen->notty == TRUE) 462 return OK; 463 _cursesi_screen->rawt.c_iflag |= ICRNL; 464 _cursesi_screen->rawt.c_oflag |= ONLCR; 465 _cursesi_screen->cbreakt.c_iflag |= ICRNL; 466 _cursesi_screen->cbreakt.c_oflag |= ONLCR; 467 _cursesi_screen->baset.c_iflag |= ICRNL; 468 _cursesi_screen->baset.c_oflag |= ONLCR; 469 470 _cursesi_screen->nl = 1; 471 _cursesi_screen->pfast = _cursesi_screen->rawmode; 472 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 473 _cursesi_screen->curt) ? ERR : OK; 474 } 475 476 int 477 nonl(void) 478 { 479 #ifdef DEBUG 480 __CTRACE(__CTRACE_MISC, "nonl()\n"); 481 #endif 482 /* Check if we need to restart ... */ 483 if (_cursesi_screen->endwin) 484 __restartwin(); 485 486 if (_cursesi_screen->notty == TRUE) 487 return OK; 488 _cursesi_screen->rawt.c_iflag &= ~ICRNL; 489 _cursesi_screen->rawt.c_oflag &= ~ONLCR; 490 _cursesi_screen->cbreakt.c_iflag &= ~ICRNL; 491 _cursesi_screen->cbreakt.c_oflag &= ~ONLCR; 492 _cursesi_screen->baset.c_iflag &= ~ICRNL; 493 _cursesi_screen->baset.c_oflag &= ~ONLCR; 494 495 _cursesi_screen->nl = 0; 496 __pfast = 1; 497 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 498 _cursesi_screen->curt) ? ERR : OK; 499 } 500 501 #ifndef _CURSES_USE_MACROS 502 void 503 noqiflush(void) 504 { 505 506 (void)intrflush(stdscr, FALSE); 507 } 508 509 void 510 qiflush(void) 511 { 512 513 (void)intrflush(stdscr, TRUE); 514 } 515 #endif /* _CURSES_USE_MACROS */ 516 517 /*ARGSUSED*/ 518 int 519 intrflush(WINDOW *win, bool bf) 520 { 521 /* Check if we need to restart ... */ 522 if (_cursesi_screen->endwin) 523 __restartwin(); 524 525 if (_cursesi_screen->notty == TRUE) 526 return OK; 527 if (bf) { 528 _cursesi_screen->rawt.c_lflag &= ~NOFLSH; 529 _cursesi_screen->cbreakt.c_lflag &= ~NOFLSH; 530 _cursesi_screen->baset.c_lflag &= ~NOFLSH; 531 } else { 532 _cursesi_screen->rawt.c_lflag |= NOFLSH; 533 _cursesi_screen->cbreakt.c_lflag |= NOFLSH; 534 _cursesi_screen->baset.c_lflag |= NOFLSH; 535 } 536 537 __pfast = 1; 538 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 539 _cursesi_screen->curt) ? ERR : OK; 540 } 541 542 void 543 __startwin(SCREEN *screen) 544 { 545 546 (void)fflush(screen->infd); 547 548 /* 549 * Some C libraries default to a 1K buffer when talking to a tty. 550 * With a larger screen, especially across a network, we'd like 551 * to get it to all flush in a single write. Make it twice as big 552 * as just the characters (so that we have room for cursor motions 553 * and attribute information) but no more than 8K. 554 */ 555 if (screen->stdbuf == NULL) { 556 screen->len = LINES * COLS * 2; 557 if (screen->len > 8192) 558 screen->len = 8192; 559 if ((screen->stdbuf = malloc(screen->len)) == NULL) 560 screen->len = 0; 561 } 562 (void)setvbuf(screen->outfd, screen->stdbuf, _IOFBF, screen->len); 563 564 ti_puts(screen->term, t_enter_ca_mode(screen->term), 0, 565 __cputchar_args, (void *) screen->outfd); 566 ti_puts(screen->term, t_cursor_normal(screen->term), 0, 567 __cputchar_args, (void *) screen->outfd); 568 if (screen->curscr->flags & __KEYPAD) 569 ti_puts(screen->term, t_keypad_xmit(screen->term), 0, 570 __cputchar_args, (void *) screen->outfd); 571 screen->endwin = 0; 572 } 573 574 int 575 endwin(void) 576 { 577 #ifdef DEBUG 578 __CTRACE(__CTRACE_MISC, "endwin\n"); 579 #endif 580 return __stopwin(); 581 } 582 583 bool 584 isendwin(void) 585 { 586 587 return _cursesi_screen->endwin ? TRUE : FALSE; 588 } 589 590 int 591 flushinp(void) 592 { 593 594 (void)fpurge(_cursesi_screen->infd); 595 return OK; 596 } 597 598 /* 599 * The following routines, savetty and resetty are completely useless and 600 * are left in only as stubs. If people actually use them they will almost 601 * certainly screw up the state of the world. 602 */ 603 /*static struct termios savedtty;*/ 604 int 605 savetty(void) 606 { 607 608 if (_cursesi_screen->notty == TRUE) 609 return OK; 610 return tcgetattr(fileno(_cursesi_screen->infd), 611 &_cursesi_screen->savedtty) ? ERR : OK; 612 } 613 614 int 615 resetty(void) 616 { 617 618 if (_cursesi_screen->notty == TRUE) 619 return OK; 620 return tcsetattr(fileno(_cursesi_screen->infd), TCSASOFT | TCSADRAIN, 621 &_cursesi_screen->savedtty) ? ERR : OK; 622 } 623 624 /* 625 * erasechar -- 626 * Return the character of the erase key. 627 */ 628 char 629 erasechar(void) 630 { 631 632 if (_cursesi_screen->notty == TRUE) 633 return 0; 634 return _cursesi_screen->baset.c_cc[VERASE]; 635 } 636 637 /* 638 * killchar -- 639 * Return the character of the kill key. 640 */ 641 char 642 killchar(void) 643 { 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 658 #ifndef HAVE_WCHAR 659 return ERR; 660 #else 661 if (_cursesi_screen->notty == TRUE) 662 return ERR; 663 *ch = _cursesi_screen->baset.c_cc[VERASE]; 664 return OK; 665 #endif /* HAVE_WCHAR */ 666 } 667 668 /* 669 * killwchar -- 670 * Return the wide character of the kill key. 671 */ 672 int 673 killwchar( wchar_t *ch ) 674 { 675 676 #ifndef HAVE_WCHAR 677 return ERR; 678 #else 679 if (_cursesi_screen->notty == TRUE) 680 return 0; 681 *ch = _cursesi_screen->baset.c_cc[VKILL]; 682 return OK; 683 #endif /* HAVE_WCHAR */ 684 } 685 686 int 687 typeahead(int filedes) 688 { 689 690 _cursesi_screen->checkfd = filedes; 691 return OK; 692 } 693