xref: /dragonfly/contrib/tcsh-6/tc.bind.c (revision b97fef05)
1 /*
2  * tc.bind.c: Key binding functions
3  */
4 /*-
5  * Copyright (c) 1980, 1991 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 #include "sh.h"
33 #include "ed.h"
34 #include "ed.defns.h"
35 #include "tw.h"
36 
37 static	void   printkey		(const KEYCMD *, CStr *);
38 static	KEYCMD parsecmd		(Char *);
39 static  void   bad_spec		(const Char *);
40 static	CStr  *parsestring	(const Char *, CStr *);
41 static	CStr  *parsebind	(const Char *, CStr *);
42 static	void   print_all_keys	(void);
43 static	void   printkeys	(KEYCMD *, int, int);
44 static	void   bindkey_usage	(void);
45 static	void   list_functions	(void);
46 
47 extern int MapsAreInited;
48 
49 
50 
51 
52 /*ARGSUSED*/
53 void
54 dobindkey(Char **v, struct command *c)
55 {
56     KEYCMD *map;
57     int     ntype, no, removeb, key, bindk;
58     Char   *par;
59     Char    p;
60     KEYCMD  cmd;
61     CStr    in;
62     CStr    out;
63     uChar   ch;
64 
65     USE(c);
66     if (!MapsAreInited)
67 	ed_InitMaps();
68 
69     map = CcKeyMap;
70     ntype = XK_CMD;
71     key = removeb = bindk = 0;
72     for (no = 1, par = v[no];
73 	 par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
74 	if ((p = (*par & CHAR)) == '-') {
75 	    no++;
76 	    break;
77 	}
78 	else
79 	    switch (p) {
80 	    case 'b':
81 		bindk = 1;
82 		break;
83 	    case 'k':
84 		key = 1;
85 		break;
86 	    case 'a':
87 		map = CcAltMap;
88 		break;
89 	    case 's':
90 		ntype = XK_STR;
91 		break;
92 	    case 'c':
93 		ntype = XK_EXE;
94 		break;
95 	    case 'r':
96 		removeb = 1;
97 		break;
98 	    case 'v':
99 		ed_InitVIMaps();
100 		return;
101 	    case 'e':
102 		ed_InitEmacsMaps();
103 		return;
104 	    case 'd':
105 #ifdef VIDEFAULT
106 		ed_InitVIMaps();
107 #else /* EMACSDEFAULT */
108 		ed_InitEmacsMaps();
109 #endif /* VIDEFAULT */
110 		return;
111 	    case 'l':
112 		list_functions();
113 		return;
114 	    default:
115 		bindkey_usage();
116 		return;
117 	    }
118     }
119 
120     if (!v[no]) {
121 	print_all_keys();
122 	return;
123     }
124 
125     if (key) {
126 	if (!IsArrowKey(v[no]))
127 	    xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
128 	in.buf = Strsave(v[no++]);
129 	in.len = Strlen(in.buf);
130     }
131     else {
132 	if (bindk) {
133 	    if (parsebind(v[no++], &in) == NULL)
134 		return;
135 	}
136 	else {
137 	    if (parsestring(v[no++], &in) == NULL)
138 		return;
139 	}
140     }
141     cleanup_push(in.buf, xfree);
142 
143 #if !defined(WINNT_NATIVE) && defined(SHORT_STRINGS)
144     if (in.buf[0] > 0xFF) {
145 	bad_spec(in.buf);
146 	cleanup_until(in.buf);
147 	return;
148     }
149 #endif
150     ch = (uChar) in.buf[0];
151 
152     if (removeb) {
153 	if (key)
154 	    (void) ClearArrowKeys(&in);
155 	else if (in.len > 1) {
156 	    (void) DeleteXkey(&in);
157 	}
158 	else if (map[ch] == F_XKEY) {
159 	    (void) DeleteXkey(&in);
160 	    map[ch] = F_UNASSIGNED;
161 	}
162 	else {
163 	    map[ch] = F_UNASSIGNED;
164 	}
165 	cleanup_until(in.buf);
166 	return;
167     }
168     if (!v[no]) {
169 	if (key)
170 	    PrintArrowKeys(&in);
171 	else
172 	    printkey(map, &in);
173 	cleanup_until(in.buf);
174 	return;
175     }
176     if (v[no + 1]) {
177 	bindkey_usage();
178 	cleanup_until(in.buf);
179 	return;
180     }
181     switch (ntype) {
182     case XK_STR:
183     case XK_EXE:
184 	if (parsestring(v[no], &out) == NULL) {
185 	    cleanup_until(in.buf);
186 	    return;
187 	}
188 	cleanup_push(out.buf, xfree);
189 	if (key) {
190 	    if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
191 		xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf);
192 	    else
193 		cleanup_ignore(out.buf);
194 	}
195 	else
196 	    AddXkey(&in, XmapStr(&out), ntype);
197 	map[ch] = F_XKEY;
198 	break;
199     case XK_CMD:
200 	if ((cmd = parsecmd(v[no])) == 0) {
201 	    cleanup_until(in.buf);
202 	    return;
203 	}
204 	if (key)
205 	    (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
206 	else {
207 	    if (in.len > 1) {
208 		AddXkey(&in, XmapCmd((int) cmd), ntype);
209 		map[ch] = F_XKEY;
210 	    }
211 	    else {
212 		ClearXkey(map, &in);
213 		map[ch] = cmd;
214 	    }
215 	}
216 	break;
217     default:
218 	abort();
219 	break;
220     }
221     cleanup_until(in.buf);
222     if (key)
223 	BindArrowKeys();
224 }
225 
226 static void
227 printkey(const KEYCMD *map, CStr *in)
228 {
229     struct KeyFuncs *fp;
230 
231     if (in->len < 2) {
232 	unsigned char *unparsed;
233 
234 	unparsed = unparsestring(in, STRQQ);
235 	cleanup_push(unparsed, xfree);
236 	for (fp = FuncNames; fp->name; fp++) {
237 	    if (fp->func == map[(uChar) *(in->buf)]) {
238 		xprintf("%s\t->\t%s\n", unparsed, fp->name);
239 	    }
240 	}
241 	cleanup_until(unparsed);
242     }
243     else
244 	PrintXkey(in);
245 }
246 
247 static  KEYCMD
248 parsecmd(Char *str)
249 {
250     struct KeyFuncs *fp;
251 
252     for (fp = FuncNames; fp->name; fp++) {
253 	if (strcmp(short2str(str), fp->name) == 0) {
254 	    return (KEYCMD) fp->func;
255 	}
256     }
257     xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
258     return 0;
259 }
260 
261 
262 static void
263 bad_spec(const Char *str)
264 {
265     xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
266 }
267 
268 static CStr *
269 parsebind(const Char *s, CStr *str)
270 {
271     struct Strbuf b = Strbuf_INIT;
272 
273     cleanup_push(&b, Strbuf_cleanup);
274     if (Iscntrl(*s)) {
275 	Strbuf_append1(&b, *s);
276 	goto end;
277     }
278 
279     switch (*s) {
280     case '^':
281 	s++;
282 #ifdef IS_ASCII
283 	Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
284 #else
285 	Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
286 		       : _toebcdic[_toascii[*s & CHAR] & 0237]);
287 #endif
288 	break;
289 
290     case 'F':
291     case 'M':
292     case 'X':
293     case 'C':
294 #ifdef WINNT_NATIVE
295     case 'N':
296 #endif /* WINNT_NATIVE */
297 	if (s[1] != '-' || s[2] == '\0')
298 	    goto bad_spec;
299 	s += 2;
300 	switch (s[-2]) {
301 	case 'F': case 'f':	/* Turn into ^[str */
302 	    Strbuf_append1(&b, CTL_ESC('\033'));
303 	    Strbuf_append(&b, s);
304 	    break;
305 
306 	case 'C': case 'c':	/* Turn into ^c */
307 #ifdef IS_ASCII
308 	    Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
309 #else
310 	    Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
311 			   : _toebcdic[_toascii[*s & CHAR] & 0237]);
312 #endif
313 	    break;
314 
315 	case 'X' : case 'x':	/* Turn into ^Xc */
316 #ifdef IS_ASCII
317 	    Strbuf_append1(&b, 'X' & 0237);
318 #else
319 	    Strbuf_append1(&b, _toebcdic[_toascii['X'] & 0237]);
320 #endif
321 	    Strbuf_append1(&b, *s);
322 	    break;
323 
324 	case 'M' : case 'm':	/* Turn into 0x80|c */
325 	    if (!NoNLSRebind) {
326 		Strbuf_append1(&b, CTL_ESC('\033'));
327 	    	Strbuf_append1(&b, *s);
328 	    } else {
329 #ifdef IS_ASCII
330 		Strbuf_append1(&b, *s | 0x80);
331 #else
332 		Strbuf_append1(&b, _toebcdic[_toascii[*s] | 0x80]);
333 #endif
334 	    }
335 	    break;
336 #ifdef WINNT_NATIVE
337 	case 'N' : case 'n':	/* NT */
338 		{
339 			Char bnt;
340 
341 			bnt = nt_translate_bindkey(s);
342 			if (bnt != 0)
343 			        Strbuf_append1(&b, bnt);
344 			else
345 				bad_spec(s);
346 		}
347 	    break;
348 #endif /* WINNT_NATIVE */
349 
350 	default:
351 	    abort();
352 	}
353 	break;
354 
355     default:
356 	goto bad_spec;
357     }
358 
359  end:
360     cleanup_ignore(&b);
361     cleanup_until(&b);
362     Strbuf_terminate(&b);
363     str->buf = xrealloc(b.s, (b.len + 1) * sizeof (*str->buf));
364     str->len = b.len;
365     return str;
366 
367  bad_spec:
368     bad_spec(s);
369     cleanup_until(&b);
370     return NULL;
371 }
372 
373 
374 static CStr *
375 parsestring(const Char *str, CStr *buf)
376 {
377     struct Strbuf b = Strbuf_INIT;
378     const Char   *p;
379     eChar  es;
380 
381     if (*str == 0) {
382 	xprintf("%s", CGETS(20, 5, "Null string specification\n"));
383 	return NULL;
384     }
385 
386     cleanup_push(&b, Strbuf_cleanup);
387     for (p = str; *p != 0; p++) {
388 	if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
389 	    if ((es = parseescape(&p, TRUE)) == CHAR_ERR) {
390 		cleanup_until(&b);
391 		return 0;
392 	    } else
393 		Strbuf_append1(&b, es);
394 	}
395 	else
396 	    Strbuf_append1(&b, *p & CHAR);
397     }
398     cleanup_ignore(&b);
399     cleanup_until(&b);
400     Strbuf_terminate(&b);
401     buf->buf = xrealloc(b.s, (b.len + 1) * sizeof (*buf->buf));
402     buf->len = b.len;
403     return buf;
404 }
405 
406 static void
407 print_all_keys(void)
408 {
409     int     prev, i;
410     CStr nilstr;
411     nilstr.buf = NULL;
412     nilstr.len = 0;
413 
414 
415     xprintf("%s", CGETS(20, 6, "Standard key bindings\n"));
416     prev = 0;
417     for (i = 0; i < 256; i++) {
418 	if (CcKeyMap[prev] == CcKeyMap[i])
419 	    continue;
420 	printkeys(CcKeyMap, prev, i - 1);
421 	prev = i;
422     }
423     printkeys(CcKeyMap, prev, i - 1);
424 
425     xprintf("%s", CGETS(20, 7, "Alternative key bindings\n"));
426     prev = 0;
427     for (i = 0; i < 256; i++) {
428 	if (CcAltMap[prev] == CcAltMap[i])
429 	    continue;
430 	printkeys(CcAltMap, prev, i - 1);
431 	prev = i;
432     }
433     printkeys(CcAltMap, prev, i - 1);
434     xprintf("%s", CGETS(20, 8, "Multi-character bindings\n"));
435     PrintXkey(NULL);	/* print all Xkey bindings */
436     xprintf("%s", CGETS(20, 9, "Arrow key bindings\n"));
437     PrintArrowKeys(&nilstr);
438 }
439 
440 static void
441 printkeys(KEYCMD *map, int first, int last)
442 {
443     struct KeyFuncs *fp;
444     Char    firstbuf[2], lastbuf[2];
445     CStr fb, lb;
446     unsigned char *unparsed;
447     fb.buf = firstbuf;
448     lb.buf = lastbuf;
449 
450     firstbuf[0] = (Char) first;
451     firstbuf[1] = 0;
452     lastbuf[0] = (Char) last;
453     lastbuf[1] = 0;
454     fb.len = 1;
455     lb.len = 1;
456 
457     unparsed = unparsestring(&fb, STRQQ);
458     cleanup_push(unparsed, xfree);
459     if (map[first] == F_UNASSIGNED) {
460 	if (first == last)
461 	    xprintf(CGETS(20, 10, "%-15s->  is undefined\n"), unparsed);
462 	cleanup_until(unparsed);
463 	return;
464     }
465 
466     for (fp = FuncNames; fp->name; fp++) {
467 	if (fp->func == map[first]) {
468 	    if (first == last)
469 		xprintf("%-15s->  %s\n", unparsed, fp->name);
470 	    else {
471 		unsigned char *p;
472 
473 		p = unparsestring(&lb, STRQQ);
474 		cleanup_push(p, xfree);
475 		xprintf("%-4s to %-7s->  %s\n", unparsed, p, fp->name);
476 	    }
477 	    cleanup_until(unparsed);
478 	    return;
479 	}
480     }
481     xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), unparsed);
482     if (map == CcKeyMap)
483 	xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
484     else
485 	xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
486     cleanup_until(unparsed);
487 }
488 
489 static void
490 bindkey_usage(void)
491 {
492     xprintf("%s", CGETS(20, 12,
493 	    "Usage: bindkey [options] [--] [KEY [COMMAND]]\n"));
494     xprintf("%s", CGETS(20, 13,
495     	    "    -a   list or bind KEY in alternative key map\n"));
496     xprintf("%s", CGETS(20, 14,
497 	    "    -b   interpret KEY as a C-, M-, F- or X- key name\n"));
498     xprintf("%s", CGETS(20, 15,
499             "    -s   interpret COMMAND as a literal string to be output\n"));
500     xprintf("%s", CGETS(20, 16,
501             "    -c   interpret COMMAND as a builtin or external command\n"));
502     xprintf("%s", CGETS(20, 17,
503 	    "    -v   bind all keys to vi bindings\n"));
504     xprintf("%s", CGETS(20, 18,
505 	    "    -e   bind all keys to emacs bindings\n"));
506     xprintf(CGETS(20, 19,
507 	    "    -d   bind all keys to default editor's bindings (%s)\n"),
508 #ifdef VIDEFAULT
509 	    "vi"
510 #else /* EMACSDEFAULT */
511 	    "emacs"
512 #endif /* VIDEFAULT */
513 	    );
514     xprintf("%s", CGETS(20, 20,
515 	    "    -l   list editor commands with descriptions\n"));
516     xprintf("%s", CGETS(20, 21,
517 	    "    -r   remove KEY's binding\n"));
518     xprintf("%s", CGETS(20, 22,
519 	    "    -k   interpret KEY as a symbolic arrow-key name\n"));
520     xprintf("%s", CGETS(20, 23,
521 	    "    --   force a break from option processing\n"));
522     xprintf("%s", CGETS(20, 24,
523 	    "    -u   (or any invalid option) this message\n"));
524     xprintf("\n");
525     xprintf("%s", CGETS(20, 25,
526 	    "Without KEY or COMMAND, prints all bindings\n"));
527     xprintf("%s", CGETS(20, 26,
528 	    "Without COMMAND, prints the binding for KEY.\n"));
529 }
530 
531 static void
532 list_functions(void)
533 {
534     struct KeyFuncs *fp;
535 
536     for (fp = FuncNames; fp->name; fp++) {
537 	xprintf("%s\n          %s\n", fp->name, fp->desc);
538     }
539 }
540