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