tty.c revision 1.38 1 /* $NetBSD: tty.c,v 1.38 2011/07/29 15:16:33 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.38 2011/07/29 15:16:33 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 {-1, -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 #ifdef notdef
566 else
567 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
568 #endif
569
570 el->el_tty.t_ed.c_iflag &= ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
571 el->el_tty.t_ed.c_iflag |= el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
572
573 el->el_tty.t_ed.c_oflag &= ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
574 el->el_tty.t_ed.c_oflag |= el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
575
576 el->el_tty.t_ed.c_cflag &= ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
577 el->el_tty.t_ed.c_cflag |= el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
578
579 el->el_tty.t_ed.c_lflag &= ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
580 el->el_tty.t_ed.c_lflag |= el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
581
582 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
583 tty_bind_char(el, 1);
584 return 0;
585 }
586
587 protected int
588 tty_init(EditLine *el)
589 {
590
591 el->el_tty.t_mode = EX_IO;
592 el->el_tty.t_vdisable = _POSIX_VDISABLE;
593 (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
594 (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
595 return tty_setup(el);
596 }
597
598
599 /* tty_end():
600 * Restore the tty to its original settings
601 */
602 protected void
603 /*ARGSUSED*/
604 tty_end(EditLine *el __attribute__((__unused__)))
605 {
606
607 /* XXX: Maybe reset to an initial state? */
608 }
609
610
611 /* tty__getspeed():
612 * Get the tty speed
613 */
614 private speed_t
615 tty__getspeed(struct termios *td)
616 {
617 speed_t spd;
618
619 if ((spd = cfgetispeed(td)) == 0)
620 spd = cfgetospeed(td);
621 return spd;
622 }
623
624 /* tty__getspeed():
625 * Return the index of the asked char in the c_cc array
626 */
627 private int
628 tty__getcharindex(int i)
629 {
630 switch (i) {
631 #ifdef VINTR
632 case C_INTR:
633 return VINTR;
634 #endif /* VINTR */
635 #ifdef VQUIT
636 case C_QUIT:
637 return VQUIT;
638 #endif /* VQUIT */
639 #ifdef VERASE
640 case C_ERASE:
641 return VERASE;
642 #endif /* VERASE */
643 #ifdef VKILL
644 case C_KILL:
645 return VKILL;
646 #endif /* VKILL */
647 #ifdef VEOF
648 case C_EOF:
649 return VEOF;
650 #endif /* VEOF */
651 #ifdef VEOL
652 case C_EOL:
653 return VEOL;
654 #endif /* VEOL */
655 #ifdef VEOL2
656 case C_EOL2:
657 return VEOL2;
658 #endif /* VEOL2 */
659 #ifdef VSWTCH
660 case C_SWTCH:
661 return VSWTCH;
662 #endif /* VSWTCH */
663 #ifdef VDSWTCH
664 case C_DSWTCH:
665 return VDSWTCH;
666 #endif /* VDSWTCH */
667 #ifdef VERASE2
668 case C_ERASE2:
669 return VERASE2;
670 #endif /* VERASE2 */
671 #ifdef VSTART
672 case C_START:
673 return VSTART;
674 #endif /* VSTART */
675 #ifdef VSTOP
676 case C_STOP:
677 return VSTOP;
678 #endif /* VSTOP */
679 #ifdef VWERASE
680 case C_WERASE:
681 return VWERASE;
682 #endif /* VWERASE */
683 #ifdef VSUSP
684 case C_SUSP:
685 return VSUSP;
686 #endif /* VSUSP */
687 #ifdef VDSUSP
688 case C_DSUSP:
689 return VDSUSP;
690 #endif /* VDSUSP */
691 #ifdef VREPRINT
692 case C_REPRINT:
693 return VREPRINT;
694 #endif /* VREPRINT */
695 #ifdef VDISCARD
696 case C_DISCARD:
697 return VDISCARD;
698 #endif /* VDISCARD */
699 #ifdef VLNEXT
700 case C_LNEXT:
701 return VLNEXT;
702 #endif /* VLNEXT */
703 #ifdef VSTATUS
704 case C_STATUS:
705 return VSTATUS;
706 #endif /* VSTATUS */
707 #ifdef VPAGE
708 case C_PAGE:
709 return VPAGE;
710 #endif /* VPAGE */
711 #ifdef VPGOFF
712 case C_PGOFF:
713 return VPGOFF;
714 #endif /* VPGOFF */
715 #ifdef VKILL2
716 case C_KILL2:
717 return VKILL2;
718 #endif /* KILL2 */
719 #ifdef VMIN
720 case C_MIN:
721 return VMIN;
722 #endif /* VMIN */
723 #ifdef VTIME
724 case C_TIME:
725 return VTIME;
726 #endif /* VTIME */
727 default:
728 return -1;
729 }
730 }
731
732 /* tty__getchar():
733 * Get the tty characters
734 */
735 private void
736 tty__getchar(struct termios *td, unsigned char *s)
737 {
738
739 #ifdef VINTR
740 s[C_INTR] = td->c_cc[VINTR];
741 #endif /* VINTR */
742 #ifdef VQUIT
743 s[C_QUIT] = td->c_cc[VQUIT];
744 #endif /* VQUIT */
745 #ifdef VERASE
746 s[C_ERASE] = td->c_cc[VERASE];
747 #endif /* VERASE */
748 #ifdef VKILL
749 s[C_KILL] = td->c_cc[VKILL];
750 #endif /* VKILL */
751 #ifdef VEOF
752 s[C_EOF] = td->c_cc[VEOF];
753 #endif /* VEOF */
754 #ifdef VEOL
755 s[C_EOL] = td->c_cc[VEOL];
756 #endif /* VEOL */
757 #ifdef VEOL2
758 s[C_EOL2] = td->c_cc[VEOL2];
759 #endif /* VEOL2 */
760 #ifdef VSWTCH
761 s[C_SWTCH] = td->c_cc[VSWTCH];
762 #endif /* VSWTCH */
763 #ifdef VDSWTCH
764 s[C_DSWTCH] = td->c_cc[VDSWTCH];
765 #endif /* VDSWTCH */
766 #ifdef VERASE2
767 s[C_ERASE2] = td->c_cc[VERASE2];
768 #endif /* VERASE2 */
769 #ifdef VSTART
770 s[C_START] = td->c_cc[VSTART];
771 #endif /* VSTART */
772 #ifdef VSTOP
773 s[C_STOP] = td->c_cc[VSTOP];
774 #endif /* VSTOP */
775 #ifdef VWERASE
776 s[C_WERASE] = td->c_cc[VWERASE];
777 #endif /* VWERASE */
778 #ifdef VSUSP
779 s[C_SUSP] = td->c_cc[VSUSP];
780 #endif /* VSUSP */
781 #ifdef VDSUSP
782 s[C_DSUSP] = td->c_cc[VDSUSP];
783 #endif /* VDSUSP */
784 #ifdef VREPRINT
785 s[C_REPRINT] = td->c_cc[VREPRINT];
786 #endif /* VREPRINT */
787 #ifdef VDISCARD
788 s[C_DISCARD] = td->c_cc[VDISCARD];
789 #endif /* VDISCARD */
790 #ifdef VLNEXT
791 s[C_LNEXT] = td->c_cc[VLNEXT];
792 #endif /* VLNEXT */
793 #ifdef VSTATUS
794 s[C_STATUS] = td->c_cc[VSTATUS];
795 #endif /* VSTATUS */
796 #ifdef VPAGE
797 s[C_PAGE] = td->c_cc[VPAGE];
798 #endif /* VPAGE */
799 #ifdef VPGOFF
800 s[C_PGOFF] = td->c_cc[VPGOFF];
801 #endif /* VPGOFF */
802 #ifdef VKILL2
803 s[C_KILL2] = td->c_cc[VKILL2];
804 #endif /* KILL2 */
805 #ifdef VMIN
806 s[C_MIN] = td->c_cc[VMIN];
807 #endif /* VMIN */
808 #ifdef VTIME
809 s[C_TIME] = td->c_cc[VTIME];
810 #endif /* VTIME */
811 } /* tty__getchar */
812
813
814 /* tty__setchar():
815 * Set the tty characters
816 */
817 private void
818 tty__setchar(struct termios *td, unsigned char *s)
819 {
820
821 #ifdef VINTR
822 td->c_cc[VINTR] = s[C_INTR];
823 #endif /* VINTR */
824 #ifdef VQUIT
825 td->c_cc[VQUIT] = s[C_QUIT];
826 #endif /* VQUIT */
827 #ifdef VERASE
828 td->c_cc[VERASE] = s[C_ERASE];
829 #endif /* VERASE */
830 #ifdef VKILL
831 td->c_cc[VKILL] = s[C_KILL];
832 #endif /* VKILL */
833 #ifdef VEOF
834 td->c_cc[VEOF] = s[C_EOF];
835 #endif /* VEOF */
836 #ifdef VEOL
837 td->c_cc[VEOL] = s[C_EOL];
838 #endif /* VEOL */
839 #ifdef VEOL2
840 td->c_cc[VEOL2] = s[C_EOL2];
841 #endif /* VEOL2 */
842 #ifdef VSWTCH
843 td->c_cc[VSWTCH] = s[C_SWTCH];
844 #endif /* VSWTCH */
845 #ifdef VDSWTCH
846 td->c_cc[VDSWTCH] = s[C_DSWTCH];
847 #endif /* VDSWTCH */
848 #ifdef VERASE2
849 td->c_cc[VERASE2] = s[C_ERASE2];
850 #endif /* VERASE2 */
851 #ifdef VSTART
852 td->c_cc[VSTART] = s[C_START];
853 #endif /* VSTART */
854 #ifdef VSTOP
855 td->c_cc[VSTOP] = s[C_STOP];
856 #endif /* VSTOP */
857 #ifdef VWERASE
858 td->c_cc[VWERASE] = s[C_WERASE];
859 #endif /* VWERASE */
860 #ifdef VSUSP
861 td->c_cc[VSUSP] = s[C_SUSP];
862 #endif /* VSUSP */
863 #ifdef VDSUSP
864 td->c_cc[VDSUSP] = s[C_DSUSP];
865 #endif /* VDSUSP */
866 #ifdef VREPRINT
867 td->c_cc[VREPRINT] = s[C_REPRINT];
868 #endif /* VREPRINT */
869 #ifdef VDISCARD
870 td->c_cc[VDISCARD] = s[C_DISCARD];
871 #endif /* VDISCARD */
872 #ifdef VLNEXT
873 td->c_cc[VLNEXT] = s[C_LNEXT];
874 #endif /* VLNEXT */
875 #ifdef VSTATUS
876 td->c_cc[VSTATUS] = s[C_STATUS];
877 #endif /* VSTATUS */
878 #ifdef VPAGE
879 td->c_cc[VPAGE] = s[C_PAGE];
880 #endif /* VPAGE */
881 #ifdef VPGOFF
882 td->c_cc[VPGOFF] = s[C_PGOFF];
883 #endif /* VPGOFF */
884 #ifdef VKILL2
885 td->c_cc[VKILL2] = s[C_KILL2];
886 #endif /* VKILL2 */
887 #ifdef VMIN
888 td->c_cc[VMIN] = s[C_MIN];
889 #endif /* VMIN */
890 #ifdef VTIME
891 td->c_cc[VTIME] = s[C_TIME];
892 #endif /* VTIME */
893 } /* tty__setchar */
894
895
896 /* tty_bind_char():
897 * Rebind the editline functions
898 */
899 protected void
900 tty_bind_char(EditLine *el, int force)
901 {
902
903 unsigned char *t_n = el->el_tty.t_c[ED_IO];
904 unsigned char *t_o = el->el_tty.t_ed.c_cc;
905 Char new[2], old[2];
906 const ttymap_t *tp;
907 el_action_t *map, *alt;
908 const el_action_t *dmap, *dalt;
909 new[1] = old[1] = '\0';
910
911 map = el->el_map.key;
912 alt = el->el_map.alt;
913 if (el->el_map.type == MAP_VI) {
914 dmap = el->el_map.vii;
915 dalt = el->el_map.vic;
916 } else {
917 dmap = el->el_map.emacs;
918 dalt = NULL;
919 }
920
921 for (tp = tty_map; tp->nch != -1; tp++) {
922 new[0] = t_n[tp->nch];
923 old[0] = t_o[tp->och];
924 if (new[0] == old[0] && !force)
925 continue;
926 /* Put the old default binding back, and set the new binding */
927 keymacro_clear(el, map, old);
928 map[UC(old[0])] = dmap[UC(old[0])];
929 keymacro_clear(el, map, new);
930 /* MAP_VI == 1, MAP_EMACS == 0... */
931 map[UC(new[0])] = tp->bind[el->el_map.type];
932 if (dalt) {
933 keymacro_clear(el, alt, old);
934 alt[UC(old[0])] = dalt[UC(old[0])];
935 keymacro_clear(el, alt, new);
936 alt[UC(new[0])] = tp->bind[el->el_map.type + 1];
937 }
938 }
939 }
940
941
942 /* tty_rawmode():
943 * Set terminal into 1 character at a time mode.
944 */
945 protected int
946 tty_rawmode(EditLine *el)
947 {
948
949 if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
950 return 0;
951
952 if (el->el_flags & EDIT_DISABLED)
953 return 0;
954
955 if (tty_getty(el, &el->el_tty.t_ts) == -1) {
956 #ifdef DEBUG_TTY
957 (void) fprintf(el->el_errfile, "tty_rawmode: tty_getty: %s\n",
958 strerror(errno));
959 #endif /* DEBUG_TTY */
960 return -1;
961 }
962 /*
963 * We always keep up with the eight bit setting and the speed of the
964 * tty. But we only believe changes that are made to cooked mode!
965 */
966 el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
967 el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
968
969 if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
970 tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
971 (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
972 (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
973 (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
974 (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
975 }
976 if (tty__cooked_mode(&el->el_tty.t_ts)) {
977 if (el->el_tty.t_ts.c_cflag != el->el_tty.t_ex.c_cflag) {
978 el->el_tty.t_ex.c_cflag =
979 el->el_tty.t_ts.c_cflag;
980 el->el_tty.t_ex.c_cflag &=
981 ~el->el_tty.t_t[EX_IO][MD_CTL].t_clrmask;
982 el->el_tty.t_ex.c_cflag |=
983 el->el_tty.t_t[EX_IO][MD_CTL].t_setmask;
984
985 el->el_tty.t_ed.c_cflag =
986 el->el_tty.t_ts.c_cflag;
987 el->el_tty.t_ed.c_cflag &=
988 ~el->el_tty.t_t[ED_IO][MD_CTL].t_clrmask;
989 el->el_tty.t_ed.c_cflag |=
990 el->el_tty.t_t[ED_IO][MD_CTL].t_setmask;
991 }
992 if ((el->el_tty.t_ts.c_lflag != el->el_tty.t_ex.c_lflag) &&
993 (el->el_tty.t_ts.c_lflag != el->el_tty.t_ed.c_lflag)) {
994 el->el_tty.t_ex.c_lflag =
995 el->el_tty.t_ts.c_lflag;
996 el->el_tty.t_ex.c_lflag &=
997 ~el->el_tty.t_t[EX_IO][MD_LIN].t_clrmask;
998 el->el_tty.t_ex.c_lflag |=
999 el->el_tty.t_t[EX_IO][MD_LIN].t_setmask;
1000
1001 el->el_tty.t_ed.c_lflag =
1002 el->el_tty.t_ts.c_lflag;
1003 el->el_tty.t_ed.c_lflag &=
1004 ~el->el_tty.t_t[ED_IO][MD_LIN].t_clrmask;
1005 el->el_tty.t_ed.c_lflag |=
1006 el->el_tty.t_t[ED_IO][MD_LIN].t_setmask;
1007 }
1008 if ((el->el_tty.t_ts.c_iflag != el->el_tty.t_ex.c_iflag) &&
1009 (el->el_tty.t_ts.c_iflag != el->el_tty.t_ed.c_iflag)) {
1010 el->el_tty.t_ex.c_iflag =
1011 el->el_tty.t_ts.c_iflag;
1012 el->el_tty.t_ex.c_iflag &=
1013 ~el->el_tty.t_t[EX_IO][MD_INP].t_clrmask;
1014 el->el_tty.t_ex.c_iflag |=
1015 el->el_tty.t_t[EX_IO][MD_INP].t_setmask;
1016
1017 el->el_tty.t_ed.c_iflag =
1018 el->el_tty.t_ts.c_iflag;
1019 el->el_tty.t_ed.c_iflag &=
1020 ~el->el_tty.t_t[ED_IO][MD_INP].t_clrmask;
1021 el->el_tty.t_ed.c_iflag |=
1022 el->el_tty.t_t[ED_IO][MD_INP].t_setmask;
1023 }
1024 if ((el->el_tty.t_ts.c_oflag != el->el_tty.t_ex.c_oflag) &&
1025 (el->el_tty.t_ts.c_oflag != el->el_tty.t_ed.c_oflag)) {
1026 el->el_tty.t_ex.c_oflag =
1027 el->el_tty.t_ts.c_oflag;
1028 el->el_tty.t_ex.c_oflag &=
1029 ~el->el_tty.t_t[EX_IO][MD_OUT].t_clrmask;
1030 el->el_tty.t_ex.c_oflag |=
1031 el->el_tty.t_t[EX_IO][MD_OUT].t_setmask;
1032
1033 el->el_tty.t_ed.c_oflag =
1034 el->el_tty.t_ts.c_oflag;
1035 el->el_tty.t_ed.c_oflag &=
1036 ~el->el_tty.t_t[ED_IO][MD_OUT].t_clrmask;
1037 el->el_tty.t_ed.c_oflag |=
1038 el->el_tty.t_t[ED_IO][MD_OUT].t_setmask;
1039 }
1040 if (tty__gettabs(&el->el_tty.t_ex) == 0)
1041 el->el_tty.t_tabs = 0;
1042 else
1043 el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1044
1045 {
1046 int i;
1047
1048 tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1049 /*
1050 * Check if the user made any changes.
1051 * If he did, then propagate the changes to the
1052 * edit and execute data structures.
1053 */
1054 for (i = 0; i < C_NCC; i++)
1055 if (el->el_tty.t_c[TS_IO][i] !=
1056 el->el_tty.t_c[EX_IO][i])
1057 break;
1058
1059 if (i != C_NCC) {
1060 /*
1061 * Propagate changes only to the unprotected
1062 * chars that have been modified just now.
1063 */
1064 for (i = 0; i < C_NCC; i++) {
1065 if (!((el->el_tty.t_t[ED_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[ED_IO][i] = el->el_tty.t_c[TS_IO][i];
1068 if (el->el_tty.t_t[ED_IO][MD_CHAR].t_clrmask & C_SH(i))
1069 el->el_tty.t_c[ED_IO][i] = el->el_tty.t_vdisable;
1070 }
1071 tty_bind_char(el, 0);
1072 tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1073
1074 for (i = 0; i < C_NCC; i++) {
1075 if (!((el->el_tty.t_t[EX_IO][MD_CHAR].t_setmask & C_SH(i)))
1076 && (el->el_tty.t_c[TS_IO][i] != el->el_tty.t_c[EX_IO][i]))
1077 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_c[TS_IO][i];
1078 if (el->el_tty.t_t[EX_IO][MD_CHAR].t_clrmask & C_SH(i))
1079 el->el_tty.t_c[EX_IO][i] = el->el_tty.t_vdisable;
1080 }
1081 tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1082 }
1083 }
1084 }
1085 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1086 #ifdef DEBUG_TTY
1087 (void) fprintf(el->el_errfile, "tty_rawmode: tty_setty: %s\n",
1088 strerror(errno));
1089 #endif /* DEBUG_TTY */
1090 return -1;
1091 }
1092 el->el_tty.t_mode = ED_IO;
1093 return 0;
1094 }
1095
1096
1097 /* tty_cookedmode():
1098 * Set the tty back to normal mode
1099 */
1100 protected int
1101 tty_cookedmode(EditLine *el)
1102 { /* set tty in normal setup */
1103
1104 if (el->el_tty.t_mode == EX_IO)
1105 return 0;
1106
1107 if (el->el_flags & EDIT_DISABLED)
1108 return 0;
1109
1110 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1111 #ifdef DEBUG_TTY
1112 (void) fprintf(el->el_errfile,
1113 "tty_cookedmode: tty_setty: %s\n",
1114 strerror(errno));
1115 #endif /* DEBUG_TTY */
1116 return -1;
1117 }
1118 el->el_tty.t_mode = EX_IO;
1119 return 0;
1120 }
1121
1122
1123 /* tty_quotemode():
1124 * Turn on quote mode
1125 */
1126 protected int
1127 tty_quotemode(EditLine *el)
1128 {
1129 if (el->el_tty.t_mode == QU_IO)
1130 return 0;
1131
1132 el->el_tty.t_qu = el->el_tty.t_ed;
1133
1134 el->el_tty.t_qu.c_iflag &= ~el->el_tty.t_t[QU_IO][MD_INP].t_clrmask;
1135 el->el_tty.t_qu.c_iflag |= el->el_tty.t_t[QU_IO][MD_INP].t_setmask;
1136
1137 el->el_tty.t_qu.c_oflag &= ~el->el_tty.t_t[QU_IO][MD_OUT].t_clrmask;
1138 el->el_tty.t_qu.c_oflag |= el->el_tty.t_t[QU_IO][MD_OUT].t_setmask;
1139
1140 el->el_tty.t_qu.c_cflag &= ~el->el_tty.t_t[QU_IO][MD_CTL].t_clrmask;
1141 el->el_tty.t_qu.c_cflag |= el->el_tty.t_t[QU_IO][MD_CTL].t_setmask;
1142
1143 el->el_tty.t_qu.c_lflag &= ~el->el_tty.t_t[QU_IO][MD_LIN].t_clrmask;
1144 el->el_tty.t_qu.c_lflag |= el->el_tty.t_t[QU_IO][MD_LIN].t_setmask;
1145
1146 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1147 #ifdef DEBUG_TTY
1148 (void) fprintf(el->el_errfile, "QuoteModeOn: tty_setty: %s\n",
1149 strerror(errno));
1150 #endif /* DEBUG_TTY */
1151 return -1;
1152 }
1153 el->el_tty.t_mode = QU_IO;
1154 return 0;
1155 }
1156
1157
1158 /* tty_noquotemode():
1159 * Turn off quote mode
1160 */
1161 protected int
1162 tty_noquotemode(EditLine *el)
1163 {
1164
1165 if (el->el_tty.t_mode != QU_IO)
1166 return 0;
1167 if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1168 #ifdef DEBUG_TTY
1169 (void) fprintf(el->el_errfile, "QuoteModeOff: tty_setty: %s\n",
1170 strerror(errno));
1171 #endif /* DEBUG_TTY */
1172 return -1;
1173 }
1174 el->el_tty.t_mode = ED_IO;
1175 return 0;
1176 }
1177
1178
1179 /* tty_stty():
1180 * Stty builtin
1181 */
1182 protected int
1183 /*ARGSUSED*/
1184 tty_stty(EditLine *el, int argc __attribute__((__unused__)), const Char **argv)
1185 {
1186 const ttymodes_t *m;
1187 char x;
1188 int aflag = 0;
1189 const Char *s, *d;
1190 char name[EL_BUFSIZ];
1191 struct termios *tios = &el->el_tty.t_ex;
1192 int z = EX_IO;
1193
1194 if (argv == NULL)
1195 return -1;
1196 strncpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1197 name[sizeof(name) - 1] = '\0';
1198
1199 while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1200 switch (argv[0][1]) {
1201 case 'a':
1202 aflag++;
1203 argv++;
1204 break;
1205 case 'd':
1206 argv++;
1207 tios = &el->el_tty.t_ed;
1208 z = ED_IO;
1209 break;
1210 case 'x':
1211 argv++;
1212 tios = &el->el_tty.t_ex;
1213 z = EX_IO;
1214 break;
1215 case 'q':
1216 argv++;
1217 tios = &el->el_tty.t_ts;
1218 z = QU_IO;
1219 break;
1220 default:
1221 (void) fprintf(el->el_errfile,
1222 "%s: Unknown switch `%c'.\n",
1223 name, argv[0][1]);
1224 return -1;
1225 }
1226
1227 if (!argv || !*argv) {
1228 int i = -1;
1229 size_t len = 0, st = 0, cu;
1230 for (m = ttymodes; m->m_name; m++) {
1231 if (m->m_type != i) {
1232 (void) fprintf(el->el_outfile, "%s%s",
1233 i != -1 ? "\n" : "",
1234 el->el_tty.t_t[z][m->m_type].t_name);
1235 i = m->m_type;
1236 st = len =
1237 strlen(el->el_tty.t_t[z][m->m_type].t_name);
1238 }
1239 if (i != -1) {
1240 x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1241 ? '+' : '\0';
1242 x = (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1243 ? '-' : x;
1244 } else {
1245 x = '\0';
1246 }
1247
1248 if (x != '\0' || aflag) {
1249
1250 cu = strlen(m->m_name) + (x != '\0') + 1;
1251
1252 if (len + cu >= (size_t)el->el_terminal.t_size.h) {
1253 (void) fprintf(el->el_outfile, "\n%*s",
1254 (int)st, "");
1255 len = st + cu;
1256 } else
1257 len += cu;
1258
1259 if (x != '\0')
1260 (void) fprintf(el->el_outfile, "%c%s ",
1261 x, m->m_name);
1262 else
1263 (void) fprintf(el->el_outfile, "%s ",
1264 m->m_name);
1265 }
1266 }
1267 (void) fprintf(el->el_outfile, "\n");
1268 return 0;
1269 }
1270 while (argv && (s = *argv++)) {
1271 const Char *p;
1272 switch (*s) {
1273 case '+':
1274 case '-':
1275 x = *s++;
1276 break;
1277 default:
1278 x = '\0';
1279 break;
1280 }
1281 d = s;
1282 p = Strchr(s, '=');
1283 for (m = ttymodes; m->m_name; m++)
1284 if ((p ? strncmp(m->m_name, ct_encode_string(d, &el->el_scratch), (size_t)(p - d)) :
1285 strcmp(m->m_name, ct_encode_string(d, &el->el_scratch))) == 0 &&
1286 (p == NULL || m->m_type == MD_CHAR))
1287 break;
1288
1289 if (!m->m_name) {
1290 (void) fprintf(el->el_errfile,
1291 "%s: Invalid argument `" FSTR "'.\n", name, d);
1292 return -1;
1293 }
1294 if (p) {
1295 int c = ffs((int)m->m_value);
1296 int v = *++p ? parse__escape(&p) :
1297 el->el_tty.t_vdisable;
1298 assert(c != 0);
1299 c--;
1300 c = tty__getcharindex(c);
1301 assert(c != -1);
1302 tios->c_cc[c] = v;
1303 continue;
1304 }
1305 switch (x) {
1306 case '+':
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 case '-':
1311 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1312 el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1313 break;
1314 default:
1315 el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1316 el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1317 break;
1318 }
1319 }
1320
1321 if (el->el_tty.t_mode == z) {
1322 if (tty_setty(el, TCSADRAIN, tios) == -1) {
1323 #ifdef DEBUG_TTY
1324 (void) fprintf(el->el_errfile,
1325 "tty_stty: tty_setty: %s\n", strerror(errno));
1326 #endif /* DEBUG_TTY */
1327 return -1;
1328 }
1329 }
1330
1331 return 0;
1332 }
1333
1334
1335 #ifdef notyet
1336 /* tty_printchar():
1337 * DEbugging routine to print the tty characters
1338 */
1339 private void
1340 tty_printchar(EditLine *el, unsigned char *s)
1341 {
1342 ttyperm_t *m;
1343 int i;
1344
1345 for (i = 0; i < C_NCC; i++) {
1346 for (m = el->el_tty.t_t; m->m_name; m++)
1347 if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1348 break;
1349 if (m->m_name)
1350 (void) fprintf(el->el_errfile, "%s ^%c ",
1351 m->m_name, s[i] + 'A' - 1);
1352 if (i % 5 == 0)
1353 (void) fprintf(el->el_errfile, "\n");
1354 }
1355 (void) fprintf(el->el_errfile, "\n");
1356 }
1357 #endif /* notyet */
1358