xref: /netbsd-src/external/bsd/tmux/dist/tty-term.c (revision 890b6d91a44b7fcb2dfbcbc1e93463086e462d2d)
199e242abSchristos /* $OpenBSD$ */
2698d5317Sjmmv 
3698d5317Sjmmv /*
4f26e8bc9Schristos  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
5698d5317Sjmmv  *
6698d5317Sjmmv  * Permission to use, copy, modify, and distribute this software for any
7698d5317Sjmmv  * purpose with or without fee is hereby granted, provided that the above
8698d5317Sjmmv  * copyright notice and this permission notice appear in all copies.
9698d5317Sjmmv  *
10698d5317Sjmmv  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11698d5317Sjmmv  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12698d5317Sjmmv  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13698d5317Sjmmv  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14698d5317Sjmmv  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15698d5317Sjmmv  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16698d5317Sjmmv  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17698d5317Sjmmv  */
18698d5317Sjmmv 
19698d5317Sjmmv #include <sys/types.h>
20698d5317Sjmmv 
21f26e8bc9Schristos #if defined(HAVE_CURSES_H)
22698d5317Sjmmv #include <curses.h>
23f26e8bc9Schristos #elif defined(HAVE_NCURSES_H)
240f3d2746Sjmmv #include <ncurses.h>
25698d5317Sjmmv #endif
26698d5317Sjmmv #include <fnmatch.h>
27698d5317Sjmmv #include <stdlib.h>
28698d5317Sjmmv #include <string.h>
29698d5317Sjmmv #include <term.h>
30698d5317Sjmmv 
31698d5317Sjmmv #include "tmux.h"
32698d5317Sjmmv 
33e9a2d6faSchristos static char	*tty_term_strip(const char *);
34698d5317Sjmmv 
350f3d2746Sjmmv struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms);
36698d5317Sjmmv 
3799e242abSchristos enum tty_code_type {
3899e242abSchristos 	TTYCODE_NONE = 0,
3999e242abSchristos 	TTYCODE_STRING,
4099e242abSchristos 	TTYCODE_NUMBER,
4199e242abSchristos 	TTYCODE_FLAG,
42698d5317Sjmmv };
43698d5317Sjmmv 
4499e242abSchristos struct tty_code {
4599e242abSchristos 	enum tty_code_type	type;
4699e242abSchristos 	union {
4799e242abSchristos 		char	       *string;
4899e242abSchristos 		int		number;
4999e242abSchristos 		int		flag;
5099e242abSchristos 	} value;
5199e242abSchristos };
5299e242abSchristos 
5399e242abSchristos struct tty_term_code_entry {
5499e242abSchristos 	enum tty_code_type	type;
5599e242abSchristos 	const char	       *name;
5699e242abSchristos };
5799e242abSchristos 
58e9a2d6faSchristos static const struct tty_term_code_entry tty_term_codes[] = {
5999e242abSchristos 	[TTYC_ACSC] = { TTYCODE_STRING, "acsc" },
60e271dbb8Schristos 	[TTYC_AM] = { TTYCODE_FLAG, "am" },
6199e242abSchristos 	[TTYC_AX] = { TTYCODE_FLAG, "AX" },
6299e242abSchristos 	[TTYC_BCE] = { TTYCODE_FLAG, "bce" },
6399e242abSchristos 	[TTYC_BEL] = { TTYCODE_STRING, "bel" },
64e271dbb8Schristos 	[TTYC_BIDI] = { TTYCODE_STRING, "Bidi" },
6599e242abSchristos 	[TTYC_BLINK] = { TTYCODE_STRING, "blink" },
6699e242abSchristos 	[TTYC_BOLD] = { TTYCODE_STRING, "bold" },
6799e242abSchristos 	[TTYC_CIVIS] = { TTYCODE_STRING, "civis" },
6899e242abSchristos 	[TTYC_CLEAR] = { TTYCODE_STRING, "clear" },
69e271dbb8Schristos 	[TTYC_CLMG] = { TTYCODE_STRING, "Clmg" },
70e271dbb8Schristos 	[TTYC_CMG] = { TTYCODE_STRING, "Cmg" },
7199e242abSchristos 	[TTYC_CNORM] = { TTYCODE_STRING, "cnorm" },
7299e242abSchristos 	[TTYC_COLORS] = { TTYCODE_NUMBER, "colors" },
7399e242abSchristos 	[TTYC_CR] = { TTYCODE_STRING, "Cr" },
7499e242abSchristos 	[TTYC_CSR] = { TTYCODE_STRING, "csr" },
75fe99a117Schristos 	[TTYC_CS] = { TTYCODE_STRING, "Cs" },
7699e242abSchristos 	[TTYC_CUB1] = { TTYCODE_STRING, "cub1" },
77fe99a117Schristos 	[TTYC_CUB] = { TTYCODE_STRING, "cub" },
7899e242abSchristos 	[TTYC_CUD1] = { TTYCODE_STRING, "cud1" },
79fe99a117Schristos 	[TTYC_CUD] = { TTYCODE_STRING, "cud" },
8099e242abSchristos 	[TTYC_CUF1] = { TTYCODE_STRING, "cuf1" },
81fe99a117Schristos 	[TTYC_CUF] = { TTYCODE_STRING, "cuf" },
8299e242abSchristos 	[TTYC_CUP] = { TTYCODE_STRING, "cup" },
8399e242abSchristos 	[TTYC_CUU1] = { TTYCODE_STRING, "cuu1" },
84fe99a117Schristos 	[TTYC_CUU] = { TTYCODE_STRING, "cuu" },
8599e242abSchristos 	[TTYC_CVVIS] = { TTYCODE_STRING, "cvvis" },
8699e242abSchristos 	[TTYC_DCH1] = { TTYCODE_STRING, "dch1" },
87fe99a117Schristos 	[TTYC_DCH] = { TTYCODE_STRING, "dch" },
8899e242abSchristos 	[TTYC_DIM] = { TTYCODE_STRING, "dim" },
8999e242abSchristos 	[TTYC_DL1] = { TTYCODE_STRING, "dl1" },
90fe99a117Schristos 	[TTYC_DL] = { TTYCODE_STRING, "dl" },
91e271dbb8Schristos 	[TTYC_DSEKS] = { TTYCODE_STRING, "Dseks" },
92e271dbb8Schristos 	[TTYC_DSFCS] = { TTYCODE_STRING, "Dsfcs" },
93e271dbb8Schristos 	[TTYC_DSBP] = { TTYCODE_STRING, "Dsbp" },
94e271dbb8Schristos 	[TTYC_DSMG] = { TTYCODE_STRING, "Dsmg" },
9599e242abSchristos 	[TTYC_E3] = { TTYCODE_STRING, "E3" },
9699e242abSchristos 	[TTYC_ECH] = { TTYCODE_STRING, "ech" },
97e9a2d6faSchristos 	[TTYC_ED] = { TTYCODE_STRING, "ed" },
9899e242abSchristos 	[TTYC_EL1] = { TTYCODE_STRING, "el1" },
99fe99a117Schristos 	[TTYC_EL] = { TTYCODE_STRING, "el" },
10099e242abSchristos 	[TTYC_ENACS] = { TTYCODE_STRING, "enacs" },
101e271dbb8Schristos 	[TTYC_ENBP] = { TTYCODE_STRING, "Enbp" },
102e271dbb8Schristos 	[TTYC_ENEKS] = { TTYCODE_STRING, "Eneks" },
103e271dbb8Schristos 	[TTYC_ENFCS] = { TTYCODE_STRING, "Enfcs" },
104e271dbb8Schristos 	[TTYC_ENMG] = { TTYCODE_STRING, "Enmg" },
10599e242abSchristos 	[TTYC_FSL] = { TTYCODE_STRING, "fsl" },
106f844e94eSwiz 	[TTYC_HLS] = { TTYCODE_STRING, "Hls" },
10799e242abSchristos 	[TTYC_HOME] = { TTYCODE_STRING, "home" },
10899e242abSchristos 	[TTYC_HPA] = { TTYCODE_STRING, "hpa" },
10999e242abSchristos 	[TTYC_ICH1] = { TTYCODE_STRING, "ich1" },
110fe99a117Schristos 	[TTYC_ICH] = { TTYCODE_STRING, "ich" },
11199e242abSchristos 	[TTYC_IL1] = { TTYCODE_STRING, "il1" },
112fe99a117Schristos 	[TTYC_IL] = { TTYCODE_STRING, "il" },
113e9a2d6faSchristos 	[TTYC_INDN] = { TTYCODE_STRING, "indn" },
11499e242abSchristos 	[TTYC_INVIS] = { TTYCODE_STRING, "invis" },
11599e242abSchristos 	[TTYC_KCBT] = { TTYCODE_STRING, "kcbt" },
11699e242abSchristos 	[TTYC_KCUB1] = { TTYCODE_STRING, "kcub1" },
11799e242abSchristos 	[TTYC_KCUD1] = { TTYCODE_STRING, "kcud1" },
11899e242abSchristos 	[TTYC_KCUF1] = { TTYCODE_STRING, "kcuf1" },
11999e242abSchristos 	[TTYC_KCUU1] = { TTYCODE_STRING, "kcuu1" },
12099e242abSchristos 	[TTYC_KDC2] = { TTYCODE_STRING, "kDC" },
12199e242abSchristos 	[TTYC_KDC3] = { TTYCODE_STRING, "kDC3" },
12299e242abSchristos 	[TTYC_KDC4] = { TTYCODE_STRING, "kDC4" },
12399e242abSchristos 	[TTYC_KDC5] = { TTYCODE_STRING, "kDC5" },
12499e242abSchristos 	[TTYC_KDC6] = { TTYCODE_STRING, "kDC6" },
12599e242abSchristos 	[TTYC_KDC7] = { TTYCODE_STRING, "kDC7" },
12699e242abSchristos 	[TTYC_KDCH1] = { TTYCODE_STRING, "kdch1" },
127fe99a117Schristos 	[TTYC_KDN2] = { TTYCODE_STRING, "kDN" }, /* not kDN2 */
12899e242abSchristos 	[TTYC_KDN3] = { TTYCODE_STRING, "kDN3" },
12999e242abSchristos 	[TTYC_KDN4] = { TTYCODE_STRING, "kDN4" },
13099e242abSchristos 	[TTYC_KDN5] = { TTYCODE_STRING, "kDN5" },
13199e242abSchristos 	[TTYC_KDN6] = { TTYCODE_STRING, "kDN6" },
13299e242abSchristos 	[TTYC_KDN7] = { TTYCODE_STRING, "kDN7" },
13399e242abSchristos 	[TTYC_KEND2] = { TTYCODE_STRING, "kEND" },
13499e242abSchristos 	[TTYC_KEND3] = { TTYCODE_STRING, "kEND3" },
13599e242abSchristos 	[TTYC_KEND4] = { TTYCODE_STRING, "kEND4" },
13699e242abSchristos 	[TTYC_KEND5] = { TTYCODE_STRING, "kEND5" },
13799e242abSchristos 	[TTYC_KEND6] = { TTYCODE_STRING, "kEND6" },
13899e242abSchristos 	[TTYC_KEND7] = { TTYCODE_STRING, "kEND7" },
139fe99a117Schristos 	[TTYC_KEND] = { TTYCODE_STRING, "kend" },
14099e242abSchristos 	[TTYC_KF10] = { TTYCODE_STRING, "kf10" },
14199e242abSchristos 	[TTYC_KF11] = { TTYCODE_STRING, "kf11" },
14299e242abSchristos 	[TTYC_KF12] = { TTYCODE_STRING, "kf12" },
14399e242abSchristos 	[TTYC_KF13] = { TTYCODE_STRING, "kf13" },
14499e242abSchristos 	[TTYC_KF14] = { TTYCODE_STRING, "kf14" },
14599e242abSchristos 	[TTYC_KF15] = { TTYCODE_STRING, "kf15" },
14699e242abSchristos 	[TTYC_KF16] = { TTYCODE_STRING, "kf16" },
14799e242abSchristos 	[TTYC_KF17] = { TTYCODE_STRING, "kf17" },
14899e242abSchristos 	[TTYC_KF18] = { TTYCODE_STRING, "kf18" },
14999e242abSchristos 	[TTYC_KF19] = { TTYCODE_STRING, "kf19" },
150fe99a117Schristos 	[TTYC_KF1] = { TTYCODE_STRING, "kf1" },
15199e242abSchristos 	[TTYC_KF20] = { TTYCODE_STRING, "kf20" },
15299e242abSchristos 	[TTYC_KF21] = { TTYCODE_STRING, "kf21" },
15399e242abSchristos 	[TTYC_KF22] = { TTYCODE_STRING, "kf22" },
15499e242abSchristos 	[TTYC_KF23] = { TTYCODE_STRING, "kf23" },
15599e242abSchristos 	[TTYC_KF24] = { TTYCODE_STRING, "kf24" },
15699e242abSchristos 	[TTYC_KF25] = { TTYCODE_STRING, "kf25" },
15799e242abSchristos 	[TTYC_KF26] = { TTYCODE_STRING, "kf26" },
15899e242abSchristos 	[TTYC_KF27] = { TTYCODE_STRING, "kf27" },
15999e242abSchristos 	[TTYC_KF28] = { TTYCODE_STRING, "kf28" },
16099e242abSchristos 	[TTYC_KF29] = { TTYCODE_STRING, "kf29" },
161fe99a117Schristos 	[TTYC_KF2] = { TTYCODE_STRING, "kf2" },
16299e242abSchristos 	[TTYC_KF30] = { TTYCODE_STRING, "kf30" },
16399e242abSchristos 	[TTYC_KF31] = { TTYCODE_STRING, "kf31" },
16499e242abSchristos 	[TTYC_KF32] = { TTYCODE_STRING, "kf32" },
16599e242abSchristos 	[TTYC_KF33] = { TTYCODE_STRING, "kf33" },
16699e242abSchristos 	[TTYC_KF34] = { TTYCODE_STRING, "kf34" },
16799e242abSchristos 	[TTYC_KF35] = { TTYCODE_STRING, "kf35" },
16899e242abSchristos 	[TTYC_KF36] = { TTYCODE_STRING, "kf36" },
16999e242abSchristos 	[TTYC_KF37] = { TTYCODE_STRING, "kf37" },
17099e242abSchristos 	[TTYC_KF38] = { TTYCODE_STRING, "kf38" },
17199e242abSchristos 	[TTYC_KF39] = { TTYCODE_STRING, "kf39" },
172fe99a117Schristos 	[TTYC_KF3] = { TTYCODE_STRING, "kf3" },
17399e242abSchristos 	[TTYC_KF40] = { TTYCODE_STRING, "kf40" },
17499e242abSchristos 	[TTYC_KF41] = { TTYCODE_STRING, "kf41" },
17599e242abSchristos 	[TTYC_KF42] = { TTYCODE_STRING, "kf42" },
17699e242abSchristos 	[TTYC_KF43] = { TTYCODE_STRING, "kf43" },
17799e242abSchristos 	[TTYC_KF44] = { TTYCODE_STRING, "kf44" },
17899e242abSchristos 	[TTYC_KF45] = { TTYCODE_STRING, "kf45" },
17999e242abSchristos 	[TTYC_KF46] = { TTYCODE_STRING, "kf46" },
18099e242abSchristos 	[TTYC_KF47] = { TTYCODE_STRING, "kf47" },
18199e242abSchristos 	[TTYC_KF48] = { TTYCODE_STRING, "kf48" },
18299e242abSchristos 	[TTYC_KF49] = { TTYCODE_STRING, "kf49" },
183fe99a117Schristos 	[TTYC_KF4] = { TTYCODE_STRING, "kf4" },
18499e242abSchristos 	[TTYC_KF50] = { TTYCODE_STRING, "kf50" },
18599e242abSchristos 	[TTYC_KF51] = { TTYCODE_STRING, "kf51" },
18699e242abSchristos 	[TTYC_KF52] = { TTYCODE_STRING, "kf52" },
18799e242abSchristos 	[TTYC_KF53] = { TTYCODE_STRING, "kf53" },
18899e242abSchristos 	[TTYC_KF54] = { TTYCODE_STRING, "kf54" },
18999e242abSchristos 	[TTYC_KF55] = { TTYCODE_STRING, "kf55" },
19099e242abSchristos 	[TTYC_KF56] = { TTYCODE_STRING, "kf56" },
19199e242abSchristos 	[TTYC_KF57] = { TTYCODE_STRING, "kf57" },
19299e242abSchristos 	[TTYC_KF58] = { TTYCODE_STRING, "kf58" },
19399e242abSchristos 	[TTYC_KF59] = { TTYCODE_STRING, "kf59" },
194fe99a117Schristos 	[TTYC_KF5] = { TTYCODE_STRING, "kf5" },
19599e242abSchristos 	[TTYC_KF60] = { TTYCODE_STRING, "kf60" },
19699e242abSchristos 	[TTYC_KF61] = { TTYCODE_STRING, "kf61" },
19799e242abSchristos 	[TTYC_KF62] = { TTYCODE_STRING, "kf62" },
19899e242abSchristos 	[TTYC_KF63] = { TTYCODE_STRING, "kf63" },
199fe99a117Schristos 	[TTYC_KF6] = { TTYCODE_STRING, "kf6" },
20099e242abSchristos 	[TTYC_KF7] = { TTYCODE_STRING, "kf7" },
20199e242abSchristos 	[TTYC_KF8] = { TTYCODE_STRING, "kf8" },
20299e242abSchristos 	[TTYC_KF9] = { TTYCODE_STRING, "kf9" },
20399e242abSchristos 	[TTYC_KHOM2] = { TTYCODE_STRING, "kHOM" },
20499e242abSchristos 	[TTYC_KHOM3] = { TTYCODE_STRING, "kHOM3" },
20599e242abSchristos 	[TTYC_KHOM4] = { TTYCODE_STRING, "kHOM4" },
20699e242abSchristos 	[TTYC_KHOM5] = { TTYCODE_STRING, "kHOM5" },
20799e242abSchristos 	[TTYC_KHOM6] = { TTYCODE_STRING, "kHOM6" },
20899e242abSchristos 	[TTYC_KHOM7] = { TTYCODE_STRING, "kHOM7" },
20999e242abSchristos 	[TTYC_KHOME] = { TTYCODE_STRING, "khome" },
21099e242abSchristos 	[TTYC_KIC2] = { TTYCODE_STRING, "kIC" },
21199e242abSchristos 	[TTYC_KIC3] = { TTYCODE_STRING, "kIC3" },
21299e242abSchristos 	[TTYC_KIC4] = { TTYCODE_STRING, "kIC4" },
21399e242abSchristos 	[TTYC_KIC5] = { TTYCODE_STRING, "kIC5" },
21499e242abSchristos 	[TTYC_KIC6] = { TTYCODE_STRING, "kIC6" },
21599e242abSchristos 	[TTYC_KIC7] = { TTYCODE_STRING, "kIC7" },
21699e242abSchristos 	[TTYC_KICH1] = { TTYCODE_STRING, "kich1" },
217fe99a117Schristos 	[TTYC_KIND] = { TTYCODE_STRING, "kind" },
21899e242abSchristos 	[TTYC_KLFT2] = { TTYCODE_STRING, "kLFT" },
21999e242abSchristos 	[TTYC_KLFT3] = { TTYCODE_STRING, "kLFT3" },
22099e242abSchristos 	[TTYC_KLFT4] = { TTYCODE_STRING, "kLFT4" },
22199e242abSchristos 	[TTYC_KLFT5] = { TTYCODE_STRING, "kLFT5" },
22299e242abSchristos 	[TTYC_KLFT6] = { TTYCODE_STRING, "kLFT6" },
22399e242abSchristos 	[TTYC_KLFT7] = { TTYCODE_STRING, "kLFT7" },
22499e242abSchristos 	[TTYC_KMOUS] = { TTYCODE_STRING, "kmous" },
22599e242abSchristos 	[TTYC_KNP] = { TTYCODE_STRING, "knp" },
22699e242abSchristos 	[TTYC_KNXT2] = { TTYCODE_STRING, "kNXT" },
22799e242abSchristos 	[TTYC_KNXT3] = { TTYCODE_STRING, "kNXT3" },
22899e242abSchristos 	[TTYC_KNXT4] = { TTYCODE_STRING, "kNXT4" },
22999e242abSchristos 	[TTYC_KNXT5] = { TTYCODE_STRING, "kNXT5" },
23099e242abSchristos 	[TTYC_KNXT6] = { TTYCODE_STRING, "kNXT6" },
23199e242abSchristos 	[TTYC_KNXT7] = { TTYCODE_STRING, "kNXT7" },
23299e242abSchristos 	[TTYC_KPP] = { TTYCODE_STRING, "kpp" },
23399e242abSchristos 	[TTYC_KPRV2] = { TTYCODE_STRING, "kPRV" },
23499e242abSchristos 	[TTYC_KPRV3] = { TTYCODE_STRING, "kPRV3" },
23599e242abSchristos 	[TTYC_KPRV4] = { TTYCODE_STRING, "kPRV4" },
23699e242abSchristos 	[TTYC_KPRV5] = { TTYCODE_STRING, "kPRV5" },
23799e242abSchristos 	[TTYC_KPRV6] = { TTYCODE_STRING, "kPRV6" },
23899e242abSchristos 	[TTYC_KPRV7] = { TTYCODE_STRING, "kPRV7" },
23999e242abSchristos 	[TTYC_KRIT2] = { TTYCODE_STRING, "kRIT" },
24099e242abSchristos 	[TTYC_KRIT3] = { TTYCODE_STRING, "kRIT3" },
24199e242abSchristos 	[TTYC_KRIT4] = { TTYCODE_STRING, "kRIT4" },
24299e242abSchristos 	[TTYC_KRIT5] = { TTYCODE_STRING, "kRIT5" },
24399e242abSchristos 	[TTYC_KRIT6] = { TTYCODE_STRING, "kRIT6" },
24499e242abSchristos 	[TTYC_KRIT7] = { TTYCODE_STRING, "kRIT7" },
245fe99a117Schristos 	[TTYC_KRI] = { TTYCODE_STRING, "kri" },
246fe99a117Schristos 	[TTYC_KUP2] = { TTYCODE_STRING, "kUP" }, /* not kUP2 */
24799e242abSchristos 	[TTYC_KUP3] = { TTYCODE_STRING, "kUP3" },
24899e242abSchristos 	[TTYC_KUP4] = { TTYCODE_STRING, "kUP4" },
24999e242abSchristos 	[TTYC_KUP5] = { TTYCODE_STRING, "kUP5" },
25099e242abSchristos 	[TTYC_KUP6] = { TTYCODE_STRING, "kUP6" },
25199e242abSchristos 	[TTYC_KUP7] = { TTYCODE_STRING, "kUP7" },
25299e242abSchristos 	[TTYC_MS] = { TTYCODE_STRING, "Ms" },
253f844e94eSwiz 	[TTYC_NOBR] = { TTYCODE_STRING, "Nobr" },
254e271dbb8Schristos 	[TTYC_OL] = { TTYCODE_STRING, "ol" },
25599e242abSchristos 	[TTYC_OP] = { TTYCODE_STRING, "op" },
25659b94b2cSchristos 	[TTYC_RECT] = { TTYCODE_STRING, "Rect" },
25799e242abSchristos 	[TTYC_REV] = { TTYCODE_STRING, "rev" },
258c7e17de0Schristos 	[TTYC_RGB] = { TTYCODE_FLAG, "RGB" },
25930744affSchristos 	[TTYC_RIN] = { TTYCODE_STRING, "rin" },
260e271dbb8Schristos 	[TTYC_RI] = { TTYCODE_STRING, "ri" },
26199e242abSchristos 	[TTYC_RMACS] = { TTYCODE_STRING, "rmacs" },
26299e242abSchristos 	[TTYC_RMCUP] = { TTYCODE_STRING, "rmcup" },
26399e242abSchristos 	[TTYC_RMKX] = { TTYCODE_STRING, "rmkx" },
26499e242abSchristos 	[TTYC_SETAB] = { TTYCODE_STRING, "setab" },
26599e242abSchristos 	[TTYC_SETAF] = { TTYCODE_STRING, "setaf" },
266e271dbb8Schristos 	[TTYC_SETAL] = { TTYCODE_STRING, "setal" },
267fe99a117Schristos 	[TTYC_SETRGBB] = { TTYCODE_STRING, "setrgbb" },
268fe99a117Schristos 	[TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" },
26930744affSchristos 	[TTYC_SETULC] = { TTYCODE_STRING, "Setulc" },
270f844e94eSwiz 	[TTYC_SETULC1] = { TTYCODE_STRING, "Setulc1" },
271fe99a117Schristos 	[TTYC_SE] = { TTYCODE_STRING, "Se" },
272f844e94eSwiz 	[TTYC_SXL] =  { TTYCODE_FLAG, "Sxl" },
27399e242abSchristos 	[TTYC_SGR0] = { TTYCODE_STRING, "sgr0" },
27499e242abSchristos 	[TTYC_SITM] = { TTYCODE_STRING, "sitm" },
27599e242abSchristos 	[TTYC_SMACS] = { TTYCODE_STRING, "smacs" },
27699e242abSchristos 	[TTYC_SMCUP] = { TTYCODE_STRING, "smcup" },
27799e242abSchristos 	[TTYC_SMKX] = { TTYCODE_STRING, "smkx" },
27830744affSchristos 	[TTYC_SMOL] = { TTYCODE_STRING, "Smol" },
27999e242abSchristos 	[TTYC_SMSO] = { TTYCODE_STRING, "smso" },
2800a274e86Schristos 	[TTYC_SMULX] = { TTYCODE_STRING, "Smulx" },
28199e242abSchristos 	[TTYC_SMUL] = { TTYCODE_STRING, "smul" },
282e9a2d6faSchristos 	[TTYC_SMXX] =  { TTYCODE_STRING, "smxx" },
28399e242abSchristos 	[TTYC_SS] = { TTYCODE_STRING, "Ss" },
28446548964Swiz 	[TTYC_SWD] = { TTYCODE_STRING, "Swd" },
285e271dbb8Schristos 	[TTYC_SYNC] = { TTYCODE_STRING, "Sync" },
286f26e8bc9Schristos 	[TTYC_TC] = { TTYCODE_FLAG, "Tc" },
28799e242abSchristos 	[TTYC_TSL] = { TTYCODE_STRING, "tsl" },
288fe99a117Schristos 	[TTYC_U8] = { TTYCODE_NUMBER, "U8" },
28999e242abSchristos 	[TTYC_VPA] = { TTYCODE_STRING, "vpa" },
290e271dbb8Schristos 	[TTYC_XT] = { TTYCODE_FLAG, "XT" }
29199e242abSchristos };
29299e242abSchristos 
29399e242abSchristos u_int
29499e242abSchristos tty_term_ncodes(void)
29599e242abSchristos {
29699e242abSchristos 	return (nitems(tty_term_codes));
29799e242abSchristos }
29899e242abSchristos 
299e9a2d6faSchristos static char *
300698d5317Sjmmv tty_term_strip(const char *s)
301698d5317Sjmmv {
302698d5317Sjmmv 	const char     *ptr;
30330744affSchristos 	static char	buf[8192];
304698d5317Sjmmv 	size_t		len;
305698d5317Sjmmv 
306698d5317Sjmmv 	/* Ignore strings with no padding. */
307698d5317Sjmmv 	if (strchr(s, '$') == NULL)
308698d5317Sjmmv 		return (xstrdup(s));
309698d5317Sjmmv 
310698d5317Sjmmv 	len = 0;
311698d5317Sjmmv 	for (ptr = s; *ptr != '\0'; ptr++) {
312698d5317Sjmmv 		if (*ptr == '$' && *(ptr + 1) == '<') {
313698d5317Sjmmv 			while (*ptr != '\0' && *ptr != '>')
314698d5317Sjmmv 				ptr++;
315698d5317Sjmmv 			if (*ptr == '>')
316698d5317Sjmmv 				ptr++;
317e271dbb8Schristos 			if (*ptr == '\0')
318e271dbb8Schristos 				break;
319698d5317Sjmmv 		}
320698d5317Sjmmv 
321698d5317Sjmmv 		buf[len++] = *ptr;
322698d5317Sjmmv 		if (len == (sizeof buf) - 1)
323698d5317Sjmmv 			break;
324698d5317Sjmmv 	}
325698d5317Sjmmv 	buf[len] = '\0';
326698d5317Sjmmv 
327698d5317Sjmmv 	return (xstrdup(buf));
328698d5317Sjmmv }
329698d5317Sjmmv 
3300a274e86Schristos static char *
3310a274e86Schristos tty_term_override_next(const char *s, size_t *offset)
3320a274e86Schristos {
33330744affSchristos 	static char	value[8192];
3340a274e86Schristos 	size_t		n = 0, at = *offset;
3350a274e86Schristos 
3360a274e86Schristos 	if (s[at] == '\0')
3370a274e86Schristos 		return (NULL);
3380a274e86Schristos 
3390a274e86Schristos 	while (s[at] != '\0') {
3400a274e86Schristos 		if (s[at] == ':') {
3410a274e86Schristos 			if (s[at + 1] == ':') {
3420a274e86Schristos 				value[n++] = ':';
3430a274e86Schristos 				at += 2;
3440a274e86Schristos 			} else
3450a274e86Schristos 				break;
3460a274e86Schristos 		} else {
3470a274e86Schristos 			value[n++] = s[at];
3480a274e86Schristos 			at++;
3490a274e86Schristos 		}
3500a274e86Schristos 		if (n == (sizeof value) - 1)
3510a274e86Schristos 			return (NULL);
3520a274e86Schristos 	}
3530a274e86Schristos 	if (s[at] != '\0')
3540a274e86Schristos 		*offset = at + 1;
3550a274e86Schristos 	else
3560a274e86Schristos 		*offset = at;
3570a274e86Schristos 	value[n] = '\0';
3580a274e86Schristos 	return (value);
3590a274e86Schristos }
3600a274e86Schristos 
361e271dbb8Schristos void
362e271dbb8Schristos tty_term_apply(struct tty_term *term, const char *capabilities, int quiet)
363698d5317Sjmmv {
3640f3d2746Sjmmv 	const struct tty_term_code_entry	*ent;
365698d5317Sjmmv 	struct tty_code				*code;
3660a274e86Schristos 	size_t                                   offset = 0;
3670a274e86Schristos 	char					*cp, *value, *s;
368e271dbb8Schristos 	const char				*errstr, *name = term->name;
369698d5317Sjmmv 	u_int					 i;
370e9a2d6faSchristos 	int					 n, remove;
371698d5317Sjmmv 
372e271dbb8Schristos 	while ((s = tty_term_override_next(capabilities, &offset)) != NULL) {
373e9a2d6faSchristos 		if (*s == '\0')
374e9a2d6faSchristos 			continue;
375e9a2d6faSchristos 		value = NULL;
376e9a2d6faSchristos 
377e9a2d6faSchristos 		remove = 0;
378e9a2d6faSchristos 		if ((cp = strchr(s, '=')) != NULL) {
379e9a2d6faSchristos 			*cp++ = '\0';
380e9a2d6faSchristos 			value = xstrdup(cp);
381e9a2d6faSchristos 			if (strunvis(value, cp) == -1) {
382e9a2d6faSchristos 				free(value);
383e9a2d6faSchristos 				value = xstrdup(cp);
384e9a2d6faSchristos 			}
385e9a2d6faSchristos 		} else if (s[strlen(s) - 1] == '@') {
386e9a2d6faSchristos 			s[strlen(s) - 1] = '\0';
387e9a2d6faSchristos 			remove = 1;
388e9a2d6faSchristos 		} else
389e9a2d6faSchristos 			value = xstrdup("");
390e9a2d6faSchristos 
391e271dbb8Schristos 		if (!quiet) {
392e9a2d6faSchristos 			if (remove)
393e271dbb8Schristos 				log_debug("%s override: %s@", name, s);
3940a274e86Schristos 			else if (*value == '\0')
395e271dbb8Schristos 				log_debug("%s override: %s", name, s);
396e9a2d6faSchristos 			else
397e271dbb8Schristos 				log_debug("%s override: %s=%s", name, s, value);
398e271dbb8Schristos 		}
399e9a2d6faSchristos 
40099e242abSchristos 		for (i = 0; i < tty_term_ncodes(); i++) {
401698d5317Sjmmv 			ent = &tty_term_codes[i];
402e9a2d6faSchristos 			if (strcmp(s, ent->name) != 0)
403698d5317Sjmmv 				continue;
40499e242abSchristos 			code = &term->codes[i];
405698d5317Sjmmv 
406e9a2d6faSchristos 			if (remove) {
407698d5317Sjmmv 				code->type = TTYCODE_NONE;
408698d5317Sjmmv 				continue;
409698d5317Sjmmv 			}
410698d5317Sjmmv 			switch (ent->type) {
411698d5317Sjmmv 			case TTYCODE_NONE:
412698d5317Sjmmv 				break;
413698d5317Sjmmv 			case TTYCODE_STRING:
414698d5317Sjmmv 				if (code->type == TTYCODE_STRING)
41561fba46bSchristos 					free(code->value.string);
416e9a2d6faSchristos 				code->value.string = xstrdup(value);
417698d5317Sjmmv 				code->type = ent->type;
418698d5317Sjmmv 				break;
419698d5317Sjmmv 			case TTYCODE_NUMBER:
420e9a2d6faSchristos 				n = strtonum(value, 0, INT_MAX, &errstr);
421698d5317Sjmmv 				if (errstr != NULL)
422698d5317Sjmmv 					break;
423698d5317Sjmmv 				code->value.number = n;
424698d5317Sjmmv 				code->type = ent->type;
425698d5317Sjmmv 				break;
426698d5317Sjmmv 			case TTYCODE_FLAG:
427698d5317Sjmmv 				code->value.flag = 1;
428698d5317Sjmmv 				code->type = ent->type;
429698d5317Sjmmv 				break;
430698d5317Sjmmv 			}
431698d5317Sjmmv 		}
432698d5317Sjmmv 
433e9a2d6faSchristos 		free(value);
434698d5317Sjmmv 	}
435698d5317Sjmmv }
436698d5317Sjmmv 
437e271dbb8Schristos void
438e271dbb8Schristos tty_term_apply_overrides(struct tty_term *term)
439e271dbb8Schristos {
440e271dbb8Schristos 	struct options_entry		*o;
441e271dbb8Schristos 	struct options_array_item	*a;
442e271dbb8Schristos 	union options_value		*ov;
44359b94b2cSchristos 	const char			*s, *acs;
444e271dbb8Schristos 	size_t				 offset;
445e271dbb8Schristos 	char				*first;
446e271dbb8Schristos 
44759b94b2cSchristos 	/* Update capabilities from the option. */
448e271dbb8Schristos 	o = options_get_only(global_options, "terminal-overrides");
449e271dbb8Schristos 	a = options_array_first(o);
450e271dbb8Schristos 	while (a != NULL) {
451e271dbb8Schristos 		ov = options_array_item_value(a);
452e271dbb8Schristos 		s = ov->string;
453e271dbb8Schristos 
454e271dbb8Schristos 		offset = 0;
455e271dbb8Schristos 		first = tty_term_override_next(s, &offset);
456e271dbb8Schristos 		if (first != NULL && fnmatch(first, term->name, 0) == 0)
457e271dbb8Schristos 			tty_term_apply(term, s + offset, 0);
458e271dbb8Schristos 		a = options_array_next(a);
459e271dbb8Schristos 	}
46059b94b2cSchristos 
461f844e94eSwiz 	/* Log the SIXEL flag. */
462f844e94eSwiz 	log_debug("SIXEL flag is %d", !!(term->flags & TERM_SIXEL));
463f844e94eSwiz 
46459b94b2cSchristos 	/* Update the RGB flag if the terminal has RGB colours. */
46559b94b2cSchristos 	if (tty_term_has(term, TTYC_SETRGBF) &&
46659b94b2cSchristos 	    tty_term_has(term, TTYC_SETRGBB))
46759b94b2cSchristos 		term->flags |= TERM_RGBCOLOURS;
46859b94b2cSchristos 	else
46959b94b2cSchristos 		term->flags &= ~TERM_RGBCOLOURS;
47059b94b2cSchristos 	log_debug("RGBCOLOURS flag is %d", !!(term->flags & TERM_RGBCOLOURS));
47159b94b2cSchristos 
47259b94b2cSchristos 	/*
47359b94b2cSchristos 	 * Set or clear the DECSLRM flag if the terminal has the margin
47459b94b2cSchristos 	 * capabilities.
47559b94b2cSchristos 	 */
47659b94b2cSchristos 	if (tty_term_has(term, TTYC_CMG) && tty_term_has(term, TTYC_CLMG))
47759b94b2cSchristos 		term->flags |= TERM_DECSLRM;
47859b94b2cSchristos 	else
47959b94b2cSchristos 		term->flags &= ~TERM_DECSLRM;
48059b94b2cSchristos 	log_debug("DECSLRM flag is %d", !!(term->flags & TERM_DECSLRM));
48159b94b2cSchristos 
48259b94b2cSchristos 	/*
48359b94b2cSchristos 	 * Set or clear the DECFRA flag if the terminal has the rectangle
48459b94b2cSchristos 	 * capability.
48559b94b2cSchristos 	 */
48659b94b2cSchristos 	if (tty_term_has(term, TTYC_RECT))
48759b94b2cSchristos 		term->flags |= TERM_DECFRA;
48859b94b2cSchristos 	else
48959b94b2cSchristos 		term->flags &= ~TERM_DECFRA;
49059b94b2cSchristos 	log_debug("DECFRA flag is %d", !!(term->flags & TERM_DECFRA));
49159b94b2cSchristos 
49259b94b2cSchristos 	/*
49359b94b2cSchristos 	 * Terminals without am (auto right margin) wrap at at $COLUMNS - 1
49459b94b2cSchristos 	 * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
49559b94b2cSchristos 	 *
49659b94b2cSchristos 	 * Terminals without xenl (eat newline glitch) ignore a newline beyond
49759b94b2cSchristos 	 * the right edge of the terminal, but tmux doesn't care about this -
49859b94b2cSchristos 	 * it always uses absolute only moves the cursor with a newline when
49959b94b2cSchristos 	 * also sending a linefeed.
50059b94b2cSchristos 	 *
50159b94b2cSchristos 	 * This is irritating, most notably because it is painful to write to
50259b94b2cSchristos 	 * the very bottom-right of the screen without scrolling.
50359b94b2cSchristos 	 *
50459b94b2cSchristos 	 * Flag the terminal here and apply some workarounds in other places to
50559b94b2cSchristos 	 * do the best possible.
50659b94b2cSchristos 	 */
50759b94b2cSchristos 	if (!tty_term_flag(term, TTYC_AM))
50859b94b2cSchristos 		term->flags |= TERM_NOAM;
50959b94b2cSchristos 	else
51059b94b2cSchristos 		term->flags &= ~TERM_NOAM;
51159b94b2cSchristos 	log_debug("NOAM flag is %d", !!(term->flags & TERM_NOAM));
51259b94b2cSchristos 
51359b94b2cSchristos 	/* Generate ACS table. If none is present, use nearest ASCII. */
51459b94b2cSchristos 	memset(term->acs, 0, sizeof term->acs);
51559b94b2cSchristos 	if (tty_term_has(term, TTYC_ACSC))
51659b94b2cSchristos 		acs = tty_term_string(term, TTYC_ACSC);
51759b94b2cSchristos 	else
51859b94b2cSchristos 		acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
51959b94b2cSchristos 	for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2)
52059b94b2cSchristos 		term->acs[(u_char) acs[0]][0] = acs[1];
521e271dbb8Schristos }
522e271dbb8Schristos 
523698d5317Sjmmv struct tty_term *
524e271dbb8Schristos tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
525e271dbb8Schristos     int *feat, char **cause)
526698d5317Sjmmv {
527698d5317Sjmmv 	struct tty_term				*term;
5280f3d2746Sjmmv 	const struct tty_term_code_entry	*ent;
529698d5317Sjmmv 	struct tty_code				*code;
530e9a2d6faSchristos 	struct options_entry			*o;
5310a274e86Schristos 	struct options_array_item		*a;
53230744affSchristos 	union options_value			*ov;
533e271dbb8Schristos 	u_int					 i, j;
534*890b6d91Swiz 	const char				*s, *value, *errstr;
535e271dbb8Schristos 	size_t					 offset, namelen;
536e271dbb8Schristos 	char					*first;
537*890b6d91Swiz 	int					 n;
538698d5317Sjmmv 
539e271dbb8Schristos 	log_debug("adding term %s", name);
540fe99a117Schristos 
541e271dbb8Schristos 	term = xcalloc(1, sizeof *term);
542e271dbb8Schristos 	term->tty = tty;
543698d5317Sjmmv 	term->name = xstrdup(name);
54499e242abSchristos 	term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
5450f3d2746Sjmmv 	LIST_INSERT_HEAD(&tty_terms, term, entry);
546698d5317Sjmmv 
547698d5317Sjmmv 	/* Fill in codes. */
548e271dbb8Schristos 	for (i = 0; i < ncaps; i++) {
549e271dbb8Schristos 		namelen = strcspn(caps[i], "=");
550e271dbb8Schristos 		if (namelen == 0)
551e271dbb8Schristos 			continue;
552e271dbb8Schristos 		value = caps[i] + namelen + 1;
553698d5317Sjmmv 
554e271dbb8Schristos 		for (j = 0; j < tty_term_ncodes(); j++) {
555e271dbb8Schristos 			ent = &tty_term_codes[j];
556e271dbb8Schristos 			if (strncmp(ent->name, caps[i], namelen) != 0)
557e271dbb8Schristos 				continue;
558e271dbb8Schristos 			if (ent->name[namelen] != '\0')
559e271dbb8Schristos 				continue;
560e271dbb8Schristos 
561e271dbb8Schristos 			code = &term->codes[j];
562698d5317Sjmmv 			code->type = TTYCODE_NONE;
563698d5317Sjmmv 			switch (ent->type) {
564698d5317Sjmmv 			case TTYCODE_NONE:
565698d5317Sjmmv 				break;
566698d5317Sjmmv 			case TTYCODE_STRING:
567698d5317Sjmmv 				code->type = TTYCODE_STRING;
568e271dbb8Schristos 				code->value.string = tty_term_strip(value);
569698d5317Sjmmv 				break;
570698d5317Sjmmv 			case TTYCODE_NUMBER:
571*890b6d91Swiz 				n = strtonum(value, 0, INT_MAX, &errstr);
572*890b6d91Swiz 				if (errstr != NULL)
573*890b6d91Swiz 					log_debug("%s: %s", ent->name, errstr);
574*890b6d91Swiz 				else {
575698d5317Sjmmv 					code->type = TTYCODE_NUMBER;
576*890b6d91Swiz 					code->value.number = n;
577*890b6d91Swiz 				}
578698d5317Sjmmv 				break;
579698d5317Sjmmv 			case TTYCODE_FLAG:
580698d5317Sjmmv 				code->type = TTYCODE_FLAG;
581e271dbb8Schristos 				code->value.flag = (*value == '1');
582698d5317Sjmmv 				break;
583698d5317Sjmmv 			}
584698d5317Sjmmv 		}
585e271dbb8Schristos 	}
58699e242abSchristos 
587e271dbb8Schristos 	/* Apply terminal features. */
588e271dbb8Schristos 	o = options_get_only(global_options, "terminal-features");
5890a274e86Schristos 	a = options_array_first(o);
5900a274e86Schristos 	while (a != NULL) {
59130744affSchristos 		ov = options_array_item_value(a);
592e271dbb8Schristos 		s = ov->string;
593e271dbb8Schristos 
594e271dbb8Schristos 		offset = 0;
595e271dbb8Schristos 		first = tty_term_override_next(s, &offset);
596e271dbb8Schristos 		if (first != NULL && fnmatch(first, term->name, 0) == 0)
597e271dbb8Schristos 			tty_add_features(feat, s + offset, ":");
5980a274e86Schristos 		a = options_array_next(a);
599e9a2d6faSchristos 	}
600698d5317Sjmmv 
601698d5317Sjmmv 	/* Delete curses data. */
60261fba46bSchristos #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
60361fba46bSchristos     (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
604698d5317Sjmmv 	del_curterm(cur_term);
605698d5317Sjmmv #endif
606698d5317Sjmmv 
607e271dbb8Schristos 	/* Apply overrides so any capabilities used for features are changed. */
608e271dbb8Schristos 	tty_term_apply_overrides(term);
609e271dbb8Schristos 
610698d5317Sjmmv 	/* These are always required. */
611698d5317Sjmmv 	if (!tty_term_has(term, TTYC_CLEAR)) {
612698d5317Sjmmv 		xasprintf(cause, "terminal does not support clear");
613698d5317Sjmmv 		goto error;
614698d5317Sjmmv 	}
615698d5317Sjmmv 	if (!tty_term_has(term, TTYC_CUP)) {
616698d5317Sjmmv 		xasprintf(cause, "terminal does not support cup");
617698d5317Sjmmv 		goto error;
618698d5317Sjmmv 	}
619698d5317Sjmmv 
620e271dbb8Schristos 	/*
621e271dbb8Schristos 	 * If TERM has XT or clear starts with CSI then it is safe to assume
622e271dbb8Schristos 	 * the terminal is derived from the VT100. This controls whether device
623e271dbb8Schristos 	 * attributes requests are sent to get more information.
624e271dbb8Schristos 	 *
625e271dbb8Schristos 	 * This is a bit of a hack but there aren't that many alternatives.
626e271dbb8Schristos 	 * Worst case tmux will just fall back to using whatever terminfo(5)
627e271dbb8Schristos 	 * says without trying to correct anything that is missing.
628e271dbb8Schristos 	 *
629e271dbb8Schristos 	 * Also add few features that VT100-like terminals should either
630e271dbb8Schristos 	 * support or safely ignore.
631e271dbb8Schristos 	 */
632e271dbb8Schristos 	s = tty_term_string(term, TTYC_CLEAR);
633e271dbb8Schristos 	if (tty_term_flag(term, TTYC_XT) || strncmp(s, "\033[", 2) == 0) {
634e271dbb8Schristos 		term->flags |= TERM_VT100LIKE;
635e271dbb8Schristos 		tty_add_features(feat, "bpaste,focus,title", ",");
636698d5317Sjmmv 	}
637698d5317Sjmmv 
638e271dbb8Schristos 	/* Add RGB feature if terminal has RGB colours. */
639e271dbb8Schristos 	if ((tty_term_flag(term, TTYC_TC) || tty_term_has(term, TTYC_RGB)) &&
640e271dbb8Schristos 	    (!tty_term_has(term, TTYC_SETRGBF) ||
641e271dbb8Schristos 	    !tty_term_has(term, TTYC_SETRGBB)))
642e271dbb8Schristos 		tty_add_features(feat, "RGB", ",");
64368e6ba84Schristos 
644e271dbb8Schristos 	/* Apply the features and overrides again. */
64559b94b2cSchristos 	if (tty_apply_features(term, *feat))
646e271dbb8Schristos 		tty_term_apply_overrides(term);
647e271dbb8Schristos 
64868e6ba84Schristos 	/* Log the capabilities. */
649fe99a117Schristos 	for (i = 0; i < tty_term_ncodes(); i++)
650fe99a117Schristos 		log_debug("%s%s", name, tty_term_describe(term, i));
651fe99a117Schristos 
652698d5317Sjmmv 	return (term);
653698d5317Sjmmv 
654698d5317Sjmmv error:
655698d5317Sjmmv 	tty_term_free(term);
656698d5317Sjmmv 	return (NULL);
657698d5317Sjmmv }
658698d5317Sjmmv 
659698d5317Sjmmv void
660698d5317Sjmmv tty_term_free(struct tty_term *term)
661698d5317Sjmmv {
662698d5317Sjmmv 	u_int	i;
663698d5317Sjmmv 
664e271dbb8Schristos 	log_debug("removing term %s", term->name);
665698d5317Sjmmv 
66699e242abSchristos 	for (i = 0; i < tty_term_ncodes(); i++) {
667698d5317Sjmmv 		if (term->codes[i].type == TTYCODE_STRING)
66861fba46bSchristos 			free(term->codes[i].value.string);
669698d5317Sjmmv 	}
67099e242abSchristos 	free(term->codes);
67199e242abSchristos 
672e271dbb8Schristos 	LIST_REMOVE(term, entry);
67361fba46bSchristos 	free(term->name);
67461fba46bSchristos 	free(term);
675698d5317Sjmmv }
676698d5317Sjmmv 
677698d5317Sjmmv int
678e271dbb8Schristos tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
679e271dbb8Schristos     char **cause)
680e271dbb8Schristos {
681e271dbb8Schristos 	const struct tty_term_code_entry	*ent;
682e271dbb8Schristos 	int					 error, n;
683e271dbb8Schristos 	u_int					 i;
684e271dbb8Schristos 	const char				*s;
685e271dbb8Schristos 	char					 tmp[11];
686e271dbb8Schristos 
68746548964Swiz 	if (setupterm(__UNCONST(name), fd, &error) != OK) {
688e271dbb8Schristos 		switch (error) {
689e271dbb8Schristos 		case 1:
690e271dbb8Schristos 			xasprintf(cause, "can't use hardcopy terminal: %s",
691e271dbb8Schristos 			    name);
692e271dbb8Schristos 			break;
693e271dbb8Schristos 		case 0:
694e271dbb8Schristos 			xasprintf(cause, "missing or unsuitable terminal: %s",
695e271dbb8Schristos 			    name);
696e271dbb8Schristos 			break;
697e271dbb8Schristos 		case -1:
698e271dbb8Schristos 			xasprintf(cause, "can't find terminfo database");
699e271dbb8Schristos 			break;
700e271dbb8Schristos 		default:
701e271dbb8Schristos 			xasprintf(cause, "unknown error");
702e271dbb8Schristos 			break;
703e271dbb8Schristos 		}
704e271dbb8Schristos 		return (-1);
705e271dbb8Schristos 	}
706e271dbb8Schristos 
707e271dbb8Schristos 	*ncaps = 0;
708e271dbb8Schristos 	*caps = NULL;
709e271dbb8Schristos 
710e271dbb8Schristos 	for (i = 0; i < tty_term_ncodes(); i++) {
711e271dbb8Schristos 		ent = &tty_term_codes[i];
712e271dbb8Schristos 		switch (ent->type) {
713e271dbb8Schristos 		case TTYCODE_NONE:
714e271dbb8Schristos 			continue;
715e271dbb8Schristos 		case TTYCODE_STRING:
716e271dbb8Schristos 			s = tigetstr((const char *)ent->name);
717e271dbb8Schristos 			if (s == NULL || s == (char *)-1)
718e271dbb8Schristos 				continue;
719e271dbb8Schristos 			break;
720e271dbb8Schristos 		case TTYCODE_NUMBER:
721e271dbb8Schristos 			n = tigetnum((const char *)ent->name);
722e271dbb8Schristos 			if (n == -1 || n == -2)
723e271dbb8Schristos 				continue;
724e271dbb8Schristos 			xsnprintf(tmp, sizeof tmp, "%d", n);
725e271dbb8Schristos 			s = tmp;
726e271dbb8Schristos 			break;
727e271dbb8Schristos 		case TTYCODE_FLAG:
728e271dbb8Schristos 			n = tigetflag((const char *)ent->name);
729e271dbb8Schristos 			if (n == -1)
730e271dbb8Schristos 				continue;
731e271dbb8Schristos 			if (n)
732e271dbb8Schristos 				s = "1";
733e271dbb8Schristos 			else
734e271dbb8Schristos 				s = "0";
735e271dbb8Schristos 			break;
736e271dbb8Schristos 		default:
737f844e94eSwiz 			fatalx("unknown capability type");
738e271dbb8Schristos 		}
739e271dbb8Schristos 		*caps = xreallocarray(*caps, (*ncaps) + 1, sizeof **caps);
740e271dbb8Schristos 		xasprintf(&(*caps)[*ncaps], "%s=%s", ent->name, s);
741e271dbb8Schristos 		(*ncaps)++;
742e271dbb8Schristos 	}
743e271dbb8Schristos 
744e271dbb8Schristos #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
745e271dbb8Schristos     (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
746e271dbb8Schristos 	del_curterm(cur_term);
747e271dbb8Schristos #endif
748e271dbb8Schristos 	return (0);
749e271dbb8Schristos }
750e271dbb8Schristos 
751e271dbb8Schristos void
752e271dbb8Schristos tty_term_free_list(char **caps, u_int ncaps)
753e271dbb8Schristos {
754e271dbb8Schristos 	u_int	i;
755e271dbb8Schristos 
756e271dbb8Schristos 	for (i = 0; i < ncaps; i++)
757e271dbb8Schristos 		free(caps[i]);
758e271dbb8Schristos 	free(caps);
759e271dbb8Schristos }
760e271dbb8Schristos 
761e271dbb8Schristos int
762698d5317Sjmmv tty_term_has(struct tty_term *term, enum tty_code_code code)
763698d5317Sjmmv {
764698d5317Sjmmv 	return (term->codes[code].type != TTYCODE_NONE);
765698d5317Sjmmv }
766698d5317Sjmmv 
767698d5317Sjmmv const char *
768698d5317Sjmmv tty_term_string(struct tty_term *term, enum tty_code_code code)
769698d5317Sjmmv {
770698d5317Sjmmv 	if (!tty_term_has(term, code))
771698d5317Sjmmv 		return ("");
772698d5317Sjmmv 	if (term->codes[code].type != TTYCODE_STRING)
773f26e8bc9Schristos 		fatalx("not a string: %d", code);
774698d5317Sjmmv 	return (term->codes[code].value.string);
775698d5317Sjmmv }
776698d5317Sjmmv 
777698d5317Sjmmv const char *
778f844e94eSwiz tty_term_string_i(struct tty_term *term, enum tty_code_code code, int a)
779698d5317Sjmmv {
780f844e94eSwiz 	const char	*x = tty_term_string(term, code), *s;
781f844e94eSwiz 
782f844e94eSwiz #if defined(HAVE_TIPARM_S)
783f844e94eSwiz 	s = tiparm_s(1, 0, x, a);
784f844e94eSwiz #elif defined(HAVE_TIPARM)
785f844e94eSwiz 	s = tiparm(x, a);
786f844e94eSwiz #else
7873f0a6bcaSwiz 	s = tparm((char *)x, a, 0, 0, 0, 0, 0, 0, 0, 0);
788f844e94eSwiz #endif
789f844e94eSwiz 	if (s == NULL) {
790f844e94eSwiz 		log_debug("could not expand %s", tty_term_codes[code].name);
791f844e94eSwiz 		return ("");
792f844e94eSwiz 	}
793f844e94eSwiz 	return (s);
794698d5317Sjmmv }
795698d5317Sjmmv 
796698d5317Sjmmv const char *
797f844e94eSwiz tty_term_string_ii(struct tty_term *term, enum tty_code_code code, int a, int b)
798698d5317Sjmmv {
799f844e94eSwiz 	const char	*x = tty_term_string(term, code), *s;
800f844e94eSwiz 
801f844e94eSwiz #if defined(HAVE_TIPARM_S)
802f844e94eSwiz 	s = tiparm_s(2, 0, x, a, b);
803f844e94eSwiz #elif defined(HAVE_TIPARM)
804f844e94eSwiz 	s = tiparm(x, a, b);
805f844e94eSwiz #else
8063f0a6bcaSwiz 	s = tparm((char *)x, a, b, 0, 0, 0, 0, 0, 0, 0);
807f844e94eSwiz #endif
808f844e94eSwiz 	if (s == NULL) {
809f844e94eSwiz 		log_debug("could not expand %s", tty_term_codes[code].name);
810f844e94eSwiz 		return ("");
811f844e94eSwiz 	}
812f844e94eSwiz 	return (s);
813698d5317Sjmmv }
814698d5317Sjmmv 
8150f3d2746Sjmmv const char *
816f844e94eSwiz tty_term_string_iii(struct tty_term *term, enum tty_code_code code, int a,
817f844e94eSwiz     int b, int c)
818fe99a117Schristos {
819f844e94eSwiz 	const char	*x = tty_term_string(term, code), *s;
820f844e94eSwiz 
821f844e94eSwiz #if defined(HAVE_TIPARM_S)
822f844e94eSwiz 	s = tiparm_s(3, 0, x, a, b, c);
823f844e94eSwiz #elif defined(HAVE_TIPARM)
824f844e94eSwiz 	s = tiparm(x, a, b, c);
825f844e94eSwiz #else
8263f0a6bcaSwiz 	s = tparm((char *)x, a, b, c, 0, 0, 0, 0, 0, 0);
827f844e94eSwiz #endif
828f844e94eSwiz 	if (s == NULL) {
829f844e94eSwiz 		log_debug("could not expand %s", tty_term_codes[code].name);
830f844e94eSwiz 		return ("");
831f844e94eSwiz 	}
832f844e94eSwiz 	return (s);
833fe99a117Schristos }
834fe99a117Schristos 
835fe99a117Schristos const char *
836f844e94eSwiz tty_term_string_s(struct tty_term *term, enum tty_code_code code, const char *a)
8370f3d2746Sjmmv {
838f844e94eSwiz 	const char	*x = tty_term_string(term, code), *s;
839f844e94eSwiz 
840f844e94eSwiz #if defined(HAVE_TIPARM_S)
841f844e94eSwiz 	s = tiparm_s(1, 1, x, a);
842f844e94eSwiz #elif defined(HAVE_TIPARM)
843f844e94eSwiz 	s = tiparm(x, a);
844f844e94eSwiz #else
8453f0a6bcaSwiz 	s = tparm((char *)x, (long)a, 0, 0, 0, 0, 0, 0, 0, 0);
846f844e94eSwiz #endif
847f844e94eSwiz 	if (s == NULL) {
848f844e94eSwiz 		log_debug("could not expand %s", tty_term_codes[code].name);
849f844e94eSwiz 		return ("");
850f844e94eSwiz 	}
851f844e94eSwiz 	return (s);
8520f3d2746Sjmmv }
8530f3d2746Sjmmv 
8540f3d2746Sjmmv const char *
855f844e94eSwiz tty_term_string_ss(struct tty_term *term, enum tty_code_code code,
856f844e94eSwiz     const char *a, const char *b)
8570f3d2746Sjmmv {
858f844e94eSwiz 	const char	*x = tty_term_string(term, code), *s;
859f844e94eSwiz 
860f844e94eSwiz #if defined(HAVE_TIPARM_S)
861f844e94eSwiz 	s = tiparm_s(2, 3, x, a, b);
862f844e94eSwiz #elif defined(HAVE_TIPARM)
863f844e94eSwiz 	s = tiparm(x, a, b);
864f844e94eSwiz #else
8653f0a6bcaSwiz 	s = tparm((char *)x, (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0);
866f844e94eSwiz #endif
867f844e94eSwiz 	if (s == NULL) {
868f844e94eSwiz 		log_debug("could not expand %s", tty_term_codes[code].name);
869f844e94eSwiz 		return ("");
870f844e94eSwiz 	}
871f844e94eSwiz 	return (s);
8720f3d2746Sjmmv }
8730f3d2746Sjmmv 
874698d5317Sjmmv int
875698d5317Sjmmv tty_term_number(struct tty_term *term, enum tty_code_code code)
876698d5317Sjmmv {
877698d5317Sjmmv 	if (!tty_term_has(term, code))
878698d5317Sjmmv 		return (0);
879698d5317Sjmmv 	if (term->codes[code].type != TTYCODE_NUMBER)
880f26e8bc9Schristos 		fatalx("not a number: %d", code);
881698d5317Sjmmv 	return (term->codes[code].value.number);
882698d5317Sjmmv }
883698d5317Sjmmv 
884698d5317Sjmmv int
885698d5317Sjmmv tty_term_flag(struct tty_term *term, enum tty_code_code code)
886698d5317Sjmmv {
887698d5317Sjmmv 	if (!tty_term_has(term, code))
888698d5317Sjmmv 		return (0);
889698d5317Sjmmv 	if (term->codes[code].type != TTYCODE_FLAG)
890f26e8bc9Schristos 		fatalx("not a flag: %d", code);
891698d5317Sjmmv 	return (term->codes[code].value.flag);
892698d5317Sjmmv }
89399e242abSchristos 
89499e242abSchristos const char *
89599e242abSchristos tty_term_describe(struct tty_term *term, enum tty_code_code code)
89699e242abSchristos {
89799e242abSchristos 	static char	 s[256];
89899e242abSchristos 	char		 out[128];
89999e242abSchristos 
90099e242abSchristos 	switch (term->codes[code].type) {
90199e242abSchristos 	case TTYCODE_NONE:
90299e242abSchristos 		xsnprintf(s, sizeof s, "%4u: %s: [missing]",
90399e242abSchristos 		    code, tty_term_codes[code].name);
90499e242abSchristos 		break;
90599e242abSchristos 	case TTYCODE_STRING:
90699e242abSchristos 		strnvis(out, sizeof out, term->codes[code].value.string,
90730744affSchristos 		    VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
90899e242abSchristos 		xsnprintf(s, sizeof s, "%4u: %s: (string) %s",
90999e242abSchristos 		    code, tty_term_codes[code].name,
91099e242abSchristos 		    out);
91199e242abSchristos 		break;
91299e242abSchristos 	case TTYCODE_NUMBER:
91399e242abSchristos 		xsnprintf(s, sizeof s, "%4u: %s: (number) %d",
91499e242abSchristos 		    code, tty_term_codes[code].name,
91599e242abSchristos 		    term->codes[code].value.number);
91699e242abSchristos 		break;
91799e242abSchristos 	case TTYCODE_FLAG:
91899e242abSchristos 		xsnprintf(s, sizeof s, "%4u: %s: (flag) %s",
91999e242abSchristos 		    code, tty_term_codes[code].name,
92099e242abSchristos 		    term->codes[code].value.flag ? "true" : "false");
92199e242abSchristos 		break;
92299e242abSchristos 	}
92399e242abSchristos 	return (s);
92499e242abSchristos }
925