xref: /dragonfly/contrib/libedit/src/tty.c (revision 698e9e6cd5f042847de67460caaa3fde98cdfe99)
1 /*        $NetBSD: tty.c,v 1.70 2021/07/14 07:47:23 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.70 2021/07/14 07:47:23 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 <stdlib.h> /* for abort */
50 #include <string.h>
51 #include <strings.h>          /* for ffs */
52 #include <unistd.h> /* for isatty */
53 
54 #include "el.h"
55 #include "fcns.h"
56 #include "parse.h"
57 
58 typedef struct ttymodes_t {
59           const char *m_name;
60           unsigned int m_value;
61           int m_type;
62 }          ttymodes_t;
63 
64 typedef struct ttymap_t {
65           wint_t nch, och;    /* Internal and termio rep of chars */
66           el_action_t bind[3];          /* emacs, vi, and vi-cmd */
67 } ttymap_t;
68 
69 
70 static const ttyperm_t ttyperm = {
71           {
72                     {"iflag:", ICRNL, (INLCR | IGNCR)},
73                     {"oflag:", (OPOST | ONLCR), ONLRET},
74                     {"cflag:", 0, 0},
75                     {"lflag:", (ISIG | ICANON | ECHO | ECHOE | ECHOCTL | IEXTEN),
76                     (NOFLSH | ECHONL | EXTPROC | FLUSHO)},
77                     {"chars:", 0, 0},
78           },
79           {
80                     {"iflag:", (INLCR | ICRNL), IGNCR},
81                     {"oflag:", (OPOST | ONLCR), ONLRET},
82                     {"cflag:", 0, 0},
83                     {"lflag:", ISIG,
84                     (NOFLSH | ICANON | ECHO | ECHOK | ECHONL | EXTPROC | IEXTEN | FLUSHO)},
85                     {"chars:", (C_SH(C_MIN) | C_SH(C_TIME) | C_SH(C_SWTCH) | C_SH(C_DSWTCH) |
86                                   C_SH(C_SUSP) | C_SH(C_DSUSP) | C_SH(C_EOL) | C_SH(C_DISCARD) |
87                         C_SH(C_PGOFF) | C_SH(C_PAGE) | C_SH(C_STATUS)), 0}
88           },
89           {
90                     {"iflag:", 0, IXON | IXOFF | INLCR | ICRNL},
91                     {"oflag:", 0, 0},
92                     {"cflag:", 0, 0},
93                     {"lflag:", 0, ISIG | IEXTEN},
94                     {"chars:", 0, 0},
95           }
96 };
97 
98 static const ttychar_t ttychar = {
99           {
100                     CINTR, CQUIT, CERASE, CKILL,
101                     CEOF, CEOL, CEOL2, CSWTCH,
102                     CDSWTCH, CERASE2, CSTART, CSTOP,
103                     CWERASE, CSUSP, CDSUSP, CREPRINT,
104                     CDISCARD, CLNEXT, CSTATUS, CPAGE,
105                     CPGOFF, CKILL2, CBRK, CMIN,
106                     CTIME
107           },
108           {
109                     CINTR, CQUIT, CERASE, CKILL,
110                     _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
111                     _POSIX_VDISABLE, CERASE2, CSTART, CSTOP,
112                     _POSIX_VDISABLE, CSUSP, _POSIX_VDISABLE, _POSIX_VDISABLE,
113                     CDISCARD, _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE,
114                     _POSIX_VDISABLE, _POSIX_VDISABLE, _POSIX_VDISABLE, 1,
115                     0
116           },
117           {
118                     0, 0, 0, 0,
119                     0, 0, 0, 0,
120                     0, 0, 0, 0,
121                     0, 0, 0, 0,
122                     0, 0, 0, 0,
123                     0, 0, 0, 0,
124                     0
125           }
126 };
127 
128 static const ttymap_t tty_map[] = {
129 #ifdef VERASE
130           {C_ERASE, VERASE,
131           {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
132 #endif /* VERASE */
133 #ifdef VERASE2
134           {C_ERASE2, VERASE2,
135           {EM_DELETE_PREV_CHAR, VI_DELETE_PREV_CHAR, ED_PREV_CHAR}},
136 #endif /* VERASE2 */
137 #ifdef VKILL
138           {C_KILL, VKILL,
139           {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
140 #endif /* VKILL */
141 #ifdef VKILL2
142           {C_KILL2, VKILL2,
143           {EM_KILL_LINE, VI_KILL_LINE_PREV, ED_UNASSIGNED}},
144 #endif /* VKILL2 */
145 #ifdef VEOF
146           {C_EOF, VEOF,
147           {EM_DELETE_OR_LIST, VI_LIST_OR_EOF, ED_UNASSIGNED}},
148 #endif /* VEOF */
149 #ifdef VWERASE
150           {C_WERASE, VWERASE,
151           {ED_DELETE_PREV_WORD, ED_DELETE_PREV_WORD, ED_PREV_WORD}},
152 #endif /* VWERASE */
153 #ifdef VREPRINT
154           {C_REPRINT, VREPRINT,
155           {ED_REDISPLAY, ED_INSERT, ED_REDISPLAY}},
156 #endif /* VREPRINT */
157 #ifdef VLNEXT
158           {C_LNEXT, VLNEXT,
159           {ED_QUOTED_INSERT, ED_QUOTED_INSERT, ED_UNASSIGNED}},
160 #endif /* VLNEXT */
161           {(wint_t)-1, (wint_t)-1,
162           {ED_UNASSIGNED, ED_UNASSIGNED, ED_UNASSIGNED}}
163 };
164 
165 static const ttymodes_t ttymodes[] = {
166 #ifdef    IGNBRK
167           {"ignbrk", IGNBRK, MD_INP},
168 #endif /* IGNBRK */
169 #ifdef    BRKINT
170           {"brkint", BRKINT, MD_INP},
171 #endif /* BRKINT */
172 #ifdef    IGNPAR
173           {"ignpar", IGNPAR, MD_INP},
174 #endif /* IGNPAR */
175 #ifdef    PARMRK
176           {"parmrk", PARMRK, MD_INP},
177 #endif /* PARMRK */
178 #ifdef    INPCK
179           {"inpck", INPCK, MD_INP},
180 #endif /* INPCK */
181 #ifdef    ISTRIP
182           {"istrip", ISTRIP, MD_INP},
183 #endif /* ISTRIP */
184 #ifdef    INLCR
185           {"inlcr", INLCR, MD_INP},
186 #endif /* INLCR */
187 #ifdef    IGNCR
188           {"igncr", IGNCR, MD_INP},
189 #endif /* IGNCR */
190 #ifdef    ICRNL
191           {"icrnl", ICRNL, MD_INP},
192 #endif /* ICRNL */
193 #ifdef    IUCLC
194           {"iuclc", IUCLC, MD_INP},
195 #endif /* IUCLC */
196 #ifdef    IXON
197           {"ixon", IXON, MD_INP},
198 #endif /* IXON */
199 #ifdef    IXANY
200           {"ixany", IXANY, MD_INP},
201 #endif /* IXANY */
202 #ifdef    IXOFF
203           {"ixoff", IXOFF, MD_INP},
204 #endif /* IXOFF */
205 #ifdef  IMAXBEL
206           {"imaxbel", IMAXBEL, MD_INP},
207 #endif /* IMAXBEL */
208 
209 #ifdef    OPOST
210           {"opost", OPOST, MD_OUT},
211 #endif /* OPOST */
212 #ifdef    OLCUC
213           {"olcuc", OLCUC, MD_OUT},
214 #endif /* OLCUC */
215 #ifdef    ONLCR
216           {"onlcr", ONLCR, MD_OUT},
217 #endif /* ONLCR */
218 #ifdef    OCRNL
219           {"ocrnl", OCRNL, MD_OUT},
220 #endif /* OCRNL */
221 #ifdef    ONOCR
222           {"onocr", ONOCR, MD_OUT},
223 #endif /* ONOCR */
224 #ifdef ONOEOT
225           {"onoeot", ONOEOT, MD_OUT},
226 #endif /* ONOEOT */
227 #ifdef    ONLRET
228           {"onlret", ONLRET, MD_OUT},
229 #endif /* ONLRET */
230 #ifdef    OFILL
231           {"ofill", OFILL, MD_OUT},
232 #endif /* OFILL */
233 #ifdef    OFDEL
234           {"ofdel", OFDEL, MD_OUT},
235 #endif /* OFDEL */
236 #ifdef    NLDLY
237           {"nldly", NLDLY, MD_OUT},
238 #endif /* NLDLY */
239 #ifdef    CRDLY
240           {"crdly", CRDLY, MD_OUT},
241 #endif /* CRDLY */
242 #ifdef    TABDLY
243           {"tabdly", TABDLY, MD_OUT},
244 #endif /* TABDLY */
245 #ifdef    XTABS
246           {"xtabs", XTABS, MD_OUT},
247 #endif /* XTABS */
248 #ifdef    BSDLY
249           {"bsdly", BSDLY, MD_OUT},
250 #endif /* BSDLY */
251 #ifdef    VTDLY
252           {"vtdly", VTDLY, MD_OUT},
253 #endif /* VTDLY */
254 #ifdef    FFDLY
255           {"ffdly", FFDLY, MD_OUT},
256 #endif /* FFDLY */
257 #ifdef    PAGEOUT
258           {"pageout", PAGEOUT, MD_OUT},
259 #endif /* PAGEOUT */
260 #ifdef    WRAP
261           {"wrap", WRAP, MD_OUT},
262 #endif /* WRAP */
263 
264 #ifdef    CIGNORE
265           {"cignore", CIGNORE, MD_CTL},
266 #endif /* CBAUD */
267 #ifdef    CBAUD
268           {"cbaud", CBAUD, MD_CTL},
269 #endif /* CBAUD */
270 #ifdef    CSTOPB
271           {"cstopb", CSTOPB, MD_CTL},
272 #endif /* CSTOPB */
273 #ifdef    CREAD
274           {"cread", CREAD, MD_CTL},
275 #endif /* CREAD */
276 #ifdef    PARENB
277           {"parenb", PARENB, MD_CTL},
278 #endif /* PARENB */
279 #ifdef    PARODD
280           {"parodd", PARODD, MD_CTL},
281 #endif /* PARODD */
282 #ifdef    HUPCL
283           {"hupcl", HUPCL, MD_CTL},
284 #endif /* HUPCL */
285 #ifdef    CLOCAL
286           {"clocal", CLOCAL, MD_CTL},
287 #endif /* CLOCAL */
288 #ifdef    LOBLK
289           {"loblk", LOBLK, MD_CTL},
290 #endif /* LOBLK */
291 #ifdef    CIBAUD
292           {"cibaud", CIBAUD, MD_CTL},
293 #endif /* CIBAUD */
294 #ifdef CRTSCTS
295 #ifdef CCTS_OFLOW
296           {"ccts_oflow", CCTS_OFLOW, MD_CTL},
297 #else
298           {"crtscts", CRTSCTS, MD_CTL},
299 #endif /* CCTS_OFLOW */
300 #endif /* CRTSCTS */
301 #ifdef CRTS_IFLOW
302           {"crts_iflow", CRTS_IFLOW, MD_CTL},
303 #endif /* CRTS_IFLOW */
304 #ifdef CDTRCTS
305           {"cdtrcts", CDTRCTS, MD_CTL},
306 #endif /* CDTRCTS */
307 #ifdef MDMBUF
308           {"mdmbuf", MDMBUF, MD_CTL},
309 #endif /* MDMBUF */
310 #ifdef RCV1EN
311           {"rcv1en", RCV1EN, MD_CTL},
312 #endif /* RCV1EN */
313 #ifdef XMT1EN
314           {"xmt1en", XMT1EN, MD_CTL},
315 #endif /* XMT1EN */
316 
317 #ifdef    ISIG
318           {"isig", ISIG, MD_LIN},
319 #endif /* ISIG */
320 #ifdef    ICANON
321           {"icanon", ICANON, MD_LIN},
322 #endif /* ICANON */
323 #ifdef    XCASE
324           {"xcase", XCASE, MD_LIN},
325 #endif /* XCASE */
326 #ifdef    ECHO
327           {"echo", ECHO, MD_LIN},
328 #endif /* ECHO */
329 #ifdef    ECHOE
330           {"echoe", ECHOE, MD_LIN},
331 #endif /* ECHOE */
332 #ifdef    ECHOK
333           {"echok", ECHOK, MD_LIN},
334 #endif /* ECHOK */
335 #ifdef    ECHONL
336           {"echonl", ECHONL, MD_LIN},
337 #endif /* ECHONL */
338 #ifdef    NOFLSH
339           {"noflsh", NOFLSH, MD_LIN},
340 #endif /* NOFLSH */
341 #ifdef    TOSTOP
342           {"tostop", TOSTOP, MD_LIN},
343 #endif /* TOSTOP */
344 #ifdef    ECHOCTL
345           {"echoctl", ECHOCTL, MD_LIN},
346 #endif /* ECHOCTL */
347 #ifdef    ECHOPRT
348           {"echoprt", ECHOPRT, MD_LIN},
349 #endif /* ECHOPRT */
350 #ifdef    ECHOKE
351           {"echoke", ECHOKE, MD_LIN},
352 #endif /* ECHOKE */
353 #ifdef    DEFECHO
354           {"defecho", DEFECHO, MD_LIN},
355 #endif /* DEFECHO */
356 #ifdef    FLUSHO
357           {"flusho", FLUSHO, MD_LIN},
358 #endif /* FLUSHO */
359 #ifdef    PENDIN
360           {"pendin", PENDIN, MD_LIN},
361 #endif /* PENDIN */
362 #ifdef    IEXTEN
363           {"iexten", IEXTEN, MD_LIN},
364 #endif /* IEXTEN */
365 #ifdef    NOKERNINFO
366           {"nokerninfo", NOKERNINFO, MD_LIN},
367 #endif /* NOKERNINFO */
368 #ifdef    ALTWERASE
369           {"altwerase", ALTWERASE, MD_LIN},
370 #endif /* ALTWERASE */
371 #ifdef    EXTPROC
372           {"extproc", EXTPROC, MD_LIN},
373 #endif /* EXTPROC */
374 
375 #if defined(VINTR)
376           {"intr", C_SH(C_INTR), MD_CHAR},
377 #endif /* VINTR */
378 #if defined(VQUIT)
379           {"quit", C_SH(C_QUIT), MD_CHAR},
380 #endif /* VQUIT */
381 #if defined(VERASE)
382           {"erase", C_SH(C_ERASE), MD_CHAR},
383 #endif /* VERASE */
384 #if defined(VKILL)
385           {"kill", C_SH(C_KILL), MD_CHAR},
386 #endif /* VKILL */
387 #if defined(VEOF)
388           {"eof", C_SH(C_EOF), MD_CHAR},
389 #endif /* VEOF */
390 #if defined(VEOL)
391           {"eol", C_SH(C_EOL), MD_CHAR},
392 #endif /* VEOL */
393 #if defined(VEOL2)
394           {"eol2", C_SH(C_EOL2), MD_CHAR},
395 #endif /* VEOL2 */
396 #if defined(VSWTCH)
397           {"swtch", C_SH(C_SWTCH), MD_CHAR},
398 #endif /* VSWTCH */
399 #if defined(VDSWTCH)
400           {"dswtch", C_SH(C_DSWTCH), MD_CHAR},
401 #endif /* VDSWTCH */
402 #if defined(VERASE2)
403           {"erase2", C_SH(C_ERASE2), MD_CHAR},
404 #endif /* VERASE2 */
405 #if defined(VSTART)
406           {"start", C_SH(C_START), MD_CHAR},
407 #endif /* VSTART */
408 #if defined(VSTOP)
409           {"stop", C_SH(C_STOP), MD_CHAR},
410 #endif /* VSTOP */
411 #if defined(VWERASE)
412           {"werase", C_SH(C_WERASE), MD_CHAR},
413 #endif /* VWERASE */
414 #if defined(VSUSP)
415           {"susp", C_SH(C_SUSP), MD_CHAR},
416 #endif /* VSUSP */
417 #if defined(VDSUSP)
418           {"dsusp", C_SH(C_DSUSP), MD_CHAR},
419 #endif /* VDSUSP */
420 #if defined(VREPRINT)
421           {"reprint", C_SH(C_REPRINT), MD_CHAR},
422 #endif /* VREPRINT */
423 #if defined(VDISCARD)
424           {"discard", C_SH(C_DISCARD), MD_CHAR},
425 #endif /* VDISCARD */
426 #if defined(VLNEXT)
427           {"lnext", C_SH(C_LNEXT), MD_CHAR},
428 #endif /* VLNEXT */
429 #if defined(VSTATUS)
430           {"status", C_SH(C_STATUS), MD_CHAR},
431 #endif /* VSTATUS */
432 #if defined(VPAGE)
433           {"page", C_SH(C_PAGE), MD_CHAR},
434 #endif /* VPAGE */
435 #if defined(VPGOFF)
436           {"pgoff", C_SH(C_PGOFF), MD_CHAR},
437 #endif /* VPGOFF */
438 #if defined(VKILL2)
439           {"kill2", C_SH(C_KILL2), MD_CHAR},
440 #endif /* VKILL2 */
441 #if defined(VBRK)
442           {"brk", C_SH(C_BRK), MD_CHAR},
443 #endif /* VBRK */
444 #if defined(VMIN)
445           {"min", C_SH(C_MIN), MD_CHAR},
446 #endif /* VMIN */
447 #if defined(VTIME)
448           {"time", C_SH(C_TIME), MD_CHAR},
449 #endif /* VTIME */
450           {NULL, 0, -1},
451 };
452 
453 
454 
455 #define   tty__gettabs(td)    ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
456 #define   tty__geteightbit(td)          (((td)->c_cflag & CSIZE) == CS8)
457 #define   tty__cooked_mode(td)          ((td)->c_lflag & ICANON)
458 
459 static int          tty_getty(EditLine *, struct termios *);
460 static int          tty_setty(EditLine *, int, const struct termios *);
461 static int          tty__getcharindex(int);
462 static void         tty__getchar(struct termios *, unsigned char *);
463 static void         tty__setchar(struct termios *, unsigned char *);
464 static speed_t      tty__getspeed(struct termios *);
465 static int          tty_setup(EditLine *);
466 static void         tty_setup_flags(EditLine *, struct termios *, int);
467 
468 #define   t_qu      t_ts
469 
470 /* tty_getty():
471  *        Wrapper for tcgetattr to handle EINTR
472  */
473 static int
tty_getty(EditLine * el,struct termios * t)474 tty_getty(EditLine *el, struct termios *t)
475 {
476           int rv;
477           while ((rv = tcgetattr(el->el_infd, t)) == -1 && errno == EINTR)
478                     continue;
479           return rv;
480 }
481 
482 /* tty_setty():
483  *        Wrapper for tcsetattr to handle EINTR
484  */
485 static int
tty_setty(EditLine * el,int action,const struct termios * t)486 tty_setty(EditLine *el, int action, const struct termios *t)
487 {
488           int rv;
489           while ((rv = tcsetattr(el->el_infd, action, t)) == -1 && errno == EINTR)
490                     continue;
491           return rv;
492 }
493 
494 /* tty_setup():
495  *        Get the tty parameters and initialize the editing state
496  */
497 static int
tty_setup(EditLine * el)498 tty_setup(EditLine *el)
499 {
500           int rst = (el->el_flags & NO_RESET) == 0;
501 
502           if (el->el_flags & EDIT_DISABLED)
503                     return 0;
504 
505           if (el->el_tty.t_initialized)
506                     return -1;
507 
508           if (!isatty(el->el_outfd)) {
509 #ifdef DEBUG_TTY
510                     (void) fprintf(el->el_errfile, "%s: isatty: %s\n", __func__,
511                         strerror(errno));
512 #endif /* DEBUG_TTY */
513                     return -1;
514           }
515           if (tty_getty(el, &el->el_tty.t_or) == -1) {
516 #ifdef DEBUG_TTY
517                     (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
518                         strerror(errno));
519 #endif /* DEBUG_TTY */
520                     return -1;
521           }
522           el->el_tty.t_ts = el->el_tty.t_ex = el->el_tty.t_ed = el->el_tty.t_or;
523 
524           el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ex);
525           el->el_tty.t_tabs = tty__gettabs(&el->el_tty.t_ex);
526           el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ex);
527 
528           tty_setup_flags(el, &el->el_tty.t_ex, EX_IO);
529 
530           /*
531          * Reset the tty chars to reasonable defaults
532          * If they are disabled, then enable them.
533          */
534           if (rst) {
535                     if (tty__cooked_mode(&el->el_tty.t_ts)) {
536                               tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
537                               /*
538                            * Don't affect CMIN and CTIME for the editor mode
539                            */
540                               for (rst = 0; rst < C_NCC - 2; rst++)
541                                         if (el->el_tty.t_c[TS_IO][rst] !=
542                                               el->el_tty.t_vdisable
543                                             && el->el_tty.t_c[ED_IO][rst] !=
544                                               el->el_tty.t_vdisable)
545                                                   el->el_tty.t_c[ED_IO][rst] =
546                                                       el->el_tty.t_c[TS_IO][rst];
547                               for (rst = 0; rst < C_NCC; rst++)
548                                         if (el->el_tty.t_c[TS_IO][rst] !=
549                                             el->el_tty.t_vdisable)
550                                                   el->el_tty.t_c[EX_IO][rst] =
551                                                       el->el_tty.t_c[TS_IO][rst];
552                     }
553                     tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
554                     if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
555 #ifdef DEBUG_TTY
556                               (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
557                                   __func__, strerror(errno));
558 #endif /* DEBUG_TTY */
559                               return -1;
560                     }
561           }
562 
563           tty_setup_flags(el, &el->el_tty.t_ed, ED_IO);
564 
565           tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
566           tty_bind_char(el, 1);
567           el->el_tty.t_initialized = 1;
568           return 0;
569 }
570 
571 libedit_private int
tty_init(EditLine * el)572 tty_init(EditLine *el)
573 {
574 
575           el->el_tty.t_mode = EX_IO;
576           el->el_tty.t_vdisable = _POSIX_VDISABLE;
577           el->el_tty.t_initialized = 0;
578           (void) memcpy(el->el_tty.t_t, ttyperm, sizeof(ttyperm_t));
579           (void) memcpy(el->el_tty.t_c, ttychar, sizeof(ttychar_t));
580           return tty_setup(el);
581 }
582 
583 
584 /* tty_end():
585  *        Restore the tty to its original settings
586  */
587 libedit_private void
588 /*ARGSUSED*/
tty_end(EditLine * el,int how)589 tty_end(EditLine *el, int how)
590 {
591           if (el->el_flags & EDIT_DISABLED)
592                     return;
593 
594           if (!el->el_tty.t_initialized)
595                     return;
596 
597           if (tty_setty(el, how, &el->el_tty.t_or) == -1)
598           {
599 #ifdef DEBUG_TTY
600                     (void) fprintf(el->el_errfile,
601                         "%s: tty_setty: %s\n", __func__, strerror(errno));
602 #endif /* DEBUG_TTY */
603           }
604 }
605 
606 
607 /* tty__getspeed():
608  *        Get the tty speed
609  */
610 static speed_t
tty__getspeed(struct termios * td)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 static int
tty__getcharindex(int i)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 static void
tty__getchar(struct termios * td,unsigned char * s)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 static void
tty__setchar(struct termios * td,unsigned char * s)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 libedit_private void
tty_bind_char(EditLine * el,int force)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           wchar_t 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 != (wint_t)-1; tp++) {
918                     new[0] = (wchar_t)t_n[tp->nch];
919                     old[0] = (wchar_t)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[(unsigned char)old[0]] = dmap[(unsigned char)old[0]];
925                     keymacro_clear(el, map, new);
926                     /* MAP_VI == 1, MAP_EMACS == 0... */
927                     map[(unsigned char)new[0]] = tp->bind[el->el_map.type];
928                     if (dalt) {
929                               keymacro_clear(el, alt, old);
930                               alt[(unsigned char)old[0]] =
931                                   dalt[(unsigned char)old[0]];
932                               keymacro_clear(el, alt, new);
933                               alt[(unsigned char)new[0]] =
934                                   tp->bind[el->el_map.type + 1];
935                     }
936           }
937 }
938 
939 
940 static tcflag_t *
tty__get_flag(struct termios * t,int kind)941 tty__get_flag(struct termios *t, int kind) {
942           switch (kind) {
943           case MD_INP:
944                     return &t->c_iflag;
945           case MD_OUT:
946                     return &t->c_oflag;
947           case MD_CTL:
948                     return &t->c_cflag;
949           case MD_LIN:
950                     return &t->c_lflag;
951           default:
952                     abort();
953                     /*NOTREACHED*/
954           }
955 }
956 
957 
958 static tcflag_t
tty_update_flag(EditLine * el,tcflag_t f,int mode,int kind)959 tty_update_flag(EditLine *el, tcflag_t f, int mode, int kind)
960 {
961           f &= ~el->el_tty.t_t[mode][kind].t_clrmask;
962           f |= el->el_tty.t_t[mode][kind].t_setmask;
963           return f;
964 }
965 
966 
967 static void
tty_update_flags(EditLine * el,int kind)968 tty_update_flags(EditLine *el, int kind)
969 {
970           tcflag_t *tt, *ed, *ex;
971           tt = tty__get_flag(&el->el_tty.t_ts, kind);
972           ed = tty__get_flag(&el->el_tty.t_ed, kind);
973           ex = tty__get_flag(&el->el_tty.t_ex, kind);
974 
975           if (*tt != *ex && (kind != MD_CTL || *tt != *ed)) {
976                     *ed = tty_update_flag(el, *tt, ED_IO, kind);
977                     *ex = tty_update_flag(el, *tt, EX_IO, kind);
978           }
979 }
980 
981 
982 static void
tty_update_char(EditLine * el,int mode,int c)983 tty_update_char(EditLine *el, int mode, int c) {
984           if (!((el->el_tty.t_t[mode][MD_CHAR].t_setmask & C_SH(c)))
985               && (el->el_tty.t_c[TS_IO][c] != el->el_tty.t_c[EX_IO][c]))
986                     el->el_tty.t_c[mode][c] = el->el_tty.t_c[TS_IO][c];
987           if (el->el_tty.t_t[mode][MD_CHAR].t_clrmask & C_SH(c))
988                     el->el_tty.t_c[mode][c] = el->el_tty.t_vdisable;
989 }
990 
991 
992 /* tty_rawmode():
993  *        Set terminal into 1 character at a time mode.
994  */
995 libedit_private int
tty_rawmode(EditLine * el)996 tty_rawmode(EditLine *el)
997 {
998 
999           if (el->el_tty.t_mode == ED_IO || el->el_tty.t_mode == QU_IO)
1000                     return 0;
1001 
1002           if (el->el_flags & EDIT_DISABLED)
1003                     return 0;
1004 
1005           if (tty_getty(el, &el->el_tty.t_ts) == -1) {
1006 #ifdef DEBUG_TTY
1007                     (void) fprintf(el->el_errfile, "%s: tty_getty: %s\n", __func__,
1008                         strerror(errno));
1009 #endif /* DEBUG_TTY */
1010                     return -1;
1011           }
1012           /*
1013          * We always keep up with the eight bit setting and the speed of the
1014          * tty. But we only believe changes that are made to cooked mode!
1015          */
1016           el->el_tty.t_eight = tty__geteightbit(&el->el_tty.t_ts);
1017           el->el_tty.t_speed = tty__getspeed(&el->el_tty.t_ts);
1018 
1019           if (tty__getspeed(&el->el_tty.t_ex) != el->el_tty.t_speed ||
1020               tty__getspeed(&el->el_tty.t_ed) != el->el_tty.t_speed) {
1021                     (void) cfsetispeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1022                     (void) cfsetospeed(&el->el_tty.t_ex, el->el_tty.t_speed);
1023                     (void) cfsetispeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1024                     (void) cfsetospeed(&el->el_tty.t_ed, el->el_tty.t_speed);
1025           }
1026           if (tty__cooked_mode(&el->el_tty.t_ts)) {
1027                     int i;
1028 
1029                     for (i = MD_INP; i <= MD_LIN; i++)
1030                               tty_update_flags(el, i);
1031 
1032                     if (tty__gettabs(&el->el_tty.t_ex) == 0)
1033                               el->el_tty.t_tabs = 0;
1034                     else
1035                               el->el_tty.t_tabs = EL_CAN_TAB ? 1 : 0;
1036 
1037                     tty__getchar(&el->el_tty.t_ts, el->el_tty.t_c[TS_IO]);
1038                     /*
1039                      * Check if the user made any changes.
1040                      * If he did, then propagate the changes to the
1041                      * edit and execute data structures.
1042                      */
1043                     for (i = 0; i < C_NCC; i++)
1044                               if (el->el_tty.t_c[TS_IO][i] !=
1045                                   el->el_tty.t_c[EX_IO][i])
1046                                         break;
1047 
1048                     if (i != C_NCC) {
1049                               /*
1050                                * Propagate changes only to the unlibedit_private
1051                                * chars that have been modified just now.
1052                                */
1053                               for (i = 0; i < C_NCC; i++)
1054                                         tty_update_char(el, ED_IO, i);
1055 
1056                               tty_bind_char(el, 0);
1057                               tty__setchar(&el->el_tty.t_ed, el->el_tty.t_c[ED_IO]);
1058 
1059                               for (i = 0; i < C_NCC; i++)
1060                                         tty_update_char(el, EX_IO, i);
1061 
1062                               tty__setchar(&el->el_tty.t_ex, el->el_tty.t_c[EX_IO]);
1063                     }
1064           }
1065           if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1066 #ifdef DEBUG_TTY
1067                     (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1068                         strerror(errno));
1069 #endif /* DEBUG_TTY */
1070                     return -1;
1071           }
1072           el->el_tty.t_mode = ED_IO;
1073           return 0;
1074 }
1075 
1076 
1077 /* tty_cookedmode():
1078  *        Set the tty back to normal mode
1079  */
1080 libedit_private int
tty_cookedmode(EditLine * el)1081 tty_cookedmode(EditLine *el)
1082 {                                       /* set tty in normal setup */
1083 
1084           if (el->el_tty.t_mode == EX_IO)
1085                     return 0;
1086 
1087           if (el->el_flags & EDIT_DISABLED)
1088                     return 0;
1089 
1090           if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ex) == -1) {
1091 #ifdef DEBUG_TTY
1092                     (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1093                         strerror(errno));
1094 #endif /* DEBUG_TTY */
1095                     return -1;
1096           }
1097           el->el_tty.t_mode = EX_IO;
1098           return 0;
1099 }
1100 
1101 
1102 /* tty_quotemode():
1103  *        Turn on quote mode
1104  */
1105 libedit_private int
tty_quotemode(EditLine * el)1106 tty_quotemode(EditLine *el)
1107 {
1108           if (el->el_tty.t_mode == QU_IO)
1109                     return 0;
1110 
1111           el->el_tty.t_qu = el->el_tty.t_ed;
1112 
1113           tty_setup_flags(el, &el->el_tty.t_qu, QU_IO);
1114 
1115           if (tty_setty(el, TCSADRAIN, &el->el_tty.t_qu) == -1) {
1116 #ifdef DEBUG_TTY
1117                     (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1118                         strerror(errno));
1119 #endif /* DEBUG_TTY */
1120                     return -1;
1121           }
1122           el->el_tty.t_mode = QU_IO;
1123           return 0;
1124 }
1125 
1126 
1127 /* tty_noquotemode():
1128  *        Turn off quote mode
1129  */
1130 libedit_private int
tty_noquotemode(EditLine * el)1131 tty_noquotemode(EditLine *el)
1132 {
1133 
1134           if (el->el_tty.t_mode != QU_IO)
1135                     return 0;
1136           if (tty_setty(el, TCSADRAIN, &el->el_tty.t_ed) == -1) {
1137 #ifdef DEBUG_TTY
1138                     (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n", __func__,
1139                         strerror(errno));
1140 #endif /* DEBUG_TTY */
1141                     return -1;
1142           }
1143           el->el_tty.t_mode = ED_IO;
1144           return 0;
1145 }
1146 
1147 
1148 /* tty_stty():
1149  *        Stty builtin
1150  */
1151 libedit_private int
1152 /*ARGSUSED*/
tty_stty(EditLine * el,int argc,const wchar_t ** argv)1153 tty_stty(EditLine *el, int argc __attribute__((__unused__)),
1154     const wchar_t **argv)
1155 {
1156           const ttymodes_t *m;
1157           char x;
1158           int aflag = 0;
1159           const wchar_t *s, *d;
1160         char name[EL_BUFSIZ];
1161           struct termios *tios = &el->el_tty.t_ex;
1162           int z = EX_IO;
1163 
1164           if (argv == NULL)
1165                     return -1;
1166           strlcpy(name, ct_encode_string(*argv++, &el->el_scratch), sizeof(name));
1167 
1168           while (argv && *argv && argv[0][0] == '-' && argv[0][2] == '\0')
1169                     switch (argv[0][1]) {
1170                     case 'a':
1171                               aflag++;
1172                               argv++;
1173                               break;
1174                     case 'd':
1175                               argv++;
1176                               tios = &el->el_tty.t_ed;
1177                               z = ED_IO;
1178                               break;
1179                     case 'x':
1180                               argv++;
1181                               tios = &el->el_tty.t_ex;
1182                               z = EX_IO;
1183                               break;
1184                     case 'q':
1185                               argv++;
1186                               tios = &el->el_tty.t_ts;
1187                               z = QU_IO;
1188                               break;
1189                     default:
1190                               (void) fprintf(el->el_errfile,
1191                                   "%s: Unknown switch `%lc'.\n",
1192                                   name, (wint_t)argv[0][1]);
1193                               return -1;
1194                     }
1195 
1196           if (!argv || !*argv) {
1197                     int i = -1;
1198                     size_t len = 0, st = 0, cu;
1199                     for (m = ttymodes; m->m_name; m++) {
1200                               if (m->m_type != i) {
1201                                         (void) fprintf(el->el_outfile, "%s%s",
1202                                             i != -1 ? "\n" : "",
1203                                             el->el_tty.t_t[z][m->m_type].t_name);
1204                                         i = m->m_type;
1205                                         st = len =
1206                                             strlen(el->el_tty.t_t[z][m->m_type].t_name);
1207                               }
1208                               if (i != -1) {
1209                                   x = (el->el_tty.t_t[z][i].t_setmask & m->m_value)
1210                                         ?  '+' : '\0';
1211 
1212                                   if (el->el_tty.t_t[z][i].t_clrmask & m->m_value)
1213                                         x = '-';
1214                               } else {
1215                                   x = '\0';
1216                               }
1217 
1218                               if (x != '\0' || aflag) {
1219 
1220                                         cu = strlen(m->m_name) + (x != '\0') + 1;
1221 
1222                                         if (len + cu >=
1223                                             (size_t)el->el_terminal.t_size.h) {
1224                                                   (void) fprintf(el->el_outfile, "\n%*s",
1225                                                       (int)st, "");
1226                                                   len = st + cu;
1227                                         } else
1228                                                   len += cu;
1229 
1230                                         if (x != '\0')
1231                                                   (void) fprintf(el->el_outfile, "%c%s ",
1232                                                       x, m->m_name);
1233                                         else
1234                                                   (void) fprintf(el->el_outfile, "%s ",
1235                                                       m->m_name);
1236                               }
1237                     }
1238                     (void) fprintf(el->el_outfile, "\n");
1239                     return 0;
1240           }
1241           while (argv && (s = *argv++)) {
1242                     const wchar_t *p;
1243                     switch (*s) {
1244                     case '+':
1245                     case '-':
1246                               x = (char)*s++;
1247                               break;
1248                     default:
1249                               x = '\0';
1250                               break;
1251                     }
1252                     d = s;
1253                     p = wcschr(s, L'=');
1254                     for (m = ttymodes; m->m_name; m++)
1255                               if ((p ? strncmp(m->m_name, ct_encode_string(d,
1256                                   &el->el_scratch), (size_t)(p - d)) :
1257                                   strcmp(m->m_name, ct_encode_string(d,
1258                                   &el->el_scratch))) == 0 &&
1259                                   (p == NULL || m->m_type == MD_CHAR))
1260                                         break;
1261 
1262                     if (!m->m_name) {
1263                               (void) fprintf(el->el_errfile,
1264                                   "%s: Invalid argument `%ls'.\n", name, d);
1265                               return -1;
1266                     }
1267                     if (p) {
1268                               int c = ffs((int)m->m_value);
1269                               int v = *++p ? parse__escape(&p) :
1270                                   el->el_tty.t_vdisable;
1271                               assert(c != 0);
1272                               c--;
1273                               c = tty__getcharindex(c);
1274                               assert(c != -1);
1275                               tios->c_cc[c] = (cc_t)v;
1276                               continue;
1277                     }
1278                     switch (x) {
1279                     case '+':
1280                               el->el_tty.t_t[z][m->m_type].t_setmask |= m->m_value;
1281                               el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1282                               break;
1283                     case '-':
1284                               el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1285                               el->el_tty.t_t[z][m->m_type].t_clrmask |= m->m_value;
1286                               break;
1287                     default:
1288                               el->el_tty.t_t[z][m->m_type].t_setmask &= ~m->m_value;
1289                               el->el_tty.t_t[z][m->m_type].t_clrmask &= ~m->m_value;
1290                               break;
1291                     }
1292           }
1293 
1294           tty_setup_flags(el, tios, z);
1295           if (el->el_tty.t_mode == z) {
1296                     if (tty_setty(el, TCSADRAIN, tios) == -1) {
1297 #ifdef DEBUG_TTY
1298                               (void) fprintf(el->el_errfile, "%s: tty_setty: %s\n",
1299                                   __func__, strerror(errno));
1300 #endif /* DEBUG_TTY */
1301                               return -1;
1302                     }
1303           }
1304 
1305           return 0;
1306 }
1307 
1308 
1309 #ifdef notyet
1310 /* tty_printchar():
1311  *        DEbugging routine to print the tty characters
1312  */
1313 static void
tty_printchar(EditLine * el,unsigned char * s)1314 tty_printchar(EditLine *el, unsigned char *s)
1315 {
1316           ttyperm_t *m;
1317           int i;
1318 
1319           for (i = 0; i < C_NCC; i++) {
1320                     for (m = el->el_tty.t_t; m->m_name; m++)
1321                               if (m->m_type == MD_CHAR && C_SH(i) == m->m_value)
1322                                         break;
1323                     if (m->m_name)
1324                               (void) fprintf(el->el_errfile, "%s ^%c ",
1325                                   m->m_name, s[i] + 'A' - 1);
1326                     if (i % 5 == 0)
1327                               (void) fprintf(el->el_errfile, "\n");
1328           }
1329           (void) fprintf(el->el_errfile, "\n");
1330 }
1331 #endif /* notyet */
1332 
1333 
1334 static void
tty_setup_flags(EditLine * el,struct termios * tios,int mode)1335 tty_setup_flags(EditLine *el, struct termios *tios, int mode)
1336 {
1337           int kind;
1338           for (kind = MD_INP; kind <= MD_LIN; kind++) {
1339                     tcflag_t *f = tty__get_flag(tios, kind);
1340                     *f = tty_update_flag(el, *f, mode, kind);
1341           }
1342 }
1343 
1344 libedit_private int
tty_get_signal_character(EditLine * el,int sig)1345 tty_get_signal_character(EditLine *el, int sig)
1346 {
1347 #ifdef ECHOCTL
1348           tcflag_t *ed = tty__get_flag(&el->el_tty.t_ed, MD_INP);
1349           if ((*ed & ECHOCTL) == 0)
1350                     return -1;
1351 #endif
1352           switch (sig) {
1353 #if defined(SIGINT) && defined(VINTR)
1354           case SIGINT:
1355                     return el->el_tty.t_c[ED_IO][VINTR];
1356 #endif
1357 #if defined(SIGQUIT) && defined(VQUIT)
1358           case SIGQUIT:
1359                     return el->el_tty.t_c[ED_IO][VQUIT];
1360 #endif
1361 #if defined(SIGINFO) && defined(VSTATUS)
1362           case SIGINFO:
1363                     return el->el_tty.t_c[ED_IO][VSTATUS];
1364 #endif
1365 #if defined(SIGTSTP) && defined(VSUSP)
1366           case SIGTSTP:
1367                     return el->el_tty.t_c[ED_IO][VSUSP];
1368 #endif
1369           default:
1370                     return -1;
1371           }
1372 }
1373