]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libedit/tty.c
Remove spurious newline
[FreeBSD/FreeBSD.git] / lib / libedit / tty.c
1 /*      $NetBSD: tty.c,v 1.59 2016/03/22 01:34:32 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.59 2016/03/22 01:34:32 christos Exp $");
41 #endif
42 #endif /* not lint && not SCCSID */
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 /*
47  * tty.c: tty interface stuff
48  */
49 #include <assert.h>
50 #include <errno.h>
51 #include <stdlib.h>     /* for abort */
52 #include <string.h>
53 #include <strings.h>    /* for ffs */
54 #include <unistd.h>     /* for isatty */
55
56 #include "el.h"
57 #include "parse.h"
58
59 typedef struct ttymodes_t {
60         const char *m_name;
61         unsigned int m_value;
62         int m_type;
63 }          ttymodes_t;
64
65 typedef struct ttymap_t {
66         wint_t nch, och;        /* Internal and termio rep of chars */
67         el_action_t bind[3];    /* emacs, vi, and vi-cmd */
68 } ttymap_t;
69
70
71 private const ttyperm_t ttyperm = {
72         {
73                 {"iflag:", ICRNL, (INLCR | IGNCR)},
74                 {"oflag:", (OPOST | ONLCR), ONLRET},
75                 {"cflag:", 0, 0},
76                 {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
77                 (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
78                 {"chars:", 0, 0},
79         },
80         {
81                 {"iflag:", (INLCR | ICRNL), IGNCR},
82                 {"oflag:", (OPOST | ONLCR), ONLRET},
83                 {"cflag:", 0, 0},
84                 {"lflag:", ISIG,
85                 (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
86                 {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
87                             C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
88                     C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
89         },
90         {
91                 {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
92                 {"oflag:", 0, 0},
93                 {"cflag:", 0, 0},
94                 {"lflag:", 0, ISIG | IEXTEN},
95                 {"chars:", 0, 0},
96         }
97 };
98
99 private const ttychar_t ttychar = {
100         {
101                 CINTR, CQUIT, CERASE, CKILL,
102                 CEOF, CEOL, CEOL2, CSWTCH,
103                 CDSWTCH, CERASE2, CSTART, CSTOP,
104                 CWERASE, CSUSP, CDSUSP, CREPRINT,
105                 CDISCARD, CLNEXT, CSTATUS, CPAGE,
106                 CPGOFF, CKILL2, CBRK, CMIN,
107                 CTIME
108         },
109         {
110                 CINTR, CQUIT, CERASE, CKILL,
111                 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
112                 _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
113                 _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
114                 CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
115                 _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
116                 0
117         },
118         {
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, 0, 0, 0,
125                 0
126         }
127 };
128
129 private const ttymap_t tty_map[] = {
130 #ifdef VERASE
131         {C_ERASE, VERASE,
132         {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
133 #endif /* VERASE */
134 #ifdef VERASE2
135         {C_ERASE2, VERASE2,
136         {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
137 #endif /* VERASE2 */
138 #ifdef VKILL
139         {C_KILL, VKILL,
140         {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
141 #endif /* VKILL */
142 #ifdef VKILL2
143         {C_KILL2, VKILL2,
144         {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
145 #endif /* VKILL2 */
146 #ifdef VEOF
147         {C_EOF, VEOF,
148         {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
149 #endif /* VEOF */
150 #ifdef VWERASE
151         {C_WERASE, VWERASE,
152         {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
153 #endif /* VWERASE */
154 #ifdef VREPRINT
155         {C_REPRINT, VREPRINT,
156         {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
157 #endif /* VREPRINT */
158 #ifdef VLNEXT
159         {C_LNEXT, VLNEXT,
160         {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
161 #endif /* VLNEXT */
162         {(wint_t)-1, (wint_t)-1,
163         {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
164 };
165
166 private const ttymodes_t ttymodes[] = {
167 #ifdef  IGNBRK
168         {"ignbrk", IGNBRK, MD_INP},
169 #endif /* IGNBRK */
170 #ifdef  BRKINT
171         {"brkint", BRKINT, MD_INP},
172 #endif /* BRKINT */
173 #ifdef  IGNPAR
174         {"ignpar", IGNPAR, MD_INP},
175 #endif /* IGNPAR */
176 #ifdef  PARMRK
177         {"parmrk", PARMRK, MD_INP},
178 #endif /* PARMRK */
179 #ifdef  INPCK
180         {"inpck", INPCK, MD_INP},
181 #endif /* INPCK */
182 #ifdef  ISTRIP
183         {"istrip", ISTRIP, MD_INP},
184 #endif /* ISTRIP */
185 #ifdef  INLCR
186         {"inlcr", INLCR, MD_INP},
187 #endif /* INLCR */
188 #ifdef  IGNCR
189         {"igncr", IGNCR, MD_INP},
190 #endif /* IGNCR */
191 #ifdef  ICRNL
192         {"icrnl", ICRNL, MD_INP},
193 #endif /* ICRNL */
194 #ifdef  IUCLC
195         {"iuclc", IUCLC, MD_INP},
196 #endif /* IUCLC */
197 #ifdef  IXON
198         {"ixon", IXON, MD_INP},
199 #endif /* IXON */
200 #ifdef  IXANY
201         {"ixany", IXANY, MD_INP},
202 #endif /* IXANY */
203 #ifdef  IXOFF
204         {"ixoff", IXOFF, MD_INP},
205 #endif /* IXOFF */
206 #ifdef  IMAXBEL
207         {"imaxbel", IMAXBEL, MD_INP},
208 #endif /* IMAXBEL */
209
210 #ifdef  OPOST
211         {"opost", OPOST, MD_OUT},
212 #endif /* OPOST */
213 #ifdef  OLCUC
214         {"olcuc", OLCUC, MD_OUT},
215 #endif /* OLCUC */
216 #ifdef  ONLCR
217         {"onlcr", ONLCR, MD_OUT},
218 #endif /* ONLCR */
219 #ifdef  OCRNL
220         {"ocrnl", OCRNL, MD_OUT},
221 #endif /* OCRNL */
222 #ifdef  ONOCR
223         {"onocr", ONOCR, MD_OUT},
224 #endif /* ONOCR */
225 #ifdef ONOEOT
226         {"onoeot", ONOEOT, MD_OUT},
227 #endif /* ONOEOT */
228 #ifdef  ONLRET
229         {"onlret", ONLRET, MD_OUT},
230 #endif /* ONLRET */
231 #ifdef  OFILL
232         {"ofill", OFILL, MD_OUT},
233 #endif /* OFILL */
234 #ifdef  OFDEL
235         {"ofdel", OFDEL, MD_OUT},
236 #endif /* OFDEL */
237 #ifdef  NLDLY
238         {"nldly", NLDLY, MD_OUT},
239 #endif /* NLDLY */
240 #ifdef  CRDLY
241         {"crdly", CRDLY, MD_OUT},
242 #endif /* CRDLY */
243 #ifdef  TABDLY
244         {"tabdly", TABDLY, MD_OUT},
245 #endif /* TABDLY */
246 #ifdef  XTABS
247         {"xtabs", XTABS, MD_OUT},
248 #endif /* XTABS */
249 #ifdef  BSDLY
250         {"bsdly", BSDLY, MD_OUT},
251 #endif /* BSDLY */
252 #ifdef  VTDLY
253         {"vtdly", VTDLY, MD_OUT},
254 #endif /* VTDLY */
255 #ifdef  FFDLY
256         {"ffdly", FFDLY, MD_OUT},
257 #endif /* FFDLY */
258 #ifdef  PAGEOUT
259         {"pageout", PAGEOUT, MD_OUT},
260 #endif /* PAGEOUT */
261 #ifdef  WRAP
262         {"wrap", WRAP, MD_OUT},
263 #endif /* WRAP */
264
265 #ifdef  CIGNORE
266         {"cignore", CIGNORE, MD_CTL},
267 #endif /* CBAUD */
268 #ifdef  CBAUD
269         {"cbaud", CBAUD, MD_CTL},
270 #endif /* CBAUD */
271 #ifdef  CSTOPB
272         {"cstopb", CSTOPB, MD_CTL},
273 #endif /* CSTOPB */
274 #ifdef  CREAD
275         {"cread", CREAD, MD_CTL},
276 #endif /* CREAD */
277 #ifdef  PARENB
278         {"parenb", PARENB, MD_CTL},
279 #endif /* PARENB */
280 #ifdef  PARODD
281         {"parodd", PARODD, MD_CTL},
282 #endif /* PARODD */
283 #ifdef  HUPCL
284         {"hupcl", HUPCL, MD_CTL},
285 #endif /* HUPCL */
286 #ifdef  CLOCAL
287         {"clocal", CLOCAL, MD_CTL},
288 #endif /* CLOCAL */
289 #ifdef  LOBLK
290         {"loblk", LOBLK, MD_CTL},
291 #endif /* LOBLK */
292 #ifdef  CIBAUD
293         {"cibaud", CIBAUD, MD_CTL},
294 #endif /* CIBAUD */
295 #ifdef CRTSCTS
296 #ifdef CCTS_OFLOW
297         {"ccts_oflow", CCTS_OFLOW, MD_CTL},
298 #else
299         {"crtscts", CRTSCTS, MD_CTL},
300 #endif /* CCTS_OFLOW */
301 #endif /* CRTSCTS */
302 #ifdef CRTS_IFLOW
303         {"crts_iflow", CRTS_IFLOW, MD_CTL},
304 #endif /* CRTS_IFLOW */
305 #ifdef CDTRCTS
306         {"cdtrcts", CDTRCTS, MD_CTL},
307 #endif /* CDTRCTS */
308 #ifdef MDMBUF
309         {"mdmbuf", MDMBUF, MD_CTL},
310 #endif /* MDMBUF */
311 #ifdef RCV1EN
312         {"rcv1en", RCV1EN, MD_CTL},
313 #endif /* RCV1EN */
314 #ifdef XMT1EN
315         {"xmt1en", XMT1EN, MD_CTL},
316 #endif /* XMT1EN */
317
318 #ifdef  ISIG
319         {"isig", ISIG, MD_LIN},
320 #endif /* ISIG */
321 #ifdef  ICANON
322         {"icanon", ICANON, MD_LIN},
323 #endif /* ICANON */
324 #ifdef  XCASE
325         {"xcase", XCASE, MD_LIN},
326 #endif /* XCASE */
327 #ifdef  ECHO
328         {"echo", ECHO, MD_LIN},
329 #endif /* ECHO */
330 #ifdef  ECHOE
331         {"echoe", ECHOE, MD_LIN},
332 #endif /* ECHOE */
333 #ifdef  ECHOK
334         {"echok", ECHOK, MD_LIN},
335 #endif /* ECHOK */
336 #ifdef  ECHONL
337         {"echonl", ECHONL, MD_LIN},
338 #endif /* ECHONL */
339 #ifdef  NOFLSH
340         {"noflsh", NOFLSH, MD_LIN},
341 #endif /* NOFLSH */
342 #ifdef  TOSTOP
343         {"tostop", TOSTOP, MD_LIN},
344 #endif /* TOSTOP */
345 #ifdef  ECHOCTL
346         {"echoctl", ECHOCTL, MD_LIN},
347 #endif /* ECHOCTL */
348 #ifdef  ECHOPRT
349         {"echoprt", ECHOPRT, MD_LIN},
350 #endif /* ECHOPRT */
351 #ifdef  ECHOKE
352         {"echoke", ECHOKE, MD_LIN},
353 #endif /* ECHOKE */
354 #ifdef  DEFECHO
355         {"defecho", DEFECHO, MD_LIN},
356 #endif /* DEFECHO */
357 #ifdef  FLUSHO
358         {"flusho", FLUSHO, MD_LIN},
359 #endif /* FLUSHO */
360 #ifdef  PENDIN
361         {"pendin", PENDIN, MD_LIN},
362 #endif /* PENDIN */
363 #ifdef  IEXTEN
364         {"iexten", IEXTEN, MD_LIN},
365 #endif /* IEXTEN */
366 #ifdef  NOKERNINFO
367         {"nokerninfo", NOKERNINFO, MD_LIN},
368 #endif /* NOKERNINFO */
369 #ifdef  ALTWERASE
370         {"altwerase", ALTWERASE, MD_LIN},
371 #endif /* ALTWERASE */
372 #ifdef  EXTPROC
373         {"extproc", EXTPROC, MD_LIN},
374 #endif /* EXTPROC */
375
376 #if defined(VINTR)
377         {"intr", C_SH(C_INTR), MD_CHAR},
378 #endif /* VINTR */
379 #if defined(VQUIT)
380         {"quit", C_SH(C_QUIT), MD_CHAR},
381 #endif /* VQUIT */
382 #if defined(VERASE)
383         {"erase", C_SH(C_ERASE), MD_CHAR},
384 #endif /* VERASE */
385 #if defined(VKILL)
386         {"kill", C_SH(C_KILL), MD_CHAR},
387 #endif /* VKILL */
388 #if defined(VEOF)
389         {"eof", C_SH(C_EOF), MD_CHAR},
390 #endif /* VEOF */
391 #if defined(VEOL)
392         {"eol", C_SH(C_EOL), MD_CHAR},
393 #endif /* VEOL */
394 #if defined(VEOL2)
395         {"eol2", C_SH(C_EOL2), MD_CHAR},
396 #endif /* VEOL2 */
397 #if defined(VSWTCH)
398         {"swtch", C_SH(C_SWTCH), MD_CHAR},
399 #endif /* VSWTCH */
400 #if defined(VDSWTCH)
401         {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
402 #endif /* VDSWTCH */
403 #if defined(VERASE2)
404         {"erase2", C_SH(C_ERASE2), MD_CHAR},
405 #endif /* VERASE2 */
406 #if defined(VSTART)
407         {"start", C_SH(C_START), MD_CHAR},
408 #endif /* VSTART */
409 #if defined(VSTOP)
410         {"stop", C_SH(C_STOP), MD_CHAR},
411 #endif /* VSTOP */
412 #if defined(VWERASE)
413         {"werase", C_SH(C_WERASE), MD_CHAR},
414 #endif /* VWERASE */
415 #if defined(VSUSP)
416         {"susp", C_SH(C_SUSP), MD_CHAR},
417 #endif /* VSUSP */
418 #if defined(VDSUSP)
419         {"dsusp", C_SH(C_DSUSP), MD_CHAR},
420 #endif /* VDSUSP */
421 #if defined(VREPRINT)
422         {"reprint", C_SH(C_REPRINT), MD_CHAR},
423 #endif /* VREPRINT */
424 #if defined(VDISCARD)
425         {"discard", C_SH(C_DISCARD), MD_CHAR},
426 #endif /* VDISCARD */
427 #if defined(VLNEXT)
428         {"lnext", C_SH(C_LNEXT), MD_CHAR},
429 #endif /* VLNEXT */
430 #if defined(VSTATUS)
431         {"status", C_SH(C_STATUS), MD_CHAR},
432 #endif /* VSTATUS */
433 #if defined(VPAGE)
434         {"page", C_SH(C_PAGE), MD_CHAR},
435 #endif /* VPAGE */
436 #if defined(VPGOFF)
437         {"pgoff", C_SH(C_PGOFF), MD_CHAR},
438 #endif /* VPGOFF */
439 #if defined(VKILL2)
440         {"kill2", C_SH(C_KILL2), MD_CHAR},
441 #endif /* VKILL2 */
442 #if defined(VBRK)
443         {"brk", C_SH(C_BRK), MD_CHAR},
444 #endif /* VBRK */
445 #if defined(VMIN)
446         {"min", C_SH(C_MIN), MD_CHAR},
447 #endif /* VMIN */
448 #if defined(VTIME)
449         {"time", C_SH(C_TIME), MD_CHAR},
450 #endif /* VTIME */
451         {NULL, 0, -1},
452 };
453
454
455
456 #define tty__gettabs(td)        ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
457 #define tty__geteightbit(td)    (((td)->c_cflag & CSIZE) == CS8)
458 #define tty__cooked_mode(td)    ((td)->c_lflag & ICANON)
459
460 private int     tty_getty(EditLine *, struct termios *);
461 private int     tty_setty(EditLine *, int, const struct termios *);
462 private int     tty__getcharindex(int);
463 private void    tty__getchar(struct termios *, unsigned char *);
464 private void    tty__setchar(struct termios *, unsigned char *);
465 private speed_t tty__getspeed(struct termios *);
466 private int     tty_setup(EditLine *);
467 private void    tty_setup_flags(EditLine *, struct termios *, int);
468
469 #define t_qu    t_ts
470
471 /* tty_getty():
472  *      Wrapper for tcgetattr to handle EINTR
473  */
474 private int
475 tty_getty(EditLine *el, struct termios *t)
476 {
477         int rv;
478         while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
479                 continue;
480         return rv;
481 }
482
483 /* tty_setty():
484  *      Wrapper for tcsetattr to handle EINTR
485  */
486 private int
487 tty_setty(EditLine *el, int action, const struct termios *t)
488 {
489         int rv;
490         while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
491                 continue;
492         return rv;
493 }
494
495 /* tty_setup():
496  *      Get the tty parameters and initialize the editing state
497  */
498 private int
499 tty_setup(EditLine *el)
500 {
501         int rst = 1;
502
503         if (el->el_flags & EDIT_DISABLED)
504                 return 0;
505
506         if (el->el_tty.t_initialized)
507                 return -1;
508
509         if (!isatty(el->el_outfd)) {
510 #ifdef DEBUG_TTY
511                 (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
512                     strerror(errno));
513 #endif /* DEBUG_TTY */
514                 return -1;
515         }
516         if (tty_getty(el, &el->el_tty.t_or) == -1) {
517 #ifdef DEBUG_TTY
518                 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
519                     strerror(errno));
520 #endif /* DEBUG_TTY */
521                 return -1;
522         }
523         el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
524
525         el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
526         el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
527         el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
528
529         tty_setup_flags(el, &el->el_tty.t_ex, EX_IO);
530
531         /*
532          * Reset the tty chars to reasonable defaults
533          * If they are disabled, then enable them.
534          */
535         if (rst) {
536                 if (tty__cooked_mode(&el->el_tty.t_ts)) {
537                         tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
538                         /*
539                          * Don't affect CMIN and CTIME for the editor mode
540                          */
541                         for (rst = 0; rst < C_NCC - 2; rst++)
542                                 if (el->el_tty.t_c[TS_IO][rst] !=
543                                       el->el_tty.t_vdisable
544                                     && el->el_tty.t_c[ED_IO][rst] !=
545                                       el->el_tty.t_vdisable)
546                                         el->el_tty.t_c[ED_IO][rst] =
547                                             el->el_tty.t_c[TS_IO][rst];
548                         for (rst = 0; rst < C_NCC; rst++)
549                                 if (el->el_tty.t_c[TS_IO][rst] !=
550                                     el->el_tty.t_vdisable)
551                                         el->el_tty.t_c[EX_IO][rst] =
552                                             el->el_tty.t_c[TS_IO][rst];
553                 }
554                 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
555                 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
556 #ifdef DEBUG_TTY
557                         (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
558                             __func__, strerror(errno));
559 #endif /* DEBUG_TTY */
560                         return -1;
561                 }
562         }
563
564         tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
565
566         tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
567         tty_bind_char(el, 1);
568         el->el_tty.t_initialized = 1;
569         return 0;
570 }
571
572 protected int
573 tty_init(EditLine *el)
574 {
575
576         el->el_tty.t_mode = EX_IO;
577         el->el_tty.t_vdisable = _POSIX_VDISABLE;
578         el->el_tty.t_initialized = 0;
579         (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
580         (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
581         return tty_setup(el);
582 }
583
584
585 /* tty_end():
586  *      Restore the tty to its original settings
587  */
588 protected void
589 /*ARGSUSED*/
590 tty_end(EditLine *el)
591 {
592         if (el->el_flags & EDIT_DISABLED)
593                 return;
594
595         if (!el->el_tty.t_initialized)
596                 return;
597
598         if (tty_setty(el, TCSAFLUSH, &el->el_tty.t_or) == -1) {
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 private 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 private 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 private 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 private 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 protected 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         Char 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] = (Char)t_n[tp->nch];
919                 old[0] = (Char)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[UC(old[0])] = dmap[UC(old[0])];
925                 keymacro_clear(el, map, new);
926                 /* MAP_VI == 1, MAP_EMACS == 0... */
927                 map[UC(new[0])] = tp->bind[el->el_map.type];
928                 if (dalt) {
929                         keymacro_clear(el, alt, old);
930                         alt[UC(old[0])] = dalt[UC(old[0])];
931                         keymacro_clear(el, alt, new);
932                         alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
933                 }
934         }
935 }
936
937
938 private tcflag_t *
939 tty__get_flag(struct termios *t, int kind) {
940         switch (kind) {
941         case MD_INP:
942                 return &t->c_iflag;
943         case MD_OUT:
944                 return &t->c_oflag;
945         case MD_CTL:
946                 return &t->c_cflag;
947         case MD_LIN:
948                 return &t->c_lflag;
949         default:
950                 abort();
951                 /*NOTREACHED*/
952         }
953 }
954
955
956 private tcflag_t
957 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
958 {
959         f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
960         f |= el->el_tty.t_t[mode][kind].t_setmask;
961         return f;
962 }
963
964
965 private void
966 tty_update_flags(EditLine *el, int kind)
967 {
968         tcflag_t *tt, *ed, *ex;
969         tt = tty__get_flag(&el->el_tty.t_ts, kind);
970         ed = tty__get_flag(&el->el_tty.t_ed, kind);
971         ex = tty__get_flag(&el->el_tty.t_ex, kind);
972
973         if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
974                 *ed = tty_update_flag(el, *tt, ED_IO, kind);
975                 *ex = tty_update_flag(el, *tt, EX_IO, kind);
976         }
977 }
978
979
980 private void
981 tty_update_char(EditLine *el, int mode, int c) {
982         if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
983             && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
984                 el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
985         if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
986                 el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
987 }
988
989
990 /* tty_rawmode():
991  *      Set terminal into 1 character at a time mode.
992  */
993 protected int
994 tty_rawmode(EditLine *el)
995 {
996
997         if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
998                 return 0;
999
1000         if (el->el_flags & EDIT_DISABLED)
1001                 return 0;
1002
1003         if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1004 #ifdef DEBUG_TTY
1005                 (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
1006                     strerror(errno));
1007 #endif /* DEBUG_TTY */
1008                 return -1;
1009         }
1010         /*
1011          * We always keep up with the eight bit setting and the speed of the
1012          * tty. But we only believe changes that are made to cooked mode!
1013          */
1014         el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1015         el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1016
1017         if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1018             tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1019                 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1020                 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1021                 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1022                 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1023         }
1024         if (tty__cooked_mode(&el->el_tty.t_ts)) {
1025                 int i;
1026
1027                 for (i = MD_INP; i <= MD_LIN; i++)
1028                         tty_update_flags(el, i);
1029
1030                 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1031                         el->el_tty.t_tabs = 0;
1032                 else
1033                         el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1034
1035                 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1036                 /*
1037                  * Check if the user made any changes.
1038                  * If he did, then propagate the changes to the
1039                  * edit and execute data structures.
1040                  */
1041                 for (i = 0; i < C_NCC; i++)
1042                         if (el->el_tty.t_c[TS_IO][i] !=
1043                             el->el_tty.t_c[EX_IO][i])
1044                                 break;
1045
1046                 if (i != C_NCC) {
1047                         /*
1048                          * Propagate changes only to the unprotected
1049                          * chars that have been modified just now.
1050                          */
1051                         for (i = 0; i < C_NCC; i++)
1052                                 tty_update_char(el, ED_IO, i);
1053
1054                         tty_bind_char(el, 0);
1055                         tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1056
1057                         for (i = 0; i < C_NCC; i++)
1058                                 tty_update_char(el, EX_IO, i);
1059
1060                         tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1061                 }
1062         }
1063         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1064 #ifdef DEBUG_TTY
1065                 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1066                     strerror(errno));
1067 #endif /* DEBUG_TTY */
1068                 return -1;
1069         }
1070         el->el_tty.t_mode = ED_IO;
1071         return 0;
1072 }
1073
1074
1075 /* tty_cookedmode():
1076  *      Set the tty back to normal mode
1077  */
1078 protected int
1079 tty_cookedmode(EditLine *el)
1080 {                               /* set tty in normal setup */
1081
1082         if (el->el_tty.t_mode == EX_IO)
1083                 return 0;
1084
1085         if (el->el_flags & EDIT_DISABLED)
1086                 return 0;
1087
1088         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1089 #ifdef DEBUG_TTY
1090                 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1091                     strerror(errno));
1092 #endif /* DEBUG_TTY */
1093                 return -1;
1094         }
1095         el->el_tty.t_mode = EX_IO;
1096         return 0;
1097 }
1098
1099
1100 /* tty_quotemode():
1101  *      Turn on quote mode
1102  */
1103 protected int
1104 tty_quotemode(EditLine *el)
1105 {
1106         if (el->el_tty.t_mode == QU_IO)
1107                 return 0;
1108
1109         el->el_tty.t_qu = el->el_tty.t_ed;
1110
1111         tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1112
1113         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1114 #ifdef DEBUG_TTY
1115                 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1116                     strerror(errno));
1117 #endif /* DEBUG_TTY */
1118                 return -1;
1119         }
1120         el->el_tty.t_mode = QU_IO;
1121         return 0;
1122 }
1123
1124
1125 /* tty_noquotemode():
1126  *      Turn off quote mode
1127  */
1128 protected int
1129 tty_noquotemode(EditLine *el)
1130 {
1131
1132         if (el->el_tty.t_mode != QU_IO)
1133                 return 0;
1134         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1135 #ifdef DEBUG_TTY
1136                 (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1137                     strerror(errno));
1138 #endif /* DEBUG_TTY */
1139                 return -1;
1140         }
1141         el->el_tty.t_mode = ED_IO;
1142         return 0;
1143 }
1144
1145
1146 /* tty_stty():
1147  *      Stty builtin
1148  */
1149 protected int
1150 /*ARGSUSED*/
1151 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1152 {
1153         const ttymodes_t *m;
1154         char x;
1155         int aflag = 0;
1156         const Char *s, *d;
1157         char name[EL_BUFSIZ];
1158         struct termios *tios = &el->el_tty.t_ex;
1159         int z = EX_IO;
1160
1161         if (argv == NULL)
1162                 return -1;
1163         strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1164         name[sizeof(name) - 1] = '\0';
1165
1166         while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1167                 switch (argv[0][1]) {
1168                 case 'a':
1169                         aflag++;
1170                         argv++;
1171                         break;
1172                 case 'd':
1173                         argv++;
1174                         tios = &el->el_tty.t_ed;
1175                         z = ED_IO;
1176                         break;
1177                 case 'x':
1178                         argv++;
1179                         tios = &el->el_tty.t_ex;
1180                         z = EX_IO;
1181                         break;
1182                 case 'q':
1183                         argv++;
1184                         tios = &el->el_tty.t_ts;
1185                         z = QU_IO;
1186                         break;
1187                 default:
1188                         (void) fprintf(el->el_errfile,
1189                             "%s: Unknown switch `%lc'.\n",
1190                             name, (wint_t)argv[0][1]);
1191                         return -1;
1192                 }
1193
1194         if (!argv || !*argv) {
1195                 int i = -1;
1196                 size_t len = 0, st = 0, cu;
1197                 for (m = ttymodes; m->m_name; m++) {
1198                         if (m->m_type != i) {
1199                                 (void) fprintf(el->el_outfile, "%s%s",
1200                                     i != -1 ? "\n" : "",
1201                                     el->el_tty.t_t[z][m->m_type].t_name);
1202                                 i = m->m_type;
1203                                 st = len =
1204                                     strlen(el->el_tty.t_t[z][m->m_type].t_name);
1205                         }
1206                         if (i != -1) {
1207                             x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1208                                 ?  '+' : '\0';
1209
1210                             if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1211                                 x = '-';
1212                         } else {
1213                             x = '\0';
1214                         }
1215
1216                         if (x != '\0' || aflag) {
1217
1218                                 cu = strlen(m->m_name) + (x != '\0') + 1;
1219
1220                                 if (len + cu >=
1221                                     (size_t)el->el_terminal.t_size.h) {
1222                                         (void) fprintf(el->el_outfile, "\n%*s",
1223                                             (int)st, "");
1224                                         len = st + cu;
1225                                 } else
1226                                         len += cu;
1227
1228                                 if (x != '\0')
1229                                         (void) fprintf(el->el_outfile, "%c%s ",
1230                                             x, m->m_name);
1231                                 else
1232                                         (void) fprintf(el->el_outfile, "%s ",
1233                                             m->m_name);
1234                         }
1235                 }
1236                 (void) fprintf(el->el_outfile, "\n");
1237                 return 0;
1238         }
1239         while (argv && (s = *argv++)) {
1240                 const Char *p;
1241                 switch (*s) {
1242                 case '+':
1243                 case '-':
1244                         x = (char)*s++;
1245                         break;
1246                 default:
1247                         x = '\0';
1248                         break;
1249                 }
1250                 d = s;
1251                 p = Strchr(s, '=');
1252                 for (m = ttymodes; m->m_name; m++)
1253                         if ((p ? strncmp(m->m_name, ct_encode_string(d,
1254                             &el->el_scratch), (size_t)(p - d)) :
1255                             strcmp(m->m_name, ct_encode_string(d,
1256                             &el->el_scratch))) == 0 &&
1257                             (p == NULL || m->m_type == MD_CHAR))
1258                                 break;
1259
1260                 if (!m->m_name) {
1261                         (void) fprintf(el->el_errfile,
1262                             "%s: Invalid argument `" FSTR "'.\n", name, d);
1263                         return -1;
1264                 }
1265                 if (p) {
1266                         int c = ffs((int)m->m_value);
1267                         int v = *++p ? parse__escape(&p) :
1268                             el->el_tty.t_vdisable;
1269                         assert(c != 0);
1270                         c--;
1271                         c = tty__getcharindex(c);
1272                         assert(c != -1);
1273                         tios->c_cc[c] = (cc_t)v;
1274                         continue;
1275                 }
1276                 switch (x) {
1277                 case '+':
1278                         el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1279                         el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1280                         break;
1281                 case '-':
1282                         el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1283                         el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1284                         break;
1285                 default:
1286                         el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1287                         el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1288                         break;
1289                 }
1290         }
1291
1292         tty_setup_flags(el, tios, z);
1293         if (el->el_tty.t_mode == z) {
1294                 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1295 #ifdef DEBUG_TTY
1296                         (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1297                             __func__, strerror(errno));
1298 #endif /* DEBUG_TTY */
1299                         return -1;
1300                 }
1301         }
1302
1303         return 0;
1304 }
1305
1306
1307 #ifdef notyet
1308 /* tty_printchar():
1309  *      DEbugging routine to print the tty characters
1310  */
1311 private void
1312 tty_printchar(EditLine *el, unsigned char *s)
1313 {
1314         ttyperm_t *m;
1315         int i;
1316
1317         for (i = 0; i < C_NCC; i++) {
1318                 for (m = el->el_tty.t_t; m->m_name; m++)
1319                         if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1320                                 break;
1321                 if (m->m_name)
1322                         (void) fprintf(el->el_errfile, "%s ^%c ",
1323                             m->m_name, s[i] + 'A' - 1);
1324                 if (i % 5 == 0)
1325                         (void) fprintf(el->el_errfile, "\n");
1326         }
1327         (void) fprintf(el->el_errfile, "\n");
1328 }
1329 #endif /* notyet */
1330
1331
1332 private void
1333 tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1334 {
1335         int kind;
1336         for (kind = MD_INP; kind <= MD_LIN; kind++) {
1337                 tcflag_t *f = tty__get_flag(tios, kind);
1338                 *f = tty_update_flag(el, *f, mode, kind);
1339         }
1340 }