1
0
mirror of https://github.com/rkd77/elinks.git synced 2024-06-12 23:10:51 +00:00

Merge branch 'elinks-0.12' into elinks-0.13

Conflicts:
	src/bookmarks/backend/default.c
	src/bookmarks/bookmarks.c
	src/session/session.c
	src/terminal/event.c
	src/viewer/text/search.c
This commit is contained in:
Kalle Olavi Niemitalo 2009-02-08 22:02:57 +02:00 committed by Kalle Olavi Niemitalo
commit d2854dca8d
26 changed files with 1030 additions and 234 deletions

View File

@ -87,6 +87,8 @@ SEE_CFLAGS = @SEE_CFLAGS@
SPARSE = @SPARSE@
SPIDERMONKEY_CFLAGS = @SPIDERMONKEY_CFLAGS@
SPIDERMONKEY_LIBS = @SPIDERMONKEY_LIBS@
TRE_CFLAGS = @TRE_CFLAGS@
TRE_LIBS = @TRE_LIBS@
VERSION = @VERSION@
XMLTO = @XMLTO@
X_CFLAGS = @X_CFLAGS@

10
NEWS
View File

@ -75,16 +75,26 @@ 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.
Incompatibilities:
* bug 1060: Regexp searching now requires the TRE library.
Other changes:
* 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 153: Preserve Unicode characters in XBEL bookmark files.
However, Unicode in URIs (really IRIs) does not work reliably yet;
this is being tracked as bug 1066.
* 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.
* bug 1061: Correctly truncate UTF-8 titles in the tab bar.
* enhancement: Updated ISO 8859-7, ISO 8859-16, KOI8-R, and MacRoman.
ELinks 0.12pre2:

View File

