Remove an old comment that no longer applies.
[dragonfly/port-amd64.git] / contrib / tcsh / tc.bind.c
blobda2e3c38e2b8bb8bb2b8dec2dd85573099b70784
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.
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.
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.
33 #include "sh.h"
35 RCSID("$Id: tc.bind.c,v 3.36 2002/03/08 17:36:47 christos Exp $")
37 #include "ed.h"
38 #include "ed.defns.h"
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 */
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;
63 /*ARGSUSED*/
64 void
65 dobindkey(v, c)
66 Char **v;
67 struct command *c;
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;
84 USE(c);
85 if (!MapsAreInited)
86 ed_InitMaps();
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;
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;
139 if (!v[no]) {
140 print_all_keys();
141 return;
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);
150 else {
151 if (bind) {
152 if (parsebind(v[no++], &in) == NULL)
153 return;
155 else {
156 if (parsestring(v[no++], &in) == NULL)
157 return;
161 ch = (uChar) in.buf[0];
163 if (remove) {
164 if (key) {
165 (void) ClearArrowKeys(&in);
166 return;
168 if (in.len > 1) {
169 (void) DeleteXkey(&in);
171 else if (map[ch] == F_XKEY) {
172 (void) DeleteXkey(&in);
173 map[ch] = F_UNASSIGNED;
175 else {
176 map[ch] = F_UNASSIGNED;
178 return;
180 if (!v[no]) {
181 if (key)
182 PrintArrowKeys(&in);
183 else
184 printkey(map, &in);
185 return;
187 if (v[no + 1]) {
188 bindkey_usage();
189 return;
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);
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;
214 else {
215 ClearXkey(map, &in);
216 map[ch] = cmd;
219 break;
220 default:
221 abort();
222 break;
224 if (key)
225 BindArrowKeys();
228 static void
229 printkey(map, in)
230 KEYCMD *map;
231 CStr *in;
233 unsigned char outbuf[100];
234 register struct KeyFuncs *fp;
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);
244 else
245 PrintXkey(in);
248 static KEYCMD
249 parsecmd(str)
250 Char *str;
252 register struct KeyFuncs *fp;
254 for (fp = FuncNames; fp->name; fp++) {
255 if (strcmp(short2str(str), fp->name) == 0) {
256 return (KEYCMD) fp->func;
259 xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
260 return 0;
264 static void
265 bad_spec(str)
266 Char *str;
268 xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
271 static CStr *
272 parsebind(s, str)
273 Char *s;
274 CStr *str;
276 #ifdef DSPMBYTE
277 extern bool NoNLSRebind;
278 #endif /* DSPMBYTE */
279 Char *b = str->buf;
281 if (Iscntrl(*s)) {
282 *b++ = *s;
283 *b = '\0';
284 str->len = (int) (b - str->buf);
285 return str;
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;
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;
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;
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;
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;
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
352 #endif /* DSPMBYTE */
353 *b = '\0';
354 break;
355 #ifdef WINNT_NATIVE
356 case 'N' : case 'n': /* NT */
358 Char bnt;
360 bnt = nt_translate_bindkey(s);
361 if (bnt != 0)
362 *b++ = bnt;
363 else
364 bad_spec(s);
366 break;
367 #endif /* WINNT_NATIVE */
369 default:
370 abort();
371 /*NOTREACHED*/
372 return NULL;
374 break;
376 default:
377 bad_spec(s);
378 return NULL;
381 str->len = (int) (b - str->buf);
382 return str;
386 static CStr *
387 parsestring(str, buf)
388 Char *str;
389 CStr *buf;
391 Char *b;
392 const Char *p;
393 int es;
395 b = buf->buf;
396 if (*str == 0) {
397 xprintf(CGETS(20, 5, "Null string specification\n"));
398 return NULL;
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;
408 else
409 *b++ = *p & CHAR;
411 *b = 0;
412 buf->len = (int) (b - buf->buf);
413 return buf;
416 static void
417 print_all_keys()
419 int prev, i;
420 CStr nilstr;
421 nilstr.buf = NULL;
422 nilstr.len = 0;
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;
433 printkeys(CcKeyMap, prev, i - 1);
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;
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);
450 static void
451 printkeys(map, first, last)
452 KEYCMD *map;
453 int first, last;
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;
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;
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;
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);
482 else {
483 xprintf("%-4s to %-7s-> %s\n",
484 unparsestring(&fb, unparsbuf, STRQQ),
485 unparsestring(&lb, extrabuf, STRQQ), fp->name);
487 return;
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]);
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]);
502 static void
503 bindkey_usage()
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"));
538 static void
539 list_functions()
541 register struct KeyFuncs *fp;
543 for (fp = FuncNames; fp->name; fp++) {
544 xprintf("%s\n %s\n", fp->name, fp->desc);
548 #ifdef OBSOLETE
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 :-)
557 #ifdef apollo
558 static unsigned char APOLLO_0377 = 0377;
559 #else /* sane */
560 # define APOLLO_0377 0377
561 #endif /* apollo */
563 static int
564 tocontrol(c)
565 int c;
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);
584 static char *
585 unparsekey(c) /* 'c' -> "c", '^C' -> "^" + "C" */
586 register int c;
588 register char *cp;
589 static char tmp[10];
591 cp = tmp;
593 if (c & 0400) {
594 *cp++ = 'A';
595 *cp++ = '-';
596 c &= APOLLO_0377;
598 if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) {
599 *cp++ = 'M';
600 *cp++ = '-';
601 c &= ASCII;
603 if (Isprint(c)) {
604 *cp++ = (char) c;
605 *cp = '\0';
606 return (tmp);
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++ = '?';
633 else {
634 *cp++ = c | 0100;
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);
644 else if (*cp == CTL_ESC('\177')) {
645 (void) strcpy(cp, "Del");
646 return (tmp);
648 else if (Isupper(_toebcdic[_toascii[c]|0100])
649 || strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) {
650 *cp++ = '^';
651 *cp++ = _toebcdic[_toascii[c]|0100]
653 else {
654 xsnprintf(cp, 3, "\\%3.3o", c);
655 cp += 4;
657 #endif /* IS_ASCII */
661 static KEYCMD
662 getkeycmd(sp)
663 Char **sp;
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;
672 map = CcKeyMap;
674 while (*s) {
675 if (*s == '^' && s[1]) {
676 s++;
677 c = tocontrol(*s++);
679 else
680 c = *s++;
682 if (*s == '\0')
683 break;
685 switch (map[c | meta]) {
686 case F_METANEXT:
687 meta = META;
688 keycmd = F_METANEXT;
689 ret_sp = s;
690 break;
692 case F_XKEY:
693 keycmd = F_XKEY;
694 ret_sp = s;
695 /* FALLTHROUGH */
697 default:
698 *sp = ret_sp;
699 return (keycmd);
703 *sp = ret_sp;
704 return (keycmd);
707 static int
708 parsekey(sp)
709 Char **sp; /* Return position of first unparsed character
710 * for return value -2 (xkeynext) */
712 register int c, meta = 0, control = 0, ctrlx = 0;
713 Char *s = *sp;
714 KEYCMD keycmd;
716 if (s == NULL) {
717 xprintf(CGETS(20, 27, "bad key specification -- null string\n"));
718 return -1;
720 if (*s == 0) {
721 xprintf(CGETS(20, 28, "bad key specification -- empty string\n"));
722 return -1;
725 (void) strip(s); /* trim to 7 bits. */
727 if (s[1] == 0) /* single char */
728 return (s[0] & APOLLO_0377);
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);
736 *sp = s + 2;
737 return (-2);
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 */
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;
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 */
765 c = (c * 8) + *s - '0';
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 */
776 c = (c * 10) + *s - '0';
779 else {
780 keycmd = getkeycmd(&s);
782 if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') { /* X- */
783 ctrlx++;
784 s += 2;
785 keycmd = getkeycmd(&s);
787 if ((*s == 'm' || *s == 'M') && s[1] == '-') { /* meta */
788 meta++;
789 s += 2;
790 keycmd = getkeycmd(&s);
792 else if (keycmd == F_METANEXT && *s) { /* meta */
793 meta++;
794 keycmd = getkeycmd(&s);
796 if (*s == '^' && s[1]) {
797 control++;
798 s++;
799 keycmd = getkeycmd(&s);
801 else if ((*s == 'c' || *s == 'C') && s[1] == '-') { /* control */
802 control++;
803 s += 2;
804 keycmd = getkeycmd(&s);
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);
814 *sp = s;
815 return (-2);
818 if (s[1] != 0) { /* if symbolic name */
819 char *ts;
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 */
844 else
845 c = *s; /* just a single char */
847 if (control)
848 c = tocontrol(c);
849 if (meta)
850 c |= META;
851 if (ctrlx)
852 c |= 0400;
854 return (c & 0777);
858 /*ARGSUSED*/
859 void
860 dobind(v, dummy)
861 register Char **v;
862 struct command *dummy;
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];
871 USE(dummy);
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.
877 if (!MapsAreInited)
878 ed_InitMaps();
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;
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];
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;
903 else {
904 *p++ = (Char) i;
906 #else
907 *p++ = (Char) i;
908 #endif
909 for (l = s; *l != 0; l++) {
910 *p++ = *l;
912 *p = 0;
913 cstr.buf = buf;
914 cstr.len = Strlen(buf);
915 AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
918 return;
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);
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;
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);
954 return;
957 stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function"));
959 else if (v[1]) {
960 char *cv = short2str(v[1]);
962 if (strcmp(cv, "list") == 0) {
963 for (fp = FuncNames; fp->name; fp++) {
964 xprintf("%s\n", fp->name);
966 return;
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
979 else if ((strcmp(cv, "vi") == 0)
980 || (strcmp(cv, "default") == 0)
981 || (strcmp(cv, "defaults") == 0)) {
982 #else
984 else if (strcmp(cv, "vi") == 0) {
985 #endif
986 ed_InitVIMaps();
988 else { /* want to know what this key does */
989 Char *s = v[1];
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;
999 pkeys(c, c); /* must be regular key */
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;
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;
1018 pkeys(prev, i - 1);
1019 cstr.buf = NULL;
1020 cstr.len = 0;
1021 PrintXkey(&cstr); /* print all Xkey bindings */
1023 return;
1026 static void
1027 pkeys(first, last)
1028 register int first, last;
1030 register struct KeyFuncs *fp;
1031 register KEYCMD *map;
1032 int mask;
1033 char buf[8];
1035 if (last & 0400) {
1036 map = CcAltMap;
1037 first &= APOLLO_0377;
1038 last &= APOLLO_0377;
1039 mask = 0400;
1041 else {
1042 map = CcKeyMap;
1043 mask = 0;
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;
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);
1062 return;
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]);
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]);
1076 #endif /* OBSOLETE */