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

func.c

/* 
 * w3m func.c
 */

#include <stdarg.h>
#include <stdio.h>

#include "fm.h"
#include "func.h"
#include "myctype.h"

#include "funcname.c"

btri_string_tab_t w3mFuncTab[] = {
#include "funcname.h"
};

KeyTabList *w3mFuncKeyTabList = &w3mDefaultFuncKeyTabList;
KeyTabList *w3mEditKeyTabList = &w3mDefaultEditKeyTabList;
#ifdef USE_MENU
KeyTabList *w3mMenuKeyTabList = &w3mDefaultMenuKeyTabList;
#endif

static btri_uint_tab_t *KeyData;
static char keymap_initialized;
static struct stat current_keymap_file;

void
addToKeyTab(KeyTabList *kl, int key, int cmd)
{
    NEW_OBJV1(&kl->size, kl->nitem, &kl->key_table, sizeof(KeyTabItem), 1);
    kl->key_table[(kl->nitem)++] = K_SET_FUNC(key, cmd);
}

int
cmpKeyTabItem(const void *x, const void *y)
{
    return K_CMP(*(int *)x, -, *(int *)y);
}

KeyTabList *
copyKeyTabList(KeyTabList *kl)
{
    if (kl->key_table) {
      KeyTabList *new;

      qsort(kl->key_table, kl->nitem, sizeof(KeyTabItem), cmpKeyTabItem);
      new = GC_MALLOC(sizeof(KeyTabList));
      *new = *kl;
      return new;
    }
    else
      return kl->next;
}

void
setKeymap(char *p, int lineno, int verbose,
        KeyTabList *func_tab, KeyTabList *edit_tab
#ifdef USE_MENU
        , KeyTabList *menu_tab
#endif
        )
{
    char *s, *emsg;
    int c;
    KeyTabList *tab;
    FuncList *fl;

    s = getQWord(&p);
    c = getKey(s);

    if (c < 0) {        /* error */
      if (lineno > 0)
          emsg = Sprintf("line %d: unknown key '%s'", lineno, s)->ptr;
      else
          emsg = Sprintf("defkey: unknown key '%s'", s)->ptr;

      record_err_message(emsg);

      if (verbose)
          disp_message_nsec(emsg, FALSE, 0, FALSE, TRUE);

      return;
    }

    s = getWord(&p);

    if (!strncasecmp(s, "E:", sizeof("E:") - 1))
      tab = edit_tab;
#ifdef USE_MENU
    else if (!strncasecmp(s, "M:", sizeof("M:") - 1)) {
      tab = menu_tab;

#ifdef USE_MENU_BUFFER
      if (s[sizeof("M:") - 1] == ':')
          s += sizeof("M::") - 1;
#endif
    }
#endif
    else
      tab = func_tab;

    if (btri_fast_ci_search_str(s, w3mFuncTab, (void **)&fl) == bt_failure) {
      if (lineno > 0)
          emsg = Sprintf("line %d: invalid command '%s'", lineno, s)->ptr;
      else
          emsg = Sprintf("defkey: invalid command '%s'", s)->ptr;

      record_err_message(emsg);

      if (verbose)
          disp_message_nsec(emsg, FALSE, 0, FALSE, TRUE);

      return;
    }

    if (lineno <= 0) {
      if (w3mFuncKeyTabList != &w3mDefaultFuncKeyTabList)
          *func_tab = *w3mFuncKeyTabList;

      if (w3mEditKeyTabList != &w3mDefaultEditKeyTabList)
          *edit_tab = *w3mEditKeyTabList;

#ifdef USE_MENU
      if (w3mMenuKeyTabList != &w3mDefaultMenuKeyTabList)
          *menu_tab = *w3mMenuKeyTabList;
#endif
    }

    addToKeyTab(tab, c, fl - w3mFuncList);

    if (tab == func_tab) {
      s = getQWord(&p);

      if (*s) {
          void *value;

          if (!KeyData)
            KeyData = btri_new_node(&btri_uint_tab_desc);

          value = s;
          btri_search_uint(&btri_uint_tab_desc, BTRI_OP_ADD | BTRI_OP_WR, c, KeyData, &value);
      }
    }

    if (lineno <= 0) {
      w3mFuncKeyTabList = copyKeyTabList(func_tab);
      w3mEditKeyTabList = copyKeyTabList(edit_tab);
#ifdef USE_MENU
      w3mMenuKeyTabList = copyKeyTabList(menu_tab);
#endif
    }
}

