Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD$ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 2010 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 <stdlib.h> |
22 | | #include <string.h> |
23 | | |
24 | | #include "tmux.h" |
25 | | |
26 | | /* Table mapping ACS entries to UTF-8. */ |
27 | | struct tty_acs_entry { |
28 | | u_char key; |
29 | | const char *string; |
30 | | }; |
31 | | static const struct tty_acs_entry tty_acs_table[] = { |
32 | | { '+', "\342\206\222" }, /* arrow pointing right */ |
33 | | { ',', "\342\206\220" }, /* arrow pointing left */ |
34 | | { '-', "\342\206\221" }, /* arrow pointing up */ |
35 | | { '.', "\342\206\223" }, /* arrow pointing down */ |
36 | | { '0', "\342\226\256" }, /* solid square block */ |
37 | | { '`', "\342\227\206" }, /* diamond */ |
38 | | { 'a', "\342\226\222" }, /* checker board (stipple) */ |
39 | | { 'b', "\342\220\211" }, |
40 | | { 'c', "\342\220\214" }, |
41 | | { 'd', "\342\220\215" }, |
42 | | { 'e', "\342\220\212" }, |
43 | | { 'f', "\302\260" }, /* degree symbol */ |
44 | | { 'g', "\302\261" }, /* plus/minus */ |
45 | | { 'h', "\342\220\244" }, |
46 | | { 'i', "\342\220\213" }, |
47 | | { 'j', "\342\224\230" }, /* lower right corner */ |
48 | | { 'k', "\342\224\220" }, /* upper right corner */ |
49 | | { 'l', "\342\224\214" }, /* upper left corner */ |
50 | | { 'm', "\342\224\224" }, /* lower left corner */ |
51 | | { 'n', "\342\224\274" }, /* large plus or crossover */ |
52 | | { 'o', "\342\216\272" }, /* scan line 1 */ |
53 | | { 'p', "\342\216\273" }, /* scan line 3 */ |
54 | | { 'q', "\342\224\200" }, /* horizontal line */ |
55 | | { 'r', "\342\216\274" }, /* scan line 7 */ |
56 | | { 's', "\342\216\275" }, /* scan line 9 */ |
57 | | { 't', "\342\224\234" }, /* tee pointing right */ |
58 | | { 'u', "\342\224\244" }, /* tee pointing left */ |
59 | | { 'v', "\342\224\264" }, /* tee pointing up */ |
60 | | { 'w', "\342\224\254" }, /* tee pointing down */ |
61 | | { 'x', "\342\224\202" }, /* vertical line */ |
62 | | { 'y', "\342\211\244" }, /* less-than-or-equal-to */ |
63 | | { 'z', "\342\211\245" }, /* greater-than-or-equal-to */ |
64 | | { '{', "\317\200" }, /* greek pi */ |
65 | | { '|', "\342\211\240" }, /* not-equal */ |
66 | | { '}', "\302\243" }, /* UK pound sign */ |
67 | | { '~', "\302\267" } /* bullet */ |
68 | | }; |
69 | | |
70 | | /* Table mapping UTF-8 to ACS entries. */ |
71 | | struct tty_acs_reverse_entry { |
72 | | const char *string; |
73 | | u_char key; |
74 | | }; |
75 | | static const struct tty_acs_reverse_entry tty_acs_reverse2[] = { |
76 | | { "\302\267", '~' } |
77 | | }; |
78 | | static const struct tty_acs_reverse_entry tty_acs_reverse3[] = { |
79 | | { "\342\224\200", 'q' }, |
80 | | { "\342\224\201", 'q' }, |
81 | | { "\342\224\202", 'x' }, |
82 | | { "\342\224\203", 'x' }, |
83 | | { "\342\224\214", 'l' }, |
84 | | { "\342\224\217", 'k' }, |
85 | | { "\342\224\220", 'k' }, |
86 | | { "\342\224\223", 'l' }, |
87 | | { "\342\224\224", 'm' }, |
88 | | { "\342\224\227", 'm' }, |
89 | | { "\342\224\230", 'j' }, |
90 | | { "\342\224\233", 'j' }, |
91 | | { "\342\224\234", 't' }, |
92 | | { "\342\224\243", 't' }, |
93 | | { "\342\224\244", 'u' }, |
94 | | { "\342\224\253", 'u' }, |
95 | | { "\342\224\263", 'w' }, |
96 | | { "\342\224\264", 'v' }, |
97 | | { "\342\224\273", 'v' }, |
98 | | { "\342\224\274", 'n' }, |
99 | | { "\342\225\213", 'n' }, |
100 | | { "\342\225\220", 'q' }, |
101 | | { "\342\225\221", 'x' }, |
102 | | { "\342\225\224", 'l' }, |
103 | | { "\342\225\227", 'k' }, |
104 | | { "\342\225\232", 'm' }, |
105 | | { "\342\225\235", 'j' }, |
106 | | { "\342\225\240", 't' }, |
107 | | { "\342\225\243", 'u' }, |
108 | | { "\342\225\246", 'w' }, |
109 | | { "\342\225\251", 'v' }, |
110 | | { "\342\225\254", 'n' }, |
111 | | }; |
112 | | |
113 | | /* UTF-8 double borders. */ |
114 | | static const struct utf8_data tty_acs_double_borders_list[] = { |
115 | | { "", 0, 0, 0 }, |
116 | | { "\342\225\221", 0, 3, 1 }, /* U+2551 */ |
117 | | { "\342\225\220", 0, 3, 1 }, /* U+2550 */ |
118 | | { "\342\225\224", 0, 3, 1 }, /* U+2554 */ |
119 | | { "\342\225\227", 0, 3, 1 }, /* U+2557 */ |
120 | | { "\342\225\232", 0, 3, 1 }, /* U+255A */ |
121 | | { "\342\225\235", 0, 3, 1 }, /* U+255D */ |
122 | | { "\342\225\246", 0, 3, 1 }, /* U+2566 */ |
123 | | { "\342\225\251", 0, 3, 1 }, /* U+2569 */ |
124 | | { "\342\225\240", 0, 3, 1 }, /* U+2560 */ |
125 | | { "\342\225\243", 0, 3, 1 }, /* U+2563 */ |
126 | | { "\342\225\254", 0, 3, 1 }, /* U+256C */ |
127 | | { "\302\267", 0, 2, 1 } /* U+00B7 */ |
128 | | }; |
129 | | |
130 | | /* UTF-8 heavy borders. */ |
131 | | static const struct utf8_data tty_acs_heavy_borders_list[] = { |
132 | | { "", 0, 0, 0 }, |
133 | | { "\342\224\203", 0, 3, 1 }, /* U+2503 */ |
134 | | { "\342\224\201", 0, 3, 1 }, /* U+2501 */ |
135 | | { "\342\224\217", 0, 3, 1 }, /* U+250F */ |
136 | | { "\342\224\223", 0, 3, 1 }, /* U+2513 */ |
137 | | { "\342\224\227", 0, 3, 1 }, /* U+2517 */ |
138 | | { "\342\224\233", 0, 3, 1 }, /* U+251B */ |
139 | | { "\342\224\263", 0, 3, 1 }, /* U+2533 */ |
140 | | { "\342\224\273", 0, 3, 1 }, /* U+253B */ |
141 | | { "\342\224\243", 0, 3, 1 }, /* U+2523 */ |
142 | | { "\342\224\253", 0, 3, 1 }, /* U+252B */ |
143 | | { "\342\225\213", 0, 3, 1 }, /* U+254B */ |
144 | | { "\302\267", 0, 2, 1 } /* U+00B7 */ |
145 | | }; |
146 | | |
147 | | /* UTF-8 rounded borders. */ |
148 | | static const struct utf8_data tty_acs_rounded_borders_list[] = { |
149 | | { "", 0, 0, 0 }, |
150 | | { "\342\224\202", 0, 3, 1 }, /* U+2502 */ |
151 | | { "\342\224\200", 0, 3, 1 }, /* U+2500 */ |
152 | | { "\342\225\255", 0, 3, 1 }, /* U+256D */ |
153 | | { "\342\225\256", 0, 3, 1 }, /* U+256E */ |
154 | | { "\342\225\260", 0, 3, 1 }, /* U+2570 */ |
155 | | { "\342\225\257", 0, 3, 1 }, /* U+256F */ |
156 | | { "\342\224\263", 0, 3, 1 }, /* U+2533 */ |
157 | | { "\342\224\273", 0, 3, 1 }, /* U+253B */ |
158 | | { "\342\224\234", 0, 3, 1 }, /* U+2524 */ |
159 | | { "\342\224\244", 0, 3, 1 }, /* U+251C */ |
160 | | { "\342\225\213", 0, 3, 1 }, /* U+254B */ |
161 | | { "\302\267", 0, 2, 1 } /* U+00B7 */ |
162 | | }; |
163 | | |
164 | | /* Get cell border character for double style. */ |
165 | | const struct utf8_data * |
166 | | tty_acs_double_borders(int cell_type) |
167 | 0 | { |
168 | 0 | return (&tty_acs_double_borders_list[cell_type]); |
169 | 0 | } |
170 | | |
171 | | /* Get cell border character for heavy style. */ |
172 | | const struct utf8_data * |
173 | | tty_acs_heavy_borders(int cell_type) |
174 | 0 | { |
175 | 0 | return (&tty_acs_heavy_borders_list[cell_type]); |
176 | 0 | } |
177 | | |
178 | | /* Get cell border character for rounded style. */ |
179 | | const struct utf8_data * |
180 | | tty_acs_rounded_borders(int cell_type) |
181 | 0 | { |
182 | 0 | return (&tty_acs_rounded_borders_list[cell_type]); |
183 | 0 | } |
184 | | |
185 | | static int |
186 | | tty_acs_cmp(const void *key, const void *value) |
187 | 0 | { |
188 | 0 | const struct tty_acs_entry *entry = value; |
189 | 0 | int test = *(u_char *)key; |
190 | |
|
191 | 0 | return (test - entry->key); |
192 | 0 | } |
193 | | |
194 | | static int |
195 | | tty_acs_reverse_cmp(const void *key, const void *value) |
196 | 0 | { |
197 | 0 | const struct tty_acs_reverse_entry *entry = value; |
198 | 0 | const char *test = key; |
199 | |
|
200 | 0 | return (strcmp(test, entry->string)); |
201 | 0 | } |
202 | | |
203 | | /* Should this terminal use ACS instead of UTF-8 line drawing? */ |
204 | | int |
205 | | tty_acs_needed(struct tty *tty) |
206 | 0 | { |
207 | 0 | if (tty == NULL) |
208 | 0 | return (0); |
209 | | |
210 | | /* |
211 | | * If the U8 flag is present, it marks whether a terminal supports |
212 | | * UTF-8 and ACS together. |
213 | | * |
214 | | * If it is present and zero, we force ACS - this gives users a way to |
215 | | * turn off UTF-8 line drawing. |
216 | | * |
217 | | * If it is nonzero, we can fall through to the default and use UTF-8 |
218 | | * line drawing on UTF-8 terminals. |
219 | | */ |
220 | 0 | if (tty_term_has(tty->term, TTYC_U8) && |
221 | 0 | tty_term_number(tty->term, TTYC_U8) == 0) |
222 | 0 | return (1); |
223 | | |
224 | 0 | if (tty->client->flags & CLIENT_UTF8) |
225 | 0 | return (0); |
226 | 0 | return (1); |
227 | 0 | } |
228 | | |
229 | | /* Retrieve ACS to output as UTF-8. */ |
230 | | const char * |
231 | | tty_acs_get(struct tty *tty, u_char ch) |
232 | 0 | { |
233 | 0 | const struct tty_acs_entry *entry; |
234 | | |
235 | | /* Use the ACS set instead of UTF-8 if needed. */ |
236 | 0 | if (tty_acs_needed(tty)) { |
237 | 0 | if (tty->term->acs[ch][0] == '\0') |
238 | 0 | return (NULL); |
239 | 0 | return (&tty->term->acs[ch][0]); |
240 | 0 | } |
241 | | |
242 | | /* Otherwise look up the UTF-8 translation. */ |
243 | 0 | entry = bsearch(&ch, tty_acs_table, nitems(tty_acs_table), |
244 | 0 | sizeof tty_acs_table[0], tty_acs_cmp); |
245 | 0 | if (entry == NULL) |
246 | 0 | return (NULL); |
247 | 0 | return (entry->string); |
248 | 0 | } |
249 | | |
250 | | /* Reverse UTF-8 into ACS. */ |
251 | | int |
252 | | tty_acs_reverse_get(__unused struct tty *tty, const char *s, size_t slen) |
253 | 0 | { |
254 | 0 | const struct tty_acs_reverse_entry *table, *entry; |
255 | 0 | u_int items; |
256 | |
|
257 | 0 | if (slen == 2) { |
258 | 0 | table = tty_acs_reverse2; |
259 | 0 | items = nitems(tty_acs_reverse2); |
260 | 0 | } else if (slen == 3) { |
261 | 0 | table = tty_acs_reverse3; |
262 | 0 | items = nitems(tty_acs_reverse3); |
263 | 0 | } else |
264 | 0 | return (-1); |
265 | 0 | entry = bsearch(s, table, items, sizeof table[0], tty_acs_reverse_cmp); |
266 | 0 | if (entry == NULL) |
267 | 0 | return (-1); |
268 | 0 | return (entry->key); |
269 | 0 | } |