1 /* $OpenBSD: tty.c,v 1.27 2016/05/06 13:12:52 schwarze Exp $ */
2 /* $NetBSD: tty.c,v 1.34 2011/01/27 23:11:40 christos Exp $ */
5 * Copyright (c) 1992, 1993
6 * The Regents of the University of California. All rights reserved.
8 * This code is derived from software contributed to Berkeley by
9 * Christos Zoulas of Cornell University.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * tty.c: tty interface stuff
43 #include <stdlib.h> /* for abort */
45 #include <strings.h> /* for ffs */
46 #include <unistd.h> /* for isatty */
52 typedef struct ttymodes_t
{
58 typedef struct ttymap_t
{
59 wint_t nch
, och
; /* Internal and termio rep of chars */
60 el_action_t bind
[3]; /* emacs, vi, and vi-cmd */
64 static const ttyperm_t ttyperm
= {
66 {"iflag:", ICRNL
, (INLCR
| IGNCR
)},
67 {"oflag:", (OPOST
| ONLCR
), ONLRET
},
69 {"lflag:", (ISIG
| ICANON
| ECHO
| ECHOE
| ECHOCTL
| IEXTEN
),
70 (NOFLSH
| ECHONL
| EXTPROC
| FLUSHO
)},
74 {"iflag:", (INLCR
| ICRNL
), IGNCR
},
75 {"oflag:", (OPOST
| ONLCR
), ONLRET
},
78 (NOFLSH
| ICANON
| ECHO
| ECHOK
| ECHONL
| EXTPROC
| IEXTEN
| FLUSHO
)},
79 {"chars:", (C_SH(C_MIN
) | C_SH(C_TIME
) | C_SH(C_SWTCH
) | C_SH(C_DSWTCH
) |
80 C_SH(C_SUSP
) | C_SH(C_DSUSP
) | C_SH(C_EOL
) | C_SH(C_DISCARD
) |
81 C_SH(C_PGOFF
) | C_SH(C_PAGE
) | C_SH(C_STATUS
)), 0}
84 {"iflag:", 0, IXON
| IXOFF
| INLCR
| ICRNL
},
87 {"lflag:", 0, ISIG
| IEXTEN
},
92 static const ttychar_t ttychar
= {
94 CINTR
, CQUIT
, CERASE
, CKILL
,
95 CEOF
, CEOL
, CEOL2
, CSWTCH
,
96 CDSWTCH
, CERASE2
, CSTART
, CSTOP
,
97 CWERASE
, CSUSP
, CDSUSP
, CREPRINT
,
98 CDISCARD
, CLNEXT
, CSTATUS
, CPAGE
,
99 CPGOFF
, CKILL2
, CBRK
, CMIN
,
103 CINTR
, CQUIT
, CERASE
, CKILL
,
104 _POSIX_VDISABLE
, _POSIX_VDISABLE
, _POSIX_VDISABLE
, _POSIX_VDISABLE
,
105 _POSIX_VDISABLE
, CERASE2
, CSTART
, CSTOP
,
106 _POSIX_VDISABLE
, CSUSP
, _POSIX_VDISABLE
, _POSIX_VDISABLE
,
107 CDISCARD
, _POSIX_VDISABLE
, _POSIX_VDISABLE
, _POSIX_VDISABLE
,
108 _POSIX_VDISABLE
, _POSIX_VDISABLE
, _POSIX_VDISABLE
, 1,
122 static const ttymap_t tty_map
[] = {
125 {EM_DELETE_PREV_CHAR
, VI_DELETE_PREV_CHAR
, ED_PREV_CHAR
}},
129 {EM_DELETE_PREV_CHAR
, VI_DELETE_PREV_CHAR
, ED_PREV_CHAR
}},
133 {EM_KILL_LINE
, VI_KILL_LINE_PREV
, ED_UNASSIGNED
}},
137 {EM_KILL_LINE
, VI_KILL_LINE_PREV
, ED_UNASSIGNED
}},
141 {EM_DELETE_OR_LIST
, VI_LIST_OR_EOF
, ED_UNASSIGNED
}},
145 {ED_DELETE_PREV_WORD
, ED_DELETE_PREV_WORD
, ED_PREV_WORD
}},
148 {C_REPRINT
, VREPRINT
,
149 {ED_REDISPLAY
, ED_INSERT
, ED_REDISPLAY
}},
150 #endif /* VREPRINT */
153 {ED_QUOTED_INSERT
, ED_QUOTED_INSERT
, ED_UNASSIGNED
}},
155 {(wint_t)-1, (wint_t)-1,
156 {ED_UNASSIGNED
, ED_UNASSIGNED
, ED_UNASSIGNED
}}
159 static const ttymodes_t ttymodes
[] = {
161 {"ignbrk", IGNBRK
, MD_INP
},
164 {"brkint", BRKINT
, MD_INP
},
167 {"ignpar", IGNPAR
, MD_INP
},
170 {"parmrk", PARMRK
, MD_INP
},
173 {"inpck", INPCK
, MD_INP
},
176 {"istrip", ISTRIP
, MD_INP
},
179 {"inlcr", INLCR
, MD_INP
},
182 {"igncr", IGNCR
, MD_INP
},
185 {"icrnl", ICRNL
, MD_INP
},
188 {"iuclc", IUCLC
, MD_INP
},
191 {"ixon", IXON
, MD_INP
},
194 {"ixany", IXANY
, MD_INP
},
197 {"ixoff", IXOFF
, MD_INP
},
200 {"imaxbel", IMAXBEL
, MD_INP
},
204 {"opost", OPOST
, MD_OUT
},
207 {"olcuc", OLCUC
, MD_OUT
},
210 {"onlcr", ONLCR
, MD_OUT
},
213 {"ocrnl", OCRNL
, MD_OUT
},
216 {"onocr", ONOCR
, MD_OUT
},
219 {"onoeot", ONOEOT
, MD_OUT
},
222 {"onlret", ONLRET
, MD_OUT
},
225 {"ofill", OFILL
, MD_OUT
},
228 {"ofdel", OFDEL
, MD_OUT
},
231 {"nldly", NLDLY
, MD_OUT
},
234 {"crdly", CRDLY
, MD_OUT
},
237 {"tabdly", TABDLY
, MD_OUT
},
240 {"xtabs", XTABS
, MD_OUT
},
243 {"bsdly", BSDLY
, MD_OUT
},
246 {"vtdly", VTDLY
, MD_OUT
},
249 {"ffdly", FFDLY
, MD_OUT
},
252 {"pageout", PAGEOUT
, MD_OUT
},
255 {"wrap", WRAP
, MD_OUT
},
259 {"cignore", CIGNORE
, MD_CTL
},
262 {"cbaud", CBAUD
, MD_CTL
},
265 {"cstopb", CSTOPB
, MD_CTL
},
268 {"cread", CREAD
, MD_CTL
},
271 {"parenb", PARENB
, MD_CTL
},
274 {"parodd", PARODD
, MD_CTL
},
277 {"hupcl", HUPCL
, MD_CTL
},
280 {"clocal", CLOCAL
, MD_CTL
},
283 {"loblk", LOBLK
, MD_CTL
},
286 {"cibaud", CIBAUD
, MD_CTL
},
290 {"ccts_oflow", CCTS_OFLOW
, MD_CTL
},
292 {"crtscts", CRTSCTS
, MD_CTL
},
293 #endif /* CCTS_OFLOW */
296 {"crts_iflow", CRTS_IFLOW
, MD_CTL
},
297 #endif /* CRTS_IFLOW */
299 {"cdtrcts", CDTRCTS
, MD_CTL
},
302 {"mdmbuf", MDMBUF
, MD_CTL
},
305 {"rcv1en", RCV1EN
, MD_CTL
},
308 {"xmt1en", XMT1EN
, MD_CTL
},
312 {"isig", ISIG
, MD_LIN
},
315 {"icanon", ICANON
, MD_LIN
},
318 {"xcase", XCASE
, MD_LIN
},
321 {"echo", ECHO
, MD_LIN
},
324 {"echoe", ECHOE
, MD_LIN
},
327 {"echok", ECHOK
, MD_LIN
},
330 {"echonl", ECHONL
, MD_LIN
},
333 {"noflsh", NOFLSH
, MD_LIN
},
336 {"tostop", TOSTOP
, MD_LIN
},
339 {"echoctl", ECHOCTL
, MD_LIN
},
342 {"echoprt", ECHOPRT
, MD_LIN
},
345 {"echoke", ECHOKE
, MD_LIN
},
348 {"defecho", DEFECHO
, MD_LIN
},
351 {"flusho", FLUSHO
, MD_LIN
},
354 {"pendin", PENDIN
, MD_LIN
},
357 {"iexten", IEXTEN
, MD_LIN
},
360 {"nokerninfo", NOKERNINFO
, MD_LIN
},
361 #endif /* NOKERNINFO */
363 {"altwerase", ALTWERASE
, MD_LIN
},
364 #endif /* ALTWERASE */
366 {"extproc", EXTPROC
, MD_LIN
},
370 {"intr", C_SH(C_INTR
), MD_CHAR
},
373 {"quit", C_SH(C_QUIT
), MD_CHAR
},
376 {"erase", C_SH(C_ERASE
), MD_CHAR
},
379 {"kill", C_SH(C_KILL
), MD_CHAR
},
382 {"eof", C_SH(C_EOF
), MD_CHAR
},
385 {"eol", C_SH(C_EOL
), MD_CHAR
},
388 {"eol2", C_SH(C_EOL2
), MD_CHAR
},
391 {"swtch", C_SH(C_SWTCH
), MD_CHAR
},
394 {"dswtch", C_SH(C_DSWTCH
), MD_CHAR
},
397 {"erase2", C_SH(C_ERASE2
), MD_CHAR
},
400 {"start", C_SH(C_START
), MD_CHAR
},
403 {"stop", C_SH(C_STOP
), MD_CHAR
},
406 {"werase", C_SH(C_WERASE
), MD_CHAR
},
409 {"susp", C_SH(C_SUSP
), MD_CHAR
},
412 {"dsusp", C_SH(C_DSUSP
), MD_CHAR
},
414 #if defined(VREPRINT)
415 {"reprint", C_SH(C_REPRINT
), MD_CHAR
},
416 #endif /* VREPRINT */
417 #if defined(VDISCARD)
418 {"discard", C_SH(C_DISCARD
), MD_CHAR
},
419 #endif /* VDISCARD */
421 {"lnext", C_SH(C_LNEXT
), MD_CHAR
},
424 {"status", C_SH(C_STATUS
), MD_CHAR
},
427 {"page", C_SH(C_PAGE
), MD_CHAR
},
430 {"pgoff", C_SH(C_PGOFF
), MD_CHAR
},
433 {"kill2", C_SH(C_KILL2
), MD_CHAR
},
436 {"brk", C_SH(C_BRK
), MD_CHAR
},
439 {"min", C_SH(C_MIN
), MD_CHAR
},
442 {"time", C_SH(C_TIME
), MD_CHAR
},
449 #define tty__gettabs(td) ((((td)->c_oflag & TAB3) == TAB3) ? 0 : 1)
450 #define tty__geteightbit(td) (((td)->c_cflag & CSIZE) == CS8)
451 #define tty__cooked_mode(td) ((td)->c_lflag & ICANON)
453 static int tty_getty(EditLine
*, struct termios
*);
454 static int tty_setty(EditLine
*, int, const struct termios
*);
455 static int tty__getcharindex(int);
456 static void tty__getchar(struct termios
*, unsigned char *);
457 static void tty__setchar(struct termios
*, unsigned char *);
458 static speed_t
tty__getspeed(struct termios
*);
459 static int tty_setup(EditLine
*);
460 static void tty_setup_flags(EditLine
*, struct termios
*, int);
465 * Wrapper for tcgetattr to handle EINTR
468 tty_getty(EditLine
*el
, struct termios
*t
)
471 while ((rv
= tcgetattr(el
->el_infd
, t
)) == -1 && errno
== EINTR
)
477 * Wrapper for tcsetattr to handle EINTR
480 tty_setty(EditLine
*el
, int action
, const struct termios
*t
)
483 while ((rv
= tcsetattr(el
->el_infd
, action
, t
)) == -1 && errno
== EINTR
)
489 * Get the tty parameters and initialize the editing state
492 tty_setup(EditLine
*el
)
496 if (el
->el_flags
& EDIT_DISABLED
)
499 if (el
->el_tty
.t_initialized
)
502 if (!isatty(el
->el_outfd
)) {
504 (void) fprintf(el
->el_errfile
,
505 "tty_setup: isatty: %s\n", strerror(errno
));
506 #endif /* DEBUG_TTY */
509 if (tty_getty(el
, &el
->el_tty
.t_or
) == -1) {
511 (void) fprintf(el
->el_errfile
,
512 "tty_setup: tty_getty: %s\n", strerror(errno
));
513 #endif /* DEBUG_TTY */
516 el
->el_tty
.t_ts
= el
->el_tty
.t_ex
= el
->el_tty
.t_ed
= el
->el_tty
.t_or
;
518 el
->el_tty
.t_speed
= tty__getspeed(&el
->el_tty
.t_ex
);
519 el
->el_tty
.t_tabs
= tty__gettabs(&el
->el_tty
.t_ex
);
520 el
->el_tty
.t_eight
= tty__geteightbit(&el
->el_tty
.t_ex
);
522 tty_setup_flags(el
, &el
->el_tty
.t_ex
, EX_IO
);
525 * Reset the tty chars to reasonable defaults
526 * If they are disabled, then enable them.
529 if (tty__cooked_mode(&el
->el_tty
.t_ts
)) {
530 tty__getchar(&el
->el_tty
.t_ts
, el
->el_tty
.t_c
[TS_IO
]);
532 * Don't affect CMIN and CTIME for the editor mode
534 for (rst
= 0; rst
< C_NCC
- 2; rst
++)
535 if (el
->el_tty
.t_c
[TS_IO
][rst
] !=
536 el
->el_tty
.t_vdisable
537 && el
->el_tty
.t_c
[ED_IO
][rst
] !=
538 el
->el_tty
.t_vdisable
)
539 el
->el_tty
.t_c
[ED_IO
][rst
] =
540 el
->el_tty
.t_c
[TS_IO
][rst
];
541 for (rst
= 0; rst
< C_NCC
; rst
++)
542 if (el
->el_tty
.t_c
[TS_IO
][rst
] !=
543 el
->el_tty
.t_vdisable
)
544 el
->el_tty
.t_c
[EX_IO
][rst
] =
545 el
->el_tty
.t_c
[TS_IO
][rst
];
547 tty__setchar(&el
->el_tty
.t_ex
, el
->el_tty
.t_c
[EX_IO
]);
548 if (tty_setty(el
, TCSADRAIN
, &el
->el_tty
.t_ex
) == -1) {
550 (void) fprintf(el
->el_errfile
,
551 "tty_setup: tty_setty: %s\n",
553 #endif /* DEBUG_TTY */
558 tty_setup_flags(el
, &el
->el_tty
.t_ed
, ED_IO
);
560 tty__setchar(&el
->el_tty
.t_ed
, el
->el_tty
.t_c
[ED_IO
]);
561 tty_bind_char(el
, 1);
562 el
->el_tty
.t_initialized
= 1;
567 tty_init(EditLine
*el
)
570 el
->el_tty
.t_mode
= EX_IO
;
571 el
->el_tty
.t_vdisable
= _POSIX_VDISABLE
;
572 el
->el_tty
.t_initialized
= 0;
573 (void) memcpy(el
->el_tty
.t_t
, ttyperm
, sizeof(ttyperm_t
));
574 (void) memcpy(el
->el_tty
.t_c
, ttychar
, sizeof(ttychar_t
));
575 return tty_setup(el
);
580 * Restore the tty to its original settings
584 tty_end(EditLine
*el
)
586 if (el
->el_flags
& EDIT_DISABLED
)
589 if (!el
->el_tty
.t_initialized
)
592 if (tty_setty(el
, TCSAFLUSH
, &el
->el_tty
.t_or
) == -1) {
594 (void) fprintf(el
->el_errfile
,
595 "%s: tty_setty: %s\n", __func__
, strerror(errno
));
596 #endif /* DEBUG_TTY */
605 tty__getspeed(struct termios
*td
)
609 if ((spd
= cfgetispeed(td
)) == 0)
610 spd
= cfgetospeed(td
);
615 * Return the index of the asked char in the c_cc array
618 tty__getcharindex(int i
)
684 #endif /* VREPRINT */
688 #endif /* VDISCARD */
723 * Get the tty characters
726 tty__getchar(struct termios
*td
, unsigned char *s
)
730 s
[C_INTR
] = td
->c_cc
[VINTR
];
733 s
[C_QUIT
] = td
->c_cc
[VQUIT
];
736 s
[C_ERASE
] = td
->c_cc
[VERASE
];
739 s
[C_KILL
] = td
->c_cc
[VKILL
];
742 s
[C_EOF
] = td
->c_cc
[VEOF
];
745 s
[C_EOL
] = td
->c_cc
[VEOL
];
748 s
[C_EOL2
] = td
->c_cc
[VEOL2
];
751 s
[C_SWTCH
] = td
->c_cc
[VSWTCH
];
754 s
[C_DSWTCH
] = td
->c_cc
[VDSWTCH
];
757 s
[C_ERASE2
] = td
->c_cc
[VERASE2
];
760 s
[C_START
] = td
->c_cc
[VSTART
];
763 s
[C_STOP
] = td
->c_cc
[VSTOP
];
766 s
[C_WERASE
] = td
->c_cc
[VWERASE
];
769 s
[C_SUSP
] = td
->c_cc
[VSUSP
];
772 s
[C_DSUSP
] = td
->c_cc
[VDSUSP
];
775 s
[C_REPRINT
] = td
->c_cc
[VREPRINT
];
776 #endif /* VREPRINT */
778 s
[C_DISCARD
] = td
->c_cc
[VDISCARD
];
779 #endif /* VDISCARD */
781 s
[C_LNEXT
] = td
->c_cc
[VLNEXT
];
784 s
[C_STATUS
] = td
->c_cc
[VSTATUS
];
787 s
[C_PAGE
] = td
->c_cc
[VPAGE
];
790 s
[C_PGOFF
] = td
->c_cc
[VPGOFF
];
793 s
[C_KILL2
] = td
->c_cc
[VKILL2
];
796 s
[C_MIN
] = td
->c_cc
[VMIN
];
799 s
[C_TIME
] = td
->c_cc
[VTIME
];
805 * Set the tty characters
808 tty__setchar(struct termios
*td
, unsigned char *s
)
812 td
->c_cc
[VINTR
] = s
[C_INTR
];
815 td
->c_cc
[VQUIT
] = s
[C_QUIT
];
818 td
->c_cc
[VERASE
] = s
[C_ERASE
];
821 td
->c_cc
[VKILL
] = s
[C_KILL
];
824 td
->c_cc
[VEOF
] = s
[C_EOF
];
827 td
->c_cc
[VEOL
] = s
[C_EOL
];
830 td
->c_cc
[VEOL2
] = s
[C_EOL2
];
833 td
->c_cc
[VSWTCH
] = s
[C_SWTCH
];
836 td
->c_cc
[VDSWTCH
] = s
[C_DSWTCH
];
839 td
->c_cc
[VERASE2
] = s
[C_ERASE2
];
842 td
->c_cc
[VSTART
] = s
[C_START
];
845 td
->c_cc
[VSTOP
] = s
[C_STOP
];
848 td
->c_cc
[VWERASE
] = s
[C_WERASE
];
851 td
->c_cc
[VSUSP
] = s
[C_SUSP
];
854 td
->c_cc
[VDSUSP
] = s
[C_DSUSP
];
857 td
->c_cc
[VREPRINT
] = s
[C_REPRINT
];
858 #endif /* VREPRINT */
860 td
->c_cc
[VDISCARD
] = s
[C_DISCARD
];
861 #endif /* VDISCARD */
863 td
->c_cc
[VLNEXT
] = s
[C_LNEXT
];
866 td
->c_cc
[VSTATUS
] = s
[C_STATUS
];
869 td
->c_cc
[VPAGE
] = s
[C_PAGE
];
872 td
->c_cc
[VPGOFF
] = s
[C_PGOFF
];
875 td
->c_cc
[VKILL2
] = s
[C_KILL2
];
878 td
->c_cc
[VMIN
] = s
[C_MIN
];
881 td
->c_cc
[VTIME
] = s
[C_TIME
];
887 * Rebind the editline functions
890 tty_bind_char(EditLine
*el
, int force
)
893 unsigned char *t_n
= el
->el_tty
.t_c
[ED_IO
];
894 unsigned char *t_o
= el
->el_tty
.t_ed
.c_cc
;
895 wchar_t new[2], old
[2];
897 el_action_t
*map
, *alt
;
898 const el_action_t
*dmap
, *dalt
;
899 new[1] = old
[1] = '\0';
901 map
= el
->el_map
.key
;
902 alt
= el
->el_map
.alt
;
903 if (el
->el_map
.type
== MAP_VI
) {
904 dmap
= el
->el_map
.vii
;
905 dalt
= el
->el_map
.vic
;
907 dmap
= el
->el_map
.emacs
;
911 for (tp
= tty_map
; tp
->nch
!= (wint_t)-1; tp
++) {
912 new[0] = (wchar_t)t_n
[tp
->nch
];
913 old
[0] = (wchar_t)t_o
[tp
->och
];
914 if (new[0] == old
[0] && !force
)
916 /* Put the old default binding back, and set the new binding */
917 keymacro_clear(el
, map
, old
);
918 map
[(unsigned char)old
[0]] = dmap
[(unsigned char)old
[0]];
919 keymacro_clear(el
, map
, new);
920 /* MAP_VI == 1, MAP_EMACS == 0... */
921 map
[(unsigned char)new[0]] = tp
->bind
[el
->el_map
.type
];
923 keymacro_clear(el
, alt
, old
);
924 alt
[(unsigned char)old
[0]] =
925 dalt
[(unsigned char)old
[0]];
926 keymacro_clear(el
, alt
, new);
927 alt
[(unsigned char)new[0]] =
928 tp
->bind
[el
->el_map
.type
+ 1];
935 tty__get_flag(struct termios
*t
, int kind
) {
953 tty_update_flag(EditLine
*el
, tcflag_t f
, int mode
, int kind
)
955 f
&= ~el
->el_tty
.t_t
[mode
][kind
].t_clrmask
;
956 f
|= el
->el_tty
.t_t
[mode
][kind
].t_setmask
;
962 tty_update_flags(EditLine
*el
, int kind
)
964 tcflag_t
*tt
, *ed
, *ex
;
965 tt
= tty__get_flag(&el
->el_tty
.t_ts
, kind
);
966 ed
= tty__get_flag(&el
->el_tty
.t_ed
, kind
);
967 ex
= tty__get_flag(&el
->el_tty
.t_ex
, kind
);
969 if (*tt
!= *ex
&& (kind
!= MD_CTL
|| *tt
!= *ed
)) {
970 *ed
= tty_update_flag(el
, *tt
, ED_IO
, kind
);
971 *ex
= tty_update_flag(el
, *tt
, EX_IO
, kind
);
977 tty_update_char(EditLine
*el
, int mode
, int c
) {
978 if (!((el
->el_tty
.t_t
[mode
][MD_CHAR
].t_setmask
& C_SH(c
)))
979 && (el
->el_tty
.t_c
[TS_IO
][c
] != el
->el_tty
.t_c
[EX_IO
][c
]))
980 el
->el_tty
.t_c
[mode
][c
] = el
->el_tty
.t_c
[TS_IO
][c
];
981 if (el
->el_tty
.t_t
[mode
][MD_CHAR
].t_clrmask
& C_SH(c
))
982 el
->el_tty
.t_c
[mode
][c
] = el
->el_tty
.t_vdisable
;
987 * Set terminal into 1 character at a time mode.
990 tty_rawmode(EditLine
*el
)
993 if (el
->el_tty
.t_mode
== ED_IO
|| el
->el_tty
.t_mode
== QU_IO
)
996 if (el
->el_flags
& EDIT_DISABLED
)
999 if (tty_getty(el
, &el
->el_tty
.t_ts
) == -1) {
1001 (void) fprintf(el
->el_errfile
, "tty_rawmode: tty_getty: %s\n",
1003 #endif /* DEBUG_TTY */
1007 * We always keep up with the eight bit setting and the speed of the
1008 * tty. But we only believe changes that are made to cooked mode!
1010 el
->el_tty
.t_eight
= tty__geteightbit(&el
->el_tty
.t_ts
);
1011 el
->el_tty
.t_speed
= tty__getspeed(&el
->el_tty
.t_ts
);
1013 if (tty__getspeed(&el
->el_tty
.t_ex
) != el
->el_tty
.t_speed
||
1014 tty__getspeed(&el
->el_tty
.t_ed
) != el
->el_tty
.t_speed
) {
1015 (void) cfsetispeed(&el
->el_tty
.t_ex
, el
->el_tty
.t_speed
);
1016 (void) cfsetospeed(&el
->el_tty
.t_ex
, el
->el_tty
.t_speed
);
1017 (void) cfsetispeed(&el
->el_tty
.t_ed
, el
->el_tty
.t_speed
);
1018 (void) cfsetospeed(&el
->el_tty
.t_ed
, el
->el_tty
.t_speed
);
1020 if (tty__cooked_mode(&el
->el_tty
.t_ts
)) {
1023 for (i
= MD_INP
; i
<= MD_LIN
; i
++)
1024 tty_update_flags(el
, i
);
1026 if (tty__gettabs(&el
->el_tty
.t_ex
) == 0)
1027 el
->el_tty
.t_tabs
= 0;
1029 el
->el_tty
.t_tabs
= EL_CAN_TAB
? 1 : 0;
1031 tty__getchar(&el
->el_tty
.t_ts
, el
->el_tty
.t_c
[TS_IO
]);
1033 * Check if the user made any changes.
1034 * If he did, then propagate the changes to the
1035 * edit and execute data structures.
1037 for (i
= 0; i
< C_NCC
; i
++)
1038 if (el
->el_tty
.t_c
[TS_IO
][i
] !=
1039 el
->el_tty
.t_c
[EX_IO
][i
])
1044 * Propagate changes only to the unprotected
1045 * chars that have been modified just now.
1047 for (i
= 0; i
< C_NCC
; i
++)
1048 tty_update_char(el
, ED_IO
, i
);
1050 tty_bind_char(el
, 0);
1051 tty__setchar(&el
->el_tty
.t_ed
, el
->el_tty
.t_c
[ED_IO
]);
1053 for (i
= 0; i
< C_NCC
; i
++)
1054 tty_update_char(el
, EX_IO
, i
);
1056 tty__setchar(&el
->el_tty
.t_ex
, el
->el_tty
.t_c
[EX_IO
]);
1059 if (tty_setty(el
, TCSADRAIN
, &el
->el_tty
.t_ed
) == -1) {
1061 (void) fprintf(el
->el_errfile
, "tty_rawmode: tty_setty: %s\n",
1063 #endif /* DEBUG_TTY */
1066 el
->el_tty
.t_mode
= ED_IO
;
1071 /* tty_cookedmode():
1072 * Set the tty back to normal mode
1075 tty_cookedmode(EditLine
*el
)
1076 { /* set tty in normal setup */
1078 if (el
->el_tty
.t_mode
== EX_IO
)
1081 if (el
->el_flags
& EDIT_DISABLED
)
1084 if (tty_setty(el
, TCSADRAIN
, &el
->el_tty
.t_ex
) == -1) {
1086 (void) fprintf(el
->el_errfile
,
1087 "tty_cookedmode: tty_setty: %s\n",
1089 #endif /* DEBUG_TTY */
1092 el
->el_tty
.t_mode
= EX_IO
;
1098 * Turn on quote mode
1101 tty_quotemode(EditLine
*el
)
1103 if (el
->el_tty
.t_mode
== QU_IO
)
1106 el
->el_tty
.t_qu
= el
->el_tty
.t_ed
;
1108 tty_setup_flags(el
, &el
->el_tty
.t_qu
, QU_IO
);
1110 if (tty_setty(el
, TCSADRAIN
, &el
->el_tty
.t_qu
) == -1) {
1112 (void) fprintf(el
->el_errfile
, "QuoteModeOn: tty_setty: %s\n",
1114 #endif /* DEBUG_TTY */
1117 el
->el_tty
.t_mode
= QU_IO
;
1122 /* tty_noquotemode():
1123 * Turn off quote mode
1126 tty_noquotemode(EditLine
*el
)
1129 if (el
->el_tty
.t_mode
!= QU_IO
)
1131 if (tty_setty(el
, TCSADRAIN
, &el
->el_tty
.t_ed
) == -1) {
1133 (void) fprintf(el
->el_errfile
, "QuoteModeOff: tty_setty: %s\n",
1135 #endif /* DEBUG_TTY */
1138 el
->el_tty
.t_mode
= ED_IO
;
1148 tty_stty(EditLine
*el
, int argc
__attribute__((__unused__
)),
1149 const wchar_t **argv
)
1151 const ttymodes_t
*m
;
1154 const wchar_t *s
, *d
;
1155 char name
[EL_BUFSIZ
];
1156 struct termios
*tios
= &el
->el_tty
.t_ex
;
1161 strncpy(name
, ct_encode_string(*argv
++, &el
->el_scratch
), sizeof(name
));
1162 name
[sizeof(name
) - 1] = '\0';
1164 while (argv
&& *argv
&& argv
[0][0] == '-' && argv
[0][2] == '\0')
1165 switch (argv
[0][1]) {
1172 tios
= &el
->el_tty
.t_ed
;
1177 tios
= &el
->el_tty
.t_ex
;
1182 tios
= &el
->el_tty
.t_ts
;
1186 (void) fprintf(el
->el_errfile
,
1187 "%s: Unknown switch `%lc'.\n",
1192 if (!argv
|| !*argv
) {
1194 size_t len
= 0, st
= 0, cu
;
1195 for (m
= ttymodes
; m
->m_name
; m
++) {
1196 if (m
->m_type
!= i
) {
1197 (void) fprintf(el
->el_outfile
, "%s%s",
1198 i
!= -1 ? "\n" : "",
1199 el
->el_tty
.t_t
[z
][m
->m_type
].t_name
);
1202 strlen(el
->el_tty
.t_t
[z
][m
->m_type
].t_name
);
1205 x
= (el
->el_tty
.t_t
[z
][i
].t_setmask
& m
->m_value
)
1207 x
= (el
->el_tty
.t_t
[z
][i
].t_clrmask
& m
->m_value
)
1213 if (x
!= '\0' || aflag
) {
1215 cu
= strlen(m
->m_name
) + (x
!= '\0') + 1;
1218 (size_t)el
->el_terminal
.t_size
.h
) {
1219 (void) fprintf(el
->el_outfile
, "\n%*s",
1226 (void) fprintf(el
->el_outfile
, "%c%s ",
1229 (void) fprintf(el
->el_outfile
, "%s ",
1233 (void) fprintf(el
->el_outfile
, "\n");
1236 while (argv
&& (s
= *argv
++)) {
1248 p
= wcschr(s
, L
'=');
1249 for (m
= ttymodes
; m
->m_name
; m
++)
1250 if ((p
? strncmp(m
->m_name
, ct_encode_string(d
, &el
->el_scratch
), (size_t)(p
- d
)) :
1251 strcmp(m
->m_name
, ct_encode_string(d
, &el
->el_scratch
))) == 0 &&
1252 (p
== NULL
|| m
->m_type
== MD_CHAR
))
1256 (void) fprintf(el
->el_errfile
,
1257 "%s: Invalid argument `%ls'.\n", name
, d
);
1261 int c
= ffs((int)m
->m_value
);
1262 int v
= *++p
? parse__escape(&p
) :
1263 el
->el_tty
.t_vdisable
;
1266 c
= tty__getcharindex(c
);
1273 el
->el_tty
.t_t
[z
][m
->m_type
].t_setmask
|= m
->m_value
;
1274 el
->el_tty
.t_t
[z
][m
->m_type
].t_clrmask
&= ~m
->m_value
;
1277 el
->el_tty
.t_t
[z
][m
->m_type
].t_setmask
&= ~m
->m_value
;
1278 el
->el_tty
.t_t
[z
][m
->m_type
].t_clrmask
|= m
->m_value
;
1281 el
->el_tty
.t_t
[z
][m
->m_type
].t_setmask
&= ~m
->m_value
;
1282 el
->el_tty
.t_t
[z
][m
->m_type
].t_clrmask
&= ~m
->m_value
;
1287 tty_setup_flags(el
, tios
, z
);
1288 if (el
->el_tty
.t_mode
== z
) {
1289 if (tty_setty(el
, TCSADRAIN
, tios
) == -1) {
1291 (void) fprintf(el
->el_errfile
,
1292 "tty_stty: tty_setty: %s\n", strerror(errno
));
1293 #endif /* DEBUG_TTY */
1304 * DEbugging routine to print the tty characters
1307 tty_printchar(EditLine
*el
, unsigned char *s
)
1312 for (i
= 0; i
< C_NCC
; i
++) {
1313 for (m
= el
->el_tty
.t_t
; m
->m_name
; m
++)
1314 if (m
->m_type
== MD_CHAR
&& C_SH(i
) == m
->m_value
)
1317 (void) fprintf(el
->el_errfile
, "%s ^%c ",
1318 m
->m_name
, s
[i
] + 'A' - 1);
1320 (void) fprintf(el
->el_errfile
, "\n");
1322 (void) fprintf(el
->el_errfile
, "\n");
1328 tty_setup_flags(EditLine
*el
, struct termios
*tios
, int mode
)
1331 for (kind
= MD_INP
; kind
<= MD_LIN
; kind
++) {
1332 tcflag_t
*f
= tty__get_flag(tios
, kind
);
1333 *f
= tty_update_flag(el
, *f
, mode
, kind
);