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