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