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