mirror of
https://github.com/rkd77/elinks.git
synced 2025-04-18 00:47:36 -04: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:
commit
d2854dca8d
@ -87,6 +87,8 @@ SEE_CFLAGS = @SEE_CFLAGS@
|
|||||||
SPARSE = @SPARSE@
|
SPARSE = @SPARSE@
|
||||||
SPIDERMONKEY_CFLAGS = @SPIDERMONKEY_CFLAGS@
|
SPIDERMONKEY_CFLAGS = @SPIDERMONKEY_CFLAGS@
|
||||||
SPIDERMONKEY_LIBS = @SPIDERMONKEY_LIBS@
|
SPIDERMONKEY_LIBS = @SPIDERMONKEY_LIBS@
|
||||||
|
TRE_CFLAGS = @TRE_CFLAGS@
|
||||||
|
TRE_LIBS = @TRE_LIBS@
|
||||||
VERSION = @VERSION@
|
VERSION = @VERSION@
|
||||||
XMLTO = @XMLTO@
|
XMLTO = @XMLTO@
|
||||||
X_CFLAGS = @X_CFLAGS@
|
X_CFLAGS = @X_CFLAGS@
|
||||||
|
10
NEWS
10
NEWS
@ -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
|
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.
|
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
|
* critical: Fix assertion failure if IMG/@usemap refers to a different
|
||||||
file.
|
file.
|
||||||
* Preserve newlines in hidden input fields, and submit them as CRLF.
|
* Preserve newlines in hidden input fields, and submit them as CRLF.
|
||||||
Previously, they could turn into spaces or disappear entirely.
|
Previously, they could turn into spaces or disappear entirely.
|
||||||
* Perl scripts can use modules that dynamically load C libraries, like
|
* Perl scripts can use modules that dynamically load C libraries, like
|
||||||
XML::LibXML::SAX does.
|
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
|
* bug 885: Convert xterm titles to ISO-8859-1 by default, but add an
|
||||||
option to disable this. When removing control characters from a
|
option to disable this. When removing control characters from a
|
||||||
title, note the charset. Don't truncate titles to the width of the
|
title, note the charset. Don't truncate titles to the width of the
|
||||||
terminal.
|
terminal.
|
||||||
|
* bug 1061: Correctly truncate UTF-8 titles in the tab bar.
|
||||||
* enhancement: Updated ISO 8859-7, ISO 8859-16, KOI8-R, and MacRoman.
|
* enhancement: Updated ISO 8859-7, ISO 8859-16, KOI8-R, and MacRoman.
|
||||||
|
|
||||||
ELinks 0.12pre2:
|
ELinks 0.12pre2:
|
||||||
|
48
configure.in
48
configure.in
@ -250,12 +250,6 @@ EL_CHECK_CODE([variadic macros], HAVE_VARIADIC_MACROS,
|
|||||||
#define a(b,c...) printf(b,##c)],
|
#define a(b,c...) printf(b,##c)],
|
||||||
[a("foo");a("%s","bar");a("%s%s","baz","quux");])
|
[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.
|
# Checks for library functions.
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
@ -909,6 +903,48 @@ else
|
|||||||
AC_SUBST(LUA_CFLAGS)
|
AC_SUBST(LUA_CFLAGS)
|
||||||
fi
|
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.
|
# Check for Ruby, optional even if installed.
|
||||||
|
@ -85,8 +85,8 @@ Triggered When:
|
|||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
struct bookmark *bookmark
|
struct bookmark *bookmark
|
||||||
unsigned char *new_title
|
unsigned char *new_title /* UTF-8 */
|
||||||
unsigned char *new_url
|
unsigned char *new_url /* UTF-8 */
|
||||||
|
|
||||||
Description:
|
Description:
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ OpenSSL, GNU TLS, or nss_compat_ossl \
|
|||||||
|For handling secure HTTP browsing.
|
|For handling secure HTTP browsing.
|
||||||
GPM |'General Purpose Mouse' for mouse support.
|
GPM |'General Purpose Mouse' for mouse support.
|
||||||
expat |'XML Parser Toolkit' needed for XBEL 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.
|
libsmbclient |Library needed for smb:// protocol support.
|
||||||
rxvt-unicode |For terminal emulator which supports 88 colors.
|
rxvt-unicode |For terminal emulator which supports 88 colors.
|
||||||
xterm with 256 colors |Program atleast patch level 179 or rxvt program \
|
xterm with 256 colors |Program atleast patch level 179 or rxvt program \
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -33,6 +34,7 @@ read_bookmarks_default(FILE *f)
|
|||||||
unsigned char in_buffer[INBUF_SIZE]; /* read buffer */
|
unsigned char in_buffer[INBUF_SIZE]; /* read buffer */
|
||||||
struct bookmark *last_bm = NULL;
|
struct bookmark *last_bm = NULL;
|
||||||
int last_depth = 0;
|
int last_depth = 0;
|
||||||
|
const int file_cp = get_cp_index("System");
|
||||||
|
|
||||||
/* TODO: Ignore lines with bad chars in title or url (?). -- Zas */
|
/* TODO: Ignore lines with bad chars in title or url (?). -- Zas */
|
||||||
while (fgets(in_buffer, INBUF_SIZE, f)) {
|
while (fgets(in_buffer, INBUF_SIZE, f)) {
|
||||||
@ -101,7 +103,8 @@ read_bookmarks_default(FILE *f)
|
|||||||
root = last_bm->root;
|
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;
|
last_depth = depth;
|
||||||
|
|
||||||
if (!*url && title[0] == '-' && title[1] == '\0') {
|
if (!*url && title[0] == '-' && title[1] == '\0') {
|
||||||
@ -125,27 +128,65 @@ read_bookmarks_default(FILE *f)
|
|||||||
#undef INBUF_SIZE
|
#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 */
|
/* Saves the bookmarks to file */
|
||||||
static void
|
static void
|
||||||
write_bookmarks_default(struct secure_save_info *ssi,
|
write_bookmarks_default(struct secure_save_info *ssi,
|
||||||
LIST_OF(struct bookmark) *bookmarks_list)
|
LIST_OF(struct bookmark) *bookmarks_list)
|
||||||
{
|
{
|
||||||
int folder_state = get_opt_bool("bookmarks.folder_state", NULL);
|
struct write_bookmarks_default out;
|
||||||
struct bookmark *bm;
|
|
||||||
|
|
||||||
foreach (bm, *bookmarks_list) {
|
out.ssi = ssi;
|
||||||
secure_fprintf(ssi, "%s\t%s\t%d\t", bm->title, bm->url, bm->box_item->depth);
|
out.save_folder_state = get_opt_bool("bookmarks.folder_state", NULL);
|
||||||
if (bm->box_item->type == BI_FOLDER) {
|
out.codepage = get_cp_index("System");
|
||||||
secure_fputc(ssi, 'F');
|
out.conv_table = get_translation_table(get_cp_index("UTF-8"),
|
||||||
if (folder_state && bm->box_item->expanded)
|
out.codepage);
|
||||||
secure_fputc(ssi, 'E');
|
write_bookmarks_default_inner(&out, bookmarks_list);
|
||||||
}
|
|
||||||
secure_fputc(ssi, '\n');
|
|
||||||
if (ssi->err) break;
|
|
||||||
|
|
||||||
if (!list_empty(bm->child))
|
|
||||||
write_bookmarks_default(ssi, &bm->child);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *
|
static unsigned char *
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <expat.h>
|
#include <expat.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -38,6 +39,7 @@ struct attributes {
|
|||||||
LIST_HEAD(struct attributes);
|
LIST_HEAD(struct attributes);
|
||||||
|
|
||||||
unsigned char *name;
|
unsigned char *name;
|
||||||
|
unsigned char *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
@ -53,9 +55,14 @@ static unsigned char *get_attribute_value(struct tree_node *node,
|
|||||||
unsigned char *name);
|
unsigned char *name);
|
||||||
|
|
||||||
|
|
||||||
|
struct read_bookmarks_xbel {
|
||||||
|
int utf8_cp;
|
||||||
|
};
|
||||||
|
|
||||||
static void read_bookmarks_xbel(FILE *f);
|
static void read_bookmarks_xbel(FILE *f);
|
||||||
static unsigned char * filename_bookmarks_xbel(int writing);
|
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);
|
struct bookmark *current_parent);
|
||||||
static void write_bookmarks_list(struct secure_save_info *ssi,
|
static void write_bookmarks_list(struct secure_save_info *ssi,
|
||||||
LIST_OF(struct bookmark) *bookmarks_list,
|
LIST_OF(struct bookmark) *bookmarks_list,
|
||||||
@ -89,6 +96,7 @@ read_bookmarks_xbel(FILE *f)
|
|||||||
XML_Parser p;
|
XML_Parser p;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
struct read_bookmarks_xbel preload;
|
||||||
|
|
||||||
readok = 0;
|
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);
|
XML_ParserFree(p);
|
||||||
free_xbeltree(root_node);
|
free_xbeltree(root_node);
|
||||||
@ -140,7 +153,7 @@ write_bookmarks_xbel(struct secure_save_info *ssi,
|
|||||||
/* We check for readok in filename_bookmarks_xbel(). */
|
/* We check for readok in filename_bookmarks_xbel(). */
|
||||||
|
|
||||||
secure_fputs(ssi,
|
secure_fputs(ssi,
|
||||||
"<?xml version=\"1.0\"?>\n"
|
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
||||||
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD XML "
|
"<!DOCTYPE xbel PUBLIC \"+//IDN python.org//DTD XML "
|
||||||
"Bookmark Exchange Language 1.0//EN//XML\"\n"
|
"Bookmark Exchange Language 1.0//EN//XML\"\n"
|
||||||
" "
|
" "
|
||||||
@ -168,42 +181,20 @@ indentation(struct secure_save_info *ssi, int num)
|
|||||||
secure_fputs(ssi, " ");
|
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
|
static void
|
||||||
print_xml_entities(struct secure_save_info *ssi, const unsigned char *str)
|
print_xml_entities(struct secure_save_info *ssi, const unsigned char *str)
|
||||||
{
|
{
|
||||||
#define accept_char(x) (isident((x)) || (x) == ' ' || (x) == '.' \
|
struct string entitized = NULL_STRING;
|
||||||
|| (x) == ':' || (x) == ';' \
|
|
||||||
|| (x) == '/' || (x) == '(' \
|
|
||||||
|| (x) == ')' || (x) == '}' \
|
|
||||||
|| (x) == '{' || (x) == '%' \
|
|
||||||
|| (x) == '+')
|
|
||||||
|
|
||||||
static int cp = -1;
|
if (init_string(&entitized)
|
||||||
|
&& add_html_to_string(&entitized, str, strlen(str))) {
|
||||||
if (cp == -1) cp = get_cp_index("us-ascii");
|
secure_fputs(ssi, entitized.source);
|
||||||
|
} else {
|
||||||
for (; *str; str++) {
|
secsave_errno = SS_ERR_OUT_OF_MEM;
|
||||||
if (accept_char(*str))
|
ssi->err = ENOMEM;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef accept_char
|
done_string(&entitized);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -257,7 +248,6 @@ write_bookmarks_list(struct secure_save_info *ssi,
|
|||||||
static void
|
static void
|
||||||
on_element_open(void *data, const char *name, const char **attr)
|
on_element_open(void *data, const char *name, const char **attr)
|
||||||
{
|
{
|
||||||
struct attributes *attribute;
|
|
||||||
struct tree_node *node;
|
struct tree_node *node;
|
||||||
|
|
||||||
node = new_node(current_node);
|
node = new_node(current_node);
|
||||||
@ -284,26 +274,23 @@ on_element_open(void *data, const char *name, const char **attr)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (*attr) {
|
for (; *attr; attr += 2) {
|
||||||
unsigned char *tmp = stracpy((unsigned char *) *attr);
|
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);
|
free_node(current_node);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
attribute = mem_calloc(1, sizeof(*attribute));
|
attribute->name = name;
|
||||||
if (!attribute) {
|
attribute->value = value;
|
||||||
mem_free(tmp);
|
|
||||||
free_node(current_node);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
attribute->name = tmp;
|
add_to_list_end(current_node->attrs, attribute);
|
||||||
|
|
||||||
add_to_list(current_node->attrs, attribute);
|
|
||||||
|
|
||||||
++attr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -315,25 +302,34 @@ on_element_close(void *data, const char *name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *
|
static unsigned char *
|
||||||
delete_whites(unsigned char *s)
|
delete_whites(const unsigned char *s)
|
||||||
{
|
{
|
||||||
unsigned char *r;
|
unsigned char *r;
|
||||||
int count = 0, c = 0, i;
|
int last_was_space = 0, c = 0, i;
|
||||||
int len = strlen(s);
|
int len = strlen(s);
|
||||||
|
|
||||||
r = mem_alloc(len + 1);
|
r = mem_alloc(len + 1);
|
||||||
if (!r) return NULL;
|
if (!r) return NULL;
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++) {
|
||||||
if (isspace(s[i])) {
|
/* Recognize only the whitespace characters listed
|
||||||
if (count == 1) continue;
|
* in section 2.3 of XML 1.1. U+0085 and U+2028 need
|
||||||
else count = 1;
|
* not be recognized here because section 2.11 says
|
||||||
}
|
* the XML processor must translate them to U+000A.
|
||||||
else count = 0;
|
* Do not use isspace() because the string is in UTF-8
|
||||||
|
* and individual bytes might not be characters at
|
||||||
if (s[i] == '\n' || s[i] == '\t')
|
* all. */
|
||||||
|
switch (s[i]) {
|
||||||
|
case '\x20': case '\x09': case '\x0D': case '\x0A':
|
||||||
|
if (last_was_space) continue;
|
||||||
|
last_was_space = 1;
|
||||||
r[c++] = ' ';
|
r[c++] = ' ';
|
||||||
else r[c++] = s[i];
|
break;
|
||||||
|
default:
|
||||||
|
last_was_space = 0;
|
||||||
|
r[c++] = s[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r[c] = '\0';
|
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,
|
/* xbel_tree_to_bookmarks_list: returns 0 on fail,
|
||||||
* 1 on success */
|
* 1 on success */
|
||||||
static int
|
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 *current_parent)
|
||||||
{
|
{
|
||||||
struct bookmark *tmp;
|
struct bookmark *tmp;
|
||||||
@ -384,6 +381,7 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
|
|||||||
title = get_child(node, "title");
|
title = get_child(node, "title");
|
||||||
href = get_attribute_value(node, "href");
|
href = get_attribute_value(node, "href");
|
||||||
|
|
||||||
|
intl_set_charset_by_index(preload->utf8_cp);
|
||||||
tmp = add_bookmark(current_parent, 0,
|
tmp = add_bookmark(current_parent, 0,
|
||||||
/* The <title> element is optional */
|
/* The <title> element is optional */
|
||||||
title && title->text ? title->text
|
title && title->text ? title->text
|
||||||
@ -406,6 +404,7 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
|
|||||||
|
|
||||||
title = get_child(node, "title");
|
title = get_child(node, "title");
|
||||||
|
|
||||||
|
intl_set_charset_by_index(preload->utf8_cp);
|
||||||
tmp = add_bookmark(current_parent, 0,
|
tmp = add_bookmark(current_parent, 0,
|
||||||
title && title->text ? title->text
|
title && title->text ? title->text
|
||||||
: (unsigned char *) gettext("No title"),
|
: (unsigned char *) gettext("No title"),
|
||||||
@ -431,14 +430,18 @@ xbeltree_to_bookmarks_list(struct tree_node *node,
|
|||||||
|
|
||||||
if (node->children) {
|
if (node->children) {
|
||||||
int ret;
|
int ret;
|
||||||
|
struct bookmark *parent_for_nested;
|
||||||
|
|
||||||
/* If this node is a <folder> element, current parent
|
/* If this node is a <folder> element, current parent
|
||||||
* changes */
|
* changes */
|
||||||
ret = (!strcmp(node->name, "folder") ?
|
if (!strcmp(node->name, "folder"))
|
||||||
xbeltree_to_bookmarks_list(node->children,
|
parent_for_nested = lastbm;
|
||||||
lastbm) :
|
else
|
||||||
xbeltree_to_bookmarks_list(node->children,
|
parent_for_nested = current_parent;
|
||||||
current_parent));
|
|
||||||
|
ret = xbeltree_to_bookmarks_list(preload,
|
||||||
|
node->children,
|
||||||
|
parent_for_nested);
|
||||||
/* Out of memory */
|
/* Out of memory */
|
||||||
if (!ret) return 0;
|
if (!ret) return 0;
|
||||||
}
|
}
|
||||||
@ -491,9 +494,9 @@ get_attribute_value(struct tree_node *node, unsigned char *name)
|
|||||||
{
|
{
|
||||||
struct attributes *attribute;
|
struct attributes *attribute;
|
||||||
|
|
||||||
foreachback (attribute, node->attrs) {
|
foreach (attribute, node->attrs) {
|
||||||
if (!strcmp(attribute->name, name)) {
|
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;
|
struct attributes *attribute;
|
||||||
|
|
||||||
foreachback (attribute, node->attrs)
|
foreach (attribute, node->attrs) {
|
||||||
mem_free_if(attribute->name);
|
/* 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 */
|
free_list(node->attrs); /* Don't free list during traversal */
|
||||||
|
|
||||||
mem_free_if(node->name);
|
mem_free_if(node->name);
|
||||||
|
@ -54,14 +54,13 @@ static struct option_info bookmark_options_info[] = {
|
|||||||
"file_format", 0, 0, 1, 0,
|
"file_format", 0, 0, 1, 0,
|
||||||
N_("File format for bookmarks (affects both reading and saving):\n"
|
N_("File format for bookmarks (affects both reading and saving):\n"
|
||||||
"0 is the default native ELinks format\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
|
#else
|
||||||
INIT_OPT_INT("bookmarks", N_("File format"),
|
INIT_OPT_INT("bookmarks", N_("File format"),
|
||||||
"file_format", 0, 0, 1, 0,
|
"file_format", 0, 0, 1, 0,
|
||||||
N_("File format for bookmarks (affects both reading and saving):\n"
|
N_("File format for bookmarks (affects both reading and saving):\n"
|
||||||
"0 is the default native ELinks format\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 (DISABLED)")),
|
||||||
" (DISABLED)")),
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
INIT_OPT_BOOL("bookmarks", N_("Save folder state"),
|
INIT_OPT_BOOL("bookmarks", N_("Save folder state"),
|
||||||
@ -268,10 +267,13 @@ delete_bookmark(struct bookmark *bm)
|
|||||||
done_bookmark(bm);
|
done_bookmark(bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Deletes any bookmarks with no URLs (i.e., folders) and of which
|
/** Deletes any bookmarks with no URLs (i.e., folders) and of which
|
||||||
* the title matches the given argument. */
|
* the title matches the given argument.
|
||||||
|
*
|
||||||
|
* @param foldername
|
||||||
|
* The title of the folder, in UTF-8. */
|
||||||
static void
|
static void
|
||||||
delete_folder_by_name(unsigned char *foldername)
|
delete_folder_by_name(const unsigned char *foldername)
|
||||||
{
|
{
|
||||||
struct bookmark *bookmark, *next;
|
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 *
|
static struct bookmark *
|
||||||
init_bookmark(struct bookmark *root, unsigned char *title, unsigned char *url)
|
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);
|
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
|
/** Add a bookmark to the bookmark list.
|
||||||
* bottom. NULL or "" @url means it is a bookmark folder. */
|
*
|
||||||
|
* @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 *
|
struct bookmark *
|
||||||
add_bookmark(struct bookmark *root, int place, unsigned char *title,
|
add_bookmark(struct bookmark *root, int place, unsigned char *title,
|
||||||
unsigned char *url)
|
unsigned char *url)
|
||||||
@ -379,27 +411,87 @@ add_bookmark(struct bookmark *root, int place, unsigned char *title,
|
|||||||
return bm;
|
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.
|
/* Updates an existing bookmark.
|
||||||
*
|
*
|
||||||
* If there's any problem, return 0. Otherwise, return 1.
|
* If there's any problem, return 0. Otherwise, return 1.
|
||||||
*
|
*
|
||||||
* If any of the fields are NULL, the value is left unchanged. */
|
* If any of the fields are NULL, the value is left unchanged. */
|
||||||
int
|
int
|
||||||
update_bookmark(struct bookmark *bm, unsigned char *title,
|
update_bookmark(struct bookmark *bm, int codepage,
|
||||||
unsigned char *url)
|
unsigned char *title, unsigned char *url)
|
||||||
{
|
{
|
||||||
static int update_bookmark_event_id = EVENT_NONE;
|
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 *title2 = NULL;
|
||||||
unsigned char *url2 = NULL;
|
unsigned char *url2 = NULL;
|
||||||
|
|
||||||
|
table = get_translation_table(codepage, utf8_cp);
|
||||||
|
if (!table)
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
url2 = stracpy(url);
|
url2 = convert_string(table, url, strlen(url),
|
||||||
|
utf8_cp, CSM_NONE,
|
||||||
|
NULL, NULL, NULL);
|
||||||
if (!url2) return 0;
|
if (!url2) return 0;
|
||||||
sanitize_url(url2);
|
sanitize_url(url2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (title) {
|
if (title) {
|
||||||
title2 = stracpy(title);
|
title2 = convert_string(table, title, strlen(title),
|
||||||
|
utf8_cp, CSM_NONE,
|
||||||
|
NULL, NULL, NULL);
|
||||||
if (!title2) {
|
if (!title2) {
|
||||||
mem_free_if(url2);
|
mem_free_if(url2);
|
||||||
return 0;
|
return 0;
|
||||||
@ -435,8 +527,16 @@ update_bookmark(struct bookmark *bm, unsigned char *title,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for a bookmark with the given title. Search in the given folder
|
/** Search for a bookmark with the given title. The search does not
|
||||||
* or in the root if folder is NULL. */
|
* 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 *
|
struct bookmark *
|
||||||
get_bookmark_by_name(struct bookmark *folder, unsigned char *title)
|
get_bookmark_by_name(struct bookmark *folder, unsigned char *title)
|
||||||
{
|
{
|
||||||
@ -457,6 +557,7 @@ get_bookmark(unsigned char *url)
|
|||||||
{
|
{
|
||||||
struct hash_item *item;
|
struct hash_item *item;
|
||||||
|
|
||||||
|
/** @todo Bug 1066: URLs in bookmark_cache should be UTF-8 */
|
||||||
if (!check_bookmark_cache(url))
|
if (!check_bookmark_cache(url))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -472,6 +573,7 @@ bookmark_terminal(struct terminal *term, struct bookmark *folder)
|
|||||||
{
|
{
|
||||||
unsigned char title[MAX_STR_LEN], url[MAX_STR_LEN];
|
unsigned char title[MAX_STR_LEN], url[MAX_STR_LEN];
|
||||||
struct window *tab;
|
struct window *tab;
|
||||||
|
int term_cp = get_terminal_codepage(term);
|
||||||
|
|
||||||
foreachback_tab (tab, term->windows) {
|
foreachback_tab (tab, term->windows) {
|
||||||
struct session *ses = tab->data;
|
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))
|
if (!get_current_title(ses, title, MAX_STR_LEN))
|
||||||
continue;
|
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
|
void
|
||||||
bookmark_terminal_tabs(struct terminal *term, unsigned char *foldername)
|
bookmark_terminal_tabs(struct terminal *term, unsigned char *foldername)
|
||||||
{
|
{
|
||||||
@ -520,6 +630,8 @@ bookmark_all_terminals(struct bookmark *folder)
|
|||||||
|
|
||||||
++n;
|
++n;
|
||||||
|
|
||||||
|
/* Because subfoldername[] contains only digits,
|
||||||
|
* it is OK as UTF-8. */
|
||||||
subfolder = add_bookmark(folder, 1, subfoldername, NULL);
|
subfolder = add_bookmark(folder, 1, subfoldername, NULL);
|
||||||
if (!subfolder) return;
|
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
|
void
|
||||||
bookmark_auto_save_tabs(struct terminal *term)
|
bookmark_auto_save_tabs(struct terminal *term)
|
||||||
{
|
{
|
||||||
unsigned char *foldername;
|
unsigned char *foldername; /* UTF-8 */
|
||||||
|
|
||||||
if (get_cmd_opt_bool("anonymous")
|
if (get_cmd_opt_bool("anonymous")
|
||||||
|| !get_opt_bool("ui.sessions.auto_save", NULL))
|
|| !get_opt_bool("ui.sessions.auto_save", NULL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
foldername = get_opt_str("ui.sessions.auto_save_foldername", NULL);
|
foldername = get_auto_save_bookmark_foldername_utf8();
|
||||||
if (!*foldername) return;
|
if (!foldername) return;
|
||||||
|
|
||||||
/* Ensure uniqueness of the auto save folder, so it is possible to
|
/* Ensure uniqueness of the auto save folder, so it is possible to
|
||||||
* restore the (correct) session when starting up. */
|
* restore the (correct) session when starting up. */
|
||||||
delete_folder_by_name(foldername);
|
delete_folder_by_name(foldername);
|
||||||
|
|
||||||
bookmark_terminal_tabs(term, foldername);
|
bookmark_terminal_tabs(term, foldername);
|
||||||
|
mem_free(foldername);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -563,7 +700,10 @@ bookmark_snapshot(void)
|
|||||||
NULL);
|
NULL);
|
||||||
#endif
|
#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);
|
done_string(&folderstring);
|
||||||
if (!folder) return;
|
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
|
void
|
||||||
open_bookmark_folder(struct session *ses, unsigned char *foldername)
|
open_bookmark_folder(struct session *ses, unsigned char *foldername)
|
||||||
{
|
{
|
||||||
@ -603,6 +751,8 @@ open_bookmark_folder(struct session *ses, unsigned char *foldername)
|
|||||||
|| !*bookmark->url)
|
|| !*bookmark->url)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/** @todo Bug 1066: Tell the URI layer that
|
||||||
|
* bookmark->url is UTF-8. */
|
||||||
uri = get_translated_uri(bookmark->url, NULL);
|
uri = get_translated_uri(bookmark->url, NULL);
|
||||||
if (!uri) continue;
|
if (!uri) continue;
|
||||||
|
|
||||||
|
@ -17,7 +17,9 @@ struct bookmark {
|
|||||||
|
|
||||||
struct listbox_item *box_item;
|
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 */
|
unsigned char *url; /* Location of bookmarked item */
|
||||||
|
|
||||||
LIST_OF(struct bookmark) child;
|
LIST_OF(struct bookmark) child;
|
||||||
@ -43,12 +45,16 @@ int bookmarks_are_dirty(void);
|
|||||||
|
|
||||||
void delete_bookmark(struct bookmark *);
|
void delete_bookmark(struct bookmark *);
|
||||||
struct bookmark *add_bookmark(struct bookmark *, int, unsigned char *, unsigned char *);
|
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,
|
struct bookmark *get_bookmark_by_name(struct bookmark *folder,
|
||||||
unsigned char *title);
|
unsigned char *title);
|
||||||
struct bookmark *get_bookmark(unsigned char *url);
|
struct bookmark *get_bookmark(unsigned char *url);
|
||||||
void bookmark_terminal_tabs(struct terminal *term, unsigned char *foldername);
|
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);
|
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);
|
void open_bookmark_folder(struct session *ses, unsigned char *foldername);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -56,21 +56,52 @@ static unsigned char *
|
|||||||
get_bookmark_text(struct listbox_item *item, struct terminal *term)
|
get_bookmark_text(struct listbox_item *item, struct terminal *term)
|
||||||
{
|
{
|
||||||
struct bookmark *bookmark = item->udata;
|
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 *
|
static unsigned char *
|
||||||
get_bookmark_info(struct listbox_item *item, struct terminal *term)
|
get_bookmark_info(struct listbox_item *item, struct terminal *term)
|
||||||
{
|
{
|
||||||
struct bookmark *bookmark = item->udata;
|
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;
|
struct string info;
|
||||||
|
|
||||||
if (item->type == BI_FOLDER) return NULL;
|
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;
|
if (!init_string(&info)) return NULL;
|
||||||
|
|
||||||
add_format_to_string(&info, "%s: %s", _("Title", term), bookmark->title);
|
add_format_to_string(&info, "%s: ", _("Title", term));
|
||||||
add_format_to_string(&info, "\n%s: %s", _("URL", term), bookmark->url);
|
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;
|
return info.source;
|
||||||
}
|
}
|
||||||
@ -80,6 +111,7 @@ get_bookmark_uri(struct listbox_item *item)
|
|||||||
{
|
{
|
||||||
struct bookmark *bookmark = item->udata;
|
struct bookmark *bookmark = item->udata;
|
||||||
|
|
||||||
|
/** @todo Bug 1066: Tell the URI layer that bookmark->url is UTF-8. */
|
||||||
return bookmark->url && *bookmark->url
|
return bookmark->url && *bookmark->url
|
||||||
? get_translated_uri(bookmark->url, NULL) : NULL;
|
? 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_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
|
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 *bm = NULL;
|
||||||
struct bookmark *selected = NULL;
|
struct bookmark *selected = NULL;
|
||||||
struct listbox_data *box = 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;
|
if (!bm) return;
|
||||||
|
|
||||||
move_bookmark_after_selected(bm, selected);
|
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 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
|
static void
|
||||||
do_add_folder(struct dialog_data *dlg_data, unsigned char *foldername)
|
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
|
static widget_handler_status_T
|
||||||
push_add_folder_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
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 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
|
static widget_handler_status_T
|
||||||
push_add_separator_button(struct dialog_data *dlg_data, struct widget_data *widget_data)
|
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);
|
redraw_dialog(dlg_data, 1);
|
||||||
return EVENT_PROCESSED;
|
return EVENT_PROCESSED;
|
||||||
}
|
}
|
||||||
@ -278,8 +359,11 @@ static void
|
|||||||
bookmark_edit_done(void *data) {
|
bookmark_edit_done(void *data) {
|
||||||
struct dialog *dlg = data;
|
struct dialog *dlg = data;
|
||||||
struct bookmark *bm = (struct bookmark *) dlg->udata2;
|
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);
|
object_unlock(bm);
|
||||||
|
|
||||||
#ifdef BOOKMARKS_RESAVE
|
#ifdef BOOKMARKS_RESAVE
|
||||||
@ -303,15 +387,37 @@ push_edit_button(struct dialog_data *dlg_data, struct widget_data *edit_btn)
|
|||||||
/* Follow the bookmark */
|
/* Follow the bookmark */
|
||||||
if (box->sel) {
|
if (box->sel) {
|
||||||
struct bookmark *bm = (struct bookmark *) box->sel->udata;
|
struct bookmark *bm = (struct bookmark *) box->sel->udata;
|
||||||
const unsigned char *title = bm->title;
|
int utf8_cp = get_cp_index("UTF-8");
|
||||||
const unsigned char *url = bm->url;
|
int term_cp = get_terminal_codepage(dlg_data->win->term);
|
||||||
|
struct conv_table *convert_table;
|
||||||
|
|
||||||
object_lock(bm);
|
convert_table = get_translation_table(utf8_cp, term_cp);
|
||||||
do_edit_dialog(dlg_data->win->term, 1, N_("Edit bookmark"),
|
if (convert_table) {
|
||||||
title, url,
|
unsigned char *title;
|
||||||
(struct session *) dlg_data->dlg->udata, dlg_data,
|
unsigned char *url;
|
||||||
bookmark_edit_done, bookmark_edit_cancel,
|
|
||||||
(void *) bm, EDIT_DLG_ADD);
|
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;
|
return EVENT_PROCESSED;
|
||||||
@ -535,13 +641,15 @@ bookmark_manager(struct session *ses)
|
|||||||
* rapid search of an already existing bookmark. --Zas */
|
* rapid search of an already existing bookmark. --Zas */
|
||||||
|
|
||||||
struct bookmark_search_ctx {
|
struct bookmark_search_ctx {
|
||||||
unsigned char *url;
|
unsigned char *url; /* UTF-8 */
|
||||||
unsigned char *title;
|
unsigned char *title; /* system charset */
|
||||||
int found;
|
int found;
|
||||||
int offset;
|
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
|
static int
|
||||||
test_search(struct listbox_item *item, void *data_, int *offset)
|
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);
|
assert(ctx->title && ctx->url);
|
||||||
|
|
||||||
ctx->found = (*ctx->title && strcasestr(bm->title, ctx->title))
|
ctx->found = (*ctx->url && c_strcasestr(bm->url, ctx->url));
|
||||||
|| (*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;
|
if (ctx->found) *offset = 0;
|
||||||
}
|
}
|
||||||
@ -565,7 +702,9 @@ test_search(struct listbox_item *item, void *data_, int *offset)
|
|||||||
return 0;
|
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_title = NULL;
|
||||||
static unsigned char *bm_last_searched_url = NULL;
|
static unsigned char *bm_last_searched_url = NULL;
|
||||||
|
|
||||||
@ -577,14 +716,15 @@ free_last_searched_bookmark(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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 */
|
/* 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;
|
if (!bm_last_searched_title) return 0;
|
||||||
|
|
||||||
/* Memorize last searched url */
|
/* 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) {
|
if (!bm_last_searched_url) {
|
||||||
mem_free_set(&bm_last_searched_title, NULL);
|
mem_free_set(&bm_last_searched_title, NULL);
|
||||||
return 0;
|
return 0;
|
||||||
@ -601,38 +741,94 @@ bookmark_search_do(void *data)
|
|||||||
struct bookmark_search_ctx ctx = NULL_BOOKMARK_SEARCH_CTX;
|
struct bookmark_search_ctx ctx = NULL_BOOKMARK_SEARCH_CTX;
|
||||||
struct listbox_data *box;
|
struct listbox_data *box;
|
||||||
struct dialog_data *dlg_data;
|
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");
|
assertm(dlg->udata != NULL, "Bookmark search with NULL udata in dialog");
|
||||||
if_assert_failed return;
|
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;
|
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);
|
box = get_dlg_listbox_data(dlg_data);
|
||||||
|
|
||||||
traverse_listbox_items_list(box->sel, box, 0, 0, test_search, &ctx);
|
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);
|
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
|
static void
|
||||||
launch_bm_search_doc_dialog(struct terminal *term,
|
launch_bm_search_doc_dialog(struct terminal *term,
|
||||||
struct dialog_data *parent,
|
struct dialog_data *parent,
|
||||||
struct session *ses)
|
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"),
|
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,
|
ses, parent, bookmark_search_do, NULL, NULL,
|
||||||
EDIT_DLG_SEARCH);
|
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 *dlg = data;
|
||||||
struct dialog_data *dlg_data = (struct dialog_data *) dlg->udata;
|
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
|
void
|
||||||
launch_bm_add_dialog(struct terminal *term,
|
launch_bm_add_dialog(struct terminal *term,
|
||||||
struct dialog_data *parent,
|
struct dialog_data *parent,
|
||||||
@ -658,8 +875,22 @@ launch_bm_add_dialog(struct terminal *term,
|
|||||||
unsigned char *title,
|
unsigned char *title,
|
||||||
unsigned char *url)
|
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
|
||||||
|
* dialog.udata2, which the "Edit bookmark" dialog uses for
|
||||||
|
* struct bookmark *. When adding a new bookmark, we don't
|
||||||
|
* need a pointer to an existing one, of course. */
|
||||||
do_edit_dialog(term, 1, N_("Add bookmark"), title, url, ses,
|
do_edit_dialog(term, 1, N_("Add bookmark"), title, url, ses,
|
||||||
parent, bookmark_add_add, NULL, NULL, EDIT_DLG_ADD);
|
parent, bookmark_add_add, NULL, term, EDIT_DLG_ADD);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -687,6 +918,28 @@ launch_bm_add_link_dialog(struct terminal *term,
|
|||||||
Bookmark tabs dialog.
|
Bookmark tabs dialog.
|
||||||
\****************************************************************************/
|
\****************************************************************************/
|
||||||
|
|
||||||
|
static void
|
||||||
|
bookmark_terminal_tabs_ok(void *term_void, unsigned char *foldername)
|
||||||
|
{
|
||||||
|
struct terminal *const term = term_void;
|
||||||
|
int from_cp = get_terminal_codepage(term);
|
||||||
|
int to_cp = get_cp_index("UTF-8");
|
||||||
|
struct conv_table *convert_table;
|
||||||
|
unsigned char *converted;
|
||||||
|
|
||||||
|
convert_table = get_translation_table(from_cp, to_cp);
|
||||||
|
if (convert_table == NULL) return; /** @todo Report the error */
|
||||||
|
|
||||||
|
converted = convert_string(convert_table,
|
||||||
|
foldername, strlen(foldername),
|
||||||
|
to_cp, CSM_NONE,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
if (converted == NULL) return; /** @todo Report the error */
|
||||||
|
|
||||||
|
bookmark_terminal_tabs(term_void, converted);
|
||||||
|
mem_free(converted);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
bookmark_terminal_tabs_dialog(struct terminal *term)
|
bookmark_terminal_tabs_dialog(struct terminal *term)
|
||||||
{
|
{
|
||||||
@ -705,8 +958,7 @@ bookmark_terminal_tabs_dialog(struct terminal *term)
|
|||||||
N_("Bookmark tabs"), N_("Enter folder name"),
|
N_("Bookmark tabs"), N_("Enter folder name"),
|
||||||
term, NULL,
|
term, NULL,
|
||||||
MAX_STR_LEN, string.source, 0, 0, NULL,
|
MAX_STR_LEN, string.source, 0, 0, NULL,
|
||||||
(void (*)(void *, unsigned char *)) bookmark_terminal_tabs,
|
bookmark_terminal_tabs_ok, NULL);
|
||||||
NULL);
|
|
||||||
|
|
||||||
done_string(&string);
|
done_string(&string);
|
||||||
}
|
}
|
||||||
|
@ -389,7 +389,7 @@ static struct option_info config_options_info[] = {
|
|||||||
N_("Whether the search should match the document text while maintaining\n"
|
N_("Whether the search should match the document text while maintaining\n"
|
||||||
"case sensitivity.")),
|
"case sensitivity.")),
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
INIT_OPT_INT("document.browse.search", N_("Regular expressions"),
|
INIT_OPT_INT("document.browse.search", N_("Regular expressions"),
|
||||||
"regex", 0, 0, 2, 0,
|
"regex", 0, 0, 2, 0,
|
||||||
N_("Enable searching with regular expressions:\n"
|
N_("Enable searching with regular expressions:\n"
|
||||||
|
@ -363,7 +363,16 @@ display_tab_bar(struct session *ses, struct terminal *term, int tabs_count)
|
|||||||
box.x, box.y, actual_tab_width,
|
box.x, box.y, actual_tab_width,
|
||||||
msg, NULL);
|
msg, NULL);
|
||||||
} else {
|
} else {
|
||||||
int msglen = int_min(strlen(msg), actual_tab_width);
|
int msglen;
|
||||||
|
#ifdef CONFIG_UTF8
|
||||||
|
if (term->utf8_cp) {
|
||||||
|
msglen = utf8_step_forward(msg, NULL,
|
||||||
|
actual_tab_width,
|
||||||
|
UTF8_STEP_CELLS_FEWER,
|
||||||
|
NULL) - msg;
|
||||||
|
} else
|
||||||
|
#endif /* CONFIG_UTF8 */
|
||||||
|
msglen = int_min(strlen(msg), actual_tab_width);
|
||||||
|
|
||||||
draw_text(term, box.x, box.y, msg, msglen, 0, color);
|
draw_text(term, box.x, box.y, msg, msglen, 0, color);
|
||||||
}
|
}
|
||||||
|
@ -178,6 +178,9 @@ struct document {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct uri *uri;
|
struct uri *uri;
|
||||||
|
|
||||||
|
/** The title of the document. The charset of this string is
|
||||||
|
* document.options.cp. */
|
||||||
unsigned char *title;
|
unsigned char *title;
|
||||||
struct cache_entry *cached;
|
struct cache_entry *cached;
|
||||||
|
|
||||||
|
24
src/elinks.h
24
src/elinks.h
@ -29,6 +29,30 @@
|
|||||||
#define DEBUG_MEMLEAK
|
#define DEBUG_MEMLEAK
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* When CONFIG_UTF8 is defined, src/viewer/text/search.c makes a string
|
||||||
|
* of unicode_val_T and gives it to regwexec(), which expects a string
|
||||||
|
* of wchar_t. If the unicode_val_T and wchar_t types are too different,
|
||||||
|
* this won't work, so try to detect that and disable regexp operations
|
||||||
|
* entirely in that case.
|
||||||
|
*
|
||||||
|
* Currently, this code only compares the sizes of the types. Because
|
||||||
|
* unicode_val_T is defined as uint32_t and POSIX says bytes are 8-bit,
|
||||||
|
* sizeof(unicode_val_T) is 4 and the following compares SIZEOF_WCHAR_T
|
||||||
|
* to that.
|
||||||
|
*
|
||||||
|
* C99 says the implementation can define __STDC_ISO_10646__ if wchar_t
|
||||||
|
* values match ISO 10646 (or Unicode) numbers in all locales. Do not
|
||||||
|
* check that macro here, because it is too restrictive: it should be
|
||||||
|
* enough for ELinks if the values match in the locales where ELinks is
|
||||||
|
* actually run. */
|
||||||
|
|
||||||
|
#ifdef CONFIG_UTF8
|
||||||
|
#if SIZEOF_WCHAR_T != 4
|
||||||
|
#undef HAVE_TRE_REGEX_H
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
/* This maybe overrides some of the standard high-level functions, to ensure
|
/* This maybe overrides some of the standard high-level functions, to ensure
|
||||||
* the expected behaviour. These overrides are not system specific. */
|
* the expected behaviour. These overrides are not system specific. */
|
||||||
#include "osdep/stub.h"
|
#include "osdep/stub.h"
|
||||||
|
@ -179,10 +179,8 @@ u2cp_(unicode_val_T u, int to, enum nbsp_mode nbsp_mode)
|
|||||||
|
|
||||||
to &= ~SYSTEM_CHARSET_FLAG;
|
to &= ~SYSTEM_CHARSET_FLAG;
|
||||||
|
|
||||||
#ifdef CONFIG_UTF8
|
|
||||||
if (is_cp_ptr_utf8(&codepages[to]))
|
if (is_cp_ptr_utf8(&codepages[to]))
|
||||||
return encode_utf8(u);
|
return encode_utf8(u);
|
||||||
#endif /* CONFIG_UTF8 */
|
|
||||||
|
|
||||||
/* To mark non breaking spaces in non-UTF-8 strings, we use a
|
/* To mark non breaking spaces in non-UTF-8 strings, we use a
|
||||||
* special char NBSP_CHAR. */
|
* special char NBSP_CHAR. */
|
||||||
@ -215,13 +213,8 @@ u2cp_(unicode_val_T u, int to, enum nbsp_mode nbsp_mode)
|
|||||||
|
|
||||||
static unsigned char utf_buffer[7];
|
static unsigned char utf_buffer[7];
|
||||||
|
|
||||||
#ifdef CONFIG_UTF8
|
|
||||||
inline unsigned char *
|
inline unsigned char *
|
||||||
encode_utf8(unicode_val_T u)
|
encode_utf8(unicode_val_T u)
|
||||||
#else
|
|
||||||
static unsigned char *
|
|
||||||
encode_utf8(unicode_val_T u)
|
|
||||||
#endif /* CONFIG_UTF8 */
|
|
||||||
{
|
{
|
||||||
memset(utf_buffer, 0, 7);
|
memset(utf_buffer, 0, 7);
|
||||||
|
|
||||||
|
@ -125,8 +125,8 @@ const uint16_t *get_cp_highhalf(const unsigned char *);
|
|||||||
|
|
||||||
int is_cp_utf8(int);
|
int is_cp_utf8(int);
|
||||||
void free_conv_table(void);
|
void free_conv_table(void);
|
||||||
#ifdef CONFIG_UTF8
|
|
||||||
inline unsigned char *encode_utf8(unicode_val_T);
|
inline unsigned char *encode_utf8(unicode_val_T);
|
||||||
|
#ifdef CONFIG_UTF8
|
||||||
inline unsigned char *utf8_prevchar(unsigned char *, int, unsigned char *);
|
inline unsigned char *utf8_prevchar(unsigned char *, int, unsigned char *);
|
||||||
inline int utf8charlen(const unsigned char *);
|
inline int utf8charlen(const unsigned char *);
|
||||||
int utf8_char2cells(unsigned char *, unsigned char *);
|
int utf8_char2cells(unsigned char *, unsigned char *);
|
||||||
|
@ -45,6 +45,10 @@ n_(unsigned char *msg1, unsigned char *msg2, unsigned long int n, struct termina
|
|||||||
return gettext_noop(msg1);
|
return gettext_noop(msg1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
intl_set_charset_by_index(int new_charset)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -59,10 +63,8 @@ extern int current_charset;
|
|||||||
/* #define DEBUG_IT */
|
/* #define DEBUG_IT */
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
intl_set_charset(struct terminal *term)
|
intl_set_charset_by_index(int new_charset)
|
||||||
{
|
{
|
||||||
int new_charset = get_terminal_codepage(term);
|
|
||||||
|
|
||||||
/* Prevent useless switching. */
|
/* Prevent useless switching. */
|
||||||
if (current_charset != new_charset) {
|
if (current_charset != new_charset) {
|
||||||
bind_textdomain_codeset( /* PACKAGE */ "elinks",
|
bind_textdomain_codeset( /* PACKAGE */ "elinks",
|
||||||
@ -71,6 +73,14 @@ intl_set_charset(struct terminal *term)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
intl_set_charset(struct terminal *term)
|
||||||
|
{
|
||||||
|
int new_charset = get_terminal_codepage(term);
|
||||||
|
|
||||||
|
intl_set_charset_by_index(new_charset);
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Ideally, we should internally work only in Unicode - then the need for
|
/* TODO: Ideally, we should internally work only in Unicode - then the need for
|
||||||
* charsets multiplexing would cease. That'll take some work yet, though.
|
* charsets multiplexing would cease. That'll take some work yet, though.
|
||||||
* --pasky */
|
* --pasky */
|
||||||
|
@ -447,9 +447,16 @@ set_window_title(unsigned char *title, int codepage)
|
|||||||
|| (unicode >= 0x7F && unicode < 0xA0))
|
|| (unicode >= 0x7F && unicode < 0xA0))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* xterm entirely rejects 1024-byte or longer
|
/* If the title is getting too long, truncate
|
||||||
* titles. */
|
* it and add an ellipsis.
|
||||||
if (filtered.length + charlen >= 1024 - 3) {
|
*
|
||||||
|
* xterm entirely rejects 1024-byte or longer
|
||||||
|
* titles. GNU Screen 4.00.03 misparses
|
||||||
|
* titles longer than 765 bytes, and is unable
|
||||||
|
* to display the title in hardstatus if the
|
||||||
|
* title and other stuff together exceed 766
|
||||||
|
* bytes. So set the limit quite a bit lower. */
|
||||||
|
if (filtered.length + charlen >= 600 - 3) {
|
||||||
add_to_string(&filtered, "...");
|
add_to_string(&filtered, "...");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "bookmarks/bookmarks.h"
|
#include "bookmarks/bookmarks.h"
|
||||||
#include "ecmascript/spidermonkey-shared.h"
|
#include "ecmascript/spidermonkey-shared.h"
|
||||||
|
#include "intl/charsets.h"
|
||||||
#include "main/event.h"
|
#include "main/event.h"
|
||||||
#include "scripting/smjs/core.h"
|
#include "scripting/smjs/core.h"
|
||||||
#include "scripting/smjs/elinks_object.h"
|
#include "scripting/smjs/elinks_object.h"
|
||||||
@ -78,6 +79,60 @@ static const JSPropertySpec bookmark_props[] = {
|
|||||||
|
|
||||||
static JSObject *smjs_get_bookmark_folder_object(struct bookmark *bookmark);
|
static JSObject *smjs_get_bookmark_folder_object(struct bookmark *bookmark);
|
||||||
|
|
||||||
|
/** Convert a string retrieved from struct bookmark to a jsval.
|
||||||
|
*
|
||||||
|
* @return JS_TRUE if successful. On error, report the error and
|
||||||
|
* return JS_FALSE. */
|
||||||
|
static JSBool
|
||||||
|
bookmark_string_to_jsval(JSContext *ctx, const unsigned char *str, jsval *vp)
|
||||||
|
{
|
||||||
|
JSString *jsstr = utf8_to_jsstring(ctx, str, -1);
|
||||||
|
|
||||||
|
if (jsstr == NULL)
|
||||||
|
return JS_FALSE;
|
||||||
|
*vp = STRING_TO_JSVAL(jsstr);
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a jsval to a string and store it in struct bookmark.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* Context for memory allocations and error reports.
|
||||||
|
* @param val
|
||||||
|
* The @c jsval that should be converted.
|
||||||
|
* @param[in,out] result
|
||||||
|
* A string allocated with mem_alloc().
|
||||||
|
* On success, this function frees the original string, if any.
|
||||||
|
*
|
||||||
|
* @return JS_TRUE if successful. On error, report the error to
|
||||||
|
* SpiderMonkey and return JS_FALSE. */
|
||||||
|
static JSBool
|
||||||
|
jsval_to_bookmark_string(JSContext *ctx, jsval val, unsigned char **result)
|
||||||
|
{
|
||||||
|
JSString *jsstr = NULL;
|
||||||
|
unsigned char *str;
|
||||||
|
|
||||||
|
/* jsstring_to_utf8() might GC; protect the string to come. */
|
||||||
|
if (!JS_AddNamedRoot(ctx, &jsstr, "jsval_to_bookmark_string"))
|
||||||
|
return JS_FALSE;
|
||||||
|
|
||||||
|
jsstr = JS_ValueToString(ctx, val);
|
||||||
|
if (jsstr == NULL) {
|
||||||
|
JS_RemoveRoot(ctx, &jsstr);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = jsstring_to_utf8(ctx, jsstr, NULL);
|
||||||
|
if (str == NULL) {
|
||||||
|
JS_RemoveRoot(ctx, &jsstr);
|
||||||
|
return JS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
JS_RemoveRoot(ctx, &jsstr);
|
||||||
|
mem_free_set(result, str);
|
||||||
|
return JS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* @bookmark_class.getProperty */
|
/* @bookmark_class.getProperty */
|
||||||
static JSBool
|
static JSBool
|
||||||
bookmark_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
bookmark_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||||
@ -102,15 +157,9 @@ bookmark_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
|
|
||||||
switch (JSVAL_TO_INT(id)) {
|
switch (JSVAL_TO_INT(id)) {
|
||||||
case BOOKMARK_TITLE:
|
case BOOKMARK_TITLE:
|
||||||
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
|
return bookmark_string_to_jsval(ctx, bookmark->title, vp);
|
||||||
bookmark->title));
|
|
||||||
|
|
||||||
return JS_TRUE;
|
|
||||||
case BOOKMARK_URL:
|
case BOOKMARK_URL:
|
||||||
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(smjs_ctx,
|
return bookmark_string_to_jsval(ctx, bookmark->url, vp);
|
||||||
bookmark->url));
|
|
||||||
|
|
||||||
return JS_TRUE;
|
|
||||||
case BOOKMARK_CHILDREN:
|
case BOOKMARK_CHILDREN:
|
||||||
*vp = OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark));
|
*vp = OBJECT_TO_JSVAL(smjs_get_bookmark_folder_object(bookmark));
|
||||||
|
|
||||||
@ -131,6 +180,9 @@ static JSBool
|
|||||||
bookmark_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
bookmark_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
||||||
{
|
{
|
||||||
struct bookmark *bookmark;
|
struct bookmark *bookmark;
|
||||||
|
unsigned char *title = NULL;
|
||||||
|
unsigned char *url = NULL;
|
||||||
|
int ok;
|
||||||
|
|
||||||
/* This can be called if @obj if not itself an instance of the
|
/* This can be called if @obj if not itself an instance of the
|
||||||
* appropriate class but has one in its prototype chain. Fail
|
* appropriate class but has one in its prototype chain. Fail
|
||||||
@ -147,22 +199,14 @@ bookmark_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
return JS_FALSE;
|
return JS_FALSE;
|
||||||
|
|
||||||
switch (JSVAL_TO_INT(id)) {
|
switch (JSVAL_TO_INT(id)) {
|
||||||
case BOOKMARK_TITLE: {
|
case BOOKMARK_TITLE:
|
||||||
JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
|
if (!jsval_to_bookmark_string(ctx, *vp, &title))
|
||||||
unsigned char *str = JS_GetStringBytes(jsstr);
|
return JS_FALSE;
|
||||||
|
break;
|
||||||
mem_free_set(&bookmark->title, stracpy(str));
|
case BOOKMARK_URL:
|
||||||
|
if (!jsval_to_bookmark_string(ctx, *vp, &url))
|
||||||
return JS_TRUE;
|
return JS_FALSE;
|
||||||
}
|
break;
|
||||||
case BOOKMARK_URL: {
|
|
||||||
JSString *jsstr = JS_ValueToString(smjs_ctx, *vp);
|
|
||||||
unsigned char *str = JS_GetStringBytes(jsstr);
|
|
||||||
|
|
||||||
mem_free_set(&bookmark->url, stracpy(str));
|
|
||||||
|
|
||||||
return JS_TRUE;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
/* Unrecognized integer property ID; someone is using
|
/* Unrecognized integer property ID; someone is using
|
||||||
* the object as an array. SMJS builtin classes (e.g.
|
* the object as an array. SMJS builtin classes (e.g.
|
||||||
@ -170,6 +214,11 @@ bookmark_set_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
* Do the same here. */
|
* Do the same here. */
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ok = update_bookmark(bookmark, get_cp_index("UTF-8"), title, url);
|
||||||
|
mem_free_if(title);
|
||||||
|
mem_free_if(url);
|
||||||
|
return ok ? JS_TRUE : JS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const JSClass bookmark_class = {
|
static const JSClass bookmark_class = {
|
||||||
@ -205,7 +254,7 @@ bookmark_folder_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
{
|
{
|
||||||
struct bookmark *bookmark;
|
struct bookmark *bookmark;
|
||||||
struct bookmark *folder;
|
struct bookmark *folder;
|
||||||
unsigned char *title;
|
unsigned char *title = NULL;
|
||||||
|
|
||||||
/* This can be called if @obj if not itself an instance of the
|
/* This can be called if @obj if not itself an instance of the
|
||||||
* appropriate class but has one in its prototype chain. Fail
|
* appropriate class but has one in its prototype chain. Fail
|
||||||
@ -218,14 +267,15 @@ bookmark_folder_get_property(JSContext *ctx, JSObject *obj, jsval id, jsval *vp)
|
|||||||
|
|
||||||
*vp = JSVAL_NULL;
|
*vp = JSVAL_NULL;
|
||||||
|
|
||||||
title = JS_GetStringBytes(JS_ValueToString(ctx, id));
|
if (!jsval_to_bookmark_string(ctx, id, &title))
|
||||||
if (!title) return JS_TRUE;
|
return JS_FALSE;
|
||||||
|
|
||||||
bookmark = get_bookmark_by_name(folder, title);
|
bookmark = get_bookmark_by_name(folder, title);
|
||||||
if (bookmark) {
|
if (bookmark) {
|
||||||
*vp = OBJECT_TO_JSVAL(smjs_get_bookmark_object(bookmark));
|
*vp = OBJECT_TO_JSVAL(smjs_get_bookmark_object(bookmark));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mem_free(title);
|
||||||
return JS_TRUE;
|
return JS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "config/home.h"
|
#include "config/home.h"
|
||||||
#include "ecmascript/spidermonkey-shared.h"
|
#include "ecmascript/spidermonkey-shared.h"
|
||||||
|
#include "intl/charsets.h"
|
||||||
#include "main/module.h"
|
#include "main/module.h"
|
||||||
#include "osdep/osdep.h"
|
#include "osdep/osdep.h"
|
||||||
#include "scripting/scripting.h"
|
#include "scripting/scripting.h"
|
||||||
@ -163,3 +164,163 @@ cleanup_smjs(struct module *module)
|
|||||||
JS_DestroyContext(smjs_ctx);
|
JS_DestroyContext(smjs_ctx);
|
||||||
spidermonkey_runtime_release();
|
spidermonkey_runtime_release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Convert a UTF-8 string to a JSString.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* Allocate the string in this JSContext.
|
||||||
|
* @param[in] str
|
||||||
|
* The input string that should be converted.
|
||||||
|
* @param[in] length
|
||||||
|
* Length of @a str in bytes, or -1 if it is null-terminated.
|
||||||
|
*
|
||||||
|
* @return the new string. On error, report the error to SpiderMonkey
|
||||||
|
* and return NULL. */
|
||||||
|
JSString *
|
||||||
|
utf8_to_jsstring(JSContext *ctx, const unsigned char *str, int length)
|
||||||
|
{
|
||||||
|
size_t in_bytes;
|
||||||
|
const unsigned char *in_end;
|
||||||
|
size_t utf16_alloc;
|
||||||
|
jschar *utf16;
|
||||||
|
size_t utf16_used;
|
||||||
|
JSString *jsstr;
|
||||||
|
|
||||||
|
if (length == -1)
|
||||||
|
in_bytes = strlen(str);
|
||||||
|
else
|
||||||
|
in_bytes = length;
|
||||||
|
|
||||||
|
/* Each byte of input can become at most one UTF-16 unit.
|
||||||
|
* Check whether the multiplication could overflow. */
|
||||||
|
assert(!needs_utf16_surrogates(UCS_REPLACEMENT_CHARACTER));
|
||||||
|
if (in_bytes > ((size_t) -1) / sizeof(jschar)) {
|
||||||
|
JS_ReportAllocationOverflow(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
utf16_alloc = in_bytes;
|
||||||
|
/* Don't use fmem_alloc here because long strings could
|
||||||
|
* exhaust the stack. */
|
||||||
|
utf16 = mem_alloc(utf16_alloc * sizeof(jschar));
|
||||||
|
if (utf16 == NULL) {
|
||||||
|
JS_ReportOutOfMemory(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_end = str + in_bytes;
|
||||||
|
|
||||||
|
utf16_used = 0;
|
||||||
|
for (;;) {
|
||||||
|
unicode_val_T unicode;
|
||||||
|
|
||||||
|
unicode = utf8_to_unicode((unsigned char **) &str, in_end);
|
||||||
|
if (unicode == UCS_NO_CHAR)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (needs_utf16_surrogates(unicode)) {
|
||||||
|
assert(utf16_alloc - utf16_used >= 2);
|
||||||
|
if_assert_failed { mem_free(utf16); return NULL; }
|
||||||
|
utf16[utf16_used++] = get_utf16_high_surrogate(unicode);
|
||||||
|
utf16[utf16_used++] = get_utf16_low_surrogate(unicode);
|
||||||
|
} else {
|
||||||
|
assert(utf16_alloc - utf16_used >= 1);
|
||||||
|
if_assert_failed { mem_free(utf16); return NULL; }
|
||||||
|
utf16[utf16_used++] = unicode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jsstr = JS_NewUCString(ctx, utf16, utf16_used);
|
||||||
|
mem_free(utf16);
|
||||||
|
return jsstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a jschar array to UTF-8 and append it to struct string.
|
||||||
|
* Replace misused surrogate codepoints with UCS_REPLACEMENT_CHARACTER.
|
||||||
|
*
|
||||||
|
* @param[in,out] utf8
|
||||||
|
* The function appends characters to this UTF-8 string.
|
||||||
|
*
|
||||||
|
* @param[in] utf16
|
||||||
|
* Pointer to the first element in an array of jschars.
|
||||||
|
*
|
||||||
|
* @param[i] len
|
||||||
|
* Number of jschars in the @a utf16 array.
|
||||||
|
*
|
||||||
|
* @return @a utf8 if successful, or NULL if not. */
|
||||||
|
static struct string *
|
||||||
|
add_jschars_to_utf8_string(struct string *utf8,
|
||||||
|
const jschar *utf16, size_t len)
|
||||||
|
{
|
||||||
|
size_t pos;
|
||||||
|
|
||||||
|
for (pos = 0; pos < len; ) {
|
||||||
|
unicode_val_T unicode = utf16[pos++];
|
||||||
|
|
||||||
|
if (is_utf16_surrogate(unicode)) {
|
||||||
|
if (is_utf16_high_surrogate(unicode)
|
||||||
|
&& pos < len
|
||||||
|
&& is_utf16_low_surrogate(utf16[pos])) {
|
||||||
|
unicode = join_utf16_surrogates(unicode,
|
||||||
|
utf16[pos++]);
|
||||||
|
} else {
|
||||||
|
unicode = UCS_REPLACEMENT_CHARACTER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unicode == 0) {
|
||||||
|
if (!add_char_to_string(utf8, '\0'))
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
if (!add_to_string(utf8, encode_utf8(unicode)))
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return utf8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert a JSString to a UTF-8 string.
|
||||||
|
*
|
||||||
|
* @param ctx
|
||||||
|
* For reporting errors.
|
||||||
|
* @param[in] jsstr
|
||||||
|
* The input string that should be converted. Must not be NULL.
|
||||||
|
* @param[out] length
|
||||||
|
* Optional. The number of bytes in the returned string,
|
||||||
|
* not counting the terminating null.
|
||||||
|
*
|
||||||
|
* @return the new string, which the caller must eventually free
|
||||||
|
* with mem_free(). On error, report the error to SpiderMonkey
|
||||||
|
* and return NULL; *@a length is then undefined. */
|
||||||
|
unsigned char *
|
||||||
|
jsstring_to_utf8(JSContext *ctx, JSString *jsstr, int *length)
|
||||||
|
{
|
||||||
|
size_t utf16_len;
|
||||||
|
const jschar *utf16;
|
||||||
|
struct string utf8;
|
||||||
|
|
||||||
|
utf16_len = JS_GetStringLength(jsstr);
|
||||||
|
utf16 = JS_GetStringChars(jsstr); /* stays owned by jsstr */
|
||||||
|
if (utf16 == NULL) {
|
||||||
|
/* JS_GetStringChars doesn't have a JSContext *
|
||||||
|
* parameter so it can't report the error
|
||||||
|
* (and can't collect garbage either). */
|
||||||
|
JS_ReportOutOfMemory(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!init_string(&utf8)) {
|
||||||
|
JS_ReportOutOfMemory(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!add_jschars_to_utf8_string(&utf8, utf16, utf16_len)) {
|
||||||
|
done_string(&utf8);
|
||||||
|
JS_ReportOutOfMemory(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length)
|
||||||
|
*length = utf8.length;
|
||||||
|
return utf8.source;
|
||||||
|
}
|
||||||
|
@ -16,4 +16,9 @@ void alert_smjs_error(unsigned char *msg);
|
|||||||
void init_smjs(struct module *module);
|
void init_smjs(struct module *module);
|
||||||
void cleanup_smjs(struct module *module);
|
void cleanup_smjs(struct module *module);
|
||||||
|
|
||||||
|
JSString *utf8_to_jsstring(JSContext *ctx, const unsigned char *str,
|
||||||
|
int length);
|
||||||
|
unsigned char *jsstring_to_utf8(JSContext *ctx, JSString *jsstr,
|
||||||
|
int *length);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -825,10 +825,13 @@ setup_first_session(struct session *ses, struct uri *uri)
|
|||||||
|
|
||||||
#ifdef CONFIG_BOOKMARKS
|
#ifdef CONFIG_BOOKMARKS
|
||||||
} else if (!uri && get_opt_bool("ui.sessions.auto_restore", NULL)) {
|
} else if (!uri && get_opt_bool("ui.sessions.auto_restore", NULL)) {
|
||||||
unsigned char *folder;
|
unsigned char *folder; /* UTF-8 */
|
||||||
|
|
||||||
folder = get_opt_str("ui.sessions.auto_save_foldername", NULL);
|
folder = get_auto_save_bookmark_foldername_utf8();
|
||||||
open_bookmark_folder(ses, folder);
|
if (folder) {
|
||||||
|
open_bookmark_folder(ses, folder);
|
||||||
|
mem_free(folder);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -972,8 +975,16 @@ init_remote_session(struct session *ses, enum remote_session_flags *remote_ptr,
|
|||||||
|
|
||||||
} else if (remote & SES_REMOTE_ADD_BOOKMARK) {
|
} else if (remote & SES_REMOTE_ADD_BOOKMARK) {
|
||||||
#ifdef CONFIG_BOOKMARKS
|
#ifdef CONFIG_BOOKMARKS
|
||||||
|
int uri_cp;
|
||||||
|
|
||||||
if (!uri) return;
|
if (!uri) return;
|
||||||
add_bookmark(NULL, 1, struri(uri), struri(uri));
|
/** @todo Bug 1066: What is the encoding of struri()?
|
||||||
|
* This code currently assumes the system charset.
|
||||||
|
* It might be best to keep URIs in plain ASCII and
|
||||||
|
* then have a function that reversibly converts them
|
||||||
|
* to IRIs for display in a given encoding. */
|
||||||
|
uri_cp = get_cp_index("System");
|
||||||
|
add_bookmark_cp(NULL, 1, uri_cp, struri(uri), struri(uri));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else if (remote & SES_REMOTE_INFO_BOX) {
|
} else if (remote & SES_REMOTE_INFO_BOX) {
|
||||||
|
@ -387,10 +387,7 @@ handle_interlink_event(struct terminal *term, struct interlink_event *ilev)
|
|||||||
/* Not special and UTF-8 mode is disabled:
|
/* Not special and UTF-8 mode is disabled:
|
||||||
* recode from the terminal charset to UCS-4. */
|
* recode from the terminal charset to UCS-4. */
|
||||||
|
|
||||||
key = cp2u(get_opt_codepage_tree(term->spec,
|
key = cp2u(get_terminal_codepage(term), key);
|
||||||
"charset",
|
|
||||||
NULL),
|
|
||||||
key);
|
|
||||||
term_send_ucs(term, key, modifier);
|
term_send_ucs(term, key, modifier);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +492,10 @@ clr_spaces(unsigned char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Replace invalid chars in @a title with ' ' and trim all starting/ending
|
/** Replace invalid chars in @a title with ' ' and trim all starting/ending
|
||||||
* spaces. */
|
* spaces.
|
||||||
|
*
|
||||||
|
* update_bookmark() assumes this function does not switch translation
|
||||||
|
* tables. */
|
||||||
void
|
void
|
||||||
sanitize_title(unsigned char *title)
|
sanitize_title(unsigned char *title)
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
top_builddir=../../..
|
top_builddir=../../..
|
||||||
include $(top_builddir)/Makefile.config
|
include $(top_builddir)/Makefile.config
|
||||||
|
|
||||||
|
INCLUDES += $(TRE_CFLAGS)
|
||||||
|
|
||||||
OBJS-$(CONFIG_MARKS) += marks.o
|
OBJS-$(CONFIG_MARKS) += marks.o
|
||||||
|
|
||||||
OBJS = draw.o form.o link.o search.o textarea.o view.o vs.o
|
OBJS = draw.o form.o link.o search.o textarea.o view.o vs.o
|
||||||
|
@ -16,11 +16,11 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
#include <sys/types.h> /* FreeBSD needs this before regex.h */
|
||||||
#ifdef HAVE_REGEX_H
|
|
||||||
#include <regex.h>
|
|
||||||
#endif
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
|
#include <tre/regex.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "elinks.h"
|
#include "elinks.h"
|
||||||
|
|
||||||
@ -54,10 +54,18 @@ static INIT_INPUT_HISTORY(search_history);
|
|||||||
#undef UCHAR
|
#undef UCHAR
|
||||||
#ifdef CONFIG_UTF8
|
#ifdef CONFIG_UTF8
|
||||||
#define UCHAR unicode_val_T
|
#define UCHAR unicode_val_T
|
||||||
|
#define PATTERN const wchar_t
|
||||||
|
#define Regcomp regwcomp
|
||||||
|
#define Regexec regwexec
|
||||||
#else
|
#else
|
||||||
#define UCHAR unsigned char
|
#define UCHAR unsigned char
|
||||||
|
#define PATTERN const char
|
||||||
|
#define Regcomp regcomp
|
||||||
|
#define Regexec regexec
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static UCHAR *memacpy_u(unsigned char *text, int textlen, int utf8);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
|
add_srch_chr(struct document *document, UCHAR c, int x, int y, int nn)
|
||||||
{
|
{
|
||||||
@ -262,21 +270,21 @@ get_range(struct document *document, int y, int height, int l,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
/** Returns a string @c doc that is a copy of the text in the search
|
/** Returns a string @c doc that is a copy of the text in the search
|
||||||
* nodes from @a s1 to (@a s1 + @a doclen - 1) with the space at the
|
* nodes from @a s1 to (@a s1 + @a doclen - 1) with the space at the
|
||||||
* end of each line converted to a new-line character (LF). */
|
* end of each line converted to a new-line character (LF). */
|
||||||
static unsigned char *
|
static UCHAR *
|
||||||
get_search_region_from_search_nodes(struct search *s1, struct search *s2,
|
get_search_region_from_search_nodes(struct search *s1, struct search *s2,
|
||||||
int pattern_len, int *doclen)
|
int pattern_len, int *doclen)
|
||||||
{
|
{
|
||||||
unsigned char *doc;
|
UCHAR *doc;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
*doclen = s2 - s1 + pattern_len;
|
*doclen = s2 - s1 + pattern_len;
|
||||||
if (!*doclen) return NULL;
|
if (!*doclen) return NULL;
|
||||||
|
|
||||||
doc = mem_alloc(*doclen + 1);
|
doc = mem_alloc((*doclen + 1) * sizeof(UCHAR));
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
*doclen = -1;
|
*doclen = -1;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -301,11 +309,11 @@ struct regex_match_context {
|
|||||||
int y1;
|
int y1;
|
||||||
int y2;
|
int y2;
|
||||||
int found;
|
int found;
|
||||||
unsigned char *pattern;
|
UCHAR *pattern;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init_regex(regex_t *regex, unsigned char *pattern)
|
init_regex(regex_t *regex, UCHAR *pattern)
|
||||||
{
|
{
|
||||||
int regex_flags = REG_NEWLINE;
|
int regex_flags = REG_NEWLINE;
|
||||||
int reg_err;
|
int reg_err;
|
||||||
@ -316,7 +324,7 @@ init_regex(regex_t *regex, unsigned char *pattern)
|
|||||||
if (!get_opt_bool("document.browse.search.case", NULL))
|
if (!get_opt_bool("document.browse.search.case", NULL))
|
||||||
regex_flags |= REG_ICASE;
|
regex_flags |= REG_ICASE;
|
||||||
|
|
||||||
reg_err = regcomp(regex, pattern, regex_flags);
|
reg_err = Regcomp(regex, (PATTERN *)pattern, regex_flags);
|
||||||
if (reg_err) {
|
if (reg_err) {
|
||||||
regfree(regex);
|
regfree(regex);
|
||||||
return 0;
|
return 0;
|
||||||
@ -329,8 +337,8 @@ static void
|
|||||||
search_for_pattern(struct regex_match_context *common_ctx, void *data,
|
search_for_pattern(struct regex_match_context *common_ctx, void *data,
|
||||||
void (*match)(struct regex_match_context *, void *))
|
void (*match)(struct regex_match_context *, void *))
|
||||||
{
|
{
|
||||||
unsigned char *doc;
|
UCHAR *doc;
|
||||||
unsigned char *doctmp;
|
UCHAR *doctmp;
|
||||||
int doclen;
|
int doclen;
|
||||||
int regexec_flags = 0;
|
int regexec_flags = 0;
|
||||||
regex_t regex;
|
regex_t regex;
|
||||||
@ -381,7 +389,7 @@ find_next:
|
|||||||
save_c = doc[pos];
|
save_c = doc[pos];
|
||||||
doc[pos] = 0;
|
doc[pos] = 0;
|
||||||
|
|
||||||
while (*doctmp && !regexec(®ex, doctmp, 1, ®match, regexec_flags)) {
|
while (*doctmp && !Regexec(®ex, (PATTERN *)doctmp, 1, ®match, regexec_flags)) {
|
||||||
regexec_flags = REG_NOTBOL;
|
regexec_flags = REG_NOTBOL;
|
||||||
common_ctx->textlen = regmatch.rm_eo - regmatch.rm_so;
|
common_ctx->textlen = regmatch.rm_eo - regmatch.rm_so;
|
||||||
if (!common_ctx->textlen) { doc[pos] = save_c; common_ctx->found = 1; goto free_stuff; }
|
if (!common_ctx->textlen) { doc[pos] = save_c; common_ctx->found = 1; goto free_stuff; }
|
||||||
@ -432,10 +440,13 @@ static int
|
|||||||
is_in_range_regex(struct document *document, int y, int height,
|
is_in_range_regex(struct document *document, int y, int height,
|
||||||
unsigned char *text, int textlen,
|
unsigned char *text, int textlen,
|
||||||
int *min, int *max,
|
int *min, int *max,
|
||||||
struct search *s1, struct search *s2)
|
struct search *s1, struct search *s2, int utf8)
|
||||||
{
|
{
|
||||||
struct regex_match_context common_ctx;
|
struct regex_match_context common_ctx;
|
||||||
struct is_in_range_regex_context ctx;
|
struct is_in_range_regex_context ctx;
|
||||||
|
UCHAR *txt = memacpy_u(text, textlen, utf8);
|
||||||
|
|
||||||
|
if (!txt) return -1;
|
||||||
|
|
||||||
ctx.y = y;
|
ctx.y = y;
|
||||||
ctx.min = min;
|
ctx.min = min;
|
||||||
@ -445,15 +456,16 @@ is_in_range_regex(struct document *document, int y, int height,
|
|||||||
common_ctx.textlen = textlen;
|
common_ctx.textlen = textlen;
|
||||||
common_ctx.y1 = y - 1;
|
common_ctx.y1 = y - 1;
|
||||||
common_ctx.y2 = y + height;
|
common_ctx.y2 = y + height;
|
||||||
common_ctx.pattern = text;
|
common_ctx.pattern = txt;
|
||||||
common_ctx.s1 = s1;
|
common_ctx.s1 = s1;
|
||||||
common_ctx.s2 = s2;
|
common_ctx.s2 = s2;
|
||||||
|
|
||||||
search_for_pattern(&common_ctx, &ctx, is_in_range_regex_match);
|
search_for_pattern(&common_ctx, &ctx, is_in_range_regex_match);
|
||||||
|
mem_free(txt);
|
||||||
|
|
||||||
return common_ctx.found;
|
return common_ctx.found;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_REGEX_H */
|
#endif /* HAVE_TRE_REGEX_H */
|
||||||
|
|
||||||
static UCHAR *
|
static UCHAR *
|
||||||
memacpy_u(unsigned char *text, int textlen, int utf8)
|
memacpy_u(unsigned char *text, int textlen, int utf8)
|
||||||
@ -590,10 +602,10 @@ is_in_range(struct document *document, int y, int height,
|
|||||||
if (get_range(document, y, height, textlen, &s1, &s2))
|
if (get_range(document, y, height, textlen, &s1, &s2))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
if (get_opt_int("document.browse.search.regex", NULL))
|
if (get_opt_int("document.browse.search.regex", NULL))
|
||||||
return is_in_range_regex(document, y, height, text, textlen,
|
return is_in_range_regex(document, y, height, text, textlen,
|
||||||
min, max, s1, s2);
|
min, max, s1, s2, utf8);
|
||||||
#endif
|
#endif
|
||||||
return is_in_range_plain(document, y, height, text, textlen,
|
return is_in_range_plain(document, y, height, text, textlen,
|
||||||
min, max, s1, s2, utf8);
|
min, max, s1, s2, utf8);
|
||||||
@ -669,7 +681,7 @@ srch_failed:
|
|||||||
*pl = len;
|
*pl = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
struct get_searched_regex_context {
|
struct get_searched_regex_context {
|
||||||
int xoffset;
|
int xoffset;
|
||||||
int yoffset;
|
int yoffset;
|
||||||
@ -709,10 +721,13 @@ get_searched_regex_match(struct regex_match_context *common_ctx, void *data)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
||||||
int textlen, struct search *s1, struct search *s2)
|
int textlen, struct search *s1, struct search *s2, int utf8)
|
||||||
{
|
{
|
||||||
struct regex_match_context common_ctx;
|
struct regex_match_context common_ctx;
|
||||||
struct get_searched_regex_context ctx;
|
struct get_searched_regex_context ctx;
|
||||||
|
UCHAR *txt = memacpy_u(*doc_view->search_word, textlen, utf8);
|
||||||
|
|
||||||
|
if (!txt) return;
|
||||||
|
|
||||||
ctx.points = NULL;
|
ctx.points = NULL;
|
||||||
ctx.len = 0;
|
ctx.len = 0;
|
||||||
@ -724,16 +739,17 @@ get_searched_regex(struct document_view *doc_view, struct point **pt, int *pl,
|
|||||||
common_ctx.textlen = textlen;
|
common_ctx.textlen = textlen;
|
||||||
common_ctx.y1 = doc_view->vs->y - 1;
|
common_ctx.y1 = doc_view->vs->y - 1;
|
||||||
common_ctx.y2 = doc_view->vs->y + ctx.box->height;
|
common_ctx.y2 = doc_view->vs->y + ctx.box->height;
|
||||||
common_ctx.pattern = *doc_view->search_word;
|
common_ctx.pattern = txt;
|
||||||
common_ctx.s1 = s1;
|
common_ctx.s1 = s1;
|
||||||
common_ctx.s2 = s2;
|
common_ctx.s2 = s2;
|
||||||
|
|
||||||
search_for_pattern(&common_ctx, &ctx, get_searched_regex_match);
|
search_for_pattern(&common_ctx, &ctx, get_searched_regex_match);
|
||||||
|
|
||||||
|
mem_free(txt);
|
||||||
*pt = ctx.points;
|
*pt = ctx.points;
|
||||||
*pl = ctx.len;
|
*pl = ctx.len;
|
||||||
}
|
}
|
||||||
#endif /* HAVE_REGEX_H */
|
#endif /* HAVE_TRE_REGEX_H */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf8)
|
get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf8)
|
||||||
@ -757,9 +773,9 @@ get_searched(struct document_view *doc_view, struct point **pt, int *pl, int utf
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
if (get_opt_int("document.browse.search.regex", NULL))
|
if (get_opt_int("document.browse.search.regex", NULL))
|
||||||
get_searched_regex(doc_view, pt, pl, l, s1, s2);
|
get_searched_regex(doc_view, pt, pl, l, s1, s2, utf8);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
get_searched_plain(doc_view, pt, pl, l, s1, s2, utf8);
|
get_searched_plain(doc_view, pt, pl, l, s1, s2, utf8);
|
||||||
@ -1576,7 +1592,7 @@ search_typeahead(struct session *ses, struct document_view *doc_view,
|
|||||||
* a nice cleanup target ;-). --pasky */
|
* a nice cleanup target ;-). --pasky */
|
||||||
|
|
||||||
enum search_option {
|
enum search_option {
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
SEARCH_OPT_REGEX,
|
SEARCH_OPT_REGEX,
|
||||||
#endif
|
#endif
|
||||||
SEARCH_OPT_CASE,
|
SEARCH_OPT_CASE,
|
||||||
@ -1584,7 +1600,7 @@ enum search_option {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct option_resolver resolvers[] = {
|
static struct option_resolver resolvers[] = {
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
{ SEARCH_OPT_REGEX, "regex" },
|
{ SEARCH_OPT_REGEX, "regex" },
|
||||||
#endif
|
#endif
|
||||||
{ SEARCH_OPT_CASE, "case" },
|
{ SEARCH_OPT_CASE, "case" },
|
||||||
@ -1651,7 +1667,7 @@ search_dlg_do(struct terminal *term, struct memory_list *ml,
|
|||||||
hop->values, SEARCH_OPTIONS);
|
hop->values, SEARCH_OPTIONS);
|
||||||
hop->data = data;
|
hop->data = data;
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
#define SEARCH_WIDGETS_COUNT 8
|
#define SEARCH_WIDGETS_COUNT 8
|
||||||
#else
|
#else
|
||||||
#define SEARCH_WIDGETS_COUNT 5
|
#define SEARCH_WIDGETS_COUNT 5
|
||||||
@ -1675,7 +1691,7 @@ search_dlg_do(struct terminal *term, struct memory_list *ml,
|
|||||||
field = get_dialog_offset(dlg, SEARCH_WIDGETS_COUNT);
|
field = get_dialog_offset(dlg, SEARCH_WIDGETS_COUNT);
|
||||||
add_dlg_field(dlg, text, 0, 0, NULL, MAX_STR_LEN, field, history);
|
add_dlg_field(dlg, text, 0, 0, NULL, MAX_STR_LEN, field, history);
|
||||||
|
|
||||||
#ifdef HAVE_REGEX_H
|
#ifdef HAVE_TRE_REGEX_H
|
||||||
add_dlg_radio(dlg, _("Normal search", term), 1, 0, &hop->values[SEARCH_OPT_REGEX].number);
|
add_dlg_radio(dlg, _("Normal search", term), 1, 0, &hop->values[SEARCH_OPT_REGEX].number);
|
||||||
add_dlg_radio(dlg, _("Regexp search", term), 1, 1, &hop->values[SEARCH_OPT_REGEX].number);
|
add_dlg_radio(dlg, _("Regexp search", term), 1, 1, &hop->values[SEARCH_OPT_REGEX].number);
|
||||||
add_dlg_radio(dlg, _("Extended regexp search", term), 1, 2, &hop->values[SEARCH_OPT_REGEX].number);
|
add_dlg_radio(dlg, _("Extended regexp search", term), 1, 2, &hop->values[SEARCH_OPT_REGEX].number);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user