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