1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
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.
9  *
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.
17  */
18 
19 #include <sys/types.h>
20 
21 #if defined(HAVE_CURSES_H)
22 #include <curses.h>
23 #elif defined(HAVE_NCURSES_H)
24 #include <ncurses.h>
25 #endif
26 #include <fnmatch.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <term.h>
30 
31 #include "tmux.h"
32 
33 static char         *tty_term_strip(const char *);
34 
35 struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms);
36 
37 enum tty_code_type {
38           TTYCODE_NONE = 0,
39           TTYCODE_STRING,
40           TTYCODE_NUMBER,
41           TTYCODE_FLAG,
42 };
43 
44 struct tty_code {
45           enum tty_code_type  type;
46           union {
47                     char             *string;
48                     int                 number;
49                     int                 flag;
50           } value;
51 };
52 
53 struct tty_term_code_entry {
54           enum tty_code_type  type;
55           const char                 *name;
56 };
57 
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" }
291 };
292 
293 u_int
tty_term_ncodes(void)294 tty_term_ncodes(void)
295 {
296           return (nitems(tty_term_codes));
297 }
298 
299 static char *
tty_term_strip(const char * s)300 tty_term_strip(const char *s)
301 {
302           const char     *ptr;
303           static char         buf[8192];
304           size_t              len;
305 
306           /* Ignore strings with no padding. */
307           if (strchr(s, '$') == NULL)
308                     return (xstrdup(s));
309 
310           len = 0;
311           for (ptr = s; *ptr != '\0'; ptr++) {
312                     if (*ptr == '$' && *(ptr + 1) == '<') {
313                               while (*ptr != '\0' && *ptr != '>')
314                                         ptr++;
315                               if (*ptr == '>')
316                                         ptr++;
317                               if (*ptr == '\0')
318                                         break;
319                     }
320 
321                     buf[len++] = *ptr;
322                     if (len == (sizeof buf) - 1)
323                               break;
324           }
325           buf[len] = '\0';
326 
327           return (xstrdup(buf));
328 }
329 
330 static char *
tty_term_override_next(const char * s,size_t * offset)331 tty_term_override_next(const char *s, size_t *offset)
332 {
333           static char         value[8192];
334           size_t              n = 0, at = *offset;
335 
336           if (s[at] == '\0')
337                     return (NULL);
338 
339           while (s[at] != '\0') {
340                     if (s[at] == ':') {
341                               if (s[at + 1] == ':') {
342                                         value[n++] = ':';
343                                         at += 2;
344                               } else
345                                         break;
346                     } else {
347                               value[n++] = s[at];
348                               at++;
349                     }
350                     if (n == (sizeof value) - 1)
351                               return (NULL);
352           }
353           if (s[at] != '\0')
354                     *offset = at + 1;
355           else
356                     *offset = at;
357           value[n] = '\0';
358           return (value);
359 }
360 
361 void
tty_term_apply(struct tty_term * term,const char * capabilities,int quiet)362 tty_term_apply(struct tty_term *term, const char *capabilities, int quiet)
363 {
364           const struct tty_term_code_entry        *ent;
365           struct tty_code                                   *code;
366           size_t                                   offset = 0;
367           char                                              *cp, *value, *s;
368           const char                                        *errstr, *name = term->name;
369           u_int                                              i;
370           int                                                n, remove;
371 
372           while ((s = tty_term_override_next(capabilities, &offset)) != NULL) {
373                     if (*s == '\0')
374                               continue;
375                     value = NULL;
376 
377                     remove = 0;
378                     if ((cp = strchr(s, '=')) != NULL) {
379                               *cp++ = '\0';
380                               value = xstrdup(cp);
381                               if (strunvis(value, cp) == -1) {
382                                         free(value);
383                                         value = xstrdup(cp);
384                               }
385                     } else if (s[strlen(s) - 1] == '@') {
386                               s[strlen(s) - 1] = '\0';
387                               remove = 1;
388                     } else
389                               value = xstrdup("");
390 
391                     if (!quiet) {
392                               if (remove)
393                                         log_debug("%s override: %s@", name, s);
394                               else if (*value == '\0')
395                                         log_debug("%s override: %s", name, s);
396                               else
397                                         log_debug("%s override: %s=%s", name, s, value);
398                     }
399 
400                     for (i = 0; i < tty_term_ncodes(); i++) {
401                               ent = &tty_term_codes[i];
402                               if (strcmp(s, ent->name) != 0)
403                                         continue;
404                               code = &term->codes[i];
405 
406                               if (remove) {
407                                         code->type = TTYCODE_NONE;
408                                         continue;
409                               }
410                               switch (ent->type) {
411                               case TTYCODE_NONE:
412                                         break;
413                               case TTYCODE_STRING:
414                                         if (code->type == TTYCODE_STRING)
415                                                   free(code->value.string);
416                                         code->value.string = xstrdup(value);
417                                         code->type = ent->type;
418                                         break;
419                               case TTYCODE_NUMBER:
420                                         n = strtonum(value, 0, INT_MAX, &errstr);
421                                         if (errstr != NULL)
422                                                   break;
423                                         code->value.number = n;
424                                         code->type = ent->type;
425                                         break;
426                               case TTYCODE_FLAG:
427                                         code->value.flag = 1;
428                                         code->type = ent->type;
429                                         break;
430                               }
431                     }
432 
433                     free(value);
434           }
435 }
436 
437 void
tty_term_apply_overrides(struct tty_term * term)438 tty_term_apply_overrides(struct tty_term *term)
439 {
440           struct options_entry                    *o;
441           struct options_array_item     *a;
442           union options_value           *ov;
443           const char                              *s, *acs;
444           size_t                                   offset;
445           char                                    *first;
446 
447           /* Update capabilities from the option. */
448           o = options_get_only(global_options, "terminal-overrides");
449           a = options_array_first(o);
450           while (a != NULL) {
451                     ov = options_array_item_value(a);
452                     s = ov->string;
453 
454                     offset = 0;
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);
459           }
460 
461           /* Log the SIXEL flag. */
462           log_debug("SIXEL flag is %d", !!(term->flags & TERM_SIXEL));
463 
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;
468           else
469                     term->flags &= ~TERM_RGBCOLOURS;
470           log_debug("RGBCOLOURS flag is %d", !!(term->flags & TERM_RGBCOLOURS));
471 
472           /*
473            * Set or clear the DECSLRM flag if the terminal has the margin
474            * capabilities.
475            */
476           if (tty_term_has(term, TTYC_CMG) && tty_term_has(term, TTYC_CLMG))
477                     term->flags |= TERM_DECSLRM;
478           else
479                     term->flags &= ~TERM_DECSLRM;
480           log_debug("DECSLRM flag is %d", !!(term->flags & TERM_DECSLRM));
481 
482           /*
483            * Set or clear the DECFRA flag if the terminal has the rectangle
484            * capability.
485            */
486           if (tty_term_has(term, TTYC_RECT))
487                     term->flags |= TERM_DECFRA;
488           else
489                     term->flags &= ~TERM_DECFRA;
490           log_debug("DECFRA flag is %d", !!(term->flags & TERM_DECFRA));
491 
492           /*
493            * Terminals without am (auto right margin) wrap at at $COLUMNS - 1
494            * rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1).
495            *
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.
500            *
501            * This is irritating, most notably because it is painful to write to
502            * the very bottom-right of the screen without scrolling.
503            *
504            * Flag the terminal here and apply some workarounds in other places to
505            * do the best possible.
506            */
507           if (!tty_term_flag(term, TTYC_AM))
508                     term->flags |= TERM_NOAM;
509           else
510                     term->flags &= ~TERM_NOAM;
511           log_debug("NOAM flag is %d", !!(term->flags & TERM_NOAM));
512 
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);
517           else
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];
521 }
522 
523 struct tty_term *
tty_term_create(struct tty * tty,char * name,char ** caps,u_int ncaps,int * feat,char ** cause)524 tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
525     int *feat, char **cause)
526 {
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;
533           u_int                                              i, j;
534           const char                                        *s, *value, *errstr;
535           size_t                                             offset, namelen;
536           char                                              *first;
537           int                                                n;
538 
539           log_debug("adding term %s", name);
540 
541           term = xcalloc(1, sizeof *term);
542           term->tty = tty;
543           term->name = xstrdup(name);
544           term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes);
545           LIST_INSERT_HEAD(&tty_terms, term, entry);
546 
547           /* Fill in codes. */
548           for (i = 0; i < ncaps; i++) {
549                     namelen = strcspn(caps[i], "=");
550                     if (namelen == 0)
551                               continue;
552                     value = caps[i] + namelen + 1;
553 
554                     for (j = 0; j < tty_term_ncodes(); j++) {
555                               ent = &tty_term_codes[j];
556                               if (strncmp(ent->name, caps[i], namelen) != 0)
557                                         continue;
558                               if (ent->name[namelen] != '\0')
559                                         continue;
560 
561                               code = &term->codes[j];
562                               code->type = TTYCODE_NONE;
563                               switch (ent->type) {
564                               case TTYCODE_NONE:
565                                         break;
566                               case TTYCODE_STRING:
567                                         code->type = TTYCODE_STRING;
568                                         code->value.string = tty_term_strip(value);
569                                         break;
570                               case TTYCODE_NUMBER:
571                                         n = strtonum(value, 0, INT_MAX, &errstr);
572                                         if (errstr != NULL)
573                                                   log_debug("%s: %s", ent->name, errstr);
574                                         else {
575                                                   code->type = TTYCODE_NUMBER;
576                                                   code->value.number = n;
577                                         }
578                                         break;
579                               case TTYCODE_FLAG:
580                                         code->type = TTYCODE_FLAG;
581                                         code->value.flag = (*value == '1');
582                                         break;
583                               }
584                     }
585           }
586 
587           /* Apply terminal features. */
588           o = options_get_only(global_options, "terminal-features");
589           a = options_array_first(o);
590           while (a != NULL) {
591                     ov = options_array_item_value(a);
592                     s = ov->string;
593 
594                     offset = 0;
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);
599           }
600 
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);
605 #endif
606 
607           /* Apply overrides so any capabilities used for features are changed. */
608           tty_term_apply_overrides(term);
609 
610           /* These are always required. */
611           if (!tty_term_has(term, TTYC_CLEAR)) {
612                     xasprintf(cause, "terminal does not support clear");
613                     goto error;
614           }
615           if (!tty_term_has(term, TTYC_CUP)) {
616                     xasprintf(cause, "terminal does not support cup");
617                     goto error;
618           }
619 
620           /*
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.
624            *
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.
628            *
629            * Also add few features that VT100-like terminals should either
630            * support or safely ignore.
631            */
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", ",");
636           }
637 
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", ",");
643 
644           /* Apply the features and overrides again. */
645           if (tty_apply_features(term, *feat))
646                     tty_term_apply_overrides(term);
647 
648           /* Log the capabilities. */
649           for (i = 0; i < tty_term_ncodes(); i++)
650                     log_debug("%s%s", name, tty_term_describe(term, i));
651 
652           return (term);
653 
654 error:
655           tty_term_free(term);
656           return (NULL);
657 }
658 
659 void
tty_term_free(struct tty_term * term)660 tty_term_free(struct tty_term *term)
661 {
662           u_int     i;
663 
664           log_debug("removing term %s", term->name);
665 
666           for (i = 0; i < tty_term_ncodes(); i++) {
667                     if (term->codes[i].type == TTYCODE_STRING)
668                               free(term->codes[i].value.string);
669           }
670           free(term->codes);
671 
672           LIST_REMOVE(term, entry);
673           free(term->name);
674           free(term);
675 }
676 
677 int
tty_term_read_list(const char * name,int fd,char *** caps,u_int * ncaps,char ** cause)678 tty_term_read_list(const char *name, int fd, char ***caps, u_int *ncaps,
679     char **cause)
680 {
681           const struct tty_term_code_entry        *ent;
682           int                                                error, n;
683           u_int                                              i;
684           const char                                        *s;
685           char                                               tmp[11];
686 
687           if (setupterm(__UNCONST(name), fd, &error) != OK) {
688                     switch (error) {
689                     case 1:
690                               xasprintf(cause, "can't use hardcopy terminal: %s",
691                                   name);
692                               break;
693                     case 0:
694                               xasprintf(cause, "missing or unsuitable terminal: %s",
695                                   name);
696                               break;
697                     case -1:
698                               xasprintf(cause, "can't find terminfo database");
699                               break;
700                     default:
701                               xasprintf(cause, "unknown error");
702                               break;
703                     }
704                     return (-1);
705           }
706 
707           *ncaps = 0;
708           *caps = NULL;
709 
710           for (i = 0; i < tty_term_ncodes(); i++) {
711                     ent = &tty_term_codes[i];
712                     switch (ent->type) {
713                     case TTYCODE_NONE:
714                               continue;
715                     case TTYCODE_STRING:
716                               s = tigetstr((const char *)ent->name);
717                               if (s == NULL || s == (char *)-1)
718                                         continue;
719                               break;
720                     case TTYCODE_NUMBER:
721                               n = tigetnum((const char *)ent->name);
722                               if (n == -1 || n == -2)
723                                         continue;
724                               xsnprintf(tmp, sizeof tmp, "%d", n);
725                               s = tmp;
726                               break;
727                     case TTYCODE_FLAG:
728                               n = tigetflag((const char *)ent->name);
729                               if (n == -1)
730                                         continue;
731                               if (n)
732                                         s = "1";
733                               else
734                                         s = "0";
735                               break;
736                     default:
737                               fatalx("unknown capability type");
738                     }
739                     *caps = xreallocarray(*caps, (*ncaps) + 1, sizeof **caps);
740                     xasprintf(&(*caps)[*ncaps], "%s=%s", ent->name, s);
741                     (*ncaps)++;
742           }
743 
744 #if !defined(NCURSES_VERSION_MAJOR) || NCURSES_VERSION_MAJOR > 5 || \
745     (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 6)
746           del_curterm(cur_term);
747 #endif
748           return (0);
749 }
750 
751 void
tty_term_free_list(char ** caps,u_int ncaps)752 tty_term_free_list(char **caps, u_int ncaps)
753 {
754           u_int     i;
755 
756           for (i = 0; i < ncaps; i++)
757                     free(caps[i]);
758           free(caps);
759 }
760 
761 int
tty_term_has(struct tty_term * term,enum tty_code_code code)762 tty_term_has(struct tty_term *term, enum tty_code_code code)
763 {
764           return (term->codes[code].type != TTYCODE_NONE);
765 }
766 
767 const char *
tty_term_string(struct tty_term * term,enum tty_code_code code)768 tty_term_string(struct tty_term *term, enum tty_code_code code)
769 {
770           if (!tty_term_has(term, code))
771                     return ("");
772           if (term->codes[code].type != TTYCODE_STRING)
773                     fatalx("not a string: %d", code);
774           return (term->codes[code].value.string);
775 }
776 
777 const char *
tty_term_string_i(struct tty_term * term,enum tty_code_code code,int a)778 tty_term_string_i(struct tty_term *term, enum tty_code_code code, int a)
779 {
780           const char          *x = tty_term_string(term, code), *s;
781 
782 #if defined(HAVE_TIPARM_S)
783           s = tiparm_s(1, 0, x, a);
784 #elif defined(HAVE_TIPARM)
785           s = tiparm(x, a);
786 #else
787           s = tparm((char *)x, a, 0, 0, 0, 0, 0, 0, 0, 0);
788 #endif
789           if (s == NULL) {
790                     log_debug("could not expand %s", tty_term_codes[code].name);
791                     return ("");
792           }
793           return (s);
794 }
795 
796 const char *
tty_term_string_ii(struct tty_term * term,enum tty_code_code code,int a,int b)797 tty_term_string_ii(struct tty_term *term, enum tty_code_code code, int a, int b)
798 {
799           const char          *x = tty_term_string(term, code), *s;
800 
801 #if defined(HAVE_TIPARM_S)
802           s = tiparm_s(2, 0, x, a, b);
803 #elif defined(HAVE_TIPARM)
804           s = tiparm(x, a, b);
805 #else
806           s = tparm((char *)x, a, b, 0, 0, 0, 0, 0, 0, 0);
807 #endif
808           if (s == NULL) {
809                     log_debug("could not expand %s", tty_term_codes[code].name);
810                     return ("");
811           }
812           return (s);
813 }
814 
815 const char *
tty_term_string_iii(struct tty_term * term,enum tty_code_code code,int a,int b,int c)816 tty_term_string_iii(struct tty_term *term, enum tty_code_code code, int a,
817     int b, int c)
818 {
819           const char          *x = tty_term_string(term, code), *s;
820 
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);
825 #else
826           s = tparm((char *)x, a, b, c, 0, 0, 0, 0, 0, 0);
827 #endif
828           if (s == NULL) {
829                     log_debug("could not expand %s", tty_term_codes[code].name);
830                     return ("");
831           }
832           return (s);
833 }
834 
835 const char *
tty_term_string_s(struct tty_term * term,enum tty_code_code code,const char * a)836 tty_term_string_s(struct tty_term *term, enum tty_code_code code, const char *a)
837 {
838           const char          *x = tty_term_string(term, code), *s;
839 
840 #if defined(HAVE_TIPARM_S)
841           s = tiparm_s(1, 1, x, a);
842 #elif defined(HAVE_TIPARM)
843           s = tiparm(x, a);
844 #else
845           s = tparm((char *)x, (long)a, 0, 0, 0, 0, 0, 0, 0, 0);
846 #endif
847           if (s == NULL) {
848                     log_debug("could not expand %s", tty_term_codes[code].name);
849                     return ("");
850           }
851           return (s);
852 }
853 
854 const char *
tty_term_string_ss(struct tty_term * term,enum tty_code_code code,const char * a,const char * b)855 tty_term_string_ss(struct tty_term *term, enum tty_code_code code,
856     const char *a, const char *b)
857 {
858           const char          *x = tty_term_string(term, code), *s;
859 
860 #if defined(HAVE_TIPARM_S)
861           s = tiparm_s(2, 3, x, a, b);
862 #elif defined(HAVE_TIPARM)
863           s = tiparm(x, a, b);
864 #else
865           s = tparm((char *)x, (long)a, (long)b, 0, 0, 0, 0, 0, 0, 0);
866 #endif
867           if (s == NULL) {
868                     log_debug("could not expand %s", tty_term_codes[code].name);
869                     return ("");
870           }
871           return (s);
872 }
873 
874 int
tty_term_number(struct tty_term * term,enum tty_code_code code)875 tty_term_number(struct tty_term *term, enum tty_code_code code)
876 {
877           if (!tty_term_has(term, code))
878                     return (0);
879           if (term->codes[code].type != TTYCODE_NUMBER)
880                     fatalx("not a number: %d", code);
881           return (term->codes[code].value.number);
882 }
883 
884 int
tty_term_flag(struct tty_term * term,enum tty_code_code code)885 tty_term_flag(struct tty_term *term, enum tty_code_code code)
886 {
887           if (!tty_term_has(term, code))
888                     return (0);
889           if (term->codes[code].type != TTYCODE_FLAG)
890                     fatalx("not a flag: %d", code);
891           return (term->codes[code].value.flag);
892 }
893 
894 const char *
tty_term_describe(struct tty_term * term,enum tty_code_code code)895 tty_term_describe(struct tty_term *term, enum tty_code_code code)
896 {
897           static char          s[256];
898           char                 out[128];
899 
900           switch (term->codes[code].type) {
901           case TTYCODE_NONE:
902                     xsnprintf(s, sizeof s, "%4u: %s: [missing]",
903                         code, tty_term_codes[code].name);
904                     break;
905           case TTYCODE_STRING:
906                     strnvis(out, sizeof out, term->codes[code].value.string,
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,
910                         out);
911                     break;
912           case TTYCODE_NUMBER:
913                     xsnprintf(s, sizeof s, "%4u: %s: (number) %d",
914                         code, tty_term_codes[code].name,
915                         term->codes[code].value.number);
916                     break;
917           case TTYCODE_FLAG:
918                     xsnprintf(s, sizeof s, "%4u: %s: (flag) %s",
919                         code, tty_term_codes[code].name,
920                         term->codes[code].value.flag ? "true" : "false");
921                     break;
922           }
923           return (s);
924 }
925