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
tty_getty(EditLine * el,struct termios * t)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
tty_setty(EditLine * el,int action,const struct termios * t)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
tty_setup(EditLine * el)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
tty_init(EditLine * el)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
tty_end(EditLine * el)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
tty__getspeed(struct termios * td)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
tty__getcharindex(int i)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
tty__getchar(struct termios * td,unsigned char * s)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
tty__setchar(struct termios * td,unsigned char * s)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
tty_bind_char(EditLine * el,int force)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 *
tty__get_flag(struct termios * t,int kind)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
tty_update_flag(EditLine * el,tcflag_t f,int mode,int kind)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
tty_update_flags(EditLine * el,int kind)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
tty_update_char(EditLine * el,int mode,int c)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
tty_rawmode(EditLine * el)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
tty_cookedmode(EditLine * el)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
tty_quotemode(EditLine * el)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
tty_noquotemode(EditLine * el)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
tty_stty(EditLine * el,int argc,const wchar_t ** argv)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
tty_printchar(EditLine * el,unsigned char * s)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
tty_setup_flags(EditLine * el,struct termios * tios,int mode)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