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