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