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