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