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