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