diff options
Diffstat (limited to 'func.c')
-rw-r--r-- | func.c | 630 |
1 files changed, 630 insertions, 0 deletions
@@ -0,0 +1,630 @@ +/* $Id: func.c,v 1.27 2003/09/26 17:59:51 ukai Exp $ */ +/* + * w3m func.c + */ + +#include <stdio.h> + +#include "fm.h" +#include "func.h" +#include "myctype.h" + +#include "funcname.c" +#include "functable.c" + +#define KEYDATA_HASH_SIZE 16 +static Hash_iv *keyData = NULL; +static char keymap_initialized = FALSE; +static struct stat sys_current_keymap_file; +static struct stat current_keymap_file; + +void +setKeymap(char *p, int lineno, int verbose) +{ + unsigned char *map = NULL; + char *s, *emsg; + int c, f; + + s = getQWord(&p); + c = getKey(s); + if (c < 0) { /* error */ + if (lineno > 0) + /* FIXME: gettextize? */ + emsg = Sprintf("line %d: unknown key '%s'", lineno, s)->ptr; + else + /* FIXME: gettextize? */ + emsg = Sprintf("defkey: unknown key '%s'", s)->ptr; + record_err_message(emsg); + if (verbose) + disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE); + return; + } + s = getWord(&p); + f = getFuncList(s); + if (f < 0) { + if (lineno > 0) + /* FIXME: gettextize? */ + emsg = Sprintf("line %d: invalid command '%s'", lineno, s)->ptr; + else + /* FIXME: gettextize? */ + emsg = Sprintf("defkey: invalid command '%s'", s)->ptr; + record_err_message(emsg); + if (verbose) + disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE); + return; + } + if (c & K_MULTI) { + unsigned char **mmap = NULL; + int i, j, m = MULTI_KEY(c); + + if (m & K_ESCD) + map = EscDKeymap; + else if (m & K_ESCB) + map = EscBKeymap; + else if (m & K_ESC) + map = EscKeymap; + else + map = GlobalKeymap; + if (map[m & 0x7F] == FUNCNAME_multimap) + mmap = (unsigned char **)getKeyData(m); + else + map[m & 0x7F] = FUNCNAME_multimap; + if (!mmap) { + mmap = New_N(unsigned char *, 4); + for (i = 0; i < 4; i++) { + mmap[i] = New_N(unsigned char, 128); + for (j = 0; j < 128; j++) + mmap[i][j] = FUNCNAME_nulcmd; + } + mmap[0][ESC_CODE] = FUNCNAME_escmap; + mmap[1]['['] = FUNCNAME_escbmap; + mmap[1]['O'] = FUNCNAME_escbmap; + } + if (keyData == NULL) + keyData = newHash_iv(KEYDATA_HASH_SIZE); + putHash_iv(keyData, m, (void *)mmap); + if (c & K_ESCD) + map = mmap[3]; + else if (c & K_ESCB) + map = mmap[2]; + else if (c & K_ESC) + map = mmap[1]; + else + map = mmap[0]; + } + else { + if (c & K_ESCD) + map = EscDKeymap; + else if (c & K_ESCB) + map = EscBKeymap; + else if (c & K_ESC) + map = EscKeymap; + else + map = GlobalKeymap; + } + map[c & 0x7F] = f; + s = getQWord(&p); + if (*s) { + if (keyData == NULL) + keyData = newHash_iv(KEYDATA_HASH_SIZE); + putHash_iv(keyData, c, (void *)s); + } + else if (getKeyData(c)) + putHash_iv(keyData, c, NULL); +} + +static void +interpret_keymap(FILE * kf, struct stat *current, int force) +{ + int fd; + struct stat kstat; + Str line; + char *p, *s, *emsg; + int lineno; +#ifdef USE_M17N + wc_ces charset = SystemCharset; +#endif + int verbose = 1; + extern int str_to_bool(char *value, int old); + + if ((fd = fileno(kf)) < 0 || fstat(fd, &kstat) || + (!force && + kstat.st_mtime == current->st_mtime && + kstat.st_dev == current->st_dev && + kstat.st_ino == current->st_ino && kstat.st_size == current->st_size)) + return; + *current = kstat; + + lineno = 0; + while (!feof(kf)) { + line = Strfgets(kf); + lineno++; + Strchop(line); + Strremovefirstspaces(line); + if (line->length == 0) + continue; +#ifdef USE_M17N + line = wc_Str_conv(line, charset, InnerCharset); +#endif + p = line->ptr; + s = getWord(&p); + if (*s == '#') /* comment */ + continue; + if (!strcmp(s, "keymap")) ; +#ifdef USE_M17N + else if (!strcmp(s, "charset") || !strcmp(s, "encoding")) { + s = getQWord(&p); + if (*s) + charset = wc_guess_charset(s, charset); + continue; + } +#endif + 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, 1, TRUE, FALSE); + continue; + } + setKeymap(p, lineno, verbose); + } +} + +void +initKeymap(int force) +{ + FILE *kf; + + if ((kf = fopen(confFile(KEYMAP_FILE), "rt")) != NULL) { + interpret_keymap(kf, &sys_current_keymap_file, + force || !keymap_initialized); + fclose(kf); + } + if ((kf = fopen(rcFile(keymap_file), "rt")) != NULL) { + interpret_keymap(kf, ¤t_keymap_file, + force || !keymap_initialized); + fclose(kf); + } + keymap_initialized = TRUE; +} + +int +getFuncList(char *id) +{ + return getHash_si(&functable, id, -1); +} + +char * +getKeyData(int key) +{ + if (keyData == NULL) + return NULL; + return (char *)getHash_iv(keyData, key, NULL); +} + +static int +getKey2(char **str) +{ + char *s = *str; + int c, esc = 0, ctrl = 0; + + if (s == NULL || *s == '\0') + return -1; + + if (strcasecmp(s, "UP") == 0) { /* ^[[A */ + *str = s + 2; + return K_ESCB | 'A'; + } + else if (strcasecmp(s, "DOWN") == 0) { /* ^[[B */ + *str = s + 4; + return K_ESCB | 'B'; + } + else if (strcasecmp(s, "RIGHT") == 0) { /* ^[[C */ + *str = s + 5; + return K_ESCB | 'C'; + } + else if (strcasecmp(s, "LEFT") == 0) { /* ^[[D */ + *str = s + 4; + return K_ESCB | 'D'; + } + + if (strncasecmp(s, "ESC-", 4) == 0 || strncasecmp(s, "ESC ", 4) == 0) { /* ^[ */ + s += 4; + esc = K_ESC; + } + else if (strncasecmp(s, "M-", 2) == 0 || strncasecmp(s, "\\E", 2) == 0) { /* ^[ */ + s += 2; + esc = K_ESC; + } + else if (*s == ESC_CODE) { /* ^[ */ + s++; + esc = K_ESC; + } + if (strncasecmp(s, "C-", 2) == 0) { /* ^, ^[^ */ + s += 2; + ctrl = 1; + } + else if (*s == '^' && *(s + 1)) { /* ^, ^[^ */ + s++; + ctrl = 1; + } + if (!esc && ctrl && *s == '[') { /* ^[ */ + s++; + ctrl = 0; + esc = K_ESC; + } + if (esc && !ctrl) { + if (*s == '[' || *s == 'O') { /* ^[[, ^[O */ + s++; + esc = K_ESCB; + } + if (strncasecmp(s, "C-", 2) == 0) { /* ^[^, ^[[^ */ + s += 2; + ctrl = 1; + } + else if (*s == '^' && *(s + 1)) { /* ^[^, ^[[^ */ + s++; + ctrl = 1; + } + } + + if (ctrl) { + *str = s + 1; + if (*s >= '@' && *s <= '_') /* ^@ .. ^_ */ + return esc | (*s - '@'); + else if (*s >= 'a' && *s <= 'z') /* ^a .. ^z */ + return esc | (*s - 'a' + 1); + else if (*s == '?') /* ^? */ + return esc | DEL_CODE; + else + return -1; + } + + if (esc == K_ESCB && IS_DIGIT(*s)) { + c = (int)(*s - '0'); + s++; + if (IS_DIGIT(*s)) { + c = c * 10 + (int)(*s - '0'); + s++; + } + *str = s + 1; + if (*s == '~') + return K_ESCD | c; + else + return -1; + } + + if (strncasecmp(s, "SPC", 3) == 0) { /* ' ' */ + *str = s + 3; + return esc | ' '; + } + else if (strncasecmp(s, "TAB", 3) == 0) { /* ^i */ + *str = s + 3; + return esc | '\t'; + } + else if (strncasecmp(s, "DEL", 3) == 0) { /* ^? */ + *str = s + 3; + return esc | DEL_CODE; + } + + if (*s == '\\' && *(s + 1) != '\0') { + s++; + *str = s + 1; + switch (*s) { + case 'a': /* ^g */ + return esc | CTRL_G; + case 'b': /* ^h */ + return esc | CTRL_H; + case 't': /* ^i */ + return esc | CTRL_I; + case 'n': /* ^j */ + return esc | CTRL_J; + case 'r': /* ^m */ + return esc | CTRL_M; + case 'e': /* ^[ */ + return esc | ESC_CODE; + case '^': /* ^ */ + return esc | '^'; + case '\\': /* \ */ + return esc | '\\'; + default: + return -1; + } + } + *str = s + 1; + if (IS_ASCII(*s)) /* Ascii */ + return esc | *s; + else + return -1; +} + +int +getKey(char *s) +{ + int c, c2; + + c = getKey2(&s); + if (c < 0) + return -1; + if (*s == ' ' || *s == '-') + s++; + if (*s) { + c2 = getKey2(&s); + if (c2 < 0) + return -1; + c = K_MULTI | (c << 16) | c2; + } + return c; +} + +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; +} + +#ifdef USE_MOUSE +static MouseAction default_mouse_action = { + NULL, + "<=UpDn", + 0, 6, FALSE, 0, 0, + {{movMs, NULL}, {backBf, NULL}, {menuMs, NULL}}, /* default */ + {{NULL, NULL}, {NULL, NULL}, {NULL, NULL}}, /* anchor */ + {{followA, NULL}, {NULL, NULL}, {NULL, NULL}}, /* active */ + {{tabMs, NULL}, {closeTMs, NULL}, {NULL, NULL}}, /* tab */ + {NULL, NULL, NULL}, /* menu */ + {NULL, NULL, NULL} /* lastline */ +}; +static MouseActionMap default_lastline_action[6] = { + {backBf, NULL}, + {backBf, NULL}, + {pgBack, NULL}, + {pgBack, NULL}, + {pgFore, NULL}, + {pgFore, NULL} +}; + +static void +setMouseAction0(char **str, int *width, MouseActionMap ** map, char *p) +{ + char *s; + int b, w, x; + + s = getQWord(&p); + if (!*s) { + *str = NULL; + width = 0; + for (b = 0; b < 3; b++) + map[b] = NULL; + return; + } + w = *width; + *str = s; + *width = get_strwidth(s); + if (*width >= LIMIT_MOUSE_MENU) + *width = LIMIT_MOUSE_MENU; + if (*width <= w) + return; + for (b = 0; b < 3; b++) { + if (!map[b]) + continue; + map[b] = New_Reuse(MouseActionMap, map[b], *width); + for (x = w + 1; x < *width; x++) { + map[b][x].func = NULL; + map[b][x].data = NULL; + } + } +} + +static void +setMouseAction1(MouseActionMap ** map, int width, char *p) +{ + char *s; + int x, x2, f; + + if (!*map) { + *map = New_N(MouseActionMap, width); + for (x = 0; x < width; x++) { + (*map)[x].func = NULL; + (*map)[x].data = NULL; + } + } + s = getWord(&p); + x = atoi(s); + if (!(IS_DIGIT(*s) && x >= 0 && x < width)) + return; /* error */ + s = getWord(&p); + x2 = atoi(s); + if (!(IS_DIGIT(*s) && x2 >= 0 && x2 < width)) + return; /* error */ + s = getWord(&p); + f = getFuncList(s); + s = getQWord(&p); + if (!*s) + s = NULL; + for (; x <= x2; x++) { + (*map)[x].func = (f >= 0) ? w3mFuncList[f].func : NULL; + (*map)[x].data = s; + } +} + +static void +setMouseAction2(MouseActionMap * map, char *p) +{ + char *s; + int f; + + s = getWord(&p); + f = getFuncList(s); + s = getQWord(&p); + if (!*s) + s = NULL; + map->func = (f >= 0) ? w3mFuncList[f].func : NULL; + map->data = s; +} + +static void +interpret_mouse_action(FILE * mf) +{ + Str line; + char *p, *s; + int b; + + while (!feof(mf)) { + line = Strfgets(mf); + Strchop(line); + Strremovefirstspaces(line); + if (line->length == 0) + continue; + p = conv_from_system(line->ptr); + s = getWord(&p); + if (*s == '#') /* comment */ + continue; + if (!strcmp(s, "menu")) { + setMouseAction0(&mouse_action.menu_str, &mouse_action.menu_width, + mouse_action.menu_map, p); + continue; + } + else if (!strcmp(s, "lastline")) { + setMouseAction0(&mouse_action.lastline_str, + &mouse_action.lastline_width, + mouse_action.lastline_map, p); + continue; + } + if (strcmp(s, "button")) + continue; /* error */ + s = getWord(&p); + b = atoi(s) - 1; + if (!(b >= 0 && b <= 2)) + continue; /* error */ + SKIP_BLANKS(p); + if (IS_DIGIT(*p)) + s = "menu"; + else + s = getWord(&p); + if (!strcasecmp(s, "menu")) { + if (!mouse_action.menu_str) + continue; + setMouseAction1(&mouse_action.menu_map[b], mouse_action.menu_width, + p); + } + else if (!strcasecmp(s, "lastline")) { + if (!mouse_action.lastline_str) + continue; + setMouseAction1(&mouse_action.lastline_map[b], + mouse_action.lastline_width, p); + } + else if (!strcasecmp(s, "default")) + setMouseAction2(&mouse_action.default_map[b], p); + else if (!strcasecmp(s, "anchor")) + setMouseAction2(&mouse_action.anchor_map[b], p); + else if (!strcasecmp(s, "active")) + setMouseAction2(&mouse_action.active_map[b], p); + else if (!strcasecmp(s, "tab")) + setMouseAction2(&mouse_action.tab_map[b], p); + } +} + +void +initMouseAction(void) +{ + FILE *mf; + + bcopy((void *)&default_mouse_action, (void *)&mouse_action, + sizeof(default_mouse_action)); + mouse_action.lastline_map[0] = New_N(MouseActionMap, 6); + bcopy((void *)&default_lastline_action, + (void *)mouse_action.lastline_map[0], + sizeof(default_lastline_action)); + { +#ifdef USE_M17N + int w = 0; + char **symbol = get_symbol(DisplayCharset, &w); +#else + char **symbol = get_symbol(); +#endif + mouse_action.lastline_str = + Strnew_charp(symbol[N_GRAPH_SYMBOL + 13])->ptr; + } + + if ((mf = fopen(confFile(MOUSE_FILE), "rt")) != NULL) { + interpret_mouse_action(mf); + fclose(mf); + } + if ((mf = fopen(rcFile(MOUSE_FILE), "rt")) != NULL) { + interpret_mouse_action(mf); + fclose(mf); + } +} +#endif |