1 /* $OpenBSD: tty.c,v 1.28 2023/03/08 04:43:05 guenther 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 tty_end(EditLine *el) 584 { 585 if (el->el_flags & EDIT_DISABLED) 586 return; 587 588 if (!el->el_tty.t_initialized) 589 return; 590 591 if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) { 592 #ifdef DEBUG_TTY 593 (void) fprintf(el->el_errfile, 594 "%s: tty_setty: %s\n", __func__, strerror(errno)); 595 #endif /* DEBUG_TTY */ 596 } 597 } 598 599 600 /* tty__getspeed(): 601 * Get the tty speed 602 */ 603 static speed_t 604 tty__getspeed(struct termios *td) 605 { 606 speed_t spd; 607 608 if ((spd = cfgetispeed(td)) == 0) 609 spd = cfgetospeed(td); 610 return spd; 611 } 612 613 /* tty__getspeed(): 614 * Return the index of the asked char in the c_cc array 615 */ 616 static int 617 tty__getcharindex(int i) 618 { 619 switch (i) { 620 #ifdef VINTR 621 case C_INTR: 622 return VINTR; 623 #endif /* VINTR */ 624 #ifdef VQUIT 625 case C_QUIT: 626 return VQUIT; 627 #endif /* VQUIT */ 628 #ifdef VERASE 629 case C_ERASE: 630 return VERASE; 631 #endif /* VERASE */ 632 #ifdef VKILL 633 case C_KILL: 634 return VKILL; 635 #endif /* VKILL */ 636 #ifdef VEOF 637 case C_EOF: 638 return VEOF; 639 #endif /* VEOF */ 640 #ifdef VEOL 641 case C_EOL: 642 return VEOL; 643 #endif /* VEOL */ 644 #ifdef VEOL2 645 case C_EOL2: 646 return VEOL2; 647 #endif /* VEOL2 */ 648 #ifdef VSWTCH 649 case C_SWTCH: 650 return VSWTCH; 651 #endif /* VSWTCH */ 652 #ifdef VDSWTCH 653 case C_DSWTCH: 654 return VDSWTCH; 655 #endif /* VDSWTCH */ 656 #ifdef VERASE2 657 case C_ERASE2: 658 return VERASE2; 659 #endif /* VERASE2 */ 660 #ifdef VSTART 661 case C_START: 662 return VSTART; 663 #endif /* VSTART */ 664 #ifdef VSTOP 665 case C_STOP: 666 return VSTOP; 667 #endif /* VSTOP */ 668 #ifdef VWERASE 669 case C_WERASE: 670 return VWERASE; 671 #endif /* VWERASE */ 672 #ifdef VSUSP 673 case C_SUSP: 674 return VSUSP; 675 #endif /* VSUSP */ 676 #ifdef VDSUSP 677 case C_DSUSP: 678 return VDSUSP; 679 #endif /* VDSUSP */ 680 #ifdef VREPRINT 681 case C_REPRINT: 682 return VREPRINT; 683 #endif /* VREPRINT */ 684 #ifdef VDISCARD 685 case C_DISCARD: 686 return VDISCARD; 687 #endif /* VDISCARD */ 688 #ifdef VLNEXT 689 case C_LNEXT: 690 return VLNEXT; 691 #endif /* VLNEXT */ 692 #ifdef VSTATUS 693 case C_STATUS: 694 return VSTATUS; 695 #endif /* VSTATUS */ 696 #ifdef VPAGE 697 case C_PAGE: 698 return VPAGE; 699 #endif /* VPAGE */ 700 #ifdef VPGOFF 701 case C_PGOFF: 702 return VPGOFF; 703 #endif /* VPGOFF */ 704 #ifdef VKILL2 705 case C_KILL2: 706 return VKILL2; 707 #endif /* KILL2 */ 708 #ifdef VMIN 709 case C_MIN: 710 return VMIN; 711 #endif /* VMIN */ 712 #ifdef VTIME 713 case C_TIME: 714 return VTIME; 715 #endif /* VTIME */ 716 default: 717 return -1; 718 } 719 } 720 721 /* tty__getchar(): 722 * Get the tty characters 723 */ 724 static void 725 tty__getchar(struct termios *td, unsigned char *s) 726 { 727 728 #ifdef VINTR 729 s[C_INTR] = td->c_cc[VINTR]; 730 #endif /* VINTR */ 731 #ifdef VQUIT 732 s[C_QUIT] = td->c_cc[VQUIT]; 733 #endif /* VQUIT */ 734 #ifdef VERASE 735 s[C_ERASE] = td->c_cc[VERASE]; 736 #endif /* VERASE */ 737 #ifdef VKILL 738 s[C_KILL] = td->c_cc[VKILL]; 739 #endif /* VKILL */ 740 #ifdef VEOF 741 s[C_EOF] = td->c_cc[VEOF]; 742 #endif /* VEOF */ 743 #ifdef VEOL 744 s[C_EOL] = td->c_cc[VEOL]; 745 #endif /* VEOL */ 746 #ifdef VEOL2 747 s[C_EOL2] = td->c_cc[VEOL2]; 748 #endif /* VEOL2 */ 749 #ifdef VSWTCH 750 s[C_SWTCH] = td->c_cc[VSWTCH]; 751 #endif /* VSWTCH */ 752 #ifdef VDSWTCH 753 s[C_DSWTCH] = td->c_cc[VDSWTCH]; 754 #endif /* VDSWTCH */ 755 #ifdef VERASE2 756 s[C_ERASE2] = td->c_cc[VERASE2]; 757 #endif /* VERASE2 */ 758 #ifdef VSTART 759 s[C_START] = td->c_cc[VSTART]; 760 #endif /* VSTART */ 761 #ifdef VSTOP 762 s[C_STOP] = td->c_cc[VSTOP]; 763 #endif /* VSTOP */ 764 #ifdef VWERASE 765 s[C_WERASE] = td->c_cc[VWERASE]; 766 #endif /* VWERASE */ 767 #ifdef VSUSP 768 s[C_SUSP] = td->c_cc[VSUSP]; 769 #endif /* VSUSP */ 770 #ifdef VDSUSP 771 s[C_DSUSP] = td->c_cc[VDSUSP]; 772 #endif /* VDSUSP */ 773 #ifdef VREPRINT 774 s[C_REPRINT] = td->c_cc[VREPRINT]; 775 #endif /* VREPRINT */ 776 #ifdef VDISCARD 777 s[C_DISCARD] = td->c_cc[VDISCARD]; 778 #endif /* VDISCARD */ 779 #ifdef VLNEXT 780 s[C_LNEXT] = td->c_cc[VLNEXT]; 781 #endif /* VLNEXT */ 782 #ifdef VSTATUS 783 s[C_STATUS] = td->c_cc[VSTATUS]; 784 #endif /* VSTATUS */ 785 #ifdef VPAGE 786 s[C_PAGE] = td->c_cc[VPAGE]; 787 #endif /* VPAGE */ 788 #ifdef VPGOFF 789 s[C_PGOFF] = td->c_cc[VPGOFF]; 790 #endif /* VPGOFF */ 791 #ifdef VKILL2 792 s[C_KILL2] = td->c_cc[VKILL2]; 793 #endif /* KILL2 */ 794 #ifdef VMIN 795 s[C_MIN] = td->c_cc[VMIN]; 796 #endif /* VMIN */ 797 #ifdef VTIME 798 s[C_TIME] = td->c_cc[VTIME]; 799 #endif /* VTIME */ 800 } /* tty__getchar */ 801 802 803 /* tty__setchar(): 804 * Set the tty characters 805 */ 806 static void 807 tty__setchar(struct termios *td, unsigned char *s) 808 { 809 810 #ifdef VINTR 811 td->c_cc[VINTR] = s[C_INTR]; 812 #endif /* VINTR */ 813 #ifdef VQUIT 814 td->c_cc[VQUIT] = s[C_QUIT]; 815 #endif /* VQUIT */ 816 #ifdef VERASE 817 td->c_cc[VERASE] = s[C_ERASE]; 818 #endif /* VERASE */ 819 #ifdef VKILL 820 td->c_cc[VKILL] = s[C_KILL]; 821 #endif /* VKILL */ 822 #ifdef VEOF 823 td->c_cc[VEOF] = s[C_EOF]; 824 #endif /* VEOF */ 825 #ifdef VEOL 826 td->c_cc[VEOL] = s[C_EOL]; 827 #endif /* VEOL */ 828 #ifdef VEOL2 829 td->c_cc[VEOL2] = s[C_EOL2]; 830 #endif /* VEOL2 */ 831 #ifdef VSWTCH 832 td->c_cc[VSWTCH] = s[C_SWTCH]; 833 #endif /* VSWTCH */ 834 #ifdef VDSWTCH 835 td->c_cc[VDSWTCH] = s[C_DSWTCH]; 836 #endif /* VDSWTCH */ 837 #ifdef VERASE2 838 td->c_cc[VERASE2] = s[C_ERASE2]; 839 #endif /* VERASE2 */ 840 #ifdef VSTART 841 td->c_cc[VSTART] = s[C_START]; 842 #endif /* VSTART */ 843 #ifdef VSTOP 844 td->c_cc[VSTOP] = s[C_STOP]; 845 #endif /* VSTOP */ 846 #ifdef VWERASE 847 td->c_cc[VWERASE] = s[C_WERASE]; 848 #endif /* VWERASE */ 849 #ifdef VSUSP 850 td->c_cc[VSUSP] = s[C_SUSP]; 851 #endif /* VSUSP */ 852 #ifdef VDSUSP 853 td->c_cc[VDSUSP] = s[C_DSUSP]; 854 #endif /* VDSUSP */ 855 #ifdef VREPRINT 856 td->c_cc[VREPRINT] = s[C_REPRINT]; 857 #endif /* VREPRINT */ 858 #ifdef VDISCARD 859 td->c_cc[VDISCARD] = s[C_DISCARD]; 860 #endif /* VDISCARD */ 861 #ifdef VLNEXT 862 td->c_cc[VLNEXT] = s[C_LNEXT]; 863 #endif /* VLNEXT */ 864 #ifdef VSTATUS 865 td->c_cc[VSTATUS] = s[C_STATUS]; 866 #endif /* VSTATUS */ 867 #ifdef VPAGE 868 td->c_cc[VPAGE] = s[C_PAGE]; 869 #endif /* VPAGE */ 870 #ifdef VPGOFF 871 td->c_cc[VPGOFF] = s[C_PGOFF]; 872 #endif /* VPGOFF */ 873 #ifdef VKILL2 874 td->c_cc[VKILL2] = s[C_KILL2]; 875 #endif /* VKILL2 */ 876 #ifdef VMIN 877 td->c_cc[VMIN] = s[C_MIN]; 878 #endif /* VMIN */ 879 #ifdef VTIME 880 td->c_cc[VTIME] = s[C_TIME]; 881 #endif /* VTIME */ 882 } /* tty__setchar */ 883 884 885 /* tty_bind_char(): 886 * Rebind the editline functions 887 */ 888 protected void 889 tty_bind_char(EditLine *el, int force) 890 { 891 892 unsigned char *t_n = el->el_tty.t_c[ED_IO]; 893 unsigned char *t_o = el->el_tty.t_ed.c_cc; 894 wchar_t new[2], old[2]; 895 const ttymap_t *tp; 896 el_action_t *map, *alt; 897 const el_action_t *dmap, *dalt; 898 new[1] = old[1] = '\0'; 899 900 map = el->el_map.key; 901 alt = el->el_map.alt; 902 if (el->el_map.type == MAP_VI) { 903 dmap = el->el_map.vii; 904 dalt = el->el_map.vic; 905 } else { 906 dmap = el->el_map.emacs; 907 dalt = NULL; 908 } 909 910 for (tp = tty_map; tp->nch != (wint_t)-1; tp++) { 911 new[0] = (wchar_t)t_n[tp->nch]; 912 old[0] = (wchar_t)t_o[tp->och]; 913 if (new[0] == old[0] && !force) 914 continue; 915 /* Put the old default binding back, and set the new binding */ 916 keymacro_clear(el, map, old); 917 map[(unsigned char)old[0]] = dmap[(unsigned char)old[0]]; 918 keymacro_clear(el, map, new); 919 /* MAP_VI == 1, MAP_EMACS == 0... */ 920 map[(unsigned char)new[0]] = tp->bind[el->el_map.type]; 921 if (dalt) { 922 keymacro_clear(el, alt, old); 923 alt[(unsigned char)old[0]] = 924 dalt[(unsigned char)old[0]]; 925 keymacro_clear(el, alt, new); 926 alt[(unsigned char)new[0]] = 927 tp->bind[el->el_map.type + 1]; 928 } 929 } 930 } 931 932 933 static tcflag_t * 934 tty__get_flag(struct termios *t, int kind) { 935 switch (kind) { 936 case MD_INP: 937 return &t->c_iflag; 938 case MD_OUT: 939 return &t->c_oflag; 940 case MD_CTL: 941 return &t->c_cflag; 942 case MD_LIN: 943 return &t->c_lflag; 944 default: 945 abort(); 946 /*NOTREACHED*/ 947 } 948 } 949 950 951 static tcflag_t 952 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind) 953 { 954 f &= ~el->el_tty.t_t[mode][kind].t_clrmask; 955 f |= el->el_tty.t_t[mode][kind].t_setmask; 956 return f; 957 } 958 959 960 static void 961 tty_update_flags(EditLine *el, int kind) 962 { 963 tcflag_t *tt, *ed, *ex; 964 tt = tty__get_flag(&el->el_tty.t_ts, kind); 965 ed = tty__get_flag(&el->el_tty.t_ed, kind); 966 ex = tty__get_flag(&el->el_tty.t_ex, kind); 967 968 if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) { 969 *ed = tty_update_flag(el, *tt, ED_IO, kind); 970 *ex = tty_update_flag(el, *tt, EX_IO, kind); 971 } 972 } 973 974 975 static void 976 tty_update_char(EditLine *el, int mode, int c) { 977 if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c))) 978 && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c])) 979 el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c]; 980 if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c)) 981 el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable; 982 } 983 984 985 /* tty_rawmode(): 986 * Set terminal into 1 character at a time mode. 987 */ 988 protected int 989 tty_rawmode(EditLine *el) 990 { 991 992 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO) 993 return 0; 994 995 if (el->el_flags & EDIT_DISABLED) 996 return 0; 997 998 if (tty_getty(el, &el->el_tty.t_ts) == -1) { 999 #ifdef DEBUG_TTY 1000 (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n", 1001 strerror(errno)); 1002 #endif /* DEBUG_TTY */ 1003 return -1; 1004 } 1005 /* 1006 * We always keep up with the eight bit setting and the speed of the 1007 * tty. But we only believe changes that are made to cooked mode! 1008 */ 1009 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts); 1010 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts); 1011 1012 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed || 1013 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) { 1014 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed); 1015 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed); 1016 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed); 1017 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed); 1018 } 1019 if (tty__cooked_mode(&el->el_tty.t_ts)) { 1020 int i; 1021 1022 for (i = MD_INP; i <= MD_LIN; i++) 1023 tty_update_flags(el, i); 1024 1025 if (tty__gettabs(&el->el_tty.t_ex) == 0) 1026 el->el_tty.t_tabs = 0; 1027 else 1028 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0; 1029 1030 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]); 1031 /* 1032 * Check if the user made any changes. 1033 * If he did, then propagate the changes to the 1034 * edit and execute data structures. 1035 */ 1036 for (i = 0; i < C_NCC; i++) 1037 if (el->el_tty.t_c[TS_IO][i] != 1038 el->el_tty.t_c[EX_IO][i]) 1039 break; 1040 1041 if (i != C_NCC) { 1042 /* 1043 * Propagate changes only to the unprotected 1044 * chars that have been modified just now. 1045 */ 1046 for (i = 0; i < C_NCC; i++) 1047 tty_update_char(el, ED_IO, i); 1048 1049 tty_bind_char(el, 0); 1050 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]); 1051 1052 for (i = 0; i < C_NCC; i++) 1053 tty_update_char(el, EX_IO, i); 1054 1055 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]); 1056 } 1057 } 1058 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1059 #ifdef DEBUG_TTY 1060 (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n", 1061 strerror(errno)); 1062 #endif /* DEBUG_TTY */ 1063 return -1; 1064 } 1065 el->el_tty.t_mode = ED_IO; 1066 return 0; 1067 } 1068 1069 1070 /* tty_cookedmode(): 1071 * Set the tty back to normal mode 1072 */ 1073 protected int 1074 tty_cookedmode(EditLine *el) 1075 { /* set tty in normal setup */ 1076 1077 if (el->el_tty.t_mode == EX_IO) 1078 return 0; 1079 1080 if (el->el_flags & EDIT_DISABLED) 1081 return 0; 1082 1083 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) { 1084 #ifdef DEBUG_TTY 1085 (void) fprintf(el->el_errfile, 1086 "tty_cookedmode: tty_setty: %s\n", 1087 strerror(errno)); 1088 #endif /* DEBUG_TTY */ 1089 return -1; 1090 } 1091 el->el_tty.t_mode = EX_IO; 1092 return 0; 1093 } 1094 1095 1096 /* tty_quotemode(): 1097 * Turn on quote mode 1098 */ 1099 protected int 1100 tty_quotemode(EditLine *el) 1101 { 1102 if (el->el_tty.t_mode == QU_IO) 1103 return 0; 1104 1105 el->el_tty.t_qu = el->el_tty.t_ed; 1106 1107 tty_setup_flags(el, &el->el_tty.t_qu, QU_IO); 1108 1109 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) { 1110 #ifdef DEBUG_TTY 1111 (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n", 1112 strerror(errno)); 1113 #endif /* DEBUG_TTY */ 1114 return -1; 1115 } 1116 el->el_tty.t_mode = QU_IO; 1117 return 0; 1118 } 1119 1120 1121 /* tty_noquotemode(): 1122 * Turn off quote mode 1123 */ 1124 protected int 1125 tty_noquotemode(EditLine *el) 1126 { 1127 1128 if (el->el_tty.t_mode != QU_IO) 1129 return 0; 1130 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) { 1131 #ifdef DEBUG_TTY 1132 (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n", 1133 strerror(errno)); 1134 #endif /* DEBUG_TTY */ 1135 return -1; 1136 } 1137 el->el_tty.t_mode = ED_IO; 1138 return 0; 1139 } 1140 1141 1142 /* tty_stty(): 1143 * Stty builtin 1144 */ 1145 protected int 1146 tty_stty(EditLine *el, int argc __attribute__((__unused__)), 1147 const wchar_t **argv) 1148 { 1149 const ttymodes_t *m; 1150 char x; 1151 int aflag = 0; 1152 const wchar_t *s, *d; 1153 char name[EL_BUFSIZ]; 1154 struct termios *tios = &el->el_tty.t_ex; 1155 int z = EX_IO; 1156 1157 if (argv == NULL) 1158 return -1; 1159 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name)); 1160 name[sizeof(name) - 1] = '\0'; 1161 1162 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0') 1163 switch (argv[0][1]) { 1164 case 'a': 1165 aflag++; 1166 argv++; 1167 break; 1168 case 'd': 1169 argv++; 1170 tios = &el->el_tty.t_ed; 1171 z = ED_IO; 1172 break; 1173 case 'x': 1174 argv++; 1175 tios = &el->el_tty.t_ex; 1176 z = EX_IO; 1177 break; 1178 case 'q': 1179 argv++; 1180 tios = &el->el_tty.t_ts; 1181 z = QU_IO; 1182 break; 1183 default: 1184 (void) fprintf(el->el_errfile, 1185 "%s: Unknown switch `%lc'.\n", 1186 name, argv[0][1]); 1187 return -1; 1188 } 1189 1190 if (!argv || !*argv) { 1191 int i = -1; 1192 size_t len = 0, st = 0, cu; 1193 for (m = ttymodes; m->m_name; m++) { 1194 if (m->m_type != i) { 1195 (void) fprintf(el->el_outfile, "%s%s", 1196 i != -1 ? "\n" : "", 1197 el->el_tty.t_t[z][m->m_type].t_name); 1198 i = m->m_type; 1199 st = len = 1200 strlen(el->el_tty.t_t[z][m->m_type].t_name); 1201 } 1202 if (i != -1) { 1203 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value) 1204 ? '+' : '\0'; 1205 x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value) 1206 ? '-' : x; 1207 } else { 1208 x = '\0'; 1209 } 1210 1211 if (x != '\0' || aflag) { 1212 1213 cu = strlen(m->m_name) + (x != '\0') + 1; 1214 1215 if (len + cu >= 1216 (size_t)el->el_terminal.t_size.h) { 1217 (void) fprintf(el->el_outfile, "\n%*s", 1218 (int)st, ""); 1219 len = st + cu; 1220 } else 1221 len += cu; 1222 1223 if (x != '\0') 1224 (void) fprintf(el->el_outfile, "%c%s ", 1225 x, m->m_name); 1226 else 1227 (void) fprintf(el->el_outfile, "%s ", 1228 m->m_name); 1229 } 1230 } 1231 (void) fprintf(el->el_outfile, "\n"); 1232 return 0; 1233 } 1234 while (argv && (s = *argv++)) { 1235 const wchar_t *p; 1236 switch (*s) { 1237 case '+': 1238 case '-': 1239 x = *s++; 1240 break; 1241 default: 1242 x = '\0'; 1243 break; 1244 } 1245 d = s; 1246 p = wcschr(s, L'='); 1247 for (m = ttymodes; m->m_name; m++) 1248 if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) : 1249 strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 && 1250 (p == NULL || m->m_type == MD_CHAR)) 1251 break; 1252 1253 if (!m->m_name) { 1254 (void) fprintf(el->el_errfile, 1255 "%s: Invalid argument `%ls'.\n", name, d); 1256 return -1; 1257 } 1258 if (p) { 1259 int c = ffs((int)m->m_value); 1260 int v = *++p ? parse__escape(&p) : 1261 el->el_tty.t_vdisable; 1262 assert(c != 0); 1263 c--; 1264 c = tty__getcharindex(c); 1265 assert(c != -1); 1266 tios->c_cc[c] = v; 1267 continue; 1268 } 1269 switch (x) { 1270 case '+': 1271 el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value; 1272 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value; 1273 break; 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 default: 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 } 1283 } 1284 1285 tty_setup_flags(el, tios, z); 1286 if (el->el_tty.t_mode == z) { 1287 if (tty_setty(el, TCSADRAIN, tios) == -1) { 1288 #ifdef DEBUG_TTY 1289 (void) fprintf(el->el_errfile, 1290 "tty_stty: tty_setty: %s\n", strerror(errno)); 1291 #endif /* DEBUG_TTY */ 1292 return -1; 1293 } 1294 } 1295 1296 return 0; 1297 } 1298 1299 1300 #ifdef notyet 1301 /* tty_printchar(): 1302 * DEbugging routine to print the tty characters 1303 */ 1304 static void 1305 tty_printchar(EditLine *el, unsigned char *s) 1306 { 1307 ttyperm_t *m; 1308 int i; 1309 1310 for (i = 0; i < C_NCC; i++) { 1311 for (m = el->el_tty.t_t; m->m_name; m++) 1312 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value) 1313 break; 1314 if (m->m_name) 1315 (void) fprintf(el->el_errfile, "%s ^%c ", 1316 m->m_name, s[i] + 'A' - 1); 1317 if (i % 5 == 0) 1318 (void) fprintf(el->el_errfile, "\n"); 1319 } 1320 (void) fprintf(el->el_errfile, "\n"); 1321 } 1322 #endif /* notyet */ 1323 1324 1325 static void 1326 tty_setup_flags(EditLine *el, struct termios *tios, int mode) 1327 { 1328 int kind; 1329 for (kind = MD_INP; kind <= MD_LIN; kind++) { 1330 tcflag_t *f = tty__get_flag(tios, kind); 1331 *f = tty_update_flag(el, *f, mode, kind); 1332 } 1333 } 1334