Logo Search packages:      
Sourcecode: tcsh version File versions  Download package

tc.bind.c

/* $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);
    }
}

Generated by  Doxygen 1.6.0   Back to index