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