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