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