1 /* $NetBSD: tty.c,v 1.30 2009/02/16 00:15:45 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.30 2009/02/16 00:15:45 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 "tty.h" 50 #include "el.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 unsigned 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, (char *)old); 919 map[old[0]] = dmap[old[0]]; 920 key_clear(el, map, (char *)new); 921 /* MAP_VI == 1, MAP_EMACS == 0... */ 922 map[new[0]] = tp->bind[el->el_map.type]; 923 if (dalt) { 924 key_clear(el, alt, (char *)old); 925 alt[old[0]] = dalt[old[0]]; 926 key_clear(el, alt, (char *)new); 927 alt[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 only 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 const char *name; 1182 struct termios *tios = &el->el_tty.t_ex; 1183 int z = EX_IO; 1184 1185 if (argv == NULL) 1186 return (-1); 1187 name = *argv++; 1188 1189 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') 1190 switch (argv[0][1]) { 1191 case 'a': 1192 aflag++; 1193 argv++; 1194 break; 1195 case 'd': 1196 argv++; 1197 tios = &el->el_tty.t_ed; 1198 z = ED_IO; 1199 break; 1200 case 'x': 1201 argv++; 1202 tios = &el->el_tty.t_ex; 1203 z = EX_IO; 1204 break; 1205 case 'q': 1206 argv++; 1207 tios = &el->el_tty.t_ts; 1208 z = QU_IO; 1209 break; 1210 default: 1211 (void) fprintf(el->el_errfile, 1212 "%s: Unknown switch `%c'.\n", 1213 name, argv[0][1]); 1214 return (-1); 1215 } 1216 1217 if (!argv || !*argv) { 1218 int i = -1; 1219 size_t len = 0, st = 0, cu; 1220 for (m = ttymodes; m->m_name; m++) { 1221 if (m->m_type != i) { 1222 (void) fprintf(el->el_outfile, "%s%s", 1223 i != -1 ? "\n" : "", 1224 el->el_tty.t_t[z][m->m_type].t_name); 1225 i = m->m_type; 1226 st = len = 1227 strlen(el->el_tty.t_t[z][m->m_type].t_name); 1228 } 1229 if (i != -1) { 1230 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) 1231 ? '+' : '\0'; 1232 x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) 1233 ? '-' : x; 1234 } else { 1235 x = '\0'; 1236 } 1237 1238 if (x != '\0' || aflag) { 1239 1240 cu = strlen(m->m_name) + (x != '\0') + 1; 1241 1242 if (len + cu >= (size_t)el->el_term.t_size.h) { 1243 (void) fprintf(el->el_outfile, "\n%*s", 1244 (int)st, ""); 1245 len = st + cu; 1246 } else 1247 len += cu; 1248 1249 if (x != '\0') 1250 (void) fprintf(el->el_outfile, "%c%s ", 1251 x, m->m_name); 1252 else 1253 (void) fprintf(el->el_outfile, "%s ", 1254 m->m_name); 1255 } 1256 } 1257 (void) fprintf(el->el_outfile, "\n"); 1258 return (0); 1259 } 1260 while (argv && (s = *argv++)) { 1261 const char *p; 1262 switch (*s) { 1263 case '+': 1264 case '-': 1265 x = *s++; 1266 break; 1267 default: 1268 x = '\0'; 1269 break; 1270 } 1271 d = s; 1272 p = strchr(s, '='); 1273 for (m = ttymodes; m->m_name; m++) 1274 if ((p ? strncmp(m->m_name, d, (size_t)(p - d)) : 1275 strcmp(m->m_name, d)) == 0 && 1276 (p == NULL || m->m_type == MD_CHAR)) 1277 break; 1278 1279 if (!m->m_name) { 1280 (void) fprintf(el->el_errfile, 1281 "%s: Invalid argument `%s'.\n", name, d); 1282 return (-1); 1283 } 1284 if (p) { 1285 int c = ffs((int)m->m_value); 1286 int v = *++p ? parse__escape((const char **) &p) : 1287 el->el_tty.t_vdisable; 1288 assert(c-- != 0); 1289 c = tty__getcharindex(c); 1290 assert(c != -1); 1291 tios->c_cc[c] = v; 1292 continue; 1293 } 1294 switch (x) { 1295 case '+': 1296 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; 1297 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1298 break; 1299 case '-': 1300 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value; 1301 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value; 1302 break; 1303 default: 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 } 1308 } 1309 1310 if (el->el_tty.t_mode == z) { 1311 if (tty_setty(el, TCSADRAIN, tios) == -1) { 1312 #ifdef DEBUG_TTY 1313 (void) fprintf(el->el_errfile, 1314 "tty_stty: tty_setty: %s\n", strerror(errno)); 1315 #endif /* DEBUG_TTY */ 1316 return (-1); 1317 } 1318 } 1319 1320 return (0); 1321 } 1322 1323 1324 #ifdef notyet 1325 /* tty_printchar(): 1326 * DEbugging routine to print the tty characters 1327 */ 1328 private void 1329 tty_printchar(EditLine *el, unsigned char *s) 1330 { 1331 ttyperm_t *m; 1332 int i; 1333 1334 for (i = 0; i < C_NCC; i++) { 1335 for (m = el->el_tty.t_t; m->m_name; m++) 1336 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) 1337 break; 1338 if (m->m_name) 1339 (void) fprintf(el->el_errfile, "%s ^%c ", 1340 m->m_name, s[i] + 'A' - 1); 1341 if (i % 5 == 0) 1342 (void) fprintf(el->el_errfile, "\n"); 1343 } 1344 (void) fprintf(el->el_errfile, "\n"); 1345 } 1346 #endif /* notyet */ 1347