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