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