xref: /dragonfly/contrib/tcsh-6/tc.bind.c (revision 84d884bf08edef6c02f15218458cd5df8010b654)
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