void
initKeymap(int force)
{
    FILE *kf;
    Str line;
    char *p, *s, *emsg;
    int lineno;
    int verbose = 1;
    KeyTabList func_tab = {NULL, NULL, 0, 0}, edit_tab = {NULL, NULL, 0, 0};
#ifdef USE_MENU
    KeyTabList menu_tab = {NULL, NULL, 0, 0};
#endif
    int kfd;
    struct stat kstat;

    if (!force && !keymap_initialized)
      return;

    if ((kf = fopen(rcFile(keymap_file), "rt")) == NULL ||
      (kfd = fileno(kf)) < 0 || fstat(kfd, &kstat) ||
      (!force && keymap_initialized &&
       kstat.st_mtime == current_keymap_file.st_mtime &&
       kstat.st_dev == current_keymap_file.st_dev &&
       kstat.st_ino == current_keymap_file.st_ino &&
       kstat.st_size == current_keymap_file.st_size))
      return;

    func_tab.next = &w3mDefaultFuncKeyTabList;
    edit_tab.next = &w3mDefaultEditKeyTabList;
#ifdef USE_MENU
    menu_tab.next = &w3mDefaultMenuKeyTabList;
#endif
    lineno = 0;
    while (!feof(kf)) {
      line = Strfgets(kf);
      lineno++;
      Strchop(line);
      Strremovefirstspaces(line);
      if (line->length == 0)
          continue;
      p = line->ptr;
      s = getWord(&p);
      if (*s == '#')          /* comment */
          continue;
      if (!strcmp(s, "keymap"))
          ;
      else if (!strcmp(s, "verbose")) {
          s = getWord(&p);
          if (*s)
            verbose = str_to_bool(s, verbose);
          continue;
      } else {                /* error */
          emsg = Sprintf("line %d: syntax error '%s'", lineno, s)->ptr;
          record_err_message(emsg);
          if (verbose)
            disp_message_nsec(emsg, FALSE, 0, FALSE, TRUE);
          continue;
      }
      setKeymap(p, lineno, verbose, &func_tab, &edit_tab
#ifdef USE_MENU
              , &menu_tab
#endif
              );
    }
    fclose(kf);
    w3mFuncKeyTabList = copyKeyTabList(&func_tab);
    w3mEditKeyTabList = copyKeyTabList(&edit_tab);
#ifdef USE_MENU
    w3mMenuKeyTabList = copyKeyTabList(&menu_tab);
#endif
    keymap_initialized = TRUE;
    current_keymap_file = kstat;
}

#define DEFKEY(str) str, sizeof(str) - 1

static struct {
    const char *s;
    size_t len;
    int key;
} arrow_key[] = {
    {DEFKEY("UP"), K_ESCB | 'A'},
    {DEFKEY("DOWN"), K_ESCB | 'B'},
    {DEFKEY("RIGHT"), K_ESCB | 'C'},
    {DEFKEY("LEFT"), K_ESCB | 'D'},
}, esc_key[] = {
    {DEFKEY("ESC-"), K_ESC},
    {DEFKEY("ESC "), K_ESC},
    {DEFKEY("\\E"), K_ESC},
    {DEFKEY("M-"), K_ESC},
    {DEFKEY("\x1B"), K_ESC},
}, ctrl_key[] = {
    {DEFKEY("C-"), 1},
    {DEFKEY("CTL-"), 1},
    {DEFKEY("CTRL-"), 1},
    {DEFKEY("^"), 1},
}, sym_key[] = {
    {DEFKEY("SPC"), ' '},
    {DEFKEY("TAB"), '\t'},
    {DEFKEY("DEL"), DEL_CODE},
    {DEFKEY("CR"), '\r'},
    {DEFKEY("LF"), '\n'},
}
#ifdef USE_MOUSE
, mouse_key[] = {
    {DEFKEY("MOUSE-CLICK-"), K_MOUSE(CLICK)},
    {DEFKEY("MOUSE-DCLICK-"), K_MOUSE(DCLICK)},
    {DEFKEY("MOUSE-DOUBLE-CLICK-"), K_MOUSE(DCLICK)},
    {DEFKEY("MOUSE-DRAG-"), K_MOUSE(DRAG)},
    {DEFKEY("MOUSE-MOVE-"), K_MOUSE(MOVE)},
}
#endif
;

