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