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