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