1 /* $Header: /src/pub/tcsh/tc.bind.c,v 3.39 2005/03/25 18:46:41 kim 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("$Id: tc.bind.c,v 3.39 2005/03/25 18:46:41 kim Exp $") 36 37 #include "ed.h" 38 #include "ed.defns.h" 39 40 #ifdef OBSOLETE 41 static int tocontrol __P((int)); 42 static char *unparsekey __P((int)); 43 static KEYCMD getkeycmd __P((Char **)); 44 static int parsekey __P((Char **)); 45 static void pkeys __P((int, int)); 46 #endif /* OBSOLETE */ 47 48 static void printkey __P((KEYCMD *, CStr *)); 49 static KEYCMD parsecmd __P((Char *)); 50 static void bad_spec __P((Char *)); 51 static CStr *parsestring __P((Char *, CStr *)); 52 static CStr *parsebind __P((Char *, CStr *)); 53 static void print_all_keys __P((void)); 54 static void printkeys __P((KEYCMD *, int, int)); 55 static void bindkey_usage __P((void)); 56 static void list_functions __P((void)); 57 58 extern int MapsAreInited; 59 60 61 62 63 /*ARGSUSED*/ 64 void 65 dobindkey(v, c) 66 Char **v; 67 struct command *c; 68 { 69 KEYCMD *map; 70 int ntype, no, removeb, key, bindk; 71 Char *par; 72 Char p; 73 KEYCMD cmd; 74 CStr in; 75 CStr out; 76 Char inbuf[200]; 77 Char outbuf[200]; 78 uChar ch; 79 in.buf = inbuf; 80 out.buf = outbuf; 81 in.len = 0; 82 out.len = 0; 83 84 USE(c); 85 if (!MapsAreInited) 86 ed_InitMaps(); 87 88 map = CcKeyMap; 89 ntype = XK_CMD; 90 key = removeb = bindk = 0; 91 for (no = 1, par = v[no]; 92 par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) { 93 if ((p = (*par & CHAR)) == '-') { 94 no++; 95 break; 96 } 97 else 98 switch (p) { 99 case 'b': 100 bindk = 1; 101 break; 102 case 'k': 103 key = 1; 104 break; 105 case 'a': 106 map = CcAltMap; 107 break; 108 case 's': 109 ntype = XK_STR; 110 break; 111 case 'c': 112 ntype = XK_EXE; 113 break; 114 case 'r': 115 removeb = 1; 116 break; 117 case 'v': 118 ed_InitVIMaps(); 119 return; 120 case 'e': 121 ed_InitEmacsMaps(); 122 return; 123 case 'd': 124 #ifdef VIDEFAULT 125 ed_InitVIMaps(); 126 #else /* EMACSDEFAULT */ 127 ed_InitEmacsMaps(); 128 #endif /* VIDEFAULT */ 129 return; 130 case 'l': 131 list_functions(); 132 return; 133 default: 134 bindkey_usage(); 135 return; 136 } 137 } 138 139 if (!v[no]) { 140 print_all_keys(); 141 return; 142 } 143 144 if (key) { 145 if (!IsArrowKey(v[no])) 146 xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]); 147 in.buf = v[no++]; 148 in.len = Strlen(in.buf); 149 } 150 else { 151 if (bindk) { 152 if (parsebind(v[no++], &in) == NULL) 153 return; 154 } 155 else { 156 if (parsestring(v[no++], &in) == NULL) 157 return; 158 } 159 } 160 161 #ifndef WINNT_NATIVE 162 if (in.buf[0] > 0xFF) { 163 bad_spec(in.buf); 164 return; 165 } 166 #endif 167 ch = (uChar) in.buf[0]; 168 169 if (removeb) { 170 if (key) { 171 (void) ClearArrowKeys(&in); 172 return; 173 } 174 if (in.len > 1) { 175 (void) DeleteXkey(&in); 176 } 177 else if (map[ch] == F_XKEY) { 178 (void) DeleteXkey(&in); 179 map[ch] = F_UNASSIGNED; 180 } 181 else { 182 map[ch] = F_UNASSIGNED; 183 } 184 return; 185 } 186 if (!v[no]) { 187 if (key) 188 PrintArrowKeys(&in); 189 else 190 printkey(map, &in); 191 return; 192 } 193 if (v[no + 1]) { 194 bindkey_usage(); 195 return; 196 } 197 switch (ntype) { 198 case XK_STR: 199 case XK_EXE: 200 if (parsestring(v[no], &out) == NULL) 201 return; 202 if (key) { 203 if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1) 204 xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf); 205 } 206 else 207 AddXkey(&in, XmapStr(&out), ntype); 208 map[ch] = F_XKEY; 209 break; 210 case XK_CMD: 211 if ((cmd = parsecmd(v[no])) == 0) 212 return; 213 if (key) 214 (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype); 215 else { 216 if (in.len > 1) { 217 AddXkey(&in, XmapCmd((int) cmd), ntype); 218 map[ch] = F_XKEY; 219 } 220 else { 221 ClearXkey(map, &in); 222 map[ch] = cmd; 223 } 224 } 225 break; 226 default: 227 abort(); 228 break; 229 } 230 if (key) 231 BindArrowKeys(); 232 } 233 234 static void 235 printkey(map, in) 236 KEYCMD *map; 237 CStr *in; 238 { 239 unsigned char outbuf[100]; 240 struct KeyFuncs *fp; 241 242 if (in->len < 2) { 243 (void) unparsestring(in, outbuf, STRQQ); 244 for (fp = FuncNames; fp->name; fp++) { 245 if (fp->func == map[(uChar) *(in->buf)]) { 246 xprintf("%s\t->\t%s\n", outbuf, fp->name); 247 } 248 } 249 } 250 else 251 PrintXkey(in); 252 } 253 254 static KEYCMD 255 parsecmd(str) 256 Char *str; 257 { 258 struct KeyFuncs *fp; 259 260 for (fp = FuncNames; fp->name; fp++) { 261 if (strcmp(short2str(str), fp->name) == 0) { 262 return (KEYCMD) fp->func; 263 } 264 } 265 xprintf(CGETS(20, 3, "Bad command name: %S\n"), str); 266 return 0; 267 } 268 269 270 static void 271 bad_spec(str) 272 Char *str; 273 { 274 xprintf(CGETS(20, 4, "Bad key spec %S\n"), str); 275 } 276 277 static CStr * 278 parsebind(s, str) 279 Char *s; 280 CStr *str; 281 { 282 Char *b = str->buf; 283 284 if (Iscntrl(*s)) { 285 *b++ = *s; 286 *b = '\0'; 287 str->len = (int) (b - str->buf); 288 return str; 289 } 290 291 switch (*s) { 292 case '^': 293 s++; 294 #ifdef IS_ASCII 295 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 296 #else 297 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 298 #endif 299 *b = '\0'; 300 break; 301 302 case 'F': 303 case 'M': 304 case 'X': 305 case 'C': 306 #ifdef WINNT_NATIVE 307 case 'N': 308 #endif /* WINNT_NATIVE */ 309 if (s[1] != '-' || s[2] == '\0') { 310 bad_spec(s); 311 return NULL; 312 } 313 s += 2; 314 switch (s[-2]) { 315 case 'F': case 'f': /* Turn into ^[str */ 316 *b++ = CTL_ESC('\033'); 317 while ((*b++ = *s++) != '\0') 318 continue; 319 b--; 320 break; 321 322 case 'C': case 'c': /* Turn into ^c */ 323 #ifdef IS_ASCII 324 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 325 #else 326 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 327 #endif 328 *b = '\0'; 329 break; 330 331 case 'X' : case 'x': /* Turn into ^Xc */ 332 #ifdef IS_ASCII 333 *b++ = 'X' & 0237; 334 #else 335 *b++ = _toebcdic[_toascii['X'] & 0237]; 336 #endif 337 *b++ = *s; 338 *b = '\0'; 339 break; 340 341 case 'M' : case 'm': /* Turn into 0x80|c */ 342 if (!NoNLSRebind) { 343 *b++ = CTL_ESC('\033'); 344 *b++ = *s; 345 } else { 346 #ifdef IS_ASCII 347 *b++ = *s | 0x80; 348 #else 349 *b++ = _toebcdic[_toascii[*s] | 0x80]; 350 #endif 351 } 352 *b = '\0'; 353 break; 354 #ifdef WINNT_NATIVE 355 case 'N' : case 'n': /* NT */ 356 { 357 Char bnt; 358 359 bnt = nt_translate_bindkey(s); 360 if (bnt != 0) 361 *b++ = bnt; 362 else 363 bad_spec(s); 364 } 365 break; 366 #endif /* WINNT_NATIVE */ 367 368 default: 369 abort(); 370 /*NOTREACHED*/ 371 return NULL; 372 } 373 break; 374 375 default: 376 bad_spec(s); 377 return NULL; 378 } 379 380 str->len = (int) (b - str->buf); 381 return str; 382 } 383 384 385 static CStr * 386 parsestring(str, buf) 387 Char *str; 388 CStr *buf; 389 { 390 Char *b; 391 const Char *p; 392 eChar es; 393 394 b = buf->buf; 395 if (*str == 0) { 396 xprintf(CGETS(20, 5, "Null string specification\n")); 397 return NULL; 398 } 399 400 for (p = str; *p != 0; p++) { 401 if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') { 402 if ((es = parseescape(&p)) == CHAR_ERR) 403 return 0; 404 else 405 *b++ = (Char) es; 406 } 407 else 408 *b++ = *p & CHAR; 409 } 410 *b = 0; 411 buf->len = (int) (b - buf->buf); 412 return buf; 413 } 414 415 static void 416 print_all_keys() 417 { 418 int prev, i; 419 CStr nilstr; 420 nilstr.buf = NULL; 421 nilstr.len = 0; 422 423 424 xprintf(CGETS(20, 6, "Standard key bindings\n")); 425 prev = 0; 426 for (i = 0; i < 256; i++) { 427 if (CcKeyMap[prev] == CcKeyMap[i]) 428 continue; 429 printkeys(CcKeyMap, prev, i - 1); 430 prev = i; 431 } 432 printkeys(CcKeyMap, prev, i - 1); 433 434 xprintf(CGETS(20, 7, "Alternative key bindings\n")); 435 prev = 0; 436 for (i = 0; i < 256; i++) { 437 if (CcAltMap[prev] == CcAltMap[i]) 438 continue; 439 printkeys(CcAltMap, prev, i - 1); 440 prev = i; 441 } 442 printkeys(CcAltMap, prev, i - 1); 443 xprintf(CGETS(20, 8, "Multi-character bindings\n")); 444 PrintXkey(NULL); /* print all Xkey bindings */ 445 xprintf(CGETS(20, 9, "Arrow key bindings\n")); 446 PrintArrowKeys(&nilstr); 447 } 448 449 static void 450 printkeys(map, first, last) 451 KEYCMD *map; 452 int first, last; 453 { 454 struct KeyFuncs *fp; 455 Char firstbuf[2], lastbuf[2]; 456 CStr fb, lb; 457 unsigned char unparsbuf[10], extrabuf[10]; 458 fb.buf = firstbuf; 459 lb.buf = lastbuf; 460 461 firstbuf[0] = (Char) first; 462 firstbuf[1] = 0; 463 lastbuf[0] = (Char) last; 464 lastbuf[1] = 0; 465 fb.len = 1; 466 lb.len = 1; 467 468 if (map[first] == F_UNASSIGNED) { 469 if (first == last) 470 xprintf(CGETS(20, 10, "%-15s-> is undefined\n"), 471 unparsestring(&fb, unparsbuf, STRQQ)); 472 return; 473 } 474 475 for (fp = FuncNames; fp->name; fp++) { 476 if (fp->func == map[first]) { 477 if (first == last) { 478 xprintf("%-15s-> %s\n", 479 unparsestring(&fb, unparsbuf, STRQQ), fp->name); 480 } 481 else { 482 xprintf("%-4s to %-7s-> %s\n", 483 unparsestring(&fb, unparsbuf, STRQQ), 484 unparsestring(&lb, extrabuf, STRQQ), fp->name); 485 } 486 return; 487 } 488 } 489 if (map == CcKeyMap) { 490 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 491 unparsestring(&fb, unparsbuf, STRQQ)); 492 xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 493 } 494 else { 495 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 496 unparsestring(&fb, unparsbuf, STRQQ)); 497 xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 498 } 499 } 500 501 static void 502 bindkey_usage() 503 { 504 xprintf(CGETS(20, 12, 505 "Usage: bindkey [options] [--] [KEY [COMMAND]]\n")); 506 xprintf(CGETS(20, 13, 507 " -a list or bind KEY in alternative key map\n")); 508 xprintf(CGETS(20, 14, 509 " -b interpret KEY as a C-, M-, F- or X- key name\n")); 510 xprintf(CGETS(20, 15, 511 " -s interpret COMMAND as a literal string to be output\n")); 512 xprintf(CGETS(20, 16, 513 " -c interpret COMMAND as a builtin or external command\n")); 514 xprintf(CGETS(20, 17, 515 " -v bind all keys to vi bindings\n")); 516 xprintf(CGETS(20, 18, 517 " -e bind all keys to emacs bindings\n")); 518 xprintf(CGETS(20, 19, 519 " -d bind all keys to default editor's bindings\n")); 520 xprintf(CGETS(20, 20, 521 " -l list editor commands with descriptions\n")); 522 xprintf(CGETS(20, 21, 523 " -r remove KEY's binding\n")); 524 xprintf(CGETS(20, 22, 525 " -k interpret KEY as a symbolic arrow-key name\n")); 526 xprintf(CGETS(20, 23, 527 " -- force a break from option processing\n")); 528 xprintf(CGETS(20, 24, 529 " -u (or any invalid option) this message\n")); 530 xprintf("\n"); 531 xprintf(CGETS(20, 25, 532 "Without KEY or COMMAND, prints all bindings\n")); 533 xprintf(CGETS(20, 26, 534 "Without COMMAND, prints the binding for KEY.\n")); 535 } 536 537 static void 538 list_functions() 539 { 540 struct KeyFuncs *fp; 541 542 for (fp = FuncNames; fp->name; fp++) { 543 xprintf("%s\n %s\n", fp->name, fp->desc); 544 } 545 } 546 547 #ifdef OBSOLETE 548 549 /* 550 * Unfortunately the apollo optimizer does not like & operations 551 * with 0377, and produces illegal instructions. So we make it 552 * an unsigned char, and hope for the best. 553 * Of-course the compiler is smart enough to produce bad assembly 554 * language instructions, but dumb when it comes to fold the constant :-) 555 */ 556 #ifdef apollo 557 static unsigned char APOLLO_0377 = 0377; 558 #else /* sane */ 559 # define APOLLO_0377 0377 560 #endif /* apollo */ 561 562 static int 563 tocontrol(c) 564 int c; 565 { 566 c &= CHAR; 567 if (Islower(c)) 568 c = Toupper(c); 569 else if (c == ' ') 570 c = '@'; 571 if (c == '?') 572 c = CTL_ESC('\177'); 573 else 574 #ifdef IS_ASCII 575 c &= 037; 576 #else 577 /* EBCDIC: simulate ASCII-behavior by transforming to ASCII and back */ 578 c = _toebcdic[_toascii[c] & 037]; 579 #endif 580 return (c); 581 } 582 583 static char * 584 unparsekey(c) /* 'c' -> "c", '^C' -> "^" + "C" */ 585 int c; 586 { 587 char *cp; 588 static char tmp[10]; 589 590 cp = tmp; 591 592 if (c & 0400) { 593 *cp++ = 'A'; 594 *cp++ = '-'; 595 c &= APOLLO_0377; 596 } 597 if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) { 598 *cp++ = 'M'; 599 *cp++ = '-'; 600 c &= ASCII; 601 } 602 if (Isprint(c)) { 603 *cp++ = (char) c; 604 *cp = '\0'; 605 return (tmp); 606 } 607 switch (c) { 608 case ' ': 609 (void) strcpy(cp, "Spc"); 610 return (tmp); 611 case '\n': 612 (void) strcpy(cp, "Lfd"); 613 return (tmp); 614 case '\r': 615 (void) strcpy(cp, "Ret"); 616 return (tmp); 617 case '\t': 618 (void) strcpy(cp, "Tab"); 619 return (tmp); 620 #ifdef IS_ASCII 621 case '\033': 622 (void) strcpy(cp, "Esc"); 623 return (tmp); 624 case '\177': 625 (void) strcpy(cp, "Del"); 626 return (tmp); 627 default: 628 *cp++ = '^'; 629 if (c == '\177') { 630 *cp++ = '?'; 631 } 632 else { 633 *cp++ = c | 0100; 634 } 635 *cp = '\0'; 636 return (tmp); 637 #else /* IS_ASCII */ 638 default: 639 if (*cp == CTL_ESC('\033')) { 640 (void) strcpy(cp, "Esc"); 641 return (tmp); 642 } 643 else if (*cp == CTL_ESC('\177')) { 644 (void) strcpy(cp, "Del"); 645 return (tmp); 646 } 647 else if (Isupper(_toebcdic[_toascii[c]|0100]) 648 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) { 649 *cp++ = '^'; 650 *cp++ = _toebcdic[_toascii[c]|0100] 651 } 652 else { 653 xsnprintf(cp, 3, "\\%3.3o", c); 654 cp += 4; 655 } 656 #endif /* IS_ASCII */ 657 } 658 } 659 660 static KEYCMD 661 getkeycmd(sp) 662 Char **sp; 663 { 664 Char *s = *sp; 665 char c; 666 KEYCMD keycmd = F_UNASSIGNED; 667 KEYCMD *map; 668 int meta = 0; 669 Char *ret_sp = s; 670 671 map = CcKeyMap; 672 673 while (*s) { 674 if (*s == '^' && s[1]) { 675 s++; 676 c = tocontrol(*s++); 677 } 678 else 679 c = *s++; 680 681 if (*s == '\0') 682 break; 683 684 switch (map[c | meta]) { 685 case F_METANEXT: 686 meta = META; 687 keycmd = F_METANEXT; 688 ret_sp = s; 689 break; 690 691 case F_XKEY: 692 keycmd = F_XKEY; 693 ret_sp = s; 694 /* FALLTHROUGH */ 695 696 default: 697 *sp = ret_sp; 698 return (keycmd); 699 700 } 701 } 702 *sp = ret_sp; 703 return (keycmd); 704 } 705 706 static int 707 parsekey(sp) 708 Char **sp; /* Return position of first unparsed character 709 * for return value -2 (xkeynext) */ 710 { 711 int c, meta = 0, control = 0, ctrlx = 0; 712 Char *s = *sp; 713 KEYCMD keycmd; 714 715 if (s == NULL) { 716 xprintf(CGETS(20, 27, "bad key specification -- null string\n")); 717 return -1; 718 } 719 if (*s == 0) { 720 xprintf(CGETS(20, 28, "bad key specification -- empty string\n")); 721 return -1; 722 } 723 724 (void) strip(s); /* trim to 7 bits. */ 725 726 if (s[1] == 0) /* single char */ 727 return (s[0] & APOLLO_0377); 728 729 if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') { 730 if (s[2] == 0) { 731 xprintf(CGETS(20, 29, 732 "Bad function-key specification. Null key not allowed\n")); 733 return (-1); 734 } 735 *sp = s + 2; 736 return (-2); 737 } 738 739 if (s[0] == '0' && s[1] == 'x') { /* if 0xn, then assume number */ 740 c = 0; 741 for (s += 2; *s; s++) { /* convert to hex; skip the first 0 */ 742 c *= 16; 743 if (!Isxdigit(*s)) { 744 xprintf(CGETS(20, 30, 745 "bad key specification -- malformed hex number\n")); 746 return -1; /* error */ 747 } 748 if (Isdigit(*s)) 749 c += *s - '0'; 750 else if (*s >= 'a' && *s <= 'f') 751 c += *s - 'a' + 0xA; 752 else if (*s >= 'F' && *s <= 'F') 753 c += *s - 'A' + 0xA; 754 } 755 } 756 else if (s[0] == '0' && Isdigit(s[1])) { /* if 0n, then assume number */ 757 c = 0; 758 for (s++; *s; s++) { /* convert to octal; skip the first 0 */ 759 if (!Isdigit(*s) || *s == '8' || *s == '9') { 760 xprintf(CGETS(20, 31, 761 "bad key specification -- malformed octal number\n")); 762 return -1; /* error */ 763 } 764 c = (c * 8) + *s - '0'; 765 } 766 } 767 else if (Isdigit(s[0]) && Isdigit(s[1])) { /* decimal number */ 768 c = 0; 769 for (; *s; s++) { /* convert to octal; skip the first 0 */ 770 if (!Isdigit(*s)) { 771 xprintf(CGETS(20, 32, 772 "bad key specification -- malformed decimal number\n")); 773 return -1; /* error */ 774 } 775 c = (c * 10) + *s - '0'; 776 } 777 } 778 else { 779 keycmd = getkeycmd(&s); 780 781 if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') { /* X- */ 782 ctrlx++; 783 s += 2; 784 keycmd = getkeycmd(&s); 785 } 786 if ((*s == 'm' || *s == 'M') && s[1] == '-') { /* meta */ 787 meta++; 788 s += 2; 789 keycmd = getkeycmd(&s); 790 } 791 else if (keycmd == F_METANEXT && *s) { /* meta */ 792 meta++; 793 keycmd = getkeycmd(&s); 794 } 795 if (*s == '^' && s[1]) { 796 control++; 797 s++; 798 keycmd = getkeycmd(&s); 799 } 800 else if ((*s == 'c' || *s == 'C') && s[1] == '-') { /* control */ 801 control++; 802 s += 2; 803 keycmd = getkeycmd(&s); 804 } 805 806 if (keycmd == F_XKEY) { 807 if (*s == 0) { 808 xprintf(CGETS(20, 33, 809 "Bad function-key specification.\n")); 810 xprintf(CGETS(20, 34, "Null key not allowed\n")); 811 return (-1); 812 } 813 *sp = s; 814 return (-2); 815 } 816 817 if (s[1] != 0) { /* if symbolic name */ 818 char *ts; 819 820 ts = short2str(s); 821 if (!strcmp(ts, "space") || !strcmp(ts, "Spc")) 822 c = ' '; 823 else if (!strcmp(ts, "return") || !strcmp(ts, "Ret")) 824 c = '\r'; 825 else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd")) 826 c = '\n'; 827 else if (!strcmp(ts, "linefeed")) 828 c = '\n'; 829 else if (!strcmp(ts, "tab")) 830 c = '\t'; 831 else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc")) 832 c = CTL_ESC('\033'); 833 else if (!strcmp(ts, "backspace")) 834 c = '\b'; 835 else if (!strcmp(ts, "delete")) 836 c = CTL_ESC('\177'); 837 else { 838 xprintf(CGETS(20, 35, 839 "bad key specification -- unknown name \"%S\"\n"), s); 840 return -1; /* error */ 841 } 842 } 843 else 844 c = *s; /* just a single char */ 845 846 if (control) 847 c = tocontrol(c); 848 if (meta) 849 c |= META; 850 if (ctrlx) 851 c |= 0400; 852 } 853 return (c & 0777); 854 } 855 856 857 /*ARGSUSED*/ 858 void 859 dobind(v, dummy) 860 Char **v; 861 struct command *dummy; 862 { 863 int c; 864 struct KeyFuncs *fp; 865 int i, prev; 866 Char *p, *l; 867 CStr cstr; 868 Char buf[1000]; 869 870 USE(dummy); 871 /* 872 * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name, 873 * and the key; or 'bind' key to print the func for that key. 874 */ 875 876 if (!MapsAreInited) 877 ed_InitMaps(); 878 879 if (v[1] && v[2] && v[3]) { 880 xprintf(CGETS(20, 36, 881 "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n")); 882 return; 883 } 884 885 if (v[1] && v[2]) { /* if bind FUNCTION KEY */ 886 for (fp = FuncNames; fp->name; fp++) { 887 if (strcmp(short2str(v[1]), fp->name) == 0) { 888 Char *s = v[2]; 889 890 if ((c = parsekey(&s)) == -1) 891 return; 892 if (c == -2) { /* extended key */ 893 for (i = 0; i < 256; i++) { 894 if (i != CTL_ESC('\033') && (CcKeyMap[i] == F_XKEY || 895 CcAltMap[i] == F_XKEY)) { 896 p = buf; 897 #ifdef IS_ASCII 898 if (i > 0177) { 899 *p++ = 033; 900 *p++ = i & ASCII; 901 } 902 else { 903 *p++ = (Char) i; 904 } 905 #else 906 *p++ = (Char) i; 907 #endif 908 for (l = s; *l != 0; l++) { 909 *p++ = *l; 910 } 911 *p = 0; 912 cstr.buf = buf; 913 cstr.len = Strlen(buf); 914 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 915 } 916 } 917 return; 918 } 919 if (c & 0400) { 920 if (VImode) { 921 CcAltMap[c & APOLLO_0377] = fp->func; 922 /* bind the vi cmd mode key */ 923 if (c & META) { 924 buf[0] = CTL_ESC('\033'); 925 buf[1] = c & ASCII; 926 buf[2] = 0; 927 cstr.buf = buf; 928 cstr.len = Strlen(buf); 929 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 930 } 931 } 932 else { 933 buf[0] = CTL_ESC('\030'); /* ^X */ 934 buf[1] = c & APOLLO_0377; 935 buf[2] = 0; 936 cstr.buf = buf; 937 cstr.len = Strlen(buf); 938 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 939 CcKeyMap[CTL_ESC('\030')] = F_XKEY; 940 } 941 } 942 else { 943 CcKeyMap[c] = fp->func; /* bind the key */ 944 if (c & META) { 945 buf[0] = CTL_ESC('\033'); 946 buf[1] = c & ASCII; 947 buf[2] = 0; 948 cstr.buf = buf; 949 cstr.len = Strlen(buf); 950 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 951 } 952 } 953 return; 954 } 955 } 956 stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function")); 957 } 958 else if (v[1]) { 959 char *cv = short2str(v[1]); 960 961 if (strcmp(cv, "list") == 0) { 962 for (fp = FuncNames; fp->name; fp++) { 963 xprintf("%s\n", fp->name); 964 } 965 return; 966 } 967 if ((strcmp(cv, "emacs") == 0) || 968 #ifndef VIDEFAULT 969 (strcmp(cv, "defaults") == 0) || 970 (strcmp(cv, "default") == 0) || 971 #endif 972 (strcmp(cv, "mg") == 0) || 973 (strcmp(cv, "gnumacs") == 0)) { 974 /* reset keys to default */ 975 ed_InitEmacsMaps(); 976 #ifdef VIDEFAULT 977 } 978 else if ((strcmp(cv, "vi") == 0) 979 || (strcmp(cv, "default") == 0) 980 || (strcmp(cv, "defaults") == 0)) { 981 #else 982 } 983 else if (strcmp(cv, "vi") == 0) { 984 #endif 985 ed_InitVIMaps(); 986 } 987 else { /* want to know what this key does */ 988 Char *s = v[1]; 989 990 if ((c = parsekey(&s)) == -1) 991 return; 992 if (c == -2) { /* extended key */ 993 cstr.buf = s; 994 cstr.len = Strlen(s); 995 PrintXkey(&cstr); 996 return; 997 } 998 pkeys(c, c); /* must be regular key */ 999 } 1000 } 1001 else { /* list all the bindings */ 1002 prev = 0; 1003 for (i = 0; i < 256; i++) { 1004 if (CcKeyMap[prev] == CcKeyMap[i]) 1005 continue; 1006 pkeys(prev, i - 1); 1007 prev = i; 1008 } 1009 pkeys(prev, i - 1); 1010 prev = 0; 1011 for (i = 256; i < 512; i++) { 1012 if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377]) 1013 continue; 1014 pkeys(prev, i - 1); 1015 prev = i; 1016 } 1017 pkeys(prev, i - 1); 1018 cstr.buf = NULL; 1019 cstr.len = 0; 1020 PrintXkey(&cstr); /* print all Xkey bindings */ 1021 } 1022 return; 1023 } 1024 1025 static void 1026 pkeys(first, last) 1027 int first, last; 1028 { 1029 struct KeyFuncs *fp; 1030 KEYCMD *map; 1031 int mask; 1032 char buf[8]; 1033 1034 if (last & 0400) { 1035 map = CcAltMap; 1036 first &= APOLLO_0377; 1037 last &= APOLLO_0377; 1038 mask = 0400; 1039 } 1040 else { 1041 map = CcKeyMap; 1042 mask = 0; 1043 } 1044 if (map[first] == F_UNASSIGNED) { 1045 if (first == last) 1046 xprintf(CGETS(20, 38, " %s\t\tis undefined\n"), 1047 unparsekey(first | mask)); 1048 return; 1049 } 1050 1051 for (fp = FuncNames; fp->name; fp++) { 1052 if (fp->func == map[first]) { 1053 if (first == last) 1054 xprintf(" %s\t\t%s\n", 1055 unparsekey((first & APOLLO_0377) | mask), fp->name); 1056 else { 1057 (void) strcpy(buf, unparsekey((first & APOLLO_0377) | mask)); 1058 xprintf(" %s..%s\t\t%s\n", buf, 1059 unparsekey((last & APOLLO_0377) | mask), fp->name); 1060 } 1061 return; 1062 } 1063 } 1064 if (map == CcKeyMap) { 1065 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 1066 unparsekey(first)); 1067 xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 1068 } 1069 else { 1070 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 1071 unparsekey(first & 0400)); 1072 xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 1073 } 1074 } 1075 #endif /* OBSOLETE */ 1076