xref: /freebsd/contrib/tcsh/tc.bind.c (revision 45e5710bbb3676c9d945e9df78019b2c58930a59)
145e5710bSMark Peek /* $Header: /p/tcsh/cvsroot/tcsh/tc.bind.c,v 3.44 2006/03/02 18:46:44 christos Exp $ */
2c80476e4SDavid E. O'Brien /*
3c80476e4SDavid E. O'Brien  * tc.bind.c: Key binding functions
4c80476e4SDavid E. O'Brien  */
5c80476e4SDavid E. O'Brien /*-
6c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
7c80476e4SDavid E. O'Brien  * All rights reserved.
8c80476e4SDavid E. O'Brien  *
9c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
10c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
11c80476e4SDavid E. O'Brien  * are met:
12c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
13c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
14c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
15c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
16c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1729301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
18c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
19c80476e4SDavid E. O'Brien  *    without specific prior written permission.
20c80476e4SDavid E. O'Brien  *
21c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
32c80476e4SDavid E. O'Brien  */
33c80476e4SDavid E. O'Brien #include "sh.h"
34c80476e4SDavid E. O'Brien 
3545e5710bSMark Peek RCSID("$tcsh: tc.bind.c,v 3.44 2006/03/02 18:46:44 christos Exp $")
36c80476e4SDavid E. O'Brien 
37c80476e4SDavid E. O'Brien #include "ed.h"
38c80476e4SDavid E. O'Brien #include "ed.defns.h"
39c80476e4SDavid E. O'Brien 
4045e5710bSMark Peek static	void   printkey		(const KEYCMD *, CStr *);
4145e5710bSMark Peek static	KEYCMD parsecmd		(Char *);
4245e5710bSMark Peek static  void   bad_spec		(const Char *);
4345e5710bSMark Peek static	CStr  *parsestring	(const Char *, CStr *);
4445e5710bSMark Peek static	CStr  *parsebind	(const Char *, CStr *);
4545e5710bSMark Peek static	void   print_all_keys	(void);
4645e5710bSMark Peek static	void   printkeys	(KEYCMD *, int, int);
4745e5710bSMark Peek static	void   bindkey_usage	(void);
4845e5710bSMark Peek static	void   list_functions	(void);
49c80476e4SDavid E. O'Brien 
50c80476e4SDavid E. O'Brien extern int MapsAreInited;
51c80476e4SDavid E. O'Brien 
52c80476e4SDavid E. O'Brien 
53c80476e4SDavid E. O'Brien 
54c80476e4SDavid E. O'Brien 
55c80476e4SDavid E. O'Brien /*ARGSUSED*/
56c80476e4SDavid E. O'Brien void
5745e5710bSMark Peek dobindkey(Char **v, struct command *c)
58c80476e4SDavid E. O'Brien {
59c80476e4SDavid E. O'Brien     KEYCMD *map;
6023338178SMark Peek     int     ntype, no, removeb, key, bindk;
61c80476e4SDavid E. O'Brien     Char   *par;
62c80476e4SDavid E. O'Brien     Char    p;
63c80476e4SDavid E. O'Brien     KEYCMD  cmd;
64c80476e4SDavid E. O'Brien     CStr    in;
65c80476e4SDavid E. O'Brien     CStr    out;
66c80476e4SDavid E. O'Brien     uChar   ch;
67c80476e4SDavid E. O'Brien 
68c80476e4SDavid E. O'Brien     USE(c);
69c80476e4SDavid E. O'Brien     if (!MapsAreInited)
70c80476e4SDavid E. O'Brien 	ed_InitMaps();
71c80476e4SDavid E. O'Brien 
72c80476e4SDavid E. O'Brien     map = CcKeyMap;
73c80476e4SDavid E. O'Brien     ntype = XK_CMD;
7423338178SMark Peek     key = removeb = bindk = 0;
75c80476e4SDavid E. O'Brien     for (no = 1, par = v[no];
76c80476e4SDavid E. O'Brien 	 par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
77c80476e4SDavid E. O'Brien 	if ((p = (*par & CHAR)) == '-') {
78c80476e4SDavid E. O'Brien 	    no++;
79c80476e4SDavid E. O'Brien 	    break;
80c80476e4SDavid E. O'Brien 	}
81c80476e4SDavid E. O'Brien 	else
82c80476e4SDavid E. O'Brien 	    switch (p) {
83c80476e4SDavid E. O'Brien 	    case 'b':
8423338178SMark Peek 		bindk = 1;
85c80476e4SDavid E. O'Brien 		break;
86c80476e4SDavid E. O'Brien 	    case 'k':
87c80476e4SDavid E. O'Brien 		key = 1;
88c80476e4SDavid E. O'Brien 		break;
89c80476e4SDavid E. O'Brien 	    case 'a':
90c80476e4SDavid E. O'Brien 		map = CcAltMap;
91c80476e4SDavid E. O'Brien 		break;
92c80476e4SDavid E. O'Brien 	    case 's':
93c80476e4SDavid E. O'Brien 		ntype = XK_STR;
94c80476e4SDavid E. O'Brien 		break;
95c80476e4SDavid E. O'Brien 	    case 'c':
96c80476e4SDavid E. O'Brien 		ntype = XK_EXE;
97c80476e4SDavid E. O'Brien 		break;
98c80476e4SDavid E. O'Brien 	    case 'r':
9923338178SMark Peek 		removeb = 1;
100c80476e4SDavid E. O'Brien 		break;
101c80476e4SDavid E. O'Brien 	    case 'v':
102c80476e4SDavid E. O'Brien 		ed_InitVIMaps();
103c80476e4SDavid E. O'Brien 		return;
104c80476e4SDavid E. O'Brien 	    case 'e':
105c80476e4SDavid E. O'Brien 		ed_InitEmacsMaps();
106c80476e4SDavid E. O'Brien 		return;
107c80476e4SDavid E. O'Brien 	    case 'd':
108c80476e4SDavid E. O'Brien #ifdef VIDEFAULT
109c80476e4SDavid E. O'Brien 		ed_InitVIMaps();
110c80476e4SDavid E. O'Brien #else /* EMACSDEFAULT */
111c80476e4SDavid E. O'Brien 		ed_InitEmacsMaps();
112c80476e4SDavid E. O'Brien #endif /* VIDEFAULT */
113c80476e4SDavid E. O'Brien 		return;
114c80476e4SDavid E. O'Brien 	    case 'l':
115c80476e4SDavid E. O'Brien 		list_functions();
116c80476e4SDavid E. O'Brien 		return;
117c80476e4SDavid E. O'Brien 	    default:
118c80476e4SDavid E. O'Brien 		bindkey_usage();
119c80476e4SDavid E. O'Brien 		return;
120c80476e4SDavid E. O'Brien 	    }
121c80476e4SDavid E. O'Brien     }
122c80476e4SDavid E. O'Brien 
123c80476e4SDavid E. O'Brien     if (!v[no]) {
124c80476e4SDavid E. O'Brien 	print_all_keys();
125c80476e4SDavid E. O'Brien 	return;
126c80476e4SDavid E. O'Brien     }
127c80476e4SDavid E. O'Brien 
128c80476e4SDavid E. O'Brien     if (key) {
129c80476e4SDavid E. O'Brien 	if (!IsArrowKey(v[no]))
130c80476e4SDavid E. O'Brien 	    xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
13145e5710bSMark Peek 	in.buf = Strsave(v[no++]);
132c80476e4SDavid E. O'Brien 	in.len = Strlen(in.buf);
133c80476e4SDavid E. O'Brien     }
134c80476e4SDavid E. O'Brien     else {
13523338178SMark Peek 	if (bindk) {
136c80476e4SDavid E. O'Brien 	    if (parsebind(v[no++], &in) == NULL)
137c80476e4SDavid E. O'Brien 		return;
138c80476e4SDavid E. O'Brien 	}
139c80476e4SDavid E. O'Brien 	else {
140c80476e4SDavid E. O'Brien 	    if (parsestring(v[no++], &in) == NULL)
141c80476e4SDavid E. O'Brien 		return;
142c80476e4SDavid E. O'Brien 	}
143c80476e4SDavid E. O'Brien     }
14445e5710bSMark Peek     cleanup_push(in.buf, xfree);
145c80476e4SDavid E. O'Brien 
14623338178SMark Peek #ifndef WINNT_NATIVE
14723338178SMark Peek     if (in.buf[0] > 0xFF) {
14823338178SMark Peek 	bad_spec(in.buf);
14945e5710bSMark Peek 	cleanup_until(in.buf);
15023338178SMark Peek 	return;
15123338178SMark Peek     }
15223338178SMark Peek #endif
153c80476e4SDavid E. O'Brien     ch = (uChar) in.buf[0];
154c80476e4SDavid E. O'Brien 
15523338178SMark Peek     if (removeb) {
15645e5710bSMark Peek 	if (key)
157c80476e4SDavid E. O'Brien 	    (void) ClearArrowKeys(&in);
15845e5710bSMark Peek 	else if (in.len > 1) {
159c80476e4SDavid E. O'Brien 	    (void) DeleteXkey(&in);
160c80476e4SDavid E. O'Brien 	}
161c80476e4SDavid E. O'Brien 	else if (map[ch] == F_XKEY) {
162c80476e4SDavid E. O'Brien 	    (void) DeleteXkey(&in);
163c80476e4SDavid E. O'Brien 	    map[ch] = F_UNASSIGNED;
164c80476e4SDavid E. O'Brien 	}
165c80476e4SDavid E. O'Brien 	else {
166c80476e4SDavid E. O'Brien 	    map[ch] = F_UNASSIGNED;
167c80476e4SDavid E. O'Brien 	}
16845e5710bSMark Peek 	cleanup_until(in.buf);
169c80476e4SDavid E. O'Brien 	return;
170c80476e4SDavid E. O'Brien     }
171c80476e4SDavid E. O'Brien     if (!v[no]) {
172c80476e4SDavid E. O'Brien 	if (key)
173c80476e4SDavid E. O'Brien 	    PrintArrowKeys(&in);
174c80476e4SDavid E. O'Brien 	else
175c80476e4SDavid E. O'Brien 	    printkey(map, &in);
17645e5710bSMark Peek 	cleanup_until(in.buf);
177c80476e4SDavid E. O'Brien 	return;
178c80476e4SDavid E. O'Brien     }
179c80476e4SDavid E. O'Brien     if (v[no + 1]) {
180c80476e4SDavid E. O'Brien 	bindkey_usage();
18145e5710bSMark Peek 	cleanup_until(in.buf);
182c80476e4SDavid E. O'Brien 	return;
183c80476e4SDavid E. O'Brien     }
184c80476e4SDavid E. O'Brien     switch (ntype) {
185c80476e4SDavid E. O'Brien     case XK_STR:
186c80476e4SDavid E. O'Brien     case XK_EXE:
18745e5710bSMark Peek 	if (parsestring(v[no], &out) == NULL) {
18845e5710bSMark Peek 	    cleanup_until(in.buf);
189c80476e4SDavid E. O'Brien 	    return;
19045e5710bSMark Peek 	}
19145e5710bSMark Peek 	cleanup_push(out.buf, xfree);
192c80476e4SDavid E. O'Brien 	if (key) {
193c80476e4SDavid E. O'Brien 	    if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
19423338178SMark Peek 		xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf);
19545e5710bSMark Peek 	    else
19645e5710bSMark Peek 		cleanup_ignore(out.buf);
197c80476e4SDavid E. O'Brien 	}
198c80476e4SDavid E. O'Brien 	else
199c80476e4SDavid E. O'Brien 	    AddXkey(&in, XmapStr(&out), ntype);
200c80476e4SDavid E. O'Brien 	map[ch] = F_XKEY;
201c80476e4SDavid E. O'Brien 	break;
202c80476e4SDavid E. O'Brien     case XK_CMD:
20345e5710bSMark Peek 	if ((cmd = parsecmd(v[no])) == 0) {
20445e5710bSMark Peek 	    cleanup_until(in.buf);
205c80476e4SDavid E. O'Brien 	    return;
20645e5710bSMark Peek 	}
207c80476e4SDavid E. O'Brien 	if (key)
208c80476e4SDavid E. O'Brien 	    (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
209c80476e4SDavid E. O'Brien 	else {
210c80476e4SDavid E. O'Brien 	    if (in.len > 1) {
211c80476e4SDavid E. O'Brien 		AddXkey(&in, XmapCmd((int) cmd), ntype);
212c80476e4SDavid E. O'Brien 		map[ch] = F_XKEY;
213c80476e4SDavid E. O'Brien 	    }
214c80476e4SDavid E. O'Brien 	    else {
215c80476e4SDavid E. O'Brien 		ClearXkey(map, &in);
216c80476e4SDavid E. O'Brien 		map[ch] = cmd;
217c80476e4SDavid E. O'Brien 	    }
218c80476e4SDavid E. O'Brien 	}
219c80476e4SDavid E. O'Brien 	break;
220c80476e4SDavid E. O'Brien     default:
221c80476e4SDavid E. O'Brien 	abort();
222c80476e4SDavid E. O'Brien 	break;
223c80476e4SDavid E. O'Brien     }
22445e5710bSMark Peek     cleanup_until(in.buf);
225c80476e4SDavid E. O'Brien     if (key)
226c80476e4SDavid E. O'Brien 	BindArrowKeys();
227c80476e4SDavid E. O'Brien }
228c80476e4SDavid E. O'Brien 
229c80476e4SDavid E. O'Brien static void
23045e5710bSMark Peek printkey(const KEYCMD *map, CStr *in)
231c80476e4SDavid E. O'Brien {
23223338178SMark Peek     struct KeyFuncs *fp;
233c80476e4SDavid E. O'Brien 
234c80476e4SDavid E. O'Brien     if (in->len < 2) {
23545e5710bSMark Peek 	unsigned char *unparsed;
23645e5710bSMark Peek 
23745e5710bSMark Peek 	unparsed = unparsestring(in, STRQQ);
23845e5710bSMark Peek 	cleanup_push(unparsed, xfree);
239c80476e4SDavid E. O'Brien 	for (fp = FuncNames; fp->name; fp++) {
240c80476e4SDavid E. O'Brien 	    if (fp->func == map[(uChar) *(in->buf)]) {
24145e5710bSMark Peek 		xprintf("%s\t->\t%s\n", unparsed, fp->name);
242c80476e4SDavid E. O'Brien 	    }
243c80476e4SDavid E. O'Brien 	}
24445e5710bSMark Peek 	cleanup_until(unparsed);
245c80476e4SDavid E. O'Brien     }
246c80476e4SDavid E. O'Brien     else
247c80476e4SDavid E. O'Brien 	PrintXkey(in);
248c80476e4SDavid E. O'Brien }
249c80476e4SDavid E. O'Brien 
250c80476e4SDavid E. O'Brien static  KEYCMD
25145e5710bSMark Peek parsecmd(Char *str)
252c80476e4SDavid E. O'Brien {
25323338178SMark Peek     struct KeyFuncs *fp;
254c80476e4SDavid E. O'Brien 
255c80476e4SDavid E. O'Brien     for (fp = FuncNames; fp->name; fp++) {
256c80476e4SDavid E. O'Brien 	if (strcmp(short2str(str), fp->name) == 0) {
257c80476e4SDavid E. O'Brien 	    return (KEYCMD) fp->func;
258c80476e4SDavid E. O'Brien 	}
259c80476e4SDavid E. O'Brien     }
260c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
261c80476e4SDavid E. O'Brien     return 0;
262c80476e4SDavid E. O'Brien }
263c80476e4SDavid E. O'Brien 
264c80476e4SDavid E. O'Brien 
265c80476e4SDavid E. O'Brien static void
26645e5710bSMark Peek bad_spec(const Char *str)
267c80476e4SDavid E. O'Brien {
268c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
269c80476e4SDavid E. O'Brien }
270c80476e4SDavid E. O'Brien 
271c80476e4SDavid E. O'Brien static CStr *
27245e5710bSMark Peek parsebind(const Char *s, CStr *str)
273c80476e4SDavid E. O'Brien {
27445e5710bSMark Peek     struct Strbuf b = Strbuf_INIT;
275c80476e4SDavid E. O'Brien 
27645e5710bSMark Peek     cleanup_push(&b, Strbuf_cleanup);
277c80476e4SDavid E. O'Brien     if (Iscntrl(*s)) {
27845e5710bSMark Peek 	Strbuf_append1(&b, *s);
27945e5710bSMark Peek 	goto end;
280c80476e4SDavid E. O'Brien     }
281c80476e4SDavid E. O'Brien 
282c80476e4SDavid E. O'Brien     switch (*s) {
283c80476e4SDavid E. O'Brien     case '^':
284c80476e4SDavid E. O'Brien 	s++;
2853b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
28645e5710bSMark Peek 	Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
2873b6eaa7bSAndrey A. Chernov #else
28845e5710bSMark Peek 	Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
28945e5710bSMark Peek 		       : _toebcdic[_toascii[*s & CHAR] & 0237]);
2903b6eaa7bSAndrey A. Chernov #endif
291c80476e4SDavid E. O'Brien 	break;
292c80476e4SDavid E. O'Brien 
293c80476e4SDavid E. O'Brien     case 'F':
294c80476e4SDavid E. O'Brien     case 'M':
295c80476e4SDavid E. O'Brien     case 'X':
296c80476e4SDavid E. O'Brien     case 'C':
2973b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
298c80476e4SDavid E. O'Brien     case 'N':
2993b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
30045e5710bSMark Peek 	if (s[1] != '-' || s[2] == '\0')
30145e5710bSMark Peek 	    goto bad_spec;
302c80476e4SDavid E. O'Brien 	s += 2;
303c80476e4SDavid E. O'Brien 	switch (s[-2]) {
304c80476e4SDavid E. O'Brien 	case 'F': case 'f':	/* Turn into ^[str */
30545e5710bSMark Peek 	    Strbuf_append1(&b, CTL_ESC('\033'));
30645e5710bSMark Peek 	    Strbuf_append(&b, s);
307c80476e4SDavid E. O'Brien 	    break;
308c80476e4SDavid E. O'Brien 
309c80476e4SDavid E. O'Brien 	case 'C': case 'c':	/* Turn into ^c */
3103b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
31145e5710bSMark Peek 	    Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
3123b6eaa7bSAndrey A. Chernov #else
31345e5710bSMark Peek 	    Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
31445e5710bSMark Peek 			   : _toebcdic[_toascii[*s & CHAR] & 0237]);
3153b6eaa7bSAndrey A. Chernov #endif
316c80476e4SDavid E. O'Brien 	    break;
317c80476e4SDavid E. O'Brien 
318c80476e4SDavid E. O'Brien 	case 'X' : case 'x':	/* Turn into ^Xc */
3193b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
32045e5710bSMark Peek 	    Strbuf_append1(&b, 'X' & 0237);
3213b6eaa7bSAndrey A. Chernov #else
32245e5710bSMark Peek 	    Strbuf_append1(&b, _toebcdic[_toascii['X'] & 0237]);
3233b6eaa7bSAndrey A. Chernov #endif
32445e5710bSMark Peek 	    Strbuf_append1(&b, *s);
325c80476e4SDavid E. O'Brien 	    break;
326c80476e4SDavid E. O'Brien 
327c80476e4SDavid E. O'Brien 	case 'M' : case 'm':	/* Turn into 0x80|c */
328c80476e4SDavid E. O'Brien 	    if (!NoNLSRebind) {
32945e5710bSMark Peek 		Strbuf_append1(&b, CTL_ESC('\033'));
33045e5710bSMark Peek 	    	Strbuf_append1(&b, *s);
331c80476e4SDavid E. O'Brien 	    } else {
3323b6eaa7bSAndrey A. Chernov #ifdef IS_ASCII
33345e5710bSMark Peek 		Strbuf_append1(&b, *s | 0x80);
3343b6eaa7bSAndrey A. Chernov #else
33545e5710bSMark Peek 		Strbuf_append1(&b, _toebcdic[_toascii[*s] | 0x80]);
3363b6eaa7bSAndrey A. Chernov #endif
337c80476e4SDavid E. O'Brien 	    }
338c80476e4SDavid E. O'Brien 	    break;
3393b6eaa7bSAndrey A. Chernov #ifdef WINNT_NATIVE
340c80476e4SDavid E. O'Brien 	case 'N' : case 'n':	/* NT */
341c80476e4SDavid E. O'Brien 		{
342c80476e4SDavid E. O'Brien 			Char bnt;
343c80476e4SDavid E. O'Brien 
344c80476e4SDavid E. O'Brien 			bnt = nt_translate_bindkey(s);
345c80476e4SDavid E. O'Brien 			if (bnt != 0)
34645e5710bSMark Peek 			        Strbuf_append1(&b, bnt);
347c80476e4SDavid E. O'Brien 			else
348c80476e4SDavid E. O'Brien 				bad_spec(s);
349c80476e4SDavid E. O'Brien 		}
350c80476e4SDavid E. O'Brien 	    break;
3513b6eaa7bSAndrey A. Chernov #endif /* WINNT_NATIVE */
352c80476e4SDavid E. O'Brien 
353c80476e4SDavid E. O'Brien 	default:
354c80476e4SDavid E. O'Brien 	    abort();
355c80476e4SDavid E. O'Brien 	}
356c80476e4SDavid E. O'Brien 	break;
357c80476e4SDavid E. O'Brien 
358c80476e4SDavid E. O'Brien     default:
35945e5710bSMark Peek 	goto bad_spec;
360c80476e4SDavid E. O'Brien     }
361c80476e4SDavid E. O'Brien 
36245e5710bSMark Peek  end:
36345e5710bSMark Peek     cleanup_ignore(&b);
36445e5710bSMark Peek     cleanup_until(&b);
36545e5710bSMark Peek     Strbuf_terminate(&b);
36645e5710bSMark Peek     str->buf = xrealloc(b.s, (b.len + 1) * sizeof (*str->buf));
36745e5710bSMark Peek     str->len = b.len;
368c80476e4SDavid E. O'Brien     return str;
36945e5710bSMark Peek 
37045e5710bSMark Peek  bad_spec:
37145e5710bSMark Peek     bad_spec(s);
37245e5710bSMark Peek     cleanup_until(&b);
37345e5710bSMark Peek     return NULL;
374c80476e4SDavid E. O'Brien }
375c80476e4SDavid E. O'Brien 
376c80476e4SDavid E. O'Brien 
377c80476e4SDavid E. O'Brien static CStr *
37845e5710bSMark Peek parsestring(const Char *str, CStr *buf)
379c80476e4SDavid E. O'Brien {
38045e5710bSMark Peek     struct Strbuf b = Strbuf_INIT;
381c80476e4SDavid E. O'Brien     const Char   *p;
38223338178SMark Peek     eChar  es;
383c80476e4SDavid E. O'Brien 
384c80476e4SDavid E. O'Brien     if (*str == 0) {
385c80476e4SDavid E. O'Brien 	xprintf(CGETS(20, 5, "Null string specification\n"));
386c80476e4SDavid E. O'Brien 	return NULL;
387c80476e4SDavid E. O'Brien     }
388c80476e4SDavid E. O'Brien 
38945e5710bSMark Peek     cleanup_push(&b, Strbuf_cleanup);
390c80476e4SDavid E. O'Brien     for (p = str; *p != 0; p++) {
391c80476e4SDavid E. O'Brien 	if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
39245e5710bSMark Peek 	    if ((es = parseescape(&p)) == CHAR_ERR) {
39345e5710bSMark Peek 		cleanup_until(&b);
394c80476e4SDavid E. O'Brien 		return 0;
39545e5710bSMark Peek 	    } else
39645e5710bSMark Peek 		Strbuf_append1(&b, es);
397c80476e4SDavid E. O'Brien 	}
398c80476e4SDavid E. O'Brien 	else
39945e5710bSMark Peek 	    Strbuf_append1(&b, *p & CHAR);
400c80476e4SDavid E. O'Brien     }
40145e5710bSMark Peek     cleanup_ignore(&b);
40245e5710bSMark Peek     cleanup_until(&b);
40345e5710bSMark Peek     Strbuf_terminate(&b);
40445e5710bSMark Peek     buf->buf = xrealloc(b.s, (b.len + 1) * sizeof (*buf->buf));
40545e5710bSMark Peek     buf->len = b.len;
406c80476e4SDavid E. O'Brien     return buf;
407c80476e4SDavid E. O'Brien }
408c80476e4SDavid E. O'Brien 
409c80476e4SDavid E. O'Brien static void
41045e5710bSMark Peek print_all_keys(void)
411c80476e4SDavid E. O'Brien {
412c80476e4SDavid E. O'Brien     int     prev, i;
413c80476e4SDavid E. O'Brien     CStr nilstr;
414c80476e4SDavid E. O'Brien     nilstr.buf = NULL;
415c80476e4SDavid E. O'Brien     nilstr.len = 0;
416c80476e4SDavid E. O'Brien 
417c80476e4SDavid E. O'Brien 
418c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 6, "Standard key bindings\n"));
419c80476e4SDavid E. O'Brien     prev = 0;
420c80476e4SDavid E. O'Brien     for (i = 0; i < 256; i++) {
421c80476e4SDavid E. O'Brien 	if (CcKeyMap[prev] == CcKeyMap[i])
422c80476e4SDavid E. O'Brien 	    continue;
423c80476e4SDavid E. O'Brien 	printkeys(CcKeyMap, prev, i - 1);
424c80476e4SDavid E. O'Brien 	prev = i;
425c80476e4SDavid E. O'Brien     }
426c80476e4SDavid E. O'Brien     printkeys(CcKeyMap, prev, i - 1);
427c80476e4SDavid E. O'Brien 
428c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 7, "Alternative key bindings\n"));
429c80476e4SDavid E. O'Brien     prev = 0;
430c80476e4SDavid E. O'Brien     for (i = 0; i < 256; i++) {
431c80476e4SDavid E. O'Brien 	if (CcAltMap[prev] == CcAltMap[i])
432c80476e4SDavid E. O'Brien 	    continue;
433c80476e4SDavid E. O'Brien 	printkeys(CcAltMap, prev, i - 1);
434c80476e4SDavid E. O'Brien 	prev = i;
435c80476e4SDavid E. O'Brien     }
436c80476e4SDavid E. O'Brien     printkeys(CcAltMap, prev, i - 1);
437c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 8, "Multi-character bindings\n"));
438c80476e4SDavid E. O'Brien     PrintXkey(NULL);	/* print all Xkey bindings */
439c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 9, "Arrow key bindings\n"));
440c80476e4SDavid E. O'Brien     PrintArrowKeys(&nilstr);
441c80476e4SDavid E. O'Brien }
442c80476e4SDavid E. O'Brien 
443c80476e4SDavid E. O'Brien static void
44445e5710bSMark Peek printkeys(KEYCMD *map, int first, int last)
445c80476e4SDavid E. O'Brien {
44623338178SMark Peek     struct KeyFuncs *fp;
447c80476e4SDavid E. O'Brien     Char    firstbuf[2], lastbuf[2];
448c80476e4SDavid E. O'Brien     CStr fb, lb;
44945e5710bSMark Peek     unsigned char *unparsed;
450c80476e4SDavid E. O'Brien     fb.buf = firstbuf;
451c80476e4SDavid E. O'Brien     lb.buf = lastbuf;
452c80476e4SDavid E. O'Brien 
453c80476e4SDavid E. O'Brien     firstbuf[0] = (Char) first;
454c80476e4SDavid E. O'Brien     firstbuf[1] = 0;
455c80476e4SDavid E. O'Brien     lastbuf[0] = (Char) last;
456c80476e4SDavid E. O'Brien     lastbuf[1] = 0;
457c80476e4SDavid E. O'Brien     fb.len = 1;
458c80476e4SDavid E. O'Brien     lb.len = 1;
459c80476e4SDavid E. O'Brien 
46045e5710bSMark Peek     unparsed = unparsestring(&fb, STRQQ);
46145e5710bSMark Peek     cleanup_push(unparsed, xfree);
462c80476e4SDavid E. O'Brien     if (map[first] == F_UNASSIGNED) {
463c80476e4SDavid E. O'Brien 	if (first == last)
46445e5710bSMark Peek 	    xprintf(CGETS(20, 10, "%-15s->  is undefined\n"), unparsed);
46545e5710bSMark Peek 	cleanup_until(unparsed);
466c80476e4SDavid E. O'Brien 	return;
467c80476e4SDavid E. O'Brien     }
468c80476e4SDavid E. O'Brien 
469c80476e4SDavid E. O'Brien     for (fp = FuncNames; fp->name; fp++) {
470c80476e4SDavid E. O'Brien 	if (fp->func == map[first]) {
47145e5710bSMark Peek 	    if (first == last)
47245e5710bSMark Peek 		xprintf("%-15s->  %s\n", unparsed, fp->name);
473c80476e4SDavid E. O'Brien 	    else {
47445e5710bSMark Peek 		unsigned char *p;
47545e5710bSMark Peek 
47645e5710bSMark Peek 		p = unparsestring(&lb, STRQQ);
47745e5710bSMark Peek 		cleanup_push(p, xfree);
47845e5710bSMark Peek 		xprintf("%-4s to %-7s->  %s\n", unparsed, p, fp->name);
479c80476e4SDavid E. O'Brien 	    }
48045e5710bSMark Peek 	    cleanup_until(unparsed);
481c80476e4SDavid E. O'Brien 	    return;
482c80476e4SDavid E. O'Brien 	}
483c80476e4SDavid E. O'Brien     }
48445e5710bSMark Peek     xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), unparsed);
48545e5710bSMark Peek     if (map == CcKeyMap)
486c80476e4SDavid E. O'Brien 	xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
48745e5710bSMark Peek     else
488c80476e4SDavid E. O'Brien 	xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
48945e5710bSMark Peek     cleanup_until(unparsed);
490c80476e4SDavid E. O'Brien }
491c80476e4SDavid E. O'Brien 
492c80476e4SDavid E. O'Brien static void
49345e5710bSMark Peek bindkey_usage(void)
494c80476e4SDavid E. O'Brien {
495c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 12,
496c80476e4SDavid E. O'Brien 	    "Usage: bindkey [options] [--] [KEY [COMMAND]]\n"));
497c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 13,
498c80476e4SDavid E. O'Brien     	    "    -a   list or bind KEY in alternative key map\n"));
499c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 14,
500c80476e4SDavid E. O'Brien 	    "    -b   interpret KEY as a C-, M-, F- or X- key name\n"));
501c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 15,
502c80476e4SDavid E. O'Brien             "    -s   interpret COMMAND as a literal string to be output\n"));
503c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 16,
504c80476e4SDavid E. O'Brien             "    -c   interpret COMMAND as a builtin or external command\n"));
505c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 17,
506c80476e4SDavid E. O'Brien 	    "    -v   bind all keys to vi bindings\n"));
507c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 18,
508c80476e4SDavid E. O'Brien 	    "    -e   bind all keys to emacs bindings\n"));
509c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 19,
510c80476e4SDavid E. O'Brien 	    "    -d   bind all keys to default editor's bindings\n"));
511c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 20,
512c80476e4SDavid E. O'Brien 	    "    -l   list editor commands with descriptions\n"));
513c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 21,
514c80476e4SDavid E. O'Brien 	    "    -r   remove KEY's binding\n"));
515c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 22,
516c80476e4SDavid E. O'Brien 	    "    -k   interpret KEY as a symbolic arrow-key name\n"));
517c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 23,
518c80476e4SDavid E. O'Brien 	    "    --   force a break from option processing\n"));
519c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 24,
520c80476e4SDavid E. O'Brien 	    "    -u   (or any invalid option) this message\n"));
521c80476e4SDavid E. O'Brien     xprintf("\n");
522c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 25,
523c80476e4SDavid E. O'Brien 	    "Without KEY or COMMAND, prints all bindings\n"));
524c80476e4SDavid E. O'Brien     xprintf(CGETS(20, 26,
525c80476e4SDavid E. O'Brien 	    "Without COMMAND, prints the binding for KEY.\n"));
526c80476e4SDavid E. O'Brien }
527c80476e4SDavid E. O'Brien 
528c80476e4SDavid E. O'Brien static void
52945e5710bSMark Peek list_functions(void)
530c80476e4SDavid E. O'Brien {
53123338178SMark Peek     struct KeyFuncs *fp;
532c80476e4SDavid E. O'Brien 
533c80476e4SDavid E. O'Brien     for (fp = FuncNames; fp->name; fp++) {
534c80476e4SDavid E. O'Brien 	xprintf("%s\n          %s\n", fp->name, fp->desc);
535c80476e4SDavid E. O'Brien     }
536c80476e4SDavid E. O'Brien }
537