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