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