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 38 static 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 "el.h" 52 #include "tty.h" 53 54 typedef struct ttymodes_t { 55 const char *m_name; 56 unsigned int m_value; 57 int m_type; 58 } ttymodes_t; 59 60 typedef 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 66 private 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 94 private 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 124 private 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 {(Int)-1, (Int)-1, 158 {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}} 159 }; 160 161 private 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 455 private int tty_getty(EditLine *, struct termios *); 456 private int tty_setty(EditLine *, int, const struct termios *); 457 private int tty__getcharindex(int); 458 private void tty__getchar(struct termios *, unsigned char *); 459 private void tty__setchar(struct termios *, unsigned char *); 460 private speed_t tty__getspeed(struct termios *); 461 private int tty_setup(EditLine *); 462 463 #define t_qu t_ts 464 465 /* tty_getty(): 466 * Wrapper for tcgetattr to handle EINTR 467 */ 468 private int 469 tty_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 */ 480 private int 481 tty_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 */ 492 private int 493 tty_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, "%s: isatty: %s\n", __func__, 503 strerror(errno)); 504 #endif /* DEBUG_TTY */ 505 return -1; 506 } 507 if (tty_getty(el, &el->el_tty.t_or) == -1) { 508 #ifdef DEBUG_TTY 509 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, 510 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 = el->el_tty.t_or; 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, "%s: tty_setty: %s\n", 559 __func__, strerror(errno)); 560 #endif /* DEBUG_TTY */ 561 return -1; 562 } 563 } 564 565 el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; 566 el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask; 567 568 el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; 569 el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; 570 571 el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; 572 el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; 573 574 el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; 575 el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; 576 577 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); 578 tty_bind_char(el, 1); 579 return 0; 580 } 581 582 protected int 583 tty_init(EditLine *el) 584 { 585 586 el->el_tty.t_mode = EX_IO; 587 el->el_tty.t_vdisable = _POSIX_VDISABLE; 588 (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t)); 589 (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t)); 590 return tty_setup(el); 591 } 592 593 594 /* tty_end(): 595 * Restore the tty to its original settings 596 */ 597 protected void 598 /*ARGSUSED*/ 599 tty_end(EditLine *el) 600 { 601 if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) { 602 #ifdef DEBUG_TTY 603 (void) fprintf(el->el_errfile, 604 "%s: tty_setty: %s\n", __func__, strerror(errno)); 605 #endif /* DEBUG_TTY */ 606 } 607 } 608 609 610 /* tty__getspeed(): 611 * Get the tty speed 612 */ 613 private speed_t 614 tty__getspeed(struct termios *td) 615 { 616 speed_t spd; 617 618 if ((spd = cfgetispeed(td)) == 0) 619 spd = cfgetospeed(td); 620 return spd; 621 } 622 623 /* tty__getspeed(): 624 * Return the index of the asked char in the c_cc array 625 */ 626 private int 627 tty__getcharindex(int i) 628 { 629 switch (i) { 630 #ifdef VINTR 631 case C_INTR: 632 return VINTR; 633 #endif /* VINTR */ 634 #ifdef VQUIT 635 case C_QUIT: 636 return VQUIT; 637 #endif /* VQUIT */ 638 #ifdef VERASE 639 case C_ERASE: 640 return VERASE; 641 #endif /* VERASE */ 642 #ifdef VKILL 643 case C_KILL: 644 return VKILL; 645 #endif /* VKILL */ 646 #ifdef VEOF 647 case C_EOF: 648 return VEOF; 649 #endif /* VEOF */ 650 #ifdef VEOL 651 case C_EOL: 652 return VEOL; 653 #endif /* VEOL */ 654 #ifdef VEOL2 655 case C_EOL2: 656 return VEOL2; 657 #endif /* VEOL2 */ 658 #ifdef VSWTCH 659 case C_SWTCH: 660 return VSWTCH; 661 #endif /* VSWTCH */ 662 #ifdef VDSWTCH 663 case C_DSWTCH: 664 return VDSWTCH; 665 #endif /* VDSWTCH */ 666 #ifdef VERASE2 667 case C_ERASE2: 668 return VERASE2; 669 #endif /* VERASE2 */ 670 #ifdef VSTART 671 case C_START: 672 return VSTART; 673 #endif /* VSTART */ 674 #ifdef VSTOP 675 case C_STOP: 676 return VSTOP; 677 #endif /* VSTOP */ 678 #ifdef VWERASE 679 case C_WERASE: 680 return VWERASE; 681 #endif /* VWERASE */ 682 #ifdef VSUSP 683 case C_SUSP: 684 return VSUSP; 685 #endif /* VSUSP */ 686 #ifdef VDSUSP 687 case C_DSUSP: 688 return VDSUSP; 689 #endif /* VDSUSP */ 690 #ifdef VREPRINT 691 case C_REPRINT: 692 return VREPRINT; 693 #endif /* VREPRINT */ 694 #ifdef VDISCARD 695 case C_DISCARD: 696 return VDISCARD; 697 #endif /* VDISCARD */ 698 #ifdef VLNEXT 699 case C_LNEXT: 700 return VLNEXT; 701 #endif /* VLNEXT */ 702 #ifdef VSTATUS 703 case C_STATUS: 704 return VSTATUS; 705 #endif /* VSTATUS */ 706 #ifdef VPAGE 707 case C_PAGE: 708 return VPAGE; 709 #endif /* VPAGE */ 710 #ifdef VPGOFF 711 case C_PGOFF: 712 return VPGOFF; 713 #endif /* VPGOFF */ 714 #ifdef VKILL2 715 case C_KILL2: 716 return VKILL2; 717 #endif /* KILL2 */ 718 #ifdef VMIN 719 case C_MIN: 720 return VMIN; 721 #endif /* VMIN */ 722 #ifdef VTIME 723 case C_TIME: 724 return VTIME; 725 #endif /* VTIME */ 726 default: 727 return -1; 728 } 729 } 730 731 /* tty__getchar(): 732 * Get the tty characters 733 */ 734 private void 735 tty__getchar(struct termios *td, unsigned char *s) 736 { 737 738 #ifdef VINTR 739 s[C_INTR] = td->c_cc[VINTR]; 740 #endif /* VINTR */ 741 #ifdef VQUIT 742 s[C_QUIT] = td->c_cc[VQUIT]; 743 #endif /* VQUIT */ 744 #ifdef VERASE 745 s[C_ERASE] = td->c_cc[VERASE]; 746 #endif /* VERASE */ 747 #ifdef VKILL 748 s[C_KILL] = td->c_cc[VKILL]; 749 #endif /* VKILL */ 750 #ifdef VEOF 751 s[C_EOF] = td->c_cc[VEOF]; 752 #endif /* VEOF */ 753 #ifdef VEOL 754 s[C_EOL] = td->c_cc[VEOL]; 755 #endif /* VEOL */ 756 #ifdef VEOL2 757 s[C_EOL2] = td->c_cc[VEOL2]; 758 #endif /* VEOL2 */ 759 #ifdef VSWTCH 760 s[C_SWTCH] = td->c_cc[VSWTCH]; 761 #endif /* VSWTCH */ 762 #ifdef VDSWTCH 763 s[C_DSWTCH] = td->c_cc[VDSWTCH]; 764 #endif /* VDSWTCH */ 765 #ifdef VERASE2 766 s[C_ERASE2] = td->c_cc[VERASE2]; 767 #endif /* VERASE2 */ 768 #ifdef VSTART 769 s[C_START] = td->c_cc[VSTART]; 770 #endif /* VSTART */ 771 #ifdef VSTOP 772 s[C_STOP] = td->c_cc[VSTOP]; 773 #endif /* VSTOP */ 774 #ifdef VWERASE 775 s[C_WERASE] = td->c_cc[VWERASE]; 776 #endif /* VWERASE */ 777 #ifdef VSUSP 778 s[C_SUSP] = td->c_cc[VSUSP]; 779 #endif /* VSUSP */ 780 #ifdef VDSUSP 781 s[C_DSUSP] = td->c_cc[VDSUSP]; 782 #endif /* VDSUSP */ 783 #ifdef VREPRINT 784 s[C_REPRINT] = td->c_cc[VREPRINT]; 785 #endif /* VREPRINT */ 786 #ifdef VDISCARD 787 s[C_DISCARD] = td->c_cc[VDISCARD]; 788 #endif /* VDISCARD */ 789 #ifdef VLNEXT 790 s[C_LNEXT] = td->c_cc[VLNEXT]; 791 #endif /* VLNEXT */ 792 #ifdef VSTATUS 793 s[C_STATUS] = td->c_cc[VSTATUS]; 794 #endif /* VSTATUS */ 795 #ifdef VPAGE 796 s[C_PAGE] = td->c_cc[VPAGE]; 797 #endif /* VPAGE */ 798 #ifdef VPGOFF 799 s[C_PGOFF] = td->c_cc[VPGOFF]; 800 #endif /* VPGOFF */ 801 #ifdef VKILL2 802 s[C_KILL2] = td->c_cc[VKILL2]; 803 #endif /* KILL2 */ 804 #ifdef VMIN 805 s[C_MIN] = td->c_cc[VMIN]; 806 #endif /* VMIN */ 807 #ifdef VTIME 808 s[C_TIME] = td->c_cc[VTIME]; 809 #endif /* VTIME */ 810 } /* tty__getchar */ 811 812 813 /* tty__setchar(): 814 * Set the tty characters 815 */ 816 private void 817 tty__setchar(struct termios *td, unsigned char *s) 818 { 819 820 #ifdef VINTR 821 td->c_cc[VINTR] = s[C_INTR]; 822 #endif /* VINTR */ 823 #ifdef VQUIT 824 td->c_cc[VQUIT] = s[C_QUIT]; 825 #endif /* VQUIT */ 826 #ifdef VERASE 827 td->c_cc[VERASE] = s[C_ERASE]; 828 #endif /* VERASE */ 829 #ifdef VKILL 830 td->c_cc[VKILL] = s[C_KILL]; 831 #endif /* VKILL */ 832 #ifdef VEOF 833 td->c_cc[VEOF] = s[C_EOF]; 834 #endif /* VEOF */ 835 #ifdef VEOL 836 td->c_cc[VEOL] = s[C_EOL]; 837 #endif /* VEOL */ 838 #ifdef VEOL2 839 td->c_cc[VEOL2] = s[C_EOL2]; 840 #endif /* VEOL2 */ 841 #ifdef VSWTCH 842 td->c_cc[VSWTCH] = s[C_SWTCH]; 843 #endif /* VSWTCH */ 844 #ifdef VDSWTCH 845 td->c_cc[VDSWTCH] = s[C_DSWTCH]; 846 #endif /* VDSWTCH */ 847 #ifdef VERASE2 848 td->c_cc[VERASE2] = s[C_ERASE2]; 849 #endif /* VERASE2 */ 850 #ifdef VSTART 851 td->c_cc[VSTART] = s[C_START]; 852 #endif /* VSTART */ 853 #ifdef VSTOP 854 td->c_cc[VSTOP] = s[C_STOP]; 855 #endif /* VSTOP */ 856 #ifdef VWERASE 857 td->c_cc[VWERASE] = s[C_WERASE]; 858 #endif /* VWERASE */ 859 #ifdef VSUSP 860 td->c_cc[VSUSP] = s[C_SUSP]; 861 #endif /* VSUSP */ 862 #ifdef VDSUSP 863 td->c_cc[VDSUSP] = s[C_DSUSP]; 864 #endif /* VDSUSP */ 865 #ifdef VREPRINT 866 td->c_cc[VREPRINT] = s[C_REPRINT]; 867 #endif /* VREPRINT */ 868 #ifdef VDISCARD 869 td->c_cc[VDISCARD] = s[C_DISCARD]; 870 #endif /* VDISCARD */ 871 #ifdef VLNEXT 872 td->c_cc[VLNEXT] = s[C_LNEXT]; 873 #endif /* VLNEXT */ 874 #ifdef VSTATUS 875 td->c_cc[VSTATUS] = s[C_STATUS]; 876 #endif /* VSTATUS */ 877 #ifdef VPAGE 878 td->c_cc[VPAGE] = s[C_PAGE]; 879 #endif /* VPAGE */ 880 #ifdef VPGOFF 881 td->c_cc[VPGOFF] = s[C_PGOFF]; 882 #endif /* VPGOFF */ 883 #ifdef VKILL2 884 td->c_cc[VKILL2] = s[C_KILL2]; 885 #endif /* VKILL2 */ 886 #ifdef VMIN 887 td->c_cc[VMIN] = s[C_MIN]; 888 #endif /* VMIN */ 889 #ifdef VTIME 890 td->c_cc[VTIME] = s[C_TIME]; 891 #endif /* VTIME */ 892 } /* tty__setchar */ 893 894 895 /* tty_bind_char(): 896 * Rebind the editline functions 897 */ 898 protected void 899 tty_bind_char(EditLine *el, int force) 900 { 901 902 unsigned char *t_n = el->el_tty.t_c[ED_IO]; 903 unsigned char *t_o = el->el_tty.t_ed.c_cc; 904 Char new[2], old[2]; 905 const ttymap_t *tp; 906 el_action_t *map, *alt; 907 const el_action_t *dmap, *dalt; 908 new[1] = old[1] = '\0'; 909 910 map = el->el_map.key; 911 alt = el->el_map.alt; 912 if (el->el_map.type == MAP_VI) { 913 dmap = el->el_map.vii; 914 dalt = el->el_map.vic; 915 } else { 916 dmap = el->el_map.emacs; 917 dalt = NULL; 918 } 919 920 for (tp = tty_map; tp->nch != (Int)-1; tp++) { 921 new[0] = t_n[tp->nch]; 922 old[0] = t_o[tp->och]; 923 if (new[0] == old[0] && !force) 924 continue; 925 /* Put the old default binding back, and set the new binding */ 926 keymacro_clear(el, map, old); 927 map[UC(old[0])] = dmap[UC(old[0])]; 928 keymacro_clear(el, map, new); 929 /* MAP_VI == 1, MAP_EMACS == 0... */ 930 map[UC(new[0])] = tp->bind[el->el_map.type]; 931 if (dalt) { 932 keymacro_clear(el, alt, old); 933 alt[UC(old[0])] = dalt[UC(old[0])]; 934 keymacro_clear(el, alt, new); 935 alt[UC(new[0])] = tp->bind[el->el_map.type + 1]; 936 } 937 } 938 } 939 940 941 /* tty_rawmode(): 942 * Set terminal into 1 character at a time mode. 943 */ 944 protected int 945 tty_rawmode(EditLine *el) 946 { 947 948 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) 949 return 0; 950 951 if (el->el_flags & EDIT_DISABLED) 952 return 0; 953 954 if (tty_getty(el, &el->el_tty.t_ts) == -1) { 955 #ifdef DEBUG_TTY 956 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__, 957 strerror(errno)); 958 #endif /* DEBUG_TTY */ 959 return -1; 960 } 961 /* 962 * We always keep up with the eight bit setting and the speed of the 963 * tty. But we only believe changes that are made to cooked mode! 964 */ 965 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); 966 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); 967 968 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || 969 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { 970 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); 971 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); 972 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); 973 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); 974 } 975 if (tty__cooked_mode(&el->el_tty.t_ts)) { 976 if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) { 977 el->el_tty.t_ex.c_cflag = 978 el->el_tty.t_ts.c_cflag; 979 el->el_tty.t_ex.c_cflag &= 980 ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask; 981 el->el_tty.t_ex.c_cflag |= 982 el->el_tty.t_t[EX_IO][MD_CTL].t_setmask; 983 984 el->el_tty.t_ed.c_cflag = 985 el->el_tty.t_ts.c_cflag; 986 el->el_tty.t_ed.c_cflag &= 987 ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask; 988 el->el_tty.t_ed.c_cflag |= 989 el->el_tty.t_t[ED_IO][MD_CTL].t_setmask; 990 } 991 if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) && 992 (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) { 993 el->el_tty.t_ex.c_lflag = 994 el->el_tty.t_ts.c_lflag; 995 el->el_tty.t_ex.c_lflag &= 996 ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask; 997 el->el_tty.t_ex.c_lflag |= 998 el->el_tty.t_t[EX_IO][MD_LIN].t_setmask; 999 1000 el->el_tty.t_ed.c_lflag = 1001 el->el_tty.t_ts.c_lflag; 1002 el->el_tty.t_ed.c_lflag &= 1003 ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask; 1004 el->el_tty.t_ed.c_lflag |= 1005 el->el_tty.t_t[ED_IO][MD_LIN].t_setmask; 1006 } 1007 if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) && 1008 (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) { 1009 el->el_tty.t_ex.c_iflag = 1010 el->el_tty.t_ts.c_iflag; 1011 el->el_tty.t_ex.c_iflag &= 1012 ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask; 1013 el->el_tty.t_ex.c_iflag |= 1014 el->el_tty.t_t[EX_IO][MD_INP].t_setmask; 1015 1016 el->el_tty.t_ed.c_iflag = 1017 el->el_tty.t_ts.c_iflag; 1018 el->el_tty.t_ed.c_iflag &= 1019 ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask; 1020 el->el_tty.t_ed.c_iflag |= 1021 el->el_tty.t_t[ED_IO][MD_INP].t_setmask; 1022 } 1023 if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) && 1024 (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) { 1025 el->el_tty.t_ex.c_oflag = 1026 el->el_tty.t_ts.c_oflag; 1027 el->el_tty.t_ex.c_oflag &= 1028 ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask; 1029 el->el_tty.t_ex.c_oflag |= 1030 el->el_tty.t_t[EX_IO][MD_OUT].t_setmask; 1031 1032 el->el_tty.t_ed.c_oflag = 1033 el->el_tty.t_ts.c_oflag; 1034 el->el_tty.t_ed.c_oflag &= 1035 ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask; 1036 el->el_tty.t_ed.c_oflag |= 1037 el->el_tty.t_t[ED_IO][MD_OUT].t_setmask; 1038 } 1039 if (tty__gettabs(&el->el_tty.t_ex) == 0) 1040 el->el_tty.t_tabs = 0; 1041 else 1042 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; 1043 1044 { 1045 int i; 1046 1047 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); 1048 /* 1049 * Check if the user made any changes. 1050 * If he did, then propagate the changes to the 1051 * edit and execute data structures. 1052 */ 1053 for (i = 0; i < C_NCC; i++) 1054 if (el->el_tty.t_c[TS_IO][i] != 1055 el->el_tty.t_c[EX_IO][i]) 1056 break; 1057 1058 if (i != C_NCC) { 1059 /* 1060 * Propagate changes only to the unprotected 1061 * chars that have been modified just now. 1062 */ 1063 for (i = 0; i < C_NCC; i++) { 1064 if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i))) 1065 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) 1066 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i]; 1067 if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i)) 1068 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable; 1069 } 1070 tty_bind_char(el, 0); 1071 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); 1072 1073 for (i = 0; i < C_NCC; i++) { 1074 if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i))) 1075 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i])) 1076 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i]; 1077 if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i)) 1078 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable; 1079 } 1080 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); 1081 } 1082 } 1083 } 1084 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1085 #ifdef DEBUG_TTY 1086 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1087 strerror(errno)); 1088 #endif /* DEBUG_TTY */ 1089 return -1; 1090 } 1091 el->el_tty.t_mode = ED_IO; 1092 return 0; 1093 } 1094 1095 1096 /* tty_cookedmode(): 1097 * Set the tty back to normal mode 1098 */ 1099 protected int 1100 tty_cookedmode(EditLine *el) 1101 { /* set tty in normal setup */ 1102 1103 if (el->el_tty.t_mode == EX_IO) 1104 return 0; 1105 1106 if (el->el_flags & EDIT_DISABLED) 1107 return 0; 1108 1109 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { 1110 #ifdef DEBUG_TTY 1111 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1112 strerror(errno)); 1113 #endif /* DEBUG_TTY */ 1114 return -1; 1115 } 1116 el->el_tty.t_mode = EX_IO; 1117 return 0; 1118 } 1119 1120 1121 /* tty_quotemode(): 1122 * Turn on quote mode 1123 */ 1124 protected int 1125 tty_quotemode(EditLine *el) 1126 { 1127 if (el->el_tty.t_mode == QU_IO) 1128 return 0; 1129 1130 el->el_tty.t_qu = el->el_tty.t_ed; 1131 1132 el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask; 1133 el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask; 1134 1135 el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask; 1136 el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask; 1137 1138 el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask; 1139 el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask; 1140 1141 el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask; 1142 el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask; 1143 1144 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -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 = QU_IO; 1152 return 0; 1153 } 1154 1155 1156 /* tty_noquotemode(): 1157 * Turn off quote mode 1158 */ 1159 protected int 1160 tty_noquotemode(EditLine *el) 1161 { 1162 1163 if (el->el_tty.t_mode != QU_IO) 1164 return 0; 1165 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1166 #ifdef DEBUG_TTY 1167 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__, 1168 strerror(errno)); 1169 #endif /* DEBUG_TTY */ 1170 return -1; 1171 } 1172 el->el_tty.t_mode = ED_IO; 1173 return 0; 1174 } 1175 1176 1177 /* tty_stty(): 1178 * Stty builtin 1179 */ 1180 protected int 1181 /*ARGSUSED*/ 1182 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv) 1183 { 1184 const ttymodes_t *m; 1185 char x; 1186 int aflag = 0; 1187 const Char *s, *d; 1188 char name[EL_BUFSIZ]; 1189 struct termios *tios = &el->el_tty.t_ex; 1190 int z = EX_IO; 1191 1192 if (argv == NULL) 1193 return -1; 1194 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); 1195 name[sizeof(name) - 1] = '\0'; 1196 1197 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') 1198 switch (argv[0][1]) { 1199 case 'a': 1200 aflag++; 1201 argv++; 1202 break; 1203 case 'd': 1204 argv++; 1205 tios = &el->el_tty.t_ed; 1206 z = ED_IO; 1207 break; 1208 case 'x': 1209 argv++; 1210 tios = &el->el_tty.t_ex; 1211 z = EX_IO; 1212 break; 1213 case 'q': 1214 argv++; 1215 tios = &el->el_tty.t_ts; 1216 z = QU_IO; 1217 break; 1218 default: 1219 (void) fprintf(el->el_errfile, 1220 "%s: Unknown switch `%c'.\n", 1221 name, argv[0][1]); 1222 return -1; 1223 } 1224 1225 if (!argv || !*argv) { 1226 int i = -1; 1227 size_t len = 0, st = 0, cu; 1228 for (m = ttymodes; m->m_name; m++) { 1229 if (m->m_type != i) { 1230 (void) fprintf(el->el_outfile, "%s%s", 1231 i != -1 ? "\n" : "", 1232 el->el_tty.t_t[z][m->m_type].t_name); 1233 i = m->m_type; 1234 st = len = 1235 strlen(el->el_tty.t_t[z][m->m_type].t_name); 1236 } 1237 if (i != -1) { 1238 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) 1239 ? '+' : '\0'; 1240 1241 if (el->el_tty.t_t[z][i].t_clrmask & m->m_value) 1242 x = '-'; 1243 } else { 1244 x = '\0'; 1245 } 1246 1247 if (x != '\0' || aflag) { 1248 1249 cu = strlen(m->m_name) + (x != '\0') + 1; 1250 1251 if (len + cu >= 1252 (size_t)el->el_terminal.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 = (char)*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, 1285 &el->el_scratch), (size_t)(p - d)) : 1286 strcmp(m->m_name, ct_encode_string(d, 1287 &el->el_scratch))) == 0 && 1288 (p == NULL || m->m_type == MD_CHAR)) 1289 break; 1290 1291 if (!m->m_name) { 1292 (void) fprintf(el->el_errfile, 1293 "%s: Invalid argument `" FSTR "'.\n", name, d); 1294 return -1; 1295 } 1296 if (p) { 1297 int c = ffs((int)m->m_value); 1298 int v = *++p ? parse__escape(&p) : 1299 el->el_tty.t_vdisable; 1300 assert(c != 0); 1301 c--; 1302 c = tty__getcharindex(c); 1303 assert(c != -1); 1304 tios->c_cc[c] = (cc_t)v; 1305 continue; 1306 } 1307 switch (x) { 1308 case '+': 1309 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; 1310 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1311 break; 1312 case '-': 1313 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; 1314 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; 1315 break; 1316 default: 1317 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; 1318 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1319 break; 1320 } 1321 } 1322 1323 if (el->el_tty.t_mode == z) { 1324 if (tty_setty(el, TCSADRAIN, tios) == -1) { 1325 #ifdef DEBUG_TTY 1326 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", 1327 __func__, strerror(errno)); 1328 #endif /* DEBUG_TTY */ 1329 return -1; 1330 } 1331 } 1332 1333 return 0; 1334 } 1335 1336 1337 #ifdef notyet 1338 /* tty_printchar(): 1339 * DEbugging routine to print the tty characters 1340 */ 1341 private void 1342 tty_printchar(EditLine *el, unsigned char *s) 1343 { 1344 ttyperm_t *m; 1345 int i; 1346 1347 for (i = 0; i < C_NCC; i++) { 1348 for (m = el->el_tty.t_t; m->m_name; m++) 1349 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) 1350 break; 1351 if (m->m_name) 1352 (void) fprintf(el->el_errfile, "%s ^%c ", 1353 m->m_name, s[i] + 'A' - 1); 1354 if (i % 5 == 0) 1355 (void) fprintf(el->el_errfile, "\n"); 1356 } 1357 (void) fprintf(el->el_errfile, "\n"); 1358 } 1359 #endif /* notyet */ 1360