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