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