1 /* $Header: /src/pub/tcsh/tc.bind.c,v 3.39 2005/03/25 18:46:41 kim Exp $ */
3 * tc.bind.c: Key binding functions
6 * Copyright (c) 1980, 1991 The Regents of the University of California.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
35 RCSID("$Id: tc.bind.c,v 3.39 2005/03/25 18:46:41 kim Exp $")
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));
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));
58 extern int MapsAreInited;
70 int ntype, no, removeb, key, bindk;
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)) == '-') {
126 #else /* EMACSDEFAULT */
128 #endif /* VIDEFAULT */
145 if (!IsArrowKey(v[no]))
146 xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
148 in.len = Strlen(in.buf);
152 if (parsebind(v[no++], &in) == NULL)
156 if (parsestring(v[no++], &in) == NULL)
162 if (in.buf[0] > 0xFF) {
167 ch = (uChar) in.buf[0];
171 (void) ClearArrowKeys(&in);
175 (void) DeleteXkey(&in);
177 else if (map[ch] == F_XKEY) {
178 (void) DeleteXkey(&in);
179 map[ch] = F_UNASSIGNED;
182 map[ch] = F_UNASSIGNED;
200 if (parsestring(v[no], &out) == NULL)
203 if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
204 xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf);
207 AddXkey(&in, XmapStr(&out), ntype);
211 if ((cmd = parsecmd(v[no])) == 0)
214 (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
217 AddXkey(&in, XmapCmd((int) cmd), ntype);
239 unsigned char outbuf[100];
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);
260 for (fp = FuncNames; fp->name; fp++) {
261 if (strcmp(short2str(str), fp->name) == 0) {
262 return (KEYCMD) fp->func;
265 xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
274 xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
287 str->len = (int) (b - str->buf);
295 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237);
297 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237];
308 #endif /* WINNT_NATIVE */
309 if (s[1] != '-' || s[2] == '\0') {
315 case 'F': case 'f': /* Turn into ^[str */
316 *b++ = CTL_ESC('\033');
317 while ((*b++ = *s++) != '\0')
322 case 'C': case 'c': /* Turn into ^c */
324 *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237);
326 *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237];
331 case 'X' : case 'x': /* Turn into ^Xc */
335 *b++ = _toebcdic[_toascii['X'] & 0237];
341 case 'M' : case 'm': /* Turn into 0x80|c */
343 *b++ = CTL_ESC('\033');
349 *b++ = _toebcdic[_toascii[*s] | 0x80];
355 case 'N' : case 'n': /* NT */
359 bnt = nt_translate_bindkey(s);
366 #endif /* WINNT_NATIVE */
380 str->len = (int) (b - str->buf);
386 parsestring(str, buf)
396 xprintf(CGETS(20, 5, "Null string specification\n"));
400 for (p = str; *p != 0; p++) {
401 if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
402 if ((es = parseescape(&p)) == CHAR_ERR)
411 buf->len = (int) (b - buf->buf);
424 xprintf(CGETS(20, 6, "Standard key bindings\n"));
426 for (i = 0; i < 256; i++) {
427 if (CcKeyMap[prev] == CcKeyMap[i])
429 printkeys(CcKeyMap, prev, i - 1);
432 printkeys(CcKeyMap, prev, i - 1);
434 xprintf(CGETS(20, 7, "Alternative key bindings\n"));
436 for (i = 0; i < 256; i++) {
437 if (CcAltMap[prev] == CcAltMap[i])
439 printkeys(CcAltMap, prev, i - 1);
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);
450 printkeys(map, first, last)
455 Char firstbuf[2], lastbuf[2];
457 unsigned char unparsbuf[10], extrabuf[10];
461 firstbuf[0] = (Char) first;
463 lastbuf[0] = (Char) last;
468 if (map[first] == F_UNASSIGNED) {
470 xprintf(CGETS(20, 10, "%-15s-> is undefined\n"),
471 unparsestring(&fb, unparsbuf, STRQQ));
475 for (fp = FuncNames; fp->name; fp++) {
476 if (fp->func == map[first]) {
478 xprintf("%-15s-> %s\n",
479 unparsestring(&fb, unparsbuf, STRQQ), fp->name);
482 xprintf("%-4s to %-7s-> %s\n",
483 unparsestring(&fb, unparsbuf, STRQQ),
484 unparsestring(&lb, extrabuf, STRQQ), fp->name);
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]);
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]);
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"));
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"));
542 for (fp = FuncNames; fp->name; fp++) {
543 xprintf("%s\n %s\n", fp->name, fp->desc);
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 :-)
557 static unsigned char APOLLO_0377 = 0377;
559 # define APOLLO_0377 0377
577 /* EBCDIC: simulate ASCII-behavior by transforming to ASCII and back */
578 c = _toebcdic[_toascii[c] & 037];
584 unparsekey(c) /* 'c' -> "c", '^C' -> "^" + "C" */
597 if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) {
609 (void) strcpy(cp, "Spc");
612 (void) strcpy(cp, "Lfd");
615 (void) strcpy(cp, "Ret");
618 (void) strcpy(cp, "Tab");
622 (void) strcpy(cp, "Esc");
625 (void) strcpy(cp, "Del");
639 if (*cp == CTL_ESC('\033')) {
640 (void) strcpy(cp, "Esc");
643 else if (*cp == CTL_ESC('\177')) {
644 (void) strcpy(cp, "Del");
647 else if (Isupper(_toebcdic[_toascii[c]|0100])
648 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) {
650 *cp++ = _toebcdic[_toascii[c]|0100]
653 xsnprintf(cp, 3, "\\%3.3o", c);
656 #endif /* IS_ASCII */
666 KEYCMD keycmd = F_UNASSIGNED;
674 if (*s == '^' && s[1]) {
684 switch (map[c | meta]) {
708 Char **sp; /* Return position of first unparsed character
709 * for return value -2 (xkeynext) */
711 int c, meta = 0, control = 0, ctrlx = 0;
716 xprintf(CGETS(20, 27, "bad key specification -- null string\n"));
720 xprintf(CGETS(20, 28, "bad key specification -- empty string\n"));
724 (void) strip(s); /* trim to 7 bits. */
726 if (s[1] == 0) /* single char */
727 return (s[0] & APOLLO_0377);
729 if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') {
731 xprintf(CGETS(20, 29,
732 "Bad function-key specification. Null key not allowed\n"));
739 if (s[0] == '0' && s[1] == 'x') { /* if 0xn, then assume number */
741 for (s += 2; *s; s++) { /* convert to hex; skip the first 0 */
744 xprintf(CGETS(20, 30,
745 "bad key specification -- malformed hex number\n"));
746 return -1; /* error */
750 else if (*s >= 'a' && *s <= 'f')
752 else if (*s >= 'F' && *s <= 'F')
756 else if (s[0] == '0' && Isdigit(s[1])) { /* if 0n, then assume number */
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 */
764 c = (c * 8) + *s - '0';
767 else if (Isdigit(s[0]) && Isdigit(s[1])) { /* decimal number */
769 for (; *s; s++) { /* convert to octal; skip the first 0 */
771 xprintf(CGETS(20, 32,
772 "bad key specification -- malformed decimal number\n"));
773 return -1; /* error */
775 c = (c * 10) + *s - '0';
779 keycmd = getkeycmd(&s);
781 if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') { /* X- */
784 keycmd = getkeycmd(&s);
786 if ((*s == 'm' || *s == 'M') && s[1] == '-') { /* meta */
789 keycmd = getkeycmd(&s);
791 else if (keycmd == F_METANEXT && *s) { /* meta */
793 keycmd = getkeycmd(&s);
795 if (*s == '^' && s[1]) {
798 keycmd = getkeycmd(&s);
800 else if ((*s == 'c' || *s == 'C') && s[1] == '-') { /* control */
803 keycmd = getkeycmd(&s);
806 if (keycmd == F_XKEY) {
808 xprintf(CGETS(20, 33,
809 "Bad function-key specification.\n"));
810 xprintf(CGETS(20, 34, "Null key not allowed\n"));
817 if (s[1] != 0) { /* if symbolic name */
821 if (!strcmp(ts, "space") || !strcmp(ts, "Spc"))
823 else if (!strcmp(ts, "return") || !strcmp(ts, "Ret"))
825 else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd"))
827 else if (!strcmp(ts, "linefeed"))
829 else if (!strcmp(ts, "tab"))
831 else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc"))
833 else if (!strcmp(ts, "backspace"))
835 else if (!strcmp(ts, "delete"))
838 xprintf(CGETS(20, 35,
839 "bad key specification -- unknown name \"%S\"\n"), s);
840 return -1; /* error */
844 c = *s; /* just a single char */
861 struct command *dummy;
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.
879 if (v[1] && v[2] && v[3]) {
880 xprintf(CGETS(20, 36,
881 "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n"));
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) {
890 if ((c = parsekey(&s)) == -1)
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)) {
908 for (l = s; *l != 0; l++) {
913 cstr.len = Strlen(buf);
914 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
921 CcAltMap[c & APOLLO_0377] = fp->func;
922 /* bind the vi cmd mode key */
924 buf[0] = CTL_ESC('\033');
928 cstr.len = Strlen(buf);
929 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
933 buf[0] = CTL_ESC('\030'); /* ^X */
934 buf[1] = c & APOLLO_0377;
937 cstr.len = Strlen(buf);
938 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
939 CcKeyMap[CTL_ESC('\030')] = F_XKEY;
943 CcKeyMap[c] = fp->func; /* bind the key */
945 buf[0] = CTL_ESC('\033');
949 cstr.len = Strlen(buf);
950 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
956 stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function"));
959 char *cv = short2str(v[1]);
961 if (strcmp(cv, "list") == 0) {
962 for (fp = FuncNames; fp->name; fp++) {
963 xprintf("%s\n", fp->name);
967 if ((strcmp(cv, "emacs") == 0) ||
969 (strcmp(cv, "defaults") == 0) ||
970 (strcmp(cv, "default") == 0) ||
972 (strcmp(cv, "mg") == 0) ||
973 (strcmp(cv, "gnumacs") == 0)) {
974 /* reset keys to default */
978 else if ((strcmp(cv, "vi") == 0)
979 || (strcmp(cv, "default") == 0)
980 || (strcmp(cv, "defaults") == 0)) {
983 else if (strcmp(cv, "vi") == 0) {
987 else { /* want to know what this key does */
990 if ((c = parsekey(&s)) == -1)
992 if (c == -2) { /* extended key */
994 cstr.len = Strlen(s);
998 pkeys(c, c); /* must be regular key */
1001 else { /* list all the bindings */
1003 for (i = 0; i < 256; i++) {
1004 if (CcKeyMap[prev] == CcKeyMap[i])
1011 for (i = 256; i < 512; i++) {
1012 if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377])
1020 PrintXkey(&cstr); /* print all Xkey bindings */
1029 struct KeyFuncs *fp;
1036 first &= APOLLO_0377;
1037 last &= APOLLO_0377;
1044 if (map[first] == F_UNASSIGNED) {
1046 xprintf(CGETS(20, 38, " %s\t\tis undefined\n"),
1047 unparsekey(first | mask));
1051 for (fp = FuncNames; fp->name; fp++) {
1052 if (fp->func == map[first]) {
1054 xprintf(" %s\t\t%s\n",
1055 unparsekey((first & APOLLO_0377) | mask), fp->name);
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);
1064 if (map == CcKeyMap) {
1065 xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"),
1067 xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
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]);
1075 #endif /* OBSOLETE */