1 /* 2 * tc.bind.c: Key binding functions 3 */ 4 /*- 5 * Copyright (c) 1980, 1991 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 #include "sh.h" 33 #include "ed.h" 34 #include "ed.defns.h" 35 36 static void printkey (const KEYCMD *, CStr *); 37 static KEYCMD parsecmd (Char *); 38 static void bad_spec (const Char *); 39 static CStr *parsestring (const Char *, CStr *); 40 static CStr *parsebind (const Char *, CStr *); 41 static void print_all_keys (void); 42 static void printkeys (KEYCMD *, int, int); 43 static void bindkey_usage (void); 44 static void list_functions (void); 45 46 extern int MapsAreInited; 47 48 49 50 51 /*ARGSUSED*/ 52 void 53 dobindkey(Char **v, struct command *c) 54 { 55 KEYCMD *map; 56 int ntype, no, removeb, key, bindk; 57 Char *par; 58 Char p; 59 KEYCMD cmd; 60 CStr in; 61 CStr out; 62 uChar ch; 63 64 USE(c); 65 if (!MapsAreInited) 66 ed_InitMaps(); 67 68 map = CcKeyMap; 69 ntype = XK_CMD; 70 key = removeb = bindk = 0; 71 for (no = 1, par = v[no]; 72 par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) { 73 if ((p = (*par & CHAR)) == '-') { 74 no++; 75 break; 76 } 77 else 78 switch (p) { 79 case 'b': 80 bindk = 1; 81 break; 82 case 'k': 83 key = 1; 84 break; 85 case 'a': 86 map = CcAltMap; 87 break; 88 case 's': 89 ntype = XK_STR; 90 break; 91 case 'c': 92 ntype = XK_EXE; 93 break; 94 case 'r': 95 removeb = 1; 96 break; 97 case 'v': 98 ed_InitVIMaps(); 99 return; 100 case 'e': 101 ed_InitEmacsMaps(); 102 return; 103 case 'd': 104 #ifdef VIDEFAULT 105 ed_InitVIMaps(); 106 #else /* EMACSDEFAULT */ 107 ed_InitEmacsMaps(); 108 #endif /* VIDEFAULT */ 109 return; 110 case 'l': 111 list_functions(); 112 return; 113 default: 114 bindkey_usage(); 115 return; 116 } 117 } 118 119 if (!v[no]) { 120 print_all_keys(); 121 return; 122 } 123 124 if (key) { 125 if (!IsArrowKey(v[no])) 126 xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]); 127 in.buf = Strsave(v[no++]); 128 in.len = Strlen(in.buf); 129 } 130 else { 131 if (bindk) { 132 if (parsebind(v[no++], &in) == NULL) 133 return; 134 } 135 else { 136 if (parsestring(v[no++], &in) == NULL) 137 return; 138 } 139 } 140 cleanup_push(in.buf, xfree); 141 142 #ifndef WINNT_NATIVE 143 if (in.buf[0] > 0xFF) { 144 bad_spec(in.buf); 145 cleanup_until(in.buf); 146 return; 147 } 148 #endif 149 ch = (uChar) in.buf[0]; 150 151 if (removeb) { 152 if (key) 153 (void) ClearArrowKeys(&in); 154 else if (in.len > 1) { 155 (void) DeleteXkey(&in); 156 } 157 else if (map[ch] == F_XKEY) { 158 (void) DeleteXkey(&in); 159 map[ch] = F_UNASSIGNED; 160 } 161 else { 162 map[ch] = F_UNASSIGNED; 163 } 164 cleanup_until(in.buf); 165 return; 166 } 167 if (!v[no]) { 168 if (key) 169 PrintArrowKeys(&in); 170 else 171 printkey(map, &in); 172 cleanup_until(in.buf); 173 return; 174 } 175 if (v[no + 1]) { 176 bindkey_usage(); 177 cleanup_until(in.buf); 178 return; 179 } 180 switch (ntype) { 181 case XK_STR: 182 case XK_EXE: 183 if (parsestring(v[no], &out) == NULL) { 184 cleanup_until(in.buf); 185 return; 186 } 187 cleanup_push(out.buf, xfree); 188 if (key) { 189 if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1) 190 xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf); 191 else 192 cleanup_ignore(out.buf); 193 } 194 else 195 AddXkey(&in, XmapStr(&out), ntype); 196 map[ch] = F_XKEY; 197 break; 198 case XK_CMD: 199 if ((cmd = parsecmd(v[no])) == 0) { 200 cleanup_until(in.buf); 201 return; 202 } 203 if (key) 204 (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype); 205 else { 206 if (in.len > 1) { 207 AddXkey(&in, XmapCmd((int) cmd), ntype); 208 map[ch] = F_XKEY; 209 } 210 else { 211 ClearXkey(map, &in); 212 map[ch] = cmd; 213 } 214 } 215 break; 216 default: 217 abort(); 218 break; 219 } 220 cleanup_until(in.buf); 221 if (key) 222 BindArrowKeys(); 223 } 224 225 static void 226 printkey(const KEYCMD *map, CStr *in) 227 { 228 struct KeyFuncs *fp; 229 230 if (in->len < 2) { 231 unsigned char *unparsed; 232 233 unparsed = unparsestring(in, STRQQ); 234 cleanup_push(unparsed, xfree); 235 for (fp = FuncNames; fp->name; fp++) { 236 if (fp->func == map[(uChar) *(in->buf)]) { 237 xprintf("%s\t->\t%s\n", unparsed, fp->name); 238 } 239 } 240 cleanup_until(unparsed); 241 } 242 else 243 PrintXkey(in); 244 } 245 246 static KEYCMD 247 parsecmd(Char *str) 248 { 249 struct KeyFuncs *fp; 250 251 for (fp = FuncNames; fp->name; fp++) { 252 if (strcmp(short2str(str), fp->name) == 0) { 253 return (KEYCMD) fp->func; 254 } 255 } 256 xprintf(CGETS(20, 3, "Bad command name: %S\n"), str); 257 return 0; 258 } 259 260 261 static void 262 bad_spec(const Char *str) 263 { 264 xprintf(CGETS(20, 4, "Bad key spec %S\n"), str); 265 } 266 267 static CStr * 268 parsebind(const Char *s, CStr *str) 269 { 270 struct Strbuf b = Strbuf_INIT; 271 272 cleanup_push(&b, Strbuf_cleanup); 273 if (Iscntrl(*s)) { 274 Strbuf_append1(&b, *s); 275 goto end; 276 } 277 278 switch (*s) { 279 case '^': 280 s++; 281 #ifdef IS_ASCII 282 Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237)); 283 #else 284 Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177') 285 : _toebcdic[_toascii[*s & CHAR] & 0237]); 286 #endif 287 break; 288 289 case 'F': 290 case 'M': 291 case 'X': 292 case 'C': 293 #ifdef WINNT_NATIVE 294 case 'N': 295 #endif /* WINNT_NATIVE */ 296 if (s[1] != '-' || s[2] == '\0') 297 goto bad_spec; 298 s += 2; 299 switch (s[-2]) { 300 case 'F': case 'f': /* Turn into ^[str */ 301 Strbuf_append1(&b, CTL_ESC('\033')); 302 Strbuf_append(&b, s); 303 break; 304 305 case 'C': case 'c': /* Turn into ^c */ 306 #ifdef IS_ASCII 307 Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237)); 308 #else 309 Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177') 310 : _toebcdic[_toascii[*s & CHAR] & 0237]); 311 #endif 312 break; 313 314 case 'X' : case 'x': /* Turn into ^Xc */ 315 #ifdef IS_ASCII 316 Strbuf_append1(&b, 'X' & 0237); 317 #else 318 Strbuf_append1(&b, _toebcdic[_toascii['X'] & 0237]); 319 #endif 320 Strbuf_append1(&b, *s); 321 break; 322 323 case 'M' : case 'm': /* Turn into 0x80|c */ 324 if (!NoNLSRebind) { 325 Strbuf_append1(&b, CTL_ESC('\033')); 326 Strbuf_append1(&b, *s); 327 } else { 328 #ifdef IS_ASCII 329 Strbuf_append1(&b, *s | 0x80); 330 #else 331 Strbuf_append1(&b, _toebcdic[_toascii[*s] | 0x80]); 332 #endif 333 } 334 break; 335 #ifdef WINNT_NATIVE 336 case 'N' : case 'n': /* NT */ 337 { 338 Char bnt; 339 340 bnt = nt_translate_bindkey(s); 341 if (bnt != 0) 342 Strbuf_append1(&b, bnt); 343 else 344 bad_spec(s); 345 } 346 break; 347 #endif /* WINNT_NATIVE */ 348 349 default: 350 abort(); 351 } 352 break; 353 354 default: 355 goto bad_spec; 356 } 357 358 end: 359 cleanup_ignore(&b); 360 cleanup_until(&b); 361 Strbuf_terminate(&b); 362 str->buf = xrealloc(b.s, (b.len + 1) * sizeof (*str->buf)); 363 str->len = b.len; 364 return str; 365 366 bad_spec: 367 bad_spec(s); 368 cleanup_until(&b); 369 return NULL; 370 } 371 372 373 static CStr * 374 parsestring(const Char *str, CStr *buf) 375 { 376 struct Strbuf b = Strbuf_INIT; 377 const Char *p; 378 eChar es; 379 380 if (*str == 0) { 381 xprintf("%s", CGETS(20, 5, "Null string specification\n")); 382 return NULL; 383 } 384 385 cleanup_push(&b, Strbuf_cleanup); 386 for (p = str; *p != 0; p++) { 387 if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') { 388 if ((es = parseescape(&p)) == CHAR_ERR) { 389 cleanup_until(&b); 390 return 0; 391 } else 392 Strbuf_append1(&b, es); 393 } 394 else 395 Strbuf_append1(&b, *p & CHAR); 396 } 397 cleanup_ignore(&b); 398 cleanup_until(&b); 399 Strbuf_terminate(&b); 400 buf->buf = xrealloc(b.s, (b.len + 1) * sizeof (*buf->buf)); 401 buf->len = b.len; 402 return buf; 403 } 404 405 static void 406 print_all_keys(void) 407 { 408 int prev, i; 409 CStr nilstr; 410 nilstr.buf = NULL; 411 nilstr.len = 0; 412 413 414 xprintf("%s", CGETS(20, 6, "Standard key bindings\n")); 415 prev = 0; 416 for (i = 0; i < 256; i++) { 417 if (CcKeyMap[prev] == CcKeyMap[i]) 418 continue; 419 printkeys(CcKeyMap, prev, i - 1); 420 prev = i; 421 } 422 printkeys(CcKeyMap, prev, i - 1); 423 424 xprintf("%s", CGETS(20, 7, "Alternative key bindings\n")); 425 prev = 0; 426 for (i = 0; i < 256; i++) { 427 if (CcAltMap[prev] == CcAltMap[i]) 428 continue; 429 printkeys(CcAltMap, prev, i - 1); 430 prev = i; 431 } 432 printkeys(CcAltMap, prev, i - 1); 433 xprintf("%s", CGETS(20, 8, "Multi-character bindings\n")); 434 PrintXkey(NULL); /* print all Xkey bindings */ 435 xprintf("%s", CGETS(20, 9, "Arrow key bindings\n")); 436 PrintArrowKeys(&nilstr); 437 } 438 439 static void 440 printkeys(KEYCMD *map, int first, int last) 441 { 442 struct KeyFuncs *fp; 443 Char firstbuf[2], lastbuf[2]; 444 CStr fb, lb; 445 unsigned char *unparsed; 446 fb.buf = firstbuf; 447 lb.buf = lastbuf; 448 449 firstbuf[0] = (Char) first; 450 firstbuf[1] = 0; 451 lastbuf[0] = (Char) last; 452 lastbuf[1] = 0; 453 fb.len = 1; 454 lb.len = 1; 455 456 unparsed = unparsestring(&fb, STRQQ); 457 cleanup_push(unparsed, xfree); 458 if (map[first] == F_UNASSIGNED) { 459 if (first == last) 460 xprintf(CGETS(20, 10, "%-15s-> is undefined\n"), unparsed); 461 cleanup_until(unparsed); 462 return; 463 } 464 465 for (fp = FuncNames; fp->name; fp++) { 466 if (fp->func == map[first]) { 467 if (first == last) 468 xprintf("%-15s-> %s\n", unparsed, fp->name); 469 else { 470 unsigned char *p; 471 472 p = unparsestring(&lb, STRQQ); 473 cleanup_push(p, xfree); 474 xprintf("%-4s to %-7s-> %s\n", unparsed, p, fp->name); 475 } 476 cleanup_until(unparsed); 477 return; 478 } 479 } 480 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), unparsed); 481 if (map == CcKeyMap) 482 xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 483 else 484 xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 485 cleanup_until(unparsed); 486 } 487 488 static void 489 bindkey_usage(void) 490 { 491 xprintf("%s", CGETS(20, 12, 492 "Usage: bindkey [options] [--] [KEY [COMMAND]]\n")); 493 xprintf("%s", CGETS(20, 13, 494 " -a list or bind KEY in alternative key map\n")); 495 xprintf("%s", CGETS(20, 14, 496 " -b interpret KEY as a C-, M-, F- or X- key name\n")); 497 xprintf("%s", CGETS(20, 15, 498 " -s interpret COMMAND as a literal string to be output\n")); 499 xprintf("%s", CGETS(20, 16, 500 " -c interpret COMMAND as a builtin or external command\n")); 501 xprintf("%s", CGETS(20, 17, 502 " -v bind all keys to vi bindings\n")); 503 xprintf("%s", CGETS(20, 18, 504 " -e bind all keys to emacs bindings\n")); 505 xprintf(CGETS(20, 19, 506 " -d bind all keys to default editor's bindings (%s)\n"), 507 #ifdef VIDEFAULT 508 "vi" 509 #else /* EMACSDEFAULT */ 510 "emacs" 511 #endif /* VIDEFAULT */ 512 ); 513 xprintf("%s", CGETS(20, 20, 514 " -l list editor commands with descriptions\n")); 515 xprintf("%s", CGETS(20, 21, 516 " -r remove KEY's binding\n")); 517 xprintf("%s", CGETS(20, 22, 518 " -k interpret KEY as a symbolic arrow-key name\n")); 519 xprintf("%s", CGETS(20, 23, 520 " -- force a break from option processing\n")); 521 xprintf("%s", CGETS(20, 24, 522 " -u (or any invalid option) this message\n")); 523 xprintf("\n"); 524 xprintf("%s", CGETS(20, 25, 525 "Without KEY or COMMAND, prints all bindings\n")); 526 xprintf("%s", CGETS(20, 26, 527 "Without COMMAND, prints the binding for KEY.\n")); 528 } 529 530 static void 531 list_functions(void) 532 { 533 struct KeyFuncs *fp; 534 535 for (fp = FuncNames; fp->name; fp++) { 536 xprintf("%s\n %s\n", fp->name, fp->desc); 537 } 538 } 539