tc.bind.c revision 100616
1100616Smp/* $Header: /src/pub/tcsh/tc.bind.c,v 3.36 2002/03/08 17:36:47 christos Exp $ */
259243Sobrien/*
359243Sobrien * tc.bind.c: Key binding functions
459243Sobrien */
559243Sobrien/*-
659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California.
759243Sobrien * All rights reserved.
859243Sobrien *
959243Sobrien * Redistribution and use in source and binary forms, with or without
1059243Sobrien * modification, are permitted provided that the following conditions
1159243Sobrien * are met:
1259243Sobrien * 1. Redistributions of source code must retain the above copyright
1359243Sobrien *    notice, this list of conditions and the following disclaimer.
1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1559243Sobrien *    notice, this list of conditions and the following disclaimer in the
1659243Sobrien *    documentation and/or other materials provided with the distribution.
17100616Smp * 3. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien#include "sh.h"
3459243Sobrien
35100616SmpRCSID("$Id: tc.bind.c,v 3.36 2002/03/08 17:36:47 christos Exp $")
3659243Sobrien
3759243Sobrien#include "ed.h"
3859243Sobrien#include "ed.defns.h"
3959243Sobrien
4059243Sobrien#ifdef OBSOLETE
4159243Sobrienstatic	int    tocontrol	__P((int));
4259243Sobrienstatic	char  *unparsekey	__P((int));
4359243Sobrienstatic	KEYCMD getkeycmd	__P((Char **));
4459243Sobrienstatic	int    parsekey		__P((Char **));
4559243Sobrienstatic	void   pkeys		__P((int, int));
4659243Sobrien#endif /* OBSOLETE */
4759243Sobrien
4859243Sobrienstatic	void   printkey		__P((KEYCMD *, CStr *));
4959243Sobrienstatic	KEYCMD parsecmd		__P((Char *));
5059243Sobrienstatic  void   bad_spec		__P((Char *));
5159243Sobrienstatic	CStr  *parsestring	__P((Char *, CStr *));
5259243Sobrienstatic	CStr  *parsebind	__P((Char *, CStr *));
5359243Sobrienstatic	void   print_all_keys	__P((void));
5459243Sobrienstatic	void   printkeys	__P((KEYCMD *, int, int));
5559243Sobrienstatic	void   bindkey_usage	__P((void));
5659243Sobrienstatic	void   list_functions	__P((void));
5759243Sobrien
5859243Sobrienextern int MapsAreInited;
5959243Sobrien
6059243Sobrien
6159243Sobrien
6259243Sobrien
6359243Sobrien/*ARGSUSED*/
6459243Sobrienvoid
6559243Sobriendobindkey(v, c)
6659243Sobrien    Char  **v;
6759243Sobrien    struct command *c;
6859243Sobrien{
6959243Sobrien    KEYCMD *map;
7059243Sobrien    int     ntype, no, remove, key, bind;
7159243Sobrien    Char   *par;
7259243Sobrien    Char    p;
7359243Sobrien    KEYCMD  cmd;
7459243Sobrien    CStr    in;
7559243Sobrien    CStr    out;
7659243Sobrien    Char    inbuf[200];
7759243Sobrien    Char    outbuf[200];
7859243Sobrien    uChar   ch;
7959243Sobrien    in.buf = inbuf;
8059243Sobrien    out.buf = outbuf;
8159243Sobrien    in.len = 0;
8259243Sobrien    out.len = 0;
8359243Sobrien
8459243Sobrien    USE(c);
8559243Sobrien    if (!MapsAreInited)
8659243Sobrien	ed_InitMaps();
8759243Sobrien
8859243Sobrien    map = CcKeyMap;
8959243Sobrien    ntype = XK_CMD;
9059243Sobrien    key = remove = bind = 0;
9159243Sobrien    for (no = 1, par = v[no];
9259243Sobrien	 par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
9359243Sobrien	if ((p = (*par & CHAR)) == '-') {
9459243Sobrien	    no++;
9559243Sobrien	    break;
9659243Sobrien	}
9759243Sobrien	else
9859243Sobrien	    switch (p) {
9959243Sobrien	    case 'b':
10059243Sobrien		bind = 1;
10159243Sobrien		break;
10259243Sobrien	    case 'k':
10359243Sobrien		key = 1;
10459243Sobrien		break;
10559243Sobrien	    case 'a':
10659243Sobrien		map = CcAltMap;
10759243Sobrien		break;
10859243Sobrien	    case 's':
10959243Sobrien		ntype = XK_STR;
11059243Sobrien		break;
11159243Sobrien	    case 'c':
11259243Sobrien		ntype = XK_EXE;
11359243Sobrien		break;
11459243Sobrien	    case 'r':
11559243Sobrien		remove = 1;
11659243Sobrien		break;
11759243Sobrien	    case 'v':
11859243Sobrien		ed_InitVIMaps();
11959243Sobrien		return;
12059243Sobrien	    case 'e':
12159243Sobrien		ed_InitEmacsMaps();
12259243Sobrien		return;
12359243Sobrien	    case 'd':
12459243Sobrien#ifdef VIDEFAULT
12559243Sobrien		ed_InitVIMaps();
12659243Sobrien#else /* EMACSDEFAULT */
12759243Sobrien		ed_InitEmacsMaps();
12859243Sobrien#endif /* VIDEFAULT */
12959243Sobrien		return;
13059243Sobrien	    case 'l':
13159243Sobrien		list_functions();
13259243Sobrien		return;
13359243Sobrien	    default:
13459243Sobrien		bindkey_usage();
13559243Sobrien		return;
13659243Sobrien	    }
13759243Sobrien    }
13859243Sobrien
13959243Sobrien    if (!v[no]) {
14059243Sobrien	print_all_keys();
14159243Sobrien	return;
14259243Sobrien    }
14359243Sobrien
14459243Sobrien    if (key) {
14559243Sobrien	if (!IsArrowKey(v[no]))
14659243Sobrien	    xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
14759243Sobrien	in.buf = v[no++];
14859243Sobrien	in.len = Strlen(in.buf);
14959243Sobrien    }
15059243Sobrien    else {
15159243Sobrien	if (bind) {
15259243Sobrien	    if (parsebind(v[no++], &in) == NULL)
15359243Sobrien		return;
15459243Sobrien	}
15559243Sobrien	else {
15659243Sobrien	    if (parsestring(v[no++], &in) == NULL)
15759243Sobrien		return;
15859243Sobrien	}
15959243Sobrien    }
16059243Sobrien
16159243Sobrien    ch = (uChar) in.buf[0];
16259243Sobrien
16359243Sobrien    if (remove) {
16459243Sobrien	if (key) {
16559243Sobrien	    (void) ClearArrowKeys(&in);
16659243Sobrien	    return;
16759243Sobrien	}
16859243Sobrien	if (in.len > 1) {
16959243Sobrien	    (void) DeleteXkey(&in);
17059243Sobrien	}
17159243Sobrien	else if (map[ch] == F_XKEY) {
17259243Sobrien	    (void) DeleteXkey(&in);
17359243Sobrien	    map[ch] = F_UNASSIGNED;
17459243Sobrien	}
17559243Sobrien	else {
17659243Sobrien	    map[ch] = F_UNASSIGNED;
17759243Sobrien	}
17859243Sobrien	return;
17959243Sobrien    }
18059243Sobrien    if (!v[no]) {
18159243Sobrien	if (key)
18259243Sobrien	    PrintArrowKeys(&in);
18359243Sobrien	else
18459243Sobrien	    printkey(map, &in);
18559243Sobrien	return;
18659243Sobrien    }
18759243Sobrien    if (v[no + 1]) {
18859243Sobrien	bindkey_usage();
18959243Sobrien	return;
19059243Sobrien    }
19159243Sobrien    switch (ntype) {
19259243Sobrien    case XK_STR:
19359243Sobrien    case XK_EXE:
19459243Sobrien	if (parsestring(v[no], &out) == NULL)
19559243Sobrien	    return;
19659243Sobrien	if (key) {
19759243Sobrien	    if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
19859243Sobrien		xprintf(CGETS(20, 2, "Bad key name: %S\n"), in);
19959243Sobrien	}
20059243Sobrien	else
20159243Sobrien	    AddXkey(&in, XmapStr(&out), ntype);
20259243Sobrien	map[ch] = F_XKEY;
20359243Sobrien	break;
20459243Sobrien    case XK_CMD:
20559243Sobrien	if ((cmd = parsecmd(v[no])) == 0)
20659243Sobrien	    return;
20759243Sobrien	if (key)
20859243Sobrien	    (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
20959243Sobrien	else {
21059243Sobrien	    if (in.len > 1) {
21159243Sobrien		AddXkey(&in, XmapCmd((int) cmd), ntype);
21259243Sobrien		map[ch] = F_XKEY;
21359243Sobrien	    }
21459243Sobrien	    else {
21559243Sobrien		ClearXkey(map, &in);
21659243Sobrien		map[ch] = cmd;
21759243Sobrien	    }
21859243Sobrien	}
21959243Sobrien	break;
22059243Sobrien    default:
22159243Sobrien	abort();
22259243Sobrien	break;
22359243Sobrien    }
22459243Sobrien    if (key)
22559243Sobrien	BindArrowKeys();
22659243Sobrien}
22759243Sobrien
22859243Sobrienstatic void
22959243Sobrienprintkey(map, in)
23059243Sobrien    KEYCMD *map;
23159243Sobrien    CStr   *in;
23259243Sobrien{
23359243Sobrien    unsigned char outbuf[100];
23459243Sobrien    register struct KeyFuncs *fp;
23559243Sobrien
23659243Sobrien    if (in->len < 2) {
23759243Sobrien	(void) unparsestring(in, outbuf, STRQQ);
23859243Sobrien	for (fp = FuncNames; fp->name; fp++) {
23959243Sobrien	    if (fp->func == map[(uChar) *(in->buf)]) {
24059243Sobrien		xprintf("%s\t->\t%s\n", outbuf, fp->name);
24159243Sobrien	    }
24259243Sobrien	}
24359243Sobrien    }
24459243Sobrien    else
24559243Sobrien	PrintXkey(in);
24659243Sobrien}
24759243Sobrien
24859243Sobrienstatic  KEYCMD
24959243Sobrienparsecmd(str)
25059243Sobrien    Char   *str;
25159243Sobrien{
25259243Sobrien    register struct KeyFuncs *fp;
25359243Sobrien
25459243Sobrien    for (fp = FuncNames; fp->name; fp++) {
25559243Sobrien	if (strcmp(short2str(str), fp->name) == 0) {
25659243Sobrien	    return (KEYCMD) fp->func;
25759243Sobrien	}
25859243Sobrien    }
25959243Sobrien    xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
26059243Sobrien    return 0;
26159243Sobrien}
26259243Sobrien
26359243Sobrien
26459243Sobrienstatic void
26559243Sobrienbad_spec(str)
26659243Sobrien    Char *str;
26759243Sobrien{
26859243Sobrien    xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
26959243Sobrien}
27059243Sobrien
27159243Sobrienstatic CStr *
27259243Sobrienparsebind(s, str)
27359243Sobrien    Char *s;
27459243Sobrien    CStr *str;
27559243Sobrien{
27659243Sobrien#ifdef DSPMBYTE
27759243Sobrien    extern bool NoNLSRebind;
27859243Sobrien#endif /* DSPMBYTE */
27959243Sobrien    Char *b = str->buf;
28059243Sobrien
28159243Sobrien    if (Iscntrl(*s)) {
28259243Sobrien	*b++ = *s;
28359243Sobrien	*b = '\0';
28459243Sobrien	str->len = (int) (b - str->buf);
28559243Sobrien	return str;
28659243Sobrien    }
28759243Sobrien
28859243Sobrien    switch (*s) {
28959243Sobrien    case '^':
29059243Sobrien	s++;
29169408Sache#ifdef IS_ASCII
29259243Sobrien	*b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237);
29369408Sache#else
29459243Sobrien	*b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237];
29569408Sache#endif
29659243Sobrien	*b = '\0';
29759243Sobrien	break;
29859243Sobrien
29959243Sobrien    case 'F':
30059243Sobrien    case 'M':
30159243Sobrien    case 'X':
30259243Sobrien    case 'C':
30369408Sache#ifdef WINNT_NATIVE
30459243Sobrien    case 'N':
30569408Sache#endif /* WINNT_NATIVE */
30659243Sobrien	if (s[1] != '-' || s[2] == '\0') {
30759243Sobrien	    bad_spec(s);
30859243Sobrien	    return NULL;
30959243Sobrien	}
31059243Sobrien	s += 2;
31159243Sobrien	switch (s[-2]) {
31259243Sobrien	case 'F': case 'f':	/* Turn into ^[str */
31359243Sobrien	    *b++ = CTL_ESC('\033');
31459243Sobrien	    while ((*b++ = *s++) != '\0')
31559243Sobrien		continue;
31659243Sobrien	    b--;
31759243Sobrien	    break;
31859243Sobrien
31959243Sobrien	case 'C': case 'c':	/* Turn into ^c */
32069408Sache#ifdef IS_ASCII
32159243Sobrien	    *b++ = (*s == '?') ? '\177' : ((*s & CHAR) & 0237);
32269408Sache#else
32359243Sobrien	    *b++ = (*s == '?') ? CTL_ESC('\177') : _toebcdic[_toascii[*s & CHAR] & 0237];
32469408Sache#endif
32559243Sobrien	    *b = '\0';
32659243Sobrien	    break;
32759243Sobrien
32859243Sobrien	case 'X' : case 'x':	/* Turn into ^Xc */
32969408Sache#ifdef IS_ASCII
33059243Sobrien	    *b++ = 'X' & 0237;
33169408Sache#else
33259243Sobrien	    *b++ = _toebcdic[_toascii['X'] & 0237];
33369408Sache#endif
33459243Sobrien	    *b++ = *s;
33559243Sobrien	    *b = '\0';
33659243Sobrien	    break;
33759243Sobrien
33859243Sobrien	case 'M' : case 'm':	/* Turn into 0x80|c */
33959243Sobrien#ifdef DSPMBYTE
34059243Sobrien	    if (!NoNLSRebind) {
34159243Sobrien	    	*b++ = CTL_ESC('\033');
34259243Sobrien	    	*b++ = *s;
34359243Sobrien	    } else {
34459243Sobrien#endif /* DSPMBYTE */
34569408Sache#ifdef IS_ASCII
34659243Sobrien	    *b++ = *s | 0x80;
34769408Sache#else
34859243Sobrien	    *b++ = _toebcdic[_toascii[*s] | 0x80];
34969408Sache#endif
35059243Sobrien#ifdef DSPMBYTE
35159243Sobrien	    }
35259243Sobrien#endif /* DSPMBYTE */
35359243Sobrien	    *b = '\0';
35459243Sobrien	    break;
35569408Sache#ifdef WINNT_NATIVE
35659243Sobrien	case 'N' : case 'n':	/* NT */
35759243Sobrien		{
35859243Sobrien			Char bnt;
35959243Sobrien
36059243Sobrien			bnt = nt_translate_bindkey(s);
36159243Sobrien			if (bnt != 0)
36259243Sobrien				*b++ = bnt;
36359243Sobrien			else
36459243Sobrien				bad_spec(s);
36559243Sobrien		}
36659243Sobrien	    break;
36769408Sache#endif /* WINNT_NATIVE */
36859243Sobrien
36959243Sobrien	default:
37059243Sobrien	    abort();
37159243Sobrien	    /*NOTREACHED*/
37259243Sobrien	    return NULL;
37359243Sobrien	}
37459243Sobrien	break;
37559243Sobrien
37659243Sobrien    default:
37759243Sobrien	bad_spec(s);
37859243Sobrien	return NULL;
37959243Sobrien    }
38059243Sobrien
38159243Sobrien    str->len = (int) (b - str->buf);
38259243Sobrien    return str;
38359243Sobrien}
38459243Sobrien
38559243Sobrien
38659243Sobrienstatic CStr *
38759243Sobrienparsestring(str, buf)
38859243Sobrien    Char   *str;
38959243Sobrien    CStr   *buf;
39059243Sobrien{
39159243Sobrien    Char   *b;
39259243Sobrien    const Char   *p;
39359243Sobrien    int    es;
39459243Sobrien
39559243Sobrien    b = buf->buf;
39659243Sobrien    if (*str == 0) {
39759243Sobrien	xprintf(CGETS(20, 5, "Null string specification\n"));
39859243Sobrien	return NULL;
39959243Sobrien    }
40059243Sobrien
40159243Sobrien    for (p = str; *p != 0; p++) {
40259243Sobrien	if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
40359243Sobrien	    if ((es = parseescape(&p)) == -1)
40459243Sobrien		return 0;
40559243Sobrien	    else
40659243Sobrien		*b++ = (Char) es;
40759243Sobrien	}
40859243Sobrien	else
40959243Sobrien	    *b++ = *p & CHAR;
41059243Sobrien    }
41159243Sobrien    *b = 0;
41259243Sobrien    buf->len = (int) (b - buf->buf);
41359243Sobrien    return buf;
41459243Sobrien}
41559243Sobrien
41659243Sobrienstatic void
41759243Sobrienprint_all_keys()
41859243Sobrien{
41959243Sobrien    int     prev, i;
42059243Sobrien    CStr nilstr;
42159243Sobrien    nilstr.buf = NULL;
42259243Sobrien    nilstr.len = 0;
42359243Sobrien
42459243Sobrien
42559243Sobrien    xprintf(CGETS(20, 6, "Standard key bindings\n"));
42659243Sobrien    prev = 0;
42759243Sobrien    for (i = 0; i < 256; i++) {
42859243Sobrien	if (CcKeyMap[prev] == CcKeyMap[i])
42959243Sobrien	    continue;
43059243Sobrien	printkeys(CcKeyMap, prev, i - 1);
43159243Sobrien	prev = i;
43259243Sobrien    }
43359243Sobrien    printkeys(CcKeyMap, prev, i - 1);
43459243Sobrien
43559243Sobrien    xprintf(CGETS(20, 7, "Alternative key bindings\n"));
43659243Sobrien    prev = 0;
43759243Sobrien    for (i = 0; i < 256; i++) {
43859243Sobrien	if (CcAltMap[prev] == CcAltMap[i])
43959243Sobrien	    continue;
44059243Sobrien	printkeys(CcAltMap, prev, i - 1);
44159243Sobrien	prev = i;
44259243Sobrien    }
44359243Sobrien    printkeys(CcAltMap, prev, i - 1);
44459243Sobrien    xprintf(CGETS(20, 8, "Multi-character bindings\n"));
44559243Sobrien    PrintXkey(NULL);	/* print all Xkey bindings */
44659243Sobrien    xprintf(CGETS(20, 9, "Arrow key bindings\n"));
44759243Sobrien    PrintArrowKeys(&nilstr);
44859243Sobrien}
44959243Sobrien
45059243Sobrienstatic void
45159243Sobrienprintkeys(map, first, last)
45259243Sobrien    KEYCMD *map;
45359243Sobrien    int     first, last;
45459243Sobrien{
45559243Sobrien    register struct KeyFuncs *fp;
45659243Sobrien    Char    firstbuf[2], lastbuf[2];
45759243Sobrien    CStr fb, lb;
45859243Sobrien    unsigned char unparsbuf[10], extrabuf[10];
45959243Sobrien    fb.buf = firstbuf;
46059243Sobrien    lb.buf = lastbuf;
46159243Sobrien
46259243Sobrien    firstbuf[0] = (Char) first;
46359243Sobrien    firstbuf[1] = 0;
46459243Sobrien    lastbuf[0] = (Char) last;
46559243Sobrien    lastbuf[1] = 0;
46659243Sobrien    fb.len = 1;
46759243Sobrien    lb.len = 1;
46859243Sobrien
46959243Sobrien    if (map[first] == F_UNASSIGNED) {
47059243Sobrien	if (first == last)
47159243Sobrien	    xprintf(CGETS(20, 10, "%-15s->  is undefined\n"),
47259243Sobrien		    unparsestring(&fb, unparsbuf, STRQQ));
47359243Sobrien	return;
47459243Sobrien    }
47559243Sobrien
47659243Sobrien    for (fp = FuncNames; fp->name; fp++) {
47759243Sobrien	if (fp->func == map[first]) {
47859243Sobrien	    if (first == last) {
47959243Sobrien		xprintf("%-15s->  %s\n",
48059243Sobrien			unparsestring(&fb, unparsbuf, STRQQ), fp->name);
48159243Sobrien	    }
48259243Sobrien	    else {
48359243Sobrien		xprintf("%-4s to %-7s->  %s\n",
48459243Sobrien			unparsestring(&fb, unparsbuf, STRQQ),
48559243Sobrien			unparsestring(&lb, extrabuf, STRQQ), fp->name);
48659243Sobrien	    }
48759243Sobrien	    return;
48859243Sobrien	}
48959243Sobrien    }
49059243Sobrien    if (map == CcKeyMap) {
49159243Sobrien	xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"),
49259243Sobrien		unparsestring(&fb, unparsbuf, STRQQ));
49359243Sobrien	xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
49459243Sobrien    }
49559243Sobrien    else {
49659243Sobrien	xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"),
49759243Sobrien		unparsestring(&fb, unparsbuf, STRQQ));
49859243Sobrien	xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
49959243Sobrien    }
50059243Sobrien}
50159243Sobrien
50259243Sobrienstatic void
50359243Sobrienbindkey_usage()
50459243Sobrien{
50559243Sobrien    xprintf(CGETS(20, 12,
50659243Sobrien	    "Usage: bindkey [options] [--] [KEY [COMMAND]]\n"));
50759243Sobrien    xprintf(CGETS(20, 13,
50859243Sobrien    	    "    -a   list or bind KEY in alternative key map\n"));
50959243Sobrien    xprintf(CGETS(20, 14,
51059243Sobrien	    "    -b   interpret KEY as a C-, M-, F- or X- key name\n"));
51159243Sobrien    xprintf(CGETS(20, 15,
51259243Sobrien            "    -s   interpret COMMAND as a literal string to be output\n"));
51359243Sobrien    xprintf(CGETS(20, 16,
51459243Sobrien            "    -c   interpret COMMAND as a builtin or external command\n"));
51559243Sobrien    xprintf(CGETS(20, 17,
51659243Sobrien	    "    -v   bind all keys to vi bindings\n"));
51759243Sobrien    xprintf(CGETS(20, 18,
51859243Sobrien	    "    -e   bind all keys to emacs bindings\n"));
51959243Sobrien    xprintf(CGETS(20, 19,
52059243Sobrien	    "    -d   bind all keys to default editor's bindings\n"));
52159243Sobrien    xprintf(CGETS(20, 20,
52259243Sobrien	    "    -l   list editor commands with descriptions\n"));
52359243Sobrien    xprintf(CGETS(20, 21,
52459243Sobrien	    "    -r   remove KEY's binding\n"));
52559243Sobrien    xprintf(CGETS(20, 22,
52659243Sobrien	    "    -k   interpret KEY as a symbolic arrow-key name\n"));
52759243Sobrien    xprintf(CGETS(20, 23,
52859243Sobrien	    "    --   force a break from option processing\n"));
52959243Sobrien    xprintf(CGETS(20, 24,
53059243Sobrien	    "    -u   (or any invalid option) this message\n"));
53159243Sobrien    xprintf("\n");
53259243Sobrien    xprintf(CGETS(20, 25,
53359243Sobrien	    "Without KEY or COMMAND, prints all bindings\n"));
53459243Sobrien    xprintf(CGETS(20, 26,
53559243Sobrien	    "Without COMMAND, prints the binding for KEY.\n"));
53659243Sobrien}
53759243Sobrien
53859243Sobrienstatic void
53959243Sobrienlist_functions()
54059243Sobrien{
54159243Sobrien    register struct KeyFuncs *fp;
54259243Sobrien
54359243Sobrien    for (fp = FuncNames; fp->name; fp++) {
54459243Sobrien	xprintf("%s\n          %s\n", fp->name, fp->desc);
54559243Sobrien    }
54659243Sobrien}
54759243Sobrien
54859243Sobrien#ifdef OBSOLETE
54959243Sobrien
55059243Sobrien/*
55159243Sobrien * Unfortunately the apollo optimizer does not like & operations
55259243Sobrien * with 0377, and produces illegal instructions. So we make it
55359243Sobrien * an unsigned char, and hope for the best.
55459243Sobrien * Of-course the compiler is smart enough to produce bad assembly
55559243Sobrien * language instructions, but dumb when it comes to fold the constant :-)
55659243Sobrien */
55759243Sobrien#ifdef apollo
55859243Sobrienstatic unsigned char APOLLO_0377 = 0377;
55959243Sobrien#else /* sane */
56059243Sobrien# define APOLLO_0377    0377
56159243Sobrien#endif /* apollo */
56259243Sobrien
56359243Sobrienstatic int
56459243Sobrientocontrol(c)
56559243Sobrien    int    c;
56659243Sobrien{
56759243Sobrien    c &= CHAR;
56859243Sobrien    if (Islower(c))
56959243Sobrien	c = Toupper(c);
57059243Sobrien    else if (c == ' ')
57159243Sobrien	c = '@';
57259243Sobrien    if (c == '?')
57359243Sobrien	c = CTL_ESC('\177');
57459243Sobrien    else
57569408Sache#ifdef IS_ASCII
57659243Sobrien	c &= 037;
57769408Sache#else
57869408Sache	/* EBCDIC: simulate ASCII-behavior by transforming to ASCII and back */
57959243Sobrien	c  = _toebcdic[_toascii[c] & 037];
58059243Sobrien#endif
58159243Sobrien    return (c);
58259243Sobrien}
58359243Sobrien
58459243Sobrienstatic char *
58559243Sobrienunparsekey(c)			/* 'c' -> "c", '^C' -> "^" + "C" */
58659243Sobrien    register int c;
58759243Sobrien{
58859243Sobrien    register char *cp;
58959243Sobrien    static char tmp[10];
59059243Sobrien
59159243Sobrien    cp = tmp;
59259243Sobrien
59359243Sobrien    if (c & 0400) {
59459243Sobrien	*cp++ = 'A';
59559243Sobrien	*cp++ = '-';
59659243Sobrien	c &= APOLLO_0377;
59759243Sobrien    }
59859243Sobrien    if ((c & META) && !(Isprint(c) || (Iscntrl(c) && Isprint(c | 0100)))) {
59959243Sobrien	*cp++ = 'M';
60059243Sobrien	*cp++ = '-';
60159243Sobrien	c &= ASCII;
60259243Sobrien    }
60359243Sobrien    if (Isprint(c)) {
60459243Sobrien	*cp++ = (char) c;
60559243Sobrien	*cp = '\0';
60659243Sobrien	return (tmp);
60759243Sobrien    }
60859243Sobrien    switch (c) {
60959243Sobrien    case ' ':
61059243Sobrien	(void) strcpy(cp, "Spc");
61159243Sobrien	return (tmp);
61259243Sobrien    case '\n':
61359243Sobrien	(void) strcpy(cp, "Lfd");
61459243Sobrien	return (tmp);
61559243Sobrien    case '\r':
61659243Sobrien	(void) strcpy(cp, "Ret");
61759243Sobrien	return (tmp);
61859243Sobrien    case '\t':
61959243Sobrien	(void) strcpy(cp, "Tab");
62059243Sobrien	return (tmp);
62169408Sache#ifdef IS_ASCII
62259243Sobrien    case '\033':
62359243Sobrien	(void) strcpy(cp, "Esc");
62459243Sobrien	return (tmp);
62559243Sobrien    case '\177':
62659243Sobrien	(void) strcpy(cp, "Del");
62759243Sobrien	return (tmp);
62859243Sobrien    default:
62959243Sobrien	*cp++ = '^';
63059243Sobrien	if (c == '\177') {
63159243Sobrien	    *cp++ = '?';
63259243Sobrien	}
63359243Sobrien	else {
63459243Sobrien	    *cp++ = c | 0100;
63559243Sobrien	}
63659243Sobrien	*cp = '\0';
63759243Sobrien	return (tmp);
63869408Sache#else /* IS_ASCII */
63959243Sobrien    default:
64059243Sobrien        if (*cp == CTL_ESC('\033')) {
64159243Sobrien	    (void) strcpy(cp, "Esc");
64259243Sobrien	    return (tmp);
64359243Sobrien	}
64459243Sobrien	else if (*cp == CTL_ESC('\177')) {
64559243Sobrien	    (void) strcpy(cp, "Del");
64659243Sobrien	    return (tmp);
64759243Sobrien	}
64859243Sobrien	else if (Isupper(_toebcdic[_toascii[c]|0100])
64959243Sobrien		|| strchr("@[\\]^_", _toebcdic[_toascii[c]|0100]) != NULL) {
65059243Sobrien	    *cp++ = '^';
65159243Sobrien	    *cp++ = _toebcdic[_toascii[c]|0100]
65259243Sobrien	}
65359243Sobrien	else {
65459243Sobrien	    xsnprintf(cp, 3, "\\%3.3o", c);
65559243Sobrien	    cp += 4;
65659243Sobrien	}
65769408Sache#endif /* IS_ASCII */
65859243Sobrien    }
65959243Sobrien}
66059243Sobrien
66159243Sobrienstatic  KEYCMD
66259243Sobriengetkeycmd(sp)
66359243Sobrien    Char  **sp;
66459243Sobrien{
66559243Sobrien    register Char *s = *sp;
66659243Sobrien    register char c;
66759243Sobrien    register KEYCMD keycmd = F_UNASSIGNED;
66859243Sobrien    KEYCMD *map;
66959243Sobrien    int     meta = 0;
67059243Sobrien    Char   *ret_sp = s;
67159243Sobrien
67259243Sobrien    map = CcKeyMap;
67359243Sobrien
67459243Sobrien    while (*s) {
67559243Sobrien	if (*s == '^' && s[1]) {
67659243Sobrien	    s++;
67759243Sobrien	    c = tocontrol(*s++);
67859243Sobrien	}
67959243Sobrien	else
68059243Sobrien	    c = *s++;
68159243Sobrien
68259243Sobrien	if (*s == '\0')
68359243Sobrien	    break;
68459243Sobrien
68559243Sobrien	switch (map[c | meta]) {
68659243Sobrien	case F_METANEXT:
68759243Sobrien	    meta = META;
68859243Sobrien	    keycmd = F_METANEXT;
68959243Sobrien	    ret_sp = s;
69059243Sobrien	    break;
69159243Sobrien
69259243Sobrien	case F_XKEY:
69359243Sobrien	    keycmd = F_XKEY;
69459243Sobrien	    ret_sp = s;
69559243Sobrien	    /* FALLTHROUGH */
69659243Sobrien
69759243Sobrien	default:
69859243Sobrien	    *sp = ret_sp;
69959243Sobrien	    return (keycmd);
70059243Sobrien
70159243Sobrien	}
70259243Sobrien    }
70359243Sobrien    *sp = ret_sp;
70459243Sobrien    return (keycmd);
70559243Sobrien}
70659243Sobrien
70759243Sobrienstatic int
70859243Sobrienparsekey(sp)
70959243Sobrien    Char  **sp;			/* Return position of first unparsed character
71059243Sobrien				 * for return value -2 (xkeynext) */
71159243Sobrien{
71259243Sobrien    register int c, meta = 0, control = 0, ctrlx = 0;
71359243Sobrien    Char   *s = *sp;
71459243Sobrien    KEYCMD  keycmd;
71559243Sobrien
71659243Sobrien    if (s == NULL) {
71759243Sobrien	xprintf(CGETS(20, 27, "bad key specification -- null string\n"));
71859243Sobrien	return -1;
71959243Sobrien    }
72059243Sobrien    if (*s == 0) {
72159243Sobrien	xprintf(CGETS(20, 28, "bad key specification -- empty string\n"));
72259243Sobrien	return -1;
72359243Sobrien    }
72459243Sobrien
72559243Sobrien    (void) strip(s);		/* trim to 7 bits. */
72659243Sobrien
72759243Sobrien    if (s[1] == 0)		/* single char */
72859243Sobrien	return (s[0] & APOLLO_0377);
72959243Sobrien
73059243Sobrien    if ((s[0] == 'F' || s[0] == 'f') && s[1] == '-') {
73159243Sobrien	if (s[2] == 0) {
73259243Sobrien	    xprintf(CGETS(20, 29,
73359243Sobrien		   "Bad function-key specification.  Null key not allowed\n"));
73459243Sobrien	    return (-1);
73559243Sobrien	}
73659243Sobrien	*sp = s + 2;
73759243Sobrien	return (-2);
73859243Sobrien    }
73959243Sobrien
74059243Sobrien    if (s[0] == '0' && s[1] == 'x') {	/* if 0xn, then assume number */
74159243Sobrien	c = 0;
74259243Sobrien	for (s += 2; *s; s++) {	/* convert to hex; skip the first 0 */
74359243Sobrien	    c *= 16;
74459243Sobrien	    if (!Isxdigit(*s)) {
74559243Sobrien		xprintf(CGETS(20, 30,
74659243Sobrien			"bad key specification -- malformed hex number\n"));
74759243Sobrien		return -1;	/* error */
74859243Sobrien	    }
74959243Sobrien	    if (Isdigit(*s))
75059243Sobrien		c += *s - '0';
75159243Sobrien	    else if (*s >= 'a' && *s <= 'f')
75259243Sobrien		c += *s - 'a' + 0xA;
75359243Sobrien	    else if (*s >= 'F' && *s <= 'F')
75459243Sobrien		c += *s - 'A' + 0xA;
75559243Sobrien	}
75659243Sobrien    }
75759243Sobrien    else if (s[0] == '0' && Isdigit(s[1])) {	/* if 0n, then assume number */
75859243Sobrien	c = 0;
75959243Sobrien	for (s++; *s; s++) {	/* convert to octal; skip the first 0 */
76059243Sobrien	    if (!Isdigit(*s) || *s == '8' || *s == '9') {
76159243Sobrien		xprintf(CGETS(20, 31,
76259243Sobrien			"bad key specification -- malformed octal number\n"));
76359243Sobrien		return -1;	/* error */
76459243Sobrien	    }
76559243Sobrien	    c = (c * 8) + *s - '0';
76659243Sobrien	}
76759243Sobrien    }
76859243Sobrien    else if (Isdigit(s[0]) && Isdigit(s[1])) {	/* decimal number */
76959243Sobrien	c = 0;
77059243Sobrien	for (; *s; s++) {	/* convert to octal; skip the first 0 */
77159243Sobrien	    if (!Isdigit(*s)) {
77259243Sobrien		xprintf(CGETS(20, 32,
77359243Sobrien		       "bad key specification -- malformed decimal number\n"));
77459243Sobrien		return -1;	/* error */
77559243Sobrien	    }
77659243Sobrien	    c = (c * 10) + *s - '0';
77759243Sobrien	}
77859243Sobrien    }
77959243Sobrien    else {
78059243Sobrien	keycmd = getkeycmd(&s);
78159243Sobrien
78259243Sobrien	if ((s[0] == 'X' || s[0] == 'x') && s[1] == '-') {	/* X- */
78359243Sobrien	    ctrlx++;
78459243Sobrien	    s += 2;
78559243Sobrien	    keycmd = getkeycmd(&s);
78659243Sobrien	}
78759243Sobrien	if ((*s == 'm' || *s == 'M') && s[1] == '-') {	/* meta */
78859243Sobrien	    meta++;
78959243Sobrien	    s += 2;
79059243Sobrien	    keycmd = getkeycmd(&s);
79159243Sobrien	}
79259243Sobrien	else if (keycmd == F_METANEXT && *s) {	/* meta */
79359243Sobrien	    meta++;
79459243Sobrien	    keycmd = getkeycmd(&s);
79559243Sobrien	}
79659243Sobrien	if (*s == '^' && s[1]) {
79759243Sobrien	    control++;
79859243Sobrien	    s++;
79959243Sobrien	    keycmd = getkeycmd(&s);
80059243Sobrien	}
80159243Sobrien	else if ((*s == 'c' || *s == 'C') && s[1] == '-') {	/* control */
80259243Sobrien	    control++;
80359243Sobrien	    s += 2;
80459243Sobrien	    keycmd = getkeycmd(&s);
80559243Sobrien	}
80659243Sobrien
80759243Sobrien	if (keycmd == F_XKEY) {
80859243Sobrien	    if (*s == 0) {
80959243Sobrien		xprintf(CGETS(20, 33,
81059243Sobrien			      "Bad function-key specification.\n"));
81159243Sobrien		xprintf(CGETS(20, 34, "Null key not allowed\n"));
81259243Sobrien		return (-1);
81359243Sobrien	    }
81459243Sobrien	    *sp = s;
81559243Sobrien	    return (-2);
81659243Sobrien	}
81759243Sobrien
81859243Sobrien	if (s[1] != 0) {	/* if symbolic name */
81959243Sobrien	    char   *ts;
82059243Sobrien
82159243Sobrien	    ts = short2str(s);
82259243Sobrien	    if (!strcmp(ts, "space") || !strcmp(ts, "Spc"))
82359243Sobrien		c = ' ';
82459243Sobrien	    else if (!strcmp(ts, "return") || !strcmp(ts, "Ret"))
82559243Sobrien		c = '\r';
82659243Sobrien	    else if (!strcmp(ts, "newline") || !strcmp(ts, "Lfd"))
82759243Sobrien		c = '\n';
82859243Sobrien	    else if (!strcmp(ts, "linefeed"))
82959243Sobrien		c = '\n';
83059243Sobrien	    else if (!strcmp(ts, "tab"))
83159243Sobrien		c = '\t';
83259243Sobrien	    else if (!strcmp(ts, "escape") || !strcmp(ts, "Esc"))
83359243Sobrien		c = CTL_ESC('\033');
83459243Sobrien	    else if (!strcmp(ts, "backspace"))
83559243Sobrien		c = '\b';
83659243Sobrien	    else if (!strcmp(ts, "delete"))
83759243Sobrien		c = CTL_ESC('\177');
83859243Sobrien	    else {
83959243Sobrien		xprintf(CGETS(20, 35,
84059243Sobrien			"bad key specification -- unknown name \"%S\"\n"), s);
84159243Sobrien		return -1;	/* error */
84259243Sobrien	    }
84359243Sobrien	}
84459243Sobrien	else
84559243Sobrien	    c = *s;		/* just a single char */
84659243Sobrien
84759243Sobrien	if (control)
84859243Sobrien	    c = tocontrol(c);
84959243Sobrien	if (meta)
85059243Sobrien	    c |= META;
85159243Sobrien	if (ctrlx)
85259243Sobrien	    c |= 0400;
85359243Sobrien    }
85459243Sobrien    return (c & 0777);
85559243Sobrien}
85659243Sobrien
85759243Sobrien
85859243Sobrien/*ARGSUSED*/
85959243Sobrienvoid
86059243Sobriendobind(v, dummy)
86159243Sobrien    register Char **v;
86259243Sobrien    struct command *dummy;
86359243Sobrien{
86459243Sobrien    register int c;
86559243Sobrien    register struct KeyFuncs *fp;
86659243Sobrien    register int i, prev;
86759243Sobrien    Char   *p, *l;
86859243Sobrien    CStr    cstr;
86959243Sobrien    Char    buf[1000];
87059243Sobrien
87159243Sobrien    USE(dummy);
87259243Sobrien    /*
87359243Sobrien     * Assume at this point that i'm given 2 or 3 args - 'bind', the f-name,
87459243Sobrien     * and the key; or 'bind' key to print the func for that key.
87559243Sobrien     */
87659243Sobrien
87759243Sobrien    if (!MapsAreInited)
87859243Sobrien	ed_InitMaps();
87959243Sobrien
88059243Sobrien    if (v[1] && v[2] && v[3]) {
88159243Sobrien	xprintf(CGETS(20, 36,
88259243Sobrien	 "usage: bind [KEY | COMMAND KEY | \"emacs\" | \"vi\" | \"-a\"]\n"));
88359243Sobrien	return;
88459243Sobrien    }
88559243Sobrien
88659243Sobrien    if (v[1] && v[2]) {		/* if bind FUNCTION KEY */
88759243Sobrien	for (fp = FuncNames; fp->name; fp++) {
88859243Sobrien	    if (strcmp(short2str(v[1]), fp->name) == 0) {
88959243Sobrien		Char   *s = v[2];
89059243Sobrien
89159243Sobrien		if ((c = parsekey(&s)) == -1)
89259243Sobrien		    return;
89359243Sobrien		if (c == -2) {	/* extended key */
89459243Sobrien		    for (i = 0; i < 256; i++) {
89559243Sobrien			if (i != CTL_ESC('\033') && (CcKeyMap[i] == F_XKEY ||
89659243Sobrien					 CcAltMap[i] == F_XKEY)) {
89759243Sobrien			    p = buf;
89869408Sache#ifdef IS_ASCII
89959243Sobrien			    if (i > 0177) {
90059243Sobrien				*p++ = 033;
90159243Sobrien				*p++ = i & ASCII;
90259243Sobrien			    }
90359243Sobrien			    else {
90459243Sobrien				*p++ = (Char) i;
90559243Sobrien			    }
90669408Sache#else
90759243Sobrien			    *p++ = (Char) i;
90869408Sache#endif
90959243Sobrien			    for (l = s; *l != 0; l++) {
91059243Sobrien				*p++ = *l;
91159243Sobrien			    }
91259243Sobrien			    *p = 0;
91359243Sobrien			    cstr.buf = buf;
91459243Sobrien			    cstr.len = Strlen(buf);
91559243Sobrien			    AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
91659243Sobrien			}
91759243Sobrien		    }
91859243Sobrien		    return;
91959243Sobrien		}
92059243Sobrien		if (c & 0400) {
92159243Sobrien		    if (VImode) {
92259243Sobrien			CcAltMap[c & APOLLO_0377] = fp->func;
92359243Sobrien			/* bind the vi cmd mode key */
92459243Sobrien			if (c & META) {
92559243Sobrien			    buf[0] = CTL_ESC('\033');
92659243Sobrien			    buf[1] = c & ASCII;
92759243Sobrien			    buf[2] = 0;
92859243Sobrien			    cstr.buf = buf;
92959243Sobrien			    cstr.len = Strlen(buf);
93059243Sobrien			    AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
93159243Sobrien			}
93259243Sobrien		    }
93359243Sobrien		    else {
93459243Sobrien			buf[0] = CTL_ESC('\030');	/* ^X */
93559243Sobrien			buf[1] = c & APOLLO_0377;
93659243Sobrien			buf[2] = 0;
93759243Sobrien			cstr.buf = buf;
93859243Sobrien			cstr.len = Strlen(buf);
93959243Sobrien			AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
94059243Sobrien			CcKeyMap[CTL_ESC('\030')] = F_XKEY;
94159243Sobrien		    }
94259243Sobrien		}
94359243Sobrien		else {
94459243Sobrien		    CcKeyMap[c] = fp->func;	/* bind the key */
94559243Sobrien		    if (c & META) {
94659243Sobrien			buf[0] = CTL_ESC('\033');
94759243Sobrien			buf[1] = c & ASCII;
94859243Sobrien			buf[2] = 0;
94959243Sobrien			cstr.buf = buf;
95059243Sobrien			cstr.len = Strlen(buf);
95159243Sobrien			AddXkey(&cstr, XmapCmd(fp->func), XK_CMD);
95259243Sobrien		    }
95359243Sobrien		}
95459243Sobrien		return;
95559243Sobrien	    }
95659243Sobrien	}
95759243Sobrien	stderror(ERR_NAME | ERR_STRING, CGETS(20, 37, "Invalid function"));
95859243Sobrien    }
95959243Sobrien    else if (v[1]) {
96059243Sobrien	char   *cv = short2str(v[1]);
96159243Sobrien
96259243Sobrien	if (strcmp(cv, "list") == 0) {
96359243Sobrien	    for (fp = FuncNames; fp->name; fp++) {
96459243Sobrien		xprintf("%s\n", fp->name);
96559243Sobrien	    }
96659243Sobrien	    return;
96759243Sobrien	}
96859243Sobrien	if ((strcmp(cv, "emacs") == 0) ||
96959243Sobrien#ifndef VIDEFAULT
97059243Sobrien	    (strcmp(cv, "defaults") == 0) ||
97159243Sobrien	    (strcmp(cv, "default") == 0) ||
97259243Sobrien#endif
97359243Sobrien	    (strcmp(cv, "mg") == 0) ||
97459243Sobrien	    (strcmp(cv, "gnumacs") == 0)) {
97559243Sobrien	    /* reset keys to default */
97659243Sobrien	    ed_InitEmacsMaps();
97759243Sobrien#ifdef VIDEFAULT
97859243Sobrien	}
97959243Sobrien	else if ((strcmp(cv, "vi") == 0)
98059243Sobrien		 || (strcmp(cv, "default") == 0)
98159243Sobrien		 || (strcmp(cv, "defaults") == 0)) {
98259243Sobrien#else
98359243Sobrien	}
98459243Sobrien	else if (strcmp(cv, "vi") == 0) {
98559243Sobrien#endif
98659243Sobrien	    ed_InitVIMaps();
98759243Sobrien	}
98859243Sobrien	else {			/* want to know what this key does */
98959243Sobrien	    Char   *s = v[1];
99059243Sobrien
99159243Sobrien	    if ((c = parsekey(&s)) == -1)
99259243Sobrien		return;
99359243Sobrien	    if (c == -2) {	/* extended key */
99459243Sobrien		cstr.buf = s;
99559243Sobrien		cstr.len = Strlen(s);
99659243Sobrien		PrintXkey(&cstr);
99759243Sobrien		return;
99859243Sobrien	    }
99959243Sobrien	    pkeys(c, c);	/* must be regular key */
100059243Sobrien	}
100159243Sobrien    }
100259243Sobrien    else {			/* list all the bindings */
100359243Sobrien	prev = 0;
100459243Sobrien	for (i = 0; i < 256; i++) {
100559243Sobrien	    if (CcKeyMap[prev] == CcKeyMap[i])
100659243Sobrien		continue;
100759243Sobrien	    pkeys(prev, i - 1);
100859243Sobrien	    prev = i;
100959243Sobrien	}
101059243Sobrien	pkeys(prev, i - 1);
101159243Sobrien	prev = 0;
101259243Sobrien	for (i = 256; i < 512; i++) {
101359243Sobrien	    if (CcAltMap[prev & APOLLO_0377] == CcAltMap[i & APOLLO_0377])
101459243Sobrien		continue;
101559243Sobrien	    pkeys(prev, i - 1);
101659243Sobrien	    prev = i;
101759243Sobrien	}
101859243Sobrien	pkeys(prev, i - 1);
101959243Sobrien	cstr.buf = NULL;
102059243Sobrien	cstr.len = 0;
102159243Sobrien	PrintXkey(&cstr);	/* print all Xkey bindings */
102259243Sobrien    }
102359243Sobrien    return;
102459243Sobrien}
102559243Sobrien
102659243Sobrienstatic void
102759243Sobrienpkeys(first, last)
102859243Sobrien    register int first, last;
102959243Sobrien{
103059243Sobrien    register struct KeyFuncs *fp;
103159243Sobrien    register KEYCMD *map;
103259243Sobrien    int mask;
103359243Sobrien    char    buf[8];
103459243Sobrien
103559243Sobrien    if (last & 0400) {
103659243Sobrien	map = CcAltMap;
103759243Sobrien	first &= APOLLO_0377;
103859243Sobrien	last &= APOLLO_0377;
103959243Sobrien	mask = 0400;
104059243Sobrien    }
104159243Sobrien    else {
104259243Sobrien	map = CcKeyMap;
104359243Sobrien	mask = 0;
104459243Sobrien    }
104559243Sobrien    if (map[first] == F_UNASSIGNED) {
104659243Sobrien	if (first == last)
104759243Sobrien	    xprintf(CGETS(20, 38, " %s\t\tis undefined\n"),
104859243Sobrien		    unparsekey(first | mask));
104959243Sobrien	return;
105059243Sobrien    }
105159243Sobrien
105259243Sobrien    for (fp = FuncNames; fp->name; fp++) {
105359243Sobrien	if (fp->func == map[first]) {
105459243Sobrien	    if (first == last)
105559243Sobrien		xprintf(" %s\t\t%s\n",
105659243Sobrien			unparsekey((first & APOLLO_0377) | mask), fp->name);
105759243Sobrien	    else {
105859243Sobrien		(void) strcpy(buf, unparsekey((first & APOLLO_0377) | mask));
105959243Sobrien		xprintf(" %s..%s\t\t%s\n", buf,
106059243Sobrien		        unparsekey((last & APOLLO_0377) | mask), fp->name);
106159243Sobrien	    }
106259243Sobrien	    return;
106359243Sobrien	}
106459243Sobrien    }
106559243Sobrien    if (map == CcKeyMap) {
106659243Sobrien	xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"),
106759243Sobrien		unparsekey(first));
106859243Sobrien	xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
106959243Sobrien    }
107059243Sobrien    else {
107159243Sobrien	xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"),
107259243Sobrien		unparsekey(first & 0400));
107359243Sobrien	xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
107459243Sobrien    }
107559243Sobrien}
107659243Sobrien#endif /* OBSOLETE */
1077