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