drm/linux: Improve put_user()
[dragonfly.git] / contrib / tcsh-6 / tc.bind.c
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
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
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
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
262 bad_spec(const Char *str)
263 {
264     xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
265 }
266
267 static CStr *
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 *
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
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
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
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
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 }