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