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