int
getKey(char *s)
{
    int c, esc, ctrl, key, n, i;

    if (!s || !*s)
      return -1;

    for (esc = ctrl = key = n = 0 ; *s ;) {
      if (!esc && !ctrl)
          key <<= K_ONE_LEN;

      for (i = sizeof(arrow_key) / sizeof(arrow_key[0]) ; i > 0 ;) {
          --i;

          if (!strncasecmp(s, arrow_key[i].s, arrow_key[i].len)) {
            key |= arrow_key[i].key;
            s += arrow_key[i].len;
            goto next_key;
          }
      }

      for (i = sizeof(esc_key) / sizeof(esc_key[0]) ; i > 0 ;) {
          --i;

          if (!strncasecmp(s, esc_key[i].s, esc_key[i].len)) {
            esc = esc_key[i].key;
            s += esc_key[i].len;
            goto next_modifier;
          }
      }

      for (i = sizeof(ctrl_key) / sizeof(ctrl_key[0]) ; i > 0 ;) {
          --i;

          if (!strncasecmp(s, ctrl_key[i].s, ctrl_key[i].len)) {
            ctrl = 1;
            s += ctrl_key[i].len;
            goto next_modifier;
          }
      }

#ifdef USE_MOUSE
      if (!n && !esc && !ctrl)
          for (i = sizeof(mouse_key) / sizeof(mouse_key[0]) ; i > 0 ;) {
            --i;

            if (!strncasecmp(s, mouse_key[i].s, mouse_key[i].len)) {
                char *e;
                long btn;

                key = mouse_key[i].key;
                s += mouse_key[i].len;

                if ((btn = strtol(s, &e, 10)) <= 0 || btn > K_MOUSE_NBTNS || *e)
                  return -1;

                key += btn - 1;
                ++n;
                goto end;
            }
          }
#endif

      if (!esc && ctrl && *s == '[') {    /* ^[ */
          ++s;
          ctrl = 0;
          esc = K_ESC;
          goto next_modifier;
      }

      if (esc && !ctrl) {
          if (*s == '[' || *s == 'O') {   /* ^[[, ^[O */
            ++s;
            esc = K_ESCB;
            goto next_modifier;
          }
      }

      if (ctrl) {
          if (*s >= '@' && *s <= '_')           /* ^@ .. ^_ */
            key |= esc | (*s - '@');
          else if (*s >= 'a' && *s <= 'z')      /* ^a .. ^z */
            key |= esc | (*s - 'a' + 1);
          else if (*s == '?')             /* ^? */
            key |= esc | DEL_CODE;
          else
            return -1;

          ++s;
          goto next_key;
      }

      if (esc == K_ESCB && IS_DIGIT(*s)) {
          c = (unsigned char)*s++ - '0';

          if (IS_DIGIT(*s))
            c = c * 10 + (unsigned char)*s++ - '0';

          if (*s++ != '~')
            return -1;

          key |= K_ESCD | c;
          goto next_key;
      }

      for (i = sizeof(sym_key) / sizeof(sym_key[0]) ; i > 0 ;) {
          --i;

          if (!strncasecmp(s, sym_key[i].s, sym_key[i].len)) {
            key |= esc | sym_key[i].key;
            s += sym_key[i].len;
            goto next_key;
          }
      }

      if (*s == '\\' && *(s + 1) != '\0') {
          switch (*(s + 1)) {
          case 'a':           /* ^g */
            key |= esc | CTRL_G;
            break;
          case 'b':           /* ^h */
            key |= esc | CTRL_H;
            break;
          case 't':           /* ^i */
            key |= esc | CTRL_I;
            break;
          case 'n':           /* ^j */
            key |= esc | CTRL_J;
            break;
          case 'r':           /* ^m */
            key |= esc | CTRL_M;
            break;
          case 'e':           /* ^[ */
            key |= esc | ESC_CODE;
            break;
          default:
            if (!IS_ASCII(*(s + 1)))
                return -1;

            key |= esc | *(s + 1);
            break;
          }

          s += 2;
          goto next_key;
      }

      if (IS_ASCII(*s))       /* Ascii */
          key |= esc | *s++;
      else
          return -1;
    next_key:
      ++n;
      esc = ctrl = 0;
    next_modifier:
    }
#ifdef USE_MOUSE
end:
#endif
    return (n <= 0 || n > K_LEN_MAX) ? -1 : (key << K_LEN_LEN) | n;
}

