1/* $NetBSD: tty.c,v 1.42 2012/05/15 15:59:01 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Christos Zoulas of Cornell University. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include "config.h" 36#if !defined(lint) && !defined(SCCSID) 37#if 0 38static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/4/93"; 39#else 40__RCSID("$NetBSD: tty.c,v 1.42 2012/05/15 15:59:01 christos Exp $"); 41#endif 42#endif /* not lint && not SCCSID */ 43 44/* 45 * tty.c: tty interface stuff 46 */ 47#include <assert.h> 48#include <errno.h> 49#include <unistd.h> /* for isatty */ 50#include <strings.h> /* for ffs */ 51#include <sys/ioctl.h> 52#include "el.h" 53#include "tty.h" 54 55typedef struct ttymodes_t { 56 const char *m_name; 57 unsigned int m_value; 58 int m_type; 59} ttymodes_t; 60 61typedef struct ttymap_t { 62 Int nch, och; /* Internal and termio rep of chars */ 63 el_action_t bind[3]; /* emacs, vi, and vi-cmd */ 64} ttymap_t; 65 66 67private const ttyperm_t ttyperm = { 68 { 69 {"iflag:", ICRNL, (INLCR | IGNCR)}, 70 {"oflag:", (OPOST | ONLCR), ONLRET}, 71 {"cflag:", 0, 0}, 72 {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN), 73 (NOFLSH | ECHONL | EXTPROC | FLUSHO)}, 74 {"chars:", 0, 0}, 75 }, 76 { 77 {"iflag:", (INLCR | ICRNL), IGNCR}, 78 {"oflag:", (OPOST | ONLCR), ONLRET}, 79 {"cflag:", 0, 0}, 80 {"lflag:", ISIG, 81 (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)}, 82 {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) | 83 C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) | 84 C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0} 85 }, 86 { 87 {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL}, 88 {"oflag:", 0, 0}, 89 {"cflag:", 0, 0}, 90 {"lflag:", 0, ISIG | IEXTEN}, 91 {"chars:", 0, 0}, 92 } 93}; 94 95private const ttychar_t ttychar = { 96 { 97 CINTR, CQUIT, CERASE, CKILL, 98 CEOF, CEOL, CEOL2, CSWTCH, 99 CDSWTCH, CERASE2, CSTART, CSTOP, 100 CWERASE, CSUSP, CDSUSP, CREPRINT, 101 CDISCARD, CLNEXT, CSTATUS, CPAGE, 102 CPGOFF, CKILL2, CBRK, CMIN, 103 CTIME 104 }, 105 { 106 CINTR, CQUIT, CERASE, CKILL, 107 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 108 _POSIX_VDISABLE, CERASE2, CSTART, CSTOP, 109 _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE, 110 CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 111 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1, 112 0 113 }, 114 { 115 0, 0, 0, 0, 116 0, 0, 0, 0, 117 0, 0, 0, 0, 118 0, 0, 0, 0, 119 0, 0, 0, 0, 120 0, 0, 0, 0, 121 0 122 } 123}; 124 125private const ttymap_t tty_map[] = { 126#ifdef VERASE 127 {C_ERASE, VERASE, 128 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, 129#endif /* VERASE */ 130#ifdef VERASE2 131 {C_ERASE2, VERASE2, 132 {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}}, 133#endif /* VERASE2 */ 134#ifdef VKILL 135 {C_KILL, VKILL, 136 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, 137#endif /* VKILL */ 138#ifdef VKILL2 139 {C_KILL2, VKILL2, 140 {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}}, 141#endif /* VKILL2 */ 142#ifdef VEOF 143 {C_EOF, VEOF, 144 {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}}, 145#endif /* VEOF */ 146#ifdef VWERASE 147 {C_WERASE, VWERASE, 148 {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}}, 149#endif /* VWERASE */ 150#ifdef VREPRINT 151 {C_REPRINT, VREPRINT, 152 {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}}, 153#endif /* VREPRINT */ 154#ifdef VLNEXT 155 {C_LNEXT, VLNEXT, 156 {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}}, 157#endif /* VLNEXT */ 158 {(Int)-1, (Int)-1, 159 {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} 160}; 161 162private const ttymodes_t ttymodes[] = { 163#ifdef IGNBRK 164 {"ignbrk", IGNBRK, MD_INP}, 165#endif /* IGNBRK */ 166#ifdef BRKINT 167 {"brkint", BRKINT, MD_INP}, 168#endif /* BRKINT */ 169#ifdef IGNPAR 170 {"ignpar", IGNPAR, MD_INP}, 171#endif /* IGNPAR */ 172#ifdef PARMRK 173 {"parmrk", PARMRK, MD_INP}, 174#endif /* PARMRK */ 175#ifdef INPCK 176 {"inpck", INPCK, MD_INP}, 177#endif /* INPCK */ 178#ifdef ISTRIP 179 {"istrip", ISTRIP, MD_INP}, 180#endif /* ISTRIP */ 181#ifdef INLCR 182 {"inlcr", INLCR, MD_INP}, 183#endif /* INLCR */ 184#ifdef IGNCR 185 {"igncr", IGNCR, MD_INP}, 186#endif /* IGNCR */ 187#ifdef ICRNL 188 {"icrnl", ICRNL, MD_INP}, 189#endif /* ICRNL */ 190#ifdef IUCLC 191 {"iuclc", IUCLC, MD_INP}, 192#endif /* IUCLC */ 193#ifdef IXON 194 {"ixon", IXON, MD_INP}, 195#endif /* IXON */ 196#ifdef IXANY 197 {"ixany", IXANY, MD_INP}, 198#endif /* IXANY */ 199#ifdef IXOFF 200 {"ixoff", IXOFF, MD_INP}, 201#endif /* IXOFF */ 202#ifdef IMAXBEL 203 {"imaxbel", IMAXBEL, MD_INP}, 204#endif /* IMAXBEL */ 205 206#ifdef OPOST 207 {"opost", OPOST, MD_OUT}, 208#endif /* OPOST */ 209#ifdef OLCUC 210 {"olcuc", OLCUC, MD_OUT}, 211#endif /* OLCUC */ 212#ifdef ONLCR 213 {"onlcr", ONLCR, MD_OUT}, 214#endif /* ONLCR */ 215#ifdef OCRNL 216 {"ocrnl", OCRNL, MD_OUT}, 217#endif /* OCRNL */ 218#ifdef ONOCR 219 {"onocr", ONOCR, MD_OUT}, 220#endif /* ONOCR */ 221#ifdef ONOEOT 222 {"onoeot", ONOEOT, MD_OUT}, 223#endif /* ONOEOT */ 224#ifdef ONLRET 225 {"onlret", ONLRET, MD_OUT}, 226#endif /* ONLRET */ 227#ifdef OFILL 228 {"ofill", OFILL, MD_OUT}, 229#endif /* OFILL */ 230#ifdef OFDEL 231 {"ofdel", OFDEL, MD_OUT}, 232#endif /* OFDEL */ 233#ifdef NLDLY 234 {"nldly", NLDLY, MD_OUT}, 235#endif /* NLDLY */ 236#ifdef CRDLY 237 {"crdly", CRDLY, MD_OUT}, 238#endif /* CRDLY */ 239#ifdef TABDLY 240 {"tabdly", TABDLY, MD_OUT}, 241#endif /* TABDLY */ 242#ifdef XTABS 243 {"xtabs", XTABS, MD_OUT}, 244#endif /* XTABS */ 245#ifdef BSDLY 246 {"bsdly", BSDLY, MD_OUT}, 247#endif /* BSDLY */ 248#ifdef VTDLY 249 {"vtdly", VTDLY, MD_OUT}, 250#endif /* VTDLY */ 251#ifdef FFDLY 252 {"ffdly", FFDLY, MD_OUT}, 253#endif /* FFDLY */ 254#ifdef PAGEOUT 255 {"pageout", PAGEOUT, MD_OUT}, 256#endif /* PAGEOUT */ 257#ifdef WRAP 258 {"wrap", WRAP, MD_OUT}, 259#endif /* WRAP */ 260 261#ifdef CIGNORE 262 {"cignore", CIGNORE, MD_CTL}, 263#endif /* CBAUD */ 264#ifdef CBAUD 265 {"cbaud", CBAUD, MD_CTL}, 266#endif /* CBAUD */ 267#ifdef CSTOPB 268 {"cstopb", CSTOPB, MD_CTL}, 269#endif /* CSTOPB */ 270#ifdef CREAD 271 {"cread", CREAD, MD_CTL}, 272#endif /* CREAD */ 273#ifdef PARENB 274 {"parenb", PARENB, MD_CTL}, 275#endif /* PARENB */ 276#ifdef PARODD 277 {"parodd", PARODD, MD_CTL}, 278#endif /* PARODD */ 279#ifdef HUPCL 280 {"hupcl", HUPCL, MD_CTL}, 281#endif /* HUPCL */ 282#ifdef CLOCAL 283 {"clocal", CLOCAL, MD_CTL}, 284#endif /* CLOCAL */ 285#ifdef LOBLK 286 {"loblk", LOBLK, MD_CTL}, 287#endif /* LOBLK */ 288#ifdef CIBAUD 289 {"cibaud", CIBAUD, MD_CTL}, 290#endif /* CIBAUD */ 291#ifdef CRTSCTS 292#ifdef CCTS_OFLOW 293 {"ccts_oflow", CCTS_OFLOW, MD_CTL}, 294#else 295 {"crtscts", CRTSCTS, MD_CTL}, 296#endif /* CCTS_OFLOW */ 297#endif /* CRTSCTS */ 298#ifdef CRTS_IFLOW 299 {"crts_iflow", CRTS_IFLOW, MD_CTL}, 300#endif /* CRTS_IFLOW */ 301#ifdef CDTRCTS 302 {"cdtrcts", CDTRCTS, MD_CTL}, 303#endif /* CDTRCTS */ 304#ifdef MDMBUF 305 {"mdmbuf", MDMBUF, MD_CTL}, 306#endif /* MDMBUF */ 307#ifdef RCV1EN 308 {"rcv1en", RCV1EN, MD_CTL}, 309#endif /* RCV1EN */ 310#ifdef XMT1EN 311 {"xmt1en", XMT1EN, MD_CTL}, 312#endif /* XMT1EN */ 313 314#ifdef ISIG 315 {"isig", ISIG, MD_LIN}, 316#endif /* ISIG */ 317#ifdef ICANON 318 {"icanon", ICANON, MD_LIN}, 319#endif /* ICANON */ 320#ifdef XCASE 321 {"xcase", XCASE, MD_LIN}, 322#endif /* XCASE */ 323#ifdef ECHO 324 {"echo", ECHO, MD_LIN}, 325#endif /* ECHO */ 326#ifdef ECHOE 327 {"echoe", ECHOE, MD_LIN}, 328#endif /* ECHOE */ 329#ifdef ECHOK 330 {"echok", ECHOK, MD_LIN}, 331#endif /* ECHOK */ 332#ifdef ECHONL 333 {"echonl", ECHONL, MD_LIN}, 334#endif /* ECHONL */ 335#ifdef NOFLSH 336 {"noflsh", NOFLSH, MD_LIN}, 337#endif /* NOFLSH */ 338#ifdef TOSTOP 339 {"tostop", TOSTOP, MD_LIN}, 340#endif /* TOSTOP */ 341#ifdef ECHOCTL 342 {"echoctl", ECHOCTL, MD_LIN}, 343#endif /* ECHOCTL */ 344#ifdef ECHOPRT 345 {"echoprt", ECHOPRT, MD_LIN}, 346#endif /* ECHOPRT */ 347#ifdef ECHOKE 348 {"echoke", ECHOKE, MD_LIN}, 349#endif /* ECHOKE */ 350#ifdef DEFECHO 351 {"defecho", DEFECHO, MD_LIN}, 352#endif /* DEFECHO */ 353#ifdef FLUSHO 354 {"flusho", FLUSHO, MD_LIN}, 355#endif /* FLUSHO */ 356#ifdef PENDIN 357 {"pendin", PENDIN, MD_LIN}, 358#endif /* PENDIN */ 359#ifdef IEXTEN 360 {"iexten", IEXTEN, MD_LIN}, 361#endif /* IEXTEN */ 362#ifdef NOKERNINFO 363 {"nokerninfo", NOKERNINFO, MD_LIN}, 364#endif /* NOKERNINFO */ 365#ifdef ALTWERASE 366 {"altwerase", ALTWERASE, MD_LIN}, 367#endif /* ALTWERASE */ 368#ifdef EXTPROC 369 {"extproc", EXTPROC, MD_LIN}, 370#endif /* EXTPROC */ 371 372#if defined(VINTR) 373 {"intr", C_SH(C_INTR), MD_CHAR}, 374#endif /* VINTR */ 375#if defined(VQUIT) 376 {"quit", C_SH(C_QUIT), MD_CHAR}, 377#endif /* VQUIT */ 378#if defined(VERASE) 379 {"erase", C_SH(C_ERASE), MD_CHAR}, 380#endif /* VERASE */ 381#if defined(VKILL) 382 {"kill", C_SH(C_KILL), MD_CHAR}, 383#endif /* VKILL */ 384#if defined(VEOF) 385 {"eof", C_SH(C_EOF), MD_CHAR}, 386#endif /* VEOF */ 387#if defined(VEOL) 388 {"eol", C_SH(C_EOL), MD_CHAR}, 389#endif /* VEOL */ 390#if defined(VEOL2) 391 {"eol2", C_SH(C_EOL2), MD_CHAR}, 392#endif /* VEOL2 */ 393#if defined(VSWTCH) 394 {"swtch", C_SH(C_SWTCH), MD_CHAR}, 395#endif /* VSWTCH */ 396#if defined(VDSWTCH) 397 {"dswtch", C_SH(C_DSWTCH), MD_CHAR}, 398#endif /* VDSWTCH */ 399#if defined(VERASE2) 400 {"erase2", C_SH(C_ERASE2), MD_CHAR}, 401#endif /* VERASE2 */ 402#if defined(VSTART) 403 {"start", C_SH(C_START), MD_CHAR}, 404#endif /* VSTART */ 405#if defined(VSTOP) 406 {"stop", C_SH(C_STOP), MD_CHAR}, 407#endif /* VSTOP */ 408#if defined(VWERASE) 409 {"werase", C_SH(C_WERASE), MD_CHAR}, 410#endif /* VWERASE */ 411#if defined(VSUSP) 412 {"susp", C_SH(C_SUSP), MD_CHAR}, 413#endif /* VSUSP */ 414#if defined(VDSUSP) 415 {"dsusp", C_SH(C_DSUSP), MD_CHAR}, 416#endif /* VDSUSP */ 417#if defined(VREPRINT) 418 {"reprint", C_SH(C_REPRINT), MD_CHAR}, 419#endif /* VREPRINT */ 420#if defined(VDISCARD) 421 {"discard", C_SH(C_DISCARD), MD_CHAR}, 422#endif /* VDISCARD */ 423#if defined(VLNEXT) 424 {"lnext", C_SH(C_LNEXT), MD_CHAR}, 425#endif /* VLNEXT */ 426#if defined(VSTATUS) 427 {"status", C_SH(C_STATUS), MD_CHAR}, 428#endif /* VSTATUS */ 429#if defined(VPAGE) 430 {"page", C_SH(C_PAGE), MD_CHAR}, 431#endif /* VPAGE */ 432#if defined(VPGOFF) 433 {"pgoff", C_SH(C_PGOFF), MD_CHAR}, 434#endif /* VPGOFF */ 435#if defined(VKILL2) 436 {"kill2", C_SH(C_KILL2), MD_CHAR}, 437#endif /* VKILL2 */ 438#if defined(VBRK) 439 {"brk", C_SH(C_BRK), MD_CHAR}, 440#endif /* VBRK */ 441#if defined(VMIN) 442 {"min", C_SH(C_MIN), MD_CHAR}, 443#endif /* VMIN */ 444#if defined(VTIME) 445 {"time", C_SH(C_TIME), MD_CHAR}, 446#endif /* VTIME */ 447 {NULL, 0, -1}, 448}; 449 450 451 452#define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1) 453#define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8) 454#define tty__cooked_mode(td) ((td)->c_lflag & ICANON) 455 456private int tty_getty(EditLine *, struct termios *); 457private int tty_setty(EditLine *, int, const struct termios *); 458private int tty__getcharindex(int); 459private void tty__getchar(struct termios *, unsigned char *); 460private void tty__setchar(struct termios *, unsigned char *); 461private speed_t tty__getspeed(struct termios *); 462private int tty_setup(EditLine *); 463 464#define t_qu t_ts 465 466/* tty_getty(): 467 * Wrapper for tcgetattr to handle EINTR 468 */ 469private int 470tty_getty(EditLine *el, struct termios *t) 471{ 472 int rv; 473 while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR) 474 continue; 475 return rv; 476} 477 478/* tty_setty(): 479 * Wrapper for tcsetattr to handle EINTR 480 */ 481private int 482tty_setty(EditLine *el, int action, const struct termios *t) 483{ 484 int rv; 485 while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR) 486 continue; 487 return rv; 488} 489 490/* tty_setup(): 491 * Get the tty parameters and initialize the editing state 492 */ 493private int 494tty_setup(EditLine *el) 495{ 496 int rst = 1; 497 int pgrp; 498 499 if (el->el_flags & EDIT_DISABLED) 500 return 0; 501 502 /* 503 * Return -1 (which will cause the NO_TTY flag to be set) if 504 * the output file descriptor isn't a tty (eg, a pipe), or if it 505 * is the controlling tty and it's process group doesn't match the 506 * process's process group (meaning the process is in the background). 507 * Note: we replicate the action of tcgetpgrp(), because we need 508 * to distinguish between when the file descriptor isn't a tty, 509 * and when that tty isn't the controlling tty. So we call isatty() 510 * to detect the first case, then call ioctl() to get the process 511 * group. If it returns ENOTTY, then the tty isn't the controlling 512 * tty, but we go ahead and allow setting the tty, because no SIGTTOU 513 * will be generated. 514 */ 515 if (!isatty(el->el_outfd)) { 516#ifdef DEBUG_TTY 517 (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__, 518 strerror(errno)); 519#endif /* DEBUG_TTY */ 520 return -1; 521 } 522 if (ioctl(el->el_outfd, TIOCGPGRP, &pgrp) < 0) { 523#ifdef DEBUG_TTY 524 (void) fprintf(el->el_errfile, 525 "%s: ioctl: %s\n", __func__, strerror(errno)); 526#endif /* DEBUG_TTY */ 527 if(errno != ENOTTY) return (-1); 528 else pgrp = -1; 529 } 530 if (pgrp >= 0 && getpgrp() != pgrp) { 531#ifdef DEBUG_TTY 532 (void) fprintf(el->el_errfile, 533 "%s: getpgrp(%d) != pgrp(%d)\n", __func__, 534 (int)getpgrp(), (int)pgrp); 535#endif /* DEBUG_TTY */ 536 return (-1); 537 } 538 539 if (tty_getty(el, &el->el_tty.t_or) == -1) { 540#ifdef DEBUG_TTY 541 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, 542 strerror(errno)); 543#endif /* DEBUG_TTY */ 544 return -1; 545 } 546 el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or; 547 548 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex); 549 el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex); 550 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex); 551 552 el->el_tty.t_ex.c_iflag &= ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask; 553 el->el_tty.t_ex.c_iflag |= el->el_tty.t_t[EX_IO][MD_INP].t_setmask; 554 555 el->el_tty.t_ex.c_oflag &= ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; 556 el->el_tty.t_ex.c_oflag |= el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; 557 558 el->el_tty.t_ex.c_cflag &= ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; 559 el->el_tty.t_ex.c_cflag |= el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; 560 561 el->el_tty.t_ex.c_lflag &= ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; 562 el->el_tty.t_ex.c_lflag |= el->el_tty.t_t[EX_IO][MD_LIN].t_setmask; 563 564 /* 565 * Reset the tty chars to reasonable defaults 566 * If they are disabled, then enable them. 567 */ 568 if (rst) { 569 if (tty__cooked_mode(&el->el_tty.t_ts)) { 570 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); 571 /* 572 * Don't affect CMIN and CTIME for the editor mode 573 */ 574 for (rst = 0; rst < C_NCC - 2; rst++) 575 if (el->el_tty.t_c[TS_IO][rst] != 576 el->el_tty.t_vdisable 577 && el->el_tty.t_c[ED_IO][rst] != 578 el->el_tty.t_vdisable) 579 el->el_tty.t_c[ED_IO][rst] = 580 el->el_tty.t_c[TS_IO][rst]; 581 for (rst = 0; rst < C_NCC; rst++) 582 if (el->el_tty.t_c[TS_IO][rst] != 583 el->el_tty.t_vdisable) 584 el->el_tty.t_c[EX_IO][rst] = 585 el->el_tty.t_c[TS_IO][rst]; 586 } 587 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); 588 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { 589#ifdef DEBUG_TTY 590 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", 591 __func__, strerror(errno)); 592#endif /* DEBUG_TTY */ 593 return -1; 594 } 595 } 596 597 el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; 598 el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask; 599 600 el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; 601 el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; 602 603 el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; 604 el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; 605 606 el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; 607 el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; 608 609 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); 610 tty_bind_char(el, 1); 611 return 0; 612} 613 614protected int 615tty_init(EditLine *el) 616{ 617 618 el->el_tty.t_mode = EX_IO; 619 el->el_tty.t_vdisable = _POSIX_VDISABLE; 620 (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); 621 (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); 622 return tty_setup(el); 623} 624 625 626/* tty_end(): 627 * Restore the tty to its original settings 628 */ 629protected void 630/*ARGSUSED*/ 631tty_end(EditLine *el) 632{ 633 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 634 return; 635 636 if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) { 637#ifdef DEBUG_TTY 638 (void) fprintf(el->el_errfile, 639 "%s: tty_setty: %s\n", __func__, strerror(errno)); 640#endif /* DEBUG_TTY */ 641 } 642} 643 644 645/* tty__getspeed(): 646 * Get the tty speed 647 */ 648private speed_t 649tty__getspeed(struct termios *td) 650{ 651 speed_t spd; 652 653 if ((spd = cfgetispeed(td)) == 0) 654 spd = cfgetospeed(td); 655 return spd; 656} 657 658/* tty__getspeed(): 659 * Return the index of the asked char in the c_cc array 660 */ 661private int 662tty__getcharindex(int i) 663{ 664 switch (i) { 665#ifdef VINTR 666 case C_INTR: 667 return VINTR; 668#endif /* VINTR */ 669#ifdef VQUIT 670 case C_QUIT: 671 return VQUIT; 672#endif /* VQUIT */ 673#ifdef VERASE 674 case C_ERASE: 675 return VERASE; 676#endif /* VERASE */ 677#ifdef VKILL 678 case C_KILL: 679 return VKILL; 680#endif /* VKILL */ 681#ifdef VEOF 682 case C_EOF: 683 return VEOF; 684#endif /* VEOF */ 685#ifdef VEOL 686 case C_EOL: 687 return VEOL; 688#endif /* VEOL */ 689#ifdef VEOL2 690 case C_EOL2: 691 return VEOL2; 692#endif /* VEOL2 */ 693#ifdef VSWTCH 694 case C_SWTCH: 695 return VSWTCH; 696#endif /* VSWTCH */ 697#ifdef VDSWTCH 698 case C_DSWTCH: 699 return VDSWTCH; 700#endif /* VDSWTCH */ 701#ifdef VERASE2 702 case C_ERASE2: 703 return VERASE2; 704#endif /* VERASE2 */ 705#ifdef VSTART 706 case C_START: 707 return VSTART; 708#endif /* VSTART */ 709#ifdef VSTOP 710 case C_STOP: 711 return VSTOP; 712#endif /* VSTOP */ 713#ifdef VWERASE 714 case C_WERASE: 715 return VWERASE; 716#endif /* VWERASE */ 717#ifdef VSUSP 718 case C_SUSP: 719 return VSUSP; 720#endif /* VSUSP */ 721#ifdef VDSUSP 722 case C_DSUSP: 723 return VDSUSP; 724#endif /* VDSUSP */ 725#ifdef VREPRINT 726 case C_REPRINT: 727 return VREPRINT; 728#endif /* VREPRINT */ 729#ifdef VDISCARD 730 case C_DISCARD: 731 return VDISCARD; 732#endif /* VDISCARD */ 733#ifdef VLNEXT 734 case C_LNEXT: 735 return VLNEXT; 736#endif /* VLNEXT */ 737#ifdef VSTATUS 738 case C_STATUS: 739 return VSTATUS; 740#endif /* VSTATUS */ 741#ifdef VPAGE 742 case C_PAGE: 743 return VPAGE; 744#endif /* VPAGE */ 745#ifdef VPGOFF 746 case C_PGOFF: 747 return VPGOFF; 748#endif /* VPGOFF */ 749#ifdef VKILL2 750 case C_KILL2: 751 return VKILL2; 752#endif /* KILL2 */ 753#ifdef VMIN 754 case C_MIN: 755 return VMIN; 756#endif /* VMIN */ 757#ifdef VTIME 758 case C_TIME: 759 return VTIME; 760#endif /* VTIME */ 761 default: 762 return -1; 763 } 764} 765 766/* tty__getchar(): 767 * Get the tty characters 768 */ 769private void 770tty__getchar(struct termios *td, unsigned char *s) 771{ 772 773#ifdef VINTR 774 s[C_INTR] = td->c_cc[VINTR]; 775#endif /* VINTR */ 776#ifdef VQUIT 777 s[C_QUIT] = td->c_cc[VQUIT]; 778#endif /* VQUIT */ 779#ifdef VERASE 780 s[C_ERASE] = td->c_cc[VERASE]; 781#endif /* VERASE */ 782#ifdef VKILL 783 s[C_KILL] = td->c_cc[VKILL]; 784#endif /* VKILL */ 785#ifdef VEOF 786 s[C_EOF] = td->c_cc[VEOF]; 787#endif /* VEOF */ 788#ifdef VEOL 789 s[C_EOL] = td->c_cc[VEOL]; 790#endif /* VEOL */ 791#ifdef VEOL2 792 s[C_EOL2] = td->c_cc[VEOL2]; 793#endif /* VEOL2 */ 794#ifdef VSWTCH 795 s[C_SWTCH] = td->c_cc[VSWTCH]; 796#endif /* VSWTCH */ 797#ifdef VDSWTCH 798 s[C_DSWTCH] = td->c_cc[VDSWTCH]; 799#endif /* VDSWTCH */ 800#ifdef VERASE2 801 s[C_ERASE2] = td->c_cc[VERASE2]; 802#endif /* VERASE2 */ 803#ifdef VSTART 804 s[C_START] = td->c_cc[VSTART]; 805#endif /* VSTART */ 806#ifdef VSTOP 807 s[C_STOP] = td->c_cc[VSTOP]; 808#endif /* VSTOP */ 809#ifdef VWERASE 810 s[C_WERASE] = td->c_cc[VWERASE]; 811#endif /* VWERASE */ 812#ifdef VSUSP 813 s[C_SUSP] = td->c_cc[VSUSP]; 814#endif /* VSUSP */ 815#ifdef VDSUSP 816 s[C_DSUSP] = td->c_cc[VDSUSP]; 817#endif /* VDSUSP */ 818#ifdef VREPRINT 819 s[C_REPRINT] = td->c_cc[VREPRINT]; 820#endif /* VREPRINT */ 821#ifdef VDISCARD 822 s[C_DISCARD] = td->c_cc[VDISCARD]; 823#endif /* VDISCARD */ 824#ifdef VLNEXT 825 s[C_LNEXT] = td->c_cc[VLNEXT]; 826#endif /* VLNEXT */ 827#ifdef VSTATUS 828 s[C_STATUS] = td->c_cc[VSTATUS]; 829#endif /* VSTATUS */ 830#ifdef VPAGE 831 s[C_PAGE] = td->c_cc[VPAGE]; 832#endif /* VPAGE */ 833#ifdef VPGOFF 834 s[C_PGOFF] = td->c_cc[VPGOFF]; 835#endif /* VPGOFF */ 836#ifdef VKILL2 837 s[C_KILL2] = td->c_cc[VKILL2]; 838#endif /* KILL2 */ 839#ifdef VMIN 840 s[C_MIN] = td->c_cc[VMIN]; 841#endif /* VMIN */ 842#ifdef VTIME 843 s[C_TIME] = td->c_cc[VTIME]; 844#endif /* VTIME */ 845} /* tty__getchar */ 846 847 848/* tty__setchar(): 849 * Set the tty characters 850 */ 851private void 852tty__setchar(struct termios *td, unsigned char *s) 853{ 854 855#ifdef VINTR 856 td->c_cc[VINTR] = s[C_INTR]; 857#endif /* VINTR */ 858#ifdef VQUIT 859 td->c_cc[VQUIT] = s[C_QUIT]; 860#endif /* VQUIT */ 861#ifdef VERASE 862 td->c_cc[VERASE] = s[C_ERASE]; 863#endif /* VERASE */ 864#ifdef VKILL 865 td->c_cc[VKILL] = s[C_KILL]; 866#endif /* VKILL */ 867#ifdef VEOF 868 td->c_cc[VEOF] = s[C_EOF]; 869#endif /* VEOF */ 870#ifdef VEOL 871 td->c_cc[VEOL] = s[C_EOL]; 872#endif /* VEOL */ 873#ifdef VEOL2 874 td->c_cc[VEOL2] = s[C_EOL2]; 875#endif /* VEOL2 */ 876#ifdef VSWTCH 877 td->c_cc[VSWTCH] = s[C_SWTCH]; 878#endif /* VSWTCH */ 879#ifdef VDSWTCH 880 td->c_cc[VDSWTCH] = s[C_DSWTCH]; 881#endif /* VDSWTCH */ 882#ifdef VERASE2 883 td->c_cc[VERASE2] = s[C_ERASE2]; 884#endif /* VERASE2 */ 885#ifdef VSTART 886 td->c_cc[VSTART] = s[C_START]; 887#endif /* VSTART */ 888#ifdef VSTOP 889 td->c_cc[VSTOP] = s[C_STOP]; 890#endif /* VSTOP */ 891#ifdef VWERASE 892 td->c_cc[VWERASE] = s[C_WERASE]; 893#endif /* VWERASE */ 894#ifdef VSUSP 895 td->c_cc[VSUSP] = s[C_SUSP]; 896#endif /* VSUSP */ 897#ifdef VDSUSP 898 td->c_cc[VDSUSP] = s[C_DSUSP]; 899#endif /* VDSUSP */ 900#ifdef VREPRINT 901 td->c_cc[VREPRINT] = s[C_REPRINT]; 902#endif /* VREPRINT */ 903#ifdef VDISCARD 904 td->c_cc[VDISCARD] = s[C_DISCARD]; 905#endif /* VDISCARD */ 906#ifdef VLNEXT 907 td->c_cc[VLNEXT] = s[C_LNEXT]; 908#endif /* VLNEXT */ 909#ifdef VSTATUS 910 td->c_cc[VSTATUS] = s[C_STATUS]; 911#endif /* VSTATUS */ 912#ifdef VPAGE 913 td->c_cc[VPAGE] = s[C_PAGE]; 914#endif /* VPAGE */ 915#ifdef VPGOFF 916 td->c_cc[VPGOFF] = s[C_PGOFF]; 917#endif /* VPGOFF */ 918#ifdef VKILL2 919 td->c_cc[VKILL2] = s[C_KILL2]; 920#endif /* VKILL2 */ 921#ifdef VMIN 922 td->c_cc[VMIN] = s[C_MIN]; 923#endif /* VMIN */ 924#ifdef VTIME 925 td->c_cc[VTIME] = s[C_TIME]; 926#endif /* VTIME */ 927} /* tty__setchar */ 928 929 930/* tty_bind_char(): 931 * Rebind the editline functions 932 */ 933protected void 934tty_bind_char(EditLine *el, int force) 935{ 936 937 unsigned char *t_n = el->el_tty.t_c[ED_IO]; 938 unsigned char *t_o = el->el_tty.t_ed.c_cc; 939 Char new[2], old[2]; 940 const ttymap_t *tp; 941 el_action_t *map, *alt; 942 const el_action_t *dmap, *dalt; 943 new[1] = old[1] = '\0'; 944 945 map = el->el_map.key; 946 alt = el->el_map.alt; 947 if (el->el_map.type == MAP_VI) { 948 dmap = el->el_map.vii; 949 dalt = el->el_map.vic; 950 } else { 951 dmap = el->el_map.emacs; 952 dalt = NULL; 953 } 954 955 for (tp = tty_map; tp->nch != (Int)-1; tp++) { 956 new[0] = t_n[tp->nch]; 957 old[0] = t_o[tp->och]; 958 if (new[0] == old[0] && !force) 959 continue; 960 /* Put the old default binding back, and set the new binding */ 961 keymacro_clear(el, map, old); 962 map[UC(old[0])] = dmap[UC(old[0])]; 963 keymacro_clear(el, map, new); 964 /* MAP_VI == 1, MAP_EMACS == 0... */ 965 map[UC(new[0])] = tp->bind[el->el_map.type]; 966 if (dalt) { 967 keymacro_clear(el, alt, old); 968 alt[UC(old[0])] = dalt[UC(old[0])]; 969 keymacro_clear(el, alt, new); 970 alt[UC(new[0])] = tp->bind[el->el_map.type + 1]; 971 } 972 } 973} 974 975 976/* tty_rawmode(): 977 * Set terminal into 1 character at a time mode. 978 */ 979protected int 980tty_rawmode(EditLine *el) 981{ 982 983 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) 984 return 0; 985 986 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 987 return 0; 988 989 if (tty_getty(el, &el->el_tty.t_ts) == -1) { 990#ifdef DEBUG_TTY 991 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, 992 strerror(errno)); 993#endif /* DEBUG_TTY */ 994 return -1; 995 } 996 /* 997 * We always keep up with the eight bit setting and the speed of the 998 * tty. But we only believe changes that are made to cooked mode! 999 */ 1000 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); 1001 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); 1002 1003 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || 1004 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { 1005 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); 1006 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); 1007 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); 1008 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); 1009 } 1010 if (tty__cooked_mode(&el->el_tty.t_ts)) { 1011 if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) { 1012 el->el_tty.t_ex.c_cflag = 1013 el->el_tty.t_ts.c_cflag; 1014 el->el_tty.t_ex.c_cflag &= 1015 ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; 1016 el->el_tty.t_ex.c_cflag |= 1017 el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; 1018 1019 el->el_tty.t_ed.c_cflag = 1020 el->el_tty.t_ts.c_cflag; 1021 el->el_tty.t_ed.c_cflag &= 1022 ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; 1023 el->el_tty.t_ed.c_cflag |= 1024 el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; 1025 } 1026 if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) && 1027 (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) { 1028 el->el_tty.t_ex.c_lflag = 1029 el->el_tty.t_ts.c_lflag; 1030 el->el_tty.t_ex.c_lflag &= 1031 ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; 1032 el->el_tty.t_ex.c_lflag |= 1033 el->el_tty.t_t[EX_IO][MD_LIN].t_setmask; 1034 1035 el->el_tty.t_ed.c_lflag = 1036 el->el_tty.t_ts.c_lflag; 1037 el->el_tty.t_ed.c_lflag &= 1038 ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; 1039 el->el_tty.t_ed.c_lflag |= 1040 el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; 1041 } 1042 if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) && 1043 (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) { 1044 el->el_tty.t_ex.c_iflag = 1045 el->el_tty.t_ts.c_iflag; 1046 el->el_tty.t_ex.c_iflag &= 1047 ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask; 1048 el->el_tty.t_ex.c_iflag |= 1049 el->el_tty.t_t[EX_IO][MD_INP].t_setmask; 1050 1051 el->el_tty.t_ed.c_iflag = 1052 el->el_tty.t_ts.c_iflag; 1053 el->el_tty.t_ed.c_iflag &= 1054 ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; 1055 el->el_tty.t_ed.c_iflag |= 1056 el->el_tty.t_t[ED_IO][MD_INP].t_setmask; 1057 } 1058 if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) && 1059 (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) { 1060 el->el_tty.t_ex.c_oflag = 1061 el->el_tty.t_ts.c_oflag; 1062 el->el_tty.t_ex.c_oflag &= 1063 ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; 1064 el->el_tty.t_ex.c_oflag |= 1065 el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; 1066 1067 el->el_tty.t_ed.c_oflag = 1068 el->el_tty.t_ts.c_oflag; 1069 el->el_tty.t_ed.c_oflag &= 1070 ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; 1071 el->el_tty.t_ed.c_oflag |= 1072 el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; 1073 } 1074 if (tty__gettabs(&el->el_tty.t_ex) == 0) 1075 el->el_tty.t_tabs = 0; 1076 else 1077 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; 1078 1079 { 1080 int i; 1081 1082 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); 1083 /* 1084 * Check if the user made any changes. 1085 * If he did, then propagate the changes to the 1086 * edit and execute data structures. 1087 */ 1088 for (i = 0; i < C_NCC; i++) 1089 if (el->el_tty.t_c[TS_IO][i] != 1090 el->el_tty.t_c[EX_IO][i]) 1091 break; 1092 1093 if (i != C_NCC) { 1094 /* 1095 * Propagate changes only to the unprotected 1096 * chars that have been modified just now. 1097 */ 1098 for (i = 0; i < C_NCC; i++) { 1099 if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i))) 1100 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) 1101 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i]; 1102 if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i)) 1103 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable; 1104 } 1105 tty_bind_char(el, 0); 1106 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); 1107 1108 for (i = 0; i < C_NCC; i++) { 1109 if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i))) 1110 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) 1111 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i]; 1112 if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i)) 1113 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable; 1114 } 1115 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); 1116 } 1117 } 1118 } 1119 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1120#ifdef DEBUG_TTY 1121 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1122 strerror(errno)); 1123#endif /* DEBUG_TTY */ 1124 return -1; 1125 } 1126 el->el_tty.t_mode = ED_IO; 1127 return 0; 1128} 1129 1130 1131/* tty_cookedmode(): 1132 * Set the tty back to normal mode 1133 */ 1134protected int 1135tty_cookedmode(EditLine *el) 1136{ /* set tty in normal setup */ 1137 1138 if (el->el_tty.t_mode == EX_IO) 1139 return 0; 1140 1141 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 1142 return 0; 1143 1144 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { 1145#ifdef DEBUG_TTY 1146 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1147 strerror(errno)); 1148#endif /* DEBUG_TTY */ 1149 return -1; 1150 } 1151 el->el_tty.t_mode = EX_IO; 1152 return 0; 1153} 1154 1155 1156/* tty_quotemode(): 1157 * Turn on quote mode 1158 */ 1159protected int 1160tty_quotemode(EditLine *el) 1161{ 1162 if (el->el_tty.t_mode == QU_IO) 1163 return 0; 1164 1165 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 1166 return 0; 1167 1168 el->el_tty.t_qu = el->el_tty.t_ed; 1169 1170 el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask; 1171 el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask; 1172 1173 el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask; 1174 el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask; 1175 1176 el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask; 1177 el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask; 1178 1179 el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask; 1180 el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask; 1181 1182 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) { 1183#ifdef DEBUG_TTY 1184 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1185 strerror(errno)); 1186#endif /* DEBUG_TTY */ 1187 return -1; 1188 } 1189 el->el_tty.t_mode = QU_IO; 1190 return 0; 1191} 1192 1193 1194/* tty_noquotemode(): 1195 * Turn off quote mode 1196 */ 1197protected int 1198tty_noquotemode(EditLine *el) 1199{ 1200 1201 if (el->el_tty.t_mode != QU_IO) 1202 return 0; 1203 1204 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 1205 return 0; 1206 1207 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1208#ifdef DEBUG_TTY 1209 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1210 strerror(errno)); 1211#endif /* DEBUG_TTY */ 1212 return -1; 1213 } 1214 el->el_tty.t_mode = ED_IO; 1215 return 0; 1216} 1217 1218 1219/* tty_stty(): 1220 * Stty builtin 1221 */ 1222protected int 1223/*ARGSUSED*/ 1224tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) 1225{ 1226 const ttymodes_t *m; 1227 char x; 1228 int aflag = 0; 1229 const Char *s, *d; 1230 char name[EL_BUFSIZ]; 1231 struct termios *tios = &el->el_tty.t_ex; 1232 int z = EX_IO; 1233 1234 if (el->el_flags & (EDIT_DISABLED|NO_TTY)) 1235 return 0; 1236 1237 if (argv == NULL) 1238 return -1; 1239 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); 1240 name[sizeof(name) - 1] = '\0'; 1241 1242 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') 1243 switch (argv[0][1]) { 1244 case 'a': 1245 aflag++; 1246 argv++; 1247 break; 1248 case 'd': 1249 argv++; 1250 tios = &el->el_tty.t_ed; 1251 z = ED_IO; 1252 break; 1253 case 'x': 1254 argv++; 1255 tios = &el->el_tty.t_ex; 1256 z = EX_IO; 1257 break; 1258 case 'q': 1259 argv++; 1260 tios = &el->el_tty.t_ts; 1261 z = QU_IO; 1262 break; 1263 default: 1264 (void) fprintf(el->el_errfile, 1265 "%s: Unknown switch `%c'.\n", 1266 name, argv[0][1]); 1267 return -1; 1268 } 1269 1270 if (!argv || !*argv) { 1271 int i = -1; 1272 size_t len = 0, st = 0, cu; 1273 for (m = ttymodes; m->m_name; m++) { 1274 if (m->m_type != i) { 1275 (void) fprintf(el->el_outfile, "%s%s", 1276 i != -1 ? "\n" : "", 1277 el->el_tty.t_t[z][m->m_type].t_name); 1278 i = m->m_type; 1279 st = len = 1280 strlen(el->el_tty.t_t[z][m->m_type].t_name); 1281 } 1282 if (i != -1) { 1283 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) 1284 ? '+' : '\0'; 1285 1286 if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) 1287 x = '-'; 1288 } else { 1289 x = '\0'; 1290 } 1291 1292 if (x != '\0' || aflag) { 1293 1294 cu = strlen(m->m_name) + (x != '\0') + 1; 1295 1296 if (len + cu >= 1297 (size_t)el->el_terminal.t_size.h) { 1298 (void) fprintf(el->el_outfile, "\n%*s", 1299 (int)st, ""); 1300 len = st + cu; 1301 } else 1302 len += cu; 1303 1304 if (x != '\0') 1305 (void) fprintf(el->el_outfile, "%c%s ", 1306 x, m->m_name); 1307 else 1308 (void) fprintf(el->el_outfile, "%s ", 1309 m->m_name); 1310 } 1311 } 1312 (void) fprintf(el->el_outfile, "\n"); 1313 return 0; 1314 } 1315 while (argv && (s = *argv++)) { 1316 const Char *p; 1317 switch (*s) { 1318 case '+': 1319 case '-': 1320 x = (char)*s++; 1321 break; 1322 default: 1323 x = '\0'; 1324 break; 1325 } 1326 d = s; 1327 p = Strchr(s, '='); 1328 for (m = ttymodes; m->m_name; m++) 1329 if ((p ? strncmp(m->m_name, ct_encode_string(d, 1330 &el->el_scratch), (size_t)(p - d)) : 1331 strcmp(m->m_name, ct_encode_string(d, 1332 &el->el_scratch))) == 0 && 1333 (p == NULL || m->m_type == MD_CHAR)) 1334 break; 1335 1336 if (!m->m_name) { 1337 (void) fprintf(el->el_errfile, 1338 "%s: Invalid argument `" FSTR "'.\n", name, d); 1339 return -1; 1340 } 1341 if (p) { 1342 int c = ffs((int)m->m_value); 1343 int v = *++p ? parse__escape(&p) : 1344 el->el_tty.t_vdisable; 1345 assert(c != 0); 1346 c--; 1347 c = tty__getcharindex(c); 1348 assert(c != -1); 1349 tios->c_cc[c] = (cc_t)v; 1350 continue; 1351 } 1352 switch (x) { 1353 case '+': 1354 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; 1355 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1356 break; 1357 case '-': 1358 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; 1359 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; 1360 break; 1361 default: 1362 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; 1363 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1364 break; 1365 } 1366 } 1367 1368 if (el->el_tty.t_mode == z) { 1369 if (tty_setty(el, TCSADRAIN, tios) == -1) { 1370#ifdef DEBUG_TTY 1371 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", 1372 __func__, strerror(errno)); 1373#endif /* DEBUG_TTY */ 1374 return -1; 1375 } 1376 } 1377 1378 return 0; 1379} 1380 1381 1382#ifdef notyet 1383/* tty_printchar(): 1384 * DEbugging routine to print the tty characters 1385 */ 1386private void 1387tty_printchar(EditLine *el, unsigned char *s) 1388{ 1389 ttyperm_t *m; 1390 int i; 1391 1392 for (i = 0; i < C_NCC; i++) { 1393 for (m = el->el_tty.t_t; m->m_name; m++) 1394 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) 1395 break; 1396 if (m->m_name) 1397 (void) fprintf(el->el_errfile, "%s ^%c ", 1398 m->m_name, s[i] + 'A' - 1); 1399 if (i % 5 == 0) 1400 (void) fprintf(el->el_errfile, "\n"); 1401 } 1402 (void) fprintf(el->el_errfile, "\n"); 1403} 1404#endif /* notyet */ 1405