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