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