1 |
|
|
/* $OpenBSD: tty-term.c,v 1.57 2017/08/27 08:33:55 nicm Exp $ */ |
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 |
|
|
#include <curses.h> |
22 |
|
|
#include <fnmatch.h> |
23 |
|
|
#include <stdlib.h> |
24 |
|
|
#include <string.h> |
25 |
|
|
#include <term.h> |
26 |
|
|
#include <vis.h> |
27 |
|
|
|
28 |
|
|
#include "tmux.h" |
29 |
|
|
|
30 |
|
|
static void tty_term_override(struct tty_term *, const char *); |
31 |
|
|
static char *tty_term_strip(const char *); |
32 |
|
|
|
33 |
|
|
struct tty_terms tty_terms = LIST_HEAD_INITIALIZER(tty_terms); |
34 |
|
|
|
35 |
|
|
enum tty_code_type { |
36 |
|
|
TTYCODE_NONE = 0, |
37 |
|
|
TTYCODE_STRING, |
38 |
|
|
TTYCODE_NUMBER, |
39 |
|
|
TTYCODE_FLAG, |
40 |
|
|
}; |
41 |
|
|
|
42 |
|
|
struct tty_code { |
43 |
|
|
enum tty_code_type type; |
44 |
|
|
union { |
45 |
|
|
char *string; |
46 |
|
|
int number; |
47 |
|
|
int flag; |
48 |
|
|
} value; |
49 |
|
|
}; |
50 |
|
|
|
51 |
|
|
struct tty_term_code_entry { |
52 |
|
|
enum tty_code_type type; |
53 |
|
|
const char *name; |
54 |
|
|
}; |
55 |
|
|
|
56 |
|
|
static const struct tty_term_code_entry tty_term_codes[] = { |
57 |
|
|
[TTYC_ACSC] = { TTYCODE_STRING, "acsc" }, |
58 |
|
|
[TTYC_AX] = { TTYCODE_FLAG, "AX" }, |
59 |
|
|
[TTYC_BCE] = { TTYCODE_FLAG, "bce" }, |
60 |
|
|
[TTYC_BEL] = { TTYCODE_STRING, "bel" }, |
61 |
|
|
[TTYC_BLINK] = { TTYCODE_STRING, "blink" }, |
62 |
|
|
[TTYC_BOLD] = { TTYCODE_STRING, "bold" }, |
63 |
|
|
[TTYC_CIVIS] = { TTYCODE_STRING, "civis" }, |
64 |
|
|
[TTYC_CLEAR] = { TTYCODE_STRING, "clear" }, |
65 |
|
|
[TTYC_CNORM] = { TTYCODE_STRING, "cnorm" }, |
66 |
|
|
[TTYC_COLORS] = { TTYCODE_NUMBER, "colors" }, |
67 |
|
|
[TTYC_CR] = { TTYCODE_STRING, "Cr" }, |
68 |
|
|
[TTYC_CSR] = { TTYCODE_STRING, "csr" }, |
69 |
|
|
[TTYC_CS] = { TTYCODE_STRING, "Cs" }, |
70 |
|
|
[TTYC_CUB1] = { TTYCODE_STRING, "cub1" }, |
71 |
|
|
[TTYC_CUB] = { TTYCODE_STRING, "cub" }, |
72 |
|
|
[TTYC_CUD1] = { TTYCODE_STRING, "cud1" }, |
73 |
|
|
[TTYC_CUD] = { TTYCODE_STRING, "cud" }, |
74 |
|
|
[TTYC_CUF1] = { TTYCODE_STRING, "cuf1" }, |
75 |
|
|
[TTYC_CUF] = { TTYCODE_STRING, "cuf" }, |
76 |
|
|
[TTYC_CUP] = { TTYCODE_STRING, "cup" }, |
77 |
|
|
[TTYC_CUU1] = { TTYCODE_STRING, "cuu1" }, |
78 |
|
|
[TTYC_CUU] = { TTYCODE_STRING, "cuu" }, |
79 |
|
|
[TTYC_CVVIS] = { TTYCODE_STRING, "cvvis" }, |
80 |
|
|
[TTYC_DCH1] = { TTYCODE_STRING, "dch1" }, |
81 |
|
|
[TTYC_DCH] = { TTYCODE_STRING, "dch" }, |
82 |
|
|
[TTYC_DIM] = { TTYCODE_STRING, "dim" }, |
83 |
|
|
[TTYC_DL1] = { TTYCODE_STRING, "dl1" }, |
84 |
|
|
[TTYC_DL] = { TTYCODE_STRING, "dl" }, |
85 |
|
|
[TTYC_E3] = { TTYCODE_STRING, "E3" }, |
86 |
|
|
[TTYC_ECH] = { TTYCODE_STRING, "ech" }, |
87 |
|
|
[TTYC_ED] = { TTYCODE_STRING, "ed" }, |
88 |
|
|
[TTYC_EL1] = { TTYCODE_STRING, "el1" }, |
89 |
|
|
[TTYC_EL] = { TTYCODE_STRING, "el" }, |
90 |
|
|
[TTYC_ENACS] = { TTYCODE_STRING, "enacs" }, |
91 |
|
|
[TTYC_FSL] = { TTYCODE_STRING, "fsl" }, |
92 |
|
|
[TTYC_HOME] = { TTYCODE_STRING, "home" }, |
93 |
|
|
[TTYC_HPA] = { TTYCODE_STRING, "hpa" }, |
94 |
|
|
[TTYC_ICH1] = { TTYCODE_STRING, "ich1" }, |
95 |
|
|
[TTYC_ICH] = { TTYCODE_STRING, "ich" }, |
96 |
|
|
[TTYC_IL1] = { TTYCODE_STRING, "il1" }, |
97 |
|
|
[TTYC_IL] = { TTYCODE_STRING, "il" }, |
98 |
|
|
[TTYC_INDN] = { TTYCODE_STRING, "indn" }, |
99 |
|
|
[TTYC_INVIS] = { TTYCODE_STRING, "invis" }, |
100 |
|
|
[TTYC_KCBT] = { TTYCODE_STRING, "kcbt" }, |
101 |
|
|
[TTYC_KCUB1] = { TTYCODE_STRING, "kcub1" }, |
102 |
|
|
[TTYC_KCUD1] = { TTYCODE_STRING, "kcud1" }, |
103 |
|
|
[TTYC_KCUF1] = { TTYCODE_STRING, "kcuf1" }, |
104 |
|
|
[TTYC_KCUU1] = { TTYCODE_STRING, "kcuu1" }, |
105 |
|
|
[TTYC_KDC2] = { TTYCODE_STRING, "kDC" }, |
106 |
|
|
[TTYC_KDC3] = { TTYCODE_STRING, "kDC3" }, |
107 |
|
|
[TTYC_KDC4] = { TTYCODE_STRING, "kDC4" }, |
108 |
|
|
[TTYC_KDC5] = { TTYCODE_STRING, "kDC5" }, |
109 |
|
|
[TTYC_KDC6] = { TTYCODE_STRING, "kDC6" }, |
110 |
|
|
[TTYC_KDC7] = { TTYCODE_STRING, "kDC7" }, |
111 |
|
|
[TTYC_KDCH1] = { TTYCODE_STRING, "kdch1" }, |
112 |
|
|
[TTYC_KDN2] = { TTYCODE_STRING, "kDN" }, /* not kDN2 */ |
113 |
|
|
[TTYC_KDN3] = { TTYCODE_STRING, "kDN3" }, |
114 |
|
|
[TTYC_KDN4] = { TTYCODE_STRING, "kDN4" }, |
115 |
|
|
[TTYC_KDN5] = { TTYCODE_STRING, "kDN5" }, |
116 |
|
|
[TTYC_KDN6] = { TTYCODE_STRING, "kDN6" }, |
117 |
|
|
[TTYC_KDN7] = { TTYCODE_STRING, "kDN7" }, |
118 |
|
|
[TTYC_KEND2] = { TTYCODE_STRING, "kEND" }, |
119 |
|
|
[TTYC_KEND3] = { TTYCODE_STRING, "kEND3" }, |
120 |
|
|
[TTYC_KEND4] = { TTYCODE_STRING, "kEND4" }, |
121 |
|
|
[TTYC_KEND5] = { TTYCODE_STRING, "kEND5" }, |
122 |
|
|
[TTYC_KEND6] = { TTYCODE_STRING, "kEND6" }, |
123 |
|
|
[TTYC_KEND7] = { TTYCODE_STRING, "kEND7" }, |
124 |
|
|
[TTYC_KEND] = { TTYCODE_STRING, "kend" }, |
125 |
|
|
[TTYC_KF10] = { TTYCODE_STRING, "kf10" }, |
126 |
|
|
[TTYC_KF11] = { TTYCODE_STRING, "kf11" }, |
127 |
|
|
[TTYC_KF12] = { TTYCODE_STRING, "kf12" }, |
128 |
|
|
[TTYC_KF13] = { TTYCODE_STRING, "kf13" }, |
129 |
|
|
[TTYC_KF14] = { TTYCODE_STRING, "kf14" }, |
130 |
|
|
[TTYC_KF15] = { TTYCODE_STRING, "kf15" }, |
131 |
|
|
[TTYC_KF16] = { TTYCODE_STRING, "kf16" }, |
132 |
|
|
[TTYC_KF17] = { TTYCODE_STRING, "kf17" }, |
133 |
|
|
[TTYC_KF18] = { TTYCODE_STRING, "kf18" }, |
134 |
|
|
[TTYC_KF19] = { TTYCODE_STRING, "kf19" }, |
135 |
|
|
[TTYC_KF1] = { TTYCODE_STRING, "kf1" }, |
136 |
|
|
[TTYC_KF20] = { TTYCODE_STRING, "kf20" }, |
137 |
|
|
[TTYC_KF21] = { TTYCODE_STRING, "kf21" }, |
138 |
|
|
[TTYC_KF22] = { TTYCODE_STRING, "kf22" }, |
139 |
|
|
[TTYC_KF23] = { TTYCODE_STRING, "kf23" }, |
140 |
|
|
[TTYC_KF24] = { TTYCODE_STRING, "kf24" }, |
141 |
|
|
[TTYC_KF25] = { TTYCODE_STRING, "kf25" }, |
142 |
|
|
[TTYC_KF26] = { TTYCODE_STRING, "kf26" }, |
143 |
|
|
[TTYC_KF27] = { TTYCODE_STRING, "kf27" }, |
144 |
|
|
[TTYC_KF28] = { TTYCODE_STRING, "kf28" }, |
145 |
|
|
[TTYC_KF29] = { TTYCODE_STRING, "kf29" }, |
146 |
|
|
[TTYC_KF2] = { TTYCODE_STRING, "kf2" }, |
147 |
|
|
[TTYC_KF30] = { TTYCODE_STRING, "kf30" }, |
148 |
|
|
[TTYC_KF31] = { TTYCODE_STRING, "kf31" }, |
149 |
|
|
[TTYC_KF32] = { TTYCODE_STRING, "kf32" }, |
150 |
|
|
[TTYC_KF33] = { TTYCODE_STRING, "kf33" }, |
151 |
|
|
[TTYC_KF34] = { TTYCODE_STRING, "kf34" }, |
152 |
|
|
[TTYC_KF35] = { TTYCODE_STRING, "kf35" }, |
153 |
|
|
[TTYC_KF36] = { TTYCODE_STRING, "kf36" }, |
154 |
|
|
[TTYC_KF37] = { TTYCODE_STRING, "kf37" }, |
155 |
|
|
[TTYC_KF38] = { TTYCODE_STRING, "kf38" }, |
156 |
|
|
[TTYC_KF39] = { TTYCODE_STRING, "kf39" }, |
157 |
|
|
[TTYC_KF3] = { TTYCODE_STRING, "kf3" }, |
158 |
|
|
[TTYC_KF40] = { TTYCODE_STRING, "kf40" }, |
159 |
|
|
[TTYC_KF41] = { TTYCODE_STRING, "kf41" }, |
160 |
|
|
[TTYC_KF42] = { TTYCODE_STRING, "kf42" }, |
161 |
|
|
[TTYC_KF43] = { TTYCODE_STRING, "kf43" }, |
162 |
|
|
[TTYC_KF44] = { TTYCODE_STRING, "kf44" }, |
163 |
|
|
[TTYC_KF45] = { TTYCODE_STRING, "kf45" }, |
164 |
|
|
[TTYC_KF46] = { TTYCODE_STRING, "kf46" }, |
165 |
|
|
[TTYC_KF47] = { TTYCODE_STRING, "kf47" }, |
166 |
|
|
[TTYC_KF48] = { TTYCODE_STRING, "kf48" }, |
167 |
|
|
[TTYC_KF49] = { TTYCODE_STRING, "kf49" }, |
168 |
|
|
[TTYC_KF4] = { TTYCODE_STRING, "kf4" }, |
169 |
|
|
[TTYC_KF50] = { TTYCODE_STRING, "kf50" }, |
170 |
|
|
[TTYC_KF51] = { TTYCODE_STRING, "kf51" }, |
171 |
|
|
[TTYC_KF52] = { TTYCODE_STRING, "kf52" }, |
172 |
|
|
[TTYC_KF53] = { TTYCODE_STRING, "kf53" }, |
173 |
|
|
[TTYC_KF54] = { TTYCODE_STRING, "kf54" }, |
174 |
|
|
[TTYC_KF55] = { TTYCODE_STRING, "kf55" }, |
175 |
|
|
[TTYC_KF56] = { TTYCODE_STRING, "kf56" }, |
176 |
|
|
[TTYC_KF57] = { TTYCODE_STRING, "kf57" }, |
177 |
|
|
[TTYC_KF58] = { TTYCODE_STRING, "kf58" }, |
178 |
|
|
[TTYC_KF59] = { TTYCODE_STRING, "kf59" }, |
179 |
|
|
[TTYC_KF5] = { TTYCODE_STRING, "kf5" }, |
180 |
|
|
[TTYC_KF60] = { TTYCODE_STRING, "kf60" }, |
181 |
|
|
[TTYC_KF61] = { TTYCODE_STRING, "kf61" }, |
182 |
|
|
[TTYC_KF62] = { TTYCODE_STRING, "kf62" }, |
183 |
|
|
[TTYC_KF63] = { TTYCODE_STRING, "kf63" }, |
184 |
|
|
[TTYC_KF6] = { TTYCODE_STRING, "kf6" }, |
185 |
|
|
[TTYC_KF7] = { TTYCODE_STRING, "kf7" }, |
186 |
|
|
[TTYC_KF8] = { TTYCODE_STRING, "kf8" }, |
187 |
|
|
[TTYC_KF9] = { TTYCODE_STRING, "kf9" }, |
188 |
|
|
[TTYC_KHOM2] = { TTYCODE_STRING, "kHOM" }, |
189 |
|
|
[TTYC_KHOM3] = { TTYCODE_STRING, "kHOM3" }, |
190 |
|
|
[TTYC_KHOM4] = { TTYCODE_STRING, "kHOM4" }, |
191 |
|
|
[TTYC_KHOM5] = { TTYCODE_STRING, "kHOM5" }, |
192 |
|
|
[TTYC_KHOM6] = { TTYCODE_STRING, "kHOM6" }, |
193 |
|
|
[TTYC_KHOM7] = { TTYCODE_STRING, "kHOM7" }, |
194 |
|
|
[TTYC_KHOME] = { TTYCODE_STRING, "khome" }, |
195 |
|
|
[TTYC_KIC2] = { TTYCODE_STRING, "kIC" }, |
196 |
|
|
[TTYC_KIC3] = { TTYCODE_STRING, "kIC3" }, |
197 |
|
|
[TTYC_KIC4] = { TTYCODE_STRING, "kIC4" }, |
198 |
|
|
[TTYC_KIC5] = { TTYCODE_STRING, "kIC5" }, |
199 |
|
|
[TTYC_KIC6] = { TTYCODE_STRING, "kIC6" }, |
200 |
|
|
[TTYC_KIC7] = { TTYCODE_STRING, "kIC7" }, |
201 |
|
|
[TTYC_KICH1] = { TTYCODE_STRING, "kich1" }, |
202 |
|
|
[TTYC_KIND] = { TTYCODE_STRING, "kind" }, |
203 |
|
|
[TTYC_KLFT2] = { TTYCODE_STRING, "kLFT" }, |
204 |
|
|
[TTYC_KLFT3] = { TTYCODE_STRING, "kLFT3" }, |
205 |
|
|
[TTYC_KLFT4] = { TTYCODE_STRING, "kLFT4" }, |
206 |
|
|
[TTYC_KLFT5] = { TTYCODE_STRING, "kLFT5" }, |
207 |
|
|
[TTYC_KLFT6] = { TTYCODE_STRING, "kLFT6" }, |
208 |
|
|
[TTYC_KLFT7] = { TTYCODE_STRING, "kLFT7" }, |
209 |
|
|
[TTYC_KMOUS] = { TTYCODE_STRING, "kmous" }, |
210 |
|
|
[TTYC_KNP] = { TTYCODE_STRING, "knp" }, |
211 |
|
|
[TTYC_KNXT2] = { TTYCODE_STRING, "kNXT" }, |
212 |
|
|
[TTYC_KNXT3] = { TTYCODE_STRING, "kNXT3" }, |
213 |
|
|
[TTYC_KNXT4] = { TTYCODE_STRING, "kNXT4" }, |
214 |
|
|
[TTYC_KNXT5] = { TTYCODE_STRING, "kNXT5" }, |
215 |
|
|
[TTYC_KNXT6] = { TTYCODE_STRING, "kNXT6" }, |
216 |
|
|
[TTYC_KNXT7] = { TTYCODE_STRING, "kNXT7" }, |
217 |
|
|
[TTYC_KPP] = { TTYCODE_STRING, "kpp" }, |
218 |
|
|
[TTYC_KPRV2] = { TTYCODE_STRING, "kPRV" }, |
219 |
|
|
[TTYC_KPRV3] = { TTYCODE_STRING, "kPRV3" }, |
220 |
|
|
[TTYC_KPRV4] = { TTYCODE_STRING, "kPRV4" }, |
221 |
|
|
[TTYC_KPRV5] = { TTYCODE_STRING, "kPRV5" }, |
222 |
|
|
[TTYC_KPRV6] = { TTYCODE_STRING, "kPRV6" }, |
223 |
|
|
[TTYC_KPRV7] = { TTYCODE_STRING, "kPRV7" }, |
224 |
|
|
[TTYC_KRIT2] = { TTYCODE_STRING, "kRIT" }, |
225 |
|
|
[TTYC_KRIT3] = { TTYCODE_STRING, "kRIT3" }, |
226 |
|
|
[TTYC_KRIT4] = { TTYCODE_STRING, "kRIT4" }, |
227 |
|
|
[TTYC_KRIT5] = { TTYCODE_STRING, "kRIT5" }, |
228 |
|
|
[TTYC_KRIT6] = { TTYCODE_STRING, "kRIT6" }, |
229 |
|
|
[TTYC_KRIT7] = { TTYCODE_STRING, "kRIT7" }, |
230 |
|
|
[TTYC_KRI] = { TTYCODE_STRING, "kri" }, |
231 |
|
|
[TTYC_KUP2] = { TTYCODE_STRING, "kUP" }, /* not kUP2 */ |
232 |
|
|
[TTYC_KUP3] = { TTYCODE_STRING, "kUP3" }, |
233 |
|
|
[TTYC_KUP4] = { TTYCODE_STRING, "kUP4" }, |
234 |
|
|
[TTYC_KUP5] = { TTYCODE_STRING, "kUP5" }, |
235 |
|
|
[TTYC_KUP6] = { TTYCODE_STRING, "kUP6" }, |
236 |
|
|
[TTYC_KUP7] = { TTYCODE_STRING, "kUP7" }, |
237 |
|
|
[TTYC_MS] = { TTYCODE_STRING, "Ms" }, |
238 |
|
|
[TTYC_OP] = { TTYCODE_STRING, "op" }, |
239 |
|
|
[TTYC_REV] = { TTYCODE_STRING, "rev" }, |
240 |
|
|
[TTYC_RI] = { TTYCODE_STRING, "ri" }, |
241 |
|
|
[TTYC_RMACS] = { TTYCODE_STRING, "rmacs" }, |
242 |
|
|
[TTYC_RMCUP] = { TTYCODE_STRING, "rmcup" }, |
243 |
|
|
[TTYC_RMKX] = { TTYCODE_STRING, "rmkx" }, |
244 |
|
|
[TTYC_SETAB] = { TTYCODE_STRING, "setab" }, |
245 |
|
|
[TTYC_SETAF] = { TTYCODE_STRING, "setaf" }, |
246 |
|
|
[TTYC_SETRGBB] = { TTYCODE_STRING, "setrgbb" }, |
247 |
|
|
[TTYC_SETRGBF] = { TTYCODE_STRING, "setrgbf" }, |
248 |
|
|
[TTYC_SE] = { TTYCODE_STRING, "Se" }, |
249 |
|
|
[TTYC_SGR0] = { TTYCODE_STRING, "sgr0" }, |
250 |
|
|
[TTYC_SITM] = { TTYCODE_STRING, "sitm" }, |
251 |
|
|
[TTYC_SMACS] = { TTYCODE_STRING, "smacs" }, |
252 |
|
|
[TTYC_SMCUP] = { TTYCODE_STRING, "smcup" }, |
253 |
|
|
[TTYC_SMKX] = { TTYCODE_STRING, "smkx" }, |
254 |
|
|
[TTYC_SMSO] = { TTYCODE_STRING, "smso" }, |
255 |
|
|
[TTYC_SMUL] = { TTYCODE_STRING, "smul" }, |
256 |
|
|
[TTYC_SMXX] = { TTYCODE_STRING, "smxx" }, |
257 |
|
|
[TTYC_SS] = { TTYCODE_STRING, "Ss" }, |
258 |
|
|
[TTYC_TC] = { TTYCODE_FLAG, "Tc" }, |
259 |
|
|
[TTYC_TSL] = { TTYCODE_STRING, "tsl" }, |
260 |
|
|
[TTYC_U8] = { TTYCODE_NUMBER, "U8" }, |
261 |
|
|
[TTYC_VPA] = { TTYCODE_STRING, "vpa" }, |
262 |
|
|
[TTYC_XENL] = { TTYCODE_FLAG, "xenl" }, |
263 |
|
|
[TTYC_XT] = { TTYCODE_FLAG, "XT" }, |
264 |
|
|
}; |
265 |
|
|
|
266 |
|
|
u_int |
267 |
|
|
tty_term_ncodes(void) |
268 |
|
|
{ |
269 |
|
|
return (nitems(tty_term_codes)); |
270 |
|
|
} |
271 |
|
|
|
272 |
|
|
static char * |
273 |
|
|
tty_term_strip(const char *s) |
274 |
|
|
{ |
275 |
|
|
const char *ptr; |
276 |
|
|
static char buf[BUFSIZ]; |
277 |
|
|
size_t len; |
278 |
|
|
|
279 |
|
|
/* Ignore strings with no padding. */ |
280 |
|
|
if (strchr(s, '$') == NULL) |
281 |
|
|
return (xstrdup(s)); |
282 |
|
|
|
283 |
|
|
len = 0; |
284 |
|
|
for (ptr = s; *ptr != '\0'; ptr++) { |
285 |
|
|
if (*ptr == '$' && *(ptr + 1) == '<') { |
286 |
|
|
while (*ptr != '\0' && *ptr != '>') |
287 |
|
|
ptr++; |
288 |
|
|
if (*ptr == '>') |
289 |
|
|
ptr++; |
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
buf[len++] = *ptr; |
293 |
|
|
if (len == (sizeof buf) - 1) |
294 |
|
|
break; |
295 |
|
|
} |
296 |
|
|
buf[len] = '\0'; |
297 |
|
|
|
298 |
|
|
return (xstrdup(buf)); |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
static void |
302 |
|
|
tty_term_override(struct tty_term *term, const char *override) |
303 |
|
|
{ |
304 |
|
|
const struct tty_term_code_entry *ent; |
305 |
|
|
struct tty_code *code; |
306 |
|
|
char *next, *s, *copy, *cp, *value; |
307 |
|
|
const char *errstr; |
308 |
|
|
u_int i; |
309 |
|
|
int n, remove; |
310 |
|
|
|
311 |
|
|
copy = next = xstrdup(override); |
312 |
|
|
|
313 |
|
|
s = strsep(&next, ":"); |
314 |
|
|
if (s == NULL || next == NULL || fnmatch(s, term->name, 0) != 0) { |
315 |
|
|
free(copy); |
316 |
|
|
return; |
317 |
|
|
} |
318 |
|
|
|
319 |
|
|
while ((s = strsep(&next, ":")) != NULL) { |
320 |
|
|
if (*s == '\0') |
321 |
|
|
continue; |
322 |
|
|
value = NULL; |
323 |
|
|
|
324 |
|
|
remove = 0; |
325 |
|
|
if ((cp = strchr(s, '=')) != NULL) { |
326 |
|
|
*cp++ = '\0'; |
327 |
|
|
value = xstrdup(cp); |
328 |
|
|
if (strunvis(value, cp) == -1) { |
329 |
|
|
free(value); |
330 |
|
|
value = xstrdup(cp); |
331 |
|
|
} |
332 |
|
|
} else if (s[strlen(s) - 1] == '@') { |
333 |
|
|
s[strlen(s) - 1] = '\0'; |
334 |
|
|
remove = 1; |
335 |
|
|
} else |
336 |
|
|
value = xstrdup(""); |
337 |
|
|
|
338 |
|
|
if (remove) |
339 |
|
|
log_debug("%s override: %s@", term->name, s); |
340 |
|
|
else |
341 |
|
|
log_debug("%s override: %s=%s", term->name, s, value); |
342 |
|
|
|
343 |
|
|
for (i = 0; i < tty_term_ncodes(); i++) { |
344 |
|
|
ent = &tty_term_codes[i]; |
345 |
|
|
if (strcmp(s, ent->name) != 0) |
346 |
|
|
continue; |
347 |
|
|
code = &term->codes[i]; |
348 |
|
|
|
349 |
|
|
if (remove) { |
350 |
|
|
code->type = TTYCODE_NONE; |
351 |
|
|
continue; |
352 |
|
|
} |
353 |
|
|
switch (ent->type) { |
354 |
|
|
case TTYCODE_NONE: |
355 |
|
|
break; |
356 |
|
|
case TTYCODE_STRING: |
357 |
|
|
if (code->type == TTYCODE_STRING) |
358 |
|
|
free(code->value.string); |
359 |
|
|
code->value.string = xstrdup(value); |
360 |
|
|
code->type = ent->type; |
361 |
|
|
break; |
362 |
|
|
case TTYCODE_NUMBER: |
363 |
|
|
n = strtonum(value, 0, INT_MAX, &errstr); |
364 |
|
|
if (errstr != NULL) |
365 |
|
|
break; |
366 |
|
|
code->value.number = n; |
367 |
|
|
code->type = ent->type; |
368 |
|
|
break; |
369 |
|
|
case TTYCODE_FLAG: |
370 |
|
|
code->value.flag = 1; |
371 |
|
|
code->type = ent->type; |
372 |
|
|
break; |
373 |
|
|
} |
374 |
|
|
} |
375 |
|
|
|
376 |
|
|
free(value); |
377 |
|
|
} |
378 |
|
|
free(s); |
379 |
|
|
} |
380 |
|
|
|
381 |
|
|
struct tty_term * |
382 |
|
|
tty_term_find(char *name, int fd, char **cause) |
383 |
|
|
{ |
384 |
|
|
struct tty_term *term; |
385 |
|
|
const struct tty_term_code_entry *ent; |
386 |
|
|
struct tty_code *code; |
387 |
|
|
struct options_entry *o; |
388 |
|
|
u_int size, i; |
389 |
|
|
int n, error; |
390 |
|
|
const char *s, *acs; |
391 |
|
|
|
392 |
|
|
LIST_FOREACH(term, &tty_terms, entry) { |
393 |
|
|
if (strcmp(term->name, name) == 0) { |
394 |
|
|
term->references++; |
395 |
|
|
return (term); |
396 |
|
|
} |
397 |
|
|
} |
398 |
|
|
log_debug("new term: %s", name); |
399 |
|
|
|
400 |
|
|
term = xmalloc(sizeof *term); |
401 |
|
|
term->name = xstrdup(name); |
402 |
|
|
term->references = 1; |
403 |
|
|
term->flags = 0; |
404 |
|
|
term->codes = xcalloc(tty_term_ncodes(), sizeof *term->codes); |
405 |
|
|
LIST_INSERT_HEAD(&tty_terms, term, entry); |
406 |
|
|
|
407 |
|
|
/* Set up curses terminal. */ |
408 |
|
|
if (setupterm(name, fd, &error) != OK) { |
409 |
|
|
switch (error) { |
410 |
|
|
case 1: |
411 |
|
|
xasprintf(cause, "can't use hardcopy terminal: %s", |
412 |
|
|
name); |
413 |
|
|
break; |
414 |
|
|
case 0: |
415 |
|
|
xasprintf(cause, "missing or unsuitable terminal: %s", |
416 |
|
|
name); |
417 |
|
|
break; |
418 |
|
|
case -1: |
419 |
|
|
xasprintf(cause, "can't find terminfo database"); |
420 |
|
|
break; |
421 |
|
|
default: |
422 |
|
|
xasprintf(cause, "unknown error"); |
423 |
|
|
break; |
424 |
|
|
} |
425 |
|
|
goto error; |
426 |
|
|
} |
427 |
|
|
|
428 |
|
|
/* Fill in codes. */ |
429 |
|
|
for (i = 0; i < tty_term_ncodes(); i++) { |
430 |
|
|
ent = &tty_term_codes[i]; |
431 |
|
|
|
432 |
|
|
code = &term->codes[i]; |
433 |
|
|
code->type = TTYCODE_NONE; |
434 |
|
|
switch (ent->type) { |
435 |
|
|
case TTYCODE_NONE: |
436 |
|
|
break; |
437 |
|
|
case TTYCODE_STRING: |
438 |
|
|
s = tigetstr((char *) ent->name); |
439 |
|
|
if (s == NULL || s == (char *) -1) |
440 |
|
|
break; |
441 |
|
|
code->type = TTYCODE_STRING; |
442 |
|
|
code->value.string = tty_term_strip(s); |
443 |
|
|
break; |
444 |
|
|
case TTYCODE_NUMBER: |
445 |
|
|
n = tigetnum((char *) ent->name); |
446 |
|
|
if (n == -1 || n == -2) |
447 |
|
|
break; |
448 |
|
|
code->type = TTYCODE_NUMBER; |
449 |
|
|
code->value.number = n; |
450 |
|
|
break; |
451 |
|
|
case TTYCODE_FLAG: |
452 |
|
|
n = tigetflag((char *) ent->name); |
453 |
|
|
if (n == -1) |
454 |
|
|
break; |
455 |
|
|
code->type = TTYCODE_FLAG; |
456 |
|
|
code->value.flag = n; |
457 |
|
|
break; |
458 |
|
|
} |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
/* Apply terminal overrides. */ |
462 |
|
|
o = options_get_only(global_options, "terminal-overrides"); |
463 |
|
|
if (options_array_size(o, &size) != -1) { |
464 |
|
|
for (i = 0; i < size; i++) { |
465 |
|
|
s = options_array_get(o, i); |
466 |
|
|
if (s != NULL) |
467 |
|
|
tty_term_override(term, s); |
468 |
|
|
} |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
/* Delete curses data. */ |
472 |
|
|
del_curterm(cur_term); |
473 |
|
|
|
474 |
|
|
/* These are always required. */ |
475 |
|
|
if (!tty_term_has(term, TTYC_CLEAR)) { |
476 |
|
|
xasprintf(cause, "terminal does not support clear"); |
477 |
|
|
goto error; |
478 |
|
|
} |
479 |
|
|
if (!tty_term_has(term, TTYC_CUP)) { |
480 |
|
|
xasprintf(cause, "terminal does not support cup"); |
481 |
|
|
goto error; |
482 |
|
|
} |
483 |
|
|
|
484 |
|
|
/* These can be emulated so one of the two is required. */ |
485 |
|
|
if (!tty_term_has(term, TTYC_CUD1) && !tty_term_has(term, TTYC_CUD)) { |
486 |
|
|
xasprintf(cause, "terminal does not support cud1 or cud"); |
487 |
|
|
goto error; |
488 |
|
|
} |
489 |
|
|
|
490 |
|
|
/* Figure out if we have 256. */ |
491 |
|
|
if (tty_term_number(term, TTYC_COLORS) == 256) |
492 |
|
|
term->flags |= TERM_256COLOURS; |
493 |
|
|
|
494 |
|
|
/* |
495 |
|
|
* Terminals without xenl (eat newline glitch) wrap at at $COLUMNS - 1 |
496 |
|
|
* rather than $COLUMNS (the cursor can never be beyond $COLUMNS - 1). |
497 |
|
|
* |
498 |
|
|
* This is irritating, most notably because it is impossible to write |
499 |
|
|
* to the very bottom-right of the screen without scrolling. |
500 |
|
|
* |
501 |
|
|
* Flag the terminal here and apply some workarounds in other places to |
502 |
|
|
* do the best possible. |
503 |
|
|
*/ |
504 |
|
|
if (!tty_term_flag(term, TTYC_XENL)) |
505 |
|
|
term->flags |= TERM_EARLYWRAP; |
506 |
|
|
|
507 |
|
|
/* Generate ACS table. If none is present, use nearest ASCII. */ |
508 |
|
|
memset(term->acs, 0, sizeof term->acs); |
509 |
|
|
if (tty_term_has(term, TTYC_ACSC)) |
510 |
|
|
acs = tty_term_string(term, TTYC_ACSC); |
511 |
|
|
else |
512 |
|
|
acs = "a#j+k+l+m+n+o-p-q-r-s-t+u+v+w+x|y<z>~."; |
513 |
|
|
for (; acs[0] != '\0' && acs[1] != '\0'; acs += 2) |
514 |
|
|
term->acs[(u_char) acs[0]][0] = acs[1]; |
515 |
|
|
|
516 |
|
|
/* On terminals with xterm titles (XT), fill in tsl and fsl. */ |
517 |
|
|
if (tty_term_flag(term, TTYC_XT) && |
518 |
|
|
!tty_term_has(term, TTYC_TSL) && |
519 |
|
|
!tty_term_has(term, TTYC_FSL)) { |
520 |
|
|
code = &term->codes[TTYC_TSL]; |
521 |
|
|
code->value.string = xstrdup("\033]0;"); |
522 |
|
|
code->type = TTYCODE_STRING; |
523 |
|
|
code = &term->codes[TTYC_FSL]; |
524 |
|
|
code->value.string = xstrdup("\007"); |
525 |
|
|
code->type = TTYCODE_STRING; |
526 |
|
|
} |
527 |
|
|
|
528 |
|
|
/* On terminals with RGB colour (TC), fill in setrgbf and setrgbb. */ |
529 |
|
|
if (tty_term_flag(term, TTYC_TC) && |
530 |
|
|
!tty_term_has(term, TTYC_SETRGBF) && |
531 |
|
|
!tty_term_has(term, TTYC_SETRGBB)) { |
532 |
|
|
code = &term->codes[TTYC_SETRGBF]; |
533 |
|
|
code->value.string = xstrdup("\033[38;2;%p1%d;%p2%d;%p3%dm"); |
534 |
|
|
code->type = TTYCODE_STRING; |
535 |
|
|
code = &term->codes[TTYC_SETRGBB]; |
536 |
|
|
code->value.string = xstrdup("\033[48;2;%p1%d;%p2%d;%p3%dm"); |
537 |
|
|
code->type = TTYCODE_STRING; |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
/* Log it. */ |
541 |
|
|
for (i = 0; i < tty_term_ncodes(); i++) |
542 |
|
|
log_debug("%s%s", name, tty_term_describe(term, i)); |
543 |
|
|
|
544 |
|
|
return (term); |
545 |
|
|
|
546 |
|
|
error: |
547 |
|
|
tty_term_free(term); |
548 |
|
|
return (NULL); |
549 |
|
|
} |
550 |
|
|
|
551 |
|
|
void |
552 |
|
|
tty_term_free(struct tty_term *term) |
553 |
|
|
{ |
554 |
|
|
u_int i; |
555 |
|
|
|
556 |
|
|
if (--term->references != 0) |
557 |
|
|
return; |
558 |
|
|
|
559 |
|
|
LIST_REMOVE(term, entry); |
560 |
|
|
|
561 |
|
|
for (i = 0; i < tty_term_ncodes(); i++) { |
562 |
|
|
if (term->codes[i].type == TTYCODE_STRING) |
563 |
|
|
free(term->codes[i].value.string); |
564 |
|
|
} |
565 |
|
|
free(term->codes); |
566 |
|
|
|
567 |
|
|
free(term->name); |
568 |
|
|
free(term); |
569 |
|
|
} |
570 |
|
|
|
571 |
|
|
int |
572 |
|
|
tty_term_has(struct tty_term *term, enum tty_code_code code) |
573 |
|
|
{ |
574 |
|
|
return (term->codes[code].type != TTYCODE_NONE); |
575 |
|
|
} |
576 |
|
|
|
577 |
|
|
const char * |
578 |
|
|
tty_term_string(struct tty_term *term, enum tty_code_code code) |
579 |
|
|
{ |
580 |
|
|
if (!tty_term_has(term, code)) |
581 |
|
|
return (""); |
582 |
|
|
if (term->codes[code].type != TTYCODE_STRING) |
583 |
|
|
fatalx("not a string: %d", code); |
584 |
|
|
return (term->codes[code].value.string); |
585 |
|
|
} |
586 |
|
|
|
587 |
|
|
const char * |
588 |
|
|
tty_term_string1(struct tty_term *term, enum tty_code_code code, int a) |
589 |
|
|
{ |
590 |
|
|
return (tparm((char *) tty_term_string(term, code), a)); |
591 |
|
|
} |
592 |
|
|
|
593 |
|
|
const char * |
594 |
|
|
tty_term_string2(struct tty_term *term, enum tty_code_code code, int a, int b) |
595 |
|
|
{ |
596 |
|
|
return (tparm((char *) tty_term_string(term, code), a, b)); |
597 |
|
|
} |
598 |
|
|
|
599 |
|
|
const char * |
600 |
|
|
tty_term_string3(struct tty_term *term, enum tty_code_code code, int a, int b, int c) |
601 |
|
|
{ |
602 |
|
|
return (tparm((char *) tty_term_string(term, code), a, b, c)); |
603 |
|
|
} |
604 |
|
|
|
605 |
|
|
const char * |
606 |
|
|
tty_term_ptr1(struct tty_term *term, enum tty_code_code code, const void *a) |
607 |
|
|
{ |
608 |
|
|
return (tparm((char *) tty_term_string(term, code), a)); |
609 |
|
|
} |
610 |
|
|
|
611 |
|
|
const char * |
612 |
|
|
tty_term_ptr2(struct tty_term *term, enum tty_code_code code, const void *a, |
613 |
|
|
const void *b) |
614 |
|
|
{ |
615 |
|
|
return (tparm((char *) tty_term_string(term, code), a, b)); |
616 |
|
|
} |
617 |
|
|
|
618 |
|
|
int |
619 |
|
|
tty_term_number(struct tty_term *term, enum tty_code_code code) |
620 |
|
|
{ |
621 |
|
|
if (!tty_term_has(term, code)) |
622 |
|
|
return (0); |
623 |
|
|
if (term->codes[code].type != TTYCODE_NUMBER) |
624 |
|
|
fatalx("not a number: %d", code); |
625 |
|
|
return (term->codes[code].value.number); |
626 |
|
|
} |
627 |
|
|
|
628 |
|
|
int |
629 |
|
|
tty_term_flag(struct tty_term *term, enum tty_code_code code) |
630 |
|
|
{ |
631 |
|
|
if (!tty_term_has(term, code)) |
632 |
|
|
return (0); |
633 |
|
|
if (term->codes[code].type != TTYCODE_FLAG) |
634 |
|
|
fatalx("not a flag: %d", code); |
635 |
|
|
return (term->codes[code].value.flag); |
636 |
|
|
} |
637 |
|
|
|
638 |
|
|
const char * |
639 |
|
|
tty_term_describe(struct tty_term *term, enum tty_code_code code) |
640 |
|
|
{ |
641 |
|
|
static char s[256]; |
642 |
|
|
char out[128]; |
643 |
|
|
|
644 |
|
|
switch (term->codes[code].type) { |
645 |
|
|
case TTYCODE_NONE: |
646 |
|
|
xsnprintf(s, sizeof s, "%4u: %s: [missing]", |
647 |
|
|
code, tty_term_codes[code].name); |
648 |
|
|
break; |
649 |
|
|
case TTYCODE_STRING: |
650 |
|
|
strnvis(out, term->codes[code].value.string, sizeof out, |
651 |
|
|
VIS_OCTAL|VIS_TAB|VIS_NL); |
652 |
|
|
xsnprintf(s, sizeof s, "%4u: %s: (string) %s", |
653 |
|
|
code, tty_term_codes[code].name, |
654 |
|
|
out); |
655 |
|
|
break; |
656 |
|
|
case TTYCODE_NUMBER: |
657 |
|
|
xsnprintf(s, sizeof s, "%4u: %s: (number) %d", |
658 |
|
|
code, tty_term_codes[code].name, |
659 |
|
|
term->codes[code].value.number); |
660 |
|
|
break; |
661 |
|
|
case TTYCODE_FLAG: |
662 |
|
|
xsnprintf(s, sizeof s, "%4u: %s: (flag) %s", |
663 |
|
|
code, tty_term_codes[code].name, |
664 |
|
|
term->codes[code].value.flag ? "true" : "false"); |
665 |
|
|
break; |
666 |
|
|
} |
667 |
|
|
return (s); |
668 |
|
|
} |