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