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