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, ¤t_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