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