w3m

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/w3m.git/
Log | Files | Refs | README

func.c (13284B)


      1 /* $Id$ */
      2 /*
      3  * w3m func.c
      4  */
      5 
      6 #include <stdio.h>
      7 
      8 #include "fm.h"
      9 #include "func.h"
     10 #include "myctype.h"
     11 
     12 #include "funcname.c"
     13 #include "functable.c"
     14 
     15 #define KEYDATA_HASH_SIZE 16
     16 static Hash_iv *keyData = NULL;
     17 static char keymap_initialized = FALSE;
     18 static struct stat sys_current_keymap_file;
     19 static struct stat current_keymap_file;
     20 
     21 void
     22 setKeymap(char *p, int lineno, int verbose)
     23 {
     24     unsigned char *map = NULL;
     25     char *s, *emsg;
     26     int c, f;
     27 
     28     s = getQWord(&p);
     29     c = getKey(s);
     30     if (c < 0) {		/* error */
     31 	if (lineno > 0)
     32 	    /* FIXME: gettextize? */
     33 	    emsg = Sprintf("line %d: unknown key '%s'", lineno, s)->ptr;
     34 	else
     35 	    /* FIXME: gettextize? */
     36 	    emsg = Sprintf("defkey: unknown key '%s'", s)->ptr;
     37 	record_err_message(emsg);
     38 	if (verbose)
     39 	    disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE);
     40 	return;
     41     }
     42     s = getWord(&p);
     43     f = getFuncList(s);
     44     if (f < 0) {
     45 	if (lineno > 0)
     46 	    /* FIXME: gettextize? */
     47 	    emsg = Sprintf("line %d: invalid command '%s'", lineno, s)->ptr;
     48 	else
     49 	    /* FIXME: gettextize? */
     50 	    emsg = Sprintf("defkey: invalid command '%s'", s)->ptr;
     51 	record_err_message(emsg);
     52 	if (verbose)
     53 	    disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE);
     54 	return;
     55     }
     56     if (c & K_MULTI) {
     57 	unsigned char **mmap = NULL;
     58 	int i, j, m = MULTI_KEY(c);
     59 
     60 	if (m & K_ESCD)
     61 	    map = EscDKeymap;
     62 	else if (m & K_ESCB)
     63 	    map = EscBKeymap;
     64 	else if (m & K_ESC)
     65 	    map = EscKeymap;
     66 	else
     67 	    map = GlobalKeymap;
     68 	if (map[m & 0x7F] == FUNCNAME_multimap)
     69 	    mmap = (unsigned char **)getKeyData(m);
     70 	else
     71 	    map[m & 0x7F] = FUNCNAME_multimap;
     72 	if (!mmap) {
     73 	    mmap = New_N(unsigned char *, 4);
     74 	    for (i = 0; i < 4; i++) {
     75 		mmap[i] = New_N(unsigned char, 128);
     76 		for (j = 0; j < 128; j++)
     77 		    mmap[i][j] = FUNCNAME_nulcmd;
     78 	    }
     79 	    mmap[0][ESC_CODE] = FUNCNAME_escmap;
     80 	    mmap[1]['['] = FUNCNAME_escbmap;
     81 	    mmap[1]['O'] = FUNCNAME_escbmap;
     82 	}
     83 	if (keyData == NULL)
     84 	    keyData = newHash_iv(KEYDATA_HASH_SIZE);
     85 	putHash_iv(keyData, m, (void *)mmap);
     86 	if (c & K_ESCD)
     87 	    map = mmap[3];
     88 	else if (c & K_ESCB)
     89 	    map = mmap[2];
     90 	else if (c & K_ESC)
     91 	    map = mmap[1];
     92 	else
     93 	    map = mmap[0];
     94     }
     95     else {
     96 	if (c & K_ESCD)
     97 	    map = EscDKeymap;
     98 	else if (c & K_ESCB)
     99 	    map = EscBKeymap;
    100 	else if (c & K_ESC)
    101 	    map = EscKeymap;
    102 	else
    103 	    map = GlobalKeymap;
    104     }
    105     map[c & 0x7F] = f;
    106     s = getQWord(&p);
    107     if (*s) {
    108 	if (keyData == NULL)
    109 	    keyData = newHash_iv(KEYDATA_HASH_SIZE);
    110 	putHash_iv(keyData, c, (void *)s);
    111     }
    112     else if (getKeyData(c))
    113 	putHash_iv(keyData, c, NULL);
    114 }
    115 
    116 static void
    117 interpret_keymap(FILE * kf, struct stat *current, int force)
    118 {
    119     int fd;
    120     struct stat kstat;
    121     Str line;
    122     char *p, *s, *emsg;
    123     int lineno;
    124 #ifdef USE_M17N
    125     wc_ces charset = SystemCharset;
    126 #endif
    127     int verbose = 1;
    128     extern int str_to_bool(char *value, int old);
    129 
    130     if ((fd = fileno(kf)) < 0 || fstat(fd, &kstat) ||
    131 	(!force &&
    132 	 kstat.st_mtime == current->st_mtime &&
    133 	 kstat.st_dev == current->st_dev &&
    134 	 kstat.st_ino == current->st_ino && kstat.st_size == current->st_size))
    135 	return;
    136     *current = kstat;
    137 
    138     lineno = 0;
    139     while (!feof(kf)) {
    140 	line = Strfgets(kf);
    141 	lineno++;
    142 	Strchop(line);
    143 	Strremovefirstspaces(line);
    144 	if (line->length == 0)
    145 	    continue;
    146 #ifdef USE_M17N
    147 	line = wc_Str_conv(line, charset, InnerCharset);
    148 #endif
    149 	p = line->ptr;
    150 	s = getWord(&p);
    151 	if (*s == '#')		/* comment */
    152 	    continue;
    153 	if (!strcmp(s, "keymap")) ;
    154 #ifdef USE_M17N
    155 	else if (!strcmp(s, "charset") || !strcmp(s, "encoding")) {
    156 	    s = getQWord(&p);
    157 	    if (*s)
    158 		charset = wc_guess_charset(s, charset);
    159 	    continue;
    160 	}
    161 #endif
    162 	else if (!strcmp(s, "verbose")) {
    163 	    s = getWord(&p);
    164 	    if (*s)
    165 		verbose = str_to_bool(s, verbose);
    166 	    continue;
    167 	}
    168 	else {			/* error */
    169 	    emsg = Sprintf("line %d: syntax error '%s'", lineno, s)->ptr;
    170 	    record_err_message(emsg);
    171 	    if (verbose)
    172 		disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE);
    173 	    continue;
    174 	}
    175 	setKeymap(p, lineno, verbose);
    176     }
    177 }
    178 
    179 void
    180 initKeymap(int force)
    181 {
    182     FILE *kf;
    183 
    184     if ((kf = fopen(confFile(KEYMAP_FILE), "rt")) != NULL) {
    185 	interpret_keymap(kf, &sys_current_keymap_file,
    186 			 force || !keymap_initialized);
    187 	fclose(kf);
    188     }
    189     if ((kf = fopen(rcFile(keymap_file), "rt")) != NULL) {
    190 	interpret_keymap(kf, &current_keymap_file,
    191 			 force || !keymap_initialized);
    192 	fclose(kf);
    193     }
    194     keymap_initialized = TRUE;
    195 }
    196 
    197 int
    198 getFuncList(char *id)
    199 {
    200     return getHash_si(&functable, id, -1);
    201 }
    202 
    203 char *
    204 getKeyData(int key)
    205 {
    206     if (keyData == NULL)
    207 	return NULL;
    208     return (char *)getHash_iv(keyData, key, NULL);
    209 }
    210 
    211 static int
    212 getKey2(char **str)
    213 {
    214     char *s = *str;
    215     int c, esc = 0, ctrl = 0;
    216 
    217     if (s == NULL || *s == '\0')
    218 	return -1;
    219 
    220     if (strcasecmp(s, "UP") == 0) {	/* ^[[A */
    221 	*str = s + 2;
    222 	return K_ESCB | 'A';
    223     }
    224     else if (strcasecmp(s, "DOWN") == 0) {	/* ^[[B */
    225 	*str = s + 4;
    226 	return K_ESCB | 'B';
    227     }
    228     else if (strcasecmp(s, "RIGHT") == 0) {	/* ^[[C */
    229 	*str = s + 5;
    230 	return K_ESCB | 'C';
    231     }
    232     else if (strcasecmp(s, "LEFT") == 0) {	/* ^[[D */
    233 	*str = s + 4;
    234 	return K_ESCB | 'D';
    235     }
    236 
    237     if (strncasecmp(s, "ESC-", 4) == 0 || strncasecmp(s, "ESC ", 4) == 0) {	/* ^[ */
    238 	s += 4;
    239 	esc = K_ESC;
    240     }
    241     else if (strncasecmp(s, "M-", 2) == 0 || strncasecmp(s, "\\E", 2) == 0) {	/* ^[ */
    242 	s += 2;
    243 	esc = K_ESC;
    244     }
    245     else if (*s == ESC_CODE) {	/* ^[ */
    246 	s++;
    247 	esc = K_ESC;
    248     }
    249     if (strncasecmp(s, "C-", 2) == 0) {	/* ^, ^[^ */
    250 	s += 2;
    251 	ctrl = 1;
    252     }
    253     else if (*s == '^' && *(s + 1)) {	/* ^, ^[^ */
    254 	s++;
    255 	ctrl = 1;
    256     }
    257     if (!esc && ctrl && *s == '[') {	/* ^[ */
    258 	s++;
    259 	ctrl = 0;
    260 	esc = K_ESC;
    261     }
    262     if (esc && !ctrl) {
    263 	if (*s == '[' || *s == 'O') {	/* ^[[, ^[O */
    264 	    s++;
    265 	    esc = K_ESCB;
    266 	}
    267 	if (strncasecmp(s, "C-", 2) == 0) {	/* ^[^, ^[[^ */
    268 	    s += 2;
    269 	    ctrl = 1;
    270 	}
    271 	else if (*s == '^' && *(s + 1)) {	/* ^[^, ^[[^ */
    272 	    s++;
    273 	    ctrl = 1;
    274 	}
    275     }
    276 
    277     if (ctrl) {
    278 	*str = s + 1;
    279 	if (*s >= '@' && *s <= '_')	/* ^@ .. ^_ */
    280 	    return esc | (*s - '@');
    281 	else if (*s >= 'a' && *s <= 'z')	/* ^a .. ^z */
    282 	    return esc | (*s - 'a' + 1);
    283 	else if (*s == '?')	/* ^? */
    284 	    return esc | DEL_CODE;
    285 	else
    286 	    return -1;
    287     }
    288 
    289     if (esc == K_ESCB && IS_DIGIT(*s)) {
    290 	c = (int)(*s - '0');
    291 	s++;
    292 	if (IS_DIGIT(*s)) {
    293 	    c = c * 10 + (int)(*s - '0');
    294 	    s++;
    295 	}
    296 	*str = s + 1;
    297 	if (*s == '~')
    298 	    return K_ESCD | c;
    299 	else
    300 	    return -1;
    301     }
    302 
    303     if (strncasecmp(s, "SPC", 3) == 0) {	/* ' ' */
    304 	*str = s + 3;
    305 	return esc | ' ';
    306     }
    307     else if (strncasecmp(s, "TAB", 3) == 0) {	/* ^i */
    308 	*str = s + 3;
    309 	return esc | '\t';
    310     }
    311     else if (strncasecmp(s, "DEL", 3) == 0) {	/* ^? */
    312 	*str = s + 3;
    313 	return esc | DEL_CODE;
    314     }
    315 
    316     if (*s == '\\' && *(s + 1) != '\0') {
    317 	s++;
    318 	*str = s + 1;
    319 	switch (*s) {
    320 	case 'a':		/* ^g */
    321 	    return esc | CTRL_G;
    322 	case 'b':		/* ^h */
    323 	    return esc | CTRL_H;
    324 	case 't':		/* ^i */
    325 	    return esc | CTRL_I;
    326 	case 'n':		/* ^j */
    327 	    return esc | CTRL_J;
    328 	case 'r':		/* ^m */
    329 	    return esc | CTRL_M;
    330 	case 'e':		/* ^[ */
    331 	    return esc | ESC_CODE;
    332 	case '^':		/* ^ */
    333 	    return esc | '^';
    334 	case '\\':		/* \ */
    335 	    return esc | '\\';
    336 	default:
    337 	    return -1;
    338 	}
    339     }
    340     *str = s + 1;
    341     if (IS_ASCII(*s))		/* Ascii */
    342 	return esc | *s;
    343     else
    344 	return -1;
    345 }
    346 
    347 int
    348 getKey(char *s)
    349 {
    350     int c, c2;
    351 
    352     c = getKey2(&s);
    353     if (c < 0)
    354 	return -1;
    355     if (*s == ' ' || *s == '-')
    356 	s++;
    357     if (*s) {
    358 	c2 = getKey2(&s);
    359 	if (c2 < 0)
    360 	    return -1;
    361 	c = K_MULTI | (c << 16) | c2;
    362     }
    363     return c;
    364 }
    365 
    366 char *
    367 getWord(char **str)
    368 {
    369     char *p, *s;
    370 
    371     p = *str;
    372     SKIP_BLANKS(p);
    373     for (s = p; *p && !IS_SPACE(*p) && *p != ';'; p++) ;
    374     *str = p;
    375     return Strnew_charp_n(s, p - s)->ptr;
    376 }
    377 
    378 char *
    379 getQWord(char **str)
    380 {
    381     Str tmp = Strnew();
    382     char *p;
    383     int in_q = 0, in_dq = 0, esc = 0;
    384 
    385     p = *str;
    386     SKIP_BLANKS(p);
    387     for (; *p; p++) {
    388 	if (esc) {
    389 	    if (in_q) {
    390 		if (*p != '\\' && *p != '\'')	/* '..\\..', '..\'..' */
    391 		    Strcat_char(tmp, '\\');
    392 	    }
    393 	    else if (in_dq) {
    394 		if (*p != '\\' && *p != '"')	/* "..\\..", "..\".." */
    395 		    Strcat_char(tmp, '\\');
    396 	    }
    397 	    else {
    398 		if (*p != '\\' && *p != '\'' &&	/* ..\\.., ..\'.. */
    399 		    *p != '"' && !IS_SPACE(*p))	/* ..\".., ..\.. */
    400 		    Strcat_char(tmp, '\\');
    401 	    }
    402 	    Strcat_char(tmp, *p);
    403 	    esc = 0;
    404 	}
    405 	else if (*p == '\\') {
    406 	    esc = 1;
    407 	}
    408 	else if (in_q) {
    409 	    if (*p == '\'')
    410 		in_q = 0;
    411 	    else
    412 		Strcat_char(tmp, *p);
    413 	}
    414 	else if (in_dq) {
    415 	    if (*p == '"')
    416 		in_dq = 0;
    417 	    else
    418 		Strcat_char(tmp, *p);
    419 	}
    420 	else if (*p == '\'') {
    421 	    in_q = 1;
    422 	}
    423 	else if (*p == '"') {
    424 	    in_dq = 1;
    425 	}
    426 	else if (IS_SPACE(*p) || *p == ';') {
    427 	    break;
    428 	}
    429 	else {
    430 	    Strcat_char(tmp, *p);
    431 	}
    432     }
    433     *str = p;
    434     return tmp->ptr;
    435 }
    436 
    437 #ifdef USE_MOUSE
    438 static MouseAction default_mouse_action = {
    439     NULL,
    440     "<=UpDn",
    441     0, 6, FALSE, 0, 0,
    442     {{movMs, NULL}, {backBf, NULL}, {menuMs, NULL}},	/* default */
    443     {{NULL, NULL}, {NULL, NULL}, {NULL, NULL}},	/* anchor */
    444     {{followA, NULL}, {NULL, NULL}, {NULL, NULL}},	/* active */
    445     {{tabMs, NULL}, {closeTMs, NULL}, {NULL, NULL}},	/* tab */
    446     {NULL, NULL, NULL},		/* menu */
    447     {NULL, NULL, NULL}		/* lastline */
    448 };
    449 static MouseActionMap default_lastline_action[6] = {
    450     {backBf, NULL},
    451     {backBf, NULL},
    452     {pgBack, NULL},
    453     {pgBack, NULL},
    454     {pgFore, NULL},
    455     {pgFore, NULL}
    456 };
    457 
    458 static void
    459 setMouseAction0(char **str, int *width, MouseActionMap ** map, char *p)
    460 {
    461     char *s;
    462     int b, w, x;
    463 
    464     s = getQWord(&p);
    465     if (!*s) {
    466 	*str = NULL;
    467 	width = 0;
    468 	for (b = 0; b < 3; b++)
    469 	    map[b] = NULL;
    470 	return;
    471     }
    472     w = *width;
    473     *str = s;
    474     *width = get_strwidth(s);
    475     if (*width >= LIMIT_MOUSE_MENU)
    476 	*width = LIMIT_MOUSE_MENU;
    477     if (*width <= w)
    478 	return;
    479     for (b = 0; b < 3; b++) {
    480 	if (!map[b])
    481 	    continue;
    482 	map[b] = New_Reuse(MouseActionMap, map[b], *width);
    483 	for (x = w + 1; x < *width; x++) {
    484 	    map[b][x].func = NULL;
    485 	    map[b][x].data = NULL;
    486 	}
    487     }
    488 }
    489 
    490 static void
    491 setMouseAction1(MouseActionMap ** map, int width, char *p)
    492 {
    493     char *s;
    494     int x, x2, f;
    495 
    496     if (!*map) {
    497 	*map = New_N(MouseActionMap, width);
    498 	for (x = 0; x < width; x++) {
    499 	    (*map)[x].func = NULL;
    500 	    (*map)[x].data = NULL;
    501 	}
    502     }
    503     s = getWord(&p);
    504     x = atoi(s);
    505     if (!(IS_DIGIT(*s) && x >= 0 && x < width))
    506 	return;			/* error */
    507     s = getWord(&p);
    508     x2 = atoi(s);
    509     if (!(IS_DIGIT(*s) && x2 >= 0 && x2 < width))
    510 	return;			/* error */
    511     s = getWord(&p);
    512     f = getFuncList(s);
    513     s = getQWord(&p);
    514     if (!*s)
    515 	s = NULL;
    516     for (; x <= x2; x++) {
    517 	(*map)[x].func = (f >= 0) ? w3mFuncList[f].func : NULL;
    518 	(*map)[x].data = s;
    519     }
    520 }
    521 
    522 static void
    523 setMouseAction2(MouseActionMap * map, char *p)
    524 {
    525     char *s;
    526     int f;
    527 
    528     s = getWord(&p);
    529     f = getFuncList(s);
    530     s = getQWord(&p);
    531     if (!*s)
    532 	s = NULL;
    533     map->func = (f >= 0) ? w3mFuncList[f].func : NULL;
    534     map->data = s;
    535 }
    536 
    537 static void
    538 interpret_mouse_action(FILE * mf)
    539 {
    540     Str line;
    541     char *p, *s;
    542     int b;
    543 
    544     while (!feof(mf)) {
    545 	line = Strfgets(mf);
    546 	Strchop(line);
    547 	Strremovefirstspaces(line);
    548 	if (line->length == 0)
    549 	    continue;
    550 	p = conv_from_system(line->ptr);
    551 	s = getWord(&p);
    552 	if (*s == '#')		/* comment */
    553 	    continue;
    554 	if (!strcmp(s, "menu")) {
    555 	    setMouseAction0(&mouse_action.menu_str, &mouse_action.menu_width,
    556 			    mouse_action.menu_map, p);
    557 	    continue;
    558 	}
    559 	else if (!strcmp(s, "lastline")) {
    560 	    setMouseAction0(&mouse_action.lastline_str,
    561 			    &mouse_action.lastline_width,
    562 			    mouse_action.lastline_map, p);
    563 	    continue;
    564 	}
    565 	if (strcmp(s, "button"))
    566 	    continue;		/* error */
    567 	s = getWord(&p);
    568 	b = atoi(s) - 1;
    569 	if (!(b >= 0 && b <= 2))
    570 	    continue;		/* error */
    571 	SKIP_BLANKS(p);
    572 	if (IS_DIGIT(*p))
    573 	    s = "menu";
    574 	else
    575 	    s = getWord(&p);
    576 	if (!strcasecmp(s, "menu")) {
    577 	    if (!mouse_action.menu_str)
    578 		continue;
    579 	    setMouseAction1(&mouse_action.menu_map[b], mouse_action.menu_width,
    580 			    p);
    581 	}
    582 	else if (!strcasecmp(s, "lastline")) {
    583 	    if (!mouse_action.lastline_str)
    584 		continue;
    585 	    setMouseAction1(&mouse_action.lastline_map[b],
    586 			    mouse_action.lastline_width, p);
    587 	}
    588 	else if (!strcasecmp(s, "default"))
    589 	    setMouseAction2(&mouse_action.default_map[b], p);
    590 	else if (!strcasecmp(s, "anchor"))
    591 	    setMouseAction2(&mouse_action.anchor_map[b], p);
    592 	else if (!strcasecmp(s, "active"))
    593 	    setMouseAction2(&mouse_action.active_map[b], p);
    594 	else if (!strcasecmp(s, "tab"))
    595 	    setMouseAction2(&mouse_action.tab_map[b], p);
    596     }
    597 }
    598 
    599 void
    600 initMouseAction(void)
    601 {
    602     FILE *mf;
    603 
    604     bcopy((void *)&default_mouse_action, (void *)&mouse_action,
    605 	  sizeof(default_mouse_action));
    606     mouse_action.lastline_map[0] = New_N(MouseActionMap, 6);
    607     bcopy((void *)&default_lastline_action,
    608 	  (void *)mouse_action.lastline_map[0],
    609 	  sizeof(default_lastline_action));
    610     {
    611 #ifdef USE_M17N
    612 	int w = 0;
    613 	char **symbol = get_symbol(DisplayCharset, &w);
    614 #else
    615 	char **symbol = get_symbol();
    616 #endif
    617 	mouse_action.lastline_str =
    618 	    Strnew_charp(symbol[N_GRAPH_SYMBOL + 13])->ptr;
    619     }
    620 
    621     if ((mf = fopen(confFile(MOUSE_FILE), "rt")) != NULL) {
    622 	interpret_mouse_action(mf);
    623 	fclose(mf);
    624     }
    625     if ((mf = fopen(rcFile(MOUSE_FILE), "rt")) != NULL) {
    626 	interpret_mouse_action(mf);
    627 	fclose(mf);
    628     }
    629 }
    630 #endif