File: | src/usr.bin/vi/build/../common/key.c |
Warning: | line 349, column 3 Null pointer passed as 1st argument to memory copy function |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: key.c,v 1.20 2022/04/21 17:50:29 millert Exp $ */ | |||
2 | ||||
3 | /*- | |||
4 | * Copyright (c) 1991, 1993, 1994 | |||
5 | * The Regents of the University of California. All rights reserved. | |||
6 | * Copyright (c) 1991, 1993, 1994, 1995, 1996 | |||
7 | * Keith Bostic. All rights reserved. | |||
8 | * | |||
9 | * See the LICENSE file for redistribution information. | |||
10 | */ | |||
11 | ||||
12 | #include "config.h" | |||
13 | ||||
14 | #include <sys/queue.h> | |||
15 | #include <sys/time.h> | |||
16 | ||||
17 | #include <bitstring.h> | |||
18 | #include <ctype.h> | |||
19 | #include <errno(*__errno()).h> | |||
20 | #include <limits.h> | |||
21 | #include <locale.h> | |||
22 | #include <stdio.h> | |||
23 | #include <stdlib.h> | |||
24 | #include <string.h> | |||
25 | #include <unistd.h> | |||
26 | ||||
27 | #include "common.h" | |||
28 | #include "../vi/vi.h" | |||
29 | ||||
30 | #define MAXIMUM(a, b)(((a) > (b)) ? (a) : (b)) (((a) > (b)) ? (a) : (b)) | |||
31 | ||||
32 | static int v_event_append(SCR *, EVENT *); | |||
33 | static int v_event_grow(SCR *, int); | |||
34 | static int v_key_cmp(const void *, const void *); | |||
35 | static void v_keyval(SCR *, int, scr_keyval_t); | |||
36 | static void v_sync(SCR *, int); | |||
37 | ||||
38 | /* | |||
39 | * !!! | |||
40 | * Historic vi always used: | |||
41 | * | |||
42 | * ^D: autoindent deletion | |||
43 | * ^H: last character deletion | |||
44 | * ^W: last word deletion | |||
45 | * ^Q: quote the next character (if not used in flow control). | |||
46 | * ^V: quote the next character | |||
47 | * | |||
48 | * regardless of the user's choices for these characters. The user's erase | |||
49 | * and kill characters worked in addition to these characters. Nvi wires | |||
50 | * down the above characters, but in addition permits the VEOF, VERASE, VKILL | |||
51 | * and VWERASE characters described by the user's termios structure. | |||
52 | * | |||
53 | * Ex was not consistent with this scheme, as it historically ran in tty | |||
54 | * cooked mode. This meant that the scroll command and autoindent erase | |||
55 | * characters were mapped to the user's EOF character, and the character | |||
56 | * and word deletion characters were the user's tty character and word | |||
57 | * deletion characters. This implementation makes it all consistent, as | |||
58 | * described above for vi. | |||
59 | * | |||
60 | * !!! | |||
61 | * This means that all screens share a special key set. | |||
62 | */ | |||
63 | KEYLIST keylist[] = { | |||
64 | {K_BACKSLASH, '\\'}, /* \ */ | |||
65 | {K_CARAT, '^'}, /* ^ */ | |||
66 | {K_CNTRLD, '\004'}, /* ^D */ | |||
67 | {K_CNTRLR, '\022'}, /* ^R */ | |||
68 | {K_CNTRLT, '\024'}, /* ^T */ | |||
69 | {K_CNTRLZ, '\032'}, /* ^Z */ | |||
70 | {K_COLON, ':'}, /* : */ | |||
71 | {K_CR, '\r'}, /* \r */ | |||
72 | {K_ESCAPE, '\033'}, /* ^[ */ | |||
73 | {K_FORMFEED, '\f'}, /* \f */ | |||
74 | {K_HEXCHAR, '\030'}, /* ^X */ | |||
75 | {K_NL, '\n'}, /* \n */ | |||
76 | {K_RIGHTBRACE, '}'}, /* } */ | |||
77 | {K_RIGHTPAREN, ')'}, /* ) */ | |||
78 | {K_TAB, '\t'}, /* \t */ | |||
79 | {K_VERASE, '\b'}, /* \b */ | |||
80 | {K_VKILL, '\025'}, /* ^U */ | |||
81 | {K_VLNEXT, '\021'}, /* ^Q */ | |||
82 | {K_VLNEXT, '\026'}, /* ^V */ | |||
83 | {K_VWERASE, '\027'}, /* ^W */ | |||
84 | {K_ZERO, '0'}, /* 0 */ | |||
85 | ||||
86 | #define ADDITIONAL_CHARACTERS4 4 | |||
87 | {K_NOTUSED, 0}, /* VEOF, VERASE, VKILL, VWERASE */ | |||
88 | {K_NOTUSED, 0}, | |||
89 | {K_NOTUSED, 0}, | |||
90 | {K_NOTUSED, 0}, | |||
91 | }; | |||
92 | static int nkeylist = | |||
93 | (sizeof(keylist) / sizeof(keylist[0])) - ADDITIONAL_CHARACTERS4; | |||
94 | ||||
95 | /* | |||
96 | * v_key_init -- | |||
97 | * Initialize the special key lookup table. | |||
98 | * | |||
99 | * PUBLIC: int v_key_init(SCR *); | |||
100 | */ | |||
101 | int | |||
102 | v_key_init(SCR *sp) | |||
103 | { | |||
104 | u_int ch; | |||
105 | GS *gp; | |||
106 | KEYLIST *kp; | |||
107 | int cnt; | |||
108 | ||||
109 | gp = sp->gp; | |||
110 | ||||
111 | /* | |||
112 | * XXX | |||
113 | * 8-bit only, for now. Recompilation should get you any 8-bit | |||
114 | * character set, as long as nul isn't a character. | |||
115 | */ | |||
116 | (void)setlocale(LC_ALL0, ""); | |||
117 | v_key_ilookup(sp); | |||
118 | ||||
119 | v_keyval(sp, K_CNTRLD, KEY_VEOF); | |||
120 | v_keyval(sp, K_VERASE, KEY_VERASE); | |||
121 | v_keyval(sp, K_VKILL, KEY_VKILL); | |||
122 | v_keyval(sp, K_VWERASE, KEY_VWERASE); | |||
123 | ||||
124 | /* Sort the special key list. */ | |||
125 | qsort(keylist, nkeylist, sizeof(keylist[0]), v_key_cmp); | |||
126 | ||||
127 | /* Initialize the fast lookup table. */ | |||
128 | for (gp->max_special = 0, kp = keylist, cnt = nkeylist; cnt--; ++kp) { | |||
129 | if (gp->max_special < kp->value) | |||
130 | gp->max_special = kp->value; | |||
131 | if (kp->ch <= MAX_FAST_KEY254) | |||
132 | gp->special_key[kp->ch] = kp->value; | |||
133 | } | |||
134 | ||||
135 | /* Find a non-printable character to use as a message separator. */ | |||
136 | for (ch = 1; ch <= MAX_CHAR_T0xff; ++ch) | |||
137 | if (!isprint(ch)) { | |||
138 | gp->noprint = ch; | |||
139 | break; | |||
140 | } | |||
141 | if (ch != gp->noprint) { | |||
142 | msgq(sp, M_ERR, "No non-printable character found"); | |||
143 | return (1); | |||
144 | } | |||
145 | return (0); | |||
146 | } | |||
147 | ||||
148 | /* | |||
149 | * v_keyval -- | |||
150 | * Set key values. | |||
151 | * | |||
152 | * We've left some open slots in the keylist table, and if these values exist, | |||
153 | * we put them into place. Note, they may reset (or duplicate) values already | |||
154 | * in the table, so we check for that first. | |||
155 | */ | |||
156 | static void | |||
157 | v_keyval(SCR *sp, int val, scr_keyval_t name) | |||
158 | { | |||
159 | KEYLIST *kp; | |||
160 | CHAR_T ch; | |||
161 | int dne; | |||
162 | ||||
163 | /* Get the key's value from the screen. */ | |||
164 | if (sp->gp->scr_keyval(sp, name, &ch, &dne)) | |||
165 | return; | |||
166 | if (dne) | |||
167 | return; | |||
168 | ||||
169 | /* Check for duplication. */ | |||
170 | for (kp = keylist; kp->value != K_NOTUSED; ++kp) | |||
171 | if (kp->ch == ch) { | |||
172 | kp->value = val; | |||
173 | return; | |||
174 | } | |||
175 | ||||
176 | /* Add a new entry. */ | |||
177 | if (kp->value == K_NOTUSED) { | |||
178 | keylist[nkeylist].ch = ch; | |||
179 | keylist[nkeylist].value = val; | |||
180 | ++nkeylist; | |||
181 | } | |||
182 | } | |||
183 | ||||
184 | /* | |||
185 | * v_key_ilookup -- | |||
186 | * Build the fast-lookup key display array. | |||
187 | * | |||
188 | * PUBLIC: void v_key_ilookup(SCR *); | |||
189 | */ | |||
190 | void | |||
191 | v_key_ilookup(SCR *sp) | |||
192 | { | |||
193 | CHAR_T ch, *p, *t; | |||
194 | GS *gp; | |||
195 | size_t len; | |||
196 | ||||
197 | for (gp = sp->gp, ch = 0; ch <= MAX_FAST_KEY254; ++ch) | |||
198 | for (p = gp->cname[ch].name, t = v_key_name(sp, ch), | |||
199 | len = gp->cname[ch].len = sp->clen; len--;) | |||
200 | *p++ = *t++; | |||
201 | } | |||
202 | ||||
203 | /* | |||
204 | * v_key_len -- | |||
205 | * Return the length of the string that will display the key. | |||
206 | * This routine is the backup for the KEY_LEN() macro. | |||
207 | * | |||
208 | * PUBLIC: size_t v_key_len(SCR *, CHAR_T); | |||
209 | */ | |||
210 | size_t | |||
211 | v_key_len(SCR *sp, CHAR_T ch) | |||
212 | { | |||
213 | (void)v_key_name(sp, ch); | |||
214 | return (sp->clen); | |||
215 | } | |||
216 | ||||
217 | /* | |||
218 | * v_key_name -- | |||
219 | * Return the string that will display the key. This routine | |||
220 | * is the backup for the KEY_NAME() macro. | |||
221 | * | |||
222 | * PUBLIC: CHAR_T *v_key_name(SCR *, CHAR_T); | |||
223 | */ | |||
224 | CHAR_T * | |||
225 | v_key_name(SCR *sp, CHAR_T ch) | |||
226 | { | |||
227 | static const CHAR_T hexdigit[] = "0123456789abcdef"; | |||
228 | static const CHAR_T octdigit[] = "01234567"; | |||
229 | CHAR_T *chp, mask; | |||
230 | size_t len; | |||
231 | int cnt, shift; | |||
232 | ||||
233 | /* See if the character was explicitly declared printable or not. */ | |||
234 | if ((chp = O_STR(sp, O_PRINT)((((&((sp))->opts[((O_PRINT))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_PRINT))].o_cur .val].o_cur.str : ((sp))->opts[((O_PRINT))].o_cur.str)) != NULL((void *)0)) | |||
235 | for (; *chp != '\0'; ++chp) | |||
236 | if (*chp == ch) | |||
237 | goto pr; | |||
238 | if ((chp = O_STR(sp, O_NOPRINT)((((&((sp))->opts[((O_NOPRINT))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_NOPRINT))].o_cur .val].o_cur.str : ((sp))->opts[((O_NOPRINT))].o_cur.str)) != NULL((void *)0)) | |||
239 | for (; *chp != '\0'; ++chp) | |||
240 | if (*chp == ch) | |||
241 | goto nopr; | |||
242 | ||||
243 | /* | |||
244 | * Historical (ARPA standard) mappings. Printable characters are left | |||
245 | * alone. Control characters less than 0x20 are represented as '^' | |||
246 | * followed by the character offset from the '@' character in the ASCII | |||
247 | * character set. Del (0x7f) is represented as '^' followed by '?'. | |||
248 | * | |||
249 | * XXX | |||
250 | * The following code depends on the current locale being identical to | |||
251 | * the ASCII map from 0x40 to 0x5f (since 0x1f + 0x40 == 0x5f). I'm | |||
252 | * told that this is a reasonable assumption... | |||
253 | * | |||
254 | * XXX | |||
255 | * This code will only work with CHAR_T's that are multiples of 8-bit | |||
256 | * bytes. | |||
257 | * | |||
258 | * XXX | |||
259 | * NB: There's an assumption here that all printable characters take | |||
260 | * up a single column on the screen. This is not always correct. | |||
261 | */ | |||
262 | if (isprint(ch)) { | |||
263 | pr: sp->cname[0] = ch; | |||
264 | len = 1; | |||
265 | goto done; | |||
266 | } | |||
267 | nopr: if (iscntrl(ch) && (ch < 0x20 || ch == 0x7f)) { | |||
268 | sp->cname[0] = '^'; | |||
269 | sp->cname[1] = ch == 0x7f ? '?' : '@' + ch; | |||
270 | len = 2; | |||
271 | } else if (O_ISSET(sp, O_OCTAL)((((&(((sp)))->opts[(((O_OCTAL)))])->flags) & ( (0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_OCTAL )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_OCTAL)))]. o_cur.val)) { | |||
272 | #define BITS(sizeof(CHAR_T) * 8) (sizeof(CHAR_T) * 8) | |||
273 | #define SHIFT((sizeof(CHAR_T) * 8) - (sizeof(CHAR_T) * 8) % 3) (BITS(sizeof(CHAR_T) * 8) - BITS(sizeof(CHAR_T) * 8) % 3) | |||
274 | #define TOPMASK((sizeof(CHAR_T) * 8) % 3 == 2 ? 3 : 1) << ((sizeof(CHAR_T ) * 8) - (sizeof(CHAR_T) * 8) % 3) (BITS(sizeof(CHAR_T) * 8) % 3 == 2 ? 3 : 1) << (BITS(sizeof(CHAR_T) * 8) - BITS(sizeof(CHAR_T) * 8) % 3) | |||
275 | sp->cname[0] = '\\'; | |||
276 | sp->cname[1] = octdigit[(ch & TOPMASK((sizeof(CHAR_T) * 8) % 3 == 2 ? 3 : 1) << ((sizeof(CHAR_T ) * 8) - (sizeof(CHAR_T) * 8) % 3)) >> SHIFT((sizeof(CHAR_T) * 8) - (sizeof(CHAR_T) * 8) % 3)]; | |||
277 | shift = SHIFT((sizeof(CHAR_T) * 8) - (sizeof(CHAR_T) * 8) % 3) - 3; | |||
278 | for (len = 2, mask = 7 << (SHIFT((sizeof(CHAR_T) * 8) - (sizeof(CHAR_T) * 8) % 3) - 3), | |||
279 | cnt = BITS(sizeof(CHAR_T) * 8) / 3; cnt-- > 0; mask >>= 3, shift -= 3) | |||
280 | sp->cname[len++] = octdigit[(ch & mask) >> shift]; | |||
281 | } else { | |||
282 | sp->cname[0] = '\\'; | |||
283 | sp->cname[1] = 'x'; | |||
284 | for (len = 2, chp = (u_int8_t *)&ch, | |||
285 | cnt = sizeof(CHAR_T); cnt-- > 0; ++chp) { | |||
286 | sp->cname[len++] = hexdigit[(*chp & 0xf0) >> 4]; | |||
287 | sp->cname[len++] = hexdigit[*chp & 0x0f]; | |||
288 | } | |||
289 | } | |||
290 | done: sp->cname[sp->clen = len] = '\0'; | |||
291 | return (sp->cname); | |||
292 | } | |||
293 | ||||
294 | /* | |||
295 | * v_key_val -- | |||
296 | * Fill in the value for a key. This routine is the backup | |||
297 | * for the KEY_VAL() macro. | |||
298 | * | |||
299 | * PUBLIC: int v_key_val(SCR *, CHAR_T); | |||
300 | */ | |||
301 | int | |||
302 | v_key_val(SCR *sp, CHAR_T ch) | |||
303 | { | |||
304 | KEYLIST k, *kp; | |||
305 | ||||
306 | k.ch = ch; | |||
307 | kp = bsearch(&k, keylist, nkeylist, sizeof(keylist[0]), v_key_cmp); | |||
308 | return (kp == NULL((void *)0) ? K_NOTUSED : kp->value); | |||
309 | } | |||
310 | ||||
311 | /* | |||
312 | * v_event_push -- | |||
313 | * Push events/keys onto the front of the buffer. | |||
314 | * | |||
315 | * There is a single input buffer in ex/vi. Characters are put onto the | |||
316 | * end of the buffer by the terminal input routines, and pushed onto the | |||
317 | * front of the buffer by various other functions in ex/vi. Each key has | |||
318 | * an associated flag value, which indicates if it has already been quoted, | |||
319 | * and if it is the result of a mapping or an abbreviation. | |||
320 | * | |||
321 | * PUBLIC: int v_event_push(SCR *, EVENT *, CHAR_T *, size_t, u_int); | |||
322 | */ | |||
323 | int | |||
324 | v_event_push(SCR *sp, EVENT *p_evp, CHAR_T *p_s, size_t nitems, u_int flags) | |||
325 | { | |||
326 | EVENT *evp; | |||
327 | GS *gp; | |||
328 | size_t total; | |||
329 | ||||
330 | /* If we have room, stuff the items into the buffer. */ | |||
331 | gp = sp->gp; | |||
332 | if (nitems <= gp->i_next || | |||
333 | (gp->i_event != NULL((void *)0) && gp->i_cnt == 0 && nitems <= gp->i_nelem)) { | |||
334 | if (gp->i_cnt != 0) | |||
335 | gp->i_next -= nitems; | |||
336 | goto copy; | |||
337 | } | |||
338 | ||||
339 | /* | |||
340 | * If there are currently items in the queue, shift them up, | |||
341 | * leaving some extra room. Get enough space plus a little | |||
342 | * extra. | |||
343 | */ | |||
344 | #define TERM_PUSH_SHIFT30 30 | |||
345 | total = gp->i_cnt + gp->i_next + nitems + TERM_PUSH_SHIFT30; | |||
346 | if (total >= gp->i_nelem && v_event_grow(sp, MAXIMUM(total, 64)(((total) > (64)) ? (total) : (64)))) | |||
347 | return (1); | |||
348 | if (gp->i_cnt) | |||
349 | MEMMOVE(gp->i_event + TERM_PUSH_SHIFT + nitems,memmove((gp->i_event + 30 + nitems), (gp->i_event + gp-> i_next), (gp->i_cnt) * sizeof(*(gp->i_event + 30 + nitems ))) | |||
| ||||
350 | gp->i_event + gp->i_next, gp->i_cnt)memmove((gp->i_event + 30 + nitems), (gp->i_event + gp-> i_next), (gp->i_cnt) * sizeof(*(gp->i_event + 30 + nitems ))); | |||
351 | gp->i_next = TERM_PUSH_SHIFT30; | |||
352 | ||||
353 | /* Put the new items into the queue. */ | |||
354 | copy: gp->i_cnt += nitems; | |||
355 | for (evp = gp->i_event + gp->i_next; nitems--; ++evp) { | |||
356 | if (p_evp != NULL((void *)0)) | |||
357 | *evp = *p_evp++; | |||
358 | else { | |||
359 | evp->e_event = E_CHARACTER; | |||
360 | evp->e_c_u_event._e_ch.c = *p_s++; | |||
361 | evp->e_value_u_event._e_ch.value = KEY_VAL(sp, evp->e_c)((unsigned char)(evp->_u_event._e_ch.c) <= 254 ? (sp)-> gp->special_key[(unsigned char)(evp->_u_event._e_ch.c)] : (unsigned char)(evp->_u_event._e_ch.c) > (sp)->gp ->max_special ? 0 : v_key_val((sp),(evp->_u_event._e_ch .c))); | |||
362 | F_INIT(&evp->e_ch, flags)((&evp->_u_event._e_ch)->flags) = ((flags)); | |||
363 | } | |||
364 | } | |||
365 | return (0); | |||
366 | } | |||
367 | ||||
368 | /* | |||
369 | * v_event_append -- | |||
370 | * Append events onto the tail of the buffer. | |||
371 | */ | |||
372 | static int | |||
373 | v_event_append(SCR *sp, EVENT *argp) | |||
374 | { | |||
375 | CHAR_T *s; /* Characters. */ | |||
376 | EVENT *evp; | |||
377 | GS *gp; | |||
378 | size_t nevents; /* Number of events. */ | |||
379 | ||||
380 | /* Grow the buffer as necessary. */ | |||
381 | nevents = argp->e_event == E_STRING ? argp->e_len_u_event._e_str.len : 1; | |||
382 | gp = sp->gp; | |||
383 | if (gp->i_event == NULL((void *)0) || | |||
384 | nevents > gp->i_nelem - (gp->i_next + gp->i_cnt)) | |||
385 | v_event_grow(sp, MAXIMUM(nevents, 64)(((nevents) > (64)) ? (nevents) : (64))); | |||
386 | evp = gp->i_event + gp->i_next + gp->i_cnt; | |||
387 | gp->i_cnt += nevents; | |||
388 | ||||
389 | /* Transform strings of characters into single events. */ | |||
390 | if (argp->e_event == E_STRING) | |||
391 | for (s = argp->e_csp_u_event._e_str.csp; nevents--; ++evp) { | |||
392 | evp->e_event = E_CHARACTER; | |||
393 | evp->e_c_u_event._e_ch.c = *s++; | |||
394 | evp->e_value_u_event._e_ch.value = KEY_VAL(sp, evp->e_c)((unsigned char)(evp->_u_event._e_ch.c) <= 254 ? (sp)-> gp->special_key[(unsigned char)(evp->_u_event._e_ch.c)] : (unsigned char)(evp->_u_event._e_ch.c) > (sp)->gp ->max_special ? 0 : v_key_val((sp),(evp->_u_event._e_ch .c))); | |||
395 | evp->e_flags_u_event._e_ch.flags = 0; | |||
396 | } | |||
397 | else | |||
398 | *evp = *argp; | |||
399 | return (0); | |||
400 | } | |||
401 | ||||
402 | /* Remove events from the queue. */ | |||
403 | #define QREM(len){ if ((gp->i_cnt -= (len)) == 0) gp->i_next = 0; else gp ->i_next += (len); } { \ | |||
404 | if ((gp->i_cnt -= (len)) == 0) \ | |||
405 | gp->i_next = 0; \ | |||
406 | else \ | |||
407 | gp->i_next += (len); \ | |||
408 | } | |||
409 | ||||
410 | /* | |||
411 | * v_event_get -- | |||
412 | * Return the next event. | |||
413 | * | |||
414 | * !!! | |||
415 | * The flag EC_NODIGIT probably needs some explanation. First, the idea of | |||
416 | * mapping keys is that one or more keystrokes act like a function key. | |||
417 | * What's going on is that vi is reading a number, and the character following | |||
418 | * the number may or may not be mapped (EC_MAPCOMMAND). For example, if the | |||
419 | * user is entering the z command, a valid command is "z40+", and we don't want | |||
420 | * to map the '+', i.e. if '+' is mapped to "xxx", we don't want to change it | |||
421 | * into "z40xxx". However, if the user enters "35x", we want to put all of the | |||
422 | * characters through the mapping code. | |||
423 | * | |||
424 | * Historical practice is a bit muddled here. (Surprise!) It always permitted | |||
425 | * mapping digits as long as they weren't the first character of the map, e.g. | |||
426 | * ":map ^A1 xxx" was okay. It also permitted the mapping of the digits 1-9 | |||
427 | * (the digit 0 was a special case as it doesn't indicate the start of a count) | |||
428 | * as the first character of the map, but then ignored those mappings. While | |||
429 | * it's probably stupid to map digits, vi isn't your mother. | |||
430 | * | |||
431 | * The way this works is that the EC_MAPNODIGIT causes term_key to return the | |||
432 | * end-of-digit without "looking" at the next character, i.e. leaving it as the | |||
433 | * user entered it. Presumably, the next term_key call will tell us how the | |||
434 | * user wants it handled. | |||
435 | * | |||
436 | * There is one more complication. Users might map keys to digits, and, as | |||
437 | * it's described above, the commands: | |||
438 | * | |||
439 | * :map g 1G | |||
440 | * d2g | |||
441 | * | |||
442 | * would return the keys "d2<end-of-digits>1G", when the user probably wanted | |||
443 | * "d21<end-of-digits>G". So, if a map starts off with a digit we continue as | |||
444 | * before, otherwise, we pretend we haven't mapped the character, and return | |||
445 | * <end-of-digits>. | |||
446 | * | |||
447 | * Now that that's out of the way, let's talk about Energizer Bunny macros. | |||
448 | * It's easy to create macros that expand to a loop, e.g. map x 3x. It's | |||
449 | * fairly easy to detect this example, because it's all internal to term_key. | |||
450 | * If we're expanding a macro and it gets big enough, at some point we can | |||
451 | * assume it's looping and kill it. The examples that are tough are the ones | |||
452 | * where the parser is involved, e.g. map x "ayyx"byy. We do an expansion | |||
453 | * on 'x', and get "ayyx"byy. We then return the first 4 characters, and then | |||
454 | * find the looping macro again. There is no way that we can detect this | |||
455 | * without doing a full parse of the command, because the character that might | |||
456 | * cause the loop (in this case 'x') may be a literal character, e.g. the map | |||
457 | * map x "ayy"xyy"byy is perfectly legal and won't cause a loop. | |||
458 | * | |||
459 | * Historic vi tried to detect looping macros by disallowing obvious cases in | |||
460 | * the map command, maps that that ended with the same letter as they started | |||
461 | * (which wrongly disallowed "map x 'x"), and detecting macros that expanded | |||
462 | * too many times before keys were returned to the command parser. It didn't | |||
463 | * get many (most?) of the tricky cases right, however, and it was certainly | |||
464 | * possible to create macros that ran forever. And, even if it did figure out | |||
465 | * what was going on, the user was usually tossed into ex mode. Finally, any | |||
466 | * changes made before vi realized that the macro was recursing were left in | |||
467 | * place. We recover gracefully, but the only recourse the user has in an | |||
468 | * infinite macro loop is to interrupt. | |||
469 | * | |||
470 | * !!! | |||
471 | * It is historic practice that mapping characters to themselves as the first | |||
472 | * part of the mapped string was legal, and did not cause infinite loops, i.e. | |||
473 | * ":map! { {^M^T" and ":map n nz." were known to work. The initial, matching | |||
474 | * characters were returned instead of being remapped. | |||
475 | * | |||
476 | * !!! | |||
477 | * It is also historic practice that the macro "map ] ]]^" caused a single ] | |||
478 | * keypress to behave as the command ]] (the ^ got the map past the vi check | |||
479 | * for "tail recursion"). Conversely, the mapping "map n nn^" went recursive. | |||
480 | * What happened was that, in the historic vi, maps were expanded as the keys | |||
481 | * were retrieved, but not all at once and not centrally. So, the keypress ] | |||
482 | * pushed ]]^ on the stack, and then the first ] from the stack was passed to | |||
483 | * the ]] command code. The ]] command then retrieved a key without entering | |||
484 | * the mapping code. This could bite us anytime a user has a map that depends | |||
485 | * on secondary keys NOT being mapped. I can't see any possible way to make | |||
486 | * this work in here without the complete abandonment of Rationality Itself. | |||
487 | * | |||
488 | * XXX | |||
489 | * The final issue is recovery. It would be possible to undo all of the work | |||
490 | * that was done by the macro if we entered a record into the log so that we | |||
491 | * knew when the macro started, and, in fact, this might be worth doing at some | |||
492 | * point. Given that this might make the log grow unacceptably (consider that | |||
493 | * cursor keys are done with maps), for now we leave any changes made in place. | |||
494 | * | |||
495 | * PUBLIC: int v_event_get(SCR *, EVENT *, int, u_int32_t); | |||
496 | */ | |||
497 | int | |||
498 | v_event_get(SCR *sp, EVENT *argp, int timeout, u_int32_t flags) | |||
499 | { | |||
500 | EVENT *evp, ev; | |||
501 | GS *gp; | |||
502 | SEQ *qp; | |||
503 | int init_nomap, ispartial, istimeout, remap_cnt; | |||
504 | ||||
505 | gp = sp->gp; | |||
506 | ||||
507 | /* If simply checking for interrupts, argp may be NULL. */ | |||
508 | if (argp == NULL((void *)0)) | |||
| ||||
509 | argp = &ev; | |||
510 | ||||
511 | retry: istimeout = remap_cnt = 0; | |||
512 | ||||
513 | /* | |||
514 | * If the queue isn't empty and we're timing out for characters, | |||
515 | * return immediately. | |||
516 | */ | |||
517 | if (gp->i_cnt != 0 && LF_ISSET(EC_TIMEOUT)((flags) & ((0x040)))) | |||
518 | return (0); | |||
519 | ||||
520 | /* | |||
521 | * If the queue is empty, we're checking for interrupts, or we're | |||
522 | * timing out for characters, get more events. | |||
523 | */ | |||
524 | if (gp->i_cnt
| |||
525 | /* | |||
526 | * If we're reading new characters, check any scripting | |||
527 | * windows for input. | |||
528 | */ | |||
529 | if (F_ISSET(gp, G_SCRWIN)(((gp)->flags) & ((0x0020))) && sscr_input(sp)) | |||
530 | return (1); | |||
531 | loop: if (gp->scr_event(sp, argp, | |||
532 | LF_ISSET(EC_INTERRUPT | EC_QUOTED | EC_RAW)((flags) & ((0x001 | 0x010 | 0x020))), timeout)) | |||
533 | return (1); | |||
534 | switch (argp->e_event) { | |||
535 | case E_ERR: | |||
536 | case E_SIGHUP: | |||
537 | case E_SIGTERM: | |||
538 | /* | |||
539 | * Fatal conditions cause the file to be synced to | |||
540 | * disk immediately. | |||
541 | */ | |||
542 | v_sync(sp, RCV_ENDSESSION0x02 | RCV_PRESERVE0x04 | | |||
543 | (argp->e_event == E_SIGTERM ? 0: RCV_EMAIL0x01)); | |||
544 | return (1); | |||
545 | case E_TIMEOUT: | |||
546 | istimeout = 1; | |||
547 | break; | |||
548 | case E_INTERRUPT: | |||
549 | /* Set the global interrupt flag. */ | |||
550 | F_SET(sp->gp, G_INTERRUPTED)(((sp->gp)->flags) |= ((0x0004))); | |||
551 | ||||
552 | /* | |||
553 | * If the caller was interested in interrupts, return | |||
554 | * immediately. | |||
555 | */ | |||
556 | if (LF_ISSET(EC_INTERRUPT)((flags) & ((0x001)))) | |||
557 | return (0); | |||
558 | goto append; | |||
559 | default: | |||
560 | append: if (v_event_append(sp, argp)) | |||
561 | return (1); | |||
562 | break; | |||
563 | } | |||
564 | } | |||
565 | ||||
566 | /* | |||
567 | * If the caller was only interested in interrupts or timeouts, return | |||
568 | * immediately. (We may have gotten characters, and that's okay, they | |||
569 | * were queued up for later use.) | |||
570 | */ | |||
571 | if (LF_ISSET(EC_INTERRUPT | EC_TIMEOUT)((flags) & ((0x001 | 0x040)))) | |||
572 | return (0); | |||
573 | ||||
574 | newmap: evp = &gp->i_event[gp->i_next]; | |||
575 | ||||
576 | /* | |||
577 | * If the next event in the queue isn't a character event, return | |||
578 | * it, we're done. | |||
579 | */ | |||
580 | if (evp->e_event != E_CHARACTER) { | |||
581 | *argp = *evp; | |||
582 | QREM(1){ if ((gp->i_cnt -= (1)) == 0) gp->i_next = 0; else gp-> i_next += (1); }; | |||
583 | return (0); | |||
584 | } | |||
585 | ||||
586 | /* | |||
587 | * If the key isn't mappable because: | |||
588 | * | |||
589 | * + ... the timeout has expired | |||
590 | * + ... it's not a mappable key | |||
591 | * + ... neither the command or input map flags are set | |||
592 | * + ... there are no maps that can apply to it | |||
593 | * | |||
594 | * return it forthwith. | |||
595 | */ | |||
596 | if (istimeout
| |||
597 | !LF_ISSET(EC_MAPCOMMAND | EC_MAPINPUT)((flags) & ((0x002 | 0x004))) || | |||
598 | (evp->e_c_u_event._e_ch.c < MAX_BIT_SEQ128 && !bit_test(gp->seqb, evp->e_c)((gp->seqb)[((evp->_u_event._e_ch.c) >> 3)] & (1 << ((evp->_u_event._e_ch.c)&0x7))))) | |||
599 | goto nomap; | |||
600 | ||||
601 | /* Search the map. */ | |||
602 | qp = seq_find(sp, NULL((void *)0), evp, NULL((void *)0), gp->i_cnt, | |||
603 | LF_ISSET(EC_MAPCOMMAND)((flags) & ((0x002))) ? SEQ_COMMAND : SEQ_INPUT, &ispartial); | |||
604 | ||||
605 | /* | |||
606 | * If get a partial match, get more characters and retry the map. | |||
607 | * If time out without further characters, return the characters | |||
608 | * unmapped. | |||
609 | * | |||
610 | * !!! | |||
611 | * <escape> characters are a problem. Cursor keys start with <escape> | |||
612 | * characters, so there's almost always a map in place that begins with | |||
613 | * an <escape> character. If we timeout <escape> keys in the same way | |||
614 | * that we timeout other keys, the user will get a noticeable pause as | |||
615 | * they enter <escape> to terminate input mode. If key timeout is set | |||
616 | * for a slow link, users will get an even longer pause. Nvi used to | |||
617 | * simply timeout <escape> characters at 1/10th of a second, but this | |||
618 | * loses over PPP links where the latency is greater than 100Ms. | |||
619 | */ | |||
620 | if (ispartial) { | |||
621 | if (O_ISSET(sp, O_TIMEOUT)((((&(((sp)))->opts[(((O_TIMEOUT)))])->flags) & ((0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_TIMEOUT )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_TIMEOUT))) ].o_cur.val)) | |||
622 | timeout = (evp->e_value_u_event._e_ch.value == K_ESCAPE ? | |||
623 | O_VAL(sp, O_ESCAPETIME)((((&((sp))->opts[((O_ESCAPETIME))])->flags) & ( (0x01))) ? ((sp))->gp->opts[((sp))->opts[((O_ESCAPETIME ))].o_cur.val].o_cur.val : ((sp))->opts[((O_ESCAPETIME))]. o_cur.val) : | |||
624 | O_VAL(sp, O_KEYTIME)((((&((sp))->opts[((O_KEYTIME))])->flags) & ((0x01 ))) ? ((sp))->gp->opts[((sp))->opts[((O_KEYTIME))].o_cur .val].o_cur.val : ((sp))->opts[((O_KEYTIME))].o_cur.val)) * 100; | |||
625 | else | |||
626 | timeout = 0; | |||
627 | goto loop; | |||
628 | } | |||
629 | ||||
630 | /* If no map, return the character. */ | |||
631 | if (qp == NULL((void *)0)) { | |||
632 | nomap: if (!isdigit(evp->e_c_u_event._e_ch.c) && LF_ISSET(EC_MAPNODIGIT)((flags) & ((0x008)))) | |||
633 | goto not_digit; | |||
634 | *argp = *evp; | |||
635 | QREM(1){ if ((gp->i_cnt -= (1)) == 0) gp->i_next = 0; else gp-> i_next += (1); }; | |||
636 | return (0); | |||
637 | } | |||
638 | ||||
639 | /* | |||
640 | * If looking for the end of a digit string, and the first character | |||
641 | * of the map is it, pretend we haven't seen the character. | |||
642 | */ | |||
643 | if (LF_ISSET(EC_MAPNODIGIT)((flags) & ((0x008))) && | |||
644 | qp->output != NULL((void *)0) && !isdigit(qp->output[0])) { | |||
645 | not_digit: argp->e_c_u_event._e_ch.c = CH_NOT_DIGIT'a'; | |||
646 | argp->e_value_u_event._e_ch.value = K_NOTUSED; | |||
647 | argp->e_event = E_CHARACTER; | |||
648 | F_INIT(&argp->e_ch, 0)((&argp->_u_event._e_ch)->flags) = ((0)); | |||
649 | return (0); | |||
650 | } | |||
651 | ||||
652 | /* Find out if the initial segments are identical. */ | |||
653 | if (qp->output != NULL((void *)0)) { | |||
654 | init_nomap = | |||
655 | !e_memcmp(qp->output, &gp->i_event[gp->i_next], qp->ilen); | |||
656 | } | |||
657 | ||||
658 | /* Delete the mapped characters from the queue. */ | |||
659 | QREM(qp->ilen){ if ((gp->i_cnt -= (qp->ilen)) == 0) gp->i_next = 0 ; else gp->i_next += (qp->ilen); }; | |||
660 | ||||
661 | /* If keys mapped to nothing, go get more. */ | |||
662 | if (qp->output
| |||
663 | goto retry; | |||
664 | ||||
665 | /* If remapping characters... */ | |||
666 | if (O_ISSET(sp, O_REMAP)((((&(((sp)))->opts[(((O_REMAP)))])->flags) & ( (0x01))) ? (((sp)))->gp->opts[(((sp)))->opts[(((O_REMAP )))].o_cur.val].o_cur.val : (((sp)))->opts[(((O_REMAP)))]. o_cur.val)) { | |||
667 | /* | |||
668 | * Periodically check for interrupts. Always check the first | |||
669 | * time through, because it's possible to set up a map that | |||
670 | * will return a character every time, but will expand to more, | |||
671 | * e.g. "map! a aaaa" will always return a 'a', but we'll never | |||
672 | * get anywhere useful. | |||
673 | */ | |||
674 | if ((++remap_cnt == 1 || remap_cnt % 10 == 0) && | |||
675 | (gp->scr_event(sp, &ev, | |||
676 | EC_INTERRUPT0x001, 0) || ev.e_event == E_INTERRUPT)) { | |||
677 | F_SET(sp->gp, G_INTERRUPTED)(((sp->gp)->flags) |= ((0x0004))); | |||
678 | argp->e_event = E_INTERRUPT; | |||
679 | return (0); | |||
680 | } | |||
681 | ||||
682 | /* | |||
683 | * If an initial part of the characters mapped, they are not | |||
684 | * further remapped -- return the first one. Push the rest | |||
685 | * of the characters, or all of the characters if no initial | |||
686 | * part mapped, back on the queue. | |||
687 | */ | |||
688 | if (init_nomap) { | |||
689 | if (v_event_push(sp, NULL((void *)0), qp->output + qp->ilen, | |||
690 | qp->olen - qp->ilen, CH_MAPPED0x02)) | |||
691 | return (1); | |||
692 | if (v_event_push(sp, NULL((void *)0), | |||
693 | qp->output, qp->ilen, CH_NOMAP0x04 | CH_MAPPED0x02)) | |||
694 | return (1); | |||
695 | evp = &gp->i_event[gp->i_next]; | |||
696 | goto nomap; | |||
697 | } | |||
698 | if (v_event_push(sp, NULL((void *)0), qp->output, qp->olen, CH_MAPPED0x02)) | |||
699 | return (1); | |||
700 | goto newmap; | |||
701 | } | |||
702 | ||||
703 | /* Else, push the characters on the queue and return one. */ | |||
704 | if (v_event_push(sp, NULL((void *)0), qp->output, qp->olen, CH_MAPPED0x02 | CH_NOMAP0x04)) | |||
705 | return (1); | |||
706 | ||||
707 | goto nomap; | |||
708 | } | |||
709 | ||||
710 | /* | |||
711 | * v_sync -- | |||
712 | * Walk the screen lists, sync'ing files to their backup copies. | |||
713 | */ | |||
714 | static void | |||
715 | v_sync(SCR *sp, int flags) | |||
716 | { | |||
717 | GS *gp; | |||
718 | ||||
719 | gp = sp->gp; | |||
720 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) | |||
721 | rcv_sync(sp, flags); | |||
722 | TAILQ_FOREACH(sp, &gp->hq, q)for((sp) = ((&gp->hq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) | |||
723 | rcv_sync(sp, flags); | |||
724 | } | |||
725 | ||||
726 | /* | |||
727 | * v_event_err -- | |||
728 | * Unexpected event. | |||
729 | * | |||
730 | * PUBLIC: void v_event_err(SCR *, EVENT *); | |||
731 | */ | |||
732 | void | |||
733 | v_event_err(SCR *sp, EVENT *evp) | |||
734 | { | |||
735 | switch (evp->e_event) { | |||
736 | case E_CHARACTER: | |||
737 | msgq(sp, M_ERR, "Unexpected character event"); | |||
738 | break; | |||
739 | case E_EOF: | |||
740 | msgq(sp, M_ERR, "Unexpected end-of-file event"); | |||
741 | break; | |||
742 | case E_INTERRUPT: | |||
743 | msgq(sp, M_ERR, "Unexpected interrupt event"); | |||
744 | break; | |||
745 | case E_QUIT: | |||
746 | msgq(sp, M_ERR, "Unexpected quit event"); | |||
747 | break; | |||
748 | case E_REPAINT: | |||
749 | msgq(sp, M_ERR, "Unexpected repaint event"); | |||
750 | break; | |||
751 | case E_STRING: | |||
752 | msgq(sp, M_ERR, "Unexpected string event"); | |||
753 | break; | |||
754 | case E_TIMEOUT: | |||
755 | msgq(sp, M_ERR, "Unexpected timeout event"); | |||
756 | break; | |||
757 | case E_WRESIZE: | |||
758 | msgq(sp, M_ERR, "Unexpected resize event"); | |||
759 | break; | |||
760 | case E_WRITE: | |||
761 | msgq(sp, M_ERR, "Unexpected write event"); | |||
762 | break; | |||
763 | ||||
764 | /* | |||
765 | * Theoretically, none of these can occur, as they're handled at the | |||
766 | * top editor level. | |||
767 | */ | |||
768 | case E_ERR: | |||
769 | case E_SIGHUP: | |||
770 | case E_SIGTERM: | |||
771 | default: | |||
772 | abort(); | |||
773 | } | |||
774 | ||||
775 | /* Free any allocated memory. */ | |||
776 | free(evp->e_asp_u_event._e_str.asp); | |||
777 | } | |||
778 | ||||
779 | /* | |||
780 | * v_event_flush -- | |||
781 | * Flush any flagged keys, returning if any keys were flushed. | |||
782 | * | |||
783 | * PUBLIC: int v_event_flush(SCR *, u_int); | |||
784 | */ | |||
785 | int | |||
786 | v_event_flush(SCR *sp, u_int flags) | |||
787 | { | |||
788 | GS *gp; | |||
789 | int rval; | |||
790 | ||||
791 | for (rval = 0, gp = sp->gp; gp->i_cnt != 0 && | |||
792 | F_ISSET(&gp->i_event[gp->i_next].e_ch, flags)(((&gp->i_event[gp->i_next]._u_event._e_ch)->flags ) & ((flags))); rval = 1) | |||
793 | QREM(1){ if ((gp->i_cnt -= (1)) == 0) gp->i_next = 0; else gp-> i_next += (1); }; | |||
794 | return (rval); | |||
795 | } | |||
796 | ||||
797 | /* | |||
798 | * v_event_grow -- | |||
799 | * Grow the terminal queue. | |||
800 | */ | |||
801 | static int | |||
802 | v_event_grow(SCR *sp, int add) | |||
803 | { | |||
804 | GS *gp; | |||
805 | size_t new_nelem, olen; | |||
806 | ||||
807 | gp = sp->gp; | |||
808 | new_nelem = gp->i_nelem + add; | |||
809 | olen = gp->i_nelem * sizeof(gp->i_event[0]); | |||
810 | BINC_RET(sp, gp->i_event, olen, new_nelem * sizeof(gp->i_event[0])){ void *L__bincp; if ((new_nelem * sizeof(gp->i_event[0])) > (olen)) { if ((L__bincp = binc((sp), (gp->i_event), & (olen), (new_nelem * sizeof(gp->i_event[0])))) == ((void * )0)) return (1); (gp->i_event) = L__bincp; } }; | |||
811 | gp->i_nelem = olen / sizeof(gp->i_event[0]); | |||
812 | return (0); | |||
813 | } | |||
814 | ||||
815 | /* | |||
816 | * v_key_cmp -- | |||
817 | * Compare two keys for sorting. | |||
818 | */ | |||
819 | static int | |||
820 | v_key_cmp(const void *ap, const void *bp) | |||
821 | { | |||
822 | return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch); | |||
823 | } |