diff --git a/NEWS b/NEWS index 589a1bec..36239271 100644 --- a/NEWS +++ b/NEWS @@ -75,10 +75,16 @@ ELinks 0.12pre2.GIT now: To be released as 0.12pre3, 0.12rc1, or even 0.12.0. This branch also includes the changes listed under ``ELinks 0.11.5.GIT'' below. +* critical: Fix assertion failure if IMG/@usemap refers to a different + file. * Preserve newlines in hidden input fields, and submit them as CRLF. Previously, they could turn into spaces or disappear entirely. * Perl scripts can use modules that dynamically load C libraries, like XML::LibXML::SAX does. +* bug 885: Convert xterm titles to ISO-8859-1 by default, but add an + option to disable this. When removing control characters from a + title, note the charset. Don't truncate titles to the width of the + terminal. * enhancement: Updated ISO 8859-7, ISO 8859-16, KOI8-R, and MacRoman. ELinks 0.12pre2: @@ -301,11 +307,14 @@ ELinks 0.11.5.GIT now: To be released as 0.11.6. +* critical: fix double-free crash if EOF immediately follows * critical bug 1053: fix crash if a download finishes after ELinks has closed the terminal from which the download was started * major bug 1004: ignore locales when comparing HTML element names and similar strings, so e.g. ``title'' matches ``TITLE'' even in the Turkish locale +* minor: clicking a link with the mouse activates that link, rather + than the one selected with move-cursor-* actions ELinks 0.11.5: -------------- diff --git a/src/bfu/dialog.c b/src/bfu/dialog.c index a090e5d1..e6d665fd 100644 --- a/src/bfu/dialog.c +++ b/src/bfu/dialog.c @@ -323,7 +323,7 @@ select_button_by_key(struct dialog_data *dlg_data) #ifdef CONFIG_UTF8 key = unicode_fold_label_case(get_kbd_key(ev)); - codepage = get_opt_codepage_tree(dlg_data->win->term->spec, "charset", NULL); + codepage = get_terminal_codepage(dlg_data->win->term); #else key = toupper(get_kbd_key(ev)); #endif diff --git a/src/bfu/hotkey.c b/src/bfu/hotkey.c index 9502d11f..c09b6ed8 100644 --- a/src/bfu/hotkey.c +++ b/src/bfu/hotkey.c @@ -127,7 +127,7 @@ check_hotkeys_common(struct menu *menu, term_event_char_T hotkey, struct termina { #ifdef CONFIG_UTF8 unicode_val_T key = unicode_fold_label_case(hotkey); - int codepage = get_opt_codepage_tree(term->spec, "charset", NULL); + int codepage = get_terminal_codepage(term); #else unsigned char key = toupper(hotkey); #endif diff --git a/src/bfu/inpfield.c b/src/bfu/inpfield.c index 5e9896e6..8a8c8fc8 100644 --- a/src/bfu/inpfield.c +++ b/src/bfu/inpfield.c @@ -692,9 +692,7 @@ kbd_field(struct dialog_data *dlg_data, struct widget_data *widget_data) /* get_kbd_key(ev) is UCS-4, and @text * is in the terminal's charset. */ ins = u2cp_no_nbsp(get_kbd_key(ev), - get_opt_codepage_tree(term->spec, - "charset", - NULL)); + get_terminal_codepage(term)); inslen = strlen(ins); #endif /* CONFIG_UTF8 */ diff --git a/src/config/options.inc b/src/config/options.inc index 43b72c7c..6d2a5b0c 100644 --- a/src/config/options.inc +++ b/src/config/options.inc @@ -847,6 +847,19 @@ static struct option_info config_options_info[] = { "3 is KOI-8\n" "4 is FreeBSD")), + INIT_OPT_BOOL("terminal._template_", N_("Always encode xterm title in ISO-8859-1"), + "latin1_title", 0, 1, + N_("When updating the window title of xterm or a similar " + "terminal emulator, encode the title in ISO-8859-1 (Latin-1), " + "rather than in the charset used for other text in the window. " + "Cyrillic and other characters get replaced with Latin ones. " + "Xterm requires this unless you explicitly enable UTF-8 " + "titles in it.\n" + "\n" + "If this option does not take effect immediately, try switching " + "to a different page so that ELinks notices it needs to update " + "the title.")), + INIT_OPT_BOOL("terminal._template_", N_("Switch fonts for line drawing"), "m11_hack", 0, 0, N_("Switch fonts when drawing lines, enabling both local characters\n" diff --git a/src/dialogs/options.c b/src/dialogs/options.c index 553ad0d7..e1717481 100644 --- a/src/dialogs/options.c +++ b/src/dialogs/options.c @@ -50,7 +50,7 @@ charset_list(struct terminal *term, void *xxx, void *ses_) int i, items; int sel = 0; const unsigned char *const sel_mime = get_cp_mime_name( - get_opt_codepage_tree(term->spec, "charset", NULL)); + get_terminal_codepage(term)); struct menu_item *mi = new_menu(FREE_LIST); if (!mi) return; diff --git a/src/dialogs/status.c b/src/dialogs/status.c index 5237a82b..782f7f5b 100644 --- a/src/dialogs/status.c +++ b/src/dialogs/status.c @@ -493,12 +493,12 @@ display_window_title(struct session *ses, struct terminal *term) if (!title) return; titlelen = strlen(title); - if (last_ses != ses - || !status->last_title - || strlen(status->last_title) != titlelen - || memcmp(status->last_title, title, titlelen)) { + if ((last_ses != ses + || !status->last_title + || strlen(status->last_title) != titlelen + || memcmp(status->last_title, title, titlelen)) + && set_terminal_title(term, title) >= 0) { mem_free_set(&status->last_title, title); - set_terminal_title(term, title); last_ses = ses; } else { mem_free(title); diff --git a/src/document/html/parser.c b/src/document/html/parser.c index c95e3792..dcaa10aa 100644 --- a/src/document/html/parser.c +++ b/src/document/html/parser.c @@ -619,6 +619,9 @@ look_for_tag(unsigned char **pos, unsigned char *eof, return 0; } +/** @return -1 if EOF is hit without the closing tag; 0 if the closing + * tag is found (in which case this also adds *@a menu to *@a ml); or + * 1 if this should be called again. */ static int look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, struct memory_list **ml, struct uri *href_base, @@ -636,7 +639,7 @@ look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, (*pos)++; } - if (*pos >= eof) return 0; + if (*pos >= eof) return -1; if (*pos + 2 <= eof && ((*pos)[1] == '!' || (*pos)[1] == '?')) { *pos = skip_comment(*pos, eof); @@ -651,7 +654,7 @@ look_for_link(unsigned char **pos, unsigned char *eof, struct menu_item **menu, if (!c_strlcasecmp(name, namelen, "A", 1)) { while (look_for_tag(pos, eof, name, namelen, &label)); - if (*pos >= eof) return 0; + if (*pos >= eof) return -1; } else if (!c_strlcasecmp(name, namelen, "AREA", 4)) { /* FIXME (bug 784): options->cp is the terminal charset; @@ -769,6 +772,7 @@ get_image_map(unsigned char *head, unsigned char *pos, unsigned char *eof, { struct conv_table *ct; struct string hd; + int look_result; if (!init_string(&hd)) return -1; @@ -789,10 +793,13 @@ get_image_map(unsigned char *head, unsigned char *pos, unsigned char *eof, *ml = NULL; - while (look_for_link(&pos, eof, menu, ml, uri, target_base, ct, options)) - ; + do { + /* This call can modify both *ml and *menu. */ + look_result = look_for_link(&pos, eof, menu, ml, uri, + target_base, ct, options); + } while (look_result > 0); - if (pos >= eof) { + if (look_result < 0) { freeml(*ml); mem_free(*menu); return -1; diff --git a/src/document/renderer.c b/src/document/renderer.c index b62719a4..71e1c691 100644 --- a/src/document/renderer.c +++ b/src/document/renderer.c @@ -457,8 +457,7 @@ render_document_frames(struct session *ses, int no_cache) if (!get_opt_bool_tree(ses->tab->term->spec, "underline", NULL)) doc_opts.color_flags |= COLOR_ENHANCE_UNDERLINE; - doc_opts.cp = get_opt_codepage_tree(ses->tab->term->spec, "charset", - NULL); + doc_opts.cp = get_terminal_codepage(ses->tab->term); doc_opts.no_cache = no_cache & 1; doc_opts.gradual_rerendering = !!(no_cache & 2); diff --git a/src/intl/charsets.c b/src/intl/charsets.c index 23442fbf..f09622f7 100644 --- a/src/intl/charsets.c +++ b/src/intl/charsets.c @@ -255,7 +255,6 @@ encode_utf8(unicode_val_T u) return utf_buffer; } -#ifdef CONFIG_UTF8 /* Number of bytes utf8 character indexed by first byte. Illegal bytes are * equal ones and handled different. */ static const char utf8char_len_tab[256] = { @@ -269,6 +268,7 @@ static const char utf8char_len_tab[256] = { 3,3,3,3,3,3,3,3, 3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4, 5,5,5,5,6,6,1,1, }; +#ifdef CONFIG_UTF8 inline int utf8charlen(const unsigned char *p) { return p ? utf8char_len_tab[*p] : 0; @@ -631,6 +631,7 @@ unicode_fold_label_case(unicode_val_T c) return c; #endif /* !(__STDC_ISO_10646__ && HAVE_WCTYPE_H) */ } +#endif /* CONFIG_UTF8 */ inline unicode_val_T utf8_to_unicode(unsigned char **string, const unsigned char *end) @@ -715,7 +716,6 @@ invalid_utf8: *string = str + length; return u; } -#endif /* CONFIG_UTF8 */ /* The common part of cp2u and cp2utf_8. */ static unicode_val_T @@ -754,9 +754,8 @@ cp2utf8(int from, int c) return encode_utf8(cp2u_shared(&codepages[from], c)); } -#ifdef CONFIG_UTF8 unicode_val_T -cp_to_unicode(int codepage, unsigned char **string, unsigned char *end) +cp_to_unicode(int codepage, unsigned char **string, const unsigned char *end) { unicode_val_T ret; @@ -770,7 +769,6 @@ cp_to_unicode(int codepage, unsigned char **string, unsigned char *end) ++*string; return ret; } -#endif /* CONFIG_UTF8 */ #ifdef CONFIG_COMBINE diff --git a/src/intl/charsets.h b/src/intl/charsets.h index d87e2ee4..a94cc410 100644 --- a/src/intl/charsets.h +++ b/src/intl/charsets.h @@ -154,9 +154,9 @@ unsigned char *utf8_step_backward(unsigned char *, unsigned char *, inline int unicode_to_cell(unicode_val_T); unicode_val_T unicode_fold_label_case(unicode_val_T); inline int strlen_utf8(unsigned char **); -inline unicode_val_T utf8_to_unicode(unsigned char **, const unsigned char *); -unicode_val_T cp_to_unicode(int, unsigned char **, unsigned char *); #endif /* CONFIG_UTF8 */ +inline unicode_val_T utf8_to_unicode(unsigned char **, const unsigned char *); +unicode_val_T cp_to_unicode(int, unsigned char **, const unsigned char *); #ifdef CONFIG_COMBINE extern unicode_val_T last_combined; diff --git a/src/intl/gettext/libintl.h b/src/intl/gettext/libintl.h index 97461b58..ac9c68d0 100644 --- a/src/intl/gettext/libintl.h +++ b/src/intl/gettext/libintl.h @@ -61,7 +61,7 @@ extern int current_charset; static inline void intl_set_charset(struct terminal *term) { - int new_charset = get_opt_codepage_tree(term->spec, "charset", NULL); + int new_charset = get_terminal_codepage(term); /* Prevent useless switching. */ if (current_charset != new_charset) { diff --git a/src/osdep/os2/os2.c b/src/osdep/os2/os2.c index 20d6d9f4..16875c14 100644 --- a/src/osdep/os2/os2.c +++ b/src/osdep/os2/os2.c @@ -303,7 +303,7 @@ get_window_title(void) } void -set_window_title(unsigned char *title) +set_window_title(unsigned char *title, int codepage) { #ifndef DEBUG_OS2 static PTIB tib; diff --git a/src/osdep/osdep.c b/src/osdep/osdep.c index 74eab68a..e26463e3 100644 --- a/src/osdep/osdep.c +++ b/src/osdep/osdep.c @@ -407,73 +407,71 @@ set_clipboard_text(unsigned char *data) /* Set xterm-like term window's title. */ void -set_window_title(unsigned char *title) +set_window_title(unsigned char *title, int codepage) { - unsigned char *s; - int xsize, ysize; - int j = 0; + struct string filtered; #ifndef HAVE_SYS_CYGWIN_H /* Check if we're in a xterm-like terminal. */ if (!is_xterm() && !is_gnuscreen()) return; #endif - /* Retrieve terminal dimensions. */ - get_terminal_size(0, &xsize, &ysize); + if (!init_string(&filtered)) return; - /* Check if terminal width is reasonnable. */ - if (xsize < 1 || xsize > 1024) return; - - /* Allocate space for title + 3 ending points + null char. */ - s = mem_alloc(xsize + 3 + 1); - if (!s) return; - - /* Copy title to s if different from NULL */ + /* Copy title to filtered if different from NULL */ if (title) { - int i; + unsigned char *scan = title; + unsigned char *end = title + strlen(title); - /* We limit title length to terminal width and ignore control - * chars if any. Note that in most cases window decoration - * reduces printable width, so it's just a precaution. */ + /* Remove control characters, so that they cannot + * interfere with the command we send to the terminal. + * However, do not attempt to limit the title length + * to terminal width, because the title is usually + * drawn in a different font anyway. */ /* Note that this is the right place where to do it, since * potential alternative set_window_title() routines might * want to take different precautions. */ - for (i = 0; title[i] && i < xsize; i++) { - /* 0x80 .. 0x9f are ISO-8859-* control characters. - * In some other encodings they could be used for - * legitimate characters, though (ie. in Kamenicky). - * We should therefore maybe check for these only - * if the terminal is running in an ISO- encoding. */ - if (iscntrl(title[i]) || (title[i] & 0x7f) < 0x20 - || title[i] == 0x7f) + for (;;) { + unsigned char *charbegin = scan; + unicode_val_T unicode + = cp_to_unicode(codepage, &scan, end); + int charlen = scan - charbegin; + + if (unicode == UCS_NO_CHAR) + break; + + /* This need not recognize all Unicode control + * characters. Only those that can make the + * terminal misparse the command. */ + if (unicode < 0x20 + || (unicode >= 0x7F && unicode < 0xA0)) continue; - s[j++] = title[i]; - } + /* xterm entirely rejects 1024-byte or longer + * titles. */ + if (filtered.length + charlen >= 1024 - 3) { + add_to_string(&filtered, "..."); + break; + } - /* If title is truncated, add "..." */ - if (i == xsize) { - s[j++] = '.'; - s[j++] = '.'; - s[j++] = '.'; + add_bytes_to_string(&filtered, charbegin, charlen); } } - s[j] = '\0'; /* Send terminal escape sequence + title string */ - printf("\033]0;%s\a", s); + printf("\033]0;%s\a", filtered.source); #if 0 /* Miciah don't like this so it is disabled because it changes the * default window name. --jonas */ /* Set the GNU screen window name */ if (is_gnuscreen()) - printf("\033k%s\033\134", s); + printf("\033k%s\033\134", filtered.source); #endif fflush(stdout); - mem_free(s); + done_string(&filtered); } #ifdef HAVE_X11 diff --git a/src/osdep/osdep.h b/src/osdep/osdep.h index 721916fd..15cefc3b 100644 --- a/src/osdep/osdep.h +++ b/src/osdep/osdep.h @@ -38,7 +38,7 @@ void resume_mouse(void *); int start_thread(void (*)(void *, int), void *, int); unsigned char *get_clipboard_text(void); void set_clipboard_text(unsigned char *); -void set_window_title(unsigned char *); +void set_window_title(unsigned char *, int codepage); unsigned char *get_window_title(void); void block_stdin(void); void unblock_stdin(void); diff --git a/src/protocol/http/codes.c b/src/protocol/http/codes.c index ac67c971..c4a260fb 100644 --- a/src/protocol/http/codes.c +++ b/src/protocol/http/codes.c @@ -171,8 +171,7 @@ show_http_error_document(struct session *ses, void *data) if (str) { /* The codepage that _("foo", term) used when it was * called by get_http_error_document. */ - const int gettext_codepage - = get_opt_codepage_tree(term->spec, "charset", NULL); + const int gettext_codepage = get_terminal_codepage(term); if (cached) delete_entry_content(cache); diff --git a/src/session/session.c b/src/session/session.c index f40e7bee..7e22a9aa 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -518,17 +518,23 @@ maybe_pre_format_html(struct cache_entry *cached, struct session *ses) * were 0, it could then be freed, and the * cached->preformatted assignment at the end of this function * would crash. Normally, the document has a reference to the - * cache entry, and that suffices. If the following assertion - * ever fails, object_lock(cached) and object_unlock(cached) - * must be added to this function. */ - assert(cached->object.refcount > 0); - if_assert_failed return; + * cache entry, and that suffices. However, if the cache + * entry was loaded to satisfy e.g. USEMAP="imgmap.html#map", + * then cached->object.refcount == 0 here, and must be + * incremented. + * + * cached->object.refcount == 0 is safe while the cache entry + * is being loaded, because garbage_collection() calls + * is_entry_used(), which checks whether any connection is + * using the cache entry. But loading has ended before this + * point. */ + object_lock(cached); fragment = get_cache_fragment(cached); - if (!fragment) return; + if (!fragment) goto unlock_and_return; /* We cannot do anything if the data are fragmented. */ - if (!list_is_singleton(cached->frag)) return; + if (!list_is_singleton(cached->frag)) goto unlock_and_return; set_event_id(pre_format_html_event, "pre-format-html"); trigger_event(pre_format_html_event, ses, cached); @@ -536,6 +542,9 @@ maybe_pre_format_html(struct cache_entry *cached, struct session *ses) /* XXX: Keep this after the trigger_event, because hooks might call * normalize_cache_entry()! */ cached->preformatted = 1; + +unlock_and_return: + object_unlock(cached); } #endif diff --git a/src/session/task.c b/src/session/task.c index 47489152..b38c28e4 100644 --- a/src/session/task.c +++ b/src/session/task.c @@ -388,7 +388,7 @@ ses_imgmap(struct session *ses) &menu, &ml, ses->loading_uri, &doc_view->document->options, ses->task.target.frame, - get_opt_codepage_tree(ses->tab->term->spec, "charset", NULL), + get_terminal_codepage(ses->tab->term), get_opt_codepage("document.codepage.assume", ses), get_opt_bool("document.codepage.force_assumed", ses))) return; diff --git a/src/terminal/event.c b/src/terminal/event.c index a6e18b0c..6b4eff8d 100644 --- a/src/terminal/event.c +++ b/src/terminal/event.c @@ -149,8 +149,7 @@ term_send_ucs(struct terminal *term, unicode_val_T u, const unsigned char *recoded; set_kbd_term_event(&ev, KBD_UNDEF, modifier); - recoded = u2cp_no_nbsp(u, get_opt_codepage_tree(term->spec, "charset", - NULL)); + recoded = u2cp_no_nbsp(u, get_terminal_codepage(term)); if (!recoded) recoded = "*"; while (*recoded) { ev.info.keyboard.key = *recoded; @@ -186,8 +185,7 @@ check_terminal_name(struct terminal *term, struct terminal_info *info) /* Probably not best place for set this. But now we finally have * term->spec and term->utf8 should be set before decode session info. * --Scrool */ - term->utf8_cp = is_cp_utf8(get_opt_codepage_tree(term->spec, - "charset", NULL)); + term->utf8_cp = is_cp_utf8(get_terminal_codepage(term)); /* Force UTF-8 I/O if the UTF-8 charset is selected. Various * places assume that the terminal's charset is unibyte if * UTF-8 I/O is disabled. (bug 827) */ diff --git a/src/terminal/itrm.h b/src/terminal/itrm.h index 05363e31..c88a37f5 100644 --- a/src/terminal/itrm.h +++ b/src/terminal/itrm.h @@ -101,6 +101,7 @@ struct itrm { unsigned char *orig_title; /**< For restoring window title */ int verase; /**< Byte to map to KBD_BS, or -1 */ + int title_codepage; /**< Codepage of terminal title */ unsigned int blocked:1; /**< Whether it was blocked */ unsigned int altscreen:1; /**< Whether to use alternate screen */ unsigned int touched_title:1; /**< Whether the term title was changed */ diff --git a/src/terminal/kbd.c b/src/terminal/kbd.c index 6a0b45e0..cd50a078 100644 --- a/src/terminal/kbd.c +++ b/src/terminal/kbd.c @@ -331,6 +331,11 @@ handle_trm(int std_in, int std_out, int sock_in, int sock_out, int ctl_in, itrm->timer = TIMER_ID_UNDEF; itrm->remote = !!remote; + /* If the master does not tell which charset it's using in + * this terminal, assume it's some ISO 8859. Because that's + * what older versions of ELinks did. */ + itrm->title_codepage = get_cp_index("ISO-8859-1"); + /* FIXME: Combination altscreen + xwin does not work as it should, * mouse clicks are reportedly partially ignored. */ if (info.system_env & (ENV_SCREEN | ENV_XWIN)) @@ -424,7 +429,7 @@ free_itrm(struct itrm *itrm) if (!itrm->remote) { if (itrm->orig_title && *itrm->orig_title) { - set_window_title(itrm->orig_title); + set_window_title(itrm->orig_title, itrm->title_codepage); } else if (itrm->touched_title) { /* Set the window title to the value of $TERM if X11 @@ -434,7 +439,8 @@ free_itrm(struct itrm *itrm) get_terminal_name(title); if (*title) - set_window_title(title); + set_window_title(title, + get_cp_index("US-ASCII")); } @@ -507,7 +513,12 @@ dispatch_special(unsigned char *text) ditrm->orig_title = get_window_title(); ditrm->touched_title = 1; } - set_window_title(text + 1); + /* TODO: Is it really possible to get here with + * ditrm == NULL, and which charset would then + * be most appropriate? */ + set_window_title(text + 1, + ditrm ? ditrm->title_codepage + : get_cp_index("US-ASCII")); break; case TERM_FN_RESIZE: if (ditrm && ditrm->remote) @@ -515,6 +526,18 @@ dispatch_special(unsigned char *text) resize_terminal_from_str(text + 1); break; + case TERM_FN_TITLE_CODEPAGE: + if (ditrm) { + int cp = get_cp_index(text + 1); + + /* If the master sends the name of an + * unrecognized charset, assume only + * that it's ASCII compatible. */ + if (cp == -1) + cp = get_cp_index("US-ASCII"); + ditrm->title_codepage = cp; + } + break; } } diff --git a/src/terminal/terminal.c b/src/terminal/terminal.c index e53e7bc8..8d263150 100644 --- a/src/terminal/terminal.c +++ b/src/terminal/terminal.c @@ -118,6 +118,24 @@ init_term(int fdin, int fdout) return term; } +/** Get the codepage of a terminal. The UTF-8 I/O option does not + * affect this. + * + * @todo Perhaps cache the value in struct terminal? + * + * @bug Bug 1064: If the charset has been set as "System", this should + * apply the locale environment variables of the slave ELinks process, + * not those of the master ELinks process that parsed the configuration + * file. That is why the parameter points to struct terminal and not + * merely to its option tree (term->spec). + * + * @see get_translation_table(), get_cp_mime_name() */ +int +get_terminal_codepage(const struct terminal *term) +{ + return get_opt_codepage_tree(term->spec, "charset", NULL); +} + void redraw_all_terminals(void) { @@ -371,12 +389,44 @@ do_terminal_function(struct terminal *term, unsigned char code, fmem_free(x_data); } -void +/** @return negative on error; zero or positive on success. */ +int set_terminal_title(struct terminal *term, unsigned char *title) { - if (term->title && !strcmp(title, term->title)) return; + int from_cp; + int to_cp; + unsigned char *converted = NULL; + + if (term->title && !strcmp(title, term->title)) return 0; + + /* In which codepage was the title parameter given? */ + from_cp = get_terminal_codepage(term); + + /* In which codepage does the terminal want the title? */ + if (get_opt_bool_tree(term->spec, "latin1_title", NULL)) + to_cp = get_cp_index("ISO-8859-1"); + else if (get_opt_bool_tree(term->spec, "utf_8_io", NULL)) + to_cp = get_cp_index("UTF-8"); + else + to_cp = from_cp; + + if (from_cp != to_cp) { + struct conv_table *convert_table; + + convert_table = get_translation_table(from_cp, to_cp); + if (!convert_table) return -1; + converted = convert_string(convert_table, title, strlen(title), + to_cp, CSM_NONE, NULL, NULL, NULL); + if (!converted) return -1; + } + mem_free_set(&term->title, stracpy(title)); - do_terminal_function(term, TERM_FN_TITLE, title); + do_terminal_function(term, TERM_FN_TITLE_CODEPAGE, + get_cp_mime_name(to_cp)); + do_terminal_function(term, TERM_FN_TITLE, + converted ? converted : title); + mem_free_if(converted); + return 0; } static int terminal_pipe[2]; diff --git a/src/terminal/terminal.h b/src/terminal/terminal.h index c0fd7a76..5d6c3cb8 100644 --- a/src/terminal/terminal.h +++ b/src/terminal/terminal.h @@ -179,6 +179,7 @@ void redraw_terminal(struct terminal *term); void redraw_terminal_cls(struct terminal *term); void cls_redraw_all_terminals(void); struct terminal *get_default_terminal(void); +int get_terminal_codepage(const struct terminal *); void redraw_all_terminals(void); void destroy_all_terminals(void); @@ -191,12 +192,14 @@ void close_handle(void *); void assert_terminal_ptr_not_dangling(const struct terminal *); #endif -/** Operations that can be requested with do_terminal_function(). +/** Operations that can be requested with do_terminal_function() in + * the master and then executed with dispatch_special() in a slave. * The interlink protocol passes these values as one byte in a * null-terminated string, so zero cannot be used. */ enum { - TERM_FN_TITLE = 1, - TERM_FN_RESIZE = 2 + TERM_FN_TITLE = 1, + TERM_FN_RESIZE = 2, + TERM_FN_TITLE_CODEPAGE = 3 }; /** How to execute a program in a terminal. These values are used in @@ -217,7 +220,7 @@ enum term_exec { void exec_on_terminal(struct terminal *, unsigned char *, unsigned char *, enum term_exec); void exec_shell(struct terminal *term); -void set_terminal_title(struct terminal *, unsigned char *); +int set_terminal_title(struct terminal *, unsigned char *); void do_terminal_function(struct terminal *, unsigned char, unsigned char *); int check_terminal_pipes(void); diff --git a/src/util/conv.c b/src/util/conv.c index 7ca0dc63..1bf78774 100644 --- a/src/util/conv.c +++ b/src/util/conv.c @@ -313,21 +313,11 @@ add_cp_html_to_string(struct string *string, int src_codepage, const unsigned char *const end = src + len; unicode_val_T unicode; - while (src != end) { - if (is_cp_utf8(src_codepage)) { -#ifdef CONFIG_UTF8 - unicode = utf8_to_unicode((unsigned char **) &src, - end); - if (unicode == UCS_NO_CHAR) - break; -#else /* !CONFIG_UTF8 */ - /* Cannot parse UTF-8 without CONFIG_UTF8. - * Pretend the input is ISO-8859-1 instead. */ - unicode = *src++; -#endif /* !CONFIG_UTF8 */ - } else { - unicode = cp2u(src_codepage, *src++); - } + for (;;) { + unicode = cp_to_unicode(src_codepage, + (unsigned char **) &src, end); + if (unicode == UCS_NO_CHAR) + break; if (unicode < 0x20 || unicode >= 0x7F || unicode == '<' || unicode == '>' || unicode == '&' diff --git a/src/viewer/text/form.c b/src/viewer/text/form.c index e64ae88c..9a6384f8 100644 --- a/src/viewer/text/form.c +++ b/src/viewer/text/form.c @@ -177,7 +177,7 @@ init_form_state(struct document_view *doc_view, doc_cp = doc_view->document->cp; term = doc_view->session->tab->term; - viewer_cp = get_opt_codepage_tree(term->spec, "charset", NULL); + viewer_cp = get_terminal_codepage(term); mem_free_set(&fs->value, NULL); @@ -1235,7 +1235,7 @@ get_form_uri(struct session *ses, struct document_view *doc_view, get_successful_controls(doc_view, fc, &submit); - cp_from = get_opt_codepage_tree(ses->tab->term->spec, "charset", NULL); + cp_from = get_terminal_codepage(ses->tab->term); cp_to = doc_view->document->cp; switch (form->method) { case FORM_METHOD_GET: @@ -1868,9 +1868,7 @@ field_op(struct session *ses, struct document_view *doc_view, #ifdef CONFIG_UTF8 /* fs->value is in the charset of the terminal. */ ctext = u2cp_no_nbsp(get_kbd_key(ev), - get_opt_codepage_tree(ses->tab->term->spec, - "charset", - NULL)); + get_terminal_codepage(ses->tab->term)); length = strlen(ctext); if (strlen(fs->value) + length > fc->maxlength diff --git a/src/viewer/text/link.c b/src/viewer/text/link.c index 804f1d21..fbabd9dd 100644 --- a/src/viewer/text/link.c +++ b/src/viewer/text/link.c @@ -1214,8 +1214,7 @@ try_document_key(struct session *ses, struct document_view *doc_view, #ifdef CONFIG_UTF8 key = get_kbd_key(ev); #else /* !CONFIG_UTF8 */ - key = cp2u(get_opt_codepage_tree(ses->tab->term->spec, - "charset", NULL), + key = cp2u(get_terminal_codepage(ses->tab->term), get_kbd_key(ev)); #endif /* !CONFIG_UTF8 */ /* If @key now is 0 (which is used in link.accesskey if there diff --git a/src/viewer/text/view.c b/src/viewer/text/view.c index 0dcc8361..cf19e418 100644 --- a/src/viewer/text/view.c +++ b/src/viewer/text/view.c @@ -1169,6 +1169,7 @@ frame_ev_mouse(struct session *ses, struct document_view *doc_view, struct term_ enum frame_event_status status = FRAME_EVENT_REFRESH; doc_view->vs->current_link = link - doc_view->document->links; + ses->navigate_mode = NAVIGATE_LINKWISE; if (!link_is_textinput(link)) { diff --git a/test/image.png b/test/image.png new file mode 100644 index 00000000..0d09732b Binary files /dev/null and b/test/image.png differ diff --git a/test/imgmap.html b/test/imgmap.html index cea1e361..99015d25 100644 --- a/test/imgmap.html +++ b/test/imgmap.html @@ -1,11 +1,11 @@ -ImageMap +ImageMap -1 -2 -3 -4 +1 +2 +3 +4 diff --git a/test/imgmap2.html b/test/imgmap2.html new file mode 100644 index 00000000..7a503feb --- /dev/null +++ b/test/imgmap2.html @@ -0,0 +1,6 @@ +Crashes in client-side image maps +

ImageMap in another file

+

ImageMap at the very end of this file

+ +see this? +