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