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