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
dobindkey(Char ** v,struct command * c)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
printkey(const KEYCMD * map,CStr * in)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
parsecmd(Char * str)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
bad_spec(const Char * str)263 bad_spec(const Char *str)
264 {
265 xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
266 }
267
268 static CStr *
parsebind(const Char * s,CStr * str)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 *
parsestring(const Char * str,CStr * buf)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
print_all_keys(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
printkeys(KEYCMD * map,int first,int last)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
bindkey_usage(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
list_functions(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