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