1 /* vifm
2 * Copyright (C) 2012 xaizek.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "bracket_notation.h"
20
21 #include <curses.h>
22
23 #include <assert.h> /* assert() */
24 #include <ctype.h> /* tolower() */
25 #include <stddef.h> /* NULL size_t wchar_t */
26 #include <stdlib.h> /* free() */
27 #include <string.h> /* strcpy() strlen() */
28 #include <wchar.h> /* wcscpy() wcslen() */
29 #include <wctype.h> /* iswcntrl() */
30
31 #include "compat/curses.h"
32 #include "compat/reallocarray.h"
33 #include "engine/text_buffer.h"
34 #include "modes/wk.h"
35 #include "utils/macros.h"
36 #include "utils/str.h"
37 #include "utils/utils.h"
38
39 /* Bracket notation entry description structure. */
40 typedef struct
41 {
42 const wchar_t *notation; /* The notation itself. */
43 const wchar_t key[8]; /* The replacement for the notation. */
44 size_t len; /* Length of the notation. */
45 }
46 key_pair_t;
47
48 static int notation_sorter(const void *first, const void *second);
49 static const key_pair_t * find_notation(const wchar_t str[]);
50 static const char * wchar_to_spec(const wchar_t c[], size_t *len, int bs);
51
52 /* All notation fields must be written in lower case. */
53 static key_pair_t key_pairs[] = {
54 { L"<esc>", L"\x1b" },
55 { L"<c-@>", { WC_C_SPACE } },
56 { L"<c-a>", L"\x01" },
57 { L"<c-b>", L"\x02" },
58 { L"<c-c>", L"\x03" },
59 { L"<c-d>", L"\x04" },
60 { L"<c-e>", L"\x05" },
61 { L"<c-f>", L"\x06" },
62 { L"<c-g>", L"\x07" },
63 { L"<c-h>", L"\x08" },
64 { L"<c-i>", L"\x09" },
65 { L"<c-j>", L"\x0a" },
66 { L"<c-k>", L"\x0b" },
67 { L"<c-l>", L"\x0c" },
68 { L"<c-m>", L"\x0d" },
69 { L"<c-n>", L"\x0e" },
70 { L"<c-o>", L"\x0f" },
71 { L"<c-p>", L"\x10" },
72 { L"<c-q>", L"\x11" },
73 { L"<c-r>", L"\x12" },
74 { L"<c-s>", L"\x13" },
75 { L"<c-t>", L"\x14" },
76 { L"<c-u>", L"\x15" },
77 { L"<c-v>", L"\x16" },
78 { L"<c-w>", L"\x17" },
79 { L"<c-x>", L"\x18" },
80 { L"<c-y>", L"\x19" },
81 { L"<c-z>", L"\x1a" },
82 { L"<c-[>", L"\x1b" },
83 { L"<c-\\>", L"\x1c" },
84 { L"<c-]>", L"\x1d" },
85 { L"<c-^>", L"\x1e" },
86 { L"<c-_>", L"\x1f" },
87 { L"<s-c-a>", L"\x01" },
88 { L"<s-c-b>", L"\x02" },
89 { L"<s-c-c>", L"\x03" },
90 { L"<s-c-d>", L"\x04" },
91 { L"<s-c-e>", L"\x05" },
92 { L"<s-c-f>", L"\x06" },
93 { L"<s-c-g>", L"\x07" },
94 { L"<s-c-h>", L"\x08" },
95 { L"<s-c-i>", L"\x09" },
96 { L"<s-c-j>", L"\x0a" },
97 { L"<s-c-k>", L"\x0b" },
98 { L"<s-c-l>", L"\x0c" },
99 { L"<s-c-m>", L"\x0d" },
100 { L"<s-c-n>", L"\x0e" },
101 { L"<s-c-o>", L"\x0f" },
102 { L"<s-c-p>", L"\x10" },
103 { L"<s-c-q>", L"\x11" },
104 { L"<s-c-r>", L"\x12" },
105 { L"<s-c-s>", L"\x13" },
106 { L"<s-c-t>", L"\x14" },
107 { L"<s-c-u>", L"\x15" },
108 { L"<s-c-v>", L"\x16" },
109 { L"<s-c-w>", L"\x17" },
110 { L"<s-c-x>", L"\x18" },
111 { L"<s-c-y>", L"\x19" },
112 { L"<s-c-z>", L"\x1a" },
113 { L"<s-c-[>", L"\x1b" },
114 { L"<s-c-\\>", L"\x1c" },
115 { L"<s-c-]>", L"\x1d" },
116 { L"<s-c-^>", L"\x1e" },
117 { L"<s-c-_>", L"\x1f" },
118 { L"<c-s-a>", L"\x01" },
119 { L"<c-s-b>", L"\x02" },
120 { L"<c-s-c>", L"\x03" },
121 { L"<c-s-d>", L"\x04" },
122 { L"<c-s-e>", L"\x05" },
123 { L"<c-s-f>", L"\x06" },
124 { L"<c-s-g>", L"\x07" },
125 { L"<c-s-h>", L"\x08" },
126 { L"<c-s-i>", L"\x09" },
127 { L"<c-s-j>", L"\x0a" },
128 { L"<c-s-k>", L"\x0b" },
129 { L"<c-s-l>", L"\x0c" },
130 { L"<c-s-m>", L"\x0d" },
131 { L"<c-s-n>", L"\x0e" },
132 { L"<c-s-o>", L"\x0f" },
133 { L"<c-s-p>", L"\x10" },
134 { L"<c-s-q>", L"\x11" },
135 { L"<c-s-r>", L"\x12" },
136 { L"<c-s-s>", L"\x13" },
137 { L"<c-s-t>", L"\x14" },
138 { L"<c-s-u>", L"\x15" },
139 { L"<c-s-v>", L"\x16" },
140 { L"<c-s-w>", L"\x17" },
141 { L"<c-s-x>", L"\x18" },
142 { L"<c-s-y>", L"\x19" },
143 { L"<c-s-z>", L"\x1a" },
144 { L"<c-s-[>", L"\x1b" },
145 { L"<c-s-\\>", L"\x1c" },
146 { L"<c-s-]>", L"\x1d" },
147 { L"<c-s-^>", L"\x1e" },
148 { L"<c-s-_>", L"\x1f" },
149 { L"<cr>", L"\r" },
150 { L"<space>", L" " },
151 { L"<nop>", L"" },
152 { L"<tab>", L"\t" },
153 { L"<lt>", L"<" },
154 #ifdef ENABLE_EXTENDED_KEYS
155 { L"<s-tab>", { K(KEY_BTAB) } },
156 #else
157 { L"<s-tab>", L"\033"L"[Z" },
158 #endif
159 #ifndef __PDCURSES__
160 { L"<a-a>", L"\033"L"a" },
161 { L"<a-b>", L"\033"L"b" },
162 { L"<a-c>", L"\033"L"c" },
163 { L"<a-d>", L"\033"L"d" },
164 { L"<a-e>", L"\033"L"e" },
165 { L"<a-f>", L"\033"L"f" },
166 { L"<a-g>", L"\033"L"g" },
167 { L"<a-h>", L"\033"L"h" },
168 { L"<a-i>", L"\033"L"i" },
169 { L"<a-j>", L"\033"L"j" },
170 { L"<a-k>", L"\033"L"k" },
171 { L"<a-l>", L"\033"L"l" },
172 { L"<a-m>", L"\033"L"m" },
173 { L"<a-n>", L"\033"L"n" },
174 { L"<a-o>", L"\033"L"o" },
175 { L"<a-p>", L"\033"L"p" },
176 { L"<a-q>", L"\033"L"q" },
177 { L"<a-r>", L"\033"L"r" },
178 { L"<a-s>", L"\033"L"s" },
179 { L"<a-t>", L"\033"L"t" },
180 { L"<a-u>", L"\033"L"u" },
181 { L"<a-v>", L"\033"L"v" },
182 { L"<a-w>", L"\033"L"w" },
183 { L"<a-x>", L"\033"L"x" },
184 { L"<a-y>", L"\033"L"y" },
185 { L"<a-z>", L"\033"L"z" },
186 { L"<m-a>", L"\033"L"a" },
187 { L"<m-b>", L"\033"L"b" },
188 { L"<m-c>", L"\033"L"c" },
189 { L"<m-d>", L"\033"L"d" },
190 { L"<m-e>", L"\033"L"e" },
191 { L"<m-f>", L"\033"L"f" },
192 { L"<m-g>", L"\033"L"g" },
193 { L"<m-h>", L"\033"L"h" },
194 { L"<m-i>", L"\033"L"i" },
195 { L"<m-j>", L"\033"L"j" },
196 { L"<m-k>", L"\033"L"k" },
197 { L"<m-l>", L"\033"L"l" },
198 { L"<m-m>", L"\033"L"m" },
199 { L"<m-n>", L"\033"L"n" },
200 { L"<m-o>", L"\033"L"o" },
201 { L"<m-p>", L"\033"L"p" },
202 { L"<m-q>", L"\033"L"q" },
203 { L"<m-r>", L"\033"L"r" },
204 { L"<m-s>", L"\033"L"s" },
205 { L"<m-t>", L"\033"L"t" },
206 { L"<m-u>", L"\033"L"u" },
207 { L"<m-v>", L"\033"L"v" },
208 { L"<m-w>", L"\033"L"w" },
209 { L"<m-x>", L"\033"L"x" },
210 { L"<m-y>", L"\033"L"y" },
211 { L"<m-z>", L"\033"L"z" },
212 { L"<a-c-a>", L"\033"L"\x01" },
213 { L"<a-c-b>", L"\033"L"\x02" },
214 { L"<a-c-c>", L"\033"L"\x03" },
215 { L"<a-c-d>", L"\033"L"\x04" },
216 { L"<a-c-e>", L"\033"L"\x05" },
217 { L"<a-c-f>", L"\033"L"\x06" },
218 { L"<a-c-g>", L"\033"L"\x07" },
219 { L"<a-c-h>", L"\033"L"\x08" },
220 { L"<a-c-i>", L"\033"L"\x09" },
221 { L"<a-c-j>", L"\033"L"\x0a" },
222 { L"<a-c-k>", L"\033"L"\x0b" },
223 { L"<a-c-l>", L"\033"L"\x0c" },
224 { L"<a-c-m>", L"\033"L"\x0d" },
225 { L"<a-c-n>", L"\033"L"\x0e" },
226 { L"<a-c-o>", L"\033"L"\x0f" },
227 { L"<a-c-p>", L"\033"L"\x10" },
228 { L"<a-c-q>", L"\033"L"\x11" },
229 { L"<a-c-r>", L"\033"L"\x12" },
230 { L"<a-c-s>", L"\033"L"\x13" },
231 { L"<a-c-t>", L"\033"L"\x14" },
232 { L"<a-c-u>", L"\033"L"\x15" },
233 { L"<a-c-v>", L"\033"L"\x16" },
234 { L"<a-c-w>", L"\033"L"\x17" },
235 { L"<a-c-x>", L"\033"L"\x18" },
236 { L"<a-c-y>", L"\033"L"\x19" },
237 { L"<a-c-z>", L"\033"L"\x1a" },
238 { L"<m-c-a>", L"\033"L"\x01" },
239 { L"<m-c-b>", L"\033"L"\x02" },
240 { L"<m-c-c>", L"\033"L"\x03" },
241 { L"<m-c-d>", L"\033"L"\x04" },
242 { L"<m-c-e>", L"\033"L"\x05" },
243 { L"<m-c-f>", L"\033"L"\x06" },
244 { L"<m-c-g>", L"\033"L"\x07" },
245 { L"<m-c-h>", L"\033"L"\x08" },
246 { L"<m-c-i>", L"\033"L"\x09" },
247 { L"<m-c-j>", L"\033"L"\x0a" },
248 { L"<m-c-k>", L"\033"L"\x0b" },
249 { L"<m-c-l>", L"\033"L"\x0c" },
250 { L"<m-c-m>", L"\033"L"\x0d" },
251 { L"<m-c-n>", L"\033"L"\x0e" },
252 { L"<m-c-o>", L"\033"L"\x0f" },
253 { L"<m-c-p>", L"\033"L"\x10" },
254 { L"<m-c-q>", L"\033"L"\x11" },
255 { L"<m-c-r>", L"\033"L"\x12" },
256 { L"<m-c-s>", L"\033"L"\x13" },
257 { L"<m-c-t>", L"\033"L"\x14" },
258 { L"<m-c-u>", L"\033"L"\x15" },
259 { L"<m-c-v>", L"\033"L"\x16" },
260 { L"<m-c-w>", L"\033"L"\x17" },
261 { L"<m-c-x>", L"\033"L"\x18" },
262 { L"<m-c-y>", L"\033"L"\x19" },
263 { L"<m-c-z>", L"\033"L"\x1a" },
264 { L"<c-a-a>", L"\033"L"\x01" },
265 { L"<c-a-b>", L"\033"L"\x02" },
266 { L"<c-a-c>", L"\033"L"\x03" },
267 { L"<c-a-d>", L"\033"L"\x04" },
268 { L"<c-a-e>", L"\033"L"\x05" },
269 { L"<c-a-f>", L"\033"L"\x06" },
270 { L"<c-a-g>", L"\033"L"\x07" },
271 { L"<c-a-h>", L"\033"L"\x08" },
272 { L"<c-a-i>", L"\033"L"\x09" },
273 { L"<c-a-j>", L"\033"L"\x0a" },
274 { L"<c-a-k>", L"\033"L"\x0b" },
275 { L"<c-a-l>", L"\033"L"\x0c" },
276 { L"<c-a-m>", L"\033"L"\x0d" },
277 { L"<c-a-n>", L"\033"L"\x0e" },
278 { L"<c-a-o>", L"\033"L"\x0f" },
279 { L"<c-a-p>", L"\033"L"\x10" },
280 { L"<c-a-q>", L"\033"L"\x11" },
281 { L"<c-a-r>", L"\033"L"\x12" },
282 { L"<c-a-s>", L"\033"L"\x13" },
283 { L"<c-a-t>", L"\033"L"\x14" },
284 { L"<c-a-u>", L"\033"L"\x15" },
285 { L"<c-a-v>", L"\033"L"\x16" },
286 { L"<c-a-w>", L"\033"L"\x17" },
287 { L"<c-a-x>", L"\033"L"\x18" },
288 { L"<c-a-y>", L"\033"L"\x19" },
289 { L"<c-a-z>", L"\033"L"\x1a" },
290 { L"<c-m-a>", L"\033"L"\x01" },
291 { L"<c-m-b>", L"\033"L"\x02" },
292 { L"<c-m-c>", L"\033"L"\x03" },
293 { L"<c-m-d>", L"\033"L"\x04" },
294 { L"<c-m-e>", L"\033"L"\x05" },
295 { L"<c-m-f>", L"\033"L"\x06" },
296 { L"<c-m-g>", L"\033"L"\x07" },
297 { L"<c-m-h>", L"\033"L"\x08" },
298 { L"<c-m-i>", L"\033"L"\x09" },
299 { L"<c-m-j>", L"\033"L"\x0a" },
300 { L"<c-m-k>", L"\033"L"\x0b" },
301 { L"<c-m-l>", L"\033"L"\x0c" },
302 { L"<c-m-m>", L"\033"L"\x0d" },
303 { L"<c-m-n>", L"\033"L"\x0e" },
304 { L"<c-m-o>", L"\033"L"\x0f" },
305 { L"<c-m-p>", L"\033"L"\x10" },
306 { L"<c-m-q>", L"\033"L"\x11" },
307 { L"<c-m-r>", L"\033"L"\x12" },
308 { L"<c-m-s>", L"\033"L"\x13" },
309 { L"<c-m-t>", L"\033"L"\x14" },
310 { L"<c-m-u>", L"\033"L"\x15" },
311 { L"<c-m-v>", L"\033"L"\x16" },
312 { L"<c-m-w>", L"\033"L"\x17" },
313 { L"<c-m-x>", L"\033"L"\x18" },
314 { L"<c-m-y>", L"\033"L"\x19" },
315 { L"<c-m-z>", L"\033"L"\x1a" },
316 #else
317 { L"<a-a>", { K(ALT_A) } },
318 { L"<a-b>", { K(ALT_B) } },
319 { L"<a-c>", { K(ALT_C) } },
320 { L"<a-d>", { K(ALT_D) } },
321 { L"<a-e>", { K(ALT_E) } },
322 { L"<a-f>", { K(ALT_F) } },
323 { L"<a-g>", { K(ALT_G) } },
324 { L"<a-h>", { K(ALT_H) } },
325 { L"<a-i>", { K(ALT_I) } },
326 { L"<a-j>", { K(ALT_J) } },
327 { L"<a-k>", { K(ALT_K) } },
328 { L"<a-l>", { K(ALT_L) } },
329 { L"<a-m>", { K(ALT_M) } },
330 { L"<a-n>", { K(ALT_N) } },
331 { L"<a-o>", { K(ALT_O) } },
332 { L"<a-p>", { K(ALT_P) } },
333 { L"<a-q>", { K(ALT_Q) } },
334 { L"<a-r>", { K(ALT_R) } },
335 { L"<a-s>", { K(ALT_S) } },
336 { L"<a-t>", { K(ALT_T) } },
337 { L"<a-u>", { K(ALT_U) } },
338 { L"<a-v>", { K(ALT_V) } },
339 { L"<a-w>", { K(ALT_W) } },
340 { L"<a-x>", { K(ALT_X) } },
341 { L"<a-y>", { K(ALT_Y) } },
342 { L"<a-z>", { K(ALT_Z) } },
343 { L"<m-a>", { K(ALT_A) } },
344 { L"<m-b>", { K(ALT_B) } },
345 { L"<m-c>", { K(ALT_C) } },
346 { L"<m-d>", { K(ALT_D) } },
347 { L"<m-e>", { K(ALT_E) } },
348 { L"<m-f>", { K(ALT_F) } },
349 { L"<m-g>", { K(ALT_G) } },
350 { L"<m-h>", { K(ALT_H) } },
351 { L"<m-i>", { K(ALT_I) } },
352 { L"<m-j>", { K(ALT_J) } },
353 { L"<m-k>", { K(ALT_K) } },
354 { L"<m-l>", { K(ALT_L) } },
355 { L"<m-m>", { K(ALT_M) } },
356 { L"<m-n>", { K(ALT_N) } },
357 { L"<m-o>", { K(ALT_O) } },
358 { L"<m-p>", { K(ALT_P) } },
359 { L"<m-q>", { K(ALT_Q) } },
360 { L"<m-r>", { K(ALT_R) } },
361 { L"<m-s>", { K(ALT_S) } },
362 { L"<m-t>", { K(ALT_T) } },
363 { L"<m-u>", { K(ALT_U) } },
364 { L"<m-v>", { K(ALT_V) } },
365 { L"<m-w>", { K(ALT_W) } },
366 { L"<m-x>", { K(ALT_X) } },
367 { L"<m-y>", { K(ALT_Y) } },
368 { L"<m-z>", { K(ALT_Z) } },
369 #endif
370 { L"<del>", L"\177" },
371 #ifdef ENABLE_EXTENDED_KEYS
372 { L"<home>", { K(KEY_HOME) } },
373 { L"<end>", { K(KEY_END) } },
374 { L"<left>", { K(KEY_LEFT) } },
375 { L"<right>", { K(KEY_RIGHT) } },
376 { L"<up>", { K(KEY_UP) } },
377 { L"<down>", { K(KEY_DOWN) } },
378 { L"<bs>", { K(KEY_BACKSPACE) } },
379 { L"<delete>", { K(KEY_DC) } },
380 { L"<insert>", { K(KEY_IC) } },
381 { L"<pageup>", { K(KEY_PPAGE) } },
382 { L"<pagedown>", { K(KEY_NPAGE) } },
383 { L"<f0>", { K(KEY_F(0)) } },
384 { L"<f1>", { K(KEY_F(1)) } },
385 { L"<f2>", { K(KEY_F(2)) } },
386 { L"<f3>", { K(KEY_F(3)) } },
387 { L"<f4>", { K(KEY_F(4)) } },
388 { L"<f5>", { K(KEY_F(5)) } },
389 { L"<f6>", { K(KEY_F(6)) } },
390 { L"<f7>", { K(KEY_F(7)) } },
391 { L"<f8>", { K(KEY_F(8)) } },
392 { L"<f9>", { K(KEY_F(9)) } },
393 { L"<f10>", { K(KEY_F(10)) } },
394 { L"<f11>", { K(KEY_F(11)) } },
395 { L"<f12>", { K(KEY_F(12)) } },
396 { L"<f13>", { K(KEY_F(13)) } },
397 { L"<f14>", { K(KEY_F(14)) } },
398 { L"<f15>", { K(KEY_F(15)) } },
399 { L"<f16>", { K(KEY_F(16)) } },
400 { L"<f17>", { K(KEY_F(17)) } },
401 { L"<f18>", { K(KEY_F(18)) } },
402 { L"<f19>", { K(KEY_F(19)) } },
403 { L"<f20>", { K(KEY_F(20)) } },
404 { L"<f21>", { K(KEY_F(21)) } },
405 { L"<f22>", { K(KEY_F(22)) } },
406 { L"<f23>", { K(KEY_F(23)) } },
407 { L"<f24>", { K(KEY_F(24)) } },
408 { L"<f25>", { K(KEY_F(25)) } },
409 { L"<f26>", { K(KEY_F(26)) } },
410 { L"<f27>", { K(KEY_F(27)) } },
411 { L"<f28>", { K(KEY_F(28)) } },
412 { L"<f29>", { K(KEY_F(29)) } },
413 { L"<f30>", { K(KEY_F(30)) } },
414 { L"<f31>", { K(KEY_F(31)) } },
415 { L"<f32>", { K(KEY_F(32)) } },
416 { L"<f33>", { K(KEY_F(33)) } },
417 { L"<f34>", { K(KEY_F(34)) } },
418 { L"<f35>", { K(KEY_F(35)) } },
419 { L"<f36>", { K(KEY_F(36)) } },
420 { L"<f37>", { K(KEY_F(37)) } },
421 { L"<f38>", { K(KEY_F(38)) } },
422 { L"<f39>", { K(KEY_F(39)) } },
423 { L"<f40>", { K(KEY_F(40)) } },
424 { L"<f41>", { K(KEY_F(41)) } },
425 { L"<f42>", { K(KEY_F(42)) } },
426 { L"<f43>", { K(KEY_F(43)) } },
427 { L"<f44>", { K(KEY_F(44)) } },
428 { L"<f45>", { K(KEY_F(45)) } },
429 { L"<f46>", { K(KEY_F(46)) } },
430 { L"<f47>", { K(KEY_F(47)) } },
431 { L"<f48>", { K(KEY_F(48)) } },
432 { L"<f49>", { K(KEY_F(49)) } },
433 { L"<f50>", { K(KEY_F(50)) } },
434 { L"<f51>", { K(KEY_F(51)) } },
435 { L"<f52>", { K(KEY_F(52)) } },
436 { L"<f53>", { K(KEY_F(53)) } },
437 { L"<f54>", { K(KEY_F(54)) } },
438 { L"<f55>", { K(KEY_F(55)) } },
439 { L"<f56>", { K(KEY_F(56)) } },
440 { L"<f57>", { K(KEY_F(57)) } },
441 { L"<f58>", { K(KEY_F(58)) } },
442 { L"<f59>", { K(KEY_F(59)) } },
443 { L"<f60>", { K(KEY_F(60)) } },
444 { L"<f61>", { K(KEY_F(61)) } },
445 { L"<f62>", { K(KEY_F(62)) } },
446 { L"<f63>", { K(KEY_F(63)) } },
447 { L"<s-f1>", { K(KEY_F(13)) } },
448 { L"<s-f2>", { K(KEY_F(14)) } },
449 { L"<s-f3>", { K(KEY_F(15)) } },
450 { L"<s-f4>", { K(KEY_F(16)) } },
451 { L"<s-f5>", { K(KEY_F(17)) } },
452 { L"<s-f6>", { K(KEY_F(18)) } },
453 { L"<s-f7>", { K(KEY_F(19)) } },
454 { L"<s-f8>", { K(KEY_F(20)) } },
455 { L"<s-f9>", { K(KEY_F(21)) } },
456 { L"<s-f10>", { K(KEY_F(22)) } },
457 { L"<s-f11>", { K(KEY_F(23)) } },
458 { L"<s-f12>", { K(KEY_F(24)) } },
459 { L"<c-f1>", { K(KEY_F(25)) } },
460 { L"<c-f2>", { K(KEY_F(26)) } },
461 { L"<c-f3>", { K(KEY_F(27)) } },
462 { L"<c-f4>", { K(KEY_F(28)) } },
463 { L"<c-f5>", { K(KEY_F(29)) } },
464 { L"<c-f6>", { K(KEY_F(30)) } },
465 { L"<c-f7>", { K(KEY_F(31)) } },
466 { L"<c-f8>", { K(KEY_F(32)) } },
467 { L"<c-f9>", { K(KEY_F(33)) } },
468 { L"<c-f10>", { K(KEY_F(34)) } },
469 { L"<c-f11>", { K(KEY_F(35)) } },
470 { L"<c-f12>", { K(KEY_F(36)) } },
471 { L"<a-f1>", { K(KEY_F(37)) } },
472 { L"<a-f2>", { K(KEY_F(38)) } },
473 { L"<a-f3>", { K(KEY_F(39)) } },
474 { L"<a-f4>", { K(KEY_F(40)) } },
475 { L"<a-f5>", { K(KEY_F(41)) } },
476 { L"<a-f6>", { K(KEY_F(42)) } },
477 { L"<a-f7>", { K(KEY_F(43)) } },
478 { L"<a-f8>", { K(KEY_F(44)) } },
479 { L"<a-f9>", { K(KEY_F(45)) } },
480 { L"<a-f10>", { K(KEY_F(46)) } },
481 { L"<a-f11>", { K(KEY_F(47)) } },
482 { L"<a-f12>", { K(KEY_F(48)) } },
483 { L"<m-f1>", { K(KEY_F(37)) } },
484 { L"<m-f2>", { K(KEY_F(38)) } },
485 { L"<m-f3>", { K(KEY_F(39)) } },
486 { L"<m-f4>", { K(KEY_F(40)) } },
487 { L"<m-f5>", { K(KEY_F(41)) } },
488 { L"<m-f6>", { K(KEY_F(42)) } },
489 { L"<m-f7>", { K(KEY_F(43)) } },
490 { L"<m-f8>", { K(KEY_F(44)) } },
491 { L"<m-f9>", { K(KEY_F(45)) } },
492 { L"<m-f10>", { K(KEY_F(46)) } },
493 { L"<m-f11>", { K(KEY_F(47)) } },
494 { L"<m-f12>", { K(KEY_F(48)) } },
495 #endif
496 };
497
498 void
init_bracket_notation(void)499 init_bracket_notation(void)
500 {
501 size_t i;
502 for(i = 0; i < ARRAY_LEN(key_pairs); i++)
503 {
504 key_pairs[i].len = wcslen(key_pairs[i].notation);
505 }
506
507 safe_qsort(key_pairs, ARRAY_LEN(key_pairs), sizeof(key_pairs[0]),
508 notation_sorter);
509 }
510
511 /* Sorter function to be called by qsort. */
512 static int
notation_sorter(const void * first,const void * second)513 notation_sorter(const void *first, const void *second)
514 {
515 const key_pair_t *paira = (const key_pair_t *)first;
516 const key_pair_t *pairb = (const key_pair_t *)second;
517 const wchar_t *stra = paira->notation;
518 const wchar_t *strb = pairb->notation;
519 return wcscmp(stra, strb);
520 }
521
522 wchar_t *
substitute_specs(const char cmd[])523 substitute_specs(const char cmd[])
524 {
525 wchar_t *result;
526
527 wchar_t *const cmdw = to_wide(cmd);
528 if(cmdw == NULL)
529 {
530 return NULL;
531 }
532
533 result = substitute_specsw(cmdw);
534 free(cmdw);
535
536 return result;
537 }
538
539 wchar_t *
substitute_specsw(const wchar_t cmd[])540 substitute_specsw(const wchar_t cmd[])
541 {
542 wchar_t *buf, *p;
543 const size_t len = wcslen(cmd) + 1;
544 const wchar_t *s = cmd;
545
546 buf = reallocarray(NULL, len, sizeof(wchar_t));
547 if(buf == NULL)
548 {
549 return NULL;
550 }
551
552 p = buf;
553 while(*s != L'\0')
554 {
555 const key_pair_t *const pair = find_notation(s);
556 if(pair == NULL)
557 {
558 *p++ = *s++;
559 }
560 else
561 {
562 wcscpy(p, pair->key);
563 p += wcslen(p);
564 s += pair->len;
565 }
566 }
567 *p = L'\0';
568 assert((size_t)(p + 1 - buf) <= len && "Destination buffer was too small.");
569
570 return buf;
571 }
572
573 /* Performs binary search in the list of bracket notations. Returns NULL if
574 * str wasn't found in the list. */
575 static const key_pair_t *
find_notation(const wchar_t str[])576 find_notation(const wchar_t str[])
577 {
578 wchar_t str_lowered[wcslen(str) + 1];
579 int l = 0, u = ARRAY_LEN(key_pairs) - 1;
580
581 wcscpy(str_lowered, str);
582 wcstolower(str_lowered);
583
584 while(l <= u)
585 {
586 const int i = l + (u - l)/2;
587 const key_pair_t *const key_pair = &key_pairs[i];
588 const int comp = wcsncmp(str_lowered, key_pair->notation, key_pair->len);
589 if(comp == 0)
590 {
591 return key_pair;
592 }
593 else if(comp < 0)
594 {
595 u = i - 1;
596 }
597 else
598 {
599 l = i + 1;
600 }
601 }
602 return NULL;
603 }
604
605 char *
wstr_to_spec(const wchar_t str[])606 wstr_to_spec(const wchar_t str[])
607 {
608 vle_textbuf *const descr = vle_tb_create();
609
610 const size_t str_len = wcslen(str);
611 size_t seq_len;
612 size_t i;
613
614 for(i = 0U; i < str_len; i += seq_len)
615 {
616 if(str[i] == L' ' && i != 0U && i != str_len - 1)
617 {
618 vle_tb_append(descr, " ");
619 seq_len = 1U;
620 }
621 else
622 {
623 vle_tb_append(descr, wchar_to_spec(&str[i], &seq_len, (i == 0U)));
624 }
625 }
626
627 return vle_tb_release(descr);
628 }
629
630 /* Converts unicode character(s) starting at c into string form representing
631 * corresponding key. Upon exit *len is set to number of used characters from
632 * the string. Returns pointer to internal buffer. */
633 static const char *
wchar_to_spec(const wchar_t c[],size_t * len,int bs)634 wchar_to_spec(const wchar_t c[], size_t *len, int bs)
635 {
636 /* TODO: refactor this function wchar_to_spec() */
637
638 static char buf[256];
639
640 *len = 1;
641 switch(*c)
642 {
643 case L' ': strcpy(buf, "<space>"); break;
644 case L'\r': strcpy(buf, "<cr>"); break;
645 case L'\n': strcpy(buf, "<c-j>"); break;
646 case L'\177': strcpy(buf, "<del>"); break;
647 case K(KEY_HOME): strcpy(buf, "<home>"); break;
648 case K(KEY_END): strcpy(buf, "<end>"); break;
649 case K(KEY_UP): strcpy(buf, "<up>"); break;
650 case K(KEY_DOWN): strcpy(buf, "<down>"); break;
651 case K(KEY_LEFT): strcpy(buf, "<left>"); break;
652 case K(KEY_RIGHT): strcpy(buf, "<right>"); break;
653 case K(KEY_DC): strcpy(buf, "<delete>"); break;
654 case K(KEY_BTAB): strcpy(buf, "<s-tab>"); break;
655 case K(KEY_PPAGE): strcpy(buf, "<pageup>"); break;
656 case K(KEY_NPAGE): strcpy(buf, "<pagedown>"); break;
657 case WC_C_SPACE: strcpy(buf, "<c-@>"); break;
658
659 case L'\b':
660 if(!bs)
661 {
662 goto def;
663 }
664 /* Fall through. */
665 case K(KEY_BACKSPACE):
666 strcpy(buf, "<bs>");
667 break;
668
669 case L'\033':
670 if(c[1] == L'[' && c[2] == 'Z')
671 {
672 strcpy(buf, "<s-tab>");
673 *len += 2;
674 break;
675 }
676 if(c[1] != L'\0' && c[1] != L'\033')
677 {
678 strcpy(buf, "<m-a>");
679 buf[3] += c[1] - L'a';
680 ++*len;
681 break;
682 }
683 strcpy(buf, "<esc>");
684 break;
685
686 default:
687 def:
688 if(*c == '\n' || (*c > L' ' && *c < 256))
689 {
690 buf[0] = *c;
691 buf[1] = '\0';
692 }
693 else if(*c >= K(KEY_F0) && *c < K(KEY_F0) + 10)
694 {
695 strcpy(buf, "<f0>");
696 buf[2] += *c - K(KEY_F0);
697 }
698 else if(*c >= K(KEY_F0) + 13 && *c <= K(KEY_F0) + 21)
699 {
700 strcpy(buf, "<s-f1>");
701 buf[4] += *c - (K(KEY_F0) + 13);
702 }
703 else if(*c >= K(KEY_F0) + 22 && *c <= K(KEY_F0) + 24)
704 {
705 strcpy(buf, "<s-f10>");
706 buf[5] += *c - (K(KEY_F0) + 22);
707 }
708 else if(*c >= K(KEY_F0) + 25 && *c <= K(KEY_F0) + 33)
709 {
710 strcpy(buf, "<c-f1>");
711 buf[4] += *c - (K(KEY_F0) + 25);
712 }
713 else if(*c >= K(KEY_F0) + 34 && *c <= K(KEY_F0) + 36)
714 {
715 strcpy(buf, "<c-f10>");
716 buf[5] += *c - (K(KEY_F0) + 34);
717 }
718 else if(*c >= K(KEY_F0) + 37 && *c <= K(KEY_F0) + 45)
719 {
720 strcpy(buf, "<a-f1>");
721 buf[4] += *c - (K(KEY_F0) + 37);
722 }
723 else if(*c >= K(KEY_F0) + 46 && *c <= K(KEY_F0) + 48)
724 {
725 strcpy(buf, "<a-f10>");
726 buf[5] += *c - (K(KEY_F0) + 46);
727 }
728 else if(*c >= K(KEY_F0) + 10 && *c < K(KEY_F0) + 63)
729 {
730 strcpy(buf, "<f00>");
731 buf[2] += (*c - K(KEY_F0))/10;
732 buf[3] += (*c - K(KEY_F0))%10;
733 }
734 else if(iswcntrl(*c))
735 {
736 strcpy(buf, "<c-A>");
737 buf[3] = tolower(buf[3] + *c - 1);
738 }
739 else
740 {
741 const wchar_t wchar[] = { *c, L'\0' };
742 char *const mb = to_multibyte(wchar);
743 copy_str(buf, sizeof(buf), mb);
744 free(mb);
745 }
746 break;
747 }
748 return buf;
749 }
750
751 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
752 /* vim: set cinoptions+=t0 filetype=c : */
753