int
lookupKeyIndex(int key, KeyTabList *tabl)
{
    int b, e, i, this_key;

    for (b = 0, e = tabl->nitem ; b < e ;) {
      i = (b + e) / 2;
      this_key = tabl->key_table[i] & K_CMP_MASK;

      if (key < this_key)
          e = i;
      else if (key > this_key)
          b = i + 1;
      else
          return i;
    }

    return -1;
}

FuncList *
lookupKey(int key, KeyTabList *tabl)
{
    int i;

    for (; tabl ; tabl = tabl->next)
      if ((i = lookupKeyIndex(key, tabl)) >= 0)
          return &w3mFuncList[K_GET_FUNC(tabl->key_table[i])];

    return NULL;
}

char *
getKeyData(int key)
{
    if (KeyData) {
      void *value;

      if (btri_fast_search_uint(key, KeyData, &value) != bt_failure)
          return value;
    }

    return NULL;
}

char *
getWord(char **str)
{
    char *p, *s;

    p = *str;
    SKIP_BLANKS(p);
    for (s = p; *p && ! IS_SPACE(*p) && *p != ';'; p++) ;
    *str = p;
    return Strnew_charp_n(s, p - s)->ptr;
}

char *
getQWord(char **str)
{
    Str tmp = Strnew();
    char *p;
    int in_q = 0, in_dq = 0, esc = 0;

    p = *str;
    SKIP_BLANKS(p);
    for (; *p; p++) {
      if (esc) {
          if (in_q) {
            if (*p != '\\' && *p != '\'') /* '..\\..', '..\'..' */
                Strcat_char(tmp, '\\');
          }
          else if (in_dq) {
            if (*p != '\\' && *p != '"')  /* "..\\..", "..\".." */
                Strcat_char(tmp, '\\');
          }
          else {
            if (*p != '\\' && *p != '\'' &&           /* ..\\.., ..\'..  */
                *p != '"' && !IS_SPACE(*p))           /* ..\".., ..\.. */
                Strcat_char(tmp, '\\');
          }
          Strcat_char(tmp, *p);
          esc = 0;
      }
      else if (*p == '\\') {
          esc = 1;
      }
      else if (in_q) {
          if (*p == '\'')
            in_q = 0;
          else
            Strcat_char(tmp, *p);
      }
      else if (in_dq) {
          if (*p == '"')
            in_dq = 0;
          else
            Strcat_char(tmp, *p);
      }
      else if (*p == '\'') {
          in_q = 1;
      }
      else if (*p == '"') {
          in_dq = 1;
      }
      else if (IS_SPACE(*p) || *p == ';') {
          break;
      }
      else {
          Strcat_char(tmp, *p);
      }
    }
    *str = p;
    return tmp->ptr;
}

/* Local Variables:    */
/* c-basic-offset: 4   */
/* tab-width: 8        */
/* End:                */

Generated by  Doxygen 1.6.0   Back to index