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