1 /* $Header: /src/pub/tcsh/tc.bind.c,v 3.33 1998/11/24 18:17:40 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.33 1998/11/24 18:17:40 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 #ifndef _OSD_POSIX 296 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 297 #else /*_OSD_POSIX*/ 298 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 299 #endif /*_OSD_POSIX*/ 300 *b = '\0'; 301 break; 302 303 case 'F': 304 case 'M': 305 case 'X': 306 case 'C': 307 #ifdef WINNT 308 case 'N': 309 #endif /* WINNT */ 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 #ifndef _OSD_POSIX 325 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237); 326 #else /*_OSD_POSIX*/ 327 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237]; 328 #endif /*_OSD_POSIX*/ 329 *b = '\0'; 330 break; 331 332 case 'X' : case 'x': /* Turn into ^Xc */ 333 #ifndef _OSD_POSIX 334 *b++ = 'X' & 0237; 335 #else /*_OSD_POSIX*/ 336 *b++ = _toebcdic[_toascii['X'] & 0237]; 337 #endif /*_OSD_POSIX*/ 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 #ifndef _OSD_POSIX 350 *b++ = *s | 0x80; 351 #else /*_OSD_POSIX*/ 352 *b++ = _toebcdic[_toascii[*s] | 0x80]; 353 #endif /*_OSD_POSIX*/ 354 #ifdef DSPMBYTE 355 } 356 #endif /* DSPMBYTE */ 357 *b = '\0'; 358 break; 359 #ifdef WINNT 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 */ 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 #ifndef _OSD_POSIX 580 c &= 037; 581 #else /* EBCDIC: simulate ASCII-behavior by transforming to ASCII and back */ 582 c = _toebcdic[_toascii[c] & 037]; 583 #endif 584 return (c); 585 } 586 587 static char * 588 unparsekey(c) /* 'c' -> "c", '^C' -> "^" + "C" */ 589 register int c; 590 { 591 register char *cp; 592 static char tmp[10]; 593 594 cp = tmp; 595 596 if (c & 0400) { 597 *cp++ = 'A'; 598 *cp++ = '-'; 599 c &= APOLLO_0377; 600 } 601 if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) { 602 *cp++ = 'M'; 603 *cp++ = '-'; 604 c &= ASCII; 605 } 606 if (Isprint(c)) { 607 *cp++ = (char) c; 608 *cp = '\0'; 609 return (tmp); 610 } 611 switch (c) { 612 case ' ': 613 (void) strcpy(cp, "Spc"); 614 return (tmp); 615 case '\n': 616 (void) strcpy(cp, "Lfd"); 617 return (tmp); 618 case '\r': 619 (void) strcpy(cp, "Ret"); 620 return (tmp); 621 case '\t': 622 (void) strcpy(cp, "Tab"); 623 return (tmp); 624 #ifndef _OSD_POSIX 625 case '\033': 626 (void) strcpy(cp, "Esc"); 627 return (tmp); 628 case '\177': 629 (void) strcpy(cp, "Del"); 630 return (tmp); 631 default: 632 *cp++ = '^'; 633 if (c == '\177') { 634 *cp++ = '?'; 635 } 636 else { 637 *cp++ = c | 0100; 638 } 639 *cp = '\0'; 640 return (tmp); 641 #else /*_OSD_POSIX*/ 642 default: 643 if (*cp == CTL_ESC('\033')) { 644 (void) strcpy(cp, "Esc"); 645 return (tmp); 646 } 647 else if (*cp == CTL_ESC('\177')) { 648 (void) strcpy(cp, "Del"); 649 return (tmp); 650 } 651 else if (Isupper(_toebcdic[_toascii[c]|0100]) 652 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) { 653 *cp++ = '^'; 654 *cp++ = _toebcdic[_toascii[c]|0100] 655 } 656 else { 657 xsnprintf(cp, 3, "\\%3.3o", c); 658 cp += 4; 659 } 660 #endif /*_OSD_POSIX*/ 661 } 662 } 663 664 static KEYCMD 665 getkeycmd(sp) 666 Char **sp; 667 { 668 register Char *s = *sp; 669 register char c; 670 register KEYCMD keycmd = F_UNASSIGNED; 671 KEYCMD *map; 672 int meta = 0; 673 Char *ret_sp = s; 674 675 map = CcKeyMap; 676 677 while (*s) { 678 if (*s == '^' && s[1]) { 679 s++; 680 c = tocontrol(*s++); 681 } 682 else 683 c = *s++; 684 685 if (*s == '\0') 686 break; 687 688 switch (map[c | meta]) { 689 case F_METANEXT: 690 meta = META; 691 keycmd = F_METANEXT; 692 ret_sp = s; 693 break; 694 695 case F_XKEY: 696 keycmd = F_XKEY; 697 ret_sp = s; 698 /* FALLTHROUGH */ 699 700 default: 701 *sp = ret_sp; 702 return (keycmd); 703 704 } 705 } 706 *sp = ret_sp; 707 return (keycmd); 708 } 709 710 static int 711 parsekey(sp) 712 Char **sp; /* Return position of first unparsed character 713 * for return value -2 (xkeynext) */ 714 { 715 register int c, meta = 0, control = 0, ctrlx = 0; 716 Char *s = *sp; 717 KEYCMD keycmd; 718 719 if (s == NULL) { 720 xprintf(CGETS(20, 27, "bad key specification -- null string\n")); 721 return -1; 722 } 723 if (*s == 0) { 724 xprintf(CGETS(20, 28, "bad key specification -- empty string\n")); 725 return -1; 726 } 727 728 (void) strip(s); /* trim to 7 bits. */ 729 730 if (s[1] == 0) /* single char */ 731 return (s[0] & APOLLO_0377); 732 733 if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') { 734 if (s[2] == 0) { 735 xprintf(CGETS(20, 29, 736 "Bad function-key specification. Null key not allowed\n")); 737 return (-1); 738 } 739 *sp = s + 2; 740 return (-2); 741 } 742 743 if (s[0] == '0' && s[1] == 'x') { /* if 0xn, then assume number */ 744 c = 0; 745 for (s += 2; *s; s++) { /* convert to hex; skip the first 0 */ 746 c *= 16; 747 if (!Isxdigit(*s)) { 748 xprintf(CGETS(20, 30, 749 "bad key specification -- malformed hex number\n")); 750 return -1; /* error */ 751 } 752 if (Isdigit(*s)) 753 c += *s - '0'; 754 else if (*s >= 'a' && *s <= 'f') 755 c += *s - 'a' + 0xA; 756 else if (*s >= 'F' && *s <= 'F') 757 c += *s - 'A' + 0xA; 758 } 759 } 760 else if (s[0] == '0' && Isdigit(s[1])) { /* if 0n, then assume number */ 761 c = 0; 762 for (s++; *s; s++) { /* convert to octal; skip the first 0 */ 763 if (!Isdigit(*s) || *s == '8' || *s == '9') { 764 xprintf(CGETS(20, 31, 765 "bad key specification -- malformed octal number\n")); 766 return -1; /* error */ 767 } 768 c = (c * 8) + *s - '0'; 769 } 770 } 771 else if (Isdigit(s[0]) && Isdigit(s[1])) { /* decimal number */ 772 c = 0; 773 for (; *s; s++) { /* convert to octal; skip the first 0 */ 774 if (!Isdigit(*s)) { 775 xprintf(CGETS(20, 32, 776 "bad key specification -- malformed decimal number\n")); 777 return -1; /* error */ 778 } 779 c = (c * 10) + *s - '0'; 780 } 781 } 782 else { 783 keycmd = getkeycmd(&s); 784 785 if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') { /* X- */ 786 ctrlx++; 787 s += 2; 788 keycmd = getkeycmd(&s); 789 } 790 if ((*s == 'm' || *s == 'M') && s[1] == '-') { /* meta */ 791 meta++; 792 s += 2; 793 keycmd = getkeycmd(&s); 794 } 795 else if (keycmd == F_METANEXT && *s) { /* meta */ 796 meta++; 797 keycmd = getkeycmd(&s); 798 } 799 if (*s == '^' && s[1]) { 800 control++; 801 s++; 802 keycmd = getkeycmd(&s); 803 } 804 else if ((*s == 'c' || *s == 'C') && s[1] == '-') { /* control */ 805 control++; 806 s += 2; 807 keycmd = getkeycmd(&s); 808 } 809 810 if (keycmd == F_XKEY) { 811 if (*s == 0) { 812 xprintf(CGETS(20, 33, 813 "Bad function-key specification.\n")); 814 xprintf(CGETS(20, 34, "Null key not allowed\n")); 815 return (-1); 816 } 817 *sp = s; 818 return (-2); 819 } 820 821 if (s[1] != 0) { /* if symbolic name */ 822 char *ts; 823 824 ts = short2str(s); 825 if (!strcmp(ts, "space") || !strcmp(ts, "Spc")) 826 c = ' '; 827 else if (!strcmp(ts, "return") || !strcmp(ts, "Ret")) 828 c = '\r'; 829 else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd")) 830 c = '\n'; 831 else if (!strcmp(ts, "linefeed")) 832 c = '\n'; 833 else if (!strcmp(ts, "tab")) 834 c = '\t'; 835 else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc")) 836 c = CTL_ESC('\033'); 837 else if (!strcmp(ts, "backspace")) 838 c = '\b'; 839 else if (!strcmp(ts, "delete")) 840 c = CTL_ESC('\177'); 841 else { 842 xprintf(CGETS(20, 35, 843 "bad key specification -- unknown name \"%S\"\n"), s); 844 return -1; /* error */ 845 } 846 } 847 else 848 c = *s; /* just a single char */ 849 850 if (control) 851 c = tocontrol(c); 852 if (meta) 853 c |= META; 854 if (ctrlx) 855 c |= 0400; 856 } 857 return (c & 0777); 858 } 859 860 861 /*ARGSUSED*/ 862 void 863 dobind(v, dummy) 864 register Char **v; 865 struct command *dummy; 866 { 867 register int c; 868 register struct KeyFuncs *fp; 869 register int i, prev; 870 Char *p, *l; 871 CStr cstr; 872 Char buf[1000]; 873 874 USE(dummy); 875 /* 876 * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name, 877 * and the key; or 'bind' key to print the func for that key. 878 */ 879 880 if (!MapsAreInited) 881 ed_InitMaps(); 882 883 if (v[1] && v[2] && v[3]) { 884 xprintf(CGETS(20, 36, 885 "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n")); 886 return; 887 } 888 889 if (v[1] && v[2]) { /* if bind FUNCTION KEY */ 890 for (fp = FuncNames; fp->name; fp++) { 891 if (strcmp(short2str(v[1]), fp->name) == 0) { 892 Char *s = v[2]; 893 894 if ((c = parsekey(&s)) == -1) 895 return; 896 if (c == -2) { /* extended key */ 897 for (i = 0; i < 256; i++) { 898 if (i != CTL_ESC('\033') && (CcKeyMap[i] == F_XKEY || 899 CcAltMap[i] == F_XKEY)) { 900 p = buf; 901 #ifndef _OSD_POSIX /* this is only for ASCII, not for EBCDIC */ 902 if (i > 0177) { 903 *p++ = 033; 904 *p++ = i & ASCII; 905 } 906 else { 907 *p++ = (Char) i; 908 } 909 #else /*_OSD_POSIX*/ 910 *p++ = (Char) i; 911 #endif /*_OSD_POSIX*/ 912 for (l = s; *l != 0; l++) { 913 *p++ = *l; 914 } 915 *p = 0; 916 cstr.buf = buf; 917 cstr.len = Strlen(buf); 918 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 919 } 920 } 921 return; 922 } 923 if (c & 0400) { 924 if (VImode) { 925 CcAltMap[c & APOLLO_0377] = fp->func; 926 /* bind the vi cmd mode key */ 927 if (c & META) { 928 buf[0] = CTL_ESC('\033'); 929 buf[1] = c & ASCII; 930 buf[2] = 0; 931 cstr.buf = buf; 932 cstr.len = Strlen(buf); 933 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 934 } 935 } 936 else { 937 buf[0] = CTL_ESC('\030'); /* ^X */ 938 buf[1] = c & APOLLO_0377; 939 buf[2] = 0; 940 cstr.buf = buf; 941 cstr.len = Strlen(buf); 942 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 943 CcKeyMap[CTL_ESC('\030')] = F_XKEY; 944 } 945 } 946 else { 947 CcKeyMap[c] = fp->func; /* bind the key */ 948 if (c & META) { 949 buf[0] = CTL_ESC('\033'); 950 buf[1] = c & ASCII; 951 buf[2] = 0; 952 cstr.buf = buf; 953 cstr.len = Strlen(buf); 954 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD); 955 } 956 } 957 return; 958 } 959 } 960 stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function")); 961 } 962 else if (v[1]) { 963 char *cv = short2str(v[1]); 964 965 if (strcmp(cv, "list") == 0) { 966 for (fp = FuncNames; fp->name; fp++) { 967 xprintf("%s\n", fp->name); 968 } 969 return; 970 } 971 if ((strcmp(cv, "emacs") == 0) || 972 #ifndef VIDEFAULT 973 (strcmp(cv, "defaults") == 0) || 974 (strcmp(cv, "default") == 0) || 975 #endif 976 (strcmp(cv, "mg") == 0) || 977 (strcmp(cv, "gnumacs") == 0)) { 978 /* reset keys to default */ 979 ed_InitEmacsMaps(); 980 #ifdef VIDEFAULT 981 } 982 else if ((strcmp(cv, "vi") == 0) 983 || (strcmp(cv, "default") == 0) 984 || (strcmp(cv, "defaults") == 0)) { 985 #else 986 } 987 else if (strcmp(cv, "vi") == 0) { 988 #endif 989 ed_InitVIMaps(); 990 } 991 else { /* want to know what this key does */ 992 Char *s = v[1]; 993 994 if ((c = parsekey(&s)) == -1) 995 return; 996 if (c == -2) { /* extended key */ 997 cstr.buf = s; 998 cstr.len = Strlen(s); 999 PrintXkey(&cstr); 1000 return; 1001 } 1002 pkeys(c, c); /* must be regular key */ 1003 } 1004 } 1005 else { /* list all the bindings */ 1006 prev = 0; 1007 for (i = 0; i < 256; i++) { 1008 if (CcKeyMap[prev] == CcKeyMap[i]) 1009 continue; 1010 pkeys(prev, i - 1); 1011 prev = i; 1012 } 1013 pkeys(prev, i - 1); 1014 prev = 0; 1015 for (i = 256; i < 512; i++) { 1016 if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377]) 1017 continue; 1018 pkeys(prev, i - 1); 1019 prev = i; 1020 } 1021 pkeys(prev, i - 1); 1022 cstr.buf = NULL; 1023 cstr.len = 0; 1024 PrintXkey(&cstr); /* print all Xkey bindings */ 1025 } 1026 return; 1027 } 1028 1029 static void 1030 pkeys(first, last) 1031 register int first, last; 1032 { 1033 register struct KeyFuncs *fp; 1034 register KEYCMD *map; 1035 int mask; 1036 char buf[8]; 1037 1038 if (last & 0400) { 1039 map = CcAltMap; 1040 first &= APOLLO_0377; 1041 last &= APOLLO_0377; 1042 mask = 0400; 1043 } 1044 else { 1045 map = CcKeyMap; 1046 mask = 0; 1047 } 1048 if (map[first] == F_UNASSIGNED) { 1049 if (first == last) 1050 xprintf(CGETS(20, 38, " %s\t\tis undefined\n"), 1051 unparsekey(first | mask)); 1052 return; 1053 } 1054 1055 for (fp = FuncNames; fp->name; fp++) { 1056 if (fp->func == map[first]) { 1057 if (first == last) 1058 xprintf(" %s\t\t%s\n", 1059 unparsekey((first & APOLLO_0377) | mask), fp->name); 1060 else { 1061 (void) strcpy(buf, unparsekey((first & APOLLO_0377) | mask)); 1062 xprintf(" %s..%s\t\t%s\n", buf, 1063 unparsekey((last & APOLLO_0377) | mask), fp->name); 1064 } 1065 return; 1066 } 1067 } 1068 if (map == CcKeyMap) { 1069 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 1070 unparsekey(first)); 1071 xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]); 1072 } 1073 else { 1074 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), 1075 unparsekey(first & 0400)); 1076 xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]); 1077 } 1078 } 1079 #endif /* OBSOLETE */ 1080