86f8b8a68faa467817d69c6e58587fa76e9d9db1
[dragonfly.git] / contrib / libedit / src / tty.c
1 /*      $NetBSD: tty.c,v 1.41 2011/10/04 15:27:04 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.41 2011/10/04 15:27:04 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,
503                     "tty_setup: isatty: %s\n", strerror(errno));
504 #endif /* DEBUG_TTY */
505                 return -1;
506         }
507         if (tty_getty(el, &el->el_tty.t_ed) == -1) {
508 #ifdef DEBUG_TTY
509                 (void) fprintf(el->el_errfile,
510                     "tty_setup: tty_getty: %s\n", 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;
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,
559                             "tty_setup: tty_setty: %s\n",
560                             strerror(errno));
561 #endif /* DEBUG_TTY */
562                         return -1;
563                 }
564         }
565
566         el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
567         el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
568
569         el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
570         el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
571
572         el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
573         el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
574
575         el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
576         el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
577
578         tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
579         tty_bind_char(el, 1);
580         return 0;
581 }
582
583 protected int
584 tty_init(EditLine *el)
585 {
586
587         el->el_tty.t_mode = EX_IO;
588         el->el_tty.t_vdisable = _POSIX_VDISABLE;
589         (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
590         (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
591         return tty_setup(el);
592 }
593
594
595 /* tty_end():
596  *      Restore the tty to its original settings
597  */
598 protected void
599 /*ARGSUSED*/
600 tty_end(EditLine *el __attribute__((__unused__)))
601 {
602
603         /* XXX: Maybe reset to an initial state? */
604 }
605
606
607 /* tty__getspeed():
608  *      Get the tty speed
609  */
610 private speed_t
611 tty__getspeed(struct termios *td)
612 {
613         speed_t spd;
614
615         if ((spd = cfgetispeed(td)) == 0)
616                 spd = cfgetospeed(td);
617         return spd;
618 }
619
620 /* tty__getspeed():
621  *      Return the index of the asked char in the c_cc array
622  */
623 private int
624 tty__getcharindex(int i)
625 {
626         switch (i) {
627 #ifdef VINTR
628         case C_INTR:
629                 return VINTR;
630 #endif /* VINTR */
631 #ifdef VQUIT
632         case C_QUIT:
633                 return VQUIT;
634 #endif /* VQUIT */
635 #ifdef VERASE
636         case C_ERASE:
637                 return VERASE;
638 #endif /* VERASE */
639 #ifdef VKILL
640         case C_KILL:
641                 return VKILL;
642 #endif /* VKILL */
643 #ifdef VEOF
644         case C_EOF:
645                 return VEOF;
646 #endif /* VEOF */
647 #ifdef VEOL
648         case C_EOL:
649                 return VEOL;
650 #endif /* VEOL */
651 #ifdef VEOL2
652         case C_EOL2:
653                 return VEOL2;
654 #endif /* VEOL2 */
655 #ifdef VSWTCH
656         case C_SWTCH:
657                 return VSWTCH;
658 #endif /* VSWTCH */
659 #ifdef VDSWTCH
660         case C_DSWTCH:
661                 return VDSWTCH;
662 #endif /* VDSWTCH */
663 #ifdef VERASE2
664         case C_ERASE2:
665                 return VERASE2;
666 #endif /* VERASE2 */
667 #ifdef VSTART
668         case C_START:
669                 return VSTART;
670 #endif /* VSTART */
671 #ifdef VSTOP
672         case C_STOP:
673                 return VSTOP;
674 #endif /* VSTOP */
675 #ifdef VWERASE
676         case C_WERASE:
677                 return VWERASE;
678 #endif /* VWERASE */
679 #ifdef VSUSP
680         case C_SUSP:
681                 return VSUSP;
682 #endif /* VSUSP */
683 #ifdef VDSUSP
684         case C_DSUSP:
685                 return VDSUSP;
686 #endif /* VDSUSP */
687 #ifdef VREPRINT
688         case C_REPRINT:
689                 return VREPRINT;
690 #endif /* VREPRINT */
691 #ifdef VDISCARD
692         case C_DISCARD:
693                 return VDISCARD;
694 #endif /* VDISCARD */
695 #ifdef VLNEXT
696         case C_LNEXT:
697                 return VLNEXT;
698 #endif /* VLNEXT */
699 #ifdef VSTATUS
700         case C_STATUS:
701                 return VSTATUS;
702 #endif /* VSTATUS */
703 #ifdef VPAGE
704         case C_PAGE:
705                 return VPAGE;
706 #endif /* VPAGE */
707 #ifdef VPGOFF
708         case C_PGOFF:
709                 return VPGOFF;
710 #endif /* VPGOFF */
711 #ifdef VKILL2
712         case C_KILL2:
713                 return VKILL2;
714 #endif /* KILL2 */
715 #ifdef VMIN
716         case C_MIN:
717                 return VMIN;
718 #endif /* VMIN */
719 #ifdef VTIME
720         case C_TIME:
721                 return VTIME;
722 #endif /* VTIME */
723         default:
724                 return -1;
725         }
726 }
727
728 /* tty__getchar():
729  *      Get the tty characters
730  */
731 private void
732 tty__getchar(struct termios *td, unsigned char *s)
733 {
734
735 #ifdef VINTR
736         s[C_INTR] = td->c_cc[VINTR];
737 #endif /* VINTR */
738 #ifdef VQUIT
739         s[C_QUIT] = td->c_cc[VQUIT];
740 #endif /* VQUIT */
741 #ifdef VERASE
742         s[C_ERASE] = td->c_cc[VERASE];
743 #endif /* VERASE */
744 #ifdef VKILL
745         s[C_KILL] = td->c_cc[VKILL];
746 #endif /* VKILL */
747 #ifdef VEOF
748         s[C_EOF] = td->c_cc[VEOF];
749 #endif /* VEOF */
750 #ifdef VEOL
751         s[C_EOL] = td->c_cc[VEOL];
752 #endif /* VEOL */
753 #ifdef VEOL2
754         s[C_EOL2] = td->c_cc[VEOL2];
755 #endif /* VEOL2 */
756 #ifdef VSWTCH
757         s[C_SWTCH] = td->c_cc[VSWTCH];
758 #endif /* VSWTCH */
759 #ifdef VDSWTCH
760         s[C_DSWTCH] = td->c_cc[VDSWTCH];
761 #endif /* VDSWTCH */
762 #ifdef VERASE2
763         s[C_ERASE2] = td->c_cc[VERASE2];
764 #endif /* VERASE2 */
765 #ifdef VSTART
766         s[C_START] = td->c_cc[VSTART];
767 #endif /* VSTART */
768 #ifdef VSTOP
769         s[C_STOP] = td->c_cc[VSTOP];
770 #endif /* VSTOP */
771 #ifdef VWERASE
772         s[C_WERASE] = td->c_cc[VWERASE];
773 #endif /* VWERASE */
774 #ifdef VSUSP
775         s[C_SUSP] = td->c_cc[VSUSP];
776 #endif /* VSUSP */
777 #ifdef VDSUSP
778         s[C_DSUSP] = td->c_cc[VDSUSP];
779 #endif /* VDSUSP */
780 #ifdef VREPRINT
781         s[C_REPRINT] = td->c_cc[VREPRINT];
782 #endif /* VREPRINT */
783 #ifdef VDISCARD
784         s[C_DISCARD] = td->c_cc[VDISCARD];
785 #endif /* VDISCARD */
786 #ifdef VLNEXT
787         s[C_LNEXT] = td->c_cc[VLNEXT];
788 #endif /* VLNEXT */
789 #ifdef VSTATUS
790         s[C_STATUS] = td->c_cc[VSTATUS];
791 #endif /* VSTATUS */
792 #ifdef VPAGE
793         s[C_PAGE] = td->c_cc[VPAGE];
794 #endif /* VPAGE */
795 #ifdef VPGOFF
796         s[C_PGOFF] = td->c_cc[VPGOFF];
797 #endif /* VPGOFF */
798 #ifdef VKILL2
799         s[C_KILL2] = td->c_cc[VKILL2];
800 #endif /* KILL2 */
801 #ifdef VMIN
802         s[C_MIN] = td->c_cc[VMIN];
803 #endif /* VMIN */
804 #ifdef VTIME
805         s[C_TIME] = td->c_cc[VTIME];
806 #endif /* VTIME */
807 }                               /* tty__getchar */
808
809
810 /* tty__setchar():
811  *      Set the tty characters
812  */
813 private void
814 tty__setchar(struct termios *td, unsigned char *s)
815 {
816
817 #ifdef VINTR
818         td->c_cc[VINTR] = s[C_INTR];
819 #endif /* VINTR */
820 #ifdef VQUIT
821         td->c_cc[VQUIT] = s[C_QUIT];
822 #endif /* VQUIT */
823 #ifdef VERASE
824         td->c_cc[VERASE] = s[C_ERASE];
825 #endif /* VERASE */
826 #ifdef VKILL
827         td->c_cc[VKILL] = s[C_KILL];
828 #endif /* VKILL */
829 #ifdef VEOF
830         td->c_cc[VEOF] = s[C_EOF];
831 #endif /* VEOF */
832 #ifdef VEOL
833         td->c_cc[VEOL] = s[C_EOL];
834 #endif /* VEOL */
835 #ifdef VEOL2
836         td->c_cc[VEOL2] = s[C_EOL2];
837 #endif /* VEOL2 */
838 #ifdef VSWTCH
839         td->c_cc[VSWTCH] = s[C_SWTCH];
840 #endif /* VSWTCH */
841 #ifdef VDSWTCH
842         td->c_cc[VDSWTCH] = s[C_DSWTCH];
843 #endif /* VDSWTCH */
844 #ifdef VERASE2
845         td->c_cc[VERASE2] = s[C_ERASE2];
846 #endif /* VERASE2 */
847 #ifdef VSTART
848         td->c_cc[VSTART] = s[C_START];
849 #endif /* VSTART */
850 #ifdef VSTOP
851         td->c_cc[VSTOP] = s[C_STOP];
852 #endif /* VSTOP */
853 #ifdef VWERASE
854         td->c_cc[VWERASE] = s[C_WERASE];
855 #endif /* VWERASE */
856 #ifdef VSUSP
857         td->c_cc[VSUSP] = s[C_SUSP];
858 #endif /* VSUSP */
859 #ifdef VDSUSP
860         td->c_cc[VDSUSP] = s[C_DSUSP];
861 #endif /* VDSUSP */
862 #ifdef VREPRINT
863         td->c_cc[VREPRINT] = s[C_REPRINT];
864 #endif /* VREPRINT */
865 #ifdef VDISCARD
866         td->c_cc[VDISCARD] = s[C_DISCARD];
867 #endif /* VDISCARD */
868 #ifdef VLNEXT
869         td->c_cc[VLNEXT] = s[C_LNEXT];
870 #endif /* VLNEXT */
871 #ifdef VSTATUS
872         td->c_cc[VSTATUS] = s[C_STATUS];
873 #endif /* VSTATUS */
874 #ifdef VPAGE
875         td->c_cc[VPAGE] = s[C_PAGE];
876 #endif /* VPAGE */
877 #ifdef VPGOFF
878         td->c_cc[VPGOFF] = s[C_PGOFF];
879 #endif /* VPGOFF */
880 #ifdef VKILL2
881         td->c_cc[VKILL2] = s[C_KILL2];
882 #endif /* VKILL2 */
883 #ifdef VMIN
884         td->c_cc[VMIN] = s[C_MIN];
885 #endif /* VMIN */
886 #ifdef VTIME
887         td->c_cc[VTIME] = s[C_TIME];
888 #endif /* VTIME */
889 }                               /* tty__setchar */
890
891
892 /* tty_bind_char():
893  *      Rebind the editline functions
894  */
895 protected void
896 tty_bind_char(EditLine *el, int force)
897 {
898
899         unsigned char *t_n = el->el_tty.t_c[ED_IO];
900         unsigned char *t_o = el->el_tty.t_ed.c_cc;
901         Char new[2], old[2];
902         const ttymap_t *tp;
903         el_action_t *map, *alt;
904         const el_action_t *dmap, *dalt;
905         new[1] = old[1] = '\0';
906
907         map = el->el_map.key;
908         alt = el->el_map.alt;
909         if (el->el_map.type == MAP_VI) {
910                 dmap = el->el_map.vii;
911                 dalt = el->el_map.vic;
912         } else {
913                 dmap = el->el_map.emacs;
914                 dalt = NULL;
915         }
916
917         for (tp = tty_map; tp->nch != (Int)-1; tp++) {
918                 new[0] = t_n[tp->nch];
919                 old[0] = t_o[tp->och];
920                 if (new[0] == old[0] && !force)
921                         continue;
922                 /* Put the old default binding back, and set the new binding */
923                 keymacro_clear(el, map, old);
924                 map[UC(old[0])] = dmap[UC(old[0])];
925                 keymacro_clear(el, map, new);
926                 /* MAP_VI == 1, MAP_EMACS == 0... */
927                 map[UC(new[0])] = tp->bind[el->el_map.type];
928                 if (dalt) {
929                         keymacro_clear(el, alt, old);
930                         alt[UC(old[0])] = dalt[UC(old[0])];
931                         keymacro_clear(el, alt, new);
932                         alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
933                 }
934         }
935 }
936
937
938 /* tty_rawmode():
939  *      Set terminal into 1 character at a time mode.
940  */
941 protected int
942 tty_rawmode(EditLine *el)
943 {
944
945         if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
946                 return 0;
947
948         if (el->el_flags & EDIT_DISABLED)
949                 return 0;
950
951         if (tty_getty(el, &el->el_tty.t_ts) == -1) {
952 #ifdef DEBUG_TTY
953                 (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
954                     strerror(errno));
955 #endif /* DEBUG_TTY */
956                 return -1;
957         }
958         /*
959          * We always keep up with the eight bit setting and the speed of the
960          * tty. But we only believe changes that are made to cooked mode!
961          */
962         el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
963         el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
964
965         if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
966             tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
967                 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
968                 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
969                 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
970                 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
971         }
972         if (tty__cooked_mode(&el->el_tty.t_ts)) {
973                 if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
974                         el->el_tty.t_ex.c_cflag =
975                             el->el_tty.t_ts.c_cflag;
976                         el->el_tty.t_ex.c_cflag &=
977                             ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
978                         el->el_tty.t_ex.c_cflag |=
979                             el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
980
981                         el->el_tty.t_ed.c_cflag =
982                             el->el_tty.t_ts.c_cflag;
983                         el->el_tty.t_ed.c_cflag &=
984                             ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
985                         el->el_tty.t_ed.c_cflag |=
986                             el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
987                 }
988                 if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
989                     (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
990                         el->el_tty.t_ex.c_lflag =
991                             el->el_tty.t_ts.c_lflag;
992                         el->el_tty.t_ex.c_lflag &=
993                             ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
994                         el->el_tty.t_ex.c_lflag |=
995                             el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
996
997                         el->el_tty.t_ed.c_lflag =
998                             el->el_tty.t_ts.c_lflag;
999                         el->el_tty.t_ed.c_lflag &=
1000                             ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
1001                         el->el_tty.t_ed.c_lflag |=
1002                             el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
1003                 }
1004                 if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
1005                     (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
1006                         el->el_tty.t_ex.c_iflag =
1007                             el->el_tty.t_ts.c_iflag;
1008                         el->el_tty.t_ex.c_iflag &=
1009                             ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
1010                         el->el_tty.t_ex.c_iflag |=
1011                             el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
1012
1013                         el->el_tty.t_ed.c_iflag =
1014                             el->el_tty.t_ts.c_iflag;
1015                         el->el_tty.t_ed.c_iflag &=
1016                             ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
1017                         el->el_tty.t_ed.c_iflag |=
1018                             el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
1019                 }
1020                 if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
1021                     (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
1022                         el->el_tty.t_ex.c_oflag =
1023                             el->el_tty.t_ts.c_oflag;
1024                         el->el_tty.t_ex.c_oflag &=
1025                             ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
1026                         el->el_tty.t_ex.c_oflag |=
1027                             el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
1028
1029                         el->el_tty.t_ed.c_oflag =
1030                             el->el_tty.t_ts.c_oflag;
1031                         el->el_tty.t_ed.c_oflag &=
1032                             ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1033                         el->el_tty.t_ed.c_oflag |=
1034                             el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1035                 }
1036                 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1037                         el->el_tty.t_tabs = 0;
1038                 else
1039                         el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1040
1041                 {
1042                         int i;
1043
1044                         tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1045                         /*
1046                          * Check if the user made any changes.
1047                          * If he did, then propagate the changes to the
1048                          * edit and execute data structures.
1049                          */
1050                         for (i = 0; i < C_NCC; i++)
1051                                 if (el->el_tty.t_c[TS_IO][i] !=
1052                                     el->el_tty.t_c[EX_IO][i])
1053                                         break;
1054
1055                         if (i != C_NCC) {
1056                                 /*
1057                                  * Propagate changes only to the unprotected
1058                                  * chars that have been modified just now.
1059                                  */
1060                                 for (i = 0; i < C_NCC; i++) {
1061                                         if (!((el->el_tty.t_t[ED_IO][MD_CHAR].t_setmask & C_SH(i)))
1062                                             && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1063                                                 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1064                                         if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1065                                                 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1066                                 }
1067                                 tty_bind_char(el, 0);
1068                                 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1069
1070                                 for (i = 0; i < C_NCC; i++) {
1071                                         if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1072                                             && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1073                                                 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1074                                         if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1075                                                 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1076                                 }
1077                                 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1078                         }
1079                 }
1080         }
1081         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1082 #ifdef DEBUG_TTY
1083                 (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1084                     strerror(errno));
1085 #endif /* DEBUG_TTY */
1086                 return -1;
1087         }
1088         el->el_tty.t_mode = ED_IO;
1089         return 0;
1090 }
1091
1092
1093 /* tty_cookedmode():
1094  *      Set the tty back to normal mode
1095  */
1096 protected int
1097 tty_cookedmode(EditLine *el)
1098 {                               /* set tty in normal setup */
1099
1100         if (el->el_tty.t_mode == EX_IO)
1101                 return 0;
1102
1103         if (el->el_flags & EDIT_DISABLED)
1104                 return 0;
1105
1106         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1107 #ifdef DEBUG_TTY
1108                 (void) fprintf(el->el_errfile,
1109                     "tty_cookedmode: tty_setty: %s\n",
1110                     strerror(errno));
1111 #endif /* DEBUG_TTY */
1112                 return -1;
1113         }
1114         el->el_tty.t_mode = EX_IO;
1115         return 0;
1116 }
1117
1118
1119 /* tty_quotemode():
1120  *      Turn on quote mode
1121  */
1122 protected int
1123 tty_quotemode(EditLine *el)
1124 {
1125         if (el->el_tty.t_mode == QU_IO)
1126                 return 0;
1127
1128         el->el_tty.t_qu = el->el_tty.t_ed;
1129
1130         el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1131         el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1132
1133         el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1134         el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1135
1136         el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1137         el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1138
1139         el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1140         el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1141
1142         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1143 #ifdef DEBUG_TTY
1144                 (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1145                     strerror(errno));
1146 #endif /* DEBUG_TTY */
1147                 return -1;
1148         }
1149         el->el_tty.t_mode = QU_IO;
1150         return 0;
1151 }
1152
1153
1154 /* tty_noquotemode():
1155  *      Turn off quote mode
1156  */
1157 protected int
1158 tty_noquotemode(EditLine *el)
1159 {
1160
1161         if (el->el_tty.t_mode != QU_IO)
1162                 return 0;
1163         if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1164 #ifdef DEBUG_TTY
1165                 (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1166                     strerror(errno));
1167 #endif /* DEBUG_TTY */
1168                 return -1;
1169         }
1170         el->el_tty.t_mode = ED_IO;
1171         return 0;
1172 }
1173
1174
1175 /* tty_stty():
1176  *      Stty builtin
1177  */
1178 protected int
1179 /*ARGSUSED*/
1180 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1181 {
1182         const ttymodes_t *m;
1183         char x;
1184         int aflag = 0;
1185         const Char *s, *d;
1186         char name[EL_BUFSIZ];
1187         struct termios *tios = &el->el_tty.t_ex;
1188         int z = EX_IO;
1189
1190         if (argv == NULL)
1191                 return -1;
1192         strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1193         name[sizeof(name) - 1] = '\0';
1194
1195         while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1196                 switch (argv[0][1]) {
1197                 case 'a':
1198                         aflag++;
1199                         argv++;
1200                         break;
1201                 case 'd':
1202                         argv++;
1203                         tios = &el->el_tty.t_ed;
1204                         z = ED_IO;
1205                         break;
1206                 case 'x':
1207                         argv++;
1208                         tios = &el->el_tty.t_ex;
1209                         z = EX_IO;
1210                         break;
1211                 case 'q':
1212                         argv++;
1213                         tios = &el->el_tty.t_ts;
1214                         z = QU_IO;
1215                         break;
1216                 default:
1217                         (void) fprintf(el->el_errfile,
1218                             "%s: Unknown switch `%c'.\n",
1219                             name, argv[0][1]);
1220                         return -1;
1221                 }
1222
1223         if (!argv || !*argv) {
1224                 int i = -1;
1225                 size_t len = 0, st = 0, cu;
1226                 for (m = ttymodes; m->m_name; m++) {
1227                         if (m->m_type != i) {
1228                                 (void) fprintf(el->el_outfile, "%s%s",
1229                                     i != -1 ? "\n" : "",
1230                                     el->el_tty.t_t[z][m->m_type].t_name);
1231                                 i = m->m_type;
1232                                 st = len =
1233                                     strlen(el->el_tty.t_t[z][m->m_type].t_name);
1234                         }
1235                         if (i != -1) {
1236                             x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1237                                 ?  '+' : '\0';
1238
1239                             if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1240                                 x = '-';
1241                         } else {
1242                             x = '\0';
1243                         }
1244
1245                         if (x != '\0' || aflag) {
1246
1247                                 cu = strlen(m->m_name) + (x != '\0') + 1;
1248
1249                                 if (len + cu >= (size_t)el->el_terminal.t_size.h) {
1250                                         (void) fprintf(el->el_outfile, "\n%*s",
1251                                             (int)st, "");
1252                                         len = st + cu;
1253                                 } else
1254                                         len += cu;
1255
1256                                 if (x != '\0')
1257                                         (void) fprintf(el->el_outfile, "%c%s ",
1258                                             x, m->m_name);
1259                                 else
1260                                         (void) fprintf(el->el_outfile, "%s ",
1261                                             m->m_name);
1262                         }
1263                 }
1264                 (void) fprintf(el->el_outfile, "\n");
1265                 return 0;
1266         }
1267         while (argv && (s = *argv++)) {
1268                 const Char *p;
1269                 switch (*s) {
1270                 case '+':
1271                 case '-':
1272                         x = (char)*s++;
1273                         break;
1274                 default:
1275                         x = '\0';
1276                         break;
1277                 }
1278                 d = s;
1279                 p = Strchr(s, '=');
1280                 for (m = ttymodes; m->m_name; m++)
1281                         if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) :
1282                             strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 &&
1283                             (p == NULL || m->m_type == MD_CHAR))
1284                                 break;
1285
1286                 if (!m->m_name) {
1287                         (void) fprintf(el->el_errfile,
1288                             "%s: Invalid argument `" FSTR "'.\n", name, d);
1289                         return -1;
1290                 }
1291                 if (p) {
1292                         int c = ffs((int)m->m_value);
1293                         int v = *++p ? parse__escape(&p) :
1294                             el->el_tty.t_vdisable;
1295                         assert(c != 0);
1296                         c--;
1297                         c = tty__getcharindex(c);
1298                         assert(c != -1);
1299                         tios->c_cc[c] = (cc_t)v;
1300                         continue;
1301                 }
1302                 switch (x) {
1303                 case '+':
1304                         el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1305                         el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1306                         break;
1307                 case '-':
1308                         el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1309                         el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1310                         break;
1311                 default:
1312                         el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1313                         el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1314                         break;
1315                 }
1316         }
1317
1318         if (el->el_tty.t_mode == z) {
1319                 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1320 #ifdef DEBUG_TTY
1321                         (void) fprintf(el->el_errfile,
1322                             "tty_stty: tty_setty: %s\n", strerror(errno));
1323 #endif /* DEBUG_TTY */
1324                         return -1;
1325                 }
1326         }
1327
1328         return 0;
1329 }
1330
1331
1332 #ifdef notyet
1333 /* tty_printchar():
1334  *      DEbugging routine to print the tty characters
1335  */
1336 private void
1337 tty_printchar(EditLine *el, unsigned char *s)
1338 {
1339         ttyperm_t *m;
1340         int i;
1341
1342         for (i = 0; i < C_NCC; i++) {
1343                 for (m = el->el_tty.t_t; m->m_name; m++)
1344                         if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1345                                 break;
1346                 if (m->m_name)
1347                         (void) fprintf(el->el_errfile, "%s ^%c ",
1348                             m->m_name, s[i] + 'A' - 1);
1349                 if (i % 5 == 0)
1350                         (void) fprintf(el->el_errfile, "\n");
1351         }
1352         (void) fprintf(el->el_errfile, "\n");
1353 }
1354 #endif /* notyet */