4 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
21 #if defined(HAVE_CURSES_H)
23 #elif defined(HAVE_NCURSES_H)
33 static char *tty_term_strip(const char *);
35 struct tty_terms tty_terms
= LIST_HEAD_INITIALIZER(tty_terms
);
45 enum tty_code_type type
;
53 struct tty_term_code_entry
{
54 enum tty_code_type type
;
58 static const struct tty_term_code_entry tty_term_codes
[] = {
59 [TTYC_ACSC
] = { TTYCODE_STRING
, "acsc" },
60 [TTYC_AM
] = { TTYCODE_FLAG
, "am" },
61 [TTYC_AX
] = { TTYCODE_FLAG
, "AX" },
62 [TTYC_BCE
] = { TTYCODE_FLAG
, "bce" },
63 [TTYC_BEL
] = { TTYCODE_STRING
, "bel" },
64 [TTYC_BIDI
] = { TTYCODE_STRING
, "Bidi" },
65 [TTYC_BLINK
] = { TTYCODE_STRING
, "blink" },
66 [TTYC_BOLD
] = { TTYCODE_STRING
, "bold" },
67 [TTYC_CIVIS
] = { TTYCODE_STRING
, "civis" },
68 [TTYC_CLEAR
] = { TTYCODE_STRING
, "clear" },
69 [TTYC_CLMG
] = { TTYCODE_STRING
, "Clmg" },
70 [TTYC_CMG
] = { TTYCODE_STRING
, "Cmg" },
71 [TTYC_CNORM
] = { TTYCODE_STRING
, "cnorm" },
72 [TTYC_COLORS
] = { TTYCODE_NUMBER
, "colors" },
73 [TTYC_CR
] = { TTYCODE_STRING
, "Cr" },
74 [TTYC_CSR
] = { TTYCODE_STRING
, "csr" },
75 [TTYC_CS
] = { TTYCODE_STRING
, "Cs" },
76 [TTYC_CUB1
] = { TTYCODE_STRING
, "cub1" },
77 [TTYC_CUB
] = { TTYCODE_STRING
, "cub" },
78 [TTYC_CUD1
] = { TTYCODE_STRING
, "cud1" },
79 [TTYC_CUD
] = { TTYCODE_STRING
, "cud" },
80 [TTYC_CUF1
] = { TTYCODE_STRING
, "cuf1" },
81 [TTYC_CUF
] = { TTYCODE_STRING
, "cuf" },
82 [TTYC_CUP
] = { TTYCODE_STRING
, "cup" },
83 [TTYC_CUU1
] = { TTYCODE_STRING
, "cuu1" },
84 [TTYC_CUU
] = { TTYCODE_STRING
, "cuu" },
85 [TTYC_CVVIS
] = { TTYCODE_STRING
, "cvvis" },
86 [TTYC_DCH1
] = { TTYCODE_STRING
, "dch1" },
87 [TTYC_DCH
] = { TTYCODE_STRING
, "dch" },
88 [TTYC_DIM
] = { TTYCODE_STRING
, "dim" },
89 [TTYC_DL1
] = { TTYCODE_STRING
, "dl1" },
90 [TTYC_DL
] = { TTYCODE_STRING
, "dl" },
91 [TTYC_DSEKS
] = { TTYCODE_STRING
, "Dseks" },
92 [TTYC_DSFCS
] = { TTYCODE_STRING
, "Dsfcs" },
93 [TTYC_DSBP
] = { TTYCODE_STRING
, "Dsbp" },
94 [TTYC_DSMG
] = { TTYCODE_STRING
, "Dsmg" },
95 [TTYC_E3
] = { TTYCODE_STRING
, "E3" },
96 [TTYC_ECH
] = { TTYCODE_STRING
, "ech" },
97 [TTYC_ED
] = { TTYCODE_STRING
, "ed" },
98 [TTYC_EL1
] = { TTYCODE_STRING
, "el1" },
99 [TTYC_EL
] = { TTYCODE_STRING
, "el" },
100 [TTYC_ENACS
] = { TTYCODE_STRING
, "enacs" },
101 [TTYC_ENBP
] = { TTYCODE_STRING
, "Enbp" },
102 [TTYC_ENEKS
] = { TTYCODE_STRING
, "Eneks" },
103 [TTYC_ENFCS
] = { TTYCODE_STRING
, "Enfcs" },
104 [TTYC_ENMG
] = { TTYCODE_STRING
, "Enmg" },
105 [TTYC_FSL
] = { TTYCODE_STRING
, "fsl" },
106 [TTYC_HLS
] = { TTYCODE_STRING
, "Hls" },
107 [TTYC_HOME
] = { TTYCODE_STRING
, "home" },
108 [TTYC_HPA
] = { TTYCODE_STRING
, "hpa" },
109 [TTYC_ICH1
] = { TTYCODE_STRING
, "ich1" },
110 [TTYC_ICH
] = { TTYCODE_STRING
, "ich" },
111 [TTYC_IL1
] = { TTYCODE_STRING
, "il1" },
112 [TTYC_IL
] = { TTYCODE_STRING
, "il" },
113 [TTYC_INDN
] = { TTYCODE_STRING
, "indn" },
114 [TTYC_INVIS
] = { TTYCODE_STRING
, "invis" },
115 [TTYC_KCBT
] = { TTYCODE_STRING
, "kcbt" },
116 [TTYC_KCUB1
] = { TTYCODE_STRING
, "kcub1" },
117 [TTYC_KCUD1
] = { TTYCODE_STRING
, "kcud1" },
118 [TTYC_KCUF1
] = { TTYCODE_STRING
, "kcuf1" },
119 [TTYC_KCUU1
] = { TTYCODE_STRING
, "kcuu1" },
120 [TTYC_KDC2
] = { TTYCODE_STRING
, "kDC" },
121 [TTYC_KDC3
] = { TTYCODE_STRING
, "kDC3" },
122 [TTYC_KDC4
] = { TTYCODE_STRING
, "kDC4" },
123 [TTYC_KDC5
] = { TTYCODE_STRING
, "kDC5" },
124 [TTYC_KDC6
] = { TTYCODE_STRING
, "kDC6" },
125 [TTYC_KDC7
] = { TTYCODE_STRING
, "kDC7" },
126 [TTYC_KDCH1
] = { TTYCODE_STRING
, "kdch1" },
127 [TTYC_KDN2
] = { TTYCODE_STRING
, "kDN" }, /* not kDN2 */
128 [TTYC_KDN3
] = { TTYCODE_STRING
, "kDN3" },
129 [TTYC_KDN4
] = { TTYCODE_STRING
, "kDN4" },
130 [TTYC_KDN5
] = { TTYCODE_STRING
, "kDN5" },
131 [TTYC_KDN6
] = { TTYCODE_STRING
, "kDN6" },
132 [TTYC_KDN7
] = { TTYCODE_STRING
, "kDN7" },
133 [TTYC_KEND2
] = { TTYCODE_STRING
, "kEND" },
134 [TTYC_KEND3
] = { TTYCODE_STRING
, "kEND3" },
135 [TTYC_KEND4
] = { TTYCODE_STRING
, "kEND4" },
136 [TTYC_KEND5
] = { TTYCODE_STRING
, "kEND5" },
137 [TTYC_KEND6
] = { TTYCODE_STRING
, "kEND6" },
138 [TTYC_KEND7
] = { TTYCODE_STRING
, "kEND7" },
139 [TTYC_KEND
] = { TTYCODE_STRING
, "kend" },
140 [TTYC_KF10
] = { TTYCODE_STRING
, "kf10" },
141 [TTYC_KF11
] = { TTYCODE_STRING
, "kf11" },
142 [TTYC_KF12
] = { TTYCODE_STRING
, "kf12" },
143 [TTYC_KF13
] = { TTYCODE_STRING
, "kf13" },
144 [TTYC_KF14
] = { TTYCODE_STRING
, "kf14" },
145 [TTYC_KF15
] = { TTYCODE_STRING
, "kf15" },
146 [TTYC_KF16
] = { TTYCODE_STRING
, "kf16" },
147 [TTYC_KF17
] = { TTYCODE_STRING
, "kf17" },
148 [TTYC_KF18
] = { TTYCODE_STRING
, "kf18" },
149 [TTYC_KF19
] = { TTYCODE_STRING
, "kf19" },
150 [TTYC_KF1
] = { TTYCODE_STRING
, "kf1" },
151 [TTYC_KF20
] = { TTYCODE_STRING
, "kf20" },
152 [TTYC_KF21
] = { TTYCODE_STRING
, "kf21" },
153 [TTYC_KF22
] = { TTYCODE_STRING
, "kf22" },
154 [TTYC_KF23
] = { TTYCODE_STRING
, "kf23" },
155 [TTYC_KF24
] = { TTYCODE_STRING
, "kf24" },
156 [TTYC_KF25
] = { TTYCODE_STRING
, "kf25" },
157 [TTYC_KF26
] = { TTYCODE_STRING
, "kf26" },
158 [TTYC_KF27
] = { TTYCODE_STRING
, "kf27" },
159 [TTYC_KF28
] = { TTYCODE_STRING
, "kf28" },
160 [TTYC_KF29
] = { TTYCODE_STRING
, "kf29" },
161 [TTYC_KF2
] = { TTYCODE_STRING
, "kf2" },
162 [TTYC_KF30
] = { TTYCODE_STRING
, "kf30" },
163 [TTYC_KF31
] = { TTYCODE_STRING
, "kf31" },
164 [TTYC_KF32
] = { TTYCODE_STRING
, "kf32" },
165 [TTYC_KF33
] = { TTYCODE_STRING
, "kf33" },
166 [TTYC_KF34
] = { TTYCODE_STRING
, "kf34" },
167 [TTYC_KF35
] = { TTYCODE_STRING
, "kf35" },
168 [TTYC_KF36
] = { TTYCODE_STRING
, "kf36" },
169 [TTYC_KF37
] = { TTYCODE_STRING
, "kf37" },
170 [TTYC_KF38
] = { TTYCODE_STRING
, "kf38" },
171 [TTYC_KF39
] = { TTYCODE_STRING
, "kf39" },
172 [TTYC_KF3
] = { TTYCODE_STRING
, "kf3" },
173 [TTYC_KF40
] = { TTYCODE_STRING
, "kf40" },
174 [TTYC_KF41
] = { TTYCODE_STRING
, "kf41" },
175 [TTYC_KF42
] = { TTYCODE_STRING
, "kf42" },
176 [TTYC_KF43
] = { TTYCODE_STRING
, "kf43" },
177 [TTYC_KF44
] = { TTYCODE_STRING
, "kf44" },
178 [TTYC_KF45
] = { TTYCODE_STRING
, "kf45" },
179 [TTYC_KF46
] = { TTYCODE_STRING
, "kf46" },
180 [TTYC_KF47
] = { TTYCODE_STRING
, "kf47" },
181 [TTYC_KF48
] = { TTYCODE_STRING
, "kf48" },
182 [TTYC_KF49
] = { TTYCODE_STRING
, "kf49" },
183 [TTYC_KF4
] = { TTYCODE_STRING
, "kf4" },
184 [TTYC_KF50
] = { TTYCODE_STRING
, "kf50" },
185 [TTYC_KF51
] = { TTYCODE_STRING
, "kf51" },
186 [TTYC_KF52
] = { TTYCODE_STRING
, "kf52" },
187 [TTYC_KF53
] = { TTYCODE_STRING
, "kf53" },
188 [TTYC_KF54
] = { TTYCODE_STRING
, "kf54" },
189 [TTYC_KF55
] = { TTYCODE_STRING
, "kf55" },
190 [TTYC_KF56
] = { TTYCODE_STRING
, "kf56" },
191 [TTYC_KF57
] = { TTYCODE_STRING
, "kf57" },
192 [TTYC_KF58
] = { TTYCODE_STRING
, "kf58" },
193 [TTYC_KF59
] = { TTYCODE_STRING
, "kf59" },
194 [TTYC_KF5
] = { TTYCODE_STRING
, "kf5" },
195 [TTYC_KF60
] = { TTYCODE_STRING
, "kf60" },
196 [TTYC_KF61
] = { TTYCODE_STRING
, "kf61" },
197 [TTYC_KF62
] = { TTYCODE_STRING
, "kf62" },
198 [TTYC_KF63
] = { TTYCODE_STRING
, "kf63" },
199 [TTYC_KF6
] = { TTYCODE_STRING
, "kf6" },
200 [TTYC_KF7
] = { TTYCODE_STRING
, "kf7" },
201 [TTYC_KF8
] = { TTYCODE_STRING
, "kf8" },
202 [TTYC_KF9
] = { TTYCODE_STRING
, "kf9" },
203 [TTYC_KHOM2
] = { TTYCODE_STRING
, "kHOM" },
204 [TTYC_KHOM3
] = { TTYCODE_STRING
, "kHOM3" },
205 [TTYC_KHOM4
] = { TTYCODE_STRING
, "kHOM4" },
206 [TTYC_KHOM5
] = { TTYCODE_STRING
, "kHOM5" },
207 [TTYC_KHOM6
] = { TTYCODE_STRING
, "kHOM6" },
208 [TTYC_KHOM7
] = { TTYCODE_STRING
, "kHOM7" },
209 [TTYC_KHOME
] = { TTYCODE_STRING
, "khome" },
210 [TTYC_KIC2
] = { TTYCODE_STRING
, "kIC" },
211 [TTYC_KIC3
] = { TTYCODE_STRING
, "kIC3" },
212 [TTYC_KIC4
] = { TTYCODE_STRING
, "kIC4" },
213 [TTYC_KIC5
] = { TTYCODE_STRING
, "kIC5" },
214 [TTYC_KIC6
] = { TTYCODE_STRING
, "kIC6" },
215 [TTYC_KIC7
] = { TTYCODE_STRING
, "kIC7" },
216 [TTYC_KICH1
] = { TTYCODE_STRING
, "kich1" },
217 [TTYC_KIND
] = { TTYCODE_STRING
, "kind" },
218 [TTYC_KLFT2
] = { TTYCODE_STRING
, "kLFT" },
219 [TTYC_KLFT3
] = { TTYCODE_STRING
, "kLFT3" },
220 [TTYC_KLFT4
] = { TTYCODE_STRING
, "kLFT4" },
221 [TTYC_KLFT5
] = { TTYCODE_STRING
, "kLFT5" },
222 [TTYC_KLFT6
] = { TTYCODE_STRING
, "kLFT6" },
223 [TTYC_KLFT7
] = { TTYCODE_STRING
, "kLFT7" },
224 [TTYC_KMOUS
] = { TTYCODE_STRING
, "kmous" },
225 [TTYC_KNP
] = { TTYCODE_STRING
, "knp" },
226 [TTYC_KNXT2
] = { TTYCODE_STRING
, "kNXT" },
227 [TTYC_KNXT3
] = { TTYCODE_STRING
, "kNXT3" },
228 [TTYC_KNXT4
] = { TTYCODE_STRING
, "kNXT4" },
229 [TTYC_KNXT5
] = { TTYCODE_STRING
, "kNXT5" },
230 [TTYC_KNXT6
] = { TTYCODE_STRING
, "kNXT6" },
231 [TTYC_KNXT7
] = { TTYCODE_STRING
, "kNXT7" },
232 [TTYC_KPP
] = { TTYCODE_STRING
, "kpp" },
233 [TTYC_KPRV2
] = { TTYCODE_STRING
, "kPRV" },
234 [TTYC_KPRV3
] = { TTYCODE_STRING
, "kPRV3" },
235 [TTYC_KPRV4
] = { TTYCODE_STRING
, "kPRV4" },
236 [TTYC_KPRV5
] = { TTYCODE_STRING
, "kPRV5" },
237 [TTYC_KPRV6
] = { TTYCODE_STRING
, "kPRV6" },
238 [TTYC_KPRV7
] = { TTYCODE_STRING
, "kPRV7" },
239 [TTYC_KRIT2
] = { TTYCODE_STRING
, "kRIT" },
240 [TTYC_KRIT3
] = { TTYCODE_STRING
, "kRIT3" },
241 [TTYC_KRIT4
] = { TTYCODE_STRING
, "kRIT4" },
242 [TTYC_KRIT5
] = { TTYCODE_STRING
, "kRIT5" },
243 [TTYC_KRIT6
] = { TTYCODE_STRING
, "kRIT6" },
244 [TTYC_KRIT7
] = { TTYCODE_STRING
, "kRIT7" },
245 [TTYC_KRI
] = { TTYCODE_STRING
, "kri" },
246 [TTYC_KUP2
] = { TTYCODE_STRING
, "kUP" }, /* not kUP2 */
247 [TTYC_KUP3
] = { TTYCODE_STRING
, "kUP3" },
248 [TTYC_KUP4
] = { TTYCODE_STRING
, "kUP4" },
249 [TTYC_KUP5
] = { TTYCODE_STRING
, "kUP5" },
250 [TTYC_KUP6
] = { TTYCODE_STRING
, "kUP6" },
251 [TTYC_KUP7
] = { TTYCODE_STRING
, "kUP7" },
252 [TTYC_MS
] = { TTYCODE_STRING
, "Ms" },
253 [TTYC_NOBR
] = { TTYCODE_STRING
, "Nobr" },
254 [TTYC_OL
] = { TTYCODE_STRING
, "ol" },
255 [TTYC_OP
] = { TTYCODE_STRING
, "op" },
256 [TTYC_RECT
] = { TTYCODE_STRING
, "Rect" },
257 [TTYC_REV
] = { TTYCODE_STRING
, "rev" },
258 [TTYC_RGB
] = { TTYCODE_FLAG
, "RGB" },
259 [TTYC_RIN
] = { TTYCODE_STRING
, "rin" },
260 [TTYC_RI
] = { TTYCODE_STRING
, "ri" },
261 [TTYC_RMACS
] = { TTYCODE_STRING
, "rmacs" },
262 [TTYC_RMCUP
] = { TTYCODE_STRING
, "rmcup" },
263 [TTYC_RMKX
] = { TTYCODE_STRING
, "rmkx" },
264 [TTYC_SETAB
] = { TTYCODE_STRING
, "setab" },
265 [TTYC_SETAF
] = { TTYCODE_STRING
, "setaf" },
266 [TTYC_SETAL
] = { TTYCODE_STRING
, "setal" },
267 [TTYC_SETRGBB
] = { TTYCODE_STRING
, "setrgbb" },
268 [TTYC_SETRGBF
] = { TTYCODE_STRING
, "setrgbf" },
269 [TTYC_SETULC
] = { TTYCODE_STRING
, "Setulc" },
270 [TTYC_SETULC1
] = { TTYCODE_STRING
, "Setulc1" },
271 [TTYC_SE
] = { TTYCODE_STRING
, "Se" },
272 [TTYC_SXL
] = { TTYCODE_FLAG
, "Sxl" },
273 [TTYC_SGR0
] = { TTYCODE_STRING
, "sgr0" },
274 [TTYC_SITM
] = { TTYCODE_STRING
, "sitm" },
275 [TTYC_SMACS
] = { TTYCODE_STRING
, "smacs" },
276 [TTYC_SMCUP
] = { TTYCODE_STRING
, "smcup" },
277 [TTYC_SMKX
] = { TTYCODE_STRING
, "smkx" },
278 [TTYC_SMOL
] = { TTYCODE_STRING
, "Smol" },
279 [TTYC_SMSO
] = { TTYCODE_STRING
, "smso" },
280 [TTYC_SMULX
] = { TTYCODE_STRING
, "Smulx" },
281 [TTYC_SMUL
] = { TTYCODE_STRING
, "smul" },
282 [TTYC_SMXX
] = { TTYCODE_STRING
, "smxx" },
283 [TTYC_SS
] = { TTYCODE_STRING
, "Ss" },
284 [TTYC_SWD
] = { TTYCODE_STRING
, "Swd" },
285 [TTYC_SYNC
] = { TTYCODE_STRING
, "Sync" },
286 [TTYC_TC
] = { TTYCODE_FLAG
, "Tc" },
287 [TTYC_TSL
] = { TTYCODE_STRING
, "tsl" },
288 [TTYC_U8
] = { TTYCODE_NUMBER
, "U8" },
289 [TTYC_VPA
] = { TTYCODE_STRING
, "vpa" },
290 [TTYC_XT
] = { TTYCODE_FLAG
, "XT" }
294 tty_term_ncodes(void)
296 return (nitems(tty_term_codes
));
300 tty_term_strip(const char *s
)
303 static char buf
[8192];
306 /* Ignore strings with no padding. */
307 if (strchr(s
, '$') == NULL
)
311 for (ptr
= s
; *ptr
!= '\0'; ptr
++) {
312 if (*ptr
== '$' && *(ptr
+ 1) == '<') {
313 while (*ptr
!= '\0' && *ptr
!= '>')
322 if (len
== (sizeof buf
) - 1)
327 return (xstrdup(buf
));
331 tty_term_override_next(const char *s
, size_t *offset
)
333 static char value
[8192];
334 size_t n
= 0, at
= *offset
;
339 while (s
[at
] != '\0') {
341 if (s
[at
+ 1] == ':') {
350 if (n
== (sizeof value
) - 1)
362 tty_term_apply(struct tty_term
*term
, const char *capabilities
, int quiet
)
364 const struct tty_term_code_entry
*ent
;
365 struct tty_code
*code
;
367 char *cp
, *value
, *s
;
368 const char *errstr
, *name
= term
->name
;
372 while ((s
= tty_term_override_next(capabilities
, &offset
)) != NULL
) {
378 if ((cp
= strchr(s
, '=')) != NULL
) {
381 if (strunvis(value
, cp
) == -1) {
385 } else if (s
[strlen(s
) - 1] == '@') {
386 s
[strlen(s
) - 1] = '\0';
393 log_debug("%s override: %s@", name
, s
);
394 else if (*value
== '\0')
395 log_debug("%s override: %s", name
, s
);
397 log_debug("%s override: %s=%s", name
, s
, value
);
400 for (i
= 0; i
< tty_term_ncodes(); i
++) {
401 ent
= &tty_term_codes
[i
];
402 if (strcmp(s
, ent
->name
) != 0)
404 code
= &term
->codes
[i
];
407 code
->type
= TTYCODE_NONE
;
414 if (code
->type
== TTYCODE_STRING
)
415 free(code
->value
.string
);
416 code
->value
.string
= xstrdup(value
);
417 code
->type
= ent
->type
;
420 n
= strtonum(value
, 0, INT_MAX
, &errstr
);
423 code
->value
.number
= n
;
424 code
->type
= ent
->type
;
427 code
->value
.flag
= 1;
428 code
->type
= ent
->type
;
438 tty_term_apply_overrides(struct tty_term
*term
)
440 struct options_entry
*o
;
441 struct options_array_item
*a
;
442 union options_value
*ov
;
447 /* Update capabilities from the option. */
448 o
= options_get_only(global_options
, "terminal-overrides");
449 a
= options_array_first(o
);
451 ov
= options_array_item_value(a
);
455 first
= tty_term_override_next(s
, &offset
);
456 if (first
!= NULL
&& fnmatch(first
, term
->name
, 0) == 0)
457 tty_term_apply(term
, s
+ offset
, 0);
458 a
= options_array_next(a
);
461 /* Log the SIXEL flag. */
462 log_debug("SIXEL flag is %d", !!(term
->flags
& TERM_SIXEL
));
464 /* Update the RGB flag if the terminal has RGB colours. */
465 if (tty_term_has(term
, TTYC_SETRGBF
) &&
466 tty_term_has(term
, TTYC_SETRGBB
))
467 term
->flags
|= TERM_RGBCOLOURS
;
469 term
->flags
&= ~TERM_RGBCOLOURS
;
470 log_debug("RGBCOLOURS flag is %d", !!(term
->flags
& TERM_RGBCOLOURS
));
473 * Set or clear the DECSLRM flag if the terminal has the margin
476 if (tty_term_has(term
, TTYC_CMG
) && tty_term_has(term
, TTYC_CLMG
))
477 term
->flags
|= TERM_DECSLRM
;
479 term
->flags
&= ~TERM_DECSLRM
;
480 log_debug("DECSLRM flag is %d", !!(term
->flags
& TERM_DECSLRM
));
483 * Set or clear the DECFRA flag if the terminal has the rectangle
486 if (tty_term_has(term
, TTYC_RECT
))
487 term
->flags
|= TERM_DECFRA
;
489 term
->flags
&= ~TERM_DECFRA
;
490 log_debug("DECFRA flag is %d", !!(term
->flags
& TERM_DECFRA
));
493 * Terminals without am (auto right margin) wrap at at $COLUMNS - 1
494 * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
496 * Terminals without xenl (eat newline glitch) ignore a newline beyond
497 * the right edge of the terminal, but tmux doesn't care about this -
498 * it always uses absolute only moves the cursor with a newline when
499 * also sending a linefeed.
501 * This is irritating, most notably because it is painful to write to
502 * the very bottom-right of the screen without scrolling.
504 * Flag the terminal here and apply some workarounds in other places to
505 * do the best possible.
507 if (!tty_term_flag(term
, TTYC_AM
))
508 term
->flags
|= TERM_NOAM
;
510 term
->flags
&= ~TERM_NOAM
;
511 log_debug("NOAM flag is %d", !!(term
->flags
& TERM_NOAM
));
513 /* Generate ACS table. If none is present, use nearest ASCII. */
514 memset(term
->acs
, 0, sizeof term
->acs
);
515 if (tty_term_has(term
, TTYC_ACSC
))
516 acs
= tty_term_string(term
, TTYC_ACSC
);
518 acs
= "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~.";
519 for (; acs
[0] != '\0' && acs
[1] != '\0'; acs
+= 2)
520 term
->acs
[(u_char
) acs
[0]][0] = acs
[1];
524 tty_term_create(struct tty
*tty
, char *name
, char **caps
, u_int ncaps
,
525 int *feat
, char **cause
)
527 struct tty_term
*term
;
528 const struct tty_term_code_entry
*ent
;
529 struct tty_code
*code
;
530 struct options_entry
*o
;
531 struct options_array_item
*a
;
532 union options_value
*ov
;
534 const char *s
, *value
, *errstr
;
535 size_t offset
, namelen
;
539 log_debug("adding term %s", name
);
541 term
= xcalloc(1, sizeof *term
);
543 term
->name
= xstrdup(name
);
544 term
->codes
= xcalloc(tty_term_ncodes(), sizeof *term
->codes
);
545 LIST_INSERT_HEAD(&tty_terms
, term
, entry
);
548 for (i
= 0; i
< ncaps
; i
++) {
549 namelen
= strcspn(caps
[i
], "=");
552 value
= caps
[i
] + namelen
+ 1;
554 for (j
= 0; j
< tty_term_ncodes(); j
++) {
555 ent
= &tty_term_codes
[j
];
556 if (strncmp(ent
->name
, caps
[i
], namelen
) != 0)
558 if (ent
->name
[namelen
] != '\0')
561 code
= &term
->codes
[j
];
562 code
->type
= TTYCODE_NONE
;
567 code
->type
= TTYCODE_STRING
;
568 code
->value
.string
= tty_term_strip(value
);
571 n
= strtonum(value
, 0, INT_MAX
, &errstr
);
573 log_debug("%s: %s", ent
->name
, errstr
);
575 code
->type
= TTYCODE_NUMBER
;
576 code
->value
.number
= n
;
580 code
->type
= TTYCODE_FLAG
;
581 code
->value
.flag
= (*value
== '1');
587 /* Apply terminal features. */
588 o
= options_get_only(global_options
, "terminal-features");
589 a
= options_array_first(o
);
591 ov
= options_array_item_value(a
);
595 first
= tty_term_override_next(s
, &offset
);
596 if (first
!= NULL
&& fnmatch(first
, term
->name
, 0) == 0)
597 tty_add_features(feat
, s
+ offset
, ":");
598 a
= options_array_next(a
);
601 /* Delete curses data. */
602 #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
603 (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
604 del_curterm(cur_term
);
607 /* Apply overrides so any capabilities used for features are changed. */
608 tty_term_apply_overrides(term
);
610 /* These are always required. */
611 if (!tty_term_has(term
, TTYC_CLEAR
)) {
612 xasprintf(cause
, "terminal does not support clear");
615 if (!tty_term_has(term
, TTYC_CUP
)) {
616 xasprintf(cause
, "terminal does not support cup");
621 * If TERM has XT or clear starts with CSI then it is safe to assume
622 * the terminal is derived from the VT100. This controls whether device
623 * attributes requests are sent to get more information.
625 * This is a bit of a hack but there aren't that many alternatives.
626 * Worst case tmux will just fall back to using whatever terminfo(5)
627 * says without trying to correct anything that is missing.
629 * Also add few features that VT100-like terminals should either
630 * support or safely ignore.
632 s
= tty_term_string(term
, TTYC_CLEAR
);
633 if (tty_term_flag(term
, TTYC_XT
) || strncmp(s
, "\033[", 2) == 0) {
634 term
->flags
|= TERM_VT100LIKE
;
635 tty_add_features(feat
, "bpaste,focus,title", ",");
638 /* Add RGB feature if terminal has RGB colours. */
639 if ((tty_term_flag(term
, TTYC_TC
) || tty_term_has(term
, TTYC_RGB
)) &&
640 (!tty_term_has(term
, TTYC_SETRGBF
) ||
641 !tty_term_has(term
, TTYC_SETRGBB
)))
642 tty_add_features(feat
, "RGB", ",");
644 /* Apply the features and overrides again. */
645 if (tty_apply_features(term
, *feat
))
646 tty_term_apply_overrides(term
);
648 /* Log the capabilities. */
649 for (i
= 0; i
< tty_term_ncodes(); i
++)
650 log_debug("%s%s", name
, tty_term_describe(term
, i
));
660 tty_term_free(struct tty_term
*term
)
664 log_debug("removing term %s", term
->name
);
666 for (i
= 0; i
< tty_term_ncodes(); i
++) {
667 if (term
->codes
[i
].type
== TTYCODE_STRING
)
668 free(term
->codes
[i
].value
.string
);
672 LIST_REMOVE(term
, entry
);
678 tty_term_read_list(const char *name
, int fd
, char ***caps
, u_int
*ncaps
,
681 const struct tty_term_code_entry
*ent
;
687 if (setupterm((char *)name
, fd
, &error
) != OK
) {
690 xasprintf(cause
, "can't use hardcopy terminal: %s",
694 xasprintf(cause
, "missing or unsuitable terminal: %s",
698 xasprintf(cause
, "can't find terminfo database");
701 xasprintf(cause
, "unknown error");
710 for (i
= 0; i
< tty_term_ncodes(); i
++) {
711 ent
= &tty_term_codes
[i
];
716 s
= tigetstr((char *)ent
->name
);
717 if (s
== NULL
|| s
== (char *)-1)
721 n
= tigetnum((char *)ent
->name
);
722 if (n
== -1 || n
== -2)
724 xsnprintf(tmp
, sizeof tmp
, "%d", n
);
728 n
= tigetflag((char *)ent
->name
);
737 fatalx("unknown capability type");
739 *caps
= xreallocarray(*caps
, (*ncaps
) + 1, sizeof **caps
);
740 xasprintf(&(*caps
)[*ncaps
], "%s=%s", ent
->name
, s
);
744 #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
745 (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
746 del_curterm(cur_term
);
752 tty_term_free_list(char **caps
, u_int ncaps
)
756 for (i
= 0; i
< ncaps
; i
++)
762 tty_term_has(struct tty_term
*term
, enum tty_code_code code
)
764 return (term
->codes
[code
].type
!= TTYCODE_NONE
);
768 tty_term_string(struct tty_term
*term
, enum tty_code_code code
)
770 if (!tty_term_has(term
, code
))
772 if (term
->codes
[code
].type
!= TTYCODE_STRING
)
773 fatalx("not a string: %d", code
);
774 return (term
->codes
[code
].value
.string
);
778 tty_term_string_i(struct tty_term
*term
, enum tty_code_code code
, int a
)
780 const char *x
= tty_term_string(term
, code
), *s
;
782 #if defined(HAVE_TIPARM_S)
783 s
= tiparm_s(1, 0, x
, a
);
784 #elif defined(HAVE_TIPARM)
787 s
= tparm((char *)x
, a
, 0, 0, 0, 0, 0, 0, 0, 0);
790 log_debug("could not expand %s", tty_term_codes
[code
].name
);
797 tty_term_string_ii(struct tty_term
*term
, enum tty_code_code code
, int a
, int b
)
799 const char *x
= tty_term_string(term
, code
), *s
;
801 #if defined(HAVE_TIPARM_S)
802 s
= tiparm_s(2, 0, x
, a
, b
);
803 #elif defined(HAVE_TIPARM)
806 s
= tparm((char *)x
, a
, b
, 0, 0, 0, 0, 0, 0, 0);
809 log_debug("could not expand %s", tty_term_codes
[code
].name
);
816 tty_term_string_iii(struct tty_term
*term
, enum tty_code_code code
, int a
,
819 const char *x
= tty_term_string(term
, code
), *s
;
821 #if defined(HAVE_TIPARM_S)
822 s
= tiparm_s(3, 0, x
, a
, b
, c
);
823 #elif defined(HAVE_TIPARM)
824 s
= tiparm(x
, a
, b
, c
);
826 s
= tparm((char *)x
, a
, b
, c
, 0, 0, 0, 0, 0, 0);
829 log_debug("could not expand %s", tty_term_codes
[code
].name
);
836 tty_term_string_s(struct tty_term
*term
, enum tty_code_code code
, const char *a
)
838 const char *x
= tty_term_string(term
, code
), *s
;
840 #if defined(HAVE_TIPARM_S)
841 s
= tiparm_s(1, 1, x
, a
);
842 #elif defined(HAVE_TIPARM)
845 s
= tparm((char *)x
, (long)a
, 0, 0, 0, 0, 0, 0, 0, 0);
848 log_debug("could not expand %s", tty_term_codes
[code
].name
);
855 tty_term_string_ss(struct tty_term
*term
, enum tty_code_code code
,
856 const char *a
, const char *b
)
858 const char *x
= tty_term_string(term
, code
), *s
;
860 #if defined(HAVE_TIPARM_S)
861 s
= tiparm_s(2, 3, x
, a
, b
);
862 #elif defined(HAVE_TIPARM)
865 s
= tparm((char *)x
, (long)a
, (long)b
, 0, 0, 0, 0, 0, 0, 0);
868 log_debug("could not expand %s", tty_term_codes
[code
].name
);
875 tty_term_number(struct tty_term
*term
, enum tty_code_code code
)
877 if (!tty_term_has(term
, code
))
879 if (term
->codes
[code
].type
!= TTYCODE_NUMBER
)
880 fatalx("not a number: %d", code
);
881 return (term
->codes
[code
].value
.number
);
885 tty_term_flag(struct tty_term
*term
, enum tty_code_code code
)
887 if (!tty_term_has(term
, code
))
889 if (term
->codes
[code
].type
!= TTYCODE_FLAG
)
890 fatalx("not a flag: %d", code
);
891 return (term
->codes
[code
].value
.flag
);
895 tty_term_describe(struct tty_term
*term
, enum tty_code_code code
)
900 switch (term
->codes
[code
].type
) {
902 xsnprintf(s
, sizeof s
, "%4u: %s: [missing]",
903 code
, tty_term_codes
[code
].name
);
906 strnvis(out
, term
->codes
[code
].value
.string
, sizeof out
,
907 VIS_OCTAL
|VIS_CSTYLE
|VIS_TAB
|VIS_NL
);
908 xsnprintf(s
, sizeof s
, "%4u: %s: (string) %s",
909 code
, tty_term_codes
[code
].name
,
913 xsnprintf(s
, sizeof s
, "%4u: %s: (number) %d",
914 code
, tty_term_codes
[code
].name
,
915 term
->codes
[code
].value
.number
);
918 xsnprintf(s
, sizeof s
, "%4u: %s: (flag) %s",
919 code
, tty_term_codes
[code
].name
,
920 term
->codes
[code
].value
.flag
? "true" : "false");