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