summaryrefslogtreecommitdiffstats
path: root/contrib/tcsh/tc.bind.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcsh/tc.bind.c')
-rw-r--r--contrib/tcsh/tc.bind.c536
1 files changed, 536 insertions, 0 deletions
diff --git a/contrib/tcsh/tc.bind.c b/contrib/tcsh/tc.bind.c
new file mode 100644
index 0000000..c8de1c2
--- /dev/null
+++ b/contrib/tcsh/tc.bind.c
@@ -0,0 +1,536 @@
+/* $Header: /p/tcsh/cvsroot/tcsh/tc.bind.c,v 3.45 2009/06/25 21:15:37 christos Exp $ */
+/*
+ * tc.bind.c: Key binding functions
+ */
+/*-
+ * Copyright (c) 1980, 1991 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include "sh.h"
+
+RCSID("$tcsh: tc.bind.c,v 3.45 2009/06/25 21:15:37 christos Exp $")
+
+#include "ed.h"
+#include "ed.defns.h"
+
+static void printkey (const KEYCMD *, CStr *);
+static KEYCMD parsecmd (Char *);
+static void bad_spec (const Char *);
+static CStr *parsestring (const Char *, CStr *);
+static CStr *parsebind (const Char *, CStr *);
+static void print_all_keys (void);
+static void printkeys (KEYCMD *, int, int);
+static void bindkey_usage (void);
+static void list_functions (void);
+
+extern int MapsAreInited;
+
+
+
+
+/*ARGSUSED*/
+void
+dobindkey(Char **v, struct command *c)
+{
+ KEYCMD *map;
+ int ntype, no, removeb, key, bindk;
+ Char *par;
+ Char p;
+ KEYCMD cmd;
+ CStr in;
+ CStr out;
+ uChar ch;
+
+ USE(c);
+ if (!MapsAreInited)
+ ed_InitMaps();
+
+ map = CcKeyMap;
+ ntype = XK_CMD;
+ key = removeb = bindk = 0;
+ for (no = 1, par = v[no];
+ par != NULL && (*par++ & CHAR) == '-'; no++, par = v[no]) {
+ if ((p = (*par & CHAR)) == '-') {
+ no++;
+ break;
+ }
+ else
+ switch (p) {
+ case 'b':
+ bindk = 1;
+ break;
+ case 'k':
+ key = 1;
+ break;
+ case 'a':
+ map = CcAltMap;
+ break;
+ case 's':
+ ntype = XK_STR;
+ break;
+ case 'c':
+ ntype = XK_EXE;
+ break;
+ case 'r':
+ removeb = 1;
+ break;
+ case 'v':
+ ed_InitVIMaps();
+ return;
+ case 'e':
+ ed_InitEmacsMaps();
+ return;
+ case 'd':
+#ifdef VIDEFAULT
+ ed_InitVIMaps();
+#else /* EMACSDEFAULT */
+ ed_InitEmacsMaps();
+#endif /* VIDEFAULT */
+ return;
+ case 'l':
+ list_functions();
+ return;
+ default:
+ bindkey_usage();
+ return;
+ }
+ }
+
+ if (!v[no]) {
+ print_all_keys();
+ return;
+ }
+
+ if (key) {
+ if (!IsArrowKey(v[no]))
+ xprintf(CGETS(20, 1, "Invalid key name `%S'\n"), v[no]);
+ in.buf = Strsave(v[no++]);
+ in.len = Strlen(in.buf);
+ }
+ else {
+ if (bindk) {
+ if (parsebind(v[no++], &in) == NULL)
+ return;
+ }
+ else {
+ if (parsestring(v[no++], &in) == NULL)
+ return;
+ }
+ }
+ cleanup_push(in.buf, xfree);
+
+#ifndef WINNT_NATIVE
+ if (in.buf[0] > 0xFF) {
+ bad_spec(in.buf);
+ cleanup_until(in.buf);
+ return;
+ }
+#endif
+ ch = (uChar) in.buf[0];
+
+ if (removeb) {
+ if (key)
+ (void) ClearArrowKeys(&in);
+ else if (in.len > 1) {
+ (void) DeleteXkey(&in);
+ }
+ else if (map[ch] == F_XKEY) {
+ (void) DeleteXkey(&in);
+ map[ch] = F_UNASSIGNED;
+ }
+ else {
+ map[ch] = F_UNASSIGNED;
+ }
+ cleanup_until(in.buf);
+ return;
+ }
+ if (!v[no]) {
+ if (key)
+ PrintArrowKeys(&in);
+ else
+ printkey(map, &in);
+ cleanup_until(in.buf);
+ return;
+ }
+ if (v[no + 1]) {
+ bindkey_usage();
+ cleanup_until(in.buf);
+ return;
+ }
+ switch (ntype) {
+ case XK_STR:
+ case XK_EXE:
+ if (parsestring(v[no], &out) == NULL) {
+ cleanup_until(in.buf);
+ return;
+ }
+ cleanup_push(out.buf, xfree);
+ if (key) {
+ if (SetArrowKeys(&in, XmapStr(&out), ntype) == -1)
+ xprintf(CGETS(20, 2, "Bad key name: %S\n"), in.buf);
+ else
+ cleanup_ignore(out.buf);
+ }
+ else
+ AddXkey(&in, XmapStr(&out), ntype);
+ map[ch] = F_XKEY;
+ break;
+ case XK_CMD:
+ if ((cmd = parsecmd(v[no])) == 0) {
+ cleanup_until(in.buf);
+ return;
+ }
+ if (key)
+ (void) SetArrowKeys(&in, XmapCmd((int) cmd), ntype);
+ else {
+ if (in.len > 1) {
+ AddXkey(&in, XmapCmd((int) cmd), ntype);
+ map[ch] = F_XKEY;
+ }
+ else {
+ ClearXkey(map, &in);
+ map[ch] = cmd;
+ }
+ }
+ break;
+ default:
+ abort();
+ break;
+ }
+ cleanup_until(in.buf);
+ if (key)
+ BindArrowKeys();
+}
+
+static void
+printkey(const KEYCMD *map, CStr *in)
+{
+ struct KeyFuncs *fp;
+
+ if (in->len < 2) {
+ unsigned char *unparsed;
+
+ unparsed = unparsestring(in, STRQQ);
+ cleanup_push(unparsed, xfree);
+ for (fp = FuncNames; fp->name; fp++) {
+ if (fp->func == map[(uChar) *(in->buf)]) {
+ xprintf("%s\t->\t%s\n", unparsed, fp->name);
+ }
+ }
+ cleanup_until(unparsed);
+ }
+ else
+ PrintXkey(in);
+}
+
+static KEYCMD
+parsecmd(Char *str)
+{
+ struct KeyFuncs *fp;
+
+ for (fp = FuncNames; fp->name; fp++) {
+ if (strcmp(short2str(str), fp->name) == 0) {
+ return (KEYCMD) fp->func;
+ }
+ }
+ xprintf(CGETS(20, 3, "Bad command name: %S\n"), str);
+ return 0;
+}
+
+
+static void
+bad_spec(const Char *str)
+{
+ xprintf(CGETS(20, 4, "Bad key spec %S\n"), str);
+}
+
+static CStr *
+parsebind(const Char *s, CStr *str)
+{
+ struct Strbuf b = Strbuf_INIT;
+
+ cleanup_push(&b, Strbuf_cleanup);
+ if (Iscntrl(*s)) {
+ Strbuf_append1(&b, *s);
+ goto end;
+ }
+
+ switch (*s) {
+ case '^':
+ s++;
+#ifdef IS_ASCII
+ Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
+#else
+ Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
+ : _toebcdic[_toascii[*s & CHAR] & 0237]);
+#endif
+ break;
+
+ case 'F':
+ case 'M':
+ case 'X':
+ case 'C':
+#ifdef WINNT_NATIVE
+ case 'N':
+#endif /* WINNT_NATIVE */
+ if (s[1] != '-' || s[2] == '\0')
+ goto bad_spec;
+ s += 2;
+ switch (s[-2]) {
+ case 'F': case 'f': /* Turn into ^[str */
+ Strbuf_append1(&b, CTL_ESC('\033'));
+ Strbuf_append(&b, s);
+ break;
+
+ case 'C': case 'c': /* Turn into ^c */
+#ifdef IS_ASCII
+ Strbuf_append1(&b, (*s == '?') ? '\177' : ((*s & CHAR) & 0237));
+#else
+ Strbuf_append1(&b, (*s == '?') ? CTL_ESC('\177')
+ : _toebcdic[_toascii[*s & CHAR] & 0237]);
+#endif
+ break;
+
+ case 'X' : case 'x': /* Turn into ^Xc */
+#ifdef IS_ASCII
+ Strbuf_append1(&b, 'X' & 0237);
+#else
+ Strbuf_append1(&b, _toebcdic[_toascii['X'] & 0237]);
+#endif
+ Strbuf_append1(&b, *s);
+ break;
+
+ case 'M' : case 'm': /* Turn into 0x80|c */
+ if (!NoNLSRebind) {
+ Strbuf_append1(&b, CTL_ESC('\033'));
+ Strbuf_append1(&b, *s);
+ } else {
+#ifdef IS_ASCII
+ Strbuf_append1(&b, *s | 0x80);
+#else
+ Strbuf_append1(&b, _toebcdic[_toascii[*s] | 0x80]);
+#endif
+ }
+ break;
+#ifdef WINNT_NATIVE
+ case 'N' : case 'n': /* NT */
+ {
+ Char bnt;
+
+ bnt = nt_translate_bindkey(s);
+ if (bnt != 0)
+ Strbuf_append1(&b, bnt);
+ else
+ bad_spec(s);
+ }
+ break;
+#endif /* WINNT_NATIVE */
+
+ default:
+ abort();
+ }
+ break;
+
+ default:
+ goto bad_spec;
+ }
+
+ end:
+ cleanup_ignore(&b);
+ cleanup_until(&b);
+ Strbuf_terminate(&b);
+ str->buf = xrealloc(b.s, (b.len + 1) * sizeof (*str->buf));
+ str->len = b.len;
+ return str;
+
+ bad_spec:
+ bad_spec(s);
+ cleanup_until(&b);
+ return NULL;
+}
+
+
+static CStr *
+parsestring(const Char *str, CStr *buf)
+{
+ struct Strbuf b = Strbuf_INIT;
+ const Char *p;
+ eChar es;
+
+ if (*str == 0) {
+ xprintf("%s", CGETS(20, 5, "Null string specification\n"));
+ return NULL;
+ }
+
+ cleanup_push(&b, Strbuf_cleanup);
+ for (p = str; *p != 0; p++) {
+ if ((*p & CHAR) == '\\' || (*p & CHAR) == '^') {
+ if ((es = parseescape(&p)) == CHAR_ERR) {
+ cleanup_until(&b);
+ return 0;
+ } else
+ Strbuf_append1(&b, es);
+ }
+ else
+ Strbuf_append1(&b, *p & CHAR);
+ }
+ cleanup_ignore(&b);
+ cleanup_until(&b);
+ Strbuf_terminate(&b);
+ buf->buf = xrealloc(b.s, (b.len + 1) * sizeof (*buf->buf));
+ buf->len = b.len;
+ return buf;
+}
+
+static void
+print_all_keys(void)
+{
+ int prev, i;
+ CStr nilstr;
+ nilstr.buf = NULL;
+ nilstr.len = 0;
+
+
+ xprintf("%s", CGETS(20, 6, "Standard key bindings\n"));
+ prev = 0;
+ for (i = 0; i < 256; i++) {
+ if (CcKeyMap[prev] == CcKeyMap[i])
+ continue;
+ printkeys(CcKeyMap, prev, i - 1);
+ prev = i;
+ }
+ printkeys(CcKeyMap, prev, i - 1);
+
+ xprintf("%s", CGETS(20, 7, "Alternative key bindings\n"));
+ prev = 0;
+ for (i = 0; i < 256; i++) {
+ if (CcAltMap[prev] == CcAltMap[i])
+ continue;
+ printkeys(CcAltMap, prev, i - 1);
+ prev = i;
+ }
+ printkeys(CcAltMap, prev, i - 1);
+ xprintf("%s", CGETS(20, 8, "Multi-character bindings\n"));
+ PrintXkey(NULL); /* print all Xkey bindings */
+ xprintf("%s", CGETS(20, 9, "Arrow key bindings\n"));
+ PrintArrowKeys(&nilstr);
+}
+
+static void
+printkeys(KEYCMD *map, int first, int last)
+{
+ struct KeyFuncs *fp;
+ Char firstbuf[2], lastbuf[2];
+ CStr fb, lb;
+ unsigned char *unparsed;
+ fb.buf = firstbuf;
+ lb.buf = lastbuf;
+
+ firstbuf[0] = (Char) first;
+ firstbuf[1] = 0;
+ lastbuf[0] = (Char) last;
+ lastbuf[1] = 0;
+ fb.len = 1;
+ lb.len = 1;
+
+ unparsed = unparsestring(&fb, STRQQ);
+ cleanup_push(unparsed, xfree);
+ if (map[first] == F_UNASSIGNED) {
+ if (first == last)
+ xprintf(CGETS(20, 10, "%-15s-> is undefined\n"), unparsed);
+ cleanup_until(unparsed);
+ return;
+ }
+
+ for (fp = FuncNames; fp->name; fp++) {
+ if (fp->func == map[first]) {
+ if (first == last)
+ xprintf("%-15s-> %s\n", unparsed, fp->name);
+ else {
+ unsigned char *p;
+
+ p = unparsestring(&lb, STRQQ);
+ cleanup_push(p, xfree);
+ xprintf("%-4s to %-7s-> %s\n", unparsed, p, fp->name);
+ }
+ cleanup_until(unparsed);
+ return;
+ }
+ }
+ xprintf(CGETS(20, 11, "BUG!!! %s isn't bound to anything.\n"), unparsed);
+ if (map == CcKeyMap)
+ xprintf("CcKeyMap[%d] == %d\n", first, CcKeyMap[first]);
+ else
+ xprintf("CcAltMap[%d] == %d\n", first, CcAltMap[first]);
+ cleanup_until(unparsed);
+}
+
+static void
+bindkey_usage(void)
+{
+ xprintf("%s", CGETS(20, 12,
+ "Usage: bindkey [options] [--] [KEY [COMMAND]]\n"));
+ xprintf("%s", CGETS(20, 13,
+ " -a list or bind KEY in alternative key map\n"));
+ xprintf("%s", CGETS(20, 14,
+ " -b interpret KEY as a C-, M-, F- or X- key name\n"));
+ xprintf("%s", CGETS(20, 15,
+ " -s interpret COMMAND as a literal string to be output\n"));
+ xprintf("%s", CGETS(20, 16,
+ " -c interpret COMMAND as a builtin or external command\n"));
+ xprintf("%s", CGETS(20, 17,
+ " -v bind all keys to vi bindings\n"));
+ xprintf("%s", CGETS(20, 18,
+ " -e bind all keys to emacs bindings\n"));
+ xprintf("%s", CGETS(20, 19,
+ " -d bind all keys to default editor's bindings\n"));
+ xprintf("%s", CGETS(20, 20,
+ " -l list editor commands with descriptions\n"));
+ xprintf("%s", CGETS(20, 21,
+ " -r remove KEY's binding\n"));
+ xprintf("%s", CGETS(20, 22,
+ " -k interpret KEY as a symbolic arrow-key name\n"));
+ xprintf("%s", CGETS(20, 23,
+ " -- force a break from option processing\n"));
+ xprintf("%s", CGETS(20, 24,
+ " -u (or any invalid option) this message\n"));
+ xprintf("\n");
+ xprintf("%s", CGETS(20, 25,
+ "Without KEY or COMMAND, prints all bindings\n"));
+ xprintf("%s", CGETS(20, 26,
+ "Without COMMAND, prints the binding for KEY.\n"));
+}
+
+static void
+list_functions(void)
+{
+ struct KeyFuncs *fp;
+
+ for (fp = FuncNames; fp->name; fp++) {
+ xprintf("%s\n %s\n", fp->name, fp->desc);
+ }
+}
OpenPOWER on IntegriCloud