| File: | src/usr.bin/vi/build/../common/key.c |
| Warning: | line 392, column 17 Access to field 'e_event' results in a dereference of a null pointer (loaded from variable 'evp') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: key.c,v 1.19 2017/04/18 01:45:35 deraadt 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
| |||
| 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 || F_ISSET(&evp->e_ch, CH_NOMAP)(((&evp->_u_event._e_ch)->flags) & ((0x04))) || | |||
| 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 | init_nomap = !e_memcmp(qp->output, &gp->i_event[gp->i_next], qp->ilen); | |||
| 654 | ||||
| 655 | /* Delete the mapped characters from the queue. */ | |||
| 656 | QREM(qp->ilen){ if ((gp->i_cnt -= (qp->ilen)) == 0) gp->i_next = 0 ; else gp->i_next += (qp->ilen); }; | |||
| 657 | ||||
| 658 | /* If keys mapped to nothing, go get more. */ | |||
| 659 | if (qp->output == NULL((void *)0)) | |||
| 660 | goto retry; | |||
| 661 | ||||
| 662 | /* If remapping characters... */ | |||
| 663 | 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)) { | |||
| 664 | /* | |||
| 665 | * Periodically check for interrupts. Always check the first | |||
| 666 | * time through, because it's possible to set up a map that | |||
| 667 | * will return a character every time, but will expand to more, | |||
| 668 | * e.g. "map! a aaaa" will always return a 'a', but we'll never | |||
| 669 | * get anywhere useful. | |||
| 670 | */ | |||
| 671 | if ((++remap_cnt == 1 || remap_cnt % 10 == 0) && | |||
| 672 | (gp->scr_event(sp, &ev, | |||
| 673 | EC_INTERRUPT0x001, 0) || ev.e_event == E_INTERRUPT)) { | |||
| 674 | F_SET(sp->gp, G_INTERRUPTED)(((sp->gp)->flags) |= ((0x0004))); | |||
| 675 | argp->e_event = E_INTERRUPT; | |||
| 676 | return (0); | |||
| 677 | } | |||
| 678 | ||||
| 679 | /* | |||
| 680 | * If an initial part of the characters mapped, they are not | |||
| 681 | * further remapped -- return the first one. Push the rest | |||
| 682 | * of the characters, or all of the characters if no initial | |||
| 683 | * part mapped, back on the queue. | |||
| 684 | */ | |||
| 685 | if (init_nomap) { | |||
| 686 | if (v_event_push(sp, NULL((void *)0), qp->output + qp->ilen, | |||
| 687 | qp->olen - qp->ilen, CH_MAPPED0x02)) | |||
| 688 | return (1); | |||
| 689 | if (v_event_push(sp, NULL((void *)0), | |||
| 690 | qp->output, qp->ilen, CH_NOMAP0x04 | CH_MAPPED0x02)) | |||
| 691 | return (1); | |||
| 692 | evp = &gp->i_event[gp->i_next]; | |||
| 693 | goto nomap; | |||
| 694 | } | |||
| 695 | if (v_event_push(sp, NULL((void *)0), qp->output, qp->olen, CH_MAPPED0x02)) | |||
| 696 | return (1); | |||
| 697 | goto newmap; | |||
| 698 | } | |||
| 699 | ||||
| 700 | /* Else, push the characters on the queue and return one. */ | |||
| 701 | if (v_event_push(sp, NULL((void *)0), qp->output, qp->olen, CH_MAPPED0x02 | CH_NOMAP0x04)) | |||
| 702 | return (1); | |||
| 703 | ||||
| 704 | goto nomap; | |||
| 705 | } | |||
| 706 | ||||
| 707 | /* | |||
| 708 | * v_sync -- | |||
| 709 | * Walk the screen lists, sync'ing files to their backup copies. | |||
| 710 | */ | |||
| 711 | static void | |||
| 712 | v_sync(SCR *sp, int flags) | |||
| 713 | { | |||
| 714 | GS *gp; | |||
| 715 | ||||
| 716 | gp = sp->gp; | |||
| 717 | TAILQ_FOREACH(sp, &gp->dq, q)for((sp) = ((&gp->dq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) | |||
| 718 | rcv_sync(sp, flags); | |||
| 719 | TAILQ_FOREACH(sp, &gp->hq, q)for((sp) = ((&gp->hq)->tqh_first); (sp) != ((void * )0); (sp) = ((sp)->q.tqe_next)) | |||
| 720 | rcv_sync(sp, flags); | |||
| 721 | } | |||
| 722 | ||||
| 723 | /* | |||
| 724 | * v_event_err -- | |||
| 725 | * Unexpected event. | |||
| 726 | * | |||
| 727 | * PUBLIC: void v_event_err(SCR *, EVENT *); | |||
| 728 | */ | |||
| 729 | void | |||
| 730 | v_event_err(SCR *sp, EVENT *evp) | |||
| 731 | { | |||
| 732 | switch (evp->e_event) { | |||
| 733 | case E_CHARACTER: | |||
| 734 | msgq(sp, M_ERR, "Unexpected character event"); | |||
| 735 | break; | |||
| 736 | case E_EOF: | |||
| 737 | msgq(sp, M_ERR, "Unexpected end-of-file event"); | |||
| 738 | break; | |||
| 739 | case E_INTERRUPT: | |||
| 740 | msgq(sp, M_ERR, "Unexpected interrupt event"); | |||
| 741 | break; | |||
| 742 | case E_QUIT: | |||
| 743 | msgq(sp, M_ERR, "Unexpected quit event"); | |||
| 744 | break; | |||
| 745 | case E_REPAINT: | |||
| 746 | msgq(sp, M_ERR, "Unexpected repaint event"); | |||
| 747 | break; | |||
| 748 | case E_STRING: | |||
| 749 | msgq(sp, M_ERR, "Unexpected string event"); | |||
| 750 | break; | |||
| 751 | case E_TIMEOUT: | |||
| 752 | msgq(sp, M_ERR, "Unexpected timeout event"); | |||
| 753 | break; | |||
| 754 | case E_WRESIZE: | |||
| 755 | msgq(sp, M_ERR, "Unexpected resize event"); | |||
| 756 | break; | |||
| 757 | case E_WRITE: | |||
| 758 | msgq(sp, M_ERR, "Unexpected write event"); | |||
| 759 | break; | |||
| 760 | ||||
| 761 | /* | |||
| 762 | * Theoretically, none of these can occur, as they're handled at the | |||
| 763 | * top editor level. | |||
| 764 | */ | |||
| 765 | case E_ERR: | |||
| 766 | case E_SIGHUP: | |||
| 767 | case E_SIGTERM: | |||
| 768 | default: | |||
| 769 | abort(); | |||
| 770 | } | |||
| 771 | ||||
| 772 | /* Free any allocated memory. */ | |||
| 773 | free(evp->e_asp_u_event._e_str.asp); | |||
| 774 | } | |||
| 775 | ||||
| 776 | /* | |||
| 777 | * v_event_flush -- | |||
| 778 | * Flush any flagged keys, returning if any keys were flushed. | |||
| 779 | * | |||
| 780 | * PUBLIC: int v_event_flush(SCR *, u_int); | |||
| 781 | */ | |||
| 782 | int | |||
| 783 | v_event_flush(SCR *sp, u_int flags) | |||
| 784 | { | |||
| 785 | GS *gp; | |||
| 786 | int rval; | |||
| 787 | ||||
| 788 | for (rval = 0, gp = sp->gp; gp->i_cnt != 0 && | |||
| 789 | 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) | |||
| 790 | QREM(1){ if ((gp->i_cnt -= (1)) == 0) gp->i_next = 0; else gp-> i_next += (1); }; | |||
| 791 | return (rval); | |||
| 792 | } | |||
| 793 | ||||
| 794 | /* | |||
| 795 | * v_event_grow -- | |||
| 796 | * Grow the terminal queue. | |||
| 797 | */ | |||
| 798 | static int | |||
| 799 | v_event_grow(SCR *sp, int add) | |||
| 800 | { | |||
| 801 | GS *gp; | |||
| 802 | size_t new_nelem, olen; | |||
| 803 | ||||
| 804 | gp = sp->gp; | |||
| 805 | new_nelem = gp->i_nelem + add; | |||
| 806 | olen = gp->i_nelem * sizeof(gp->i_event[0]); | |||
| 807 | 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; } }; | |||
| 808 | gp->i_nelem = olen / sizeof(gp->i_event[0]); | |||
| 809 | return (0); | |||
| 810 | } | |||
| 811 | ||||
| 812 | /* | |||
| 813 | * v_key_cmp -- | |||
| 814 | * Compare two keys for sorting. | |||
| 815 | */ | |||
| 816 | static int | |||
| 817 | v_key_cmp(const void *ap, const void *bp) | |||
| 818 | { | |||
| 819 | return (((KEYLIST *)ap)->ch - ((KEYLIST *)bp)->ch); | |||
| 820 | } |