@ -250,12 +250,6 @@ EL_CHECK_CODE([variadic macros], HAVE_VARIADIC_MACROS,
#define a(b,c...) printf(b,##c)],
[a("foo");a("%s","bar");a("%s%s","baz","quux");])
# ===================================================================
# Check for POSIX <regex.h>
# ===================================================================
EL_CHECK_SYS_TYPE(regex_t, HAVE_REGEX_H, [#include <regex.h>])
# ===================================================================
# Checks for library functions.
# ===================================================================
@ -909,6 +903,48 @@ else
AC_SUBST(LUA_CFLAGS)
fi
# ===================================================================
# Check for TRE library
# ===================================================================
AC_MSG_CHECKING([[for TRE in pkg-config]])
if pkg-config tre; then
TRE_CFLAGS=`pkg-config --cflags tre`
TRE_LIBS=`pkg-config --libs tre`
AC_MSG_RESULT([[yes]])
else
# <http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=513055>
# "libtre-dev: /usr/lib/pkgconfig/tre.pc missing"
# so we look for the library even if pkg-config doesn't know about it.
TRE_CFLAGS=
TRE_LIBS=-ltre
AC_MSG_RESULT([[no, but let's try defaults]])
fi
AC_MSG_CHECKING([[for TRE header and library]])
EL_SAVE_FLAGS
CFLAGS="$TRE_CFLAGS $CFLAGS"
LIBS="$TRE_LIBS $LIBS"
AC_TRY_LINK([#include <tre/regex.h>],
[regex_t re;
regmatch_t match[1];
regwcomp(&re, L"zap", REG_ICASE);
regwexec(&re, L"ELIZAPROGRAM", 1, match, 0);],
[AC_MSG_RESULT([[yes]])
AC_DEFINE([HAVE_TRE_REGEX_H], [1],
[Define to 1 if you have the <tre/regex.h> header file.])
# TRE_CFLAGS will be used only where needed.
# TRE_LIBS will be kept in LIBS and used everywhere.
EL_RESTORE_FLAGS
LIBS="$TRE_LIBS $LIBS"],
[AC_MSG_RESULT([[no]])
TRE_CFLAGS=
TRE_LIBS=
EL_RESTORE_FLAGS])
AC_SUBST(TRE_CFLAGS)
AC_SUBST(TRE_LIBS)
AC_CHECK_SIZEOF([wchar_t], [4], [[#include <wchar.h>]])
# ===================================================================
# Check for Ruby, optional even if installed.

View File

@ -85,8 +85,8 @@ Triggered When:
Arguments:
struct bookmark *bookmark
unsigned char *new_title
unsigned char *new_url
unsigned char *new_title /* UTF-8 */
unsigned char *new_url /* UTF-8 */
Description:

View File

@ -52,6 +52,8 @@ OpenSSL, GNU TLS, or nss_compat_ossl \
|For handling secure HTTP browsing.
GPM |'General Purpose Mouse' for mouse support.
expat |'XML Parser Toolkit' needed for XBEL support.
http://laurikari.net/tre/[TRE] \
|For regexp searching. Version 0.7.5 works.
libsmbclient |Library needed for smb:// protocol support.
rxvt-unicode |For terminal emulator which supports 88 colors.
xterm with 256 colors |Program atleast patch level 179 or rxvt program \

View File

@ -4,6 +4,7 @@
#include "config.h"
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -33,6 +34,7 @@ read_bookmarks_default(FILE *f)
unsigned char in_buffer[INBUF_SIZE]; /* read buffer */
struct bookmark *last_bm = NULL;
int last_depth = 0;
const int file_cp = get_cp_index("System");
/* TODO: Ignore lines with bad chars in title or url (?). -- Zas */
while (fgets(in_buffer, INBUF_SIZE, f)) {
@ -101,7 +103,8 @@ read_bookmarks_default(FILE *f)
root = last_bm->root;
}
}
last_bm = add_bookmark(root, 1, title, url);
last_bm = add_bookmark_cp(root, 1, file_cp,
title, url);
last_depth = depth;
if (!*url && title[0] == '-' && title[1] == '\0') {
@ -125,27 +128,65 @@ read_bookmarks_default(FILE *f)
#undef INBUF_SIZE
}
struct write_bookmarks_default
{
struct secure_save_info *ssi;
int save_folder_state;
int codepage;
struct conv_table *conv_table;
};
static void
write_bookmarks_default_inner(const struct write_bookmarks_default *out,
LIST_OF(struct bookmark) *bookmarks_list)
{
struct bookmark *bm;
foreach (bm, *bookmarks_list) {
unsigned char *title, *url;
title = convert_string(out->conv_table, bm->title,
strlen(bm->title), out->codepage,
CSM_NONE, NULL, NULL, NULL);
url = convert_string(out->conv_table, bm->url,
strlen(bm->url), out->codepage,
CSM_NONE, NULL, NULL, NULL);
secure_fprintf(out->ssi, "%s\t%s\t%d\t",
empty_string_or_(title), empty_string_or_(url),
bm->box_item->depth);
if (bm->box_item->type == BI_FOLDER) {
secure_fputc(out->ssi, 'F');
if (out->save_folder_state && bm->box_item->expanded)
secure_fputc(out->ssi, 'E');
}
secure_fputc(out->ssi, '\n');
if (!title || !url) {
secsave_errno = SS_ERR_OTHER;
out->ssi->err = ENOMEM;
}
mem_free_if(title);
mem_free_if(url);
if (out->ssi->err) break;
if (!list_empty(bm->child))
write_bookmarks_default_inner(out, &bm->child);
}
}
/* Saves the bookmarks to file */
static void
write_bookmarks_default(struct secure_save_info *ssi,
LIST_OF(struct bookmark) *bookmarks_list)
{
int folder_state = get_opt_bool("bookmarks.folder_state", NULL);
struct bookmark *bm;
struct write_bookmarks_default out;
foreach (bm, *bookmarks_list) {
secure_fprintf(ssi, "%s\t%s\t%d\t", bm->title, bm->url, bm->box_item->depth);
if (bm->box_item->type == BI_FOLDER) {
secure_fputc(ssi, 'F');
if (folder_state && bm->box_item->expanded)
secure_fputc(ssi, 'E');
}
secure_fputc(ssi, '\n');
if (ssi->err) break;
if (!list_empty(bm->child))
write_bookmarks_default(ssi, &bm->child);
}
out.ssi = ssi;
out.save_folder_state = get_opt_bool("bookmarks.folder_state", NULL);
out.codepage = get_cp_index("System");
out.conv_table = get_translation_table(get_cp_index("UTF-8"),
out.codepage);
write_bookmarks_default_inner(&out, bookmarks_list);
}
static unsigned char *

View File

@ -11,6 +11,7 @@
#endif /* HAVE_CONFIG_H */
#include <ctype.h>
#include <errno.h>
#include <expat.h>
#include <stdio.h>
#include <stdlib.h>
@ -38,6 +39,7 @@ struct attributes {
LIST_HEAD(struct attributes);
unsigned char *name;
unsigned char *value;
};
/* Prototypes */
@ -53,9 +55,14 @@ static unsigned char *get_attribute_value(struct tree_node *node,
unsigned char *name);
struct read_bookmarks_xbel {
int utf8_cp;
};
static void read_bookmarks_xbel(FILE *f);
static unsigned char * filename_bookmarks_xbel(int writing);
static int xbeltree_to_bookmarks_list(struct tree_node *root,
static int xbeltree_to_bookmarks_list(const struct read_bookmarks_xbel *preload,
struct tree_node *root,
struct bookmark *current_parent);
static void write_bookmarks_list(struct secure_save_info *ssi,
LIST_OF(struct bookmark) *bookmarks_list,
@ -89,6 +96,7 @@ read_bookmarks_xbel(FILE *f)
XML_Parser p;
int done = 0;
int err = 0;
struct read_bookmarks_xbel preload;
readok = 0;
@ -125,7 +133,12 @@ read_bookmarks_xbel(FILE *f)
}
}
if (!err) readok = xbeltree_to_bookmarks_list(root_node->children, NULL); /* Top node is xbel */
if (!err) {
preload.utf8_cp = get_cp_index("UTF-8");
readok = xbeltree_to_bookmarks_list(&preload,
root_node->children, /* Top node is xbel */
NULL);
}
XML_ParserFree(p);
free_xbeltree(root_node);
@ -140,7 +153,7 @@ write_bookmarks_xbel(struct secure_save_info *ssi,
/* We check for readok in filename_bookmarks_xbel(). */
secure_fputs(ssi,
"<?xml version=\"1.0\"?>\n"
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD XML "
"Bookmark Exchange Language 1.0//EN//XML\"\n"
" "
@ -168,42 +181,20 @@ indentation(struct secure_save_info *ssi, int num)
secure_fputs(ssi, " ");
}
/* FIXME This is totally broken, we should use the Unicode value in
* numeric entities.
* Additionally it is slow, not elegant, incomplete and
* if you pay enough attention you can smell the unmistakable
* odor of doom coming from it. --fabio */
static void
print_xml_entities(struct secure_save_info *ssi, const unsigned char *str)
{
#define accept_char(x) (isident((x)) || (x) == ' ' || (x) == '.' \
|| (x) == ':' || (x) == ';' \
|| (x) == '/' || (x) == '(' \
|| (x) == ')' || (x) == '}' \
|| (x) == '{' || (x) == '%' \
|| (x) == '+')
struct string entitized = NULL_STRING;
static int cp = -1;
if (cp == -1) cp = get_cp_index("us-ascii");
for (; *str; str++) {
if (accept_char(*str))
secure_fputc(ssi, *str);
else {
if (isascii(*str)) {
secure_fprintf(ssi, "&#%i;", (int) *str);
}
else {
const unsigned char *s = u2cp_no_nbsp(*str, cp);
if (s) print_xml_entities(ssi, s);
}
}
if (init_string(&entitized)
&& add_html_to_string(&entitized, str, strlen(str))) {
secure_fputs(ssi, entitized.source);
} else {
secsave_errno = SS_ERR_OUT_OF_MEM;
ssi->err = ENOMEM;
}
#undef accept_char
done_string(&entitized);
}
static void
@ -257,7 +248,6 @@ write_bookmarks_list(struct secure_save_info *ssi,
static void
on_element_open(void *data, const char *name, const char **attr)
{
struct attributes *attribute;
struct tree_node *node;
node = new_node(current_node);
@ -284,26 +274,23 @@ on_element_open(void *data, const char *name, const char **attr)
return;
}
while (*attr) {
unsigned char *tmp = stracpy((unsigned char *) *attr);
for (; *attr; attr += 2) {
struct attributes *attribute = mem_calloc(1, sizeof(*attribute));
unsigned char *name = stracpy((unsigned char *) attr[0]);
unsigned char *value = stracpy((unsigned char *) attr[1]);
if (!tmp) {
if (!attribute || !name || !value) {
mem_free_if(attribute);
mem_free_if(name);
mem_free_if(value);
free_node(current_node);
return;
}
attribute = mem_calloc(1, sizeof(*attribute));
if (!attribute) {
mem_free(tmp);
free_node(current_node);
return;
}
attribute->name = name;
attribute->value = value;
attribute->name = tmp;
add_to_list(current_node->attrs, attribute);
++attr;
add_to_list_end(current_node->attrs, attribute);
}
}
@ -315,25 +302,34 @@ on_element_close(void *data, const char *name)
}
static unsigned char *
delete_whites(unsigned char *s)
delete_whites(const unsigned char *s)
{
unsigned char *r;
int count = 0, c = 0, i;
int last_was_space = 0, c = 0, i;
int len = strlen(s);
r = mem_alloc(len + 1);
if (!r) return NULL;
for (i = 0; i < len; i++) {
if (isspace(s[i])) {
if (count == 1) continue;
else count = 1;
}
else count = 0;
if (s[i] == '\n' || s[i] == '\t')
/* Recognize only the whitespace characters listed
* in section 2.3 of XML 1.1. U+0085 and U+2028 need
* not be recognized here because section 2.11 says
* the XML processor must translate them to U+000A.
* Do not use isspace() because the string is in UTF-8
* and individual bytes might not be characters at
* all. */
switch (s[i]) {
case '\x20': case '\x09': case '\x0D': case '\x0A':
if (last_was_space) continue;
last_was_space = 1;
r[c++] = ' ';
else r[c++] = s[i];
break;
default:
last_was_space = 0;
r[c++] = s[i];
break;
}
}
r[c] = '\0';
@ -370,7 +366,8 @@ on_text(void *data, const XML_Char *text, int len)
/* xbel_tree_to_bookmarks_list: returns 0 on fail,
* 1 on success */
static int
xbeltree_to_bookmarks_list(struct tree_node *node,
xbeltree_to_bookmarks_list(const struct read_bookmarks_xbel *preload,
struct tree_node *node,
struct bookmark *current_parent)
{
struct bookmark *tmp;
@ -384,6 +381,7 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
title = get_child(node, "title");
href = get_attribute_value(node, "href");
intl_set_charset_by_index(preload->utf8_cp);
tmp = add_bookmark(current_parent, 0,
/* The <title> element is optional */
title && title->text ? title->text
@ -406,6 +404,7 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
title = get_child(node, "title");
intl_set_charset_by_index(preload->utf8_cp);
tmp = add_bookmark(current_parent, 0,
title && title->text ? title->text
: (unsigned char *) gettext("No title"),
@ -431,14 +430,18 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
if (node->children) {
int ret;
struct bookmark *parent_for_nested;
/* If this node is a <folder> element, current parent
* changes */
ret = (!strcmp(node->name, "folder") ?
xbeltree_to_bookmarks_list(node->children,
lastbm) :
xbeltree_to_bookmarks_list(node->children,
current_parent));
if (!strcmp(node->name, "folder"))
parent_for_nested = lastbm;
else
parent_for_nested = current_parent;
ret = xbeltree_to_bookmarks_list(preload,
node->children,
parent_for_nested);
/* Out of memory */
if (!ret) return 0;
}
@ -491,9 +494,9 @@ get_attribute_value(struct tree_node *node, unsigned char *name)
{
struct attributes *attribute;
foreachback (attribute, node->attrs) {
foreach (attribute, node->attrs) {
if (!strcmp(attribute->name, name)) {
return attribute->prev->name;
return attribute->value;
}
}
@ -519,8 +522,11 @@ free_node(struct tree_node *node)
{
struct attributes *attribute;
foreachback (attribute, node->attrs)
mem_free_if(attribute->name);
foreach (attribute, node->attrs) {
/* on_element_open() ensures ->name and ->value aren't NULL. */
mem_free(attribute->name);
mem_free(attribute->value);
}
free_list(node->attrs); /* Don't free list during traversal */
mem_free_if(node->name);

View File

@ -54,14 +54,13 @@ static struct option_info bookmark_options_info[] = {
"file_format", 0, 0, 1, 0,
N_("File format for bookmarks (affects both reading and saving):\n"
"0 is the default native ELinks format\n"
"1 is XBEL universal XML bookmarks format (ELinks bug 153: NO NATIONAL CHARS SUPPORT!)")),
"1 is XBEL universal XML bookmarks format")),
#else
INIT_OPT_INT("bookmarks", N_("File format"),
"file_format", 0, 0, 1, 0,
N_("File format for bookmarks (affects both reading and saving):\n"
"0 is the default native ELinks format\n"
"1 is XBEL universal XML bookmarks format (ELinks bug 153: NO NATIONAL CHARS SUPPORT!)"
" (DISABLED)")),
"1 is XBEL universal XML bookmarks format (DISABLED)")),
#endif
INIT_OPT_BOOL("bookmarks", N_("Save folder state"),
@ -268,10 +267,13 @@ delete_bookmark(struct bookmark *bm)
done_bookmark(bm);
}
/* Deletes any bookmarks with no URLs (i.e., folders) and of which
* the title matches the given argument. */
/** Deletes any bookmarks with no URLs (i.e., folders) and of which
* the title matches the given argument.
*
* @param foldername
* The title of the folder, in UTF-8. */
static void
delete_folder_by_name(unsigned char *foldername)
delete_folder_by_name(const unsigned char *foldername)
{
struct bookmark *bookmark, *next;
@ -284,6 +286,21 @@ delete_folder_by_name(unsigned char *foldername)
}
}
/** Allocate and initialize a bookmark in the given folder. This
* however does not set bookmark.box_item; use add_bookmark() for
* that.
*
* @param root
* The folder in which to add the bookmark, or NULL to add it at
* top level.
* @param title
* Title of the bookmark. Must be in UTF-8 and not NULL.
* "-" means add a separator.
* @param url
* URL to which the bookmark will point. Must be in UTF-8.
* NULL or "" means add a bookmark folder.
*
* @return the new bookmark, or NULL on error. */
static struct bookmark *
init_bookmark(struct bookmark *root, unsigned char *title, unsigned char *url)
{
@ -341,8 +358,23 @@ add_bookmark_item_to_bookmarks(struct bookmark *bm, struct bookmark *root, int p
add_hash_item(bookmark_cache, bm->url, strlen(bm->url), bm);
}
/* Adds a bookmark to the bookmark list. Place 0 means top, place 1 means
* bottom. NULL or "" @url means it is a bookmark folder. */
/** Add a bookmark to the bookmark list.
*
* @param root
* The folder in which to add the bookmark, or NULL to add it at
* top level.
* @param place
* 0 means add to the top. 1 means add to the bottom.
* @param title
* Title of the bookmark. Must be in UTF-8 and not NULL.
* "-" means add a separator.
* @param url
* URL to which the bookmark will point. Must be in UTF-8.
* NULL or "" means add a bookmark folder.
*
* @return the new bookmark, or NULL on error.
*
* @see add_bookmark_cp() */
struct bookmark *
add_bookmark(struct bookmark *root, int place, unsigned char *title,
unsigned char *url)
@ -379,27 +411,87 @@ add_bookmark(struct bookmark *root, int place, unsigned char *title,
return bm;
}
/** Add a bookmark to the bookmark list.
*
* @param root
* The folder in which to add the bookmark, or NULL to add it at
* top level.
* @param place
* 0 means add to the top. 1 means add to the bottom.
* @param codepage
* Codepage of @a title and @a url.
* @param title
* Title of the bookmark. Must not be NULL.
* "-" means add a separator.
* @param url
* URL to which the bookmark will point.
* NULL or "" means add a bookmark folder.
*
* @return the new bookmark.
*
* @see add_bookmark() */
struct bookmark *
add_bookmark_cp(struct bookmark *root, int place, int codepage,
unsigned char *title, unsigned char *url)
{
const int utf8_cp = get_cp_index("UTF-8");
struct conv_table *table;
unsigned char *utf8_title = NULL;
unsigned char *utf8_url = NULL;
struct bookmark *bookmark = NULL;
if (!url)
url = "";
table = get_translation_table(codepage, utf8_cp);
if (!table)
return NULL;
utf8_title = convert_string(table, title, strlen(title),
utf8_cp, CSM_NONE,
NULL, NULL, NULL);
utf8_url = convert_string(table, url, strlen(url),
utf8_cp, CSM_NONE,
NULL, NULL, NULL);
if (utf8_title && utf8_url)
bookmark = add_bookmark(root, place,
utf8_title, utf8_url);
mem_free_if(utf8_title);
mem_free_if(utf8_url);
return bookmark;
}
/* Updates an existing bookmark.
*
* If there's any problem, return 0. Otherwise, return 1.
*
* If any of the fields are NULL, the value is left unchanged. */
int
update_bookmark(struct bookmark *bm, unsigned char *title,
unsigned char *url)
update_bookmark(struct bookmark *bm, int codepage,
unsigned char *title, unsigned char *url)
{
static int update_bookmark_event_id = EVENT_NONE;
const int utf8_cp = get_cp_index("UTF-8");
struct conv_table *table;
unsigned char *title2 = NULL;
unsigned char *url2 = NULL;
table = get_translation_table(codepage, utf8_cp);
if (!table)
return 0;
if (url) {
url2 = stracpy(url);
url2 = convert_string(table, url, strlen(url),
utf8_cp, CSM_NONE,
NULL, NULL, NULL);
if (!url2) return 0;
sanitize_url(url2);
}
if (title) {
title2 = stracpy(title);
title2 = convert_string(table, title, strlen(title),
utf8_cp, CSM_NONE,
NULL, NULL, NULL);
if (!title2) {
mem_free_if(url2);
return 0;
@ -435,8 +527,16 @@ update_bookmark(struct bookmark *bm, unsigned char *title,
return 1;
}
/* Search for a bookmark with the given title. Search in the given folder
* or in the root if folder is NULL. */
/** Search for a bookmark with the given title. The search does not
* recurse into subfolders.
*
* @param folder
* Search in this folder. NULL means search in the root.
*
* @param title
* Search for this title. Must be in UTF-8 and not NULL.
*
* @return The bookmark, or NULL if not found. */
struct bookmark *
get_bookmark_by_name(struct bookmark *folder, unsigned char *title)
{
@ -457,6 +557,7 @@ get_bookmark(unsigned char *url)
{
struct hash_item *item;
/** @todo Bug 1066: URLs in bookmark_cache should be UTF-8 */
if (!check_bookmark_cache(url))
return NULL;
@ -472,6 +573,7 @@ bookmark_terminal(struct terminal *term, struct bookmark *folder)
{
unsigned char title[MAX_STR_LEN], url[MAX_STR_LEN];
struct window *tab;
int term_cp = get_terminal_codepage(term);
foreachback_tab (tab, term->windows) {
struct session *ses = tab->data;
@ -482,10 +584,18 @@ bookmark_terminal(struct terminal *term, struct bookmark *folder)
if (!get_current_title(ses, title, MAX_STR_LEN))
continue;
add_bookmark(folder, 1, title, url);
add_bookmark_cp(folder, 1, term_cp, title, url);
}
}
/** Create a bookmark for each document on the specified terminal,
* and a folder to contain those bookmarks.
*
* @param term
* The terminal whose open documents should be bookmarked.
*
* @param foldername
* The name of the new bookmark folder, in UTF-8. */
void
bookmark_terminal_tabs(struct terminal *term, unsigned char *foldername)
{
@ -520,6 +630,8 @@ bookmark_all_terminals(struct bookmark *folder)
++n;
/* Because subfoldername[] contains only digits,
* it is OK as UTF-8. */
subfolder = add_bookmark(folder, 1, subfoldername, NULL);
if (!subfolder) return;
@ -528,23 +640,48 @@ bookmark_all_terminals(struct bookmark *folder)
}
unsigned char *
get_auto_save_bookmark_foldername_utf8(void)
{
unsigned char *foldername;
int from_cp, to_cp;
struct conv_table *convert_table;
foldername = get_opt_str("ui.sessions.auto_save_foldername", NULL);
if (!*foldername) return NULL;
/* The charset of the string returned by get_opt_str()
* seems to be documented nowhere. Let's assume it is
* the system charset. */
from_cp = get_cp_index("System");
to_cp = get_cp_index("UTF-8");
convert_table = get_translation_table(from_cp, to_cp);
if (!convert_table) return NULL;
return convert_string(convert_table,
foldername, strlen(foldername),
to_cp, CSM_NONE,
NULL, NULL, NULL);
}
void
bookmark_auto_save_tabs(struct terminal *term)
{
unsigned char *foldername;
unsigned char *foldername; /* UTF-8 */
if (get_cmd_opt_bool("anonymous")
|| !get_opt_bool("ui.sessions.auto_save", NULL))
return;
foldername = get_opt_str("ui.sessions.auto_save_foldername", NULL);
if (!*foldername) return;
foldername = get_auto_save_bookmark_foldername_utf8();
if (!foldername) return;
/* Ensure uniqueness of the auto save folder, so it is possible to
* restore the (correct) session when starting up. */
delete_folder_by_name(foldername);
bookmark_terminal_tabs(term, foldername);
mem_free(foldername);
}
static void
@ -563,7 +700,10 @@ bookmark_snapshot(void)
NULL);
#endif
folder = add_bookmark(NULL, 1, folderstring.source, NULL);
/* folderstring must be in the system codepage because
* add_date_to_string() uses strftime(). */
folder = add_bookmark_cp(NULL, 1, get_cp_index("System"),
folderstring.source, NULL);
done_string(&folderstring);
if (!folder) return;
@ -574,6 +714,14 @@ bookmark_snapshot(void)
}
/** Open all bookmarks from the named folder.
*
* @param ses
* The session in which to open the first bookmark. The other
* bookmarks of the folder open in new tabs on the same terminal.
*
* @param foldername
* The name of the bookmark folder, in UTF-8. */
void
open_bookmark_folder(struct session *ses, unsigned char *foldername)
{
@ -603,6 +751,8 @@ open_bookmark_folder(struct session *ses, unsigned char *foldername)
|| !*bookmark->url)
continue;
/** @todo Bug 1066: Tell the URI layer that
* bookmark->url is UTF-8. */
uri = get_translated_uri(bookmark->url, NULL);
if (!uri) continue;

View File

@ -17,7 +17,9 @@ struct bookmark {
struct listbox_item *box_item;
unsigned char *title; /* title of bookmark */
/** @todo Bug 1066: The #url string should be in UTF-8 too,
* but this has not yet been fully implemented. */
unsigned char *title; /* UTF-8 title of bookmark */
unsigned char *url; /* Location of bookmarked item */
LIST_OF(struct bookmark) child;
@ -43,12 +45,16 @@ int bookmarks_are_dirty(void);
void delete_bookmark(struct bookmark *);
struct bookmark *add_bookmark(struct bookmark *, int, unsigned char *, unsigned char *);
struct bookmark *add_bookmark_cp(struct bookmark *, int, int,
unsigned char *, unsigned char *);
struct bookmark *get_bookmark_by_name(struct bookmark *folder,
unsigned char *title);
struct bookmark *get_bookmark(unsigned char *url);
void bookmark_terminal_tabs(struct terminal *term, unsigned char *foldername);
unsigned char *get_auto_save_bookmark_foldername_utf8(void);
void bookmark_auto_save_tabs(struct terminal *term);
int update_bookmark(struct bookmark *, unsigned char *, unsigned char *);
int update_bookmark(struct bookmark *, int,
unsigned char *, unsigned char *);
void open_bookmark_folder(struct session *ses, unsigned char *foldername);
#endif

View File

@ -56,21 +56,52 @@ static unsigned char *
get_bookmark_text(struct listbox_item *item, struct terminal *term)
{
struct bookmark *bookmark = item->udata;
int utf8_cp = get_cp_index("UTF-8");
int term_cp = get_terminal_codepage(term);
struct conv_table *convert_table;
return stracpy(bookmark->title);
convert_table = get_translation_table(utf8_cp, term_cp);
if (!convert_table) return NULL;
return convert_string(convert_table,
bookmark->title, strlen(bookmark->title),
term_cp, CSM_NONE, NULL, NULL, NULL);
}
/** A callback for convert_string(). This ignores errors and can
* result in truncated strings if out of memory. Accordingly, the
* resulting string may be displayed in the UI but should not be saved
* to a file or given to another program. */
static void
add_converted_bytes_to_string(void *data, unsigned char *buf, int buflen)
{
struct string *string = data;
add_bytes_to_string(string, buf, buflen); /* ignore errors */
}
static unsigned char *
get_bookmark_info(struct listbox_item *item, struct terminal *term)
{
struct bookmark *bookmark = item->udata;
int utf8_cp = get_cp_index("UTF-8");
int term_cp = get_terminal_codepage(term);
struct conv_table *convert_table;
struct string info;
if (item->type == BI_FOLDER) return NULL;
convert_table = get_translation_table(utf8_cp, term_cp);
if (!convert_table) return NULL;
if (!init_string(&info)) return NULL;
add_format_to_string(&info, "%s: %s", _("Title", term), bookmark->title);
add_format_to_string(&info, "\n%s: %s", _("URL", term), bookmark->url);
add_format_to_string(&info, "%s: ", _("Title", term));
convert_string(convert_table, bookmark->title, strlen(bookmark->title),
term_cp, CSM_NONE, NULL,
add_converted_bytes_to_string, &info);
add_format_to_string(&info, "\n%s: ", _("URL", term));
convert_string(convert_table, bookmark->url, strlen(bookmark->url),
term_cp, CSM_NONE, NULL,
add_converted_bytes_to_string, &info);
return info.source;
}
@ -80,6 +111,7 @@ get_bookmark_uri(struct listbox_item *item)
{
struct bookmark *bookmark = item->udata;
/** @todo Bug 1066: Tell the URI layer that bookmark->url is UTF-8. */
return bookmark->url && *bookmark->url
? get_translated_uri(bookmark->url, NULL) : NULL;
}
@ -199,9 +231,33 @@ move_bookmark_after_selected(struct bookmark *bookmark, struct bookmark *selecte
add_at_pos(selected->box_item, bookmark->box_item);
}
/** Add a bookmark; if called from the bookmark manager, also move
* the bookmark to the right place and select it in the manager.
* And possibly save the bookmarks.
*
* @param term
* The terminal whose user told ELinks to add the bookmark.
* Currently, @a term affects only the charset interpretation
* of @a title and @a url. In the future, this function could
* also display error messages in @a term.
*
* @param dlg_data
* The bookmark manager dialog, or NULL if the bookmark is being
* added without involving the bookmark manager. If @a dlg_data
* is not NULL, dlg_data->win->term should be @a term.
*
* @param title
* The title of the new bookmark, in the encoding of @a term.
* Must not be NULL. "-" means add a separator.
*
* @param url
* The URL of the new bookmark, in the encoding of @a term. NULL
* or "" means add a bookmark folder, unless @a title is "-". */
static void
do_add_bookmark(struct dialog_data *dlg_data, unsigned char *title, unsigned char *url)
do_add_bookmark(struct terminal *term, struct dialog_data *dlg_data,
unsigned char *title, unsigned char *url)
{
int term_cp = get_terminal_codepage(term);
struct bookmark *bm = NULL;
struct bookmark *selected = NULL;
struct listbox_data *box = NULL;
@ -220,7 +276,7 @@ do_add_bookmark(struct dialog_data *dlg_data, unsigned char *title, unsigned cha
}
}
bm = add_bookmark(bm, 1, title, url);
bm = add_bookmark_cp(bm, 1, term_cp, title, url);
if (!bm) return;
move_bookmark_after_selected(bm, selected);
@ -241,12 +297,29 @@ do_add_bookmark(struct dialog_data *dlg_data, unsigned char *title, unsigned cha
/**** ADD FOLDER *****************************************************/
/** Add a bookmark folder. This is called when the user pushes the OK
* button in the input dialog that asks for the folder name.
*
* @param dlg_data
* The bookmark manager. Must not be NULL.
*
* @param foldername
* The folder name that the user typed in the input dialog.
* This is in the charset of the terminal. */
static void
do_add_folder(struct dialog_data *dlg_data, unsigned char *foldername)
{
do_add_bookmark(dlg_data, foldername, NULL);
do_add_bookmark(dlg_data->win->term, dlg_data, foldername, NULL);
}
/** Prepare to add a bookmark folder. This is called when the user
* pushes the "Add folder" button in the bookmark manager.
*
* @param dlg_data
* The bookmark manager. Must not be NULL.
*
* @param widget_data
* The "Add folder" button. */
static widget_handler_status_T
push_add_folder_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
@ -262,10 +335,18 @@ push_add_folder_button(struct dialog_data *dlg_data, struct widget_data *widget_
/**** ADD SEPARATOR **************************************************/
/** Add a bookmark separator. This is called when the user pushes the
* "Add separator" button in the bookmark manager.
*
* @param dlg_data
* The bookmark manager. Must not be NULL.
*
* @param widget_data
* The "Add separator" button. */
static widget_handler_status_T
push_add_separator_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
{
do_add_bookmark(dlg_data, "-", "");
do_add_bookmark(dlg_data->win->term, dlg_data, "-", "");
redraw_dialog(dlg_data, 1);
return EVENT_PROCESSED;
}
@ -278,8 +359,11 @@ static void
bookmark_edit_done(void *data) {
struct dialog *dlg = data;
struct bookmark *bm = (struct bookmark *) dlg->udata2;
struct dialog_data *parent_dlg_data = dlg->udata;
int term_cp = get_terminal_codepage(parent_dlg_data->win->term);
update_bookmark(bm, dlg->widgets[0].data, dlg->widgets[1].data);
update_bookmark(bm, term_cp,
dlg->widgets[0].data, dlg->widgets[1].data);
object_unlock(bm);
#ifdef BOOKMARKS_RESAVE
@ -303,15 +387,37 @@ push_edit_button(struct dialog_data *dlg_data, struct widget_data *edit_btn)
/* Follow the bookmark */
if (box->sel) {
struct bookmark *bm = (struct bookmark *) box->sel->udata;
const unsigned char *title = bm->title;
const unsigned char *url = bm->url;
int utf8_cp = get_cp_index("UTF-8");
int term_cp = get_terminal_codepage(dlg_data->win->term);
struct conv_table *convert_table;
object_lock(bm);
do_edit_dialog(dlg_data->win->term, 1, N_("Edit bookmark"),
title, url,
(struct session *) dlg_data->dlg->udata, dlg_data,
bookmark_edit_done, bookmark_edit_cancel,
(void *) bm, EDIT_DLG_ADD);
convert_table = get_translation_table(utf8_cp, term_cp);
if (convert_table) {
unsigned char *title;
unsigned char *url;
title = convert_string(convert_table,
bm->title, strlen(bm->title),
term_cp, CSM_NONE,
NULL, NULL, NULL);
url = convert_string(convert_table,
bm->url, strlen(bm->url),
term_cp, CSM_NONE,
NULL, NULL, NULL);
if (title && url) {
object_lock(bm);
do_edit_dialog(dlg_data->win->term, 1,
N_("Edit bookmark"),
title, url,
(struct session *) dlg_data->dlg->udata,
dlg_data,
bookmark_edit_done,
bookmark_edit_cancel,
(void *) bm, EDIT_DLG_ADD);
}
mem_free_if(title);
mem_free_if(url);
}
}
return EVENT_PROCESSED;
@ -535,13 +641,15 @@ bookmark_manager(struct session *ses)
* rapid search of an already existing bookmark. --Zas */
struct bookmark_search_ctx {
unsigned char *url;
unsigned char *title;
unsigned char *url; /* UTF-8 */
unsigned char *title; /* system charset */
int found;
int offset;
int utf8_cp;
int system_cp;
};
#define NULL_BOOKMARK_SEARCH_CTX {NULL, NULL, 0, 0}
#define NULL_BOOKMARK_SEARCH_CTX {NULL, NULL, 0, 0, -1, -1}
static int
test_search(struct listbox_item *item, void *data_, int *offset)
@ -555,8 +663,37 @@ test_search(struct listbox_item *item, void *data_, int *offset)
assert(ctx->title && ctx->url);
ctx->found = (*ctx->title && strcasestr(bm->title, ctx->title))
|| (*ctx->url && c_strcasestr(bm->url, ctx->url));
ctx->found = (*ctx->url && c_strcasestr(bm->url, ctx->url));
if (!ctx->found && *ctx->title) {
/* The comparison of bookmark titles should
* be case-insensitive and locale-sensitive
* (Turkish dotless i). ELinks doesn't have
* such a function for UTF-8. The best we
* have is strcasestr, which uses the system
* charset. So convert bm->title to that.
* (ctx->title has already been converted.) */
struct conv_table *convert_table;
unsigned char *title = NULL;
convert_table = get_translation_table(ctx->utf8_cp,
ctx->system_cp);
if (convert_table) {
title = convert_string(convert_table,
bm->title,
strlen(bm->title),
ctx->system_cp,
CSM_NONE, NULL,
NULL, NULL);
}
if (title) {
ctx->found = strcasecmp(title,
ctx->title);
mem_free(title);
}
/** @todo Tell the user that the string could
* not be converted. */
}
if (ctx->found) *offset = 0;
}
@ -565,7 +702,9 @@ test_search(struct listbox_item *item, void *data_, int *offset)
return 0;
}
/* Last searched values */
/* Last searched values. Both are in UTF-8. (The title could be kept
* in the system charset, but that would be a bit risky, because
* setlocale calls from Lua scripts can change the system charset.) */
static unsigned char *bm_last_searched_title = NULL;
static unsigned char *bm_last_searched_url = NULL;
@ -577,14 +716,15 @@ free_last_searched_bookmark(void)
}
static int
memorize_last_searched_bookmark(struct bookmark_search_ctx *ctx)
memorize_last_searched_bookmark(const unsigned char *title,
const unsigned char *url)
{
/* Memorize last searched title */
mem_free_set(&bm_last_searched_title, stracpy(ctx->title));
mem_free_set(&bm_last_searched_title, stracpy(title));
if (!bm_last_searched_title) return 0;
/* Memorize last searched url */
mem_free_set(&bm_last_searched_url, stracpy(ctx->url));
mem_free_set(&bm_last_searched_url, stracpy(url));
if (!bm_last_searched_url) {
mem_free_set(&bm_last_searched_title, NULL);
return 0;
@ -601,38 +741,94 @@ bookmark_search_do(void *data)
struct bookmark_search_ctx ctx = NULL_BOOKMARK_SEARCH_CTX;
struct listbox_data *box;
struct dialog_data *dlg_data;
struct conv_table *convert_table;
int term_cp;
unsigned char *url_term;
unsigned char *title_term;
unsigned char *title_utf8 = NULL;
assertm(dlg->udata != NULL, "Bookmark search with NULL udata in dialog");
if_assert_failed return;
ctx.title = dlg->widgets[0].data;
ctx.url = dlg->widgets[1].data;
if (!ctx.title || !ctx.url)
return;
if (!memorize_last_searched_bookmark(&ctx))
return;
dlg_data = (struct dialog_data *) dlg->udata;
term_cp = get_terminal_codepage(dlg_data->win->term);
ctx.system_cp = get_cp_index("System");
ctx.utf8_cp = get_cp_index("UTF-8");
title_term = dlg->widgets[0].data; /* need not be freed */
url_term = dlg->widgets[1].data; /* likewise */
convert_table = get_translation_table(term_cp, ctx.system_cp);
if (!convert_table) goto free_all;
ctx.title = convert_string(convert_table,
title_term, strlen(title_term),
ctx.system_cp, CSM_NONE, NULL, NULL, NULL);
if (!ctx.title) goto free_all;
convert_table = get_translation_table(term_cp, ctx.utf8_cp);
if (!convert_table) goto free_all;
ctx.url = convert_string(convert_table,
url_term, strlen(url_term),
ctx.utf8_cp, CSM_NONE, NULL, NULL, NULL);
if (!ctx.url) goto free_all;
title_utf8 = convert_string(convert_table,
title_term, strlen(title_term),
ctx.utf8_cp, CSM_NONE, NULL, NULL, NULL);
if (!title_utf8) goto free_all;
if (!memorize_last_searched_bookmark(title_utf8, ctx.url))
goto free_all;
box = get_dlg_listbox_data(dlg_data);
traverse_listbox_items_list(box->sel, box, 0, 0, test_search, &ctx);
if (!ctx.found) return;
if (!ctx.found) goto free_all;
listbox_sel_move(dlg_data->widgets_data, ctx.offset - 1);
}
free_all:
mem_free_if(ctx.title);
mem_free_if(ctx.url);
mem_free_if(title_utf8);
}
static void
launch_bm_search_doc_dialog(struct terminal *term,
struct dialog_data *parent,
struct session *ses)
{
unsigned char *title = NULL;
unsigned char *url = NULL;
if (bm_last_searched_title && bm_last_searched_url) {
int utf8_cp, term_cp;
struct conv_table *convert_table;
utf8_cp = get_cp_index("UTF-8");
term_cp = get_terminal_codepage(term);
convert_table = get_translation_table(utf8_cp, term_cp);
if (convert_table) {
title = convert_string(convert_table, bm_last_searched_title,
strlen(bm_last_searched_title), term_cp,
CSM_NONE, NULL, NULL, NULL);
url = convert_string(convert_table, bm_last_searched_url,
strlen(bm_last_searched_url), term_cp,
CSM_NONE, NULL, NULL, NULL);
}
if (!title || !url) {
mem_free_set(&title, NULL);
mem_free_set(&url, NULL);
}
}
do_edit_dialog(term, 1, N_("Search bookmarks"),
bm_last_searched_title, bm_last_searched_url,
title, url,
ses, parent, bookmark_search_do, NULL, NULL,
EDIT_DLG_SEARCH);
mem_free_if(title);
mem_free_if(url);
}
@ -647,10 +843,31 @@ bookmark_add_add(void *data)
{
struct dialog *dlg = data;
struct dialog_data *dlg_data = (struct dialog_data *) dlg->udata;
struct terminal *term = dlg->udata2;
do_add_bookmark(dlg_data, dlg->widgets[0].data, dlg->widgets[1].data);
do_add_bookmark(term, dlg_data, dlg->widgets[0].data, dlg->widgets[1].data);
}
/** Open a dialog box for adding a bookmark.
*
* @param term
* The terminal in which the dialog box should appear.
*
* @param parent
* The bookmark manager, or NULL if the user requested this action
* from somewhere else.
*
* @param ses
* If @a title or @a url is NULL, get defaults from the current
* document of @a ses.
*
* @param title
* The initial title of the new bookmark, in the encoding of @a term.
* NULL means use @a ses.
*
* @param url
* The initial URL of the new bookmark, in the encoding of @a term.
* NULL means use @a ses. */
void
launch_bm_add_dialog(struct terminal *term,
struct dialog_data *parent,
@ -658,8 +875,22 @@ launch_bm_add_dialog(struct terminal *term,
unsigned char *title,
unsigned char *url)
{
/* When the user eventually pushes the OK button, BFU calls
* bookmark_add_add() and gives it the struct dialog * as the
* void * parameter. However, bookmark_add_add() also needs
* to know the struct terminal *, and there is no way to get
* that from struct dialog. The other bookmark dialogs work
* around that by making dialog.udata point to the struct
* dialog_data of the bookmark manager, but the "Add bookmark"
* dialog can be triggered with ACT_MAIN_ADD_BOOKMARK, which
* does not involve the bookmark manager at all.
*
* The solution here is to save the struct terminal * in