netsurf-website: branch master updated. e4fca06e16c33714371f9152de6a27b795d4de61
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-website.git/shortlog/e4fca06e16c33...
...commit http://git.netsurf-browser.org/netsurf-website.git/commit/e4fca06e16c3371...
...tree http://git.netsurf-browser.org/netsurf-website.git/tree/e4fca06e16c337143...
The branch, master has been updated
via e4fca06e16c33714371f9152de6a27b795d4de61 (commit)
from 5e7269550d57618ac40c5c1eaa7fd819713d1b33 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-website.git/commit/?id=e4fca06e16c...
commit e4fca06e16c33714371f9152de6a27b795d4de61
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Remove MNG & JNG from list of supported image formats.
diff --git a/index.en b/index.en
index 3b57b01..e792ba0 100644
--- a/index.en
+++ b/index.en
@@ -165,7 +165,7 @@
<dd>
<ul>
<li>Web standards: HTML 4.01 and CSS 2.1</li>
-<li>Image formats: PNG, GIF, JPEG, SVG, JNG, MNG and BMP</li>
+<li>Image formats including: PNG, GIF, JPEG, SVG, and BMP</li>
<li>HTTPS for secure online transactions</li>
<li>Unicode text</li>
<li>Web page thumbnailing</li>
-----------------------------------------------------------------------
Summary of changes:
index.en | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/index.en b/index.en
index 3b57b01..e792ba0 100644
--- a/index.en
+++ b/index.en
@@ -165,7 +165,7 @@
<dd>
<ul>
<li>Web standards: HTML 4.01 and CSS 2.1</li>
-<li>Image formats: PNG, GIF, JPEG, SVG, JNG, MNG and BMP</li>
+<li>Image formats including: PNG, GIF, JPEG, SVG, and BMP</li>
<li>HTTPS for secure online transactions</li>
<li>Unicode text</li>
<li>Web page thumbnailing</li>
--
NetSurf website source for *.netsurf-browser.org
9 years, 1 month
netsurf: branch vince/llcache updated. release/3.1-9-gd0054e9
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/d0054e9846fc771fa87f0...
...commit http://git.netsurf-browser.org/netsurf.git/commit/d0054e9846fc771fa87f020...
...tree http://git.netsurf-browser.org/netsurf.git/tree/d0054e9846fc771fa87f020d0...
The branch, vince/llcache has been updated
discards 2437acbb2c6c8242f53bcae30db518ebe5aa84d4 (commit)
discards 09189872900d083e2a528ff1edde9c77b744322c (commit)
discards 0107e222270a5a56c37857a33d193169e7d6d83d (commit)
discards a0a5433b995a13eda8d6cce2afb9ee364de473ba (commit)
discards a9dd342d4b96c2d59023b343d7a4b4489756918e (commit)
discards 7ef5e920c4be328fabda9dfc7e8ae2c7e6fb4ab9 (commit)
discards 2d9e02ccc8dd8147baec0eede4e3e942f3e27b17 (commit)
via d0054e9846fc771fa87f020d0f583d5eff897a4f (commit)
via f45ef2d60c25c8be656d8ccd9e9b1e3b4840ce53 (commit)
via 561baea10a1b4d26bc9ce0ceb86c3185dddea634 (commit)
via 0781dcb39e3ea1583ca1ada2289a110b1d841ebd (commit)
via 47493a689106a37b91e506125c1f19f075aeac5e (commit)
via 5dd6fa6f228f022d3e2e3e1ee7a21b3d4f17724e (commit)
via 1fd565cba706d6a9e809d14f79ceb92633b62ead (commit)
via c0ac05d39c10ff39c8f4874bdbbe192dca07e910 (commit)
via f28fc945cc33300c00dddacaa3e4dd3ce50c526f (commit)
via ddc5a52693206b60aba3aaeacecb3d8e2b15103e (commit)
via 2c4825cb38f61047c358da11b71d82541a475305 (commit)
via d1223950d76a0293d3bb09f4584bae5ab5a34333 (commit)
via 2a4f7f6b65d8e40a14533e532dedfadce2691456 (commit)
via 55415ed6cd5cca1d759b5383700e0cf5d3f52684 (commit)
via 898ff4b821b00361c747482d6b0f94c7c6ec4d02 (commit)
via 0d32293c6a0724f906e7ffe5517ccf69b8d04ccf (commit)
via 4fad67114e9ae5a0e05962cdce8e8a1bb217925a (commit)
via b6048815286dfa3a0e5a272a4c828cb33694f8ac (commit)
via 679c87e527e03926b6369c0f82096e5459beef13 (commit)
via f89516c49589528b2b2cf0185bbbdb89a8d1f2a6 (commit)
via e41900bddc8488ae29f7c302103cfea3eef8bbdc (commit)
via b828f6de02393cc47139fa268a5e1f2c2085771e (commit)
via cfc75ac6f98ce614cb224ffa243daf68a166c907 (commit)
via 263118c50179c897654a85d7067d9a02f9f528a6 (commit)
via c36078db73ba4a5e7ad5fa0019dfa3fffdead59d (commit)
via b7b3496a78fd08197899f588a4abc026c8636e74 (commit)
via 9ba0d66c6d8b248a1889a98b2e2850a728f7f3c0 (commit)
via 1ecd56bd716916af845b956326601e9bae92885d (commit)
via 4ec70fd3a2e75a3295799a685bbeb4dbffcdc05d (commit)
via 5bb5e2667df7459c288c3484d3539376a74a7c68 (commit)
via 3ea6ca89a0daf4a20ddf9962cc787ed5001f5ab6 (commit)
via a36e7aaeb304f688de2f1e01cebf3e295273d633 (commit)
via d9d0b1d3aa9ec463cd6110cdfcc7fb67c1baef47 (commit)
via ba5bae389b9bfed07e94fc8ec3191f4dcfa714f0 (commit)
via 65adc1712123f81847a85ce0374acc5a741368ec (commit)
via 975a1d3c5db0dc11a4f5ada68d5d424850858161 (commit)
via c1a32d7c6e87f3d81fa095e7e7fe11fa8d88fe5f (commit)
via b301a111405f0f5e5df7b6204e6c2bf4bee2fce5 (commit)
via 0f6859864911270c65caea459637d35cf1bba14a (commit)
via c2f9a399664faa1248eb5a043e697a7d94558c0c (commit)
via f991abc53cb5eeb874542cf8a40f4dbecef32296 (commit)
via 268cda0f560ffdacf6186b923f5540ed5da52ef9 (commit)
via d907ec9b0614e5c178720429dee7a8ef96df6aad (commit)
via 412df342987f754958a9756817ccacaebe07f764 (commit)
via 99c47eb99be4309e996f4cb038916260fd2bcb44 (commit)
via f0f05d691ba748314e57da754518dfbad6a7a339 (commit)
via fb072686c1b52f9f50ccff7241eff1e85a2dd97b (commit)
via 5324cd9abdf34c6568c7051a97c33a8934fcd89b (commit)
via 4575698f0f8b570f3c32e05cd3cbeb2d4f8ff237 (commit)
via a741ceadb89d09d7604a411ed04c0d92928ce814 (commit)
via b91c28b8d1ecf1ace615ff12e11adadf4f330b9a (commit)
via 88a99d9722f6c61cf8a338002d7a38622a1168ef (commit)
via 527bc23bdba33f1db6194c5d95f41f8a6b603bd5 (commit)
via 979b59887f6e868908519640fc795db0070371f7 (commit)
via a9fb42e71bc55ad4b498beaf2202c09cc37c5056 (commit)
via 442d1cb3cffe60253ab1481c0168d1708644fc97 (commit)
via 3445483e7838719d3feb0a6daf0fa9290b0cfb3f (commit)
via 9c60417f73868e2cd8e0db951020110ee8c295fc (commit)
via 763825e5972f6ea7f986056f84a68cec451ba7cb (commit)
via 0adbfe125e288c59588be87f7cd8493b0c8c0351 (commit)
via 97c12b975c163aa878736fe66d1968f0dc5af7eb (commit)
via b16cfd2d6edf20a31613f421582f528a93c40e41 (commit)
via 7738584b3411fa0941579831deae388139eb7a5a (commit)
via 119b8af2db392c85eb07d0aefbadeda62f1b1cc9 (commit)
via 7bcefbf72dee4cb60fa51ffc9eb4e0ab26ddab75 (commit)
via ed1ea8e6eec45123b27d6f74b9192271526f2f02 (commit)
via 6f9a93e33295fc3185ca27f2ce9a4f6fd4f4de69 (commit)
via c86d1cfba695867bf896afe463abfe61af7ca162 (commit)
via 4d4d74c8cd1a77a46cbe0816cf6150f8b4980947 (commit)
via fec9f916b640b8ffc18b7ff9f9d04fd742b32ad1 (commit)
via a67c49eacfcdfc65aadd457df9c63232eb806624 (commit)
via f09011cb0e001aca2c5e7e73927e33e96d6f4267 (commit)
via 5254f872aac16b1a810a52a1ca2d2f6375744d1a (commit)
via f7c756192e1d088e2b8198e4512e31b4841a12b8 (commit)
via 5e8c2b00f01937f82305c12fcac3943e778c92da (commit)
via ba1aeccc05fd45617cf12902e4fdd04cd4bd7a86 (commit)
via f104f99809939048890bc2e39d403a339f2976b2 (commit)
via 51cc2cfe38931f6e200a99df3a28ab2b267223ff (commit)
via e1045bf64b26e09a0b9e633d243613f6da5613bd (commit)
via 2059787a24b8bb9d1d94c028c2f4feb7745619d4 (commit)
via 5e1c19128b5ef32ca1798a9544aaf9b6e382e404 (commit)
via ca74c70cc724c8fdeb46aa2eafec354e5adcff4c (commit)
via fd139ba8f406595a538ce8f8768eecc3d12b9ca3 (commit)
via c44bbcdc08b880bead0a196826d64031de36bee6 (commit)
via 7a3d3437663ea6669811910f7671600d861a2f1f (commit)
via 9da93c23a4b6dd123f055de8507c0459e82189ce (commit)
via 0397a7cab12016c6ea452019248e6017b6f646af (commit)
This update added new revisions after undoing existing revisions. That is
to say, the old revision is not a strict subset of the new revision. This
situation occurs when you --force push a change and generate a repository
containing something like this:
* -- * -- B -- O -- O -- O (2437acbb2c6c8242f53bcae30db518ebe5aa84d4)
\
N -- N -- N (d0054e9846fc771fa87f020d0f583d5eff897a4f)
When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=d0054e9846fc771fa87...
commit d0054e9846fc771fa87f020d0f583d5eff897a4f
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Enable filesystem based cache in gtk frontend
diff --git a/gtk/Makefile.defaults b/gtk/Makefile.defaults
index 6c48b0c..90435a1 100644
--- a/gtk/Makefile.defaults
+++ b/gtk/Makefile.defaults
@@ -21,6 +21,9 @@ NETSURF_USE_NSSVG := AUTO
# Valid options: YES, NO, AUTO
NETSURF_USE_ROSPRITE := AUTO
+# Enable building the source object cache filesystem based backing store.
+NETSURF_FS_BACKING_STORE := YES
+
# Configuration overrides for Mac OS X
ifeq ($(HOST),macosx)
NETSURF_USE_LIBICONV_PLUG := NO
diff --git a/gtk/gui.c b/gtk/gui.c
index 737b8e6..9c35737 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -44,6 +44,7 @@
#include "content/fetchers/resource.h"
#include "content/hlcache.h"
#include "content/urldb.h"
+#include "content/backing_store.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/netsurf.h"
@@ -1094,11 +1095,111 @@ static nserror create_config_home(char **config_home_out)
/* strip the trailing separator */
config_home[strlen(config_home) - 1] = 0;
+ LOG(("\"%s\"", config_home));
+
*config_home_out = config_home;
return NSERROR_OK;
}
+/**
+ * Get the path to the cache directory.
+ *
+ * @param cache_home_out Path to cache directory.
+ * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
+ */
+static nserror get_cache_home(char **cache_home_out)
+{
+ nserror ret;
+ char *xdg_cache_dir;
+ char *cache_home;
+ char *home_dir;
+
+ /* $XDG_CACHE_HOME defines the base directory relative to
+ * which user specific non-essential data files should be
+ * stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ /* If $XDG_CACHE_HOME is either not set or empty, a
+ * default equal to $HOME/.cache should be used.
+ */
+
+ home_dir = getenv("HOME");
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG(("\"%s\"", cache_home));
+
+ *cache_home_out = cache_home;
+ return NSERROR_OK;
+}
+
+static nserror create_cache_home(char **cache_home_out)
+{
+ char *cache_home;
+ char *home_dir;
+ char *xdg_cache_dir;
+ nserror ret;
+
+ LOG(("Attempting to create configuration directory"));
+
+ /* $XDG_CACHE_HOME defines the base directory
+ * relative to which user specific cache files
+ * should be stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ cache_home = filepath_append(home_dir, ".cache/netsurf/");
+ if (cache_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ cache_home = filepath_append(xdg_cache_dir, "netsurf/");
+ if (cache_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = filepath_mkdir_all(cache_home);
+ if (ret != NSERROR_OK) {
+ free(cache_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ cache_home[strlen(cache_home) - 1] = 0;
+
+ LOG(("\"%s\"", cache_home));
+
+ *cache_home_out = cache_home;
+
+ return NSERROR_OK;
+}
+
static nserror nsgtk_option_init(int *pargc, char** argv)
{
nserror ret;
@@ -1156,6 +1257,7 @@ static struct gui_browser_table nsgtk_browser_table = {
int main(int argc, char** argv)
{
char *messages;
+ char *cache_home = NULL;
nserror ret;
struct gui_table nsgtk_gui_table = {
.browser = &nsgtk_browser_table,
@@ -1164,6 +1266,7 @@ int main(int argc, char** argv)
.download = nsgtk_download_table,
.fetch = nsgtk_fetch_table,
.search = nsgtk_search_table,
+ .llcache = filesystem_llcache_table,
};
/* build the common resource path list */
@@ -1199,9 +1302,20 @@ int main(int argc, char** argv)
/* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
+ /* Locate the correct user cache directory path */
+ ret = get_cache_home(&cache_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no cache directory exists yet so try to create one */
+ ret = create_cache_home(&cache_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG(("Unable to locate a cache directory."));
+ }
+
/* core initialisation */
- ret = netsurf_init(messages, NULL, &nsgtk_gui_table);
+ ret = netsurf_init(messages, cache_home, &nsgtk_gui_table);
free(messages);
+ free(cache_home);
if (ret != NSERROR_OK) {
fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
messages_get_errorcode(ret));
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=f45ef2d60c25c8be656...
commit f45ef2d60c25c8be656d8ccd9e9b1e3b4840ce53
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
add backing store storage path to browser initialisation
diff --git a/amiga/gui.c b/amiga/gui.c
index ed96676..8a1cb5e 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -5191,7 +5191,7 @@ int main(int argc, char** argv)
if (ami_locate_resource(messages, "Messages") == false)
die("Cannot open Messages file");
- ret = netsurf_init(messages, &amiga_gui_table);
+ ret = netsurf_init(messages, NULL, &amiga_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/atari/gui.c b/atari/gui.c
index 4e077bd..66a665e 100644
--- a/atari/gui.c
+++ b/atari/gui.c
@@ -1147,7 +1147,7 @@ int main(int argc, char** argv)
/* common initialisation */
LOG(("Initialising core..."));
- ret = netsurf_init(messages, &atari_gui_table);
+ ret = netsurf_init(messages, NULL, &atari_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/beos/gui.cpp b/beos/gui.cpp
index 365a356..6f08298 100644
--- a/beos/gui.cpp
+++ b/beos/gui.cpp
@@ -1097,7 +1097,7 @@ int main(int argc, char** argv)
/* common initialisation */
BPath messages = get_messages_path();
- ret = netsurf_init(messages.Path(), &beos_gui_table);
+ ret = netsurf_init(messages.Path(), NULL, &beos_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
@@ -1145,7 +1145,7 @@ int gui_init_replicant(int argc, char** argv)
/* common initialisation */
BPath messages = get_messages_path();
- ret = netsurf_init(messages.Path(), &beos_gui_table);
+ ret = netsurf_init(messages.Path(), NULL, &beos_gui_table);
if (ret != NSERROR_OK) {
// FIXME: must not die when in replicant!
die("NetSurf failed to initialise");
diff --git a/cocoa/NetsurfApp.m b/cocoa/NetsurfApp.m
index cab06a6..e31fc2a 100644
--- a/cocoa/NetsurfApp.m
+++ b/cocoa/NetsurfApp.m
@@ -213,7 +213,7 @@ int main( int argc, char **argv )
nsoption_commandline(&argc, argv, NULL);
/* common initialisation */
- error = netsurf_init(messages, &cocoa_gui_table);
+ error = netsurf_init(messages, NULL, &cocoa_gui_table);
if (error != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index f759029..a2eea08 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -124,7 +124,8 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query,
* Initialise components used by gui NetSurf.
*/
-nserror netsurf_init(const char *messages, struct gui_table *gt)
+nserror
+netsurf_init(const char *messages, const char *store_path, struct gui_table *gt)
{
nserror ret;
struct utsname utsname;
@@ -198,8 +199,7 @@ nserror netsurf_init(const char *messages, struct gui_table *gt)
hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;;
/* set the path to the backing store */
- /** \todo set the backing store path properly */
- hlcache_parameters.llcache.store.path = "/tmp/ns";
+ hlcache_parameters.llcache.store.path = store_path;
/* image handler bitmap cache */
ret = image_cache_init(&image_cache_parameters);
diff --git a/desktop/netsurf.h b/desktop/netsurf.h
index 77589c7..62e7c0f 100644
--- a/desktop/netsurf.h
+++ b/desktop/netsurf.h
@@ -30,7 +30,7 @@ extern const int netsurf_version_minor;
struct gui_table;
/** Initialise netsurf core */
-nserror netsurf_init(const char *messages, struct gui_table *gt);
+nserror netsurf_init(const char *messages, const char *store_path, struct gui_table *gt);
/** Run primary event loop */
extern int netsurf_main_loop(void);
diff --git a/framebuffer/gui.c b/framebuffer/gui.c
index 7d3e95c..479a175 100644
--- a/framebuffer/gui.c
+++ b/framebuffer/gui.c
@@ -1832,7 +1832,7 @@ main(int argc, char** argv)
/* common initialisation */
messages = filepath_find(respaths, "Messages");
- ret = netsurf_init(messages, &framebuffer_gui_table);
+ ret = netsurf_init(messages, NULL, &framebuffer_gui_table);
free(messages);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
diff --git a/gtk/gui.c b/gtk/gui.c
index 1c108a1..737b8e6 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -1200,7 +1200,7 @@ int main(int argc, char** argv)
messages = filepath_find(respaths, "Messages");
/* core initialisation */
- ret = netsurf_init(messages, &nsgtk_gui_table);
+ ret = netsurf_init(messages, NULL, &nsgtk_gui_table);
free(messages);
if (ret != NSERROR_OK) {
fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
diff --git a/monkey/main.c b/monkey/main.c
index 96476d2..004ebae 100644
--- a/monkey/main.c
+++ b/monkey/main.c
@@ -151,7 +151,7 @@ main(int argc, char **argv)
/* common initialisation */
messages = filepath_find(respaths, "Messages");
- ret = netsurf_init(messages, &monkey_gui_table);
+ ret = netsurf_init(messages, NULL, &monkey_gui_table);
free(messages);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
diff --git a/riscos/gui.c b/riscos/gui.c
index db57ff6..a4deca7 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -2439,7 +2439,7 @@ int main(int argc, char** argv)
}
/* common initialisation */
- ret = netsurf_init(path, &riscos_gui_table);
+ ret = netsurf_init(path, NULL, &riscos_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/windows/main.c b/windows/main.c
index 19cd44a..b7066a6 100644
--- a/windows/main.c
+++ b/windows/main.c
@@ -160,7 +160,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
/* common initialisation */
messages = filepath_find(respaths, "messages");
- ret = netsurf_init(messages, &win32_gui_table);
+ ret = netsurf_init(messages, NULL, &win32_gui_table);
free(messages);
if (ret != NSERROR_OK) {
free(options_file_location);
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=561baea10a1b4d26bc9...
commit 561baea10a1b4d26bc9ce0ceb86c3185dddea634
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Add filesystem based backing store
diff --git a/Docs/source-object-backing-store b/Docs/source-object-backing-store
new file mode 100644
index 0000000..e55a99d
--- /dev/null
+++ b/Docs/source-object-backing-store
@@ -0,0 +1,194 @@
+Source Object (low level) cache backing store
+=============================================
+
+Introduction
+------------
+
+The source object cache provides a system to extend the life of source
+objects (html files, images etc.) after they are no longer immediately
+being used.
+
+Only fetch types where we have well defined rules on caching are
+considered, in practice this limits us to HTTP(S). The section in
+RFC2616 [1] on caching specifies these rules.
+
+To futher extend the objects lifetime they can be pushed into a
+backing store where the objects are available for reuse less quickly
+than from RAM but faster than retriving from the network again.
+
+The backing store implementation provides a key:value infrastructure
+with a simple store, retrive and invalidate interface.
+
+Generic filesystem backing store
+--------------------------------
+
+Although the backing store interface is fully pluggable a generic
+implementation based on storing objects on the filesystem in a
+heirachy of directories.
+
+The option to alter the backing store format exists and is controled
+by a version field. It is implementation defined what happens if a
+version mis-match occours.
+
+As the backing store only holds cache data one should not expect a
+great deal of effort to be expended converting formats (i.e. the cache
+may simply be discarded).
+
+Layout version 1
+----------------
+
+An object has an identifier value generated from the url (NetSurf
+backing stores uses the url as the unique key). The value used is
+obtained using nsurl_hash() which is currently a 32 bit FNV so is
+directly usable.
+
+This identifier is adequate to ensure the collision rate for the
+hashed url values (a collision for every 2^16 urls added) is
+sufficiently low the overhead of returning the wrong object (which
+backing stores are permitted to do) is not significat.
+
+An entry list is maintained which contains all the metadata about a
+given identifier. This list is limited in length to constrain the
+resources necessary to maintain it. It is made persistant to avoid the
+overhead of reconstructing it at initialisation and to keep the data
+used to improve the eviction decisions.
+
+Each object is stored and retrived directly into the filesystem using
+a filename generated from a base64url encoding of an address
+value. The objects address is derived from the identifier by cropping
+it to a shorter length.
+
+A mapping between the object address and its entry is maintained which
+uses storage directly proportional to the size of the address length.
+
+The cropping length is stored in the control file with the default
+values set at compile time. This allows existing backing stores to
+continue operating with existing data independantly of new default
+setting. This setting gives some ability to tune the default cache
+index size to values suitable for a specific host operating system.
+
+E.g. Linux based systems can easily cope with several megabytes of
+mmaped index but RISC OS might want to limit this to a few megabytes
+of heap at most.
+
+The files are stored on disc using their base64url address value.
+By creating a directory for each character of the encoded filename
+(except the last which is of course the leafname) we create a
+directory structure where no directory has more than 64 entries.
+
+E.g. A 19bit address of 0x1 would be base64url encoded into AAAB
+resulting in the data being stored in a file path of
+"/store/prefix/data/B/A/A/BAAAAA".
+
+An address of 0x00040001 encodes to BAAB and a file path of
+"/store/prefix/meta/B/A/A/BAABAA"
+
+Control files
+~~~~~~~~~~~~~
+
+control
++++++++
+A control file is used to hold a list of values describing how the
+other files in the backing store should be used.
+
+entries
++++++++
+
+this file contains a table of entries describing the files held on the
+filesystem.
+
+Each control file table entry is 28 bytes and consists of
+
+ - signed 64 but value for last use time
+
+ - 32bit full url hash allowing for index reconstruction and
+ addiitonal collision detection. Also the possibility of increasing
+ the ADDRESS_LENGTH although this would require renaming all the
+ existing files in the cache and is not currently implemented.
+
+ - unsigned 32bit length for data
+
+ - unsigned 32bit length for metadata
+
+ - unsigned 16bit value for number of times used.
+
+ - unsigned 16bit value for flags
+
+ - unsigned 16bit value for data block index (unused)
+
+ - unsigned 16bit value for metatdata block index (unused)
+
+Address to entry index
+~~~~~~~~~~~~~~~~~~~~~~
+
+An entry index is held in RAM that allows looking up the address to
+map to an entry in the control file.
+
+The index is the only data structure whose size is directly depndant
+on the length of the hash specificaly:
+
+(2 ^ (ADDRESS_BITS - 3)) * ENTRY_BITS) in bytes
+
+where ADDRESS_BITS is how long the address is in bits and ENTRY_BITS
+is how many entries the control file (and hence the while
+cache) may hold.
+
+RISCOS values
++++++++++++++
+
+By limiting the ENTRY_BITS size to 14 (16,384 entries) the entries
+list is limited to 448kilobytes.
+
+The typical values for RISC OS would set ADDRESS_BITS to 18. This
+spreads the entries over 262144 hash values which uses 512 kilobytes
+for the index. Limiting the hash space like this reduces the
+efectiveness of the cache.
+
+A small ADDRESS_LENGTH causes a collision (two urls with the same
+address) to happen roughly for every 2 ^ (ADDRESS_BITS / 2) = 2 ^ 9 =
+512 objects stored. This roughly translates to a cache miss due to
+collision every ten pages navigated to.
+
+Larger systems
+++++++++++++++
+
+In general ENTRY_BITS set to 16 as this limits the store to 65536
+objects which given the average size of an object at 8 kilobytes
+yeilds half a gigabyte of disc used which is judged to be sufficient.
+
+For larger systems e.g. those using GTK frontend we would most likely
+select ADDRESS_BITS as 22 resulting in a collision every 2048 objects
+but the index using some 8 Megabytes
+
+Typical values
+--------------
+
+Example 1
+~~~~~~~~~
+
+For a store with 1034 objects genrated from a random navigation of
+pages linked from the about:welcome page.
+
+Metadata total size is 593608 bytes an average of 574 bytes. The
+majority of the storage is used to hold the urls and headers.
+
+Data total size is 9180475 bytes a mean of 8879 bytes 1648726 in the
+largest 10 entries which if excluded gives 7355 bytes average size
+
+Example 2
+~~~~~~~~~
+
+355 pages navigated in 80 minutes from about:welcome page and a
+handful of additional sites (google image search and reddit)
+
+2018 objects in cache at quit. 400 objects from news.bbc.co.uk alone
+
+Metadata total 987,439 bytes mean of 489 bytes
+
+data total 33,127,831 bytes mean of 16,416 bytes
+
+with one single 5,000,811 byte gif
+
+data totals without gif is 28,127,020 mean 13,945
+
+[1] http://tools.ietf.org/html/rfc2616#section-13
\ No newline at end of file
diff --git a/Makefile.defaults b/Makefile.defaults
index e11fa1f..9779331 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -86,6 +86,11 @@ NETSURF_HOMEPAGE := "about:welcome"
# Valid options: YES, NO
NETSURF_USE_LIBICONV_PLUG := YES
+# Enable building the source object cache filesystem based backing store.
+# implementation.
+# Valid options: YES, NO
+NETSURF_FS_BACKING_STORE := NO
+
# Initial CFLAGS. Optimisation level etc. tend to be target specific.
CFLAGS :=
diff --git a/content/Makefile b/content/Makefile
index 6482f30..ab257ea 100644
--- a/content/Makefile
+++ b/content/Makefile
@@ -3,4 +3,9 @@
S_CONTENT := content.c content_factory.c dirlist.c fetch.c hlcache.c \
llcache.c mimesniff.c urldb.c no_backing_store.c
+# Make filesystem backing store available
+ifeq ($(NETSURF_FS_BACKING_STORE),YES)
+ S_CONTENT += fs_backing_store.c
+endif
+
S_CONTENT := $(addprefix content/,$(S_CONTENT))
diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c
new file mode 100644
index 0000000..7a715f9
--- /dev/null
+++ b/content/fs_backing_store.c
@@ -0,0 +1,1194 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache persistent storage implementation.
+ *
+ * file based backing store.
+ *
+ * \todo Consider improving eviction sorting to include objects size
+ * and remaining lifetime and other cost metrics.
+ *
+ * \todo make backing store have a more efficient small object storage.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "utils/filepath.h"
+#include "utils/nsurl.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "desktop/gui.h"
+
+#include "content/backing_store.h"
+
+#define ADDRESS_BITS 18 /** default number of bits of the ident to use in index hash */
+#define ENTRY_BITS 14 /** default number of bits to use for an entry index. */
+
+#define CONTROL_VERSION 100 /** backing store file format version */
+
+/** get address from ident */
+#define BS_ADDRESS(ident, state) ((ident) & ((1 << state->addr_bits) - 1))
+
+/** lookup store entry index from ident */
+#define BS_ENTRY_INDEX(ident, state) state->addrmap[(ident) & ((1 << state->addr_bits) - 1)]
+
+/** get store entry from ident. */
+#define BS_ENTRY(ident, state) state->entries[state->addrmap[(ident) & ((1 << state->addr_bits) - 1)]]
+
+enum store_entry_flags {
+ STORE_ENTRY_FLAG_NONE = 0,
+};
+
+/**
+ * The type used to store index values refering to store entries. Care
+ * must be taken with this type as it is used to build address to
+ * entry mapping so changing the size will have large impacts on
+ * memory usage.
+ */
+typedef uint16_t entry_index_t;
+
+/**
+ * The type used as a binary identifier for each entry derived from
+ * the url. A larger identifier will have fewer collisions but
+ * requires proportionately more storage.
+ */
+typedef uint32_t entry_ident_t;
+
+/**
+ * Backing store object index entry.
+ *
+ * @note Order is important to avoid structure packing overhead.
+ */
+struct store_entry {
+ int64_t last_used; /**< unix time the entry was last used */
+ entry_ident_t ident; /**< entry identifier */
+ uint32_t data_alloc; /**< currently allocated size of data on disc */
+ uint32_t meta_alloc; /**< currently allocated size of metadata on disc */
+ uint16_t use_count; /**< number of times this entry has been accessed */
+ uint16_t flags; /**< entry flags (unused) */
+ uint16_t data_block; /**< small object data block entry (unused) */
+ uint16_t meta_block; /**< small object meta block entry (unused) */
+};
+
+/**
+ * Parameters controlling the backing store.
+ */
+struct store_state {
+ char *path; /**< The path to the backing store */
+ size_t limit; /**< The backing store upper bound target size */
+ size_t hysteresis; /**< The hysteresis around the target size */
+
+ unsigned int addr_bits; /**< log2 number of bits to use for address. */
+
+ struct store_entry *entries; /**< store entries. */
+ unsigned int entry_bits; /**< log2 number of bits in entry index. */
+ unsigned int last_entry; /**< index of last usable entry. */
+ bool entries_dirty; /**< flag indicating if the entries have been made persistant since they were last changed. */
+
+ entry_index_t *addrmap; /**< address to entry index mapping. */
+
+ uint64_t total_alloc; /**< total size of all allocated storage. */
+};
+
+/**
+ * Global storage state.
+ *
+ * @todo Investigate if there is a way to have a context rather than
+ * use a global.
+ */
+struct store_state *storestate;
+
+/** Base64url encoding table */
+static uint8_t encoding_table[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_'
+};
+
+#ifdef FULL_BASE64_ENCODE
+static unsigned int mod_table[] = {0, 2, 1};
+
+static uint8_t *
+base64url_encode(const char *data,
+ size_t input_length,
+ size_t *output_length)
+{
+ uint8_t *encoded_data;
+ size_t i;
+ size_t j;
+
+ *output_length = 4 * ((input_length + 2) / 3);
+
+ encoded_data = malloc(*output_length + 1);
+ if (encoded_data == NULL) {
+ return NULL;
+ }
+
+ for (i = 0, j = 0; i < input_length;) {
+
+ uint32_t octet_a = i < input_length ? data[i++] : 0;
+ uint32_t octet_b = i < input_length ? data[i++] : 0;
+ uint32_t octet_c = i < input_length ? data[i++] : 0;
+
+ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+ encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
+ }
+
+ for (i = 0; i < mod_table[input_length % 3]; i++) {
+ encoded_data[*output_length - 1 - i] = 0;
+ (*output_length)--;
+ }
+
+ return encoded_data;
+}
+
+#endif
+
+/**
+ * Remove a backing store entry from the entry table.
+ *
+ * This finds the store entry associated with the given key and
+ * removes it from the table. The removed entry is returned but is
+ * only valid until the next set_store_entry call.
+ *
+ * @param state The store state to use.
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on succes or NSERROR_NOT_FOUND
+ * if no entry coresponds to the url.
+ */
+static nserror
+remove_store_entry(struct store_state *state,
+ entry_ident_t ident,
+ struct store_entry **bse)
+{
+ entry_index_t sei; /* store entry index */
+
+ sei = BS_ENTRY_INDEX(ident, state);
+ if (sei == 0) {
+ LOG(("ident 0x%08x not in index", ident));
+ return NSERROR_NOT_FOUND;
+ }
+
+ if (state->entries[sei].ident != ident) {
+ /* entry ident did not match */
+ LOG(("ident 0x%08x did not match entry index %d", ident, sei));
+ return NSERROR_NOT_FOUND;
+ }
+
+ /* sei is entry to be removed, we swap it to the end of the
+ * table so there are no gaps and the returned entry is held
+ * in storage with reasonable lifetime.
+ */
+
+ /* remove entry from map */
+ BS_ENTRY_INDEX(ident, state) = 0;
+
+ /* global allocation accounting */
+ state->total_alloc -= state->entries[sei].data_alloc;
+ state->total_alloc -= state->entries[sei].meta_alloc;
+
+ state->last_entry--;
+
+ if (sei == state->last_entry) {
+ /* the removed entry was the last one, how conveniant */
+ *bse = &state->entries[sei];
+ } else {
+ /* need to swap entries */
+ struct store_entry tent;
+
+ tent = state->entries[sei];
+ state->entries[sei] = state->entries[state->last_entry];
+ state->entries[state->last_entry] = tent;
+
+ /* update map for moved entry */
+ BS_ENTRY_INDEX(state->entries[sei].ident, state) = sei;
+
+ *bse = &state->entries[state->last_entry];
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Generate a filename for an object.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier to use.
+ * @return The filename string or NULL on allocation error.
+ */
+static char *
+store_fname(struct store_state *state,
+ entry_ident_t ident,
+ enum backing_store_flags flags)
+{
+ int fname_len;
+ char *fname;
+ uint8_t b64u_i[7];
+ const char *dat;
+
+ /* base64 encode ident */
+ b64u_i[0] = encoding_table[(ident ) & 0x3f];
+ b64u_i[1] = encoding_table[(ident >> 6) & 0x3f];
+ b64u_i[2] = encoding_table[(ident >> 12) & 0x3f];
+ b64u_i[3] = encoding_table[(ident >> 18) & 0x3f];
+ b64u_i[4] = encoding_table[(ident >> 24) & 0x3f];
+ b64u_i[5] = encoding_table[(ident >> 30) & 0x3f];
+ b64u_i[6] = 0;
+
+ if ((flags & BACKING_STORE_META) != 0) {
+ dat = "meta";
+ } else {
+ dat = "data";
+ }
+
+ fname_len = strlen(state->path) + 32;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NULL;
+ }
+
+ /* number of chars with usefully encoded data in b64 */
+ switch(((state->addr_bits + 5) / 6)) {
+ case 1:
+ snprintf(fname, fname_len,
+ "%s/%s/%s",
+ state->path,
+ dat,
+ b64u_i);
+ break;
+
+ case 2:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i);
+ break;
+
+ case 3:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i);
+ break;
+
+ case 4:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i);
+ break;
+
+ case 5:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i[3],
+ b64u_i);
+ break;
+
+ case 6:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i[3],
+ b64u_i[4],
+ b64u_i);
+ break;
+
+ default:
+ assert(false);
+ }
+
+ return fname;
+}
+
+
+/**
+ * Remove the entry and files associated with an identifier.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier to use.
+ * @return NSERROR_OK on sucess or error code on failure.
+ */
+static nserror
+unlink_ident(struct store_state *state, entry_ident_t ident)
+{
+ char *fname;
+ nserror ret;
+ struct store_entry *bse;
+
+ /* LOG(("ident %08x", ident)); */
+
+ /* use the url hash as the entry identifier */
+ ret = remove_store_entry(state, ident, &bse);
+ if (ret != NSERROR_OK) {
+ /* LOG(("entry not found")); */
+ return ret;
+ }
+
+ fname = store_fname(state, bse->ident, BACKING_STORE_META);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ unlink(fname);
+ free(fname);
+
+ fname = store_fname(state, bse->ident, BACKING_STORE_NONE);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ unlink(fname);
+ free(fname);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Quick sort comparison.
+ */
+static int compar(const void *va, const void *vb)
+{
+ const struct store_entry *a = &BS_ENTRY(*(entry_ident_t *)va, storestate);
+ const struct store_entry *b = &BS_ENTRY(*(entry_ident_t *)vb, storestate);
+
+ if (a->use_count < b->use_count) {
+ return -1;
+ } else if (a->use_count > b->use_count) {
+ return 1;
+ }
+ /* use count is the same - now consider last use time */
+
+ if (a->last_used < b->last_used) {
+ return -1;
+ } else if (a->last_used > b->last_used) {
+ return 1;
+ }
+
+ /* they are the same */
+ return 0;
+}
+
+
+/**
+ * Evict entries from backing store as per configuration.
+ *
+ * Entries are evicted to ensure the cache remains within the
+ * configured limits on size and number of entries.
+ *
+ * The approach is to check if the cache limits have been exceeded and
+ * if so build and sort list of entries to evict. The list is sorted
+ * by use count and then by age, so oldest object with least number of uses
+ * get evicted first.
+ *
+ * @param state The store state to use.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+static nserror store_evict(struct store_state *state)
+{
+ entry_ident_t *elist; /* sorted list of entry identifiers */
+ unsigned int ent;
+ unsigned int ent_count;
+ size_t removed; /* size of removed entries */
+ nserror ret = NSERROR_OK;
+
+ /* check if the cache has exceeded configured limit */
+ if ((state->total_alloc < state->limit) &&
+ (state->last_entry < (1U << state->entry_bits))) {
+ /* cache within limits */
+ return NSERROR_OK;
+ }
+
+ LOG(("Evicting entries to reduce %d by %d",
+ state->total_alloc, state->hysteresis));
+
+ /* allocate storage for the list */
+ elist = malloc(sizeof(entry_ident_t) * state->last_entry);
+ if (elist == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* sort the list avoiding entry 0 which is the empty sentinel */
+ for (ent = 1; ent < state->last_entry; ent++) {
+ elist[ent - 1] = state->entries[ent].ident;
+ }
+ ent_count = ent - 1; /* important to keep this as the entry count will change when entries are removed */
+ qsort(elist, ent_count, sizeof(entry_ident_t), compar);
+
+ /* evict entries in listed order */
+ removed = 0;
+ for (ent = 0; ent < ent_count; ent++) {
+
+ removed += BS_ENTRY(elist[ent], state).data_alloc;
+ removed += BS_ENTRY(elist[ent], state).meta_alloc;
+
+ ret = unlink_ident(state, elist[ent]);
+ if (ret != NSERROR_OK) {
+ break;
+ }
+
+ if (removed > state->hysteresis) {
+ break;
+ }
+ }
+
+ free(elist);
+
+ LOG(("removed %d in %d entries", removed, ent));
+
+ return ret;
+}
+
+
+/**
+ * Lookup a backing store entry in the entry table from a url.
+ *
+ * This finds the store entry associated with the given
+ * key. Additionally if an entry is found it updates the usage data
+ * about the entry.
+ *
+ * @param state The store state to use.
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on success or NSERROR_NOT_FOUND
+ * if no entry corresponds to the url.
+ */
+static nserror
+get_store_entry(struct store_state *state, nsurl *url, struct store_entry **bse)
+{
+ entry_ident_t ident;
+ unsigned int sei; /* store entry index */
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ /* use the url hash as the entry identifier */
+ ident = nsurl_hash(url);
+
+ sei = BS_ENTRY_INDEX(ident, state);
+
+ if (sei == 0) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ if (state->entries[sei].ident != ident) {
+ /* entry ident did not match */
+ LOG(("ident did not match entry"));
+ return NSERROR_NOT_FOUND;
+ }
+
+ *bse = &state->entries[sei];
+
+ state->entries[sei].last_used = time(NULL);
+ state->entries[sei].use_count++;
+
+ state->entries_dirty = true;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Set a backing store entry in the entry table from a url.
+ *
+ * This creates a backing store entry in the entry table for a url.
+ *
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on succes or NSERROR_NOT_FOUND
+ * if no entry coresponds to the url.
+ */
+static nserror
+set_store_entry(struct store_state *state,
+ nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen,
+ struct store_entry **bse)
+{
+ entry_ident_t ident;
+ entry_index_t sei; /* store entry index */
+ struct store_entry *se;
+ nserror ret;
+ bool isrep; /* is the store repalcing an existing entry or not */
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ /* evict entries as required and ensure there is at least one
+ * new entry available.
+ */
+ ret = store_evict(state);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* use the url hash as the entry identifier */
+ ident = nsurl_hash(url);
+
+ sei = BS_ENTRY_INDEX(ident, state);
+
+ /** @todo Should this deal with cache eviction? */
+
+ if (sei == 0) {
+ /* allocating the next available entry */
+ sei = state->last_entry;
+ state->last_entry++;
+ BS_ENTRY_INDEX(ident, state) = sei;
+ isrep = false;
+ } else {
+ /* updating or replacing existing entry */
+ /** @todo should we be checking the entry ident
+ * matches the url. Thats a collision in the address
+ * mapping right? and is it important?
+ */
+ isrep = true;
+ }
+
+ se = &state->entries[sei];
+
+ se->ident = ident;
+ se->flags = STORE_ENTRY_FLAG_NONE;
+ se->use_count = 1;
+ se->last_used = time(NULL);
+
+ /* account for allocation */
+ if ((flags & BACKING_STORE_META) != 0) {
+ if (isrep) {
+ state->total_alloc -= se->meta_alloc;
+ } else {
+ se->data_alloc = 0;
+ }
+ se->meta_alloc = datalen;
+ } else {
+ if (isrep) {
+ state->total_alloc -= se->data_alloc;
+ } else {
+ se->meta_alloc = 0;
+ }
+ se->data_alloc = datalen;
+ }
+ state->total_alloc += datalen;
+
+ state->entries_dirty = true;
+
+ *bse = se;
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Open a file using a store ident.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier of the file to open.
+ * @param flags The backing store flags.
+ * @pram openflags The flags used with the open call.
+ * @return An fd from the open call or -1 on error.
+ */
+static int
+store_open(struct store_state *state,
+ uint32_t ident,
+ enum backing_store_flags flags,
+ int openflags)
+{
+ char *fname;
+ nserror ret;
+ int fd;
+
+ fname = store_fname(state, ident, flags);
+ if (fname == NULL) {
+ LOG(("filename error"));
+ return -1;
+ }
+
+ /* ensure path to file is usable */
+ ret = filepath_mkdir_all(fname);
+ if (ret != NSERROR_OK) {
+ LOG(("file path \"%s\" could not be created", fname));
+ free(fname);
+ return -1;
+ }
+
+ LOG(("opening %s", fname));
+ fd = open(fname, openflags, S_IRUSR | S_IWUSR);
+
+ free(fname);
+
+ return fd;
+}
+
+/**
+ * Construct address ident to filesystem entry map
+ *
+ * To allow a filesystem entry to be found from it's identifier we
+ * construct an mapping index. This is a hash map from the entries URL
+ * (its unique key) to filesystem entry.
+ *
+ * As the entire entry list must be iterated over to construct the map
+ * we also compute the total storage in use.
+ *
+ * @param state The backing store global state.
+ * @return NSERROR_OK on sucess or NSERROR_NOMEM if the map storage
+ * could not be allocated.
+ */
+static nserror
+build_entrymap(struct store_state *state)
+{
+ unsigned int eloop;
+
+ state->addrmap = calloc(1<<state->addr_bits, sizeof(entry_index_t));
+ if (state->addrmap == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ state->total_alloc = 0;
+
+ for (eloop = 1; eloop < state->last_entry; eloop++) {
+ LOG(("entry:%d ident:0x%08x used:%d",
+ eloop,
+ BS_ADDRESS(state->entries[eloop].ident, state),
+ state->entries[eloop].use_count));
+
+ /* update the address map to point at the entry */
+ BS_ENTRY_INDEX(state->entries[eloop].ident, state) = eloop;
+
+ /* account for the storage space */
+ state->total_alloc += state->entries[eloop].data_alloc +
+ state->entries[eloop].meta_alloc;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Write filesystem entries to file.
+ *
+ * @param state The backing store state to read the entries from.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror write_entries(struct store_state *state)
+{
+ int fd;
+ int fname_len;
+ char *fname;
+
+ if (state->entries_dirty == false) {
+ /* entries have not been updated since last write */
+ return NSERROR_OK;
+ }
+
+ /* entries file name string */
+ fname_len = strlen(state->path) + 11;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(fname, fname_len, "%s/entries", state->path);
+
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ free(fname);
+ if (fd == -1) {
+ return NSERROR_SAVE_FAILED;
+ }
+
+ write(fd, state->entries, state->last_entry * sizeof(struct store_entry));
+ close(fd);
+
+
+ return NSERROR_OK;
+}
+
+/**
+ * Read description entries into memory.
+ *
+ * @param state The backing store state to put the loaded entries in.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+read_entries(struct store_state *state)
+{
+ int fd;
+ ssize_t rd;
+ size_t entries_size;
+ int fname_len;
+ char *fname;
+
+ /* entries file name string */
+ fname_len = strlen(state->path) + 11;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(fname, fname_len, "%s/entries", state->path);
+
+ entries_size = (1 << state->entry_bits) * sizeof(struct store_entry);
+
+ LOG(("Allocating %d bytes", entries_size));
+
+ state->entries = calloc(1, entries_size);
+ if (state->entries == NULL) {
+ free(fname);
+ return NSERROR_NOMEM;
+ }
+
+ fd = open(fname, O_RDWR);
+ free(fname);
+ if (fd != -1) {
+ rd = read(fd, state->entries, entries_size);
+ close(fd);
+ if (rd > 0) {
+ state->last_entry = rd / sizeof(struct store_entry);
+ LOG(("Read %d entries", state->last_entry));
+ }
+ } else {
+ /* could rebuild entries from fs */
+ state->last_entry = 1;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Write the control file for the current state.
+ *
+ * @param state The state to write to the control file.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+write_control(struct store_state *state)
+{
+ FILE *fcontrol;
+ nserror ret;
+ char *fname;
+
+ /* read control file */
+ fname = filepath_append(state->path, "control");
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ ret = filepath_mkdir_all(fname);
+ if (ret != NSERROR_OK) {
+ free(fname);
+ return ret;
+ }
+
+ fcontrol = fopen(fname, "wb");
+
+ free(fname);
+
+ if (fcontrol == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ fprintf(fcontrol, "%u%c", CONTROL_VERSION, 0);
+ fprintf(fcontrol, "%u%c", state->entry_bits, 0);
+ fprintf(fcontrol, "%u%c", state->addr_bits, 0);
+ fprintf(fcontrol, "%u%c", state->last_entry, 0);
+
+ fclose(fcontrol);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Read and parse the control file.
+ *
+ * @param state The state to read from the control file.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+read_control(struct store_state *state)
+{
+ FILE *fcontrol;
+ unsigned int ctrlversion;
+ unsigned int addrbits;
+ unsigned int entrybits;
+ char *fname;
+
+ /* open control file */
+ fname = filepath_append(state->path, "control");
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ fcontrol = fopen(fname, "rb");
+
+ free(fname);
+
+ if (fcontrol == NULL) {
+ /* unable to open control file */
+ if (errno == ENOENT) {
+ return NSERROR_NOT_FOUND;
+ } else {
+ return NSERROR_INIT_FAILED;
+ }
+ }
+
+ /* read control and setup new state */
+
+ /* first line is version */
+ if (fscanf(fcontrol, "%u", &ctrlversion) != 1) {
+ goto control_error;
+ }
+
+ if (ctrlversion != CONTROL_VERSION) {
+ goto control_error;
+ }
+
+ /* second line is log2 max number of entries */
+ if (fscanf(fcontrol, "%u", &entrybits) != 1) {
+ goto control_error;
+ }
+
+ /* second line is log2 size of address hash */
+ if (fscanf(fcontrol, "%u", &addrbits) != 1) {
+ goto control_error;
+ }
+
+ fclose(fcontrol);
+
+ state->entry_bits = entrybits;
+ state->addr_bits = addrbits;
+
+ return NSERROR_OK;
+
+control_error: /* problem with the control file */
+
+ fclose(fcontrol);
+
+ return NSERROR_INIT_FAILED;
+}
+
+
+
+
+/* Functions exported in the backing store table */
+
+/**
+ * Initialise the backing store.
+ *
+ * @param parameters to configure backing store.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+initialise(const struct llcache_store_parameters *parameters)
+{
+ struct store_state *newstate;
+ nserror ret;
+
+ /* check backing store is not already initialised */
+ if (storestate != NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ /* if we are not allowed any space simply give up on init */
+ if (parameters->limit == 0) {
+ return NSERROR_OK;
+ }
+
+ /* if the path to the cache directory is not set do not init */
+ if (parameters->path == NULL) {
+ return NSERROR_OK;
+ }
+
+ /* allocate new store state and set defaults */
+ newstate = calloc(1, sizeof(struct store_state));
+ if (newstate == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ newstate->path = strdup(parameters->path);
+ newstate->limit = parameters->limit;
+ newstate->hysteresis = parameters->hysteresis;
+ newstate->addr_bits = ADDRESS_BITS;
+ newstate->entry_bits = ENTRY_BITS;
+
+ ret = read_control(newstate);
+ if (ret != NSERROR_OK) {
+ ret = write_control(newstate);
+ }
+ if (ret != NSERROR_OK) {
+ /* that went well obviously */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ /* ensure the maximum number of entries can be represented in
+ * the type available to store it.
+ */
+ if (newstate->entry_bits > (8 * sizeof(entry_index_t))) {
+ newstate->entry_bits = (8 * sizeof(entry_index_t));
+ }
+
+ /* read filesystem entries */
+ ret = read_entries(newstate);
+ if (ret != NSERROR_OK) {
+ /* that went well obviously */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ /* build entry hash map */
+ ret = build_entrymap(newstate);
+ if (ret != NSERROR_OK) {
+ /* that obviously went well */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ storestate = newstate;
+
+ LOG(("FS backing store init successful"));
+
+ LOG(("path:%s limit:%d hyst:%d addr:%d entries:%d", newstate->path, newstate->limit, newstate->hysteresis, newstate->addr_bits, newstate->entry_bits));
+ LOG(("Using %d/%d", newstate->total_alloc, newstate->limit));
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Finalise the backing store.
+ *
+ * @return NSERROR_OK on success.
+ */
+static nserror
+finalise(void)
+{
+ if (storestate != NULL) {
+ write_entries(storestate);
+
+ free(storestate->path);
+ free(storestate);
+ storestate = NULL;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Place an object in the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the object is stored.
+ * @param data The objects source data.
+ * @param datalen The length of the \a data.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+store(nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen)
+{
+ nserror ret;
+ struct store_entry *bse;
+ int fd;
+
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ /* set the store entry up */
+ ret = set_store_entry(storestate, url, flags, data, datalen, &bse);
+ if (ret != NSERROR_OK) {
+ LOG(("store entry setting failed"));
+ return ret;
+ }
+
+ fd = store_open(storestate, bse->ident, flags, O_CREAT | O_WRONLY);
+ if (fd < 0) {
+ perror("");
+ LOG(("Open failed %d",fd));
+ return NSERROR_SAVE_FAILED;
+ }
+
+ LOG(("Writing %d bytes from %p", datalen, data));
+ write(fd, data, datalen);
+
+ close(fd);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrive an object from the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the object is stored.
+ * @param data The objects data.
+ * @param datalen The length of the \a data retrieved.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+fetch(nsurl *url,
+ enum backing_store_flags *flags,
+ uint8_t **data_out,
+ size_t *datalen_out)
+{
+ nserror ret;
+ struct store_entry *bse;
+ uint8_t *data;
+ size_t datalen;
+ int fd;
+ ssize_t rd;
+
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ ret = get_store_entry(storestate, url, &bse);
+ if (ret != NSERROR_OK) {
+ LOG(("entry not found"));
+ return ret;
+ }
+
+ LOG(("retriving cache file for url:%s", nsurl_access(url)));
+
+ fd = store_open(storestate, bse->ident, *flags, O_RDONLY);
+ if (fd < 0) {
+ LOG(("Open failed"));
+ /** @todo should this invalidate the entry? */
+ return NSERROR_NOT_FOUND;
+ }
+
+ data = *data_out;
+ datalen = *datalen_out;
+
+ /* need to deal with buffers */
+ if (data == NULL) {
+ if (datalen == 0) {
+ /* caller did not know the files length */
+ if (((*flags) & BACKING_STORE_META) != 0) {
+ datalen = bse->meta_alloc;
+ } else {
+ datalen = bse->data_alloc;
+ }
+ }
+
+ data = malloc(datalen);
+ if (data == NULL) {
+ close(fd);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /** @todo should this check datalen is sufficient */
+
+ LOG(("Reading %d bytes into %p from file", datalen, data));
+
+ /** @todo this read should be an a loop */
+ rd = read(fd, data, datalen);
+ if (rd <= 0) {
+ LOG(("read returned %d", rd));
+ close(fd);
+ if ((*data_out) == NULL) {
+ free(data);
+ }
+ return NSERROR_NOT_FOUND;
+ }
+
+ close(fd);
+
+ *data_out = data;
+ *datalen_out = datalen;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Invalidate a source object from the backing store.
+ *
+ * The entry (if present in the backing store) must no longer
+ * be returned as a result to the fetch or meta operations.
+ *
+ * @param url The url is used as the unique primary key to invalidate.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+invalidate(nsurl *url)
+{
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ return unlink_ident(storestate, nsurl_hash(url));
+}
+
+
+static struct gui_llcache_table llcache_table = {
+ .initialise = initialise,
+ .finalise = finalise,
+ .store = store,
+ .fetch = fetch,
+ .invalidate = invalidate,
+};
+
+struct gui_llcache_table *filesystem_llcache_table = &llcache_table;
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=0781dcb39e3ea1583ca...
commit 0781dcb39e3ea1583ca1ada2289a110b1d841ebd
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
Extend low level source data cache with persistant storage
diff --git a/content/hlcache.c b/content/hlcache.c
index 16f9697..86d5113 100644
--- a/content/hlcache.c
+++ b/content/hlcache.c
@@ -339,9 +339,10 @@ static nserror hlcache_migrate_ctx(hlcache_retrieval_ctx *ctx,
ctx->migrate_target = true;
- if (effective_type != NULL &&
- hlcache_type_is_acceptable(effective_type,
- ctx->accepted_types, &type)) {
+ if ((effective_type != NULL) &&
+ hlcache_type_is_acceptable(effective_type,
+ ctx->accepted_types,
+ &type)) {
error = hlcache_find_content(ctx, effective_type);
if (error != NSERROR_OK && error != NSERROR_NEED_DATA) {
if (ctx->handle->cb != NULL) {
@@ -524,9 +525,7 @@ hlcache_initialise(const struct hlcache_parameters *hlcache_parameters)
return NSERROR_NOMEM;
}
- ret = llcache_initialise(hlcache_parameters->cb,
- hlcache_parameters->cb_ctx,
- hlcache_parameters->limit);
+ ret = llcache_initialise(&hlcache_parameters->llcache);
if (ret != NSERROR_OK) {
free(hlcache);
hlcache = NULL;
diff --git a/content/hlcache.h b/content/hlcache.h
index 41f1ed6..746b3c8 100644
--- a/content/hlcache.h
+++ b/content/hlcache.h
@@ -23,11 +23,12 @@
#ifndef NETSURF_CONTENT_HLCACHE_H_
#define NETSURF_CONTENT_HLCACHE_H_
-#include "content/content.h"
-#include "content/llcache.h"
#include "utils/errors.h"
#include "utils/nsurl.h"
+#include "content/content.h"
+#include "content/llcache.h"
+
/** High-level cache handle */
typedef struct hlcache_handle hlcache_handle;
@@ -44,18 +45,10 @@ typedef struct {
} hlcache_event;
struct hlcache_parameters {
- llcache_query_callback cb; /**< Query handler for llcache */
- void *cb_ctx; /**< Pointer to llcache query handler data */
-
/** How frequently the background cache clean process is run (ms) */
unsigned int bg_clean_time;
- /** The target upper bound for the cache size */
- size_t limit;
-
- /** The hysteresis allowed round the target size */
- size_t hysteresis;
-
+ struct llcache_parameters llcache;
};
/**
@@ -67,13 +60,13 @@ struct hlcache_parameters {
* \return NSERROR_OK on success, appropriate error otherwise.
*/
typedef nserror (*hlcache_handle_callback)(hlcache_handle *handle,
- const hlcache_event *event, void *pw);
+ const hlcache_event *event, void *pw);
/** Flags for high-level cache object retrieval */
enum hlcache_retrieve_flag {
- /* Note: low-level cache retrieval flags occupy the bottom 16 bits of
- * the flags word. High-level cache flags occupy the top 16 bits.
- * To avoid confusion, high-level flags are allocated from bit 31 down.
+ /* Note: low-level cache retrieval flags occupy the bottom 16 bits of
+ * the flags word. High-level cache flags occupy the top 16 bits.
+ * To avoid confusion, high-level flags are allocated from bit 31 down.
*/
/** It's permitted to convert this request into a download */
HLCACHE_RETRIEVE_MAY_DOWNLOAD = (1 << 31),
@@ -84,7 +77,7 @@ enum hlcache_retrieve_flag {
/**
* Initialise the high-level cache, preparing the llcache also.
*
- * \param hlcache_parameters Settings to initialise cache with
+ * \param hlcache_parameters Settings to initialise cache with
* \return NSERROR_OK on success, appropriate error otherwise.
*/
nserror hlcache_initialise(const struct hlcache_parameters *hlcache_parameters);
@@ -133,7 +126,7 @@ nserror hlcache_poll(void);
nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags,
nsurl *referer, llcache_post_data *post,
hlcache_handle_callback cb, void *pw,
- hlcache_child_context *child,
+ hlcache_child_context *child,
content_type accepted_types, hlcache_handle **result);
/**
@@ -169,13 +162,13 @@ nserror hlcache_handle_replace_callback(hlcache_handle *handle,
* \param handle Cache handle to dereference
* \return Pointer to content object, or NULL if there is none
*
- * \todo This may not be correct. Ideally, the client should never need to
- * directly access a content object. It may, therefore, be better to provide a
- * bunch of veneers here that take a hlcache_handle and invoke the
+ * \todo This may not be correct. Ideally, the client should never need to
+ * directly access a content object. It may, therefore, be better to provide a
+ * bunch of veneers here that take a hlcache_handle and invoke the
* corresponding content_ API. If there's no content object associated with the
- * hlcache_handle (e.g. because the source data is still being fetched, so it
- * doesn't exist yet), then these veneers would behave as a NOP. The important
- * thing being that the client need not care about this possibility and can
+ * hlcache_handle (e.g. because the source data is still being fetched, so it
+ * doesn't exist yet), then these veneers would behave as a NOP. The important
+ * thing being that the client need not care about this possibility and can
* just call the functions with impugnity.
*/
struct content *hlcache_handle_get_content(const hlcache_handle *handle);
diff --git a/content/llcache.c b/content/llcache.c
index 112a7fa..587ada6 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -17,26 +17,41 @@
*/
/** \file
- * Low-level resource cache (implementation)
+ * Low-level resource cache implementation
+ *
+ * This is the implementation of the low level cache. This cache
+ * stores source objects in memory and may use a persistant backing
+ * store to extend their lifetime.
+ *
+ * \todo fix writeout conditions and ordering.
+ *
+ * \todo support mmaped retrieve
+ *
+ * \todo instrument and (auto)tune
+ *
+ * \todo turn llcache debugging off
+ *
*/
#include <stdlib.h>
#include <string.h>
#include <time.h>
-
#include <curl/curl.h>
-#include "content/fetch.h"
-#include "content/llcache.h"
-#include "content/urldb.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
+#include "desktop/gui_factory.h"
+
+#include "content/fetch.h"
+#include "content/backing_store.h"
+#include "content/urldb.h"
/** Define to enable tracing of llcache operations. */
-#undef LLCACHE_TRACE
+//#undef LLCACHE_TRACE
+#define LLCACHE_TRACE 1
#ifdef LLCACHE_TRACE
#define LLCACHE_LOG(x) LOG(x)
@@ -44,6 +59,9 @@
#define LLCACHE_LOG(x)
#endif
+#define LLCACHE_MIN_DISC_LIFETIME 3600
+#define LLCACHE_MAX_DISC_BANDWIDTH (512*1024)
+
/** State of a low-level cache object fetch */
typedef enum {
LLCACHE_FETCH_INIT, /**< Initial state, before fetch */
@@ -96,19 +114,23 @@ typedef struct {
bool outstanding_query; /**< Waiting for a query response */
} llcache_fetch_ctx;
+/** validation control */
typedef enum {
LLCACHE_VALIDATE_FRESH, /**< Only revalidate if not fresh */
LLCACHE_VALIDATE_ALWAYS, /**< Always revalidate */
LLCACHE_VALIDATE_ONCE /**< Revalidate once only */
} llcache_validate;
+/** cache control value for invalid age */
+#define INVALID_AGE -1
+
/** Cache control data */
typedef struct {
time_t req_time; /**< Time of request */
time_t res_time; /**< Time of response */
+ time_t fin_time; /**< Time of request completion */
time_t date; /**< Date: response header */
time_t expires; /**< Expires: response header */
-#define INVALID_AGE -1
int age; /**< Age: response header */
int max_age; /**< Max-Age Cache-control parameter */
llcache_validate no_cache; /**< No-Cache Cache-control parameter */
@@ -122,31 +144,49 @@ typedef struct {
char *value; /**< Header value */
} llcache_header;
+/** Current status of objects data */
+typedef enum {
+ LLCACHE_STATE_RAM = 0, /**< source data is stored in RAM only */
+ LLCACHE_STATE_MMAP, /**< source data is mmaped (implies on disc too) */
+ LLCACHE_STATE_DISC, /**< source data is stored on disc */
+} llcache_store_state;
+
/** Low-level cache object */
/** \todo Consider whether a list is a sane container */
struct llcache_object {
- llcache_object *prev; /**< Previous in list */
- llcache_object *next; /**< Next in list */
+ llcache_object *prev; /**< Previous in list */
+ llcache_object *next; /**< Next in list */
- nsurl *url; /**< Post-redirect URL for object */
+ nsurl *url; /**< Post-redirect URL for object */
/** \todo We need a generic dynamic buffer object */
- uint8_t *source_data; /**< Source data for object */
- size_t source_len; /**< Byte length of source data */
- size_t source_alloc; /**< Allocated size of source buffer */
+ uint8_t *source_data; /**< Source data for object */
+ size_t source_len; /**< Byte length of source data */
+ size_t source_alloc; /**< Allocated size of source buffer */
+
+ llcache_store_state store_state; /**< where the data for the object is stored */
+
+ llcache_object_user *users; /**< List of users */
- llcache_object_user *users; /**< List of users */
+ llcache_fetch_ctx fetch; /**< Fetch context for object */
- llcache_fetch_ctx fetch; /**< Fetch context for object */
+ llcache_cache_control cache; /**< Cache control data for object */
+ llcache_object *candidate; /**< Object to use, if fetch determines
+ * that it is still fresh
+ */
+ uint32_t candidate_count; /**< Count of objects this is a
+ * candidate for
+ */
- llcache_cache_control cache; /**< Cache control data for object */
- llcache_object *candidate; /**< Object to use, if fetch determines
- * that it is still fresh */
- uint32_t candidate_count; /**< Count of objects this is a
- * candidate for */
+ llcache_header *headers; /**< Fetch headers */
+ size_t num_headers; /**< Number of fetch headers */
- llcache_header *headers; /**< Fetch headers */
- size_t num_headers; /**< Number of fetch headers */
+ /* Instrumentation. These elemnts are strictly for information
+ * to improve the cache performance and to provide performace
+ * metrics. The values are non-authorative and must not be used to
+ * determine object lifetime etc.
+ */
+ time_t last_used; /**< time the last user was removed from the object */
};
struct llcache_s {
@@ -162,7 +202,17 @@ struct llcache_s {
/** Head of the low-level uncached object list */
llcache_object *uncached_objects;
+ /** The target upper bound for the RAM cache size */
uint32_t limit;
+
+ /** The minimum lifetime to consider sending objects to
+ * backing store.
+ */
+ int minimum_lifetime;
+
+ /** The maximum bandwidth to allow the backing store to use. */
+ size_t bandwidth;
+
};
/** low level cache state */
@@ -261,6 +311,11 @@ static nserror llcache_object_remove_user(llcache_object *object,
user->next = user->prev = NULL;
+ /* record the time the last user was removed from the object */
+ if (object->users == NULL) {
+ object->last_used = time(NULL);
+ }
+
LLCACHE_LOG(("Removing user %p from %p", user, object));
return NSERROR_OK;
@@ -711,6 +766,7 @@ static nserror llcache_object_refetch(llcache_object *object)
/* Reset cache control data */
llcache_invalidate_cache_control_data(object);
object->cache.req_time = time(NULL);
+ object->cache.fin_time = object->cache.req_time;
/* Reset fetch state */
object->fetch.state = LLCACHE_FETCH_INIT;
@@ -878,7 +934,7 @@ llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
else
freshness_lifetime = 0;
- LLCACHE_LOG(("%d:%d", freshness_lifetime, current_age));
+ /* LLCACHE_LOG(("%d:%d", freshness_lifetime, current_age)); */
if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
(freshness_lifetime > current_age)) {
@@ -957,6 +1013,7 @@ static nserror llcache_object_clone_cache_data(llcache_object *source,
destination->cache.req_time = source->cache.req_time;
destination->cache.res_time = source->cache.res_time;
+ destination->cache.fin_time = source->cache.fin_time;
if (source->cache.date != 0)
destination->cache.date = source->cache.date;
@@ -980,6 +1037,367 @@ static nserror llcache_object_clone_cache_data(llcache_object *source,
}
/**
+ * Remove a low-level cache object from a cache list
+ *
+ * \param object Object to remove
+ * \param list List to remove from
+ * \return NSERROR_OK
+ */
+static nserror
+llcache_object_remove_from_list(llcache_object *object, llcache_object **list)
+{
+ if (object == *list)
+ *list = object->next;
+ else
+ object->prev->next = object->next;
+
+ if (object->next != NULL)
+ object->next->prev = object->prev;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrieve source data for an object from persistant store if necessary.
+ *
+ * If an objects source data has been placed in the persistant store
+ * and the in memory copy freed this will attempt to retrive the
+ * source data.
+ *
+ * @param object the object to operate on.
+ * @return apropriate error code.
+ */
+static nserror llcache_persist_retrieve(llcache_object *object)
+{
+ enum backing_store_flags flags = BACKING_STORE_NONE;
+
+ /* ensure the source data is present if necessary */
+ if ((object->source_data != NULL) ||
+ (object->store_state != LLCACHE_STATE_DISC)) {
+ /* source data does not require retriving from
+ * persistant store.
+ */
+ return NSERROR_OK;
+ }
+
+ /* Source data for the object may be in the persiatant store */
+ return guit->llcache->fetch(object->url,
+ &flags,
+ &object->source_data,
+ &object->source_len);
+}
+
+/**
+ * Generate a serialised version of an objects metadata
+ *
+ * metadata includes object headers
+ */
+static nserror
+llcache_serialise_metadata(llcache_object *object,
+ uint8_t **data_out,
+ size_t *datasize_out)
+{
+ size_t allocsize;
+ int datasize;
+ uint8_t *data;
+ char *op;
+ unsigned int hloop;
+ int use;
+ struct tm *ltm;
+
+ allocsize = 10 + 1; /* object length */
+
+ allocsize += 10 + 1; /* request time */
+
+ allocsize += 10 + 1; /* response time */
+
+ allocsize += 10 + 1; /* completion time */
+
+ allocsize += 10 + 1; /* space for number of header entries */
+
+ allocsize += nsurl_length(object->url) + 1;
+
+ for (hloop = 0 ; hloop < object->num_headers ; hloop++) {
+ allocsize += strlen(object->headers[hloop].name) + 1;
+ allocsize += strlen(object->headers[hloop].value) + 1;
+ }
+
+ data = malloc(allocsize);
+ if (data == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ op = (char *)data;
+ datasize = allocsize;
+
+ /* the url, used for checking for collisions */
+ use = snprintf(op, datasize, "%s%c", nsurl_access(object->url), 0);
+ if (use > datasize)
+ goto overflow;
+ op += use;
+ datasize -= use;
+
+ /* object size */
+ use = snprintf(op, datasize, "%zu%c", object->source_len, 0);
+ if (use > datasize)
+ goto overflow;
+ op += use;
+ datasize -= use;
+
+ /* Time of request */
+ ltm = localtime(&object->cache.req_time);
+ use = strftime(op, datasize, "%s", ltm);
+ if (use == 0)
+ goto overflow;
+ use++; /* does not count the null */
+ op += use;
+ datasize -= use;
+
+ /* Time of response */
+ ltm = localtime(&object->cache.res_time);
+ use = strftime(op, datasize, "%s", ltm);
+ if (use == 0)
+ goto overflow;
+ use++; /* does not count the null */
+ op += use;
+ datasize -= use;
+
+ /* Time of completion */
+ ltm = localtime(&object->cache.fin_time);
+ use = strftime(op, datasize, "%s", ltm);
+ if (use == 0)
+ goto overflow;
+ use++; /* does not count the null */
+ op += use;
+ datasize -= use;
+
+ /* number of headers */
+ use = snprintf(op, datasize, "%zu%c", object->num_headers, 0);
+ if (use > datasize)
+ goto overflow;
+ op += use;
+ datasize -= use;
+
+ /* headers */
+ for (hloop = 0 ; hloop < object->num_headers ; hloop++) {
+ use = snprintf(op, datasize,
+ "%s:%s%c",
+ object->headers[hloop].name,
+ object->headers[hloop].value,
+ 0);
+ if (use > datasize)
+ goto overflow;
+ op += use;
+ datasize -= use;
+ }
+
+ LLCACHE_LOG(("Filled buffer with %d spare", datasize));
+
+ *data_out = data;
+ *datasize_out = allocsize - datasize;
+
+ return NSERROR_OK;
+
+overflow:
+ /* somehow we overflowed the buffer - hth? */
+ LOG(("Overflowed metadata buffer"));
+ free(data);
+ return NSERROR_INVALID;
+}
+
+/**
+ * un-serialise an objects metadata.
+ */
+static nserror
+llcache_process_metadata(llcache_object *object)
+{
+ nserror res;
+ uint8_t *metadata = NULL;
+ size_t metadatalen = 0;
+ nsurl *metadataurl;
+ unsigned int line;
+ uint8_t *end;
+ char *ln;
+ int lnsize;
+ size_t num_headers;
+ size_t hloop;
+ struct tm ltm;
+ enum backing_store_flags flags = BACKING_STORE_META;
+
+ LOG(("Retriving metadata"));
+
+ /* attempt to retrieve object metadata from the backing store */
+ res = guit->llcache->fetch(object->url,
+ &flags,
+ &metadata,
+ &metadatalen);
+ if (res != NSERROR_OK) {
+ return res;
+ }
+
+ end = metadata + metadatalen;
+
+ LOG(("Processing retrived data"));
+
+ /* metadata line 1 is the url the metadata referrs to */
+ line = 1;
+ ln = (char *)metadata;
+ lnsize = strlen(ln);
+
+ if (lnsize < 7)
+ goto format_error;
+
+ res = nsurl_create(ln, &metadataurl);
+ if (res != NSERROR_OK) {
+ free(metadata);
+ return res;
+ }
+
+ if (nsurl_compare(object->url, metadataurl, NSURL_COMPLETE) != true) {
+ /* backing store returned the wrong object for the
+ * request. This may occour if the backing store had
+ * a collision in its stoage method. We cope with this
+ * by simply skipping caching of this object.
+ */
+
+ LOG(("Got metadata for %s instead of %s",
+ nsurl_access(metadataurl),
+ nsurl_access(object->url)));
+
+ nsurl_unref(metadataurl);
+
+ free(metadata);
+
+ return NSERROR_BAD_URL;
+ }
+ nsurl_unref(metadataurl);
+
+
+ /* metadata line 2 is the objects length */
+ line = 2;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ if ((lnsize < 1) ||
+ (sscanf(ln, "%zu", &object->source_len) != 1))
+ goto format_error;
+ object->source_alloc = metadatalen;
+
+ /* metadata line 3 is the time of request */
+ line = 3;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ if ((lnsize < 1) ||
+ (strptime(ln, "%s", <m) == NULL))
+ goto format_error;
+ object->cache.req_time = mktime(<m);
+
+ /* metadata line 4 is the time of response */
+ line = 4;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ if ((lnsize < 1) ||
+ (strptime(ln, "%s", <m) == NULL))
+ goto format_error;
+ object->cache.res_time = mktime(<m);
+
+ /* metadata line 5 is the time of request completion */
+ line = 5;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ if ((lnsize < 1) ||
+ (strptime(ln, "%s", <m) == NULL))
+ goto format_error;
+ object->cache.fin_time = mktime(<m);
+
+
+ /* metadata line 6 is the number of headers */
+ line = 6;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ if ((lnsize < 1) ||
+ (sscanf(ln, "%zu", &num_headers) != 1))
+ goto format_error;
+
+
+ /* read headers */
+ for (hloop = 0 ; hloop < num_headers; hloop++) {
+ line++;
+ ln += lnsize + 1;
+ lnsize = strlen(ln);
+
+ res = llcache_fetch_process_header(object, (uint8_t *)ln, lnsize);
+ if (res != NSERROR_OK) {
+ free(metadata);
+ return res;
+ }
+ }
+
+ free(metadata);
+
+ /* object stored in backing store */
+ object->store_state = LLCACHE_STATE_DISC;
+
+ return NSERROR_OK;
+
+format_error:
+ LOG(("metadata error on line %d\n", line));
+ free(metadata);
+ return NSERROR_INVALID;
+
+}
+
+/**
+ * attempt to retrieve an object from persistant storage.
+ */
+static nserror
+llcache_object_fetch_persistant(llcache_object *object,
+ uint32_t flags,
+ nsurl *referer,
+ const llcache_post_data *post,
+ uint32_t redirect_count)
+{
+ nserror error;
+ nsurl *referer_clone = NULL;
+ llcache_post_data *post_clone = NULL;
+
+ object->cache.req_time = time(NULL);
+ object->cache.fin_time = object->cache.req_time;
+
+ /* retrieve and process metadata */
+ error = llcache_process_metadata(object);
+ if (error != NSERROR_OK) {
+ return error;
+ }
+
+ /* entry came out of cache - need to setup object state */
+ if (post != NULL) {
+ error = llcache_post_data_clone(post, &post_clone);
+ if (error != NSERROR_OK)
+ return error;
+ }
+
+ if (referer != NULL) {
+ referer_clone = nsurl_ref(referer);
+ }
+
+ object->fetch.flags = flags;
+ object->fetch.referer = referer_clone;
+ object->fetch.post = post_clone;
+ object->fetch.redirect_count = redirect_count;
+
+ /* fetch is "finished" */
+ object->fetch.state = LLCACHE_FETCH_COMPLETE;
+ object->fetch.fetch = NULL;
+
+ return NSERROR_OK;
+}
+
+/**
* Retrieve a potentially cached object
*
* \param url URL of object to retrieve
@@ -990,89 +1408,158 @@ static nserror llcache_object_clone_cache_data(llcache_object *source,
* \param result Pointer to location to recieve retrieved object
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
- nsurl *referer, const llcache_post_data *post,
- uint32_t redirect_count, llcache_object **result)
+static nserror
+llcache_object_retrieve_from_cache(nsurl *url,
+ uint32_t flags,
+ nsurl *referer,
+ const llcache_post_data *post,
+ uint32_t redirect_count,
+ llcache_object **result)
{
nserror error;
llcache_object *obj, *newest = NULL;
- LLCACHE_LOG(("Searching cache for %s (%x %p %p)",
- nsurl_access(url), flags, referer, post));
+ LLCACHE_LOG(("Searching cache for %s flags:%x referer:%s post:%p",
+ nsurl_access(url), flags, referer==NULL?"":nsurl_access(referer), post));
/* Search for the most recently fetched matching object */
for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
if ((newest == NULL ||
- obj->cache.req_time > newest->cache.req_time) &&
- nsurl_compare(obj->url, url,
- NSURL_COMPLETE) == true) {
+ obj->cache.req_time > newest->cache.req_time) &&
+ nsurl_compare(obj->url, url,
+ NSURL_COMPLETE) == true) {
newest = obj;
}
}
- if (newest != NULL && llcache_object_is_fresh(newest)) {
- /* Found a suitable object, and it's still fresh, so use it */
- obj = newest;
+ /* No viable object found in cache create one and attempt to
+ * pull from persistant store.
+ */
+ if (newest == NULL) {
+ LLCACHE_LOG(("No viable object found in cache"));
- LLCACHE_LOG(("Found fresh %p", obj));
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ /* attempt to retrieve object from persistant store */
+ error = llcache_object_fetch_persistant(obj, flags, referer, post, redirect_count);
+ if (error == NSERROR_OK) {
+ LLCACHE_LOG(("retrived object from persistant store"));
+
+ /* set object from persistant store as newest */
+ newest = obj;
+
+ /* Add new object to cached object list */
+ llcache_object_add_to_list(obj, &llcache->cached_objects);
+
+ }
+ /* else no object found and unretrivable from cache,
+ * fall through to start fetch
+ */
+ }
+
+ if ((newest != NULL) && (llcache_object_is_fresh(newest))) {
+ /* Found a suitable object, and it's still fresh */
+ LLCACHE_LOG(("Found fresh %p", newest));
/* The client needs to catch up with the object's state.
* This will occur the next time that llcache_poll is called.
*/
- } else if (newest != NULL) {
- /* Found a candidate object but it needs freshness validation */
- /* Create a new object */
- error = llcache_object_new(url, &obj);
- if (error != NSERROR_OK)
- return error;
+ /* ensure the source data is present */
+ error = llcache_persist_retrieve(newest);
+ if (error == NSERROR_OK) {
+ /* source data was sucessfully retrived from
+ * persistant store
+ */
+ *result = newest;
- LLCACHE_LOG(("Found candidate %p (%p)", obj, newest));
+ return NSERROR_OK;
+ }
+
+ /* retrival of source data from persistant store
+ * failed, destroy cache object and fall though to
+ * cache miss to re-retch
+ */
+ LLCACHE_LOG(("Persistant retrival failed for %p", newest));
+
+ llcache_object_remove_from_list(newest, &llcache->cached_objects);
+ llcache_object_destroy(newest);
- /* Clone candidate's cache data */
- error = llcache_object_clone_cache_data(newest, obj, true);
+ error = llcache_object_new(url, &obj);
if (error != NSERROR_OK) {
- llcache_object_destroy(obj);
return error;
}
+ } else if (newest != NULL) {
+ /* Found a candidate object but it needs freshness validation */
- /* Record candidate, so we can fall back if it is still fresh */
- newest->candidate_count++;
- obj->candidate = newest;
+ /* ensure the source data is present */
+ error = llcache_persist_retrieve(newest);
+ if (error == NSERROR_OK) {
- /* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
- if (error != NSERROR_OK) {
- newest->candidate_count--;
- llcache_object_destroy(obj);
- return error;
+ /* Create a new object */
+ error = llcache_object_new(url, &obj);
+ if (error != NSERROR_OK)
+ return error;
+
+ LLCACHE_LOG(("Found candidate %p (%p)", obj, newest));
+
+ /* Clone candidate's cache data */
+ error = llcache_object_clone_cache_data(newest, obj, true);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Record candidate, so we can fall back if it is still fresh */
+ newest->candidate_count++;
+ obj->candidate = newest;
+
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post,
+ redirect_count);
+ if (error != NSERROR_OK) {
+ newest->candidate_count--;
+ llcache_object_destroy(obj);
+ return error;
+ }
+
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache->cached_objects);
+
+ *result = obj;
+
+ return NSERROR_OK;
}
- /* Add new object to cache */
- llcache_object_add_to_list(obj, &llcache->cached_objects);
- } else {
- /* No object found; create a new one */
- /* Create new object */
- error = llcache_object_new(url, &obj);
- if (error != NSERROR_OK)
- return error;
+ LLCACHE_LOG(("Persistant retrival failed for %p", newest));
- LLCACHE_LOG(("Not found %p", obj));
+ /* retrival of source data from persistant store
+ * failed, destroy cache object and fall though to
+ * cache miss to re-retch
+ */
+ llcache_object_remove_from_list(newest,
+ &llcache->cached_objects);
+ llcache_object_destroy(newest);
- /* Attempt to kick-off fetch */
- error = llcache_object_fetch(obj, flags, referer, post,
- redirect_count);
+ error = llcache_object_new(url, &obj);
if (error != NSERROR_OK) {
- llcache_object_destroy(obj);
return error;
}
+ }
- /* Add new object to cache */
- llcache_object_add_to_list(obj, &llcache->cached_objects);
+ /* Attempt to kick-off fetch */
+ error = llcache_object_fetch(obj, flags, referer, post, redirect_count);
+ if (error != NSERROR_OK) {
+ llcache_object_destroy(obj);
+ return error;
}
+ /* Add new object to cache */
+ llcache_object_add_to_list(obj, &llcache->cached_objects);
+
*result = obj;
return NSERROR_OK;
@@ -1098,8 +1585,8 @@ static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
nsurl *defragmented_url;
bool uncachable = false;
- LLCACHE_LOG(("Retrieve %s (%x, %p, %p)",
- nsurl_access(url), flags, referer, post));
+ LLCACHE_LOG(("Retrieve %s (%x, %s, %p)", nsurl_access(url), flags,
+ referer==NULL?"":nsurl_access(referer), post));
/* Get rid of any url fragment */
@@ -1626,6 +2113,146 @@ static nserror llcache_fetch_ssl_error(llcache_object *object)
}
/**
+ * construct a sorted list of objects available for writeout operation
+ *
+ * The list contains fresh cacheable objects held in RAM with no
+ * pending fetches. Any objects with a remaining lifetime less than
+ * the configured minimum lifetime are simply not considered, they will
+ * become stale before pushing to backing store is worth the cost.
+ *
+ * \todo calculate useful cost metrics to improve sorting.
+ *
+ */
+static nserror
+build_candidate_list(struct llcache_object ***lst_out, int *lst_len_out)
+{
+ llcache_object *object, *next;
+ struct llcache_object **lst;
+ int lst_len = 0;
+ int remaining_lifetime;
+
+ lst = calloc(512, sizeof(struct llcache_object *));
+ if (lst == NULL)
+ return NSERROR_NOMEM;
+
+ for (object = llcache->cached_objects; object != NULL; object = next) {
+ next = object->next;
+
+ remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(&object->cache);
+
+ /* cacehable objects with no pending fetches, not
+ * already on disc and with sufficient lifetime to
+ * make disc cache worthwile
+ */
+ if ((object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false) &&
+ (object->store_state == LLCACHE_STATE_RAM) &&
+ (remaining_lifetime > llcache->minimum_lifetime)) {
+ lst[lst_len] = object;
+ lst_len++;
+ if (lst_len == 512)
+ break;
+ }
+ }
+
+ if (lst_len == 0) {
+ free(lst);
+ return NSERROR_NOT_FOUND;
+ }
+
+ /* sort list here */
+
+ *lst_len_out = lst_len;
+ *lst_out = lst;
+
+ return NSERROR_OK;
+}
+
+static nserror
+write_backing_store(struct llcache_object *object, size_t *written_out)
+{
+ nserror ret;
+ uint8_t *metadata;
+ size_t metadatasize;
+
+ /* put object data in backing store */
+ ret = guit->llcache->store(object->url,
+ BACKING_STORE_NONE,
+ object->source_data,
+ object->source_len);
+ if (ret != NSERROR_OK) {
+ /* unable to put source data in backing store */
+ return ret;
+ }
+
+ ret = llcache_serialise_metadata(object, &metadata, &metadatasize);
+ if (ret != NSERROR_OK) {
+ /* There has been a metadata serialisation error. Ensure the
+ * already written data object is invalidated.
+ */
+ guit->llcache->invalidate(object->url);
+ return ret;
+ }
+
+ ret = guit->llcache->store(object->url,
+ BACKING_STORE_META,
+ metadata,
+ metadatasize);
+ free(metadata);
+ if (ret != NSERROR_OK) {
+ /* There has been an error putting the metadata in the
+ * backing store. Ensure the data object is invalidated.
+ */
+ guit->llcache->invalidate(object->url);
+ return ret;
+ }
+ object->store_state = LLCACHE_STATE_DISC;
+
+ *written_out = object->source_len + metadatasize;
+
+ return NSERROR_OK;
+}
+
+/**
+ * possibly write objects data to backing store.
+ */
+static void llcache_persist(void *p)
+{
+ nserror ret;
+ size_t size_written;
+ size_t total_written = 0;
+ struct llcache_object **lst;
+ int lst_count;
+ int idx;
+
+ ret = build_candidate_list(&lst, &lst_count);
+ if (ret == NSERROR_OK) {
+ /* obtained a candidate list, make each object
+ * persistant in turn
+ */
+ for (idx = 0; idx < lst_count; idx++) {
+ ret = write_backing_store(lst[idx], &size_written);
+ if (ret != NSERROR_OK) {
+ break;
+ }
+ total_written += size_written;
+
+ if (total_written > llcache->bandwidth) {
+ /* The bandwidth limit has been reached.
+ * Writeout scheduled for the remaining objects
+ */
+ guit->browser->schedule(1000, llcache_persist, NULL);
+ break;
+ }
+ }
+
+ free(lst);
+ }
+}
+
+
+/**
* Handler for fetch events
*
* \param msg Fetch event
@@ -1724,6 +2351,11 @@ static void llcache_fetch_callback(const fetch_msg *msg, void *p)
}
llcache_object_cache_update(object);
+
+ /* record when the fetch finished */
+ object->cache.fin_time = time(NULL);
+
+ guit->browser->schedule(5000, llcache_persist, NULL);
}
break;
@@ -1833,26 +2465,6 @@ static llcache_object_user *llcache_object_find_user(const llcache_handle *handl
return user;
}
-/**
- * Remove a low-level cache object from a cache list
- *
- * \param object Object to remove
- * \param list List to remove from
- * \return NSERROR_OK
- */
-static nserror llcache_object_remove_from_list(llcache_object *object,
- llcache_object **list)
-{
- if (object == *list)
- *list = object->next;
- else
- object->prev->next = object->next;
-
- if (object->next != NULL)
- object->next->prev = object->prev;
-
- return NSERROR_OK;
-}
/**
* Determine if a low-level cache object resides in a given list
@@ -2110,8 +2722,8 @@ static nserror llcache_object_notify_users(llcache_object *object)
* \param snapshot Pointer to receive snapshot of \a object
* \return NSERROR_OK on success, appropriate error otherwise
*/
-static nserror llcache_object_snapshot(llcache_object *object,
- llcache_object **snapshot)
+static nserror
+llcache_object_snapshot(llcache_object *object, llcache_object **snapshot)
{
llcache_object *newobj;
nserror error;
@@ -2162,6 +2774,35 @@ static nserror llcache_object_snapshot(llcache_object *object,
return NSERROR_OK;
}
+/**
+ * total ram usage of object
+ */
+static inline uint32_t
+total_object_size(llcache_object *object)
+{
+ uint32_t tot;
+ size_t hdrc;
+
+ tot = sizeof(*object);
+ tot += nsurl_length(object->url);
+
+ if (object->source_data != NULL) {
+ tot += object->source_len;
+ }
+
+ tot += sizeof(llcache_header) * object->num_headers;
+
+ for (hdrc = 0; hdrc < object->num_headers; hdrc++) {
+ if (object->headers[hdrc].name != NULL) {
+ tot += strlen(object->headers[hdrc].name);
+ }
+ if (object->headers[hdrc].value != NULL) {
+ tot += strlen(object->headers[hdrc].value);
+ }
+ }
+
+ return tot;
+}
/******************************************************************************
* Public API *
@@ -2169,6 +2810,8 @@ static nserror llcache_object_snapshot(llcache_object *object,
/**
* Attempt to clean the cache
+ *
+ * The memory cache cleaning discards objects in order of increasing value.
*/
/* Exported interface documented in llcache.h */
void llcache_clean(void)
@@ -2179,15 +2822,10 @@ void llcache_clean(void)
LLCACHE_LOG(("Attempting cache clean"));
- /* Candidates for cleaning are (in order of priority):
- *
- * 1) Uncacheable objects with no users
- * 2) Stale cacheable objects with no users or pending fetches
- * 3) Fresh cacheable objects with no users or pending fetches
- */
-
- /* 1) Uncacheable objects with no users or fetches */
- for (object = llcache->uncached_objects; object != NULL; object = next) {
+ /* Uncacheable objects with no users or fetches */
+ for (object = llcache->uncached_objects;
+ object != NULL;
+ object = next) {
next = object->next;
/* The candidate count of uncacheable objects is always 0 */
@@ -2195,18 +2833,21 @@ void llcache_clean(void)
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
- LLCACHE_LOG(("Found victim %p", object));
+ LLCACHE_LOG(("Discarding uncachable object with no users (%p) %s", object, nsurl_access(object->url)));
llcache_object_remove_from_list(object,
&llcache->uncached_objects);
llcache_object_destroy(object);
} else {
- llcache_size += object->source_len + sizeof(*object);
+ llcache_size += total_object_size(object);
}
}
- /* 2) Stale cacheable objects with no users or pending fetches */
- for (object = llcache->cached_objects; object != NULL; object = next) {
+
+ /* Stale cacheable objects with no users or pending fetches */
+ for (object = llcache->cached_objects;
+ object != NULL;
+ object = next) {
next = object->next;
remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(&object->cache);
@@ -2214,45 +2855,113 @@ void llcache_clean(void)
if ((object->users == NULL) &&
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
- (object->fetch.outstanding_query == false)) {
-
- if (remaining_lifetime > 0) {
- /* object is fresh */
- llcache_size += object->source_len + sizeof(*object);
- } else {
- /* object is not fresh */
- LLCACHE_LOG(("Found stale cacheable object (%p) with no users or pending fetches", object));
+ (object->fetch.outstanding_query == false) &&
+ (remaining_lifetime <= 0)) {
+ /* object is stale */
+ LLCACHE_LOG(("discarding stale cacheable object with no users or pending fetches (%p) %s", object, nsurl_access(object->url)));
llcache_object_remove_from_list(object,
&llcache->cached_objects);
+
+ if (object->store_state == LLCACHE_STATE_DISC) {
+ guit->llcache->invalidate(object->url);
+ }
+
llcache_object_destroy(object);
- }
+
} else {
- llcache_size += object->source_len + sizeof(*object);
+ /* object has users so account for the storage */
+ llcache_size += total_object_size(object);
}
}
- /* 3) Fresh cacheable objects with no users or pending
- * fetches, only if the cache exceeds the configured size.
+ /* if the cache limit is exceeded try to make some objects
+ * persistant so their RAM can be reclaimed in the next
+ * step
*/
- if (llcache->limit < llcache_size) {
- for (object = llcache->cached_objects; object != NULL;
- object = next) {
- next = object->next;
+ if (llcache->limit < llcache_size) {
+ llcache_persist(NULL);
+ }
+
+ /* Source data of fresh cacheable objects with no users, no
+ * pending fetches and pushed to persistant store while the
+ * cache exceeds the configured size.
+ */
+ for (object = llcache->cached_objects;
+ ((llcache->limit < llcache_size) && (object != NULL));
+ object = next) {
+ next = object->next;
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false) &&
+ (object->store_state == LLCACHE_STATE_DISC)) {
+ free(object->source_data);
+ object->source_data = NULL;
- if ((object->users == NULL) &&
- (object->candidate_count == 0) &&
- (object->fetch.fetch == NULL) &&
- (object->fetch.outstanding_query == false)) {
- LLCACHE_LOG(("Found victim %p", object));
+ llcache_size -= object->source_len;
- llcache_size -=
- object->source_len + sizeof(*object);
+ LLCACHE_LOG(("Freeing source data for %p len:%d",
+ object,
+ object->source_len));
+ }
+ }
- llcache_object_remove_from_list(object,
+ /* Fresh cacheable objects with no users, no pending fetches
+ * and pushed to persistant store while the cache exceeds
+ * the configured size. Efectively just the object metadata.
+ */
+ for (object = llcache->cached_objects;
+ ((llcache->limit < llcache_size) && (object != NULL));
+ object = next) {
+ next = object->next;
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false) &&
+ (object->store_state == LLCACHE_STATE_DISC) &&
+ (object->source_data == NULL)) {
+ LLCACHE_LOG(("discarding backed object len:%d age:%d (%p) %s",
+ object->source_len,
+ time(NULL) - object->last_used,
+ object,
+ nsurl_access(object->url)));
+
+ llcache_size -= total_object_size(object);
+
+ llcache_object_remove_from_list(object,
&llcache->cached_objects);
- llcache_object_destroy(object);
- }
+ llcache_object_destroy(object);
+
+ }
+ }
+
+ /* Fresh cacheable objects with no users or pending fetches
+ * while the cache exceeds the configured size. These are the
+ * most valuble objects as replacing them is a full network
+ * fetch
+ */
+ for (object = llcache->cached_objects;
+ ((llcache->limit < llcache_size) && (object != NULL));
+ object = next) {
+ next = object->next;
+
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false) &&
+ (object->store_state == LLCACHE_STATE_RAM)) {
+ LLCACHE_LOG(("discarding fresh object len:%d age:%d (%p) %s",
+ object->source_len,
+ time(NULL) - object->last_used,
+ object,
+ nsurl_access(object->url)));
+
+ llcache_size -= object->source_len + sizeof(*object);
+
+ llcache_object_remove_from_list(object,
+ &llcache->cached_objects);
+ llcache_object_destroy(object);
}
}
@@ -2261,20 +2970,23 @@ void llcache_clean(void)
/* See llcache.h for documentation */
nserror
-llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
+llcache_initialise(const struct llcache_parameters *prm)
{
llcache = calloc(1, sizeof(struct llcache_s));
if (llcache == NULL) {
return NSERROR_NOMEM;
}
- llcache->query_cb = cb;
- llcache->query_cb_pw = pw;
- llcache->limit = llcache_limit;
+ llcache->query_cb = prm->cb;
+ llcache->query_cb_pw = prm->cb_ctx;
+ llcache->limit = prm->limit;
+ llcache->minimum_lifetime = prm->minimum_lifetime;
+ llcache->bandwidth = prm->bandwidth;
- LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
+ LOG(("llcache initialised with a limit of %d bytes", llcache->limit));
- return NSERROR_OK;
+ /* backing store initialisation */
+ return guit->llcache->initialise(&prm->store);
}
/* See llcache.h for documentation */
@@ -2324,6 +3036,9 @@ void llcache_finalise(void)
llcache_object_destroy(object);
}
+ /* backing store finalisation */
+ guit->llcache->finalise();
+
free(llcache);
llcache = NULL;
}
diff --git a/content/llcache.h b/content/llcache.h
index 3d8232c..6fe5c20 100644
--- a/content/llcache.h
+++ b/content/llcache.h
@@ -76,7 +76,7 @@ typedef struct {
} data; /**< Event data */
} llcache_event;
-/**
+/**
* Client callback for low-level cache events
*
* \param handle Handle for which event is issued
@@ -84,18 +84,18 @@ typedef struct {
* \param pw Pointer to client-specific data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-typedef nserror (*llcache_handle_callback)(llcache_handle *handle,
+typedef nserror (*llcache_handle_callback)(llcache_handle *handle,
const llcache_event *event, void *pw);
/** Flags for low-level cache object retrieval */
enum llcache_retrieve_flag {
/* Note: We're permitted a maximum of 16 flags which must reside in the
- * bottom 16 bits of the flags word. See hlcache.h for further details.
+ * bottom 16 bits of the flags word. See hlcache.h for further details.
*/
/** Force a new fetch */
- LLCACHE_RETRIEVE_FORCE_FETCH = (1 << 0),
+ LLCACHE_RETRIEVE_FORCE_FETCH = (1 << 0),
/** Requested URL was verified */
- LLCACHE_RETRIEVE_VERIFIABLE = (1 << 1),
+ LLCACHE_RETRIEVE_VERIFIABLE = (1 << 1),
/**< No error pages */
LLCACHE_RETRIEVE_NO_ERROR_PAGES = (1 << 2),
/**< Stream data (implies that object is not cacheable) */
@@ -149,21 +149,52 @@ typedef nserror (*llcache_query_response)(bool proceed, void *cbpw);
* \param cbpw Opaque value to pass into \a cb
* \return NSERROR_OK on success, appropriate error otherwise
*
- * \note This callback should return immediately. Once a suitable answer to
- * the query has been obtained, the provided response callback should be
+ * \note This callback should return immediately. Once a suitable answer to
+ * the query has been obtained, the provided response callback should be
* called. This is intended to be an entirely asynchronous process.
*/
typedef nserror (*llcache_query_callback)(const llcache_query *query, void *pw,
llcache_query_response cb, void *cbpw);
/**
+ * Parameters to configure the low level cache backing store.
+ */
+struct llcache_store_parameters {
+ const char *path; /**< The path to the backing store */
+
+ size_t limit; /**< The backing store upper bound target size */
+ size_t hysteresis; /**< The hysteresis around the target size */
+};
+
+/**
+ * Parameters to configure the low level cache.
+ */
+struct llcache_parameters {
+ llcache_query_callback cb; /**< Query handler for llcache */
+ void *cb_ctx; /**< Pointer to llcache query handler data */
+
+ size_t limit; /**< The target upper bound for the RAM cache size */
+ size_t hysteresis; /**< The hysteresis around the target size */
+
+ int minimum_lifetime; /**< The minimum lifetime to consider
+ * sending objects to backing store.
+ */
+
+ size_t bandwidth; /**< The maximum bandwidth to allow the
+ * backing store to use.
+ */
+
+ struct llcache_store_parameters store;
+};
+
+/**
* Initialise the low-level cache
*
* \param cb Query handler
* \param pw Pointer to query handler data
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-nserror llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit);
+nserror llcache_initialise(const struct llcache_parameters *parameters);
/**
* Finalise the low-level cache
@@ -280,12 +311,12 @@ const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
* \return Header value, or NULL if header does not exist
*
* \todo Make the key an enumeration, to avoid needless string comparisons
- * \todo Forcing the client to parse the header value seems wrong.
- * Better would be to return the actual value part and an array of
+ * \todo Forcing the client to parse the header value seems wrong.
+ * Better would be to return the actual value part and an array of
* key-value pairs for any additional parameters.
* \todo Deal with multiple headers of the same key (e.g. Set-Cookie)
*/
-const char *llcache_handle_get_header(const llcache_handle *handle,
+const char *llcache_handle_get_header(const llcache_handle *handle,
const char *key);
/**
@@ -295,7 +326,7 @@ const char *llcache_handle_get_header(const llcache_handle *handle,
* \param b Second handle
* \return True if handles reference the same object, false otherwise
*/
-bool llcache_handle_references_same_object(const llcache_handle *a,
+bool llcache_handle_references_same_object(const llcache_handle *a,
const llcache_handle *b);
#endif
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index c3653b5..f759029 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -67,11 +67,23 @@
*/
#define SPECULATE_SMALL 4096
-/* the time between cache clean runs in ms */
+/** the time between image cache clean runs in ms. */
#define IMAGE_CACHE_CLEAN_TIME (10 * 1000)
+/** default time between content cache cleans. */
#define HL_CACHE_CLEAN_TIME (2 * IMAGE_CACHE_CLEAN_TIME)
+/** default minimum object time before object is pushed to backing store. */
+#define LLCACHE_MIN_DISC_LIFETIME (60 * 30)
+
+/** default maximum bandwidth for backing store writeout. */
+#define LLCACHE_MAX_DISC_BANDWIDTH (128 * 1024)
+
+/** ensure there is a minimal amount of memory for source objetcs and
+ * decoded bitmaps.
+ */
+#define MINIMUM_MEMORY_CACHE_SIZE (2 * 1024 * 1024)
+
bool netsurf_quit = false;
static void netsurf_lwc_iterator(lwc_string *str, void *pw)
@@ -108,20 +120,21 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query,
return NSERROR_OK;
}
-#define MINIMUM_MEMORY_CACHE_SIZE (2 * 1024 * 1024)
-
/**
* Initialise components used by gui NetSurf.
*/
nserror netsurf_init(const char *messages, struct gui_table *gt)
{
- nserror error;
+ nserror ret;
struct utsname utsname;
- nserror ret = NSERROR_OK;
struct hlcache_parameters hlcache_parameters = {
.bg_clean_time = HL_CACHE_CLEAN_TIME,
- .cb = netsurf_llcache_query_handler,
+ .llcache = {
+ .cb = netsurf_llcache_query_handler,
+ .minimum_lifetime = LLCACHE_MIN_DISC_LIFETIME,
+ .bandwidth = LLCACHE_MAX_DISC_BANDWIDTH,
+ }
};
struct image_cache_parameters image_cache_parameters = {
.bg_clean_time = IMAGE_CACHE_CLEAN_TIME,
@@ -149,82 +162,94 @@ nserror netsurf_init(const char *messages, struct gui_table *gt)
utsname.version, utsname.machine));
/* register the gui handlers */
- error = gui_factory_register(gt);
- if (error != NSERROR_OK)
- return error;
+ ret = gui_factory_register(gt);
+ if (ret != NSERROR_OK)
+ return ret;
messages_load(messages);
/* corestrings init */
- error = corestrings_init();
- if (error != NSERROR_OK)
- return error;
+ ret = corestrings_init();
+ if (ret != NSERROR_OK)
+ return ret;
/* set up cache limits based on the memory cache size option */
- hlcache_parameters.limit = nsoption_int(memory_cache_size);
+ hlcache_parameters.llcache.limit = nsoption_int(memory_cache_size);
- if (hlcache_parameters.limit < MINIMUM_MEMORY_CACHE_SIZE) {
- hlcache_parameters.limit = MINIMUM_MEMORY_CACHE_SIZE;
- LOG(("Setting minimum memory cache size to %d",
- hlcache_parameters.limit));
+ if (hlcache_parameters.llcache.limit < MINIMUM_MEMORY_CACHE_SIZE) {
+ hlcache_parameters.llcache.limit = MINIMUM_MEMORY_CACHE_SIZE;
+ LOG(("Setting minimum memory cache size %d",
+ hlcache_parameters.llcache.limit));
}
/* image cache is 25% of total memory cache size */
- image_cache_parameters.limit = (hlcache_parameters.limit * 25) / 100;
+ image_cache_parameters.limit = (hlcache_parameters.llcache.limit * 25) / 100;
/* image cache hysteresis is 20% of the image cache size */
image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100;
/* account for image cache use from total */
- hlcache_parameters.limit -= image_cache_parameters.limit;
+ hlcache_parameters.llcache.limit -= image_cache_parameters.limit;
+
+ /* set backing store target limit */
+ hlcache_parameters.llcache.store.limit = nsoption_int(disc_cache_size);
+
+ /* set backing store hysterissi to 20% */
+ hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;;
+
+ /* set the path to the backing store */
+ /** \todo set the backing store path properly */
+ hlcache_parameters.llcache.store.path = "/tmp/ns";
/* image handler bitmap cache */
- error = image_cache_init(&image_cache_parameters);
- if (error != NSERROR_OK)
- return error;
+ ret = image_cache_init(&image_cache_parameters);
+ if (ret != NSERROR_OK)
+ return ret;
/* content handler initialisation */
- error = nscss_init();
- if (error != NSERROR_OK)
- return error;
+ ret = nscss_init();
+ if (ret != NSERROR_OK)
+ return ret;
- error = html_init();
- if (error != NSERROR_OK)
- return error;
+ ret = html_init();
+ if (ret != NSERROR_OK)
+ return ret;
- error = image_init();
- if (error != NSERROR_OK)
- return error;
+ ret = image_init();
+ if (ret != NSERROR_OK)
+ return ret;
- error = textplain_init();
- if (error != NSERROR_OK)
- return error;
+ ret = textplain_init();
+ if (ret != NSERROR_OK)
+ return ret;
- error = mimesniff_init();
- if (error != NSERROR_OK)
- return error;
+ ret = mimesniff_init();
+ if (ret != NSERROR_OK)
+ return ret;
url_init();
setlocale(LC_ALL, "C");
/* initialise the fetchers */
- error = fetch_init();
- if (error != NSERROR_OK)
- return error;
+ ret = fetch_init();
+ if (ret != NSERROR_OK)
+ return ret;
/* Initialise the hlcache and allow it to init the llcache for us */
- hlcache_initialise(&hlcache_parameters);
+ ret = hlcache_initialise(&hlcache_parameters);
+ if (ret != NSERROR_OK)
+ return ret;
/* Initialize system colours */
- error = ns_system_colour_init();
- if (error != NSERROR_OK)
- return error;
+ ret = ns_system_colour_init();
+ if (ret != NSERROR_OK)
+ return ret;
js_initialise();
- return ret;
+ return NSERROR_OK;
}
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=47493a689106a37b91e...
commit 47493a689106a37b91e506125c1f19f075aeac5e
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
low level source data cache backing store interface.
diff --git a/content/Makefile b/content/Makefile
index 557e6c7..6482f30 100644
--- a/content/Makefile
+++ b/content/Makefile
@@ -1,6 +1,6 @@
# Content sources
S_CONTENT := content.c content_factory.c dirlist.c fetch.c hlcache.c \
- llcache.c mimesniff.c urldb.c
+ llcache.c mimesniff.c urldb.c no_backing_store.c
-S_CONTENT := $(addprefix content/,$(S_CONTENT))
\ No newline at end of file
+S_CONTENT := $(addprefix content/,$(S_CONTENT))
diff --git a/content/backing_store.h b/content/backing_store.h
new file mode 100644
index 0000000..849e11a
--- /dev/null
+++ b/content/backing_store.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level source data cache backing store interface
+ */
+
+#ifndef NETSURF_CONTENT_LLCACHE_PRIVATE_H_
+#define NETSURF_CONTENT_LLCACHE_PRIVATE_H_
+
+#include "content/llcache.h"
+
+/** storage control flags */
+enum backing_store_flags {
+ BACKING_STORE_NONE = 0, /**< no special processing */
+ BACKING_STORE_META = 1, /**< data is metadata */
+ BACKING_STORE_MMAP = 2, /**< when data is retrived this indicates the
+ * returned buffer may be memory mapped,
+ * flag must be cleared if the storage is
+ * allocated and is not memory mapped.
+ */
+};
+
+/** low level cache backing store operation table
+ *
+ * The low level cache (source objects) has the capability to make
+ * objects and their metadata (headers etc) persistant by writing to a
+ * backing store using these operations.
+ */
+struct gui_llcache_table {
+ /**
+ * Initialise the backing store.
+ *
+ * @param parameters to configure backing store.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+ nserror (*initialise)(const struct llcache_store_parameters *parameters);
+
+ /**
+ * Finalise the backing store.
+ *
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+ nserror (*finalise)(void);
+
+ /**
+ * Place an object in the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the obejct is stored.
+ * @param data The objects data.
+ * @param datalen The length of the \a data.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+ nserror (*store)(struct nsurl *url, enum backing_store_flags flags,
+ const uint8_t *data, const size_t datalen);
+
+ /**
+ * Retrive an object from the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the object is retrived.
+ * @param data The objects data.
+ * @param datalen The length of the \a data retrieved.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+ nserror (*fetch)(struct nsurl *url, enum backing_store_flags *flags,
+ uint8_t **data, size_t *datalen);
+
+ /**
+ * Invalidate a source object from the backing store.
+ *
+ * The entry (if present in the backing store) must no longer
+ * be returned as a result to the fetch or meta operations.
+ *
+ * @param url The url is used as the unique primary key to invalidate.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+ nserror (*invalidate)(struct nsurl *url);
+};
+
+extern struct gui_llcache_table* null_llcache_table;
+extern struct gui_llcache_table* filesystem_llcache_table;
+
+#endif
diff --git a/content/no_backing_store.c b/content/no_backing_store.c
new file mode 100644
index 0000000..1921015
--- /dev/null
+++ b/content/no_backing_store.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache null persistant storage implementation.
+ */
+
+#include "utils/nsurl.h"
+
+#include "content/backing_store.h"
+
+
+/* default to disabled backing store */
+static nserror initialise(const struct llcache_store_parameters *parameters)
+{
+ return NSERROR_OK;
+}
+
+static nserror finalise(void)
+{
+ return NSERROR_OK;
+}
+
+static nserror store(nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen)
+{
+ return NSERROR_SAVE_FAILED;
+}
+
+static nserror fetch(nsurl *url,
+ enum backing_store_flags *flags,
+ uint8_t **data_out,
+ size_t *datalen_out)
+{
+ return NSERROR_NOT_FOUND;
+}
+
+static nserror invalidate(nsurl *url)
+{
+ return NSERROR_NOT_FOUND;
+}
+
+static struct gui_llcache_table llcache_table = {
+ .initialise = initialise,
+ .finalise = finalise,
+ .store = store,
+ .fetch = fetch,
+ .invalidate = invalidate,
+};
+
+struct gui_llcache_table *null_llcache_table = &llcache_table;
diff --git a/desktop/gui.h b/desktop/gui.h
index 317a733..96fe6a8 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -540,6 +540,8 @@ struct gui_browser_table {
};
+struct gui_llcache_table;
+
/** Graphical user interface function table
*
* function table implementing GUI interface to browser core
@@ -576,12 +578,20 @@ struct gui_table {
struct gui_utf8_table *utf8;
/**
- *
* Page search table.
*
* Provides routines for the interactive text search on a page.
*/
struct gui_search_table *search;
+
+ /**
+ * Low level cache table.
+ *
+ * Used by the low level cache to push objects to persistant
+ * storage. The table is optional and may be NULL which
+ * uses the default implementation.
+ */
+ struct gui_llcache_table *llcache;
};
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index ecedf41..0b9ec31 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -17,6 +17,8 @@
*/
#include "content/hlcache.h"
+#include "content/backing_store.h"
+
#include "desktop/download.h"
#include "desktop/gui_factory.h"
@@ -24,7 +26,6 @@
struct gui_table *guit = NULL;
-
static void gui_default_window_set_title(struct gui_window *g, const char *title)
{
}
@@ -399,6 +400,34 @@ static nserror verify_search_register(struct gui_search_table *gst)
return NSERROR_OK;
}
+/** verify low level cache persistant backing store table is valid */
+static nserror verify_llcache_register(struct gui_llcache_table *glt)
+{
+ /* check table is present */
+ if (glt == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* mandantory operations */
+ if (glt->store == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (glt->fetch == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (glt->invalidate == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (glt->initialise == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+ if (glt->finalise == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ return NSERROR_OK;
+}
+
static nsurl *gui_default_get_resource_url(const char *path)
{
return NULL;
@@ -599,6 +628,16 @@ nserror gui_factory_register(struct gui_table *gt)
return err;
}
+ /* llcache table */
+ if (gt->llcache == NULL) {
+ /* set default backing store table */
+ gt->llcache = null_llcache_table;
+ }
+ err = verify_llcache_register(gt->llcache);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
guit = gt;
return NSERROR_OK;
-----------------------------------------------------------------------
Summary of changes:
!NetSurf/Resources/ca-bundle | 469 +++++++++++----
.gitignore | 1 -
Docs/BUILDING-AmigaOS | 56 +-
Docs/BUILDING-Framebuffer | 221 +++++---
Docs/BUILDING-GTK | 175 ++++--
Docs/BUILDING-Monkey | 104 ----
Docs/QUICK-START | 18 +-
Docs/env.sh | 4 +-
Docs/source-object-backing-store | 194 ++++++
Makefile | 12 +-
Makefile.defaults | 5 +
amiga/Makefile.defaults | 76 ++--
amiga/arexx.c | 7 +-
amiga/clipboard.c | 3 +-
amiga/context_menu.c | 10 +-
amiga/dist/NetSurf.guide | 5 +
amiga/download.c | 12 +-
amiga/drag.c | 9 +-
amiga/dt_anim.c | 14 +-
amiga/dt_picture.c | 8 +-
amiga/dt_sound.c | 4 -
amiga/file.c | 27 +-
amiga/filetype.c | 31 +-
amiga/font.c | 2 -
amiga/font_scan.c | 4 +-
amiga/gui.c | 106 ++--
amiga/gui_options.c | 9 +-
amiga/history_local.c | 2 -
amiga/icon.c | 8 +-
amiga/iff_dr2d.c | 14 +-
amiga/launch.c | 5 +-
amiga/menu.c | 6 +-
amiga/misc.c | 5 +-
amiga/plotters.c | 29 +-
amiga/plugin_hack.c | 2 +-
amiga/plugin_hack.h | 2 -
amiga/print.c | 2 +-
amiga/search.c | 24 +-
amiga/search.h | 2 +
amiga/stringview/stringview.c | 1 -
amiga/theme.c | 11 +-
amiga/version.c | 2 +-
atari/Makefile.defaults | 77 ++--
atari/gui.c | 3 +-
atari/search.c | 19 +-
atari/search.h | 3 +
beos/Makefile.defaults | 42 +-
beos/gui.cpp | 4 +-
beos/schedule.cpp | 1 +
beos/schedule.h | 4 +-
cocoa/Makefile.defaults | 64 +-
cocoa/Makefile.target | 74 ++--
cocoa/NetsurfApp.m | 4 +-
cocoa/SearchWindowController.h | 2 +
cocoa/SearchWindowController.m | 10 +-
content/Makefile | 9 +-
content/backing_store.c | 554 ------------------
content/backing_store.h | 15 +-
content/content.c | 11 +-
content/content.h | 5 +-
content/content_protected.h | 6 +-
content/fetchers/Makefile | 2 +-
content/fetchers/about.c | 3 +-
content/fs_backing_store.c | 1194 ++++++++++++++++++++++++++++++++++++++
content/llcache.c | 142 ++++--
content/llcache.h | 8 -
content/no_backing_store.c | 68 +++
desktop/Makefile | 2 +-
desktop/gui.h | 57 ++-
desktop/gui_factory.c | 73 +++-
desktop/netsurf.c | 9 +-
desktop/netsurf.h | 2 +-
desktop/search.c | 63 +--
desktop/search.h | 56 +--
desktop/textarea.c | 13 +-
desktop/version.c | 6 +-
framebuffer/Makefile.defaults | 84 ++--
framebuffer/convert_image.c | 1 +
framebuffer/gui.c | 2 +-
gtk/Makefile.defaults | 45 +-
gtk/dialogs/preferences.c | 31 +-
gtk/gui.c | 476 ++++++++++++----
gtk/gui.h | 5 +-
gtk/scaffolding.c | 82 ++--
gtk/search.c | 126 ++---
gtk/search.h | 13 +-
gtk/window.c | 16 +-
monkey/Makefile.defaults | 19 +-
monkey/main.c | 2 +-
render/box_normalise.c | 66 ++-
render/html.c | 6 +-
render/html_interaction.c | 14 +-
render/html_internal.h | 3 +-
render/search.c | 67 +--
render/search.h | 3 +-
render/table.c | 8 +-
render/textplain.c | 8 +-
riscos/Makefile.defaults | 41 +-
riscos/download.c | 2 +
riscos/gui.c | 11 +-
riscos/gui.h | 1 +
riscos/mouse.c | 35 +-
riscos/mouse.h | 8 +-
riscos/search.c | 42 +-
riscos/toolbar.c | 4 +-
riscos/treeview.c | 9 +-
riscos/ucstables.c | 4 +-
test/Makefile | 13 +-
test/sha1.c | 55 --
utils/Makefile | 2 +-
utils/errors.h | 6 +-
utils/filename.c | 6 +-
utils/filepath.c | 86 +++-
utils/filepath.h | 55 ++-
utils/libdom.c | 56 +--
utils/sha1.c | 267 ---------
utils/sha1.h | 72 ---
utils/utils.h | 9 +-
windows/Makefile.defaults | 26 +-
windows/main.c | 2 +-
120 files changed, 3702 insertions(+), 2493 deletions(-)
mode change 100755 => 100644 !NetSurf/Resources/ca-bundle
delete mode 100644 Docs/BUILDING-Monkey
create mode 100644 Docs/source-object-backing-store
delete mode 100644 content/backing_store.c
create mode 100644 content/fs_backing_store.c
create mode 100644 content/no_backing_store.c
delete mode 100644 test/sha1.c
delete mode 100644 utils/sha1.c
delete mode 100644 utils/sha1.h
diff --git a/!NetSurf/Resources/ca-bundle b/!NetSurf/Resources/ca-bundle
old mode 100755
new mode 100644
index 93d3d2d..67f696a
--- a/!NetSurf/Resources/ca-bundle
+++ b/!NetSurf/Resources/ca-bundle
@@ -1,12 +1,12 @@
##
## ca-bundle.crt -- Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012
+## Certificate data from Mozilla as of: Tue Jan 28 09:38:07 2014
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
## file (certdata.txt). This file can be found in the mozilla source tree:
-## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/cert...
+## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/built...
##
## It contains the certificates in PEM format and therefore
## can be directly used with curl / libcurl / php_curl, or with
@@ -14,7 +14,6 @@
## Just configure this file as the SSLCACertificateFile.
##
-# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $
GTE CyberTrust Global Root
==========================
@@ -91,46 +90,6 @@ BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95
70+sB3c4
-----END CERTIFICATE-----
-Digital Signature Trust Co. Global CA 1
-=======================================
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE
-ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy
-MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs
-IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA
-A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE
-NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i
-o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo
-BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0
-dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
-IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY
-MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM
-BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB
-ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq
-kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4
-RbyhkwS7hp86W0N6w4pl
------END CERTIFICATE-----
-
-Digital Signature Trust Co. Global CA 3
-=======================================
------BEGIN CERTIFICATE-----
-MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE
-ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy
-MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs
-IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA
-A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD
-VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS
-xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo
-BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0
-dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw
-IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY
-MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM
-BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB
-AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi
-up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1
-mPnHfxsb1gYgAlihw6ID
------END CERTIFICATE-----
-
Verisign Class 3 Public Primary Certification Authority
=======================================================
-----BEGIN CERTIFICATE-----
@@ -344,11 +303,11 @@ n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI=
Entrust.net Premium 2048 Secure Server CA
=========================================
-----BEGIN CERTIFICATE-----
-MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u
ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp
bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV
BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx
-NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
+NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3
d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl
MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u
ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
@@ -356,14 +315,13 @@ MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL
Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr
hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW
nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi
-VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC
-AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER
-gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B
-AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
-oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS
-o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z
-2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX
-OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ==
+VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ
+KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy
+T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT
+J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e
+nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
Baltimore CyberTrust Root
@@ -421,26 +379,6 @@ lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+
KpYrtWKmpj29f5JZzVoqgrI3eQ==
-----END CERTIFICATE-----
-Equifax Secure eBusiness CA 2
-=============================
------BEGIN CERTIFICATE-----
-MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE
-ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y
-MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT
-DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB
-nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn
-2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5
-BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG
-A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx
-JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG
-A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e
-uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB
-Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1
-jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia
-78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm
-V+GRMOrN
------END CERTIFICATE-----
-
AddTrust Low-Value Services Root
================================
-----BEGIN CERTIFICATE-----
@@ -1405,29 +1343,6 @@ wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm
VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA=
-----END CERTIFICATE-----
-Wells Fargo Root CA
-===================
------BEGIN CERTIFICATE-----
-MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV
-BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv
-cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN
-MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl
-bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv
-MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX
-x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3
-E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5
-OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j
-sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj
-YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF
-BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD
-ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv
-m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R
-OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx
-x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023
-tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s=
------END CERTIFICATE-----
-
Swisscom Root CA 1
==================
-----BEGIN CERTIFICATE-----
@@ -2803,29 +2718,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r
kpeDMdmztcpHWD9f
-----END CERTIFICATE-----
-TC TrustCenter Universal CA III
-===============================
------BEGIN CERTIFICATE-----
-MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC
-REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy
-IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe
-Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU
-QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex
-KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB
-AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt
-QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO
-juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut
-CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1
-M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G
-A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
-BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA
-g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+
-KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK
-BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
-CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq
-woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
------END CERTIFICATE-----
-
Autoridad de Certificacion Firmaprofesional CIF A62634068
=========================================================
-----BEGIN CERTIFICATE-----
@@ -3552,3 +3444,342 @@ uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU
3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM
dcGWxZ0=
-----END CERTIFICATE-----
+
+TURKTRUST Certificate Services Provider Root 2007
+=================================================
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF
+bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP
+MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg
+QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X
+DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl
+a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN
+BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp
+bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N
+YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv
+KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya
+KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT
+rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC
+AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s
+Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO
+Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb
+BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK
+poRq0Tl9
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 2009
+==============================
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe
+Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE
+LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD
+ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA
+BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv
+KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z
+p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC
+AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ
+4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y
+eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw
+MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G
+PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw
+OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm
+2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV
+dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph
+X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+
+D-TRUST Root Class 3 CA 2 EV 2009
+=================================
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK
+DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw
+OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS
+egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh
+zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T
+7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60
+sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35
+11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv
+cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v
+ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El
+MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp
+b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh
+c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+
+PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX
+ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA
+NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
+w9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+
+PSCProcert
+==========
+-----BEGIN CERTIFICATE-----
+MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk
+ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ
+MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz
+dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl
+cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw
+IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw
+MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w
+DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD
+ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp
+Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC
+wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA
+3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh
+RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO
+EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2
+0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH
+0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU
+td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw
+Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp
+r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/
+AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz
+Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId
+xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp
+ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH
+EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h
+Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k
+ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG
+9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG
+MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG
+LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52
+ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy
+YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v
+Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o
+dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq
+T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN
+g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q
+uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1
+n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn
+FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo
+5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq
+3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5
+poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y
+eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km
+-----END CERTIFICATE-----
+
+China Internet Network Information Center EV Certificates Root
+==============================================================
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D
+aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg
+Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG
+A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM
+PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl
+cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y
+jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV
+98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H
+klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23
+KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC
+7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD
+glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5
+0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM
+7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0
+5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8=
+-----END CERTIFICATE-----
+
+Swisscom Root CA 2
+==================
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG
+EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy
+dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2
+MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln
+aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC
+IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM
+LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo
+ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ
+wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH
+Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a
+SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS
+NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab
+mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY
+Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3
+qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw
+HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
+BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu
+MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO
+v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ
+82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz
+o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs
+a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx
+OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW
+mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o
++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC
+rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX
+5OfNeOI5wSsSnqaeG8XmDtkx2Q==
+-----END CERTIFICATE-----
+
+Swisscom Root EV CA 2
+=====================
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE
+BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl
+cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN
+MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT
+HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg
+Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz
+o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy
+Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti
+GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li
+qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH
+Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG
+alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa
+m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox
+bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi
+xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
+MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB
+bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL
+j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU
+wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7
+XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH
+59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/
+23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq
+J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA
+HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi
+uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW
+l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc=
+-----END CERTIFICATE-----
+
+CA Disig Root R1
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
+3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
+u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
+m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
+CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
+YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
+vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
+LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
+ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
+XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
+04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
+LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
+CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
+VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
+YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
+ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
+lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
+UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
+a7+h89n07eLw4+1knj0vllJPgFOL
+-----END CERTIFICATE-----
+
+CA Disig Root R2
+================
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw
+EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
+ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx
+EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
+c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC
+w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia
+xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7
+A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S
+GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV
+g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa
+5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE
+koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A
+Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i
+Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u
+Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV
+sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je
+dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8
+1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx
+mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01
+utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0
+sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg
+UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV
+7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+
+ACCVRAIZ1
+=========
+-----BEGIN CERTIFICATE-----
+MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB
+SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1
+MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH
+UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
+DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM
+jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0
+RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD
+aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ
+0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG
+WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7
+8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR
+5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J
+9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK
+Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw
+Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu
+Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
+VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM
+Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA
+QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh
+AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA
+YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj
+AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA
+IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk
+aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0
+dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2
+MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI
+hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E
+R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN
+YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49
+nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ
+TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3
+sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
+I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg
+Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd
+3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p
+EfbRD0tVNEYqi4Y7
+-----END CERTIFICATE-----
+
+TWCA Global Root CA
+===================
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT
+CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD
+QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK
+EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C
+nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV
+r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR
+Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV
+tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W
+KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99
+sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p
+yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn
+kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI
+zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC
+AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g
+cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
+LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M
+8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg
+/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg
+lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP
+A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m
+i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8
+EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3
+zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0=
+-----END CERTIFICATE-----
diff --git a/.gitignore b/.gitignore
index 82d6b6c..7088130 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,6 @@ test/nsoption
test/nsurl
test/urldbtest
test/llcache
-utils/testament.h
codedocs
nsgtk
nsfb
diff --git a/Docs/BUILDING-AmigaOS b/Docs/BUILDING-AmigaOS
index c15db57..3239e88 100644
--- a/Docs/BUILDING-AmigaOS
+++ b/Docs/BUILDING-AmigaOS
@@ -1,5 +1,5 @@
--------------------------------------------------------------------------------
- Build Instructions for AmigaOS NetSurf 13 February 2010
+ Build Instructions for AmigaOS NetSurf 29 March 2014
--------------------------------------------------------------------------------
This document provides instructions for building the AmigaOS version of
@@ -59,19 +59,9 @@
To build and install these libraries, simply enter each of their directories
and run:
- 1> gmake install
+ 1> gmake PREFIX=/path/to/buildsystem
- | Note: We advise enabling iconv() support in libparserutils, which vastly
- | increases the number of supported character sets. To do this,
- | create a file called Makefile.config.override in the libparserutils
- | directory, containing the following lines:
- |
- | CFLAGS += -DWITH_ICONV_FILTER
- | LDFLAGS += -liconv
- |
- | This requires libiconv as iconv support in newlib.library is buggy.
- |
- | For more information, consult the libparserutils README file.
+ The path MUST be in UNIX format and point to directory containing "share".
| Note: Building libsvgtiny requires gperf, which is available from Aminet:
|
@@ -83,21 +73,23 @@
A version of libcurl built for newlib is available from Aminet
- http://www.aminet.net/package/dev/lib/libcurl
+ http://www.os4depot.net/share/development/library/misc/libcurl.lha
- There is a shared object version included with some OWB releases. To use
- this when compiling with Cairo support, a link must be made:
+ To use the shared object when compiling with Cairo support, a link must be made:
- 1> makelink sdk:local/newlib/lib/libcurl.so sobjs:libcurl-7.16.so soft
+ 1> makelink sdk:local/newlib/lib/libcurl.so sobjs:libcurl.so.8 soft
libpng
--------
NetSurf uses libPNG to display PNG files.
- It builds without any problems on OS4, or available from Aminet:
+ It builds without any problems on OS4, or available from OS4Depot:
- http://www.aminet.net/package/dev/lib/libpng_so
+ http://www.os4depot.net/share/development/library/graphics/libpng.lha
+
+ If building with Cairo, NetSurf MUST be linked against the version of
+ libpng.so included with OS4.
OpenSSL
@@ -107,11 +99,10 @@
http://www.os4depot.net/share/development/library/misc/libopenssl.lha
- There is a shared object version included with some OWB releases. To use
- this when compiling with Cairo support, a link must be made:
+ To use the shared object when compiling with Cairo support, a link must be made:
- 1> makelink sdk:local/newlib/lib/libssl.so sobjs:libssl-0.9.8.so soft
- 1> makelink sdk:local/newlib/lib/libcrypto.so sobjs:libssl-0.9.8.so soft
+ 1> makelink sdk:local/newlib/lib/libssl.so sobjs:libssl.so.1.0.0 soft
+ 1> makelink sdk:local/newlib/lib/libcrypto.so sobjs:libcrypto.so.1.0.0 soft
Libharu
@@ -141,19 +132,18 @@
http://www.aminet.net/package/comm/www/OpenURL-OS4
- General requirements
-----------------------
+ Spidermonkey
+--------------
- SDK:newlib/include/strings.h needs to be modified by adding the following:
+ Experimental Javascript support requires Spidermonkey. The patches to
+ build v1.7 are available from the NetSurf toolchains Git repository.
- extern int strcasecmp(const char *, const char *);
- extern int strncasecmp(const char *, const char *, size_t);
- amiga/version.c is generated by version.rexx using the SVN command. If
- the source has not been checked out from SVN, or is being cross-compiled,
- this file will need to be created by hand. See the end of version.rexx
- for the variables that are defined in the file.
+ General requirements
+----------------------
Please note that building with Cairo (option NETSURF_AMIGA_USE_CAIRO) will
link NetSurf against shared objects, and require the OS4.1 SDK to build and
- AmigaOS 4.1 to run.
+ AmigaOS 4.1 to run. There is no longer any advantage in building against
+ Cairo beyond anti-aliasing, and this option may be removed in the future.
+
diff --git a/Docs/BUILDING-Framebuffer b/Docs/BUILDING-Framebuffer
index 9cbd660..8e695c4 100644
--- a/Docs/BUILDING-Framebuffer
+++ b/Docs/BUILDING-Framebuffer
@@ -1,5 +1,5 @@
--------------------------------------------------------------------------------
- Build Instructions for Framebuffer NetSurf 13 February 2010
+ Build Instructions for Framebuffer NetSurf 16 March 2014
--------------------------------------------------------------------------------
This document provides instructions for building the Framebuffer version of
@@ -7,8 +7,153 @@
Framebuffer NetSurf has been tested on Ubuntu and Debian.
+ Depending on the framebuffer frontend selected the build may need specific
+ libraries installed, e.g. the SDL port requires SDL1.2 or later
+
+ There are two ways to get NetSurf building. The QUICK-START (recommended),
+ and the manual build. Whichever you choose, you should read both the
+ "Fonts", and "Selecting a frontend and appropriate options" sections below.
+
+
+ Quick Start
+=============
+
+ See the QUICK-START document, which provides a simple environment with
+ which you can fetch, build and install NetSurf and its dependencies.
+
+ The QUICK-START is the recommended way to build NetSurf.
+
+
+ Manual building
+=================
+
+ If you can't follow the quick start instructions, you will have to build
+ NetSurf manually. The instructions for doing this are given below.
+
+
+ Obtaining the build dependencies
+----------------------------------
+
+ Many of NetSurf's dependencies are packaged on various operating systems.
+ The remainder must be installed manually. Currently, some of the libraries
+ developed as part of the NetSurf project have not had official releases.
+ Hopefully they will soon be released with downloadable tarballs and packaged
+ in common distros. For now, you'll have to make do with Git checkouts.
+
+ Package installation
+ --------------------
+
+ Debian-like OS:
+
+ $ apt-get install libcurl3-dev libpng-dev
+
+ Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
+ note that when it has not been built with OpenSSL, the SSL_CTX is not
+ available and results that certification details won't be presented in case
+ they are invalid. But as this is currently unimplemented in the Framebuffer
+ flavour of NetSurf, this won't make a difference at all.
+
+ Fedora:
+
+ $ yum install curl-devel libpng-devel lcms-devel
+
+ Other:
+
+ You'll need to install the development resources for libcurl3 and libpng.
+
+
+ Preparing your workspace
+--------------------------
+
+ NetSurf has a number of libraries which must be built in-order and
+ installed into your workspace. Each library depends on a core build
+ system which NetSurf projects use. This build system relies on the
+ presence of things like pkg-config to find libraries and also certain
+ environment variables in order to work correctly.
+
+ Assuming you are preparing a workspace in /home/netsurf/workspace then
+ the following steps will set you up:
+
+ Make the workspace directory and change to it
+ ---------------------------------------------
+
+ $ mkdir -p ${HOME}/netsurf/workspace
+ $ cd ${HOME}/netsurf/workspace
+
+ Make the temporary install space
+ --------------------------------
+
+ $ mkdir inst
+
+ Make an environment script
+ --------------------------
+ $ cat > env.sh <<'EOF'
+ export PKG_CONFIG_PATH=${HOME}/netsurf/workspace/inst/lib/pkgconfig::
+ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/netsurf/workspace/inst/lib
+ export PREFIX=${HOME}/netsurf/workspace/inst
+ EOF
+
+ Change to workspace and source the environment
+ ----------------------------------------------
+
+ Whenever you wish to start development in a new shell, run the following:
+
+ $ cd ${HOME}/netsurf/workspace
+ $ source env.sh
+
+ From here on, any commands in this document assume you have sourced your
+ shell environment.
+
+
+ The NetSurf project's libraries
+---------------------------------
+
+ The NetSurf project has developed several libraries which are required by
+ the browser. These are:
+
+ BuildSystem -- Shared build system, needed to build the other libraries
+ LibParserUtils -- Parser building utility functions
+ LibWapcaplet -- String internment
+ Hubbub -- HTML5 compliant HTML parser
+ LibCSS -- CSS parser and selection engine
+ LibNSGIF -- GIF format image decoder
+ LibNSBMP -- BMP and ICO format image decoder
+ LibROSprite -- RISC OS Sprite format image decoder
+ LibNSFB -- Framebuffer abstraction
+
+ To fetch each of these libraries, run the appropriate commands from the
+ Docs/LIBRARIES file.
+
+ To build and install these libraries, simply enter each of their directories
+ and run:
+
+ $ make install
+
+ | Note: We advise enabling iconv() support in libparserutils, which vastly
+ | increases the number of supported character sets. To do this,
+ | create a file called Makefile.config.override in the libparserutils
+ | directory, containing the following line:
+ |
+ | CFLAGS += -DWITH_ICONV_FILTER
+ |
+ | For more information, consult the libparserutils README file.
+
+
+ Getting the NetSurf source
+----------------------------
+
+ From your workspace directory, run the following command to get the NetSurf
+ source:
+
+ $ git clone git://git.netsurf-browser.org/netsurf.git
+
+ And change to the 'netsurf' directory:
+
+ $ cd netsurf
+
+
Building and executing NetSurf
-================================
+--------------------------------
First of all, you should examine the contents of Makefile.defaults
and enable and disable relevant features as you see fit in a
@@ -203,75 +348,3 @@ Index: framebuffer/font_freetype.c
The documentation of libnsfb should be consulted for futher
information about supported frontends and their configuration.
-
- Obtaining NetSurf's build dependencies
-========================================
-
- Many of NetSurf's dependencies are packaged on various operating systems.
- The remainder must be installed manually. Currently, some of the libraries
- developed as part of the NetSurf project have not had official releases.
- Hopefully they will soon be released with downloadable tarballs and packaged
- in common distros. For now, you'll have to make do with Git checkouts.
-
- Package installation
-----------------------
-
- Debian-like OS:
-
- $ apt-get install libcurl3-dev libpng-dev
-
- Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
- note that when it has not been built with OpenSSL, the SSL_CTX is not
- available and results that certification details won't be presented in case
- they are invalid. But as this is currently unimplemented in the Framebuffer
- flavour of NetSurf, this won't make a difference at all.
-
- Fedora:
-
- $ yum install curl-devel libpng-devel lcms-devel
-
- Other:
-
- You'll need to install the development resources for libcurl3 and libpng.
-
- The NetSurf project's libraries
----------------------------------
-
- The NetSurf project has developed several libraries which are required by
- the browser. These are:
-
- LibParserUtils -- Parser building utility functions
- LibWapcaplet -- String internment
- Hubbub -- HTML5 compliant HTML parser
- LibCSS -- CSS parser and selection engine
- LibNSGIF -- GIF format image decoder
- LibNSBMP -- BMP and ICO format image decoder
- LibROSprite -- RISC OS Sprite format image decoder
- LibNSFB -- Framebuffer abstraction
-
- To fetch each of these libraries, run the appropriate commands from the
- Docs/LIBRARIES file.
-
- To build and install these libraries, simply enter each of their directories
- and run:
-
- $ sudo make install
-
- | Note: We advise enabling iconv() support in libparserutils, which vastly
- | increases the number of supported character sets. To do this,
- | create a file called Makefile.config.override in the libparserutils
- | directory, containing the following line:
- |
- | CFLAGS += -DWITH_ICONV_FILTER
- |
- | For more information, consult the libparserutils README file.
-
- General requirements
-----------------------
-
- Depending on the frontend selected the build may need specific
- libraries installed, e.g. the SDL port requires SDL1.2 or later
-
- Installing these libraries will often will pull in loads of things,
- like the PNG and JPEG libraries, colour management libraries, zlib,
- OpenSSL etc that NetSurf also depends on.
diff --git a/Docs/BUILDING-GTK b/Docs/BUILDING-GTK
index 4641924..dab2bef 100644
--- a/Docs/BUILDING-GTK
+++ b/Docs/BUILDING-GTK
@@ -1,51 +1,32 @@
--------------------------------------------------------------------------------
- Build Instructions for GTK NetSurf 8 April 2010
+ Build Instructions for GTK NetSurf 16 March 2014
--------------------------------------------------------------------------------
This document provides instructions for building the GTK version of NetSurf
and provides guidance on obtaining NetSurf's build dependencies.
GTK NetSurf has been tested on Debian, Ubuntu, Fedora 8, FreeBSD, NetBSD and
- Solaris 10.
+ Solaris 10. NetSurf requires at minimum GTK 2.12.
- Building and executing NetSurf
-================================
+ Quick Start
+=============
- First of all, you should examine the contents of Makefile.defaults
- and enable and disable relevant features as you see fit by creating
- a Makefile.config file. Some of these options can be automatically
- detected and used, and where this is the case they are set to such.
- Others cannot be automatically detected from the Makefile, so you
- will either need to install the dependencies, or set them to NO.
-
- You should then obtain NetSurf's dependencies, keeping in mind which options
- you have enabled in the configuration file. See the next section for
- specifics.
-
- Once done, to build GTK NetSurf on a UNIX-like platform, simply run:
+ See the QUICK-START document, which provides a simple environment with
+ which you can fetch, build and install NetSurf and its dependencies.
- $ make
+ The QUICK-START is the recommended way to build NetSurf.
- If that produces errors, you probably don't have some of NetSurf's
- build dependencies installed. See "Obtaining NetSurf's dependencies"
- below. Or turn off the complaining features in a Makefile.config
- file. You may need to "make clean" before attempting to build after
- installing the dependencies.
- Run NetSurf by executing the "test-nsgtk" shell script:
+ Manual building
+=================
- $ ./test-nsgtk
+ If you can't follow the quick start instructions, you will have to build
+ NetSurf manually. The instructions for doing this are given below.
- This script makes it easy to run the nsgtk binary from the build tree. It
- sets up some environment variables which enable NetSurf to find its
- resources.
- If you are packaging NetSurf, see the PACKAGING-GTK document.
-
-
- Obtaining NetSurf's build dependencies
-========================================
+ Obtaining the build dependencies
+----------------------------------
Many of NetSurf's dependencies are packaged on various operating systems.
The remainder must be installed manually. Currently, some of the libraries
@@ -53,16 +34,8 @@
Hopefully they will soon be released with downloadable tarballs and packaged
in common distros. For now, you'll have to make do with Git checkouts.
- Some of NetSurf's own libraries will be installed in /usr/local/ by default.
- Fedora, and perhaps some other distributions of Linux, do not ship a
- pkg-config that will search here, so you will either need to change where
- these libraries install, or do the following before building NetSurf itself;
-
- $ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
- $ export PKG_CONFIG_PATH
-
Package installation
-----------------------
+ --------------------
Debian-like OS:
@@ -92,12 +65,66 @@
You'll need to install the development resources for libglade2, libcurl3,
libpng and librsvg.
+ Libharu
+ -------
+
+ NetSurf can use Haru PDF to enable PDF export. Haru PDF can be obtained
+ from http://libharu.org/. We require libharu 2.2 or later.
+
+ | Note: libharu cannot be auto-detected by the Makefile. If you wish to
+ | enable it, do so by creating a Makefile.config file.
+
+
+ Preparing your workspace
+--------------------------
+
+ NetSurf has a number of libraries which must be built in-order and
+ installed into your workspace. Each library depends on a core build
+ system which NetSurf projects use. This build system relies on the
+ presence of things like pkg-config to find libraries and also certain
+ environment variables in order to work correctly.
+
+ Assuming you are preparing a workspace in /home/netsurf/workspace then
+ the following steps will set you up:
+
+ Make the workspace directory and change to it
+ ---------------------------------------------
+
+ $ mkdir -p ${HOME}/netsurf/workspace
+ $ cd ${HOME}/netsurf/workspace
+
+ Make the temporary install space
+ --------------------------------
+
+ $ mkdir inst
+
+ Make an environment script
+ --------------------------
+ $ cat > env.sh <<'EOF'
+ export PKG_CONFIG_PATH=${HOME}/netsurf/workspace/inst/lib/pkgconfig::
+ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${HOME}/netsurf/workspace/inst/lib
+ export PREFIX=${HOME}/netsurf/workspace/inst
+ EOF
+
+ Change to workspace and source the environment
+ ----------------------------------------------
+
+ Whenever you wish to start development in a new shell, run the following:
+
+ $ cd ${HOME}/netsurf/workspace
+ $ source env.sh
+
+ From here on, any commands in this document assume you have sourced your
+ shell environment.
+
+
The NetSurf project's libraries
---------------------------------
The NetSurf project has developed several libraries which are required by
the browser. These are:
+ BuildSystem -- Shared build system, needed to build the other libraries
LibParserUtils -- Parser building utility functions
LibWapcaplet -- String internment
Hubbub -- HTML5 compliant HTML parser
@@ -107,12 +134,12 @@
LibROSprite -- RISC OS Sprite format image decoder
To fetch each of these libraries, run the appropriate commands from the
- Docs/LIBRARIES file.
+ Docs/LIBRARIES file, from within your workspace directory.
To build and install these libraries, simply enter each of their directories
and run:
- $ sudo make install
+ $ make install
| Note: We advise enabling iconv() support in libparserutils, which vastly
| increases the number of supported character sets. To do this,
@@ -123,22 +150,56 @@
|
| For more information, consult the libparserutils README file.
- Libharu
----------
+ Now you should have all the NetSurf project libraries built and installed.
- NetSurf can use Haru PDF to enable PDF export. Haru PDF can be obtained
- from http://libharu.org/. We require libharu 2.2 or later.
- | Note: libharu cannot be auto-detected by the Makefile. If you wish to
- | enable it, do so by creating a Makefile.config file.
+ Getting the NetSurf source
+----------------------------
+
+ From your workspace directory, run the following command to get the NetSurf
+ source:
+
+ $ git clone git://git.netsurf-browser.org/netsurf.git
+
+ And change to the 'netsurf' directory:
+
+ $ cd netsurf
+
+ Building and executing NetSurf
+--------------------------------
+
+ First of all, you should examine the contents of Makefile.defaults
+ and enable and disable relevant features as you see fit by creating
+ a Makefile.config file. Some of these options can be automatically
+ detected and used, and where this is the case they are set to such.
+ Others cannot be automatically detected from the Makefile, so you
+ will either need to install the dependencies, or set them to NO.
+
+ You should then obtain NetSurf's dependencies, keeping in mind which options
+ you have enabled in the configuration file. See the next section for
+ specifics.
+
+ Once done, to build GTK NetSurf on a UNIX-like platform, simply run:
+
+ $ make
- General requirements
-----------------------
+ If that produces errors, you probably don't have some of NetSurf's
+ build dependencies installed. See "Obtaining NetSurf's dependencies"
+ below. Or turn off the complaining features in a Makefile.config
+ file. You may need to "make clean" before attempting to build after
+ installing the dependencies.
- NetSurf requires at minimum GTK 2.12. Earlier versions will not work. It also
- depends on Cairo for rendering, but you should have this already with
- versions of GTK 2.12 or later.
+ Run NetSurf by executing the "test-nsgtk" shell script:
+
+ $ ./test-nsgtk
+
+ This script makes it easy to run the nsgtk binary from the build tree. It
+ sets up some environment variables which enable NetSurf to find its
+ resources.
+
+
+ Note for packagers
+====================
+
+ If you are packaging NetSurf, see the PACKAGING-GTK document.
- This will pull in loads of things, like all the GTK dev libraries, the PNG
- and JPEG libraries, colour management libraries, zlib, OpenSSL etc that
- NetSurf also depends on.
diff --git a/Docs/BUILDING-Monkey b/Docs/BUILDING-Monkey
deleted file mode 100644
index 727124c..0000000
--- a/Docs/BUILDING-Monkey
+++ /dev/null
@@ -1,104 +0,0 @@
---------------------------------------------------------------------------------
- Build Instructions for Monkey NetSurf 13 March 2011
---------------------------------------------------------------------------------
-
- This document provides instructions for building the Monkey
- automation version of NetSurf and provides guidance on obtaining
- NetSurf's build dependencies.
-
- Monkey NetSurf has been tested on Ubuntu 10.10/amd64.
-
-
- Building and executing NetSurf
- ==============================
-
- First of all, you should examine the contents of Makefile.defaults
- and enable and disable relevant features as you see fit by creating
- a Makefile.config file. Some of these options can be automatically
- detected and used, and where this is the case they are set to such.
- Others cannot be automatically detected from the Makefile, so you
- will either need to install the dependencies, or set them to NO.
-
- You should then obtain NetSurf's dependencies, keeping in mind which options
- you have enabled in the configuration file. See the next section for
- specifics.
-
- Once done, to build Monkey NetSurf on a UNIX-like platform, simply run:
-
- $ make TARGET=monkey
-
- If that produces errors, you probably don't have some of NetSurf's
- build dependencies installed. See "Obtaining NetSurf's dependencies"
- below. Or turn off the complaining features in a Makefile.config
- file. You may need to "make clean" before attempting to build after
- installing the dependencies.
-
- Run NetSurf by executing the "nsmonkey" command from within the build tree.
-
- $ ./nsmonkey
-
- If you are packaging NetSurf, do NOT package nsmonkey. It is a debug tool.
-
-
- Obtaining NetSurf's build dependencies
- ======================================
-
- Many of NetSurf's dependencies are packaged on various operating systems.
- The remainder must be installed manually. Currently, some of the libraries
- developed as part of the NetSurf project have not had official releases.
- Hopefully they will soon be released with downloadable tarballs and packaged
- in common distros. For now, you'll have to make do with Git checkouts.
-
- Some of NetSurf's own libraries will be installed in /usr/local/ by default.
- Fedora, and perhaps some other distributions of Linux, do not ship a
- pkg-config that will search here, so you will either need to change where
- these libraries install, or do the following before building NetSurf itself;
-
- $ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
- $ export PKG_CONFIG_PATH
-
- Package installation
-----------------------
-
- Debian-like OS:
-
- $ apt-get install libcurl3-dev
-
- Recent OS versions might need libcurl4-dev instead of libcurl3-dev but
- note that when it has not been built with OpenSSL, the SSL_CTX is not
- available and results that certification details won't be presented in case
- they are invalid. But as this is currently unimplemented in the GTK
- flavour of NetSurf, this won't make a difference at all.
-
-
- The NetSurf project's libraries
- -------------------------------
-
- The NetSurf project has developed several libraries which are required by
- the browser. These are:
-
- LibParserUtils -- Parser building utility functions
- LibWapcaplet -- String internment
- Hubbub -- HTML5 compliant HTML parser
- LibCSS -- CSS parser and selection engine
- LibNSGIF -- GIF format image decoder
- LibNSBMP -- BMP and ICO format image decoder
- LibROSprite -- RISC OS Sprite format image decoder
-
- To fetch each of these libraries, run the appropriate commands from the
- Docs/LIBRARIES file.
-
- To build and install these libraries, simply enter each of their directories
- and run:
-
- $ sudo make install
-
- | Note: We advise enabling iconv() support in libparserutils, which vastly
- | increases the number of supported character sets. To do this,
- | create a file called Makefile.config.override in the libparserutils
- | directory, containing the following line:
- |
- | CFLAGS += -DWITH_ICONV_FILTER
- |
- | For more information, consult the libparserutils README file.
-
diff --git a/Docs/QUICK-START b/Docs/QUICK-START
index 917a3cf..237027b 100644
--- a/Docs/QUICK-START
+++ b/Docs/QUICK-START
@@ -2,8 +2,7 @@
Quick Build Steps for NetSurf 26 February 2014
--------------------------------------------------------------------------------
- This document provides steps for building the GTK version of NetSurf on a
- debian based linux system.
+ This document provides steps for building NetSurf.
Grab a temporary env.sh
@@ -19,11 +18,14 @@
Installs all packages required to build NetSurf and the NetSurf project
libraries.
- $ ns-apt-get-install
+ $ ns-package-install
+ If your package manager is not supported, you will have to install third
+ party packages manually.
- Get the NetSurf project source code
--------------------------------------
+
+ Get the NetSurf project source code from Git
+----------------------------------------------
$ ns-clone
@@ -48,10 +50,14 @@
-----------------------
$ cd netsurf
+
+ To build the native front end (the GTK front end on Linux, BSDs, etc) you
+ could do:
+
$ make
$ ./nsgtk
- For the framebuffer front end, you could do:
+ To build the framebuffer front end, you could do:
$ make TARGET=framebuffer
$ ./nsfb
diff --git a/Docs/env.sh b/Docs/env.sh
index 113916b..89f9add 100644
--- a/Docs/env.sh
+++ b/Docs/env.sh
@@ -80,7 +80,7 @@ fi
NS_DEV_DEB="build-essential pkg-config git gperf libcurl3-dev libpng-dev libjpeg-dev libmozjs185-dev"
NS_TOOL_DEB="flex bison libhtml-parser-perl"
if [ "x${NETSURF_GTK_MAJOR}" = "x3" ]; then
- NS_GTK_DEB="libgtk3-dev librsvg2-dev"
+ NS_GTK_DEB="libgtk-3-dev librsvg2-dev"
else
NS_GTK_DEB="libgtk2.0-dev librsvg2-dev"
fi
@@ -100,7 +100,7 @@ else
NS_GTK_RPM="gtk2-devel librsvg2-devel"
fi
-# apt get commandline to install necessary dev packages
+# yum commandline to install necessary dev packages
ns-yum-install()
{
sudo yum -y install $(echo ${NS_DEV_RPM} ${NS_TOOL_RPM} ${NS_GTK_RPM})
diff --git a/Docs/source-object-backing-store b/Docs/source-object-backing-store
new file mode 100644
index 0000000..e55a99d
--- /dev/null
+++ b/Docs/source-object-backing-store
@@ -0,0 +1,194 @@
+Source Object (low level) cache backing store
+=============================================
+
+Introduction
+------------
+
+The source object cache provides a system to extend the life of source
+objects (html files, images etc.) after they are no longer immediately
+being used.
+
+Only fetch types where we have well defined rules on caching are
+considered, in practice this limits us to HTTP(S). The section in
+RFC2616 [1] on caching specifies these rules.
+
+To futher extend the objects lifetime they can be pushed into a
+backing store where the objects are available for reuse less quickly
+than from RAM but faster than retriving from the network again.
+
+The backing store implementation provides a key:value infrastructure
+with a simple store, retrive and invalidate interface.
+
+Generic filesystem backing store
+--------------------------------
+
+Although the backing store interface is fully pluggable a generic
+implementation based on storing objects on the filesystem in a
+heirachy of directories.
+
+The option to alter the backing store format exists and is controled
+by a version field. It is implementation defined what happens if a
+version mis-match occours.
+
+As the backing store only holds cache data one should not expect a
+great deal of effort to be expended converting formats (i.e. the cache
+may simply be discarded).
+
+Layout version 1
+----------------
+
+An object has an identifier value generated from the url (NetSurf
+backing stores uses the url as the unique key). The value used is
+obtained using nsurl_hash() which is currently a 32 bit FNV so is
+directly usable.
+
+This identifier is adequate to ensure the collision rate for the
+hashed url values (a collision for every 2^16 urls added) is
+sufficiently low the overhead of returning the wrong object (which
+backing stores are permitted to do) is not significat.
+
+An entry list is maintained which contains all the metadata about a
+given identifier. This list is limited in length to constrain the
+resources necessary to maintain it. It is made persistant to avoid the
+overhead of reconstructing it at initialisation and to keep the data
+used to improve the eviction decisions.
+
+Each object is stored and retrived directly into the filesystem using
+a filename generated from a base64url encoding of an address
+value. The objects address is derived from the identifier by cropping
+it to a shorter length.
+
+A mapping between the object address and its entry is maintained which
+uses storage directly proportional to the size of the address length.
+
+The cropping length is stored in the control file with the default
+values set at compile time. This allows existing backing stores to
+continue operating with existing data independantly of new default
+setting. This setting gives some ability to tune the default cache
+index size to values suitable for a specific host operating system.
+
+E.g. Linux based systems can easily cope with several megabytes of
+mmaped index but RISC OS might want to limit this to a few megabytes
+of heap at most.
+
+The files are stored on disc using their base64url address value.
+By creating a directory for each character of the encoded filename
+(except the last which is of course the leafname) we create a
+directory structure where no directory has more than 64 entries.
+
+E.g. A 19bit address of 0x1 would be base64url encoded into AAAB
+resulting in the data being stored in a file path of
+"/store/prefix/data/B/A/A/BAAAAA".
+
+An address of 0x00040001 encodes to BAAB and a file path of
+"/store/prefix/meta/B/A/A/BAABAA"
+
+Control files
+~~~~~~~~~~~~~
+
+control
++++++++
+A control file is used to hold a list of values describing how the
+other files in the backing store should be used.
+
+entries
++++++++
+
+this file contains a table of entries describing the files held on the
+filesystem.
+
+Each control file table entry is 28 bytes and consists of
+
+ - signed 64 but value for last use time
+
+ - 32bit full url hash allowing for index reconstruction and
+ addiitonal collision detection. Also the possibility of increasing
+ the ADDRESS_LENGTH although this would require renaming all the
+ existing files in the cache and is not currently implemented.
+
+ - unsigned 32bit length for data
+
+ - unsigned 32bit length for metadata
+
+ - unsigned 16bit value for number of times used.
+
+ - unsigned 16bit value for flags
+
+ - unsigned 16bit value for data block index (unused)
+
+ - unsigned 16bit value for metatdata block index (unused)
+
+Address to entry index
+~~~~~~~~~~~~~~~~~~~~~~
+
+An entry index is held in RAM that allows looking up the address to
+map to an entry in the control file.
+
+The index is the only data structure whose size is directly depndant
+on the length of the hash specificaly:
+
+(2 ^ (ADDRESS_BITS - 3)) * ENTRY_BITS) in bytes
+
+where ADDRESS_BITS is how long the address is in bits and ENTRY_BITS
+is how many entries the control file (and hence the while
+cache) may hold.
+
+RISCOS values
++++++++++++++
+
+By limiting the ENTRY_BITS size to 14 (16,384 entries) the entries
+list is limited to 448kilobytes.
+
+The typical values for RISC OS would set ADDRESS_BITS to 18. This
+spreads the entries over 262144 hash values which uses 512 kilobytes
+for the index. Limiting the hash space like this reduces the
+efectiveness of the cache.
+
+A small ADDRESS_LENGTH causes a collision (two urls with the same
+address) to happen roughly for every 2 ^ (ADDRESS_BITS / 2) = 2 ^ 9 =
+512 objects stored. This roughly translates to a cache miss due to
+collision every ten pages navigated to.
+
+Larger systems
+++++++++++++++
+
+In general ENTRY_BITS set to 16 as this limits the store to 65536
+objects which given the average size of an object at 8 kilobytes
+yeilds half a gigabyte of disc used which is judged to be sufficient.
+
+For larger systems e.g. those using GTK frontend we would most likely
+select ADDRESS_BITS as 22 resulting in a collision every 2048 objects
+but the index using some 8 Megabytes
+
+Typical values
+--------------
+
+Example 1
+~~~~~~~~~
+
+For a store with 1034 objects genrated from a random navigation of
+pages linked from the about:welcome page.
+
+Metadata total size is 593608 bytes an average of 574 bytes. The
+majority of the storage is used to hold the urls and headers.
+
+Data total size is 9180475 bytes a mean of 8879 bytes 1648726 in the
+largest 10 entries which if excluded gives 7355 bytes average size
+
+Example 2
+~~~~~~~~~
+
+355 pages navigated in 80 minutes from about:welcome page and a
+handful of additional sites (google image search and reddit)
+
+2018 objects in cache at quit. 400 objects from news.bbc.co.uk alone
+
+Metadata total 987,439 bytes mean of 489 bytes
+
+data total 33,127,831 bytes mean of 16,416 bytes
+
+with one single 5,000,811 byte gif
+
+data totals without gif is 28,127,020 mean 13,945
+
+[1] http://tools.ietf.org/html/rfc2616#section-13
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 1638f32..4f9380a 100644
--- a/Makefile
+++ b/Makefile
@@ -609,8 +609,8 @@ clean-target:
$(call clean_install_messages, !NetSurf/Resources)
clean-testament:
- $(VQ)echo " CLEAN: utils/testament.h"
- $(Q)$(RM) utils/testament.h
+ $(VQ)echo " CLEAN: testament.h"
+ $(Q)$(RM) $(OBJROOT)/testament.h
clean-builddir:
$(VQ)echo " CLEAN: $(OBJROOT)"
@@ -621,12 +621,8 @@ all-program: $(EXETARGET) post-exe
$(call split_install_messages, any, !NetSurf/Resources)
.PHONY: testament
-testament utils/testament.h:
- $(Q)if test -d .svn; then \
- $(PERL) utils/svn-testament.pl $(CURDIR) utils/testament.h; \
- else \
- $(PERL) utils/git-testament.pl $(CURDIR) utils/testament.h; \
- fi
+testament $(OBJROOT)/testament.h:
+ $(Q)$(PERL) utils/git-testament.pl $(CURDIR) $(OBJROOT)/testament.h
post-exe: $(POSTEXES)
diff --git a/Makefile.defaults b/Makefile.defaults
index e11fa1f..9779331 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -86,6 +86,11 @@ NETSURF_HOMEPAGE := "about:welcome"
# Valid options: YES, NO
NETSURF_USE_LIBICONV_PLUG := YES
+# Enable building the source object cache filesystem based backing store.
+# implementation.
+# Valid options: YES, NO
+NETSURF_FS_BACKING_STORE := NO
+
# Initial CFLAGS. Optimisation level etc. tend to be target specific.
CFLAGS :=
diff --git a/amiga/Makefile.defaults b/amiga/Makefile.defaults
index 35c35ae..43b42b2 100644
--- a/amiga/Makefile.defaults
+++ b/amiga/Makefile.defaults
@@ -2,41 +2,41 @@
# Amiga-specific options
# ----------------------------------------------------------------------------
- # Force using glibc internal iconv implementation instead of external libiconv
- # Valid options: YES, NO
- NETSURF_USE_LIBICONV_PLUG := YES
-
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := NO
-
- # Enable NetSurf's use of libwebp for displaying WebPs
- # Valid options: YES, NO
- NETSURF_USE_WEBP := NO
-
- # Enable NetSurf to display Amiga icons
- # Valid options: YES, NO (recommended)
- NETSURF_USE_AMIGA_ICON := YES
-
- # Enable NetSurf's use of DataTypes for unknown filetypes
- # Valid options: YES, NO
- NETSURF_USE_AMIGA_DATATYPES := YES
-
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO
- NETSURF_USE_NSSVG := YES
-
- # Enable NetSurf's use of libcairo for some plotter functions
- # This will also link NetSurf with shared objects, and
- # requires AmigaOS 4.1 or higher to run the resulting executable
- # Valid options: YES, NO, AUTO
- NETSURF_USE_AMIGA_CAIRO := AUTO
-
- # Enable NetSurf's use of Spidermonkey 1.80+
- # Only here to stop the build complaining;
- # enable NETSURF_USE_MOZJS instead for JavaScript support
- # Valid options: NO
- NETSURF_USE_JS := NO
-
- # Optimisation levels
- CFLAGS += -O2 -gstabs
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := YES
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
+
+# Enable NetSurf's use of libwebp for displaying WebPs
+# Valid options: YES, NO
+NETSURF_USE_WEBP := NO
+
+# Enable NetSurf to display Amiga icons
+# Valid options: YES, NO (recommended)
+NETSURF_USE_AMIGA_ICON := YES
+
+# Enable NetSurf's use of DataTypes for unknown filetypes
+# Valid options: YES, NO
+NETSURF_USE_AMIGA_DATATYPES := YES
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO
+NETSURF_USE_NSSVG := YES
+
+# Enable NetSurf's use of libcairo for some plotter functions
+# This will also link NetSurf with shared objects, and
+# requires AmigaOS 4.1 or higher to run the resulting executable
+# Valid options: YES, NO, AUTO
+NETSURF_USE_AMIGA_CAIRO := AUTO
+
+# Enable NetSurf's use of Spidermonkey 1.80+
+# Only here to stop the build complaining;
+# enable NETSURF_USE_MOZJS instead for JavaScript support
+# Valid options: NO
+NETSURF_USE_JS := NO
+
+# Optimisation levels
+CFLAGS += -O2 -gstabs
diff --git a/amiga/arexx.c b/amiga/arexx.c
index 240aafe..3bac0c2 100644
--- a/amiga/arexx.c
+++ b/amiga/arexx.c
@@ -196,12 +196,12 @@ int ami_find_tab_bw(struct gui_window_2 *gwin, struct browser_window *bw)
struct browser_window *ami_find_tab(int window, int tab)
{
- int windows = 0, tabs = 0;
struct nsObject *node, *nnode;
- struct gui_window_2 *gwin;
if(!IsMinListEmpty(window_list))
{
+ int windows = 0;
+
node = (struct nsObject *)GetHead((struct List *)window_list);
do
@@ -569,7 +569,6 @@ STATIC VOID rx_windows(struct ARexxCmd *cmd, struct RexxMsg *rxm __attribute__((
STATIC VOID rx_active(struct ARexxCmd *cmd, struct RexxMsg *rxm __attribute__((unused)))
{
- int windows = 0, tabs = 0;
int window = 0, tab = 0;
struct browser_window *bw = curbw;
struct nsObject *node, *nnode;
@@ -579,6 +578,8 @@ STATIC VOID rx_active(struct ARexxCmd *cmd, struct RexxMsg *rxm __attribute__((u
if(!IsMinListEmpty(window_list))
{
+ int windows = 0;
+
node = (struct nsObject *)GetHead((struct List *)window_list);
do
diff --git a/amiga/clipboard.c b/amiga/clipboard.c
index 6768dde..fa1d189 100644
--- a/amiga/clipboard.c
+++ b/amiga/clipboard.c
@@ -185,12 +185,10 @@ char *ami_clipboard_cat_collection(struct CollectionItem *ci, LONG codeset, size
void gui_get_clipboard(char **buffer, size_t *length)
{
- struct ContextNode *cn;
struct CollectionItem *ci = NULL;
struct StoredProperty *sp = NULL;
ULONG rlen=0,error;
struct CSet *cset;
- LONG codeset = 0;
if(OpenIFF(iffh,IFFF_READ)) return;
@@ -204,6 +202,7 @@ void gui_get_clipboard(char **buffer, size_t *length)
if(ci = FindCollection(iffh, ID_FTXT, ID_UTF8)) {
*buffer = ami_clipboard_cat_collection(ci, 106, length);
} else if(ci = FindCollection(iffh, ID_FTXT, ID_CHRS)) {
+ LONG codeset = 0;
if(sp = FindProp(iffh, ID_FTXT, ID_CSET)) {
cset = (struct CSet *)sp->sp_Data;
codeset = cset->CodeSet;
diff --git a/amiga/context_menu.c b/amiga/context_menu.c
index 3bff4c2..e1ce551 100644
--- a/amiga/context_menu.c
+++ b/amiga/context_menu.c
@@ -269,7 +269,7 @@ void ami_context_menu_add_submenu(Object *ctxmenuobj, ULONG cmsub, void *userdat
PMIA_UserData, nsurl_access(hlcache_handle_get_url(userdata)),
PMIA_CommKey, "B",
TAG_DONE),
- TAG_DONE),
+ PMEND,
TAG_DONE),
~0);
break;
@@ -324,7 +324,7 @@ void ami_context_menu_add_submenu(Object *ctxmenuobj, ULONG cmsub, void *userdat
PMIA_UserData, userdata,
PMIA_Disabled, (content_get_type(userdata) != CONTENT_HTML),
TAG_DONE),
- TAG_DONE),
+ PMEND,
TAG_DONE),
~0);
break;
@@ -364,7 +364,7 @@ void ami_context_menu_add_submenu(Object *ctxmenuobj, ULONG cmsub, void *userdat
PMIA_UserData, userdata,
PMIA_Disabled, !browser_window_stop_available(userdata),
TAG_DONE),
- TAG_DONE),
+ PMEND,
TAG_DONE),
~0);
break;
@@ -410,7 +410,7 @@ void ami_context_menu_add_submenu(Object *ctxmenuobj, ULONG cmsub, void *userdat
PMIA_ID, CMID_SAVEURL,
PMIA_UserData, userdata,
TAG_DONE),
- TAG_DONE),
+ PMEND,
TAG_DONE),
~0);
break;
@@ -467,7 +467,7 @@ void ami_context_menu_add_submenu(Object *ctxmenuobj, ULONG cmsub, void *userdat
PMIA_UserData, userdata,
PMIA_Disabled, !ami_mime_content_to_cmd(userdata),
TAG_DONE),
- TAG_DONE),
+ PMEND,
TAG_DONE),
~0);
break;
diff --git a/amiga/dist/NetSurf.guide b/amiga/dist/NetSurf.guide
index 25310bd..5aaf60a 100755
--- a/amiga/dist/NetSurf.guide
+++ b/amiga/dist/NetSurf.guide
@@ -183,6 +183,7 @@ Commands are:
@{b}OPEN URL/A,NEW=NEWWINDOW/S,NEWTAB/S,SAVEAS/K,W=WINDOW/K/N,T=TAB/K/N@{ub}
Opens URL in current window or a new window/tab if NEWWINDOW/NEWTAB is specified. Saves the location without displaying if SAVEAS and a filename is specified (SAVEAS available in 2.6325)
+Note that if the URL is non-ASCII it is expected to be encoded in UTF-8 (file: references should always be in local charset due to filesystem limitations). Usually this is not relevant, as all normalised URLs will be in their ASCII form.
@{b}SAVE FILENAME/A,W=WINDOW/K/N,T=TAB/K/N@{ub} (2.6027)
Saves current page source to FILENAME
@@ -255,6 +256,10 @@ Under OS4.1 Update 1, launch-handler is used in preference to OpenURL. The
Installer script can add the relevant configuration to launch URLs in NetSurf.
Please ensure your email application is configured in URL Prefs for mailto:
links clicked within NetSurf.
+
+Note that a helper script is installed in S:ARexx which can be used instead of
+the main executable, to stop the NetSurf executable from being loaded again if
+it is already running.
@endnode
@node hotlist "Hotlist menu"
diff --git a/amiga/download.c b/amiga/download.c
index 0f8ae4c..7ce47a3 100644
--- a/amiga/download.c
+++ b/amiga/download.c
@@ -89,7 +89,6 @@ static struct gui_download_window *gui_download_window_create(download_context *
struct gui_window *gui)
{
const char *url = download_context_get_url(ctx);
- const char *mime_type = download_context_get_mime_type(ctx);
unsigned long total_size = download_context_get_total_length(ctx);
struct gui_download_window *dw;
char *dl_filename = ami_utf8_easy(download_context_get_filename(ctx));
@@ -230,11 +229,12 @@ static nserror gui_download_window_data(struct gui_download_window *dw,
static void gui_download_window_done(struct gui_download_window *dw)
{
struct dlnode *dln,*dln2 = NULL;
- struct browser_window *bw = dw->bw;
+ struct browser_window *bw;
bool queuedl = false;
STRPTR sendcmd = NULL;
if(!dw) return;
+ bw = dw->bw;
if((nsoption_bool(download_notify)) && (dw->result == AMINS_DLOAD_OK))
{
@@ -346,7 +346,6 @@ void ami_free_download_list(struct List *dllist)
void
gui_window_save_link(struct gui_window *g, const char *url, const char *title)
{
- BPTR fh = 0;
char fname[1024];
STRPTR openurlstring,linkname;
struct DiskObject *dobj = NULL;
@@ -368,6 +367,8 @@ gui_window_save_link(struct gui_window *g, const char *url, const char *title)
if(ami_download_check_overwrite(fname, g->shared->win, 0))
{
+ BPTR fh;
+
if(fh = FOpen(fname,MODE_NEWFILE,0))
{
/* TODO: Should be URLOpen on OS4.1 */
@@ -400,8 +401,6 @@ BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG si
/* Return TRUE if file can be (over-)written */
int32 res = 0;
BPTR lock = 0;
- BPTR fh = 0;
- int64 oldsize = 0;
char *overwritetext;
if(nsoption_bool(ask_overwrite) == false) return TRUE;
@@ -411,6 +410,9 @@ BOOL ami_download_check_overwrite(const char *file, struct Window *win, ULONG si
if(lock)
{
if(size) {
+ BPTR fh;
+ int64 oldsize = 0;
+
if(fh = OpenFromLock(lock)) {
oldsize = GetFileSize(fh);
Close(fh);
diff --git a/amiga/drag.c b/amiga/drag.c
index f8944d3..09df0d0 100644
--- a/amiga/drag.c
+++ b/amiga/drag.c
@@ -98,9 +98,8 @@ void gui_drag_save_selection(struct gui_window *g, const char *selection)
void ami_drag_save(struct Window *win)
{
- ULONG which = WBO_NONE,type;
- char path[1025],dpath[1025];
- const char *source_data;
+ ULONG which = WBO_NONE, type;
+ char path[1025], dpath[1025];
ULONG source_size;
ami_drag_icon_close(NULL);
@@ -195,10 +194,8 @@ void ami_drag_save(struct Window *win)
void ami_drag_icon_show(struct Window *win, const char *type)
{
struct DiskObject *dobj = NULL;
- ULONG *icondata1;
ULONG width, height;
- long format = 0;
- int err = 0;
+ int err;
int deftype = WBPROJECT;
drag_in_progress = TRUE;
diff --git a/amiga/dt_anim.c b/amiga/dt_anim.c
index c844700..4722d2d 100644
--- a/amiga/dt_anim.c
+++ b/amiga/dt_anim.c
@@ -92,7 +92,6 @@ static const content_handler amiga_dt_anim_content_handler = {
nserror amiga_dt_anim_init(void)
{
- char dt_mime[50];
struct DataType *dt, *prevdt = NULL;
lwc_string *type;
lwc_error lerror;
@@ -161,14 +160,11 @@ bool amiga_dt_anim_convert(struct content *c)
amiga_dt_anim_content *plugin = (amiga_dt_anim_content *) c;
union content_msg_data msg_data;
int width, height;
- char title[100];
const uint8 *data;
UBYTE *bm_buffer;
ULONG size;
- Object *dto;
struct BitMapHeader *bmh;
unsigned int bm_flags = BITMAP_NEW | BITMAP_OPAQUE;
- int bm_format = PBPAFMT_RGBA;
struct adtFrame adt_frame;
APTR clut;
@@ -341,20 +337,20 @@ APTR ami_colormap_to_clut(struct ColorMap *cmap)
{
int i;
UBYTE *clut = AllocVecTags(256 * 4, AVT_ClearWithValue, 0, TAG_DONE); /* NB: Was not MEMF_PRIVATE */
- ULONG colour[3 * 256];
+ ULONG colr[256 * 4];
if(!clut) return NULL;
/* Get the palette from the ColorMap */
- GetRGB32(cmap, 0, 256, (ULONG *)&colour);
+ GetRGB32(cmap, 0, 256, (ULONG *)&colr);
/* convert it to a table of ARGB values */
for(i = 0; i < 1024; i += 4)
{
clut[i] = (0xff << 24) |
- ((colour[i] & 0xff000000) >> 8) |
- ((colour[i + 1] & 0xff000000) >> 16) |
- ((colour[i + 2] & 0xff000000) >> 24);
+ ((colr[i] & 0xff000000) >> 8) |
+ ((colr[i + 1] & 0xff000000) >> 16) |
+ ((colr[i + 2] & 0xff000000) >> 24);
}
return clut;
diff --git a/amiga/dt_picture.c b/amiga/dt_picture.c
index 211d221..779e1bc 100644
--- a/amiga/dt_picture.c
+++ b/amiga/dt_picture.c
@@ -62,7 +62,6 @@ struct amiga_dt_picture_content {
nserror amiga_dt_picture_init(void)
{
- char dt_mime[50];
struct DataType *dt, *prevdt = NULL;
lwc_string *type;
lwc_error lerror;
@@ -175,7 +174,6 @@ static struct bitmap *amiga_dt_picture_cache_convert(struct content *c)
UBYTE *bm_buffer;
Object *dto;
struct bitmap *bitmap;
- unsigned int bm_flags = BITMAP_NEW;
#ifdef __amigaos4__
int bm_format = PBPAFMT_RGBA;
#else
@@ -185,7 +183,7 @@ static struct bitmap *amiga_dt_picture_cache_convert(struct content *c)
if(dto = amiga_dt_picture_newdtobject(adt))
{
- bitmap = bitmap_create(c->width, c->height, bm_flags);
+ bitmap = bitmap_create(c->width, c->height, BITMAP_NEW);
if (!bitmap) {
msg_data.error = messages_get("NoMemory");
content_broadcast(c, CONTENT_MSG_ERROR, msg_data);
@@ -214,14 +212,10 @@ bool amiga_dt_picture_convert(struct content *c)
{
LOG(("amiga_dt_picture_convert"));
- union content_msg_data msg_data;
int width, height;
char *title;
- UBYTE *bm_buffer;
Object *dto;
struct BitMapHeader *bmh;
- unsigned int bm_flags = BITMAP_NEW;
- int bm_format = PBPAFMT_RGBA;
char *filetype;
if(dto = amiga_dt_picture_newdtobject((struct amiga_dt_picture_content *)c))
diff --git a/amiga/dt_sound.c b/amiga/dt_sound.c
index 3f82169..a1daf03 100644
--- a/amiga/dt_sound.c
+++ b/amiga/dt_sound.c
@@ -77,7 +77,6 @@ void amiga_dt_sound_play(Object *dto)
nserror amiga_dt_sound_init(void)
{
- char dt_mime[50];
struct DataType *dt, *prevdt = NULL;
lwc_string *type;
lwc_error lerror;
@@ -146,12 +145,9 @@ bool amiga_dt_sound_convert(struct content *c)
LOG(("amiga_dt_sound_convert"));
amiga_dt_sound_content *plugin = (amiga_dt_sound_content *) c;
- union content_msg_data msg_data;
int width = 50, height = 50;
- char title[100];
const uint8 *data;
ULONG size;
- Object *dto;
data = (uint8 *)content__get_source_data(c, &size);
diff --git a/amiga/file.c b/amiga/file.c
index 91d3755..008141c 100644
--- a/amiga/file.c
+++ b/amiga/file.c
@@ -49,8 +49,6 @@ static struct Hook aslhookfunc;
static const ULONG ami_file_asl_mime_hook(struct Hook *mh,
struct FileRequester *fr, struct AnchorPathOld *ap)
{
- BPTR file = 0;
- char buffer[10];
char fname[1024];
BOOL ret = FALSE;
char *mt = NULL;
@@ -151,23 +149,19 @@ void ami_file_save(int type, char *fname, struct Window *win,
struct hlcache_handle *object, struct hlcache_handle *favicon,
struct browser_window *bw)
{
- BPTR lock = 0;
+ BPTR lock, fh;
const char *source_data;
ULONG source_size;
struct bitmap *bm;
- BPTR fh=0;
ami_update_pointer(win, GUI_POINTER_WAIT);
- if(ami_download_check_overwrite(fname, win, 0))
- {
- switch(type)
- {
+ if(ami_download_check_overwrite(fname, win, 0)) {
+ switch(type) {
case AMINS_SAVE_SOURCE:
- if((source_data = content_get_source_data(object, &source_size)))
- {
- if(fh = FOpen(fname, MODE_NEWFILE,0))
- {
+ if((source_data = content_get_source_data(object, &source_size))) {
+ BPTR fh;
+ if(fh = FOpen(fname, MODE_NEWFILE,0)) {
FWrite(fh, source_data, 1, source_size);
FClose(fh);
}
@@ -179,8 +173,7 @@ void ami_file_save(int type, char *fname, struct Window *win,
break;
case AMINS_SAVE_COMPLETE:
- if(lock = CreateDir(fname))
- {
+ if(lock = CreateDir(fname)) {
UnLock(lock);
save_complete(object, fname, ami_file_set_type);
amiga_icon_superimpose_favicon(fname, favicon, NULL);
@@ -195,15 +188,13 @@ void ami_file_save(int type, char *fname, struct Window *win,
break;
case AMINS_SAVE_IFF:
- if((bm = content_get_bitmap(object)))
- {
+ if((bm = content_get_bitmap(object))) {
bm->url = (char *)nsurl_access(hlcache_handle_get_url(object));
bm->title = (char *)content_get_title(object);
bitmap_save(bm, fname, 0);
}
#ifdef WITH_NS_SVG
- else if(ami_mime_compare(object, "svg") == true)
- {
+ else if(ami_mime_compare(object, "svg") == true) {
ami_save_svg(object, fname);
}
#endif
diff --git a/amiga/filetype.c b/amiga/filetype.c
index 0cb4ac4..2d55e1f 100644
--- a/amiga/filetype.c
+++ b/amiga/filetype.c
@@ -55,9 +55,7 @@ enum
const char *fetch_filetype(const char *unix_path)
{
static char mimetype[50];
- STRPTR ttype = NULL;
struct DiskObject *dobj = NULL;
- BPTR lock = 0;
struct DataType *dtn;
BOOL found = FALSE;
lwc_string *lwc_mimetype;
@@ -66,8 +64,7 @@ const char *fetch_filetype(const char *unix_path)
We'll just do a filename check here for quickness, although the
first word ought to be checked against WB_DISKMAGIC really. */
- if(strncmp(unix_path + strlen(unix_path) - 5, ".info", 5) == 0)
- {
+ if(strncmp(unix_path + strlen(unix_path) - 5, ".info", 5) == 0) {
strcpy(mimetype,"image/x-amiga-icon");
found = TRUE;
}
@@ -76,32 +73,26 @@ const char *fetch_filetype(const char *unix_path)
/* Secondly try getting a tooltype "MIMETYPE" and use that as the MIME type.
Will fail over to default icons if the file doesn't have a real icon. */
- if(!found)
- {
+ if(!found) {
if(dobj = GetIconTags(unix_path,ICONGETA_FailIfUnavailable,FALSE,
- TAG_DONE))
- {
+ TAG_DONE)) {
+ STRPTR ttype = NULL;
ttype = FindToolType(dobj->do_ToolTypes, "MIMETYPE");
- if(ttype)
- {
+ if(ttype) {
strcpy(mimetype,ttype);
found = TRUE;
}
-
FreeDiskObject(dobj);
}
}
/* If that didn't work, use the MIME file and DataTypes */
- if(!found)
- {
- if (lock = Lock (unix_path, ACCESS_READ))
- {
- if (dtn = ObtainDataTypeA (DTST_FILE, (APTR)lock, NULL))
- {
- if(ami_mime_from_datatype(dtn, &lwc_mimetype, NULL))
- {
+ if(!found) {
+ BPTR lock;
+ if (lock = Lock (unix_path, ACCESS_READ)) {
+ if (dtn = ObtainDataTypeA (DTST_FILE, (APTR)lock, NULL)) {
+ if(ami_mime_from_datatype(dtn, &lwc_mimetype, NULL)) {
strcpy(mimetype, lwc_string_data(lwc_mimetype));
found = TRUE;
ReleaseDataType(dtn);
@@ -173,9 +164,7 @@ const char *ami_content_type_to_file_type(content_type type)
nserror ami_mime_init(const char *mimefile)
{
- lwc_string *type;
lwc_error lerror;
- nserror error;
char buffer[256];
BPTR fh = 0;
struct RDArgs *rargs = NULL;
diff --git a/amiga/font.c b/amiga/font.c
index df4a188..148d860 100755
--- a/amiga/font.c
+++ b/amiga/font.c
@@ -204,8 +204,6 @@ bool nsfont_position_in_string(const plot_font_style_t *fstyle,
FIXED kern = 0;
struct OutlineFont *ofont, *ufont = NULL;
uint32 tx=0,i=0;
- size_t len, utf8len = 0;
- uint8 *utf8;
int utf8_pos = 0;
uint32 co = 0;
int utf16charlen;
diff --git a/amiga/font_scan.c b/amiga/font_scan.c
index f3ad36e..a2738f2 100644
--- a/amiga/font_scan.c
+++ b/amiga/font_scan.c
@@ -294,7 +294,7 @@ ULONG ami_font_scan_fonts(struct MinList *list,
*/
ULONG ami_font_scan_list(struct MinList *list)
{
- int afShortage, afSize = 100, i;
+ int afShortage, afSize = 100;
struct AvailFontsHeader *afh;
struct AvailFonts *af;
ULONG found = 0;
@@ -315,7 +315,7 @@ ULONG ami_font_scan_list(struct MinList *list)
if(afh) {
af = (struct AvailFonts *)&(afh[1]);
- for(i = 0; i < afh->afh_NumEntries; i++) {
+ for(int i = 0; i < afh->afh_NumEntries; i++) {
if(af[i].af_Attr.ta_Style == FS_NORMAL) {
if(af[i].af_Attr.ta_Name != NULL) {
node = (struct nsObject *)FindIName((struct List *)list,
diff --git a/amiga/gui.c b/amiga/gui.c
index 84e9dc9..8a1cb5e 100644
--- a/amiga/gui.c
+++ b/amiga/gui.c
@@ -251,13 +251,12 @@ static bool path_add_part(char *path, int length, const char *newpart)
STRPTR ami_locale_langs(void)
{
struct Locale *locale;
- STRPTR acceptlangs = NULL, acceptlangs2 = NULL;
- int i;
+ STRPTR acceptlangs = NULL;
char *remapped;
if(locale = OpenLocale(NULL))
{
- for(i=0;i<10;i++)
+ for(int i = 0; i < 10; i++)
{
if(locale->loc_PrefLanguages[i])
{
@@ -266,7 +265,7 @@ STRPTR ami_locale_langs(void)
{
if(acceptlangs)
{
- acceptlangs2 = acceptlangs;
+ STRPTR acceptlangs2 = acceptlangs;
acceptlangs = ASPrintf("%s, %s",acceptlangs2, remapped);
FreeVec(acceptlangs2);
acceptlangs2 = NULL;
@@ -329,7 +328,6 @@ bool ami_gui_map_filename(char **remapped, const char *path, const char *file, c
bool ami_gui_check_resource(char *fullpath, const char *file)
{
- bool free_rmap = false;
bool found = false;
char *remapped;
BPTR lock = 0;
@@ -464,7 +462,7 @@ colour_option_from_pen(UWORD pen,
struct Screen *screen,
colour def_colour)
{
- ULONG colour[3];
+ ULONG colr[3];
struct DrawInfo *drinfo;
if((option < NSOPTION_SYS_COLOUR_START) ||
@@ -480,12 +478,12 @@ colour_option_from_pen(UWORD pen,
if(pen == AMINS_SCROLLERPEN) pen = ami_system_colour_scrollbar_fgpen(drinfo);
/* Get the colour of the pen being used for "pen" */
- GetRGB32(screen->ViewPort.ColorMap, drinfo->dri_Pens[pen], 1, (ULONG *)&colour);
+ GetRGB32(screen->ViewPort.ColorMap, drinfo->dri_Pens[pen], 1, (ULONG *)&colr);
/* convert it to a color */
- def_colour = ((colour[0] & 0xff000000) >> 24) |
- ((colour[1] & 0xff000000) >> 16) |
- ((colour[2] & 0xff000000) >> 8);
+ def_colour = ((colr[0] & 0xff000000) >> 24) |
+ ((colr[1] & 0xff000000) >> 16) |
+ ((colr[2] & 0xff000000) >> 8);
FreeScreenDrawInfo(screen, drinfo);
}
@@ -549,7 +547,6 @@ static void ami_set_screen_defaults(struct Screen *screen)
static nserror ami_set_options(struct nsoption_s *defaults)
{
STRPTR tempacceptlangs;
- BPTR lock = 0;
char temp[1024];
/* The following line disables the popupmenu.class select menu
@@ -607,15 +604,16 @@ static nserror ami_set_options(struct nsoption_s *defaults)
if (nsoption_charp(font_unicode) == NULL)
{
+ BPTR lock = 0;
/* Search for some likely candidates */
- if(lock=Lock("FONTS:Code2000.font",ACCESS_READ))
+ if(lock = Lock("FONTS:Code2000.font", ACCESS_READ))
{
UnLock(lock);
nsoption_set_charp(font_unicode,
(char *)strdup("Code2000"));
}
- else if(lock=Lock("FONTS:Bitstream Cyberbit.font",ACCESS_READ))
+ else if(lock = Lock("FONTS:Bitstream Cyberbit.font", ACCESS_READ))
{
UnLock(lock);
nsoption_set_charp(font_unicode,
@@ -639,7 +637,7 @@ void ami_amiupdate(void)
{
/* Create AppPath location for AmiUpdate use */
- BPTR lock = 0, amiupdatefh = 0;
+ BPTR lock = 0;
if(((lock = Lock("ENVARC:AppPaths",SHARED_LOCK)) == 0))
{
@@ -651,6 +649,7 @@ void ami_amiupdate(void)
if(lock = Lock("PROGDIR:", ACCESS_READ))
{
char filename[1024];
+ BPTR amiupdatefh;
DevNameFromLock(lock,(STRPTR)&filename,1024L,DN_FULLPATH);
@@ -764,7 +763,7 @@ void ami_openscreen(void)
}
}
- screen_signal = AllocSignal(-1);
+ if(screen_signal == -1) screen_signal = AllocSignal(-1);
LOG(("Screen signal %d", screen_signal));
scrn = OpenScreenTags(NULL,
SA_DisplayID, id,
@@ -783,6 +782,9 @@ void ami_openscreen(void)
}
else
{
+ FreeSignal(screen_signal);
+ screen_signal = -1;
+
if(scrn = LockPubScreen("NetSurf"))
{
locked_screen = TRUE;
@@ -836,7 +838,7 @@ static void ami_gui_commandline(int *argc, char **argv)
if(args = ReadArgs(template, rarray, NULL)) {
if(rarray[A_URL]) {
LOG(("URL %s specified on command line", rarray[A_URL]));
- temp_homepage_url = (char *)strdup((char *)rarray[A_URL]);
+ temp_homepage_url = ami_to_utf8_easy((char *)rarray[A_URL]);
}
if(rarray[A_FORCE]) {
@@ -932,10 +934,6 @@ static void gui_init2(int argc, char** argv)
int first=0,i=0;
char fullpath[1024];
- if (notalreadyrunning &&
- (nsoption_bool(startup_no_window) == false))
- ami_openscreenfirst();
-
for(i=0,wbarg=WBenchMsg->sm_ArgList;i<WBenchMsg->sm_NumArgs;i++,wbarg++)
{
if(i==0) continue;
@@ -949,7 +947,6 @@ static void gui_init2(int argc, char** argv)
if(notalreadyrunning)
{
error = nsurl_create(temp_homepage_url, &url);
-
if (error == NSERROR_OK) {
if(!first)
@@ -1227,7 +1224,6 @@ bool ami_spacebox_to_ns_coords(struct gui_window_2 *gwin, int *x, int *y,
bool ami_mouse_to_ns_coords(struct gui_window_2 *gwin, int *x, int *y,
int mouse_x, int mouse_y)
{
- int xs, ys;
int ns_x, ns_y;
struct IBox *bbox;
@@ -1449,20 +1445,19 @@ static void gui_window_set_icon(struct gui_window *g, hlcache_handle *icon)
void ami_handle_msg(void)
{
- struct IntuiMessage *message = NULL;
ULONG class,result,storage = 0,x,y,xs,ys,width=800,height=600;
uint16 code,quals;
struct IBox *bbox;
struct nsObject *node;
struct nsObject *nnode;
struct gui_window_2 *gwin = NULL;
- struct MenuItem *item;
struct InputEvent *ie;
struct Node *tabnode;
- int i, nskey;
+ int nskey;
struct browser_window *closedbw;
struct timeval curtime;
static int drag_x_move = 0, drag_y_move = 0;
+ char *utf8 = NULL;
nsurl *url;
if(IsMinListEmpty(window_list))
@@ -1788,12 +1783,13 @@ void ami_handle_msg(void)
GetAttr(STRINGA_TextVal,
(Object *)gwin->objects[GID_URL],
(ULONG *)&storage);
- if(search_is_url((char *)storage) == false)
- {
- storage = (ULONG)search_web_from_term((char *)storage);
- }
- {
- if (nsurl_create((char *)storage, &url) != NSERROR_OK) {
+ if(utf8 = ami_to_utf8_easy((const char *)storage)) {
+ if(search_is_url((char *)utf8) == false)
+ {
+ utf8 = search_web_from_term(utf8);
+ }
+
+ if (nsurl_create((char *)utf8, &url) != NSERROR_OK) {
warn_user("NoMemory", 0);
} else {
browser_window_navigate(gwin->bw,
@@ -1805,6 +1801,9 @@ void ami_handle_msg(void)
NULL);
nsurl_unref(url);
}
+ ami_utf8_free(utf8);
+ } else {
+ warn_user("NoMemory", 0);
}
break;
@@ -1817,8 +1816,10 @@ void ami_handle_msg(void)
GetAttr(STRINGA_TextVal,
(Object *)gwin->objects[GID_SEARCHSTRING],
(ULONG *)&storage);
- storage = (ULONG)search_web_from_term((char *)storage);
- {
+ if(utf8 = ami_to_utf8_easy((const char *)storage)) {
+ storage = (ULONG)search_web_from_term(utf8);
+ ami_utf8_free(utf8);
+
if (nsurl_create((char *)storage, &url) != NSERROR_OK) {
warn_user("NoMemory", 0);
} else {
@@ -1831,6 +1832,8 @@ void ami_handle_msg(void)
NULL);
nsurl_unref(url);
}
+ } else {
+ warn_user("NoMemory", 0);
}
break;
@@ -1884,7 +1887,6 @@ void ami_handle_msg(void)
GetAttr(STRINGA_TextVal,
(Object *)gwin->objects[GID_URL],
(ULONG *)&storage);
-
if(nsurl_create((const char *)storage, &url) == NSERROR_OK) {
if(hotlist_has_url(url)) {
hotlist_remove_url(url);
@@ -1893,7 +1895,6 @@ void ami_handle_msg(void)
}
nsurl_unref(url);
}
-
ami_gui_update_hotlist_button(gwin);
break;
@@ -2158,7 +2159,6 @@ void ami_handle_msg(void)
case WMHI_ICONIFY:
{
- struct DiskObject *dobj;
struct bitmap *bm;
bm = urldb_get_thumbnail(hlcache_handle_get_url(gwin->bw->current_content));
@@ -2742,8 +2742,6 @@ void ami_try_quit(void)
static void gui_quit(void)
{
- int i;
-
ami_theme_throbber_free();
urldb_save(nsoption_charp(url_file));
@@ -3164,8 +3162,6 @@ gui_window_create(struct browser_window *bw,
gui_window_create_flags flags)
{
struct gui_window *g = NULL;
- bool closegadg=TRUE;
- struct Node *node;
ULONG curx=nsoption_int(window_x),cury=nsoption_int(window_y),curw=nsoption_int(window_width),curh=nsoption_int(window_height);
char nav_west[100],nav_west_s[100],nav_west_g[100];
char nav_east[100],nav_east_s[100],nav_east_g[100];
@@ -3549,7 +3545,7 @@ gui_window_create(struct browser_window *bw,
GA_TabCycle, TRUE,
STRINGA_Buffer, g->shared->svbuffer,
STRINGVIEW_Header, URLHistory_GetList(),
- StringEnd,
+ TAG_DONE),
LAYOUT_AddChild, g->shared->objects[GID_FAVE] = ButtonObject,
GA_ID, GID_FAVE,
@@ -4165,9 +4161,7 @@ static void ami_do_redraw_limits(struct gui_window *g, struct browser_window *bw
struct IBox *bbox;
ULONG cur_tab = 0;
ULONG sx, sy;
- struct rect clip;
- struct RastPort *temprp;
- int posx, posy;
+
struct redraw_context ctx = {
.interactive = true,
.background_images = true,
@@ -4290,13 +4284,10 @@ static void gui_window_update_box(struct gui_window *g, const struct rect *rect)
static void ami_do_redraw(struct gui_window_2 *gwin)
{
- struct Region *reg = NULL;
struct Rectangle rect;
- hlcache_handle *c;
ULONG hcurrent,vcurrent,xoffset,yoffset,width=800,height=600,x0=0,y0=0;
struct IBox *bbox;
ULONG oldh = gwin->oldh, oldv=gwin->oldv;
- bool morescroll = false;
struct RastPort *temprp;
if(browser_window_redraw_ready(gwin->bw) == false) return;
@@ -4308,8 +4299,6 @@ static void ami_do_redraw(struct gui_window_2 *gwin)
gwin->bw->window->scrollx = hcurrent;
gwin->bw->window->scrolly = vcurrent;
- c = gwin->bw->current_content;
-
width=bbox->Width;
height=bbox->Height;
xoffset=bbox->Left;
@@ -4334,7 +4323,6 @@ static void ami_do_redraw(struct gui_window_2 *gwin)
if(gwin->redraw_scroll)
{
struct rect rect;
- int x0, y0, x1, y1;
gwin->bw->window->c_h_temp = gwin->bw->window->c_h;
gui_window_remove_caret(gwin->bw->window);
@@ -4425,7 +4413,7 @@ void ami_refresh_window(struct gui_window_2 *gwin)
struct IBox *bbox;
int x0, x1, y0, y1, sx, sy;
- struct RegionRectangle *regrect, *nregrect;
+ struct RegionRectangle *regrect;
sx = gwin->bw->window->scrollx;
sy = gwin->bw->window->scrolly;
@@ -4699,7 +4687,6 @@ static void gui_set_search_ico(hlcache_handle *ico)
struct nsObject *node;
struct nsObject *nnode;
struct gui_window_2 *gwin;
- char fname[100];
struct bitmap *ico_bitmap;
if(IsMinListEmpty(window_list)) return;
@@ -4813,9 +4800,6 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh
static void gui_window_remove_caret(struct gui_window *g)
{
- struct IBox *bbox;
- int xs,ys;
-
if(!g) return;
if(g->c_h == 0) return;
@@ -4874,9 +4858,7 @@ void ami_scroller_hook(struct Hook *hook,Object *object,struct IntuiMessage *msg
ULONG gid;
struct gui_window_2 *gwin = hook->h_Data;
struct IntuiWheelData *wheel;
- Object *reqrefresh = NULL;
struct Node *node = NULL;
- char *urltxt;
nsurl *url;
switch(msg->Class)
@@ -4949,8 +4931,7 @@ void ami_scroller_hook(struct Hook *hook,Object *object,struct IntuiMessage *msg
bool ami_text_box_at_point(struct gui_window_2 *gwin, ULONG *x, ULONG *y)
{
struct IBox *bbox;
- ULONG xs,ys,width,height;
- int box_x=0,box_y=0;
+ ULONG xs, ys, width, height;
struct contextual_content data;
GetAttr(SPACE_AreaBox, (Object *)gwin->objects[GID_BROWSER],
@@ -5161,6 +5142,7 @@ int main(int argc, char** argv)
.download = amiga_download_table,
.fetch = &amiga_fetch_table,
.utf8 = amiga_utf8_table,
+ .search = amiga_search_table,
};
/* Open popupmenu.library just to check the version.
@@ -5192,7 +5174,7 @@ int main(int argc, char** argv)
ami_schedule_create();
amiga_plugin_hack_init();
- amiga_datatypes_init();
+ ret = amiga_datatypes_init();
/* initialise logging. Not fatal if it fails but not much we
* can do about it either.
@@ -5209,12 +5191,12 @@ int main(int argc, char** argv)
if (ami_locate_resource(messages, "Messages") == false)
die("Cannot open Messages file");
- ret = netsurf_init(messages, &amiga_gui_table);
+ ret = netsurf_init(messages, NULL, &amiga_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
- amiga_icon_init();
+ ret = amiga_icon_init();
gui_init(argc, argv);
gui_init2(argc, argv);
diff --git a/amiga/gui_options.c b/amiga/gui_options.c
index b969eb8..877ff09 100755
--- a/amiga/gui_options.c
+++ b/amiga/gui_options.c
@@ -198,7 +198,7 @@ enum
#define OPTS_MAX_TABS 10
#define OPTS_MAX_SCREEN 4
#define OPTS_MAX_PROXY 5
-#define OPTS_MAX_NATIVEBM 3
+#define OPTS_MAX_NATIVEBM 4
#define OPTS_MAX_DITHER 4
struct ami_gui_opts_window {
@@ -410,6 +410,8 @@ void ami_gui_opts_open(void)
BOOL download_notify_disabled = FALSE;
BOOL ptr_disable = FALSE;
char animspeed[10];
+ char *homepage_url_lc = ami_utf8_easy(nsoption_charp(homepage_url));
+
struct TextAttr fontsans, fontserif, fontmono, fontcursive, fontfantasy;
if(gow && gow->win)
@@ -557,7 +559,7 @@ void ami_gui_opts_open(void)
LAYOUT_AddChild, gow->objects[GID_OPTS_HOMEPAGE] = StringObject,
GA_ID, GID_OPTS_HOMEPAGE,
GA_RelVerify, TRUE,
- STRINGA_TextVal, nsoption_charp(homepage_url),
+ STRINGA_TextVal, homepage_url_lc,
STRINGA_BufferPos,0,
StringEnd,
CHILD_Label, LabelObject,
@@ -1529,6 +1531,7 @@ void ami_gui_opts_open(void)
gow->node = AddObject(window_list,AMINS_GUIOPTSWINDOW);
gow->node->objstruct = gow;
}
+ ami_utf8_free(homepage_url_lc);
}
void ami_gui_opts_use(bool save)
@@ -1543,7 +1546,7 @@ void ami_gui_opts_use(bool save)
ami_update_pointer(gow->win, GUI_POINTER_WAIT);
GetAttr(STRINGA_TextVal,gow->objects[GID_OPTS_HOMEPAGE],(ULONG *)&data);
- nsoption_set_charp(homepage_url, (char *)strdup((char *)data));
+ nsoption_set_charp(homepage_url, (char *)ami_to_utf8_easy((char *)data));
GetAttr(STRINGA_TextVal,gow->objects[GID_OPTS_CONTENTLANG],(ULONG *)&data);
nsoption_set_charp(accept_language, (char *)strdup((char *)data));
diff --git a/amiga/history_local.c b/amiga/history_local.c
index 1f710b2..4849c65 100755
--- a/amiga/history_local.c
+++ b/amiga/history_local.c
@@ -74,7 +74,6 @@ static void ami_history_scroller_hook(struct Hook *hook,Object *object,struct In
void ami_history_open(struct browser_window *bw, struct history *history)
{
int width, height;
- struct IBox *bbox;
assert(history);
@@ -239,7 +238,6 @@ BOOL ami_history_event(struct history_window *hw)
/* return TRUE if window destroyed */
ULONG class,result,relevent = 0;
uint16 code;
- struct MenuItem *item;
const char *url;
struct IBox *bbox;
ULONG xs, ys;
diff --git a/amiga/icon.c b/amiga/icon.c
index c5bc6ae..66a008f 100644
--- a/amiga/icon.c
+++ b/amiga/icon.c
@@ -39,6 +39,7 @@
#include "amiga/os3support.h"
#include "amiga/bitmap.h"
#include "amiga/icon.h"
+#include "amiga/misc.h"
#include "desktop/plotters.h"
#include "image/bitmap.h"
#include "content/content_protected.h"
@@ -139,7 +140,7 @@ bool amiga_icon_convert(struct content *c)
ULONG size;
int width = 0, height = 0;
long format = 0;
- int err = 0;
+ int err;
uint8 r, g, b, a;
ULONG offset;
const char *url;
@@ -365,7 +366,7 @@ void amiga_icon_superimpose_favicon_internal(struct hlcache_handle *icon, struct
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err = 0;
+ int err;
if(dobj == NULL) return;
@@ -420,11 +421,10 @@ void amiga_icon_superimpose_favicon_internal(struct hlcache_handle *icon, struct
void amiga_icon_superimpose_favicon(char *path, struct hlcache_handle *icon, char *type)
{
struct DiskObject *dobj = NULL;
- struct BitMap *bm = NULL;
ULONG *icondata1, *icondata2;
ULONG width, height;
long format = 0;
- int err = 0;
+ int err;
ULONG trans1, pals1;
ULONG trans2, pals2;
struct ColorRegister *pal1;
diff --git a/amiga/iff_dr2d.c b/amiga/iff_dr2d.c
index 0638b94..5709d41 100644
--- a/amiga/iff_dr2d.c
+++ b/amiga/iff_dr2d.c
@@ -31,7 +31,7 @@ ULONG numcols;
ULONG findcolour(ULONG newcol)
{
ULONG i;
- ULONG colour = 0xFFFFFFFF;
+ ULONG colr = 0xFFFFFFFF;
UBYTE red,grn,blu;
red = svgtiny_RED(newcol);
@@ -41,21 +41,20 @@ ULONG findcolour(ULONG newcol)
for(i=0;i<numcols;i++)
{
if((cm[i].red == red) && (cm[i].green == grn) && (cm[i].blue == blu))
- colour = i;
+ colr = i;
}
- return colour;
+ return colr;
}
void addcolour(ULONG newcol)
{
- int i;
- ULONG colour;
+ ULONG colr;
UBYTE red,grn,blu;
- colour = findcolour(newcol);
+ colr = findcolour(newcol);
- if(colour == 0xFFFFFFFF)
+ if(colr == 0xFFFFFFFF)
{
cm[numcols].red = svgtiny_RED(newcol);
cm[numcols].green = svgtiny_GREEN(newcol);
@@ -342,7 +341,6 @@ int main(int argc, char **argv)
{
BPTR fh = 0;
char *buffer;
- size_t n;
struct IFFHandle *iffh = NULL;
int64 size;
LONG rarray[] = {0,0};
diff --git a/amiga/launch.c b/amiga/launch.c
index ebd8229..1ccc520 100755
--- a/amiga/launch.c
+++ b/amiga/launch.c
@@ -105,8 +105,6 @@ BOOL ami_openurl_check_list(struct MinList *list, const char *url)
void ami_openurl_open(void)
{
- struct ami_protocol *ami_p;
-
if(nsoption_bool(use_openurl_lib)) {
if(OpenURLBase = OpenLibrary("openurl.library",0))
IOpenURL = (struct OpenURLIFace *)GetInterface(OpenURLBase,"main",1,NULL);
@@ -128,7 +126,6 @@ void gui_launch_url(const char *url)
{
APTR procwin = SetProcWindow((APTR)-1L);
char *launchurl = NULL;
- BPTR fptr = 0;
if(ami_openurl_check_list(&ami_unsupportedprotocols, url) == FALSE)
{
@@ -137,7 +134,7 @@ void gui_launch_url(const char *url)
URL_OpenA((STRPTR)url,NULL);
} else {
if(launchurl = ASPrintf("URL:%s",url)) {
- fptr = Open(launchurl,MODE_OLDFILE);
+ BPTR fptr = Open(launchurl,MODE_OLDFILE);
if(fptr) Close(fptr);
else ami_openurl_add_protocol(url);
FreeVec(launchurl);
diff --git a/amiga/menu.c b/amiga/menu.c
index 13b9c9c..b2e2334 100644
--- a/amiga/menu.c
+++ b/amiga/menu.c
@@ -456,8 +456,6 @@ static struct gui_window_2 *ami_menu_layout(struct gui_window_2 *gwin)
struct NewMenu *ami_create_menu(struct gui_window_2 *gwin)
{
- int i;
-
gwin->menu = AllocVecTags(sizeof(struct NewMenu) * (AMI_MENU_AREXX_MAX + 1),
AVT_ClearWithValue, 0, TAG_DONE);
ami_init_menulabs(gwin);
@@ -1029,7 +1027,6 @@ static void ami_menu_item_hotlist_show(struct Hook *hook, APTR window, struct In
static void ami_menu_item_hotlist_entries(struct Hook *hook, APTR window, struct IntuiMessage *msg)
{
nsurl *url = hook->h_Data;
- nserror error;
struct gui_window_2 *gwin;
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
@@ -1096,13 +1093,13 @@ static void ami_menu_item_arexx_entries(struct Hook *hook, APTR window, struct I
char *script = hook->h_Data;
char *temp;
struct gui_window_2 *gwin;
- BPTR lock = 0;
GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
if(script)
{
if(temp = AllocVecTagList(1024, NULL))
{
+ BPTR lock;
if(lock = Lock(nsoption_charp(arexx_dir), SHARED_LOCK)) {
DevNameFromLock(lock, temp, 1024, DN_FULLPATH);
AddPart(temp, script, 1024);
@@ -1113,3 +1110,4 @@ static void ami_menu_item_arexx_entries(struct Hook *hook, APTR window, struct I
}
}
}
+
diff --git a/amiga/misc.c b/amiga/misc.c
index ac9d245..3f69834 100755
--- a/amiga/misc.c
+++ b/amiga/misc.c
@@ -43,7 +43,6 @@ void warn_user(const char *warning, const char *detail)
Object *req = NULL;
char *utf8warning = ami_utf8_easy(messages_get(warning));
STRPTR bodytext = NULL;
- LONG result = 0;
LOG(("%s %s", warning, detail));
@@ -63,7 +62,7 @@ void warn_user(const char *warning, const char *detail)
TAG_DONE);
if (req) {
- result = IDoMethod(req, RM_OPENREQ, NULL, NULL, scrn);
+ LONG result = IDoMethod(req, RM_OPENREQ, NULL, NULL, scrn);
DisposeObject(req);
}
@@ -108,7 +107,7 @@ void die(const char *error)
char *url_to_path(const char *url)
{
- char *tmps, *unesc, *slash, *colon, *url2;
+ char *unesc, *slash, *colon, *url2;
if (strncmp(url, "file://", SLEN("file://")) != 0)
return NULL;
diff --git a/amiga/plotters.c b/amiga/plotters.c
index 05db67f..de90755 100755
--- a/amiga/plotters.c
+++ b/amiga/plotters.c
@@ -239,16 +239,16 @@ void ami_clearclipreg(struct gui_globals *gg)
gg->rect.MaxY = scrn->Height-1;
}
-static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colour)
+static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colr)
{
struct ami_plot_pen *node;
ULONG pen = ObtainBestPenA(scrn->ViewPort.ColorMap,
- (colour & 0x000000ff) << 24,
- (colour & 0x0000ff00) << 16,
- (colour & 0x00ff0000) << 8,
+ (colr & 0x000000ff) << 24,
+ (colr & 0x0000ff00) << 16,
+ (colr & 0x00ff0000) << 8,
NULL);
- if(pen == -1) LOG(("WARNING: Cannot allocate pen for ABGR:%lx", colour));
+ if(pen == -1) LOG(("WARNING: Cannot allocate pen for ABGR:%lx", colr));
if(shared_pens != NULL) {
if(node = (struct ami_plot_pen *)AllocVecTagList(sizeof(struct ami_plot_pen), NULL)) {
@@ -278,26 +278,26 @@ void ami_plot_release_pens(struct MinList *shared_pens)
}while(node = nnode);
}
-static void ami_plot_setapen(ULONG colour)
+static void ami_plot_setapen(ULONG colr)
{
if(palette_mapped == false) {
SetRPAttrs(glob->rp, RPTAG_APenColor,
- ns_color_to_nscss(colour),
+ ns_color_to_nscss(colr),
TAG_DONE);
} else {
- ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colour);
+ ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colr);
if(pen != -1) SetAPen(glob->rp, pen);
}
}
-static void ami_plot_setopen(ULONG colour)
+static void ami_plot_setopen(ULONG colr)
{
if(palette_mapped == false) {
SetRPAttrs(glob->rp, RPTAG_OPenColor,
- ns_color_to_nscss(colour),
+ ns_color_to_nscss(colr),
TAG_DONE);
} else {
- ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colour);
+ ULONG pen = ami_plot_obtain_pen(glob->shared_pens, colr);
if(pen != -1) SetOPen(glob->rp, pen);
}
}
@@ -473,8 +473,6 @@ bool ami_polygon(const int *p, unsigned int n, const plot_style_t *style)
LOG(("[ami_plotter] Entered ami_polygon()"));
#endif
- int k;
-
if((nsoption_int(cairo_renderer) < 1) || (palette_mapped == true))
{
ULONG cx,cy;
@@ -484,7 +482,7 @@ bool ami_polygon(const int *p, unsigned int n, const plot_style_t *style)
if(AreaMove(glob->rp,p[0],p[1]) == -1)
LOG(("AreaMove: vector list full"));
- for(k=1;k<n;k++)
+ for(int k = 1; k < n; k++)
{
if(AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1)
LOG(("AreaDraw: vector list full"));
@@ -501,7 +499,7 @@ bool ami_polygon(const int *p, unsigned int n, const plot_style_t *style)
cairo_set_line_width(glob->cr, 0);
cairo_move_to(glob->cr, p[0], p[1]);
- for (k = 1; k != n; k++) {
+ for (int k = 1; k != n; k++) {
cairo_line_to(glob->cr, p[k * 2], p[k * 2 + 1]);
}
cairo_fill(glob->cr);
@@ -945,7 +943,6 @@ bool ami_path(const float *p, unsigned int n, colour fill, float width,
colour c, const float transform[6])
{
unsigned int i;
- struct bez_point *old_p;
struct bez_point start_p, cur_p, p_a, p_b, p_c, p_r;
#ifdef AMI_PLOTTER_DEBUG
diff --git a/amiga/plugin_hack.c b/amiga/plugin_hack.c
index f78a67e..9bfd7a3 100644
--- a/amiga/plugin_hack.c
+++ b/amiga/plugin_hack.c
@@ -132,7 +132,7 @@ void amiga_plugin_hack_destroy(struct content *c)
{
amiga_plugin_hack_content *plugin = (amiga_plugin_hack_content *) c;
- LOG(("amiga_plugin_hack_destroy"));
+ LOG(("amiga_plugin_hack_destroy %p", plugin));
return;
}
diff --git a/amiga/plugin_hack.h b/amiga/plugin_hack.h
index ae79a1f..3d644ae 100644
--- a/amiga/plugin_hack.h
+++ b/amiga/plugin_hack.h
@@ -22,8 +22,6 @@
#include "utils/config.h"
#include "utils/errors.h"
-struct hlcache_handle;
-
nserror amiga_plugin_hack_init(void);
void amiga_plugin_hack_execute(struct hlcache_handle *c);
diff --git a/amiga/print.c b/amiga/print.c
index 93dde35..66e5a55 100644
--- a/amiga/print.c
+++ b/amiga/print.c
@@ -375,7 +375,7 @@ BOOL ami_print_event(struct ami_print_window *pw)
void ami_print(struct hlcache_handle *c, int copies)
{
- double height, print_height;
+ double height;
float scale = nsoption_int(print_scale) / 100.0;
if(ami_print_info.msgport == NULL)
diff --git a/amiga/search.c b/amiga/search.c
index 17a2d45..5375414 100755
--- a/amiga/search.c
+++ b/amiga/search.c
@@ -69,14 +69,15 @@ static void ami_search_add_recent(const char *string, void *p);
static void ami_search_set_forward_state(bool active, void *p);
static void ami_search_set_back_state(bool active, void *p);
-static struct gui_search_callbacks ami_search_callbacks = {
- ami_search_set_forward_state,
- ami_search_set_back_state,
+static struct gui_search_table search_table = {
ami_search_set_status,
ami_search_set_hourglass,
- ami_search_add_recent
+ ami_search_add_recent,
+ ami_search_set_forward_state,
+ ami_search_set_back_state,
};
+struct gui_search_table *amiga_search_table = &search_table;
/**
* Change the displayed search status.
@@ -90,8 +91,6 @@ void ami_search_open(struct gui_window *gwin)
if(fwin)
{
browser_window_search_clear(fwin->gwin->shared->bw);
- ami_search_set_forward_state(true, NULL);
- ami_search_set_back_state(true, NULL);
fwin->gwin->shared->searchwin = NULL;
fwin->gwin = gwin;
gwin->shared->searchwin = fwin;
@@ -177,8 +176,6 @@ void ami_search_open(struct gui_window *gwin)
void ami_search_close(void)
{
browser_window_search_clear(fwin->gwin->shared->bw);
- ami_search_set_forward_state(true, NULL);
- ami_search_set_back_state(true, NULL);
fwin->gwin->shared->searchwin = NULL;
DisposeObject(fwin->objects[OID_MAIN]);
DelObject(fwin->node);
@@ -201,12 +198,7 @@ BOOL ami_search_event(void)
switch(result & WMHI_GADGETMASK)
{
case GID_SEARCHSTRING:
- browser_window_search_clear(
- fwin->gwin->shared->bw);
- ami_search_set_forward_state(
- true, NULL);
- ami_search_set_back_state(
- true, NULL);
+ browser_window_search_clear(fwin->gwin->shared->bw);
RefreshSetGadgetAttrs((struct Gadget *)fwin->objects[GID_PREV],
fwin->win, NULL,
@@ -226,7 +218,7 @@ BOOL ami_search_event(void)
ami_search_flags();
browser_window_search(
fwin->gwin->shared->bw,
- &ami_search_callbacks, NULL,
+ NULL,
flags, ami_search_string());
ActivateWindow(fwin->gwin->shared->win);
break;
@@ -237,7 +229,7 @@ BOOL ami_search_event(void)
ami_search_flags();
browser_window_search(
fwin->gwin->shared->bw,
- &ami_search_callbacks, NULL,
+ NULL,
flags, ami_search_string());
ActivateWindow(fwin->gwin->shared->win);
break;
diff --git a/amiga/search.h b/amiga/search.h
index fde7302..ce5ae7c 100755
--- a/amiga/search.h
+++ b/amiga/search.h
@@ -28,6 +28,8 @@ struct find_window {
struct gui_window *gwin;
};
+struct gui_search_table *amiga_search_table;
+
void ami_search_open(struct gui_window *gwin);
BOOL ami_search_event(void);
void ami_search_close(void);
diff --git a/amiga/stringview/stringview.c b/amiga/stringview/stringview.c
index 5aea939..9aa110a 100755
--- a/amiga/stringview/stringview.c
+++ b/amiga/stringview/stringview.c
@@ -859,7 +859,6 @@ Class *MakeStringClass( void )
void FreeStringClass(Class *cl)
{
- struct Library *libbase;
URLHistory_Free();
FreeClass(cl);
}
diff --git a/amiga/theme.c b/amiga/theme.c
index 0da15ac..1e9640f 100644
--- a/amiga/theme.c
+++ b/amiga/theme.c
@@ -156,7 +156,6 @@ void ami_theme_init(void)
void ami_theme_throbber_setup(void)
{
char throbberfile[1024];
- Object *dto;
struct bitmap *bm;
ami_get_theme_filename(throbberfile,"theme_throbber",false);
@@ -289,7 +288,7 @@ void ami_init_mouse_pointers(void)
for(i=0;i<=AMI_LASTPOINTER;i++)
{
- BPTR ptrfile = 0;
+ BPTR ptrfile;
mouseptrbm[i] = NULL;
mouseptrobj[i] = NULL;
char ptrfname[1024];
@@ -470,10 +469,10 @@ void gui_window_stop_throbber(struct gui_window *g)
// g->shared->throbber_frame = 0;
}
-void ami_update_throbber(struct gui_window_2 *g,bool redraw)
+void ami_update_throbber(struct gui_window_2 *g, bool redraw)
{
struct IBox *bbox;
- int frame = g->throbber_frame;
+ int frame;
if(!g) return;
if(!g->objects[GID_THROBBER]) return;
@@ -481,10 +480,12 @@ void ami_update_throbber(struct gui_window_2 *g,bool redraw)
if(g->bw->window->throbbing == false)
{
frame = 0;
- g->throbber_frame=1;
+ g->throbber_frame = 1;
}
else
{
+ frame = g->throbber_frame;
+
if(!redraw)
{
if(g->throbber_update_count < throbber_update_interval)
diff --git a/amiga/version.c b/amiga/version.c
index 8bc1fbc..dbddbb0 100644
--- a/amiga/version.c
+++ b/amiga/version.c
@@ -16,7 +16,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "utils/testament.h"
+#include "testament.h"
/* NB: AmigaOS revision numbers start at 1 (not 0) and are monotonically
* incremental (v1.20 is higher than v1.3 and not the same as v1.2).
diff --git a/atari/Makefile.defaults b/atari/Makefile.defaults
index d4ef023..dcdc1d6 100644
--- a/atari/Makefile.defaults
+++ b/atari/Makefile.defaults
@@ -2,57 +2,56 @@
# Atari-specific options
# ----------------------------------------------------------------------------
- # Force using glibc internal iconv implementation instead of external libiconv
- # Valid options: YES, NO
- NETSURF_USE_LIBICONV_PLUG := NO
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := NO
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
- # Enable NetSurf's use of libwebp for displaying WebPs
- # Valid options: YES, NO
- NETSURF_USE_WEBP := NO
+# Enable NetSurf's use of libwebp for displaying WebPs
+# Valid options: YES, NO
+NETSURF_USE_WEBP := NO
- # Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_RSVG := AUTO
+# Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_RSVG := AUTO
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_NSSVG := AUTO
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := AUTO
- # Enable Spidermonkey JavaScript engine
- # Valid options: YES, NO
- NETSURF_USE_MOZJS := NO
+# Enable Spidermonkey JavaScript engine
+# Valid options: YES, NO
+NETSURF_USE_MOZJS := NO
- # enable true type fonts via freetype2
- # Valid options: YES, NO
- NETSURF_USE_ATARI_FREETYPE_FONT := YES
+# enable true type fonts via freetype2
+# Valid options: YES, NO
+NETSURF_USE_ATARI_FREETYPE_FONT := YES
- # Enable use of netsurf embedded font
- # Valid options: YES, NO
- NETSURF_USE_ATARI_NETSURF_FONT := YES
+# Enable use of netsurf embedded font
+# Valid options: YES, NO
+NETSURF_USE_ATARI_NETSURF_FONT := YES
- # Enable VDI Font rendering
- # Valid options: YES, NO
- NETSURF_USE_ATARI_VDI_FONT := NO
+# Enable VDI Font rendering
+# Valid options: YES, NO
+NETSURF_USE_ATARI_VDI_FONT := NO
- # Configure support for screen drivers with no true colour mode
- # Valid options: YES, NO
- NETSURF_USE_ATARI_8BPP_SUPPORT := NO
+# Configure support for screen drivers with no true colour mode
+# Valid options: YES, NO
+NETSURF_USE_ATARI_8BPP_SUPPORT := NO
- # Configure the CPU target
- # Valid options: 68000, 68020-60, 5475 (coldfire)
- ATARIARCH = 68020-60
+# Configure the CPU target
+# Valid options: 68000, 68020-60, 5475 (coldfire)
+ATARIARCH = 68020-60
- # enable optimizations
- # -O2 is currently broken with m68000 / m68020-60 builds
- CFLAGS += -O3
+# enable optimizations
+# -O2 is currently broken with m68000 / m68020-60 builds
+CFLAGS += -O3
- # override warning flags removing -Wall
- WARNFLAGS = -W -Wundef -Wpointer-arith \
+# override warning flags removing -Wall
+WARNFLAGS = -W -Wundef -Wpointer-arith \
-Wcast-align -Wwrite-strings -Wstrict-prototypes \
-Wmissing-prototypes -Wmissing-declarations -Wredundant-decls \
-Wnested-externs -Wuninitialized -Wl,-t
-
diff --git a/atari/gui.c b/atari/gui.c
index d838644..66a665e 100644
--- a/atari/gui.c
+++ b/atari/gui.c
@@ -1112,6 +1112,7 @@ int main(int argc, char** argv)
.download = atari_download_table,
.fetch = &atari_fetch_table,
.utf8 = atari_utf8_table,
+ .search = atari_search_table,
};
/* @todo logging file descriptor update belongs in a nslog_init callback */
@@ -1146,7 +1147,7 @@ int main(int argc, char** argv)
/* common initialisation */
LOG(("Initialising core..."));
- ret = netsurf_init(messages, &atari_gui_table);
+ ret = netsurf_init(messages, NULL, &atari_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/atari/search.c b/atari/search.c
index 6d8f53b..f73a04a 100644
--- a/atari/search.c
+++ b/atari/search.c
@@ -53,13 +53,16 @@ static void nsatari_search_add_recent(const char *string, void *p);
void nsatari_search_set_forward_state(bool active, void *p);
void nsatari_search_set_back_state(bool active, void *p);
-static struct gui_search_callbacks nsatari_search_callbacks = {
- nsatari_search_set_forward_state,
- nsatari_search_set_back_state,
- nsatari_search_set_status,
- nsatari_search_set_hourglass,
- nsatari_search_add_recent
-};
+static struct gui_search_table search_table = {
+ nsatari_search_set_status,
+ nsatari_search_set_hourglass,
+ nsatari_search_add_recent,
+ nsatari_search_set_forward_state,
+ nsatari_search_set_back_state,
+};
+
+struct gui_search_table *atari_search_table = &search_table;
+
/**
@@ -282,7 +285,7 @@ void nsatari_search_perform(struct s_search_form_session *s, OBJECT *obj,
else
s->state.flags &= (~SEARCH_FLAG_FORWARDS);
- browser_window_search(s->bw, &nsatari_search_callbacks, s,
+ browser_window_search(s->bw, s,
s->state.flags,
gemtk_obj_get_text(obj, TOOLBAR_TB_SRCH));
diff --git a/atari/search.h b/atari/search.h
index 00671e4..984fd37 100644
--- a/atari/search.h
+++ b/atari/search.h
@@ -49,6 +49,9 @@ typedef struct s_search_form_session * SEARCH_FORM_SESSION;
struct s_search_form_session * nsatari_search_session_create(OBJECT * obj,
struct browser_window *bw);
+
+struct gui_search_table *atari_search_table;
+
void nsatari_search_session_destroy(struct s_search_form_session *s);
void nsatari_search_perform(struct s_search_form_session *s, OBJECT *obj,
search_flags_t f);
diff --git a/beos/Makefile.defaults b/beos/Makefile.defaults
index d5bf6b3..303414d 100644
--- a/beos/Makefile.defaults
+++ b/beos/Makefile.defaults
@@ -2,31 +2,29 @@
# BeOS-specific options
# ----------------------------------------------------------------------------
+# Where to install the netsurf binary
+NETSURF_BEOS_BIN := /boot/apps/netsurf/
- # Where to install the netsurf binary
- NETSURF_BEOS_BIN := /boot/apps/netsurf/
+# TODO:HAIKU -- not sure if ~/.netsurf applies in beos
+# Where to search for NetSurf's resources after looking in ~/.netsurf and
+# $NETSURFRES. It must have a trailing /
+NETSURF_BEOS_RESOURCES := /boot/apps/netsurf/res/
- # TODO:HAIKU -- not sure if ~/.netsurf applies in beos
- # Where to search for NetSurf's resources after looking in ~/.netsurf and
- # $NETSURFRES. It must have a trailing /
- NETSURF_BEOS_RESOURCES := /boot/apps/netsurf/res/
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := YES
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_NSSVG := YES
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := AUTO
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := AUTO
+# Enable NetSurf's use of libharu for PDF export.
+# Valid options: YES, NO
+NETSURF_USE_HARU_PDF := NO
- # Enable NetSurf's use of libharu for PDF export.
- # Valid options: YES, NO
- NETSURF_USE_HARU_PDF := NO
-
- # Force using glibc internal iconv implementation instead of external libiconv
- # Valid options: YES, NO
- NETSURF_USE_LIBICONV_PLUG := NO
-
- # Optimisation levels
- CFLAGS += -O2
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
+# Optimisation levels
+CFLAGS += -O2
diff --git a/beos/gui.cpp b/beos/gui.cpp
index 365a356..6f08298 100644
--- a/beos/gui.cpp
+++ b/beos/gui.cpp
@@ -1097,7 +1097,7 @@ int main(int argc, char** argv)
/* common initialisation */
BPath messages = get_messages_path();
- ret = netsurf_init(messages.Path(), &beos_gui_table);
+ ret = netsurf_init(messages.Path(), NULL, &beos_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
@@ -1145,7 +1145,7 @@ int gui_init_replicant(int argc, char** argv)
/* common initialisation */
BPath messages = get_messages_path();
- ret = netsurf_init(messages.Path(), &beos_gui_table);
+ ret = netsurf_init(messages.Path(), NULL, &beos_gui_table);
if (ret != NSERROR_OK) {
// FIXME: must not die when in replicant!
die("NetSurf failed to initialise");
diff --git a/beos/schedule.cpp b/beos/schedule.cpp
index 75e3490..62ddb0e 100644
--- a/beos/schedule.cpp
+++ b/beos/schedule.cpp
@@ -23,6 +23,7 @@
#include <List.h>
extern "C" {
+#include "utils/errors.h"
#include "beos/schedule.h"
#include "desktop/browser.h"
diff --git a/beos/schedule.h b/beos/schedule.h
index a446156..18f1efd 100644
--- a/beos/schedule.h
+++ b/beos/schedule.h
@@ -21,9 +21,9 @@
extern bigtime_t earliest_callback_timeout;
-extern nserror beos_schedule(int t, void (*callback)(void *p), void *p);
+extern "C" nserror beos_schedule(int t, void (*callback)(void *p), void *p);
-extern void schedule_run(void);
+extern "C" bool schedule_run(void);
#endif /* NETSURF_BEOS_CALLBACK_H */
diff --git a/cocoa/Makefile.defaults b/cocoa/Makefile.defaults
index 2451749..501d175 100644
--- a/cocoa/Makefile.defaults
+++ b/cocoa/Makefile.defaults
@@ -2,35 +2,35 @@
# Cocoa-specific options
# ----------------------------------------------------------------------------
- # Force using glibc internal iconv implementation instead of external libiconv
- # Valid options: YES, NO
- NETSURF_USE_LIBICONV_PLUG := NO
-
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := NO
-
- # Enable NetSurf's use of libwebp for displaying WebPs
- # Valid options: YES, NO
- NETSURF_USE_WEBP := NO
-
- # Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_RSVG := AUTO
-
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_NSSVG := AUTO
-
- NETSURF_USE_BMP := NO
- NETSURF_USE_GIF := NO
- NETSURF_USE_PNG := NO
- NETSURF_USE_JPEG := NO
- NETSURF_USE_IMAGEIO := YES
-
- DEVELOPER_PATH := /Developer
- MACOSX_VERSION := 10.5
- SDK_VERSION := $(MACOSX_VERSION)
-
- # Optimisation levels
- CFLAGS += -O2
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
+
+# Enable NetSurf's use of libwebp for displaying WebPs
+# Valid options: YES, NO
+NETSURF_USE_WEBP := NO
+
+# Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_RSVG := AUTO
+
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := AUTO
+
+NETSURF_USE_BMP := NO
+NETSURF_USE_GIF := NO
+NETSURF_USE_PNG := NO
+NETSURF_USE_JPEG := NO
+NETSURF_USE_IMAGEIO := YES
+
+DEVELOPER_PATH := /Developer
+MACOSX_VERSION := 10.5
+SDK_VERSION := $(MACOSX_VERSION)
+
+# Optimisation levels
+CFLAGS += -O2
diff --git a/cocoa/Makefile.target b/cocoa/Makefile.target
index 40e8d43..e6292c1 100644
--- a/cocoa/Makefile.target
+++ b/cocoa/Makefile.target
@@ -2,67 +2,66 @@
# Mac OS X target setup
# ----------------------------------------------------------------------------
- POSTEXES += NetSurf.app
+POSTEXES += NetSurf.app
- LDFLAGS += -L/usr/lib
- LDFLAGS += $(shell $(PKG_CONFIG) --libs libhubbub libcss libdom)
- LDFLAGS += -L/usr/X11/lib
- LDFLAGS += -lm -lcurl -liconv
- LDFLAGS += -lssl -lcrypto
+LDFLAGS += -L/usr/lib
+LDFLAGS += $(shell $(PKG_CONFIG) --libs libhubbub libcss libdom)
+LDFLAGS += -L/usr/X11/lib
+LDFLAGS += -lm -lcurl -liconv
+LDFLAGS += -lssl -lcrypto
- CFLAGS += -O $(WARNFLAGS) -Dnscocoa \
- -D_BSD_SOURCE -D_POSIX_C_SOURCE \
+CFLAGS += -O $(WARNFLAGS) -Dnscocoa -D_BSD_SOURCE -D_POSIX_C_SOURCE \
-std=c99 -g -Os
- CFLAGS += $(shell $(PKG_CONFIG) --cflags libhubbub libcss libdom)
+CFLAGS += $(shell $(PKG_CONFIG) --cflags libhubbub libcss libdom)
- # shut up zconf.h and zlib.h
- #CFLAGS += -D_LARGEFILE64_SOURCE=1
+# shut up zconf.h and zlib.h
+#CFLAGS += -D_LARGEFILE64_SOURCE=1
ifneq ($(WITH_MACPORTS),)
LDFLAGS += -L/opt/local/lib
CFLAGS += -I/opt/local/include
endif
- # for timerisset()
- CFLAGS += -D_DARWIN_C_SOURCE
+# for timerisset()
+CFLAGS += -D_DARWIN_C_SOURCE
- MACOSX_VERSION ?= 10.5
- SDK_VERSION ?= $(MACOSX_VERSION)
- SDK_PATH ?= $(DEVELOPER_PATH)/SDKs/MacOSX$(SDK_VERSION).sdk
- SDK_FLAGS := -isysroot $(SDK_PATH) -mmacosx-version-min=$(MACOSX_VERSION)
- CFLAGS := $(SDK_FLAGS) $(CFLAGS)
- LDFLAGS := $(SDK_FLAGS) -Wl,-syslibroot,$(SDK_PATH) $(LDFLAGS)
- CXXFLAGS := $(SDK_FLAGS) $(CXXFLAGS)
+MACOSX_VERSION ?= 10.5
+SDK_VERSION ?= $(MACOSX_VERSION)
+SDK_PATH ?= $(DEVELOPER_PATH)/SDKs/MacOSX$(SDK_VERSION).sdk
+SDK_FLAGS := -isysroot $(SDK_PATH) -mmacosx-version-min=$(MACOSX_VERSION)
+CFLAGS := $(SDK_FLAGS) $(CFLAGS)
+LDFLAGS := $(SDK_FLAGS) -Wl,-syslibroot,$(SDK_PATH) $(LDFLAGS)
+CXXFLAGS := $(SDK_FLAGS) $(CXXFLAGS)
- CFLAGS += -I/usr/X11/include
- CFLAGS += -include cocoa/Prefix.pch
+CFLAGS += -I/usr/X11/include
+CFLAGS += -include cocoa/Prefix.pch
# VERSION_FULL := $(shell sed -n '/\"/{s/.*"\(.*\)\".*/\1/;p;}' desktop/version.c)
# TODO: this needs fixing properly everywhere
- VERSION_FULL := "3.0 (Dev)"
- VERSION_MAJ := $(shell sed -n '/_major/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
- VERSION_MIN := $(shell sed -n '/_minor/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
+VERSION_FULL := "3.0 (Dev)"
+VERSION_MAJ := $(shell sed -n '/_major/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
+VERSION_MIN := $(shell sed -n '/_minor/{s/.* = \([0-9]*\).*/\1/;p;}' desktop/version.c)
- LDFLAGS += -Wl,-framework,Cocoa -Wl,-framework,Carbon $(NETLDFLAGS)
+LDFLAGS += -Wl,-framework,Cocoa -Wl,-framework,Carbon $(NETLDFLAGS)
- NETSURF_FEATURE_BMP_CFLAGS := -DWITH_BMP
- NETSURF_FEATURE_GIF_CFLAGS := -DWITH_GIF
- NETSURF_FEATURE_PNG_CFLAGS := -DWITH_PNG
- NETSURF_FEATURE_NSSVG_CFLAGS := -DWITH_NS_SVG
+NETSURF_FEATURE_BMP_CFLAGS := -DWITH_BMP
+NETSURF_FEATURE_GIF_CFLAGS := -DWITH_GIF
+NETSURF_FEATURE_PNG_CFLAGS := -DWITH_PNG
+NETSURF_FEATURE_NSSVG_CFLAGS := -DWITH_NS_SVG
- $(eval $(call pkg_config_find_and_add_enabled,BMP,libnsbmp,BMP))
- $(eval $(call pkg_config_find_and_add_enabled,GIF,libnsgif,GIF))
- $(eval $(call pkg_config_find_and_add_enabled,PNG,libpng,PNG))
- $(eval $(call pkg_config_find_and_add_enabled,NSSVG,libsvgtiny,SVG))
- $(eval $(call feature_enabled,IMAGEIO,-DWITH_APPLE_IMAGE,,Apple ImageIO ))
+$(eval $(call pkg_config_find_and_add_enabled,BMP,libnsbmp,BMP))
+$(eval $(call pkg_config_find_and_add_enabled,GIF,libnsgif,GIF))
+$(eval $(call pkg_config_find_and_add_enabled,PNG,libpng,PNG))
+$(eval $(call pkg_config_find_and_add_enabled,NSSVG,libsvgtiny,SVG))
+$(eval $(call feature_enabled,IMAGEIO,-DWITH_APPLE_IMAGE,,Apple ImageIO ))
- ifneq ($(UNIVERSAL),)
+ifneq ($(UNIVERSAL),)
UNIVERSAL_FLAGS := $(foreach arch,$(UNIVERSAL),-arch $(arch) )
CFLAGS += $(UNIVERSAL_FLAGS)
LDFLAGS += $(UNIVERSAL_FLAGS)
CXXFLAGS += $(UNIVERSAL_FLAGS)
- endif
+endif
# ----------------------------------------------------------------------------
# Source file setup
@@ -240,4 +239,3 @@ clean-package-cocoa:
$(Q)$(RM) NetSurf.dmg
$(VQ)echo " CLEAN: NetSurf.app"
$(Q)$(RM) -r NetSurf.app
-
diff --git a/cocoa/NetsurfApp.m b/cocoa/NetsurfApp.m
index a1f1564..e31fc2a 100644
--- a/cocoa/NetsurfApp.m
+++ b/cocoa/NetsurfApp.m
@@ -21,6 +21,7 @@
#import "cocoa/gui.h"
#import "cocoa/plotter.h"
#import "cocoa/DownloadWindowController.h"
+#import "cocoa/SearchWindowController.h"
#import "cocoa/selection.h"
#import "cocoa/fetch.h"
@@ -190,6 +191,7 @@ int main( int argc, char **argv )
.clipboard = cocoa_clipboard_table,
.download = cocoa_download_table,
.fetch = cocoa_fetch_table,
+ .search = cocoa_search_table,
};
cocoa_autorelease();
@@ -211,7 +213,7 @@ int main( int argc, char **argv )
nsoption_commandline(&argc, argv, NULL);
/* common initialisation */
- error = netsurf_init(messages, &cocoa_gui_table);
+ error = netsurf_init(messages, NULL, &cocoa_gui_table);
if (error != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/cocoa/SearchWindowController.h b/cocoa/SearchWindowController.h
index a1aac2e..896983b 100644
--- a/cocoa/SearchWindowController.h
+++ b/cocoa/SearchWindowController.h
@@ -49,4 +49,6 @@ typedef enum {
- (void) search: (SearchDirection)direction;
+struct gui_search_table *cocoa_search_table;
+
@end
diff --git a/cocoa/SearchWindowController.m b/cocoa/SearchWindowController.m
index 06147fa..e4dfb73 100644
--- a/cocoa/SearchWindowController.m
+++ b/cocoa/SearchWindowController.m
@@ -20,20 +20,20 @@
#import "cocoa/SearchWindowController.h"
#import "cocoa/BrowserViewController.h"
+#import "desktop/gui.h"
#import "desktop/browser.h"
#import "desktop/search.h"
static void cocoa_search_set_back( bool active, void *p );
static void cocoa_search_set_forward( bool active, void *p );
-static struct gui_search_callbacks cocoa_search_callbacks = {
+static struct gui_search_table search_table = {
.forward_state = cocoa_search_set_forward,
.back_state = cocoa_search_set_back,
- .status = NULL,
- .hourglass = NULL,
- .add_recent = NULL
};
+struct gui_search_table *cocoa_search_table = &search_table;
+
@implementation SearchWindowController
@synthesize caseSensitive;
@@ -76,7 +76,7 @@ static struct gui_search_callbacks cocoa_search_callbacks = {
if (selectAll) flags |= SEARCH_FLAG_SHOWALL;
struct browser_window *bw = [browser browser];
- browser_window_search( bw, &cocoa_search_callbacks, self, flags, [searchString UTF8String] );
+ browser_window_search( bw, self, flags, [searchString UTF8String] );
}
- (IBAction) searchStringDidChange: (id) sender;
diff --git a/content/Makefile b/content/Makefile
index 38b0b49..ab257ea 100644
--- a/content/Makefile
+++ b/content/Makefile
@@ -1,6 +1,11 @@
# Content sources
S_CONTENT := content.c content_factory.c dirlist.c fetch.c hlcache.c \
- llcache.c mimesniff.c urldb.c backing_store.c
+ llcache.c mimesniff.c urldb.c no_backing_store.c
-S_CONTENT := $(addprefix content/,$(S_CONTENT))
\ No newline at end of file
+# Make filesystem backing store available
+ifeq ($(NETSURF_FS_BACKING_STORE),YES)
+ S_CONTENT += fs_backing_store.c
+endif
+
+S_CONTENT := $(addprefix content/,$(S_CONTENT))
diff --git a/content/backing_store.c b/content/backing_store.c
deleted file mode 100644
index 65e74fe..0000000
--- a/content/backing_store.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Low-level resource cache persistant storage implementation.
- */
-
-#include <unistd.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "utils/nsurl.h"
-#include "utils/log.h"
-#include "utils/utils.h"
-#include "utils/sha1.h"
-#include "desktop/gui.h"
-
-#include "content/backing_store.h"
-
-#ifdef BACKING_STORE_FILE
-
-/* file based backing store */
-
-struct llcache_store_state {
- /** parameters controlling the backing store */
- struct llcache_store_parameters params;
-
- /** key to filename conversion */
- char *(*store_fname)(nsurl *url, enum llcache_store_flags flags);
-};
-
-struct llcache_store_state *storestate;
-
-
-static uint8_t encoding_table[] = {
- 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
- 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
- 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
- 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
- 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
- 'w', 'x', 'y', 'z', '0', '1', '2', '3',
- '4', '5', '6', '7', '8', '9', '-', '_'
-};
-static unsigned int mod_table[] = {0, 2, 1};
-
-
-static uint8_t *
-base64url_encode(const char *data,
- size_t input_length,
- size_t *output_length)
-{
- uint8_t *encoded_data;
- size_t i;
- size_t j;
-
- *output_length = 4 * ((input_length + 2) / 3);
-
- encoded_data = malloc(*output_length + 1);
- if (encoded_data == NULL) {
- return NULL;
- }
-
- for (i = 0, j = 0; i < input_length;) {
-
- uint32_t octet_a = i < input_length ? data[i++] : 0;
- uint32_t octet_b = i < input_length ? data[i++] : 0;
- uint32_t octet_c = i < input_length ? data[i++] : 0;
-
- uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
-
- encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
- encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
- encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
- encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
- }
-
- for (i = 0; i < mod_table[input_length % 3]; i++) {
- encoded_data[*output_length - 1 - i] = 0;
- (*output_length)--;
- }
-
- return encoded_data;
-}
-
-/**
- * create filename from url and flags
- *
- * This uses 160bit sha1 and a bit from the from flags which is then
- * base64 encoded. This yeilds a 28 character base64 encoded string
- * (168 bits is minimum byte representation of 161 bits) where the
- * last character can be discarded (27*6 is 162 bits)
- */
-static char *
-b64_store_fname_sha1(nsurl *url, enum llcache_store_flags flags)
-{
- uint8_t hash[NSSHA1_DIGEST_SIZE + 1];
- int fname_len;
- char *fname;
- uint8_t *b64u;
- size_t b64ulen;
-
- NSSHA1((uint8_t *)nsurl_access(url), nsurl_length(url), hash);
-
- if ((flags & LLCACHE_STORE_META) != 0) {
- hash[NSSHA1_DIGEST_SIZE] = 0xff;
- } else {
- hash[NSSHA1_DIGEST_SIZE] = 0;
- }
-
- b64u = base64url_encode((char *)hash, NSSHA1_DIGEST_SIZE + 1, &b64ulen);
- if (b64u == NULL) {
- return NULL;
- }
- b64u[27] = 0;
- LOG(("b64u len:%d from %d with \"%s\"", b64ulen, NSSHA1_DIGEST_SIZE + 1, b64u));
- fname_len = strlen(storestate->params.path) + 31;
- fname = calloc(1, fname_len);
- if (fname == NULL) {
- free(b64u);
- return NULL;
- }
-
- snprintf(fname,
- fname_len,
- "%s/%c%c/%s",
- storestate->params.path,
- b64u[0], b64u[1], b64u + 2 );
- free(b64u);
-
- return fname;
-}
-
-/**
- * Create filename from url and flags
- *
- * This uses 17bits from the fnv url hash and one bit from the
- * flags. Yeilding data in 3 bytes which is base64 encoded, the fourth
- * character (last 6 bits) of the base 64 encoding is not used as it is
- * empty.
- */
-static char *
-b64_store_fname_fnv(nsurl *url, enum llcache_store_flags flags)
-{
- uint32_t hash;
- char *hashp;
- int fname_len;
- char *fname;
- uint8_t *b64u;
- size_t b64ulen;
-
- hash = nsurl_hash(url);
-
- hashp = (char *)&hash;
-
- hashp[2] = hashp[2] & 0x80;
-
- if ((flags & LLCACHE_STORE_META) != 0) {
- hashp[2] = hashp[2] | 0x40;
- }
-
- b64u = base64url_encode(hashp, 3, &b64ulen);
- if (b64u == NULL) {
- return NULL;
- }
-
- fname_len = strlen(storestate->params.path) + 7;
- fname = calloc(1, fname_len);
- if (fname == NULL) {
- free(b64u);
- return NULL;
- }
-
- snprintf(fname,
- fname_len,
- "%s/%c/%c/%c",
- storestate->params.path,
- b64u[0], b64u[1], b64u[2]);
- free(b64u);
-
- return fname;
-}
-
-/**
- * create filename from url and flags
- *
- * no hashing, just base64 encode the url
- */
-static char *
-b64_store_fname(nsurl *url, enum llcache_store_flags flags)
-{
- char *fname;
- uint8_t *b64u;
- size_t b64ulen;
- char sep;
-
- b64u = base64url_encode(nsurl_access(url),
- strlen(nsurl_access(url)),
- &b64ulen);
- if (b64u == NULL) {
- return NULL;
- }
-
- fname = malloc(strlen(storestate->params.path) +
- SLEN("/x") + b64ulen + 1);
- if (fname == NULL) {
- free(b64u);
- return NULL;
- }
-
- if ((flags & LLCACHE_STORE_META) == 0) {
- sep ='d';
- } else {
- sep ='i';
- }
-
- snprintf(fname,
- (strlen(storestate->params.path) + SLEN("/x") + b64ulen + 1),
- "%s/%s%c",
- storestate->params.path,
- b64u,
- sep);
- free(b64u);
-
- return fname;
-}
-
-/* backing store implementation */
-
-/**
- * Initialise the backing store.
- *
- * @param parameters to configure backing store.
- * @return NSERROR_OK on success or error code on faliure.
- */
-static nserror
-initialise(const struct llcache_store_parameters *parameters)
-{
- /* check backing store is not already initialised */
- if (storestate != NULL) {
- return NSERROR_INIT_FAILED;
- }
-
- storestate = calloc(1, sizeof(struct llcache_store_state));
- if (storestate == NULL) {
- return NSERROR_NOMEM;
- }
-
- memcpy(&storestate->params,
- parameters,
- sizeof(struct llcache_store_parameters));
-
- if (storestate->params.hashsize == 0) {
- storestate->store_fname = b64_store_fname;
- } else if (storestate->params.hashsize < 32) {
- storestate->store_fname = b64_store_fname_fnv;
- } else {
- storestate->store_fname = b64_store_fname_sha1;
- }
-
- return NSERROR_OK;
-}
-
-/**
- * Finalise the backing store.
- *
- * @return NSERROR_OK on success.
- */
-static nserror
-finalise(void)
-{
- if (storestate != NULL) {
- free(storestate);
- storestate = NULL;
- }
- return NSERROR_OK;
-}
-
-/* ensure that all directory elements needed to store a filename exist */
-static nserror mkfilepath(const char *fname)
-{
- char *dname;
- char *sep;
- struct stat sb;
-
- dname = strdup(fname);
-
- sep = strrchr(dname, '/');
- if (sep == NULL) {
- /* no directory separator path is just filename so its ok */
- free(dname);
- return NSERROR_OK;
- }
-
- *sep = 0; /* null terminate directory path */
-
- if (stat(dname, &sb) == 0) {
- free(dname);
- if (S_ISDIR(sb.st_mode)) {
- /* path to file exists and is a directory */
- return NSERROR_OK;
- }
- return NSERROR_NOT_FOUND;
- }
- *sep = '/'; /* restore separator */
-
- sep = dname;
- while (*sep == '/') {
- sep++;
- }
- while ((sep = strchr(sep, '/')) != NULL) {
- *sep = 0;
- if (stat(dname, &sb) != 0) {
- if (mkdir(dname, 0700) != 0) {
- /* could not create path element */
- free(dname);
- return NSERROR_NOT_FOUND;
- }
- } else {
- if (! S_ISDIR(sb.st_mode)) {
- /* path element not a directory */
- free(dname);
- return NSERROR_NOT_FOUND;
- }
- }
- *sep = '/'; /* restore separator */
- /* skip directory separators */
- while (*sep == '/') {
- sep++;
- }
- }
-
- free(dname);
- return NSERROR_OK;
-}
-
-/**
- * Place a source object and its metadata in the backing store.
- *
- * @param url The url is used as the unique primary key for the data.
- * @param flags The flags to control how the object is stored.
- * @param data The objects source data.
- * @param datalen The length of the \a data.
- * @return NSERROR_OK on success or error code on faliure.
- */
-static nserror
-store(nsurl *url,
- enum llcache_store_flags flags,
- const uint8_t *data,
- const size_t datalen)
-{
- char *fname;
- FILE *file;
- nserror ret;
-
- LOG(("Writing object for url:%s", nsurl_access(url)));
- fname = storestate->store_fname(url, flags);
- if (fname == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* ensure path to file is usable */
- ret = mkfilepath(fname);
- if (ret != NSERROR_OK) {
- LOG(("file path \"%s\" could not be created", fname));
- free(fname);
- return ret;
- }
-
- LOG(("Opening data file %s", fname));
- file = fopen(fname, "wb");
- free(fname);
- if (file == NULL) {
- return NSERROR_SAVE_FAILED;
- }
-
- LOG(("Writing %d bytes from %p", datalen, data));
- if (fwrite(data, datalen, 1, file) != 1) {
- LOG(("did not return 1"));
- fclose(file);
- return NSERROR_SAVE_FAILED;
- }
-
- fclose(file);
-
- return NSERROR_OK;
-}
-
-/**
- * Retrive an object from the backing store.
- *
- * @param url The url is used as the unique primary key for the data.
- * @param flags The flags to control how the object is stored.
- * @param data The objects data.
- * @param datalen The length of the \a data retrieved.
- * @return NSERROR_OK on success or error code on faliure.
- */
-static nserror
-fetch(nsurl *url,
- enum llcache_store_flags *flags,
- uint8_t **data_out,
- size_t *datalen_out)
-{
- char *fname;
- FILE *file;
- uint8_t *data;
- size_t datalen;
-
- data = *data_out;
- datalen = *datalen_out;
-
- LOG(("retriving cache file for url:%s", nsurl_access(url)));
-
- fname = storestate->store_fname(url, *flags);
- if (fname == NULL) {
- return NSERROR_NOMEM;
- }
-
- LOG(("Opening file %s",fname));
-
- file = fopen(fname, "rb");
- free(fname);
- if (file == NULL) {
- return NSERROR_NOT_FOUND;
- }
-
- /* need to deal with buffers */
- if (data == NULL) {
- if (datalen == 0) {
- /* caller did not know the files length */
- fseek(file, 0L, SEEK_END);
- datalen = ftell(file);
- fseek(file, 0L, SEEK_SET);
- }
-
- data = malloc(datalen);
- if (data == NULL) {
- fclose(file);
- return NSERROR_NOMEM;
- }
- }
-
- LOG(("Reading %d bytes into %p from file", datalen, data));
- if (fread(data, datalen, 1, file) != 1) {
- LOG(("did not return 1"));
- fclose(file);
- if ((*data_out) == NULL) {
- free(data);
- }
- return NSERROR_NOT_FOUND;
- }
-
- fclose(file);
-
- *data_out = data;
- *datalen_out = datalen;
-
- return NSERROR_OK;
-}
-
-
-/**
- * Invalidate a source object from the backing store.
- *
- * The entry (if present in the backing store) must no longer
- * be returned as a result to the fetch or meta operations.
- *
- * @param url The url is used as the unique primary key to invalidate.
- * @return NSERROR_OK on success or error code on faliure.
- */
-static nserror
-invalidate(nsurl *url)
-{
- char *fname;
- fname = storestate->store_fname(url, LLCACHE_STORE_META);
- if (fname == NULL) {
- return NSERROR_NOMEM;
- }
- unlink(fname);
- free(fname);
-
- fname = storestate->store_fname(url, LLCACHE_STORE_NONE);
- if (fname == NULL) {
- return NSERROR_NOMEM;
- }
- unlink(fname);
- free(fname);
-
- return NSERROR_OK;
-}
-
-#else
-
-/* default to disabled backing store */
-static nserror initialise(const struct llcache_store_parameters *parameters)
-{
- return NSERROR_OK;
-}
-
-static nserror finalise(void)
-{
- return NSERROR_OK;
-}
-
-static nserror store(nsurl *url,
- enum llcache_store_flags flags,
- const uint8_t *data,
- const size_t datalen)
-{
- return NSERROR_SAVE_FAILED;
-}
-
-static nserror fetch(nsurl *url,
- enum llcache_store_flags *flags,
- uint8_t **data_out,
- size_t *datalen_out)
-{
- return NSERROR_NOT_FOUND;
-}
-
-static nserror invalidate(nsurl *url)
-{
- return NSERROR_NOT_FOUND;
-}
-
-
-#endif
-
-
-static struct gui_llcache_table llcache_table = {
- .initialise = initialise,
- .finalise = finalise,
- .store = store,
- .fetch = fetch,
- .invalidate = invalidate,
-};
-
-struct gui_llcache_table *default_llcache_table = &llcache_table;
diff --git a/content/backing_store.h b/content/backing_store.h
index 33f711e..849e11a 100644
--- a/content/backing_store.h
+++ b/content/backing_store.h
@@ -26,10 +26,10 @@
#include "content/llcache.h"
/** storage control flags */
-enum llcache_store_flags {
- LLCACHE_STORE_NONE = 0, /**< no special processing */
- LLCACHE_STORE_META = 1, /**< data is metadata */
- LLCACHE_STORE_MMAP = 2, /**< when data is retrived this indicates the
+enum backing_store_flags {
+ BACKING_STORE_NONE = 0, /**< no special processing */
+ BACKING_STORE_META = 1, /**< data is metadata */
+ BACKING_STORE_MMAP = 2, /**< when data is retrived this indicates the
* returned buffer may be memory mapped,
* flag must be cleared if the storage is
* allocated and is not memory mapped.
@@ -67,7 +67,7 @@ struct gui_llcache_table {
* @param datalen The length of the \a data.
* @return NSERROR_OK on success or error code on faliure.
*/
- nserror (*store)(struct nsurl *url, enum llcache_store_flags flags,
+ nserror (*store)(struct nsurl *url, enum backing_store_flags flags,
const uint8_t *data, const size_t datalen);
/**
@@ -79,7 +79,7 @@ struct gui_llcache_table {
* @param datalen The length of the \a data retrieved.
* @return NSERROR_OK on success or error code on faliure.
*/
- nserror (*fetch)(struct nsurl *url, enum llcache_store_flags *flags,
+ nserror (*fetch)(struct nsurl *url, enum backing_store_flags *flags,
uint8_t **data, size_t *datalen);
/**
@@ -94,6 +94,7 @@ struct gui_llcache_table {
nserror (*invalidate)(struct nsurl *url);
};
-extern struct gui_llcache_table* default_llcache_table;
+extern struct gui_llcache_table* null_llcache_table;
+extern struct gui_llcache_table* filesystem_llcache_table;
#endif
diff --git a/content/content.c b/content/content.c
index 93b6b8f..87dcfa2 100644
--- a/content/content.c
+++ b/content/content.c
@@ -838,15 +838,15 @@ bool content_drop_file_at_point(struct hlcache_handle *h,
}
-void content_search(struct hlcache_handle *h,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+void content_search(struct hlcache_handle *h, void *context,
search_flags_t flags, const char *string)
{
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
- if (c->handler->search != NULL)
- c->handler->search(c, gui_callbacks, gui_data, flags, string);
+ if (c->handler->search != NULL) {
+ c->handler->search(c, context, flags, string);
+ }
}
@@ -855,8 +855,9 @@ void content_search_clear(struct hlcache_handle *h)
struct content *c = hlcache_handle_get_content(h);
assert(c != 0);
- if (c->handler->search_clear != NULL)
+ if (c->handler->search_clear != NULL) {
c->handler->search_clear(c);
+ }
}
diff --git a/content/content.h b/content/content.h
index 91a6ae9..a2d0792 100644
--- a/content/content.h
+++ b/content/content.h
@@ -266,10 +266,11 @@ bool content_scroll_at_point(struct hlcache_handle *h,
int x, int y, int scrx, int scry);
bool content_drop_file_at_point(struct hlcache_handle *h,
int x, int y, char *file);
-void content_search(struct hlcache_handle *h,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+
+void content_search(struct hlcache_handle *h, void *context,
search_flags_t flags, const char *string);
void content_search_clear(struct hlcache_handle *h);
+
void content_debug_dump(struct hlcache_handle *h, FILE *f);
struct content_rfc5988_link *content_find_rfc5988_link(struct hlcache_handle *c,
lwc_string *rel);
diff --git a/content/content_protected.h b/content/content_protected.h
index 57ce357..f5448c8 100644
--- a/content/content_protected.h
+++ b/content/content_protected.h
@@ -73,10 +73,8 @@ struct content_handler {
int scrx, int scry);
bool (*drop_file_at_point)(struct content *c, int x, int y,
char *file);
- void (*search)(struct content *c,
- struct gui_search_callbacks *gui_callbacks,
- void *gui_data, search_flags_t flags,
- const char *string);
+ void (*search)(struct content *c, void *context, search_flags_t flags,
+ const char *string);
void (*search_clear)(struct content *c);
void (*debug_dump)(struct content *c, FILE *f);
nserror (*clone)(const struct content *old, struct content **newc);
diff --git a/content/fetchers/Makefile b/content/fetchers/Makefile
index 06e38e4..8551542 100644
--- a/content/fetchers/Makefile
+++ b/content/fetchers/Makefile
@@ -5,4 +5,4 @@ S_FETCHERS := curl.c data.c file.c about.c resource.c
S_FETCHERS := $(addprefix content/fetchers/,$(S_FETCHERS))
# The following files depend on the testament
-content/fetchers/about.c: testament utils/testament.h
+content/fetchers/about.c: testament $(OBJROOT)/testament.h
diff --git a/content/fetchers/about.c b/content/fetchers/about.c
index 8e973a9..f0244a9 100644
--- a/content/fetchers/about.c
+++ b/content/fetchers/about.c
@@ -41,6 +41,8 @@
#include <libwapcaplet/libwapcaplet.h>
+#include "testament.h"
+
#include "utils/config.h"
#include "content/dirlist.h"
#include "content/fetch.h"
@@ -54,7 +56,6 @@
#include "utils/url.h"
#include "utils/utils.h"
#include "utils/ring.h"
-#include "utils/testament.h"
#include "image/image_cache.h"
struct fetch_about_context;
diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c
new file mode 100644
index 0000000..7a715f9
--- /dev/null
+++ b/content/fs_backing_store.c
@@ -0,0 +1,1194 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache persistent storage implementation.
+ *
+ * file based backing store.
+ *
+ * \todo Consider improving eviction sorting to include objects size
+ * and remaining lifetime and other cost metrics.
+ *
+ * \todo make backing store have a more efficient small object storage.
+ *
+ */
+
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "utils/filepath.h"
+#include "utils/nsurl.h"
+#include "utils/log.h"
+#include "utils/utils.h"
+#include "desktop/gui.h"
+
+#include "content/backing_store.h"
+
+#define ADDRESS_BITS 18 /** default number of bits of the ident to use in index hash */
+#define ENTRY_BITS 14 /** default number of bits to use for an entry index. */
+
+#define CONTROL_VERSION 100 /** backing store file format version */
+
+/** get address from ident */
+#define BS_ADDRESS(ident, state) ((ident) & ((1 << state->addr_bits) - 1))
+
+/** lookup store entry index from ident */
+#define BS_ENTRY_INDEX(ident, state) state->addrmap[(ident) & ((1 << state->addr_bits) - 1)]
+
+/** get store entry from ident. */
+#define BS_ENTRY(ident, state) state->entries[state->addrmap[(ident) & ((1 << state->addr_bits) - 1)]]
+
+enum store_entry_flags {
+ STORE_ENTRY_FLAG_NONE = 0,
+};
+
+/**
+ * The type used to store index values refering to store entries. Care
+ * must be taken with this type as it is used to build address to
+ * entry mapping so changing the size will have large impacts on
+ * memory usage.
+ */
+typedef uint16_t entry_index_t;
+
+/**
+ * The type used as a binary identifier for each entry derived from
+ * the url. A larger identifier will have fewer collisions but
+ * requires proportionately more storage.
+ */
+typedef uint32_t entry_ident_t;
+
+/**
+ * Backing store object index entry.
+ *
+ * @note Order is important to avoid structure packing overhead.
+ */
+struct store_entry {
+ int64_t last_used; /**< unix time the entry was last used */
+ entry_ident_t ident; /**< entry identifier */
+ uint32_t data_alloc; /**< currently allocated size of data on disc */
+ uint32_t meta_alloc; /**< currently allocated size of metadata on disc */
+ uint16_t use_count; /**< number of times this entry has been accessed */
+ uint16_t flags; /**< entry flags (unused) */
+ uint16_t data_block; /**< small object data block entry (unused) */
+ uint16_t meta_block; /**< small object meta block entry (unused) */
+};
+
+/**
+ * Parameters controlling the backing store.
+ */
+struct store_state {
+ char *path; /**< The path to the backing store */
+ size_t limit; /**< The backing store upper bound target size */
+ size_t hysteresis; /**< The hysteresis around the target size */
+
+ unsigned int addr_bits; /**< log2 number of bits to use for address. */
+
+ struct store_entry *entries; /**< store entries. */
+ unsigned int entry_bits; /**< log2 number of bits in entry index. */
+ unsigned int last_entry; /**< index of last usable entry. */
+ bool entries_dirty; /**< flag indicating if the entries have been made persistant since they were last changed. */
+
+ entry_index_t *addrmap; /**< address to entry index mapping. */
+
+ uint64_t total_alloc; /**< total size of all allocated storage. */
+};
+
+/**
+ * Global storage state.
+ *
+ * @todo Investigate if there is a way to have a context rather than
+ * use a global.
+ */
+struct store_state *storestate;
+
+/** Base64url encoding table */
+static uint8_t encoding_table[] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3',
+ '4', '5', '6', '7', '8', '9', '-', '_'
+};
+
+#ifdef FULL_BASE64_ENCODE
+static unsigned int mod_table[] = {0, 2, 1};
+
+static uint8_t *
+base64url_encode(const char *data,
+ size_t input_length,
+ size_t *output_length)
+{
+ uint8_t *encoded_data;
+ size_t i;
+ size_t j;
+
+ *output_length = 4 * ((input_length + 2) / 3);
+
+ encoded_data = malloc(*output_length + 1);
+ if (encoded_data == NULL) {
+ return NULL;
+ }
+
+ for (i = 0, j = 0; i < input_length;) {
+
+ uint32_t octet_a = i < input_length ? data[i++] : 0;
+ uint32_t octet_b = i < input_length ? data[i++] : 0;
+ uint32_t octet_c = i < input_length ? data[i++] : 0;
+
+ uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
+
+ encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F];
+ encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F];
+ }
+
+ for (i = 0; i < mod_table[input_length % 3]; i++) {
+ encoded_data[*output_length - 1 - i] = 0;
+ (*output_length)--;
+ }
+
+ return encoded_data;
+}
+
+#endif
+
+/**
+ * Remove a backing store entry from the entry table.
+ *
+ * This finds the store entry associated with the given key and
+ * removes it from the table. The removed entry is returned but is
+ * only valid until the next set_store_entry call.
+ *
+ * @param state The store state to use.
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on succes or NSERROR_NOT_FOUND
+ * if no entry coresponds to the url.
+ */
+static nserror
+remove_store_entry(struct store_state *state,
+ entry_ident_t ident,
+ struct store_entry **bse)
+{
+ entry_index_t sei; /* store entry index */
+
+ sei = BS_ENTRY_INDEX(ident, state);
+ if (sei == 0) {
+ LOG(("ident 0x%08x not in index", ident));
+ return NSERROR_NOT_FOUND;
+ }
+
+ if (state->entries[sei].ident != ident) {
+ /* entry ident did not match */
+ LOG(("ident 0x%08x did not match entry index %d", ident, sei));
+ return NSERROR_NOT_FOUND;
+ }
+
+ /* sei is entry to be removed, we swap it to the end of the
+ * table so there are no gaps and the returned entry is held
+ * in storage with reasonable lifetime.
+ */
+
+ /* remove entry from map */
+ BS_ENTRY_INDEX(ident, state) = 0;
+
+ /* global allocation accounting */
+ state->total_alloc -= state->entries[sei].data_alloc;
+ state->total_alloc -= state->entries[sei].meta_alloc;
+
+ state->last_entry--;
+
+ if (sei == state->last_entry) {
+ /* the removed entry was the last one, how conveniant */
+ *bse = &state->entries[sei];
+ } else {
+ /* need to swap entries */
+ struct store_entry tent;
+
+ tent = state->entries[sei];
+ state->entries[sei] = state->entries[state->last_entry];
+ state->entries[state->last_entry] = tent;
+
+ /* update map for moved entry */
+ BS_ENTRY_INDEX(state->entries[sei].ident, state) = sei;
+
+ *bse = &state->entries[state->last_entry];
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Generate a filename for an object.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier to use.
+ * @return The filename string or NULL on allocation error.
+ */
+static char *
+store_fname(struct store_state *state,
+ entry_ident_t ident,
+ enum backing_store_flags flags)
+{
+ int fname_len;
+ char *fname;
+ uint8_t b64u_i[7];
+ const char *dat;
+
+ /* base64 encode ident */
+ b64u_i[0] = encoding_table[(ident ) & 0x3f];
+ b64u_i[1] = encoding_table[(ident >> 6) & 0x3f];
+ b64u_i[2] = encoding_table[(ident >> 12) & 0x3f];
+ b64u_i[3] = encoding_table[(ident >> 18) & 0x3f];
+ b64u_i[4] = encoding_table[(ident >> 24) & 0x3f];
+ b64u_i[5] = encoding_table[(ident >> 30) & 0x3f];
+ b64u_i[6] = 0;
+
+ if ((flags & BACKING_STORE_META) != 0) {
+ dat = "meta";
+ } else {
+ dat = "data";
+ }
+
+ fname_len = strlen(state->path) + 32;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NULL;
+ }
+
+ /* number of chars with usefully encoded data in b64 */
+ switch(((state->addr_bits + 5) / 6)) {
+ case 1:
+ snprintf(fname, fname_len,
+ "%s/%s/%s",
+ state->path,
+ dat,
+ b64u_i);
+ break;
+
+ case 2:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i);
+ break;
+
+ case 3:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i);
+ break;
+
+ case 4:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i);
+ break;
+
+ case 5:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i[3],
+ b64u_i);
+ break;
+
+ case 6:
+ snprintf(fname, fname_len,
+ "%s/%s/%c/%c/%c/%c/%c/%s",
+ state->path,
+ dat,
+ b64u_i[0],
+ b64u_i[1],
+ b64u_i[2],
+ b64u_i[3],
+ b64u_i[4],
+ b64u_i);
+ break;
+
+ default:
+ assert(false);
+ }
+
+ return fname;
+}
+
+
+/**
+ * Remove the entry and files associated with an identifier.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier to use.
+ * @return NSERROR_OK on sucess or error code on failure.
+ */
+static nserror
+unlink_ident(struct store_state *state, entry_ident_t ident)
+{
+ char *fname;
+ nserror ret;
+ struct store_entry *bse;
+
+ /* LOG(("ident %08x", ident)); */
+
+ /* use the url hash as the entry identifier */
+ ret = remove_store_entry(state, ident, &bse);
+ if (ret != NSERROR_OK) {
+ /* LOG(("entry not found")); */
+ return ret;
+ }
+
+ fname = store_fname(state, bse->ident, BACKING_STORE_META);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ unlink(fname);
+ free(fname);
+
+ fname = store_fname(state, bse->ident, BACKING_STORE_NONE);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+ unlink(fname);
+ free(fname);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Quick sort comparison.
+ */
+static int compar(const void *va, const void *vb)
+{
+ const struct store_entry *a = &BS_ENTRY(*(entry_ident_t *)va, storestate);
+ const struct store_entry *b = &BS_ENTRY(*(entry_ident_t *)vb, storestate);
+
+ if (a->use_count < b->use_count) {
+ return -1;
+ } else if (a->use_count > b->use_count) {
+ return 1;
+ }
+ /* use count is the same - now consider last use time */
+
+ if (a->last_used < b->last_used) {
+ return -1;
+ } else if (a->last_used > b->last_used) {
+ return 1;
+ }
+
+ /* they are the same */
+ return 0;
+}
+
+
+/**
+ * Evict entries from backing store as per configuration.
+ *
+ * Entries are evicted to ensure the cache remains within the
+ * configured limits on size and number of entries.
+ *
+ * The approach is to check if the cache limits have been exceeded and
+ * if so build and sort list of entries to evict. The list is sorted
+ * by use count and then by age, so oldest object with least number of uses
+ * get evicted first.
+ *
+ * @param state The store state to use.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+static nserror store_evict(struct store_state *state)
+{
+ entry_ident_t *elist; /* sorted list of entry identifiers */
+ unsigned int ent;
+ unsigned int ent_count;
+ size_t removed; /* size of removed entries */
+ nserror ret = NSERROR_OK;
+
+ /* check if the cache has exceeded configured limit */
+ if ((state->total_alloc < state->limit) &&
+ (state->last_entry < (1U << state->entry_bits))) {
+ /* cache within limits */
+ return NSERROR_OK;
+ }
+
+ LOG(("Evicting entries to reduce %d by %d",
+ state->total_alloc, state->hysteresis));
+
+ /* allocate storage for the list */
+ elist = malloc(sizeof(entry_ident_t) * state->last_entry);
+ if (elist == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* sort the list avoiding entry 0 which is the empty sentinel */
+ for (ent = 1; ent < state->last_entry; ent++) {
+ elist[ent - 1] = state->entries[ent].ident;
+ }
+ ent_count = ent - 1; /* important to keep this as the entry count will change when entries are removed */
+ qsort(elist, ent_count, sizeof(entry_ident_t), compar);
+
+ /* evict entries in listed order */
+ removed = 0;
+ for (ent = 0; ent < ent_count; ent++) {
+
+ removed += BS_ENTRY(elist[ent], state).data_alloc;
+ removed += BS_ENTRY(elist[ent], state).meta_alloc;
+
+ ret = unlink_ident(state, elist[ent]);
+ if (ret != NSERROR_OK) {
+ break;
+ }
+
+ if (removed > state->hysteresis) {
+ break;
+ }
+ }
+
+ free(elist);
+
+ LOG(("removed %d in %d entries", removed, ent));
+
+ return ret;
+}
+
+
+/**
+ * Lookup a backing store entry in the entry table from a url.
+ *
+ * This finds the store entry associated with the given
+ * key. Additionally if an entry is found it updates the usage data
+ * about the entry.
+ *
+ * @param state The store state to use.
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on success or NSERROR_NOT_FOUND
+ * if no entry corresponds to the url.
+ */
+static nserror
+get_store_entry(struct store_state *state, nsurl *url, struct store_entry **bse)
+{
+ entry_ident_t ident;
+ unsigned int sei; /* store entry index */
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ /* use the url hash as the entry identifier */
+ ident = nsurl_hash(url);
+
+ sei = BS_ENTRY_INDEX(ident, state);
+
+ if (sei == 0) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ if (state->entries[sei].ident != ident) {
+ /* entry ident did not match */
+ LOG(("ident did not match entry"));
+ return NSERROR_NOT_FOUND;
+ }
+
+ *bse = &state->entries[sei];
+
+ state->entries[sei].last_used = time(NULL);
+ state->entries[sei].use_count++;
+
+ state->entries_dirty = true;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Set a backing store entry in the entry table from a url.
+ *
+ * This creates a backing store entry in the entry table for a url.
+ *
+ * @param url The value used as the unique key to search entries for.
+ * @param bse Pointer used to return value.
+ * @return NSERROR_OK and bse updated on succes or NSERROR_NOT_FOUND
+ * if no entry coresponds to the url.
+ */
+static nserror
+set_store_entry(struct store_state *state,
+ nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen,
+ struct store_entry **bse)
+{
+ entry_ident_t ident;
+ entry_index_t sei; /* store entry index */
+ struct store_entry *se;
+ nserror ret;
+ bool isrep; /* is the store repalcing an existing entry or not */
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ /* evict entries as required and ensure there is at least one
+ * new entry available.
+ */
+ ret = store_evict(state);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* use the url hash as the entry identifier */
+ ident = nsurl_hash(url);
+
+ sei = BS_ENTRY_INDEX(ident, state);
+
+ /** @todo Should this deal with cache eviction? */
+
+ if (sei == 0) {
+ /* allocating the next available entry */
+ sei = state->last_entry;
+ state->last_entry++;
+ BS_ENTRY_INDEX(ident, state) = sei;
+ isrep = false;
+ } else {
+ /* updating or replacing existing entry */
+ /** @todo should we be checking the entry ident
+ * matches the url. Thats a collision in the address
+ * mapping right? and is it important?
+ */
+ isrep = true;
+ }
+
+ se = &state->entries[sei];
+
+ se->ident = ident;
+ se->flags = STORE_ENTRY_FLAG_NONE;
+ se->use_count = 1;
+ se->last_used = time(NULL);
+
+ /* account for allocation */
+ if ((flags & BACKING_STORE_META) != 0) {
+ if (isrep) {
+ state->total_alloc -= se->meta_alloc;
+ } else {
+ se->data_alloc = 0;
+ }
+ se->meta_alloc = datalen;
+ } else {
+ if (isrep) {
+ state->total_alloc -= se->data_alloc;
+ } else {
+ se->meta_alloc = 0;
+ }
+ se->data_alloc = datalen;
+ }
+ state->total_alloc += datalen;
+
+ state->entries_dirty = true;
+
+ *bse = se;
+
+ return NSERROR_OK;
+}
+
+
+
+
+/**
+ * Open a file using a store ident.
+ *
+ * @param state The store state to use.
+ * @param ident The identifier of the file to open.
+ * @param flags The backing store flags.
+ * @pram openflags The flags used with the open call.
+ * @return An fd from the open call or -1 on error.
+ */
+static int
+store_open(struct store_state *state,
+ uint32_t ident,
+ enum backing_store_flags flags,
+ int openflags)
+{
+ char *fname;
+ nserror ret;
+ int fd;
+
+ fname = store_fname(state, ident, flags);
+ if (fname == NULL) {
+ LOG(("filename error"));
+ return -1;
+ }
+
+ /* ensure path to file is usable */
+ ret = filepath_mkdir_all(fname);
+ if (ret != NSERROR_OK) {
+ LOG(("file path \"%s\" could not be created", fname));
+ free(fname);
+ return -1;
+ }
+
+ LOG(("opening %s", fname));
+ fd = open(fname, openflags, S_IRUSR | S_IWUSR);
+
+ free(fname);
+
+ return fd;
+}
+
+/**
+ * Construct address ident to filesystem entry map
+ *
+ * To allow a filesystem entry to be found from it's identifier we
+ * construct an mapping index. This is a hash map from the entries URL
+ * (its unique key) to filesystem entry.
+ *
+ * As the entire entry list must be iterated over to construct the map
+ * we also compute the total storage in use.
+ *
+ * @param state The backing store global state.
+ * @return NSERROR_OK on sucess or NSERROR_NOMEM if the map storage
+ * could not be allocated.
+ */
+static nserror
+build_entrymap(struct store_state *state)
+{
+ unsigned int eloop;
+
+ state->addrmap = calloc(1<<state->addr_bits, sizeof(entry_index_t));
+ if (state->addrmap == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ state->total_alloc = 0;
+
+ for (eloop = 1; eloop < state->last_entry; eloop++) {
+ LOG(("entry:%d ident:0x%08x used:%d",
+ eloop,
+ BS_ADDRESS(state->entries[eloop].ident, state),
+ state->entries[eloop].use_count));
+
+ /* update the address map to point at the entry */
+ BS_ENTRY_INDEX(state->entries[eloop].ident, state) = eloop;
+
+ /* account for the storage space */
+ state->total_alloc += state->entries[eloop].data_alloc +
+ state->entries[eloop].meta_alloc;
+ }
+
+ return NSERROR_OK;
+}
+
+/**
+ * Write filesystem entries to file.
+ *
+ * @param state The backing store state to read the entries from.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror write_entries(struct store_state *state)
+{
+ int fd;
+ int fname_len;
+ char *fname;
+
+ if (state->entries_dirty == false) {
+ /* entries have not been updated since last write */
+ return NSERROR_OK;
+ }
+
+ /* entries file name string */
+ fname_len = strlen(state->path) + 11;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(fname, fname_len, "%s/entries", state->path);
+
+ fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
+ free(fname);
+ if (fd == -1) {
+ return NSERROR_SAVE_FAILED;
+ }
+
+ write(fd, state->entries, state->last_entry * sizeof(struct store_entry));
+ close(fd);
+
+
+ return NSERROR_OK;
+}
+
+/**
+ * Read description entries into memory.
+ *
+ * @param state The backing store state to put the loaded entries in.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+read_entries(struct store_state *state)
+{
+ int fd;
+ ssize_t rd;
+ size_t entries_size;
+ int fname_len;
+ char *fname;
+
+ /* entries file name string */
+ fname_len = strlen(state->path) + 11;
+ fname = calloc(1, fname_len);
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ snprintf(fname, fname_len, "%s/entries", state->path);
+
+ entries_size = (1 << state->entry_bits) * sizeof(struct store_entry);
+
+ LOG(("Allocating %d bytes", entries_size));
+
+ state->entries = calloc(1, entries_size);
+ if (state->entries == NULL) {
+ free(fname);
+ return NSERROR_NOMEM;
+ }
+
+ fd = open(fname, O_RDWR);
+ free(fname);
+ if (fd != -1) {
+ rd = read(fd, state->entries, entries_size);
+ close(fd);
+ if (rd > 0) {
+ state->last_entry = rd / sizeof(struct store_entry);
+ LOG(("Read %d entries", state->last_entry));
+ }
+ } else {
+ /* could rebuild entries from fs */
+ state->last_entry = 1;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Write the control file for the current state.
+ *
+ * @param state The state to write to the control file.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+write_control(struct store_state *state)
+{
+ FILE *fcontrol;
+ nserror ret;
+ char *fname;
+
+ /* read control file */
+ fname = filepath_append(state->path, "control");
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ ret = filepath_mkdir_all(fname);
+ if (ret != NSERROR_OK) {
+ free(fname);
+ return ret;
+ }
+
+ fcontrol = fopen(fname, "wb");
+
+ free(fname);
+
+ if (fcontrol == NULL) {
+ return NSERROR_NOT_FOUND;
+ }
+
+ fprintf(fcontrol, "%u%c", CONTROL_VERSION, 0);
+ fprintf(fcontrol, "%u%c", state->entry_bits, 0);
+ fprintf(fcontrol, "%u%c", state->addr_bits, 0);
+ fprintf(fcontrol, "%u%c", state->last_entry, 0);
+
+ fclose(fcontrol);
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Read and parse the control file.
+ *
+ * @param state The state to read from the control file.
+ * @return NSERROR_OK on sucess or error code on faliure.
+ */
+static nserror
+read_control(struct store_state *state)
+{
+ FILE *fcontrol;
+ unsigned int ctrlversion;
+ unsigned int addrbits;
+ unsigned int entrybits;
+ char *fname;
+
+ /* open control file */
+ fname = filepath_append(state->path, "control");
+ if (fname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ fcontrol = fopen(fname, "rb");
+
+ free(fname);
+
+ if (fcontrol == NULL) {
+ /* unable to open control file */
+ if (errno == ENOENT) {
+ return NSERROR_NOT_FOUND;
+ } else {
+ return NSERROR_INIT_FAILED;
+ }
+ }
+
+ /* read control and setup new state */
+
+ /* first line is version */
+ if (fscanf(fcontrol, "%u", &ctrlversion) != 1) {
+ goto control_error;
+ }
+
+ if (ctrlversion != CONTROL_VERSION) {
+ goto control_error;
+ }
+
+ /* second line is log2 max number of entries */
+ if (fscanf(fcontrol, "%u", &entrybits) != 1) {
+ goto control_error;
+ }
+
+ /* second line is log2 size of address hash */
+ if (fscanf(fcontrol, "%u", &addrbits) != 1) {
+ goto control_error;
+ }
+
+ fclose(fcontrol);
+
+ state->entry_bits = entrybits;
+ state->addr_bits = addrbits;
+
+ return NSERROR_OK;
+
+control_error: /* problem with the control file */
+
+ fclose(fcontrol);
+
+ return NSERROR_INIT_FAILED;
+}
+
+
+
+
+/* Functions exported in the backing store table */
+
+/**
+ * Initialise the backing store.
+ *
+ * @param parameters to configure backing store.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+initialise(const struct llcache_store_parameters *parameters)
+{
+ struct store_state *newstate;
+ nserror ret;
+
+ /* check backing store is not already initialised */
+ if (storestate != NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ /* if we are not allowed any space simply give up on init */
+ if (parameters->limit == 0) {
+ return NSERROR_OK;
+ }
+
+ /* if the path to the cache directory is not set do not init */
+ if (parameters->path == NULL) {
+ return NSERROR_OK;
+ }
+
+ /* allocate new store state and set defaults */
+ newstate = calloc(1, sizeof(struct store_state));
+ if (newstate == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ newstate->path = strdup(parameters->path);
+ newstate->limit = parameters->limit;
+ newstate->hysteresis = parameters->hysteresis;
+ newstate->addr_bits = ADDRESS_BITS;
+ newstate->entry_bits = ENTRY_BITS;
+
+ ret = read_control(newstate);
+ if (ret != NSERROR_OK) {
+ ret = write_control(newstate);
+ }
+ if (ret != NSERROR_OK) {
+ /* that went well obviously */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ /* ensure the maximum number of entries can be represented in
+ * the type available to store it.
+ */
+ if (newstate->entry_bits > (8 * sizeof(entry_index_t))) {
+ newstate->entry_bits = (8 * sizeof(entry_index_t));
+ }
+
+ /* read filesystem entries */
+ ret = read_entries(newstate);
+ if (ret != NSERROR_OK) {
+ /* that went well obviously */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ /* build entry hash map */
+ ret = build_entrymap(newstate);
+ if (ret != NSERROR_OK) {
+ /* that obviously went well */
+ free(newstate->path);
+ free(newstate);
+ return ret;
+ }
+
+ storestate = newstate;
+
+ LOG(("FS backing store init successful"));
+
+ LOG(("path:%s limit:%d hyst:%d addr:%d entries:%d", newstate->path, newstate->limit, newstate->hysteresis, newstate->addr_bits, newstate->entry_bits));
+ LOG(("Using %d/%d", newstate->total_alloc, newstate->limit));
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Finalise the backing store.
+ *
+ * @return NSERROR_OK on success.
+ */
+static nserror
+finalise(void)
+{
+ if (storestate != NULL) {
+ write_entries(storestate);
+
+ free(storestate->path);
+ free(storestate);
+ storestate = NULL;
+ }
+ return NSERROR_OK;
+}
+
+
+/**
+ * Place an object in the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the object is stored.
+ * @param data The objects source data.
+ * @param datalen The length of the \a data.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+store(nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen)
+{
+ nserror ret;
+ struct store_entry *bse;
+ int fd;
+
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ /* set the store entry up */
+ ret = set_store_entry(storestate, url, flags, data, datalen, &bse);
+ if (ret != NSERROR_OK) {
+ LOG(("store entry setting failed"));
+ return ret;
+ }
+
+ fd = store_open(storestate, bse->ident, flags, O_CREAT | O_WRONLY);
+ if (fd < 0) {
+ perror("");
+ LOG(("Open failed %d",fd));
+ return NSERROR_SAVE_FAILED;
+ }
+
+ LOG(("Writing %d bytes from %p", datalen, data));
+ write(fd, data, datalen);
+
+ close(fd);
+
+ return NSERROR_OK;
+}
+
+/**
+ * Retrive an object from the backing store.
+ *
+ * @param url The url is used as the unique primary key for the data.
+ * @param flags The flags to control how the object is stored.
+ * @param data The objects data.
+ * @param datalen The length of the \a data retrieved.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+fetch(nsurl *url,
+ enum backing_store_flags *flags,
+ uint8_t **data_out,
+ size_t *datalen_out)
+{
+ nserror ret;
+ struct store_entry *bse;
+ uint8_t *data;
+ size_t datalen;
+ int fd;
+ ssize_t rd;
+
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ ret = get_store_entry(storestate, url, &bse);
+ if (ret != NSERROR_OK) {
+ LOG(("entry not found"));
+ return ret;
+ }
+
+ LOG(("retriving cache file for url:%s", nsurl_access(url)));
+
+ fd = store_open(storestate, bse->ident, *flags, O_RDONLY);
+ if (fd < 0) {
+ LOG(("Open failed"));
+ /** @todo should this invalidate the entry? */
+ return NSERROR_NOT_FOUND;
+ }
+
+ data = *data_out;
+ datalen = *datalen_out;
+
+ /* need to deal with buffers */
+ if (data == NULL) {
+ if (datalen == 0) {
+ /* caller did not know the files length */
+ if (((*flags) & BACKING_STORE_META) != 0) {
+ datalen = bse->meta_alloc;
+ } else {
+ datalen = bse->data_alloc;
+ }
+ }
+
+ data = malloc(datalen);
+ if (data == NULL) {
+ close(fd);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /** @todo should this check datalen is sufficient */
+
+ LOG(("Reading %d bytes into %p from file", datalen, data));
+
+ /** @todo this read should be an a loop */
+ rd = read(fd, data, datalen);
+ if (rd <= 0) {
+ LOG(("read returned %d", rd));
+ close(fd);
+ if ((*data_out) == NULL) {
+ free(data);
+ }
+ return NSERROR_NOT_FOUND;
+ }
+
+ close(fd);
+
+ *data_out = data;
+ *datalen_out = datalen;
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Invalidate a source object from the backing store.
+ *
+ * The entry (if present in the backing store) must no longer
+ * be returned as a result to the fetch or meta operations.
+ *
+ * @param url The url is used as the unique primary key to invalidate.
+ * @return NSERROR_OK on success or error code on faliure.
+ */
+static nserror
+invalidate(nsurl *url)
+{
+ /* check backing store is initialised */
+ if (storestate == NULL) {
+ return NSERROR_INIT_FAILED;
+ }
+
+ LOG(("url:%s", nsurl_access(url)));
+
+ return unlink_ident(storestate, nsurl_hash(url));
+}
+
+
+static struct gui_llcache_table llcache_table = {
+ .initialise = initialise,
+ .finalise = finalise,
+ .store = store,
+ .fetch = fetch,
+ .invalidate = invalidate,
+};
+
+struct gui_llcache_table *filesystem_llcache_table = &llcache_table;
diff --git a/content/llcache.c b/content/llcache.c
index 77d0335..587ada6 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -31,15 +31,6 @@
*
* \todo turn llcache debugging off
*
- * \todo implement expiry from backing store of objects not currently
- * in cache lists.
- *
- * \todo make backing store size bounded by configuration
- *
- * \todo make backing store have an index to improve performance
- *
- * \todo make backing store have a more efficient metadata store.
- *
*/
#include <stdlib.h>
@@ -943,7 +934,7 @@ llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
else
freshness_lifetime = 0;
- LLCACHE_LOG(("%d:%d", freshness_lifetime, current_age));
+ /* LLCACHE_LOG(("%d:%d", freshness_lifetime, current_age)); */
if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
(freshness_lifetime > current_age)) {
@@ -1078,7 +1069,7 @@ llcache_object_remove_from_list(llcache_object *object, llcache_object **list)
*/
static nserror llcache_persist_retrieve(llcache_object *object)
{
- enum llcache_store_flags flags = LLCACHE_STORE_NONE;
+ enum backing_store_flags flags = BACKING_STORE_NONE;
/* ensure the source data is present if necessary */
if ((object->source_data != NULL) ||
@@ -1231,18 +1222,23 @@ llcache_process_metadata(llcache_object *object)
size_t num_headers;
size_t hloop;
struct tm ltm;
- enum llcache_store_flags flags = LLCACHE_STORE_META;
+ enum backing_store_flags flags = BACKING_STORE_META;
- /* attempt to retrieve object metadata from the cache */
+ LOG(("Retriving metadata"));
+
+ /* attempt to retrieve object metadata from the backing store */
res = guit->llcache->fetch(object->url,
&flags,
&metadata,
&metadatalen);
- if (res != NSERROR_OK)
+ if (res != NSERROR_OK) {
return res;
+ }
end = metadata + metadatalen;
+ LOG(("Processing retrived data"));
+
/* metadata line 1 is the url the metadata referrs to */
line = 1;
ln = (char *)metadata;
@@ -1374,8 +1370,9 @@ llcache_object_fetch_persistant(llcache_object *object,
/* retrieve and process metadata */
error = llcache_process_metadata(object);
- if (error != NSERROR_OK)
+ if (error != NSERROR_OK) {
return error;
+ }
/* entry came out of cache - need to setup object state */
if (post != NULL) {
@@ -1384,8 +1381,9 @@ llcache_object_fetch_persistant(llcache_object *object,
return error;
}
- if (referer != NULL)
+ if (referer != NULL) {
referer_clone = nsurl_ref(referer);
+ }
object->fetch.flags = flags;
object->fetch.referer = referer_clone;
@@ -1448,6 +1446,8 @@ llcache_object_retrieve_from_cache(nsurl *url,
/* attempt to retrieve object from persistant store */
error = llcache_object_fetch_persistant(obj, flags, referer, post, redirect_count);
if (error == NSERROR_OK) {
+ LLCACHE_LOG(("retrived object from persistant store"));
+
/* set object from persistant store as newest */
newest = obj;
@@ -2178,7 +2178,7 @@ write_backing_store(struct llcache_object *object, size_t *written_out)
/* put object data in backing store */
ret = guit->llcache->store(object->url,
- LLCACHE_STORE_NONE,
+ BACKING_STORE_NONE,
object->source_data,
object->source_len);
if (ret != NSERROR_OK) {
@@ -2196,7 +2196,7 @@ write_backing_store(struct llcache_object *object, size_t *written_out)
}
ret = guit->llcache->store(object->url,
- LLCACHE_STORE_META,
+ BACKING_STORE_META,
metadata,
metadatasize);
free(metadata);
@@ -2774,12 +2774,44 @@ llcache_object_snapshot(llcache_object *object, llcache_object **snapshot)
return NSERROR_OK;
}
+/**
+ * total ram usage of object
+ */
+static inline uint32_t
+total_object_size(llcache_object *object)
+{
+ uint32_t tot;
+ size_t hdrc;
+
+ tot = sizeof(*object);
+ tot += nsurl_length(object->url);
+
+ if (object->source_data != NULL) {
+ tot += object->source_len;
+ }
+
+ tot += sizeof(llcache_header) * object->num_headers;
+
+ for (hdrc = 0; hdrc < object->num_headers; hdrc++) {
+ if (object->headers[hdrc].name != NULL) {
+ tot += strlen(object->headers[hdrc].name);
+ }
+ if (object->headers[hdrc].value != NULL) {
+ tot += strlen(object->headers[hdrc].value);
+ }
+ }
+
+ return tot;
+}
+
/******************************************************************************
* Public API *
******************************************************************************/
/**
* Attempt to clean the cache
+ *
+ * The memory cache cleaning discards objects in order of increasing value.
*/
/* Exported interface documented in llcache.h */
void llcache_clean(void)
@@ -2801,13 +2833,13 @@ void llcache_clean(void)
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false)) {
- LLCACHE_LOG(("Found victim %p", object));
+ LLCACHE_LOG(("Discarding uncachable object with no users (%p) %s", object, nsurl_access(object->url)));
llcache_object_remove_from_list(object,
&llcache->uncached_objects);
llcache_object_destroy(object);
} else {
- llcache_size += object->source_len + sizeof(*object);
+ llcache_size += total_object_size(object);
}
}
@@ -2823,17 +2855,10 @@ void llcache_clean(void)
if ((object->users == NULL) &&
(object->candidate_count == 0) &&
(object->fetch.fetch == NULL) &&
- (object->fetch.outstanding_query == false)) {
-
- if (remaining_lifetime > 0) {
- /* object is fresh */
- llcache_size += sizeof(*object);
- if (object->source_data != NULL) {
- llcache_size += object->source_len;
- }
- } else {
- /* object is not fresh */
- LLCACHE_LOG(("Found stale cacheable object (%p) with no users or pending fetches", object));
+ (object->fetch.outstanding_query == false) &&
+ (remaining_lifetime <= 0)) {
+ /* object is stale */
+ LLCACHE_LOG(("discarding stale cacheable object with no users or pending fetches (%p) %s", object, nsurl_access(object->url)));
llcache_object_remove_from_list(object,
&llcache->cached_objects);
@@ -2843,10 +2868,10 @@ void llcache_clean(void)
}
llcache_object_destroy(object);
- }
+
} else {
- /* object has users */
- llcache_size += object->source_len + sizeof(*object);
+ /* object has users so account for the storage */
+ llcache_size += total_object_size(object);
}
}
@@ -2858,9 +2883,9 @@ void llcache_clean(void)
llcache_persist(NULL);
}
- /* Fresh cacheable objects with no users, no pending fetches
- * and pushed to persistant store while the cache exceeds
- * the configured size.
+ /* Source data of fresh cacheable objects with no users, no
+ * pending fetches and pushed to persistant store while the
+ * cache exceeds the configured size.
*/
for (object = llcache->cached_objects;
((llcache->limit < llcache_size) && (object != NULL));
@@ -2882,8 +2907,39 @@ void llcache_clean(void)
}
}
- /* Fresh cacheable objects with no users or pending
- * fetches while the cache exceeds the configured size.
+ /* Fresh cacheable objects with no users, no pending fetches
+ * and pushed to persistant store while the cache exceeds
+ * the configured size. Efectively just the object metadata.
+ */
+ for (object = llcache->cached_objects;
+ ((llcache->limit < llcache_size) && (object != NULL));
+ object = next) {
+ next = object->next;
+ if ((object->users == NULL) &&
+ (object->candidate_count == 0) &&
+ (object->fetch.fetch == NULL) &&
+ (object->fetch.outstanding_query == false) &&
+ (object->store_state == LLCACHE_STATE_DISC) &&
+ (object->source_data == NULL)) {
+ LLCACHE_LOG(("discarding backed object len:%d age:%d (%p) %s",
+ object->source_len,
+ time(NULL) - object->last_used,
+ object,
+ nsurl_access(object->url)));
+
+ llcache_size -= total_object_size(object);
+
+ llcache_object_remove_from_list(object,
+ &llcache->cached_objects);
+ llcache_object_destroy(object);
+
+ }
+ }
+
+ /* Fresh cacheable objects with no users or pending fetches
+ * while the cache exceeds the configured size. These are the
+ * most valuble objects as replacing them is a full network
+ * fetch
*/
for (object = llcache->cached_objects;
((llcache->limit < llcache_size) && (object != NULL));
@@ -2895,10 +2951,12 @@ void llcache_clean(void)
(object->fetch.fetch == NULL) &&
(object->fetch.outstanding_query == false) &&
(object->store_state == LLCACHE_STATE_RAM)) {
- LLCACHE_LOG(("discarding object:%p len:%d age:%d",
- object,
+ LLCACHE_LOG(("discarding fresh object len:%d age:%d (%p) %s",
object->source_len,
- time(NULL) - object->last_used));
+ time(NULL) - object->last_used,
+ object,
+ nsurl_access(object->url)));
+
llcache_size -= object->source_len + sizeof(*object);
llcache_object_remove_from_list(object,
diff --git a/content/llcache.h b/content/llcache.h
index 286e20e..6fe5c20 100644
--- a/content/llcache.h
+++ b/content/llcache.h
@@ -164,14 +164,6 @@ struct llcache_store_parameters {
size_t limit; /**< The backing store upper bound target size */
size_t hysteresis; /**< The hysteresis around the target size */
-
- /** number of bits to use for hash in filename mapping.
- *
- * 0 indicates use no hash. (variable length filenames)
- * 23 is a reasonable compromise for RISC OS.
- * 160 uses sha1 in a manner similar to git.
- */
- int hashsize;
};
/**
diff --git a/content/no_backing_store.c b/content/no_backing_store.c
new file mode 100644
index 0000000..1921015
--- /dev/null
+++ b/content/no_backing_store.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 Vincent Sanders <vince(a)netsurf-browser.org>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/** \file
+ * Low-level resource cache null persistant storage implementation.
+ */
+
+#include "utils/nsurl.h"
+
+#include "content/backing_store.h"
+
+
+/* default to disabled backing store */
+static nserror initialise(const struct llcache_store_parameters *parameters)
+{
+ return NSERROR_OK;
+}
+
+static nserror finalise(void)
+{
+ return NSERROR_OK;
+}
+
+static nserror store(nsurl *url,
+ enum backing_store_flags flags,
+ const uint8_t *data,
+ const size_t datalen)
+{
+ return NSERROR_SAVE_FAILED;
+}
+
+static nserror fetch(nsurl *url,
+ enum backing_store_flags *flags,
+ uint8_t **data_out,
+ size_t *datalen_out)
+{
+ return NSERROR_NOT_FOUND;
+}
+
+static nserror invalidate(nsurl *url)
+{
+ return NSERROR_NOT_FOUND;
+}
+
+static struct gui_llcache_table llcache_table = {
+ .initialise = initialise,
+ .finalise = finalise,
+ .store = store,
+ .fetch = fetch,
+ .invalidate = invalidate,
+};
+
+struct gui_llcache_table *null_llcache_table = &llcache_table;
diff --git a/desktop/Makefile b/desktop/Makefile
index a914eb3..218f60e 100644
--- a/desktop/Makefile
+++ b/desktop/Makefile
@@ -8,7 +8,7 @@ S_DESKTOP := cookie_manager.c knockout.c hotlist.c mouse.c \
S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP))
# version.c needs the testament
-desktop/version.c: testament utils/testament.h
+desktop/version.c: testament $(OBJROOT)/testament.h
# S_BROWSER are sources related to full browsers but are common
# between RISC OS, GTK, BeOS and AmigaOS builds
diff --git a/desktop/gui.h b/desktop/gui.h
index 93775ca..96fe6a8 100644
--- a/desktop/gui.h
+++ b/desktop/gui.h
@@ -422,6 +422,52 @@ struct gui_utf8_table {
nserror (*local_to_utf8)(const char *string, size_t len, char **result);
};
+/**
+ * function table for page text search.
+ */
+struct gui_search_table {
+ /**
+ * Change the displayed search status.
+ *
+ * \param found search pattern matched in text
+ * \param p gui private data pointer provided with search callbacks
+ */
+ void (*status)(bool found, void *p);
+
+ /**
+ * display hourglass while searching.
+ *
+ * \param active start/stop indicator
+ * \param p gui private data pointer provided with search callbacks
+ */
+ void (*hourglass)(bool active, void *p);
+
+ /**
+ * add search string to recent searches list
+ * front has full liberty how to implement the bare notification;
+ * core gives no guarantee of the integrity of the string
+ *
+ * \param string search pattern
+ * \param p gui private data pointer provided with search callbacks
+ */
+ void (*add_recent)(const char *string, void *p);
+
+ /**
+ * activate search forwards button in gui
+ *
+ * \param active activate/inactivate
+ * \param p gui private data pointer provided with search callbacks
+ */
+ void (*forward_state)(bool active, void *p);
+
+ /**
+ * activate search back button in gui
+ *
+ * \param active activate/inactivate
+ * \param p gui private data pointer provided with search callbacks
+ */
+ void (*back_state)(bool active, void *p);
+};
/**
* Graphical user interface browser misc function table.
@@ -532,11 +578,18 @@ struct gui_table {
struct gui_utf8_table *utf8;
/**
- * Low level cache table
+ * Page search table.
+ *
+ * Provides routines for the interactive text search on a page.
+ */
+ struct gui_search_table *search;
+
+ /**
+ * Low level cache table.
*
* Used by the low level cache to push objects to persistant
* storage. The table is optional and may be NULL which
- * disables persistant caching of objects
+ * uses the default implementation.
*/
struct gui_llcache_table *llcache;
};
diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c
index df51392..0b9ec31 100644
--- a/desktop/gui_factory.c
+++ b/desktop/gui_factory.c
@@ -344,7 +344,63 @@ static nserror verify_utf8_register(struct gui_utf8_table *gut)
return NSERROR_OK;
}
-/** verify clipboard table is valid */
+static void gui_default_status(bool found, void *p)
+{
+}
+
+static void gui_default_hourglass(bool active, void *p)
+{
+}
+
+static void gui_default_add_recent(const char *string, void *p)
+{
+}
+
+static void gui_default_forward_state(bool active, void *p)
+{
+}
+
+static void gui_default_back_state(bool active, void *p)
+{
+}
+
+static struct gui_search_table default_search_table = {
+ .status = gui_default_status,
+ .hourglass = gui_default_hourglass,
+ .add_recent = gui_default_add_recent,
+ .forward_state = gui_default_forward_state,
+ .back_state = gui_default_back_state,
+};
+
+/** verify search table is valid */
+static nserror verify_search_register(struct gui_search_table *gst)
+{
+ /* check table is present */
+ if (gst == NULL) {
+ return NSERROR_BAD_PARAMETER;
+ }
+
+ /* fill in the optional entries with defaults */
+ if (gst->status == NULL) {
+ gst->status = default_search_table.status;
+ }
+ if (gst->hourglass == NULL) {
+ gst->hourglass = default_search_table.hourglass;
+ }
+ if (gst->add_recent == NULL) {
+ gst->add_recent = default_search_table.add_recent;
+ }
+ if (gst->forward_state == NULL) {
+ gst->forward_state = default_search_table.forward_state;
+ }
+ if (gst->back_state == NULL) {
+ gst->back_state = default_search_table.back_state;
+ }
+
+ return NSERROR_OK;
+}
+
+/** verify low level cache persistant backing store table is valid */
static nserror verify_llcache_register(struct gui_llcache_table *glt)
{
/* check table is present */
@@ -372,7 +428,6 @@ static nserror verify_llcache_register(struct gui_llcache_table *glt)
return NSERROR_OK;
}
-
static nsurl *gui_default_get_resource_url(const char *path)
{
return NULL;
@@ -555,7 +610,7 @@ nserror gui_factory_register(struct gui_table *gt)
/* utf8 table */
if (gt->utf8 == NULL) {
- /* set default clipboard table */
+ /* set default utf8 table */
gt->utf8 = &default_utf8_table;
}
err = verify_utf8_register(gt->utf8);
@@ -563,10 +618,20 @@ nserror gui_factory_register(struct gui_table *gt)
return err;
}
+ /* search table */
+ if (gt->search == NULL) {
+ /* set default search table */
+ gt->search = &default_search_table;
+ }
+ err = verify_search_register(gt->search);
+ if (err != NSERROR_OK) {
+ return err;
+ }
+
/* llcache table */
if (gt->llcache == NULL) {
/* set default backing store table */
- gt->llcache = default_llcache_table;
+ gt->llcache = null_llcache_table;
}
err = verify_llcache_register(gt->llcache);
if (err != NSERROR_OK) {
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 51de982..a2eea08 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -124,7 +124,8 @@ static nserror netsurf_llcache_query_handler(const llcache_query *query,
* Initialise components used by gui NetSurf.
*/
-nserror netsurf_init(const char *messages, struct gui_table *gt)
+nserror
+netsurf_init(const char *messages, const char *store_path, struct gui_table *gt)
{
nserror ret;
struct utsname utsname;
@@ -134,9 +135,6 @@ nserror netsurf_init(const char *messages, struct gui_table *gt)
.cb = netsurf_llcache_query_handler,
.minimum_lifetime = LLCACHE_MIN_DISC_LIFETIME,
.bandwidth = LLCACHE_MAX_DISC_BANDWIDTH,
- .store = {
- .hashsize = 160,
- }
}
};
struct image_cache_parameters image_cache_parameters = {
@@ -201,8 +199,7 @@ nserror netsurf_init(const char *messages, struct gui_table *gt)
hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;;
/* set the path to the backing store */
- /** \todo set the backing store path properly */
- hlcache_parameters.llcache.store.path = "/tmp/ns";
+ hlcache_parameters.llcache.store.path = store_path;
/* image handler bitmap cache */
ret = image_cache_init(&image_cache_parameters);
diff --git a/desktop/netsurf.h b/desktop/netsurf.h
index 77589c7..62e7c0f 100644
--- a/desktop/netsurf.h
+++ b/desktop/netsurf.h
@@ -30,7 +30,7 @@ extern const int netsurf_version_minor;
struct gui_table;
/** Initialise netsurf core */
-nserror netsurf_init(const char *messages, struct gui_table *gt);
+nserror netsurf_init(const char *messages, const char *store_path, struct gui_table *gt);
/** Run primary event loop */
extern int netsurf_main_loop(void);
diff --git a/desktop/search.c b/desktop/search.c
index 4a02f6b..201d416 100644
--- a/desktop/search.c
+++ b/desktop/search.c
@@ -21,66 +21,27 @@
/** \file
* Free text search (core)
*/
-#include "utils/config.h"
-#include <ctype.h>
-#include <string.h>
-#include <dom/dom.h>
#include "content/content.h"
-#include "content/hlcache.h"
+
#include "desktop/browser_private.h"
-#include "utils/nsoption.h"
#include "desktop/search.h"
-#include "desktop/selection.h"
-#include "render/box.h"
-#include "render/html.h"
-#include "render/search.h"
-#include "render/textplain.h"
-#include "utils/config.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/url.h"
-#include "utils/utils.h"
-
-
-
-/**
- * Starts or continues an existing search.
- *
- * \param bw the browser_window to search
- * \param callbacks callbacks vtable to update frontend according to results
- * \param gui_data a pointer returned to the callbacks
- * \param flags search flags
- * \param string string to search for
- */
-void browser_window_search(struct browser_window *bw,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+/* exported function documented in desktop/search.h */
+void browser_window_search(struct browser_window *bw, void *context,
search_flags_t flags, const char *string)
{
- assert(gui_callbacks != NULL);
-
- if (bw == NULL || bw->current_content == NULL)
- return;
-
- content_search(bw->current_content, gui_callbacks, gui_data,
- flags, string);
+ if ((bw != NULL) &&
+ (bw->current_content != NULL)) {
+ content_search(bw->current_content, context, flags, string);
+ }
}
-
-/**
- * Clear up a search. Frees any memory used by the search
- *
- * \param bw the browser_window to search
- * \param callbacks callbacks vtable to update frontend according to results
- * \param gui_data a pointer returned to the callbacks
- * \param flags search flags
- * \param string string to search for
- */
+/* exported function documented in desktop/search.h */
void browser_window_search_clear(struct browser_window *bw)
{
- if (bw == NULL || bw->current_content == NULL)
- return;
-
- content_search_clear(bw->current_content);
+ if ((bw != NULL) &&
+ (bw->current_content != NULL)) {
+ content_search_clear(bw->current_content);
+ }
}
diff --git a/desktop/search.h b/desktop/search.h
index 8440ce9..254acde 100644
--- a/desktop/search.h
+++ b/desktop/search.h
@@ -33,54 +33,24 @@ typedef enum {
} search_flags_t;
/**
- * Change the displayed search status.
- * \param found search pattern matched in text
- * \param p gui private data pointer provided with search callbacks
- */
-typedef void (*gui_search_status)(bool found, void *p);
-
-/**
- * display hourglass while searching
- * \param active start/stop indicator
- * \param p gui private data pointer provided with search callbacks
- */
-typedef void (*gui_search_hourglass)(bool active, void *p);
-
-/**
- * add search string to recent searches list
- * front has full liberty how to implement the bare notification;
- * core gives no guarantee of the integrity of the const char *
- * \param string search pattern
- * \param p gui private data pointer provided with search callbacks
- */
-typedef void (*gui_search_add_recent)(const char *string, void *p);
-
-/**
- * activate search forwards button in gui
- * \param active activate/inactivate
- * \param p gui private data pointer provided with search callbacks
+ * Starts or continues an existing search.
+ *
+ * \param bw The browser_window to search.
+ * \param context A context pointer passed to the callbacks.
+ * \param flags Flags controlling the search operation.
+ * \param string The string being searched for.
*/
-typedef void (*gui_search_forward_state)(bool active, void *p);
+void browser_window_search(struct browser_window *bw, void *context, search_flags_t flags, const char *string);
/**
- * activate search back button in gui
- * \param active activate/inactivate
- * \param p gui private data pointer provided with search callbacks
+ * Clear up a search.
+ *
+ * Frees any memory used by the search.
+ *
+ * \param bw The browser window to clean up the search for.
+ * \param context A context pointer passed to the callbacks.
*/
-typedef void (*gui_search_back_state)(bool active, void *p);
-
-struct gui_search_callbacks {
- gui_search_forward_state forward_state;
- gui_search_back_state back_state;
- gui_search_status status;
- gui_search_hourglass hourglass;
- gui_search_add_recent add_recent;
-};
-
-void browser_window_search(struct browser_window *bw,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
- search_flags_t flags, const char *string);
void browser_window_search_clear(struct browser_window *bw);
#endif
diff --git a/desktop/textarea.c b/desktop/textarea.c
index 584642d..2ba0982 100644
--- a/desktop/textarea.c
+++ b/desktop/textarea.c
@@ -1780,13 +1780,14 @@ static void textarea_setup_text_offsets(struct textarea *ta)
if (ta->flags & TEXTAREA_MULTILINE) {
/* Multiline textarea */
text_y_offset += ta->pad_top;
- text_y_offset_baseline += (ta->line_height * 3 + 2) / 4 +
- ta->pad_top;
+ text_y_offset_baseline +=
+ (ta->line_height * 3 + 2) / 4 + ta->pad_top;
} else {
/* Single line text area; text is vertically centered */
int vis_height = ta->vis_height - 2 * ta->border_width;
text_y_offset += (vis_height - ta->line_height + 1) / 2;
- text_y_offset_baseline += (vis_height * 3 + 2) / 4;
+ text_y_offset_baseline +=
+ (2 * vis_height + ta->line_height + 2) / 4;
}
ta->text_y_offset = text_y_offset;
@@ -1894,9 +1895,9 @@ struct textarea *textarea_create(const textarea_flags flags,
ret->show = &ret->text;
}
- ret->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.3),
- FMUL(nscss_screen_dpi, INTTOFIX((setup->text.size))))),
- FONT_SIZE_SCALE * F_72));
+ ret->line_height = FIXTOINT(FMUL(FLTTOFIX(1.3), FDIV(FMUL(
+ nscss_screen_dpi, FDIV(INTTOFIX(setup->text.size),
+ INTTOFIX(FONT_SIZE_SCALE))), F_72)));
ret->caret_pos.line = ret->caret_pos.byte_off = -1;
ret->caret_x = 0;
diff --git a/desktop/version.c b/desktop/version.c
index 11544c0..99929e7 100644
--- a/desktop/version.c
+++ b/desktop/version.c
@@ -1,10 +1,10 @@
-#include "utils/testament.h"
+#include "testament.h"
-const char * const netsurf_version = "3.1 (Dev"
+const char * const netsurf_version = "3.2 (Dev"
#if defined(CI_BUILD)
" CI #" CI_BUILD
#endif
")"
;
const int netsurf_version_major = 3;
-const int netsurf_version_minor = 0;
+const int netsurf_version_minor = 2;
diff --git a/framebuffer/Makefile.defaults b/framebuffer/Makefile.defaults
index 6e2a3d1..5fe8e2c 100644
--- a/framebuffer/Makefile.defaults
+++ b/framebuffer/Makefile.defaults
@@ -2,46 +2,46 @@
# Framebuffer-target-specific options
# ----------------------------------------------------------------------------
- # Optimisation levels
- CFLAGS += -O2
-
- # Framebuffer default surface provider.
- # Valid values are: x, sdl, linux, vnc, able,
- NETSURF_FB_FRONTEND := sdl
-
- # Use libharu to enable PDF export and GTK printing support.
- # Valid options: YES, NO
- NETSURF_USE_HARU_PDF := NO
-
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := AUTO
-
- # Library to use for font plotting
- # Valid options: internal, freetype
- NETSURF_FB_FONTLIB := internal
-
- # Default freetype font files
- NETSURF_FB_FONT_SANS_SERIF := DejaVuSans.ttf
- NETSURF_FB_FONT_SANS_SERIF_BOLD := DejaVuSans-Bold.ttf
- NETSURF_FB_FONT_SANS_SERIF_ITALIC := DejaVuSans-Oblique.ttf
- NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD := DejaVuSans-BoldOblique.ttf
- NETSURF_FB_FONT_SERIF := DejaVuSerif.ttf
- NETSURF_FB_FONT_SERIF_BOLD := DejaVuSerif-Bold.ttf
- NETSURF_FB_FONT_MONOSPACE := DejaVuSansMono.ttf
- NETSURF_FB_FONT_MONOSPACE_BOLD := DejaVuSansMono-Bold.ttf
- NETSURF_FB_FONT_CURSIVE := Comic_Sans_MS.ttf
- NETSURF_FB_FONT_FANTASY := Impact.ttf
-
- # Default binary install path
- NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
-
- # Default resource install path
- NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
-
- # Default framebuffer search path
- NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
-
- # freetype compiled in font serch path
- NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
+# Optimisation levels
+CFLAGS += -O2
+
+# Framebuffer default surface provider.
+# Valid values are: x, sdl, linux, vnc, able,
+NETSURF_FB_FRONTEND := sdl
+
+# Use libharu to enable PDF export and GTK printing support.
+# Valid options: YES, NO
+NETSURF_USE_HARU_PDF := NO
+
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := AUTO
+
+# Library to use for font plotting
+# Valid options: internal, freetype
+NETSURF_FB_FONTLIB := internal
+
+# Default freetype font files
+NETSURF_FB_FONT_SANS_SERIF := DejaVuSans.ttf
+NETSURF_FB_FONT_SANS_SERIF_BOLD := DejaVuSans-Bold.ttf
+NETSURF_FB_FONT_SANS_SERIF_ITALIC := DejaVuSans-Oblique.ttf
+NETSURF_FB_FONT_SANS_SERIF_ITALIC_BOLD := DejaVuSans-BoldOblique.ttf
+NETSURF_FB_FONT_SERIF := DejaVuSerif.ttf
+NETSURF_FB_FONT_SERIF_BOLD := DejaVuSerif-Bold.ttf
+NETSURF_FB_FONT_MONOSPACE := DejaVuSansMono.ttf
+NETSURF_FB_FONT_MONOSPACE_BOLD := DejaVuSansMono-Bold.ttf
+NETSURF_FB_FONT_CURSIVE := Comic_Sans_MS.ttf
+NETSURF_FB_FONT_FANTASY := Impact.ttf
+
+# Default binary install path
+NETSURF_FRAMEBUFFER_BIN := $(PREFIX)/bin/
+
+# Default resource install path
+NETSURF_FRAMEBUFFER_RESOURCES := $(PREFIX)/share/netsurf/
+
+# Default framebuffer search path
+NETSURF_FB_RESPATH := $${HOME}/.netsurf/:$${NETSURFRES}:$(NETSURF_FRAMEBUFFER_RESOURCES):./framebuffer/res
+
+# freetype compiled in font serch path
+NETSURF_FB_FONTPATH := /usr/share/fonts/truetype/ttf-dejavu:/usr/share/fonts/truetype/msttcorefonts
diff --git a/framebuffer/convert_image.c b/framebuffer/convert_image.c
index bf47a35..838a907 100644
--- a/framebuffer/convert_image.c
+++ b/framebuffer/convert_image.c
@@ -159,6 +159,7 @@ main(int argc, char **argv)
if (br < 0) {
printf("Error reading input: %s\n", strerror(errno));
+ fclose(f);
return 1;
}
diff --git a/framebuffer/gui.c b/framebuffer/gui.c
index 7d3e95c..479a175 100644
--- a/framebuffer/gui.c
+++ b/framebuffer/gui.c
@@ -1832,7 +1832,7 @@ main(int argc, char** argv)
/* common initialisation */
messages = filepath_find(respaths, "Messages");
- ret = netsurf_init(messages, &framebuffer_gui_table);
+ ret = netsurf_init(messages, NULL, &framebuffer_gui_table);
free(messages);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
diff --git a/gtk/Makefile.defaults b/gtk/Makefile.defaults
index 23d4c17..90435a1 100644
--- a/gtk/Makefile.defaults
+++ b/gtk/Makefile.defaults
@@ -2,33 +2,36 @@
# GTK-specific options
# ----------------------------------------------------------------------------
- # Where to search for NetSurf's resources after looking in ~/.netsurf and
- # $NETSURFRES. It must have a trailing /
- NETSURF_GTK_RESOURCES := $(PREFIX)/share/netsurf/
+# Where to search for NetSurf's resources after looking in ~/.netsurf and
+# $NETSURFRES. It must have a trailing /
+NETSURF_GTK_RESOURCES := $(PREFIX)/share/netsurf/
- # Where to install the netsurf binary
- NETSURF_GTK_BIN := $(PREFIX)/bin/
+# Where to install the netsurf binary
+NETSURF_GTK_BIN := $(PREFIX)/bin/
- # Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_RSVG := AUTO
+# Enable NetSurf's use of librsvg in conjunction with Cairo to display SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_RSVG := AUTO
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO, AUTO
- NETSURF_USE_NSSVG := AUTO
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO, AUTO
+NETSURF_USE_NSSVG := AUTO
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := AUTO
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := AUTO
- # Configuration overrides for Mac OS X
- ifeq ($(HOST),macosx)
+# Enable building the source object cache filesystem based backing store.
+NETSURF_FS_BACKING_STORE := YES
+
+# Configuration overrides for Mac OS X
+ifeq ($(HOST),macosx)
NETSURF_USE_LIBICONV_PLUG := NO
NETSURF_USE_HARU_PDF := NO
- endif
+endif
- # Set default GTK version to build for (2 or 3)
- NETSURF_GTK_MAJOR := 2
+# Set default GTK version to build for (2 or 3)
+NETSURF_GTK_MAJOR := 2
- # Optimisation levels
- CFLAGS += -O2
+# Optimisation levels
+CFLAGS += -O2
diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c
index a8ff674..fcf30c8 100644
--- a/gtk/dialogs/preferences.c
+++ b/gtk/dialogs/preferences.c
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <math.h>
+#include "utils/filepath.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
@@ -1001,8 +1002,14 @@ nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
{
+ char *choices;
+
if (resid == GTK_RESPONSE_CLOSE) {
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
gtk_widget_hide(GTK_WIDGET(dlg));
}
}
@@ -1011,18 +1018,32 @@ G_MODULE_EXPORT gboolean
nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
gtk_widget_hide(GTK_WIDGET(dlg));
- /* delt with it by hiding window, no need to destory widget by
- * default */
+ /* Delt with it by hiding window, no need to destory widget by
+ * default.
+ */
return TRUE;
}
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
}
diff --git a/gtk/gui.c b/gtk/gui.c
index cf584c3..9c35737 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -44,6 +44,7 @@
#include "content/fetchers/resource.h"
#include "content/hlcache.h"
#include "content/urldb.h"
+#include "content/backing_store.h"
#include "desktop/browser.h"
#include "desktop/gui.h"
#include "desktop/netsurf.h"
@@ -56,14 +57,6 @@
#include "desktop/tree.h"
#include "css/utils.h"
-#include "render/form.h"
-#include "utils/filepath.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/url.h"
-#include "utils/utf8.h"
-#include "utils/utils.h"
-
#include "gtk/compat.h"
#include "gtk/completion.h"
#include "gtk/cookies.h"
@@ -77,14 +70,23 @@
#include "gtk/window.h"
#include "gtk/schedule.h"
#include "gtk/selection.h"
+#include "gtk/search.h"
+
+#include "render/form.h"
+#include "utils/filepath.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utf8.h"
+#include "utils/utils.h"
-char *options_file_location;
char *toolbar_indices_file_location;
char *res_dir_location;
-char *print_options_file_location;
char *languages_file_location;
char *themelist_file_location;
+char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+
GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
struct glade_file_location_s *glade_file_location;
@@ -242,48 +244,55 @@ nsgtk_init_glade(char **respath)
}
/**
- * Set option defaults for gtk frontend
+ * Set option defaults for gtk frontend.
*
* @param defaults The option table to update.
* @return error status.
*/
static nserror set_defaults(struct nsoption_s *defaults)
{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
+ char *fname;
- /* Set defaults for absent option strings */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Cookies", hdir);
- nsoption_setnull_charp(cookie_file, strdup(buf));
- nsoption_setnull_charp(cookie_jar, strdup(buf));
- if (nsoption_charp(cookie_file) == NULL ||
- nsoption_charp(cookie_jar) == NULL) {
- LOG(("Failed initialising cookie options"));
- return NSERROR_BAD_PARAMETER;
+ /* cookie file default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_file, fname);
}
- if (nsoption_charp(downloads_directory) == NULL) {
- snprintf(buf, PATH_MAX, "%s/", hdir);
- nsoption_set_charp(downloads_directory, strdup(buf));
+ /* cookie jar default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_jar, fname);
}
- if (nsoption_charp(url_file) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/URLs", hdir);
- nsoption_set_charp(url_file, strdup(buf));
+ /* url database default */
+ fname = filepath_append(nsgtk_config_home, "URLs");
+ if (fname != NULL) {
+ nsoption_setnull_charp(url_file, fname);
}
- if (nsoption_charp(hotlist_path) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/Hotlist", hdir);
- nsoption_set_charp(hotlist_path, strdup(buf));
+ /* bookmark database default */
+ fname = filepath_append(nsgtk_config_home, "Hotlist");
+ if (fname != NULL) {
+ nsoption_setnull_charp(hotlist_path, fname);
}
+ /* download directory default */
+ fname = filepath_append(getenv("HOME"), "");
+ if (fname != NULL) {
+ nsoption_setnull_charp(downloads_directory, fname);
+ }
+
+ /* default path to certificates */
nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs"));
- if (nsoption_charp(url_file) == NULL ||
- nsoption_charp(ca_path) == NULL ||
- nsoption_charp(downloads_directory) == NULL ||
- nsoption_charp(hotlist_path) == NULL) {
- LOG(("Failed initialising string options"));
+ if ((nsoption_charp(cookie_file) == NULL) ||
+ (nsoption_charp(cookie_jar) == NULL) ||
+ (nsoption_charp(url_file) == NULL) ||
+ (nsoption_charp(hotlist_path) == NULL) ||
+ (nsoption_charp(downloads_directory) == NULL) ||
+ (nsoption_charp(ca_path) == NULL)) {
+ LOG(("Failed initialising default resource paths"));
return NSERROR_BAD_PARAMETER;
}
@@ -297,32 +306,6 @@ static nserror set_defaults(struct nsoption_s *defaults)
return NSERROR_OK;
}
-static void check_options(char **respath)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
- nsoption_set_bool(core_select_menu, true);
-
- /* Attempt to handle nonsense status bar widths. These may exist
- * in people's Choices as the GTK front end used to abuse the
- * status bar width option by using it for an absolute value in px.
- * The GTK front end now correctly uses it as a proportion of window
- * width. Here we assume that a value of less than 15% is wrong
- * and set to the default two thirds. */
- if (nsoption_int(toolbar_status_size) < 1500) {
- nsoption_set_int(toolbar_status_size, 6667);
- }
-
- /* user options should be stored in the users home directory */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Choices", hdir);
- options_file_location = strdup(buf);
-
- filepath_sfinddef(respath, buf, "Print", "~/.netsurf/");
- LOG(("Using '%s' as Print Settings file", buf));
- print_options_file_location = strdup(buf);
-
-
-}
@@ -480,34 +463,6 @@ static void gui_init(int argc, char** argv, char **respath)
}
-/**
- * Check that ~/.netsurf/ exists, and if it doesn't, create it.
- */
-static void nsgtk_check_homedir(void)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
-
- if (hdir == NULL) {
- /* we really can't continue without a home directory. */
- LOG(("HOME is not set - nowhere to store state!"));
- die("NetSurf requires HOME to be set in order to run.\n");
-
- }
-
- snprintf(buf, PATH_MAX, "%s/.netsurf", hdir);
- if (access(buf, F_OK) != 0) {
- LOG(("You don't have a ~/.netsurf - creating one for you."));
- if (mkdir(buf, S_IRWXU) == -1) {
- LOG(("Unable to create %s", buf));
- die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n");
- }
- } else {
- if (chmod(buf, S_IRWXU) != 0) {
- LOG(("Unable to set permissions on %s", buf));
- }
- }
-}
/**
* Ensures output logging stream is correctly configured
@@ -600,10 +555,13 @@ static void gui_quit(void)
nsgtk_cookies_destroy();
nsgtk_history_destroy();
nsgtk_hotlist_destroy();
- free(print_options_file_location);
+
free(search_engines_file_location);
free(search_default_ico_location);
free(toolbar_indices_file_location);
+
+ free(nsgtk_config_home);
+
gtk_fetch_filetype_fin();
}
@@ -989,6 +947,298 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
}
+/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname;
+ struct stat dirname_stat;
+
+ dirname = filepath_append(path, leaf);
+ if (dirname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;;
+}
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ LOG(("\"%s\"", config_home));
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG(("\"%s\"", config_home));
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ LOG(("Attempting to create configuration directory"));
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ config_home = filepath_append(home_dir, ".config/netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ config_home = filepath_append(xdg_config_dir, "netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = filepath_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ LOG(("\"%s\"", config_home));
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+/**
+ * Get the path to the cache directory.
+ *
+ * @param cache_home_out Path to cache directory.
+ * @return NSERROR_OK on sucess and \a cache_home_out updated else error code.
+ */
+static nserror get_cache_home(char **cache_home_out)
+{
+ nserror ret;
+ char *xdg_cache_dir;
+ char *cache_home;
+ char *home_dir;
+
+ /* $XDG_CACHE_HOME defines the base directory relative to
+ * which user specific non-essential data files should be
+ * stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ /* If $XDG_CACHE_HOME is either not set or empty, a
+ * default equal to $HOME/.cache should be used.
+ */
+
+ home_dir = getenv("HOME");
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".cache/netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_cache_dir, "netsurf", &cache_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG(("\"%s\"", cache_home));
+
+ *cache_home_out = cache_home;
+ return NSERROR_OK;
+}
+
+static nserror create_cache_home(char **cache_home_out)
+{
+ char *cache_home;
+ char *home_dir;
+ char *xdg_cache_dir;
+ nserror ret;
+
+ LOG(("Attempting to create configuration directory"));
+
+ /* $XDG_CACHE_HOME defines the base directory
+ * relative to which user specific cache files
+ * should be stored.
+ */
+ xdg_cache_dir = getenv("XDG_CACHE_HOME");
+
+ if ((xdg_cache_dir == NULL) || (*xdg_cache_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ cache_home = filepath_append(home_dir, ".cache/netsurf/");
+ if (cache_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ cache_home = filepath_append(xdg_cache_dir, "netsurf/");
+ if (cache_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = filepath_mkdir_all(cache_home);
+ if (ret != NSERROR_OK) {
+ free(cache_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ cache_home[strlen(cache_home) - 1] = 0;
+
+ LOG(("\"%s\"", cache_home));
+
+ *cache_home_out = cache_home;
+
+ return NSERROR_OK;
+}
+
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* select menus generated by core code */
+ nsoption_set_bool(core_select_menu, true);
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
static struct gui_browser_table nsgtk_browser_table = {
.poll = nsgtk_poll,
.schedule = nsgtk_schedule,
@@ -1007,7 +1257,7 @@ static struct gui_browser_table nsgtk_browser_table = {
int main(int argc, char** argv)
{
char *messages;
- char *options;
+ char *cache_home = NULL;
nserror ret;
struct gui_table nsgtk_gui_table = {
.browser = &nsgtk_browser_table,
@@ -1015,13 +1265,25 @@ int main(int argc, char** argv)
.clipboard = nsgtk_clipboard_table,
.download = nsgtk_download_table,
.fetch = nsgtk_fetch_table,
+ .search = nsgtk_search_table,
+ .llcache = filesystem_llcache_table,
};
- /* check home directory is available */
- nsgtk_check_homedir();
-
+ /* build the common resource path list */
respaths = nsgtk_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"GTK_RESPATH":./gtk/res");
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG(("Unable to locate a configuration directory."));
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
gtk_init(&argc, &argv);
/* initialise logging. Not fatal if it fails but not much we
@@ -1029,23 +1291,31 @@ int main(int argc, char** argv)
*/
nslog_init(nslog_stream_configure, &argc, argv);
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ /* Initialise user options */
+ ret = nsgtk_option_init(&argc, argv);
if (ret != NSERROR_OK) {
fprintf(stderr, "Options failed to initialise (%s)\n",
messages_get_errorcode(ret));
return 1;
}
- options = filepath_find(respaths, "Choices");
- nsoption_read(options, nsoptions);
- free(options);
- nsoption_commandline(&argc, argv, nsoptions);
- check_options(respaths); /* check user options */
- /* common initialisation */
+ /* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
- ret = netsurf_init(messages, &nsgtk_gui_table);
+
+ /* Locate the correct user cache directory path */
+ ret = get_cache_home(&cache_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no cache directory exists yet so try to create one */
+ ret = create_cache_home(&cache_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG(("Unable to locate a cache directory."));
+ }
+
+ /* core initialisation */
+ ret = netsurf_init(messages, cache_home, &nsgtk_gui_table);
free(messages);
+ free(cache_home);
if (ret != NSERROR_OK) {
fprintf(stderr, "NetSurf core failed to initialise (%s)\n",
messages_get_errorcode(ret));
diff --git a/gtk/gui.h b/gtk/gui.h
index dc1f2b3..a9a98c6 100644
--- a/gtk/gui.h
+++ b/gtk/gui.h
@@ -52,11 +52,12 @@ extern struct glade_file_location_s *glade_file_location;
extern char *languages_file_location;
extern char *toolbar_indices_file_location;
-extern char *options_file_location; /**< location where user options are written */
extern char *res_dir_location;
-extern char *print_options_file_location;
extern char *themelist_file_location;
+/** Directory where all configuration files are held. */
+extern char *nsgtk_config_home;
+
extern GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
extern char **respaths; /** resource search path vector */
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index ffe6a22..436830b 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "utils/filepath.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/log.h"
@@ -863,9 +864,10 @@ MULTIHANDLER(print)
GtkPrintOperation *print_op;
GtkPageSetup *page_setup;
- GtkPrintSettings *gtk_print_settings;
+ GtkPrintSettings *print_settings;
GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
- struct print_settings *settings;
+ struct print_settings *nssettings;
+ char *settings_fname;
print_op = gtk_print_operation_new();
if (print_op == NULL) {
@@ -874,14 +876,16 @@ MULTIHANDLER(print)
}
/* use previously saved settings if any */
- gtk_print_settings = gtk_print_settings_new_from_file(
- print_options_file_location, NULL);
- if (gtk_print_settings != NULL) {
- gtk_print_operation_set_print_settings(print_op,
- gtk_print_settings);
-
- /* We're not interested in the settings any more */
- g_object_unref(gtk_print_settings);
+ settings_fname = filepath_append(nsgtk_config_home, "Print");
+ if (settings_fname != NULL) {
+ print_settings = gtk_print_settings_new_from_file(settings_fname, NULL);
+ if (print_settings != NULL) {
+ gtk_print_operation_set_print_settings(print_op,
+ print_settings);
+
+ /* We're not interested in the settings any more */
+ g_object_unref(print_settings);
+ }
}
content_to_print = bw->current_content;
@@ -889,33 +893,40 @@ MULTIHANDLER(print)
page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL);
if (page_setup == NULL) {
warn_user(messages_get("NoMemory"), 0);
+ free(settings_fname);
g_object_unref(print_op);
return TRUE;
}
gtk_print_operation_set_default_page_setup(print_op, page_setup);
- settings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
+ nssettings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
g_signal_connect(print_op, "begin_print",
- G_CALLBACK(gtk_print_signal_begin_print), settings);
+ G_CALLBACK(gtk_print_signal_begin_print), nssettings);
g_signal_connect(print_op, "draw_page",
G_CALLBACK(gtk_print_signal_draw_page), NULL);
g_signal_connect(print_op, "end_print",
- G_CALLBACK(gtk_print_signal_end_print), settings);
- if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN)
+ G_CALLBACK(gtk_print_signal_end_print), nssettings);
+
+ if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN) {
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
g->window,
NULL);
+ }
/* if the settings were used save them for future use */
- if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
- /* Don't ref the settings, as we don't want to own them */
- gtk_print_settings = gtk_print_operation_get_print_settings(
- print_op);
-
- gtk_print_settings_to_file(gtk_print_settings,
- print_options_file_location, NULL);
+ if (settings_fname != NULL) {
+ if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+ /* Do not increment the settings reference */
+ print_settings =
+ gtk_print_operation_get_print_settings(print_op);
+
+ gtk_print_settings_to_file(print_settings,
+ settings_fname,
+ NULL);
+ }
+ free(settings_fname);
}
/* Our print_settings object is destroyed by the end print handler */
@@ -1249,6 +1260,7 @@ MULTIHANDLER(downloads)
MULTIHANDLER(savewindowsize)
{
int x,y,w,h;
+ char *choices;
gtk_window_get_position(g->window, &x, &y);
gtk_window_get_size(g->window, &w, &h);
@@ -1258,7 +1270,11 @@ MULTIHANDLER(savewindowsize)
nsoption_set_int(window_x, x);
nsoption_set_int(window_y, y);
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
return TRUE;
}
@@ -1385,9 +1401,6 @@ MULTIHANDLER(reload)
/* clear potential search effects */
browser_window_search_clear(bw);
- nsgtk_search_set_forward_state(true, bw);
- nsgtk_search_set_back_state(true, bw);
-
browser_window_reload(bw, true);
return TRUE;
@@ -1404,9 +1417,6 @@ MULTIHANDLER(back)
/* clear potential search effects */
browser_window_search_clear(bw);
- nsgtk_search_set_forward_state(true, bw);
- nsgtk_search_set_back_state(true, bw);
-
browser_window_history_back(bw, false);
nsgtk_window_update_back_forward(g);
@@ -1424,9 +1434,6 @@ MULTIHANDLER(forward)
/* clear potential search effects */
browser_window_search_clear(bw);
- nsgtk_search_set_forward_state(true, bw);
- nsgtk_search_set_back_state(true, bw);
-
browser_window_history_forward(bw, false);
nsgtk_window_update_back_forward(g);
@@ -2392,14 +2399,14 @@ void nsgtk_scaffolding_set_websearch(nsgtk_scaffolding *g, const char *content)
void nsgtk_scaffolding_toggle_search_bar_visibility(nsgtk_scaffolding *g)
{
gboolean vis;
- struct browser_window *bw =
- nsgtk_get_browser_window(g->top_level);
+ struct browser_window *bw = nsgtk_get_browser_window(g->top_level);
+
g_object_get(G_OBJECT(g->search->bar), "visible", &vis, NULL);
if (vis) {
- if (bw != NULL)
+ if (bw != NULL) {
browser_window_search_clear(bw);
- nsgtk_search_set_forward_state(true, bw);
- nsgtk_search_set_back_state(true, bw);
+ }
+
gtk_widget_hide(GTK_WIDGET(g->search->bar));
} else {
gtk_widget_show(GTK_WIDGET(g->search->bar));
@@ -2436,9 +2443,6 @@ void nsgtk_scaffolding_set_top_level(struct gui_window *gw)
/* clear effects of potential searches */
browser_window_search_clear(bw);
- nsgtk_search_set_forward_state(true, bw);
- nsgtk_search_set_back_state(true, bw);
-
nsgtk_scaffolding_set_icon(gw);
/* Ensure the window's title bar is updated */
diff --git a/gtk/search.c b/gtk/search.c
index 4e3c2ff..44f9dde 100644
--- a/gtk/search.c
+++ b/gtk/search.c
@@ -25,10 +25,6 @@
#include <string.h>
#include <gdk/gdkkeysyms.h>
-#include "gtk/compat.h"
-#include "gtk/search.h"
-#include "gtk/scaffolding.h"
-#include "gtk/window.h"
#include "utils/config.h"
#include "content/content.h"
#include "content/hlcache.h"
@@ -40,17 +36,41 @@
#include "utils/messages.h"
#include "utils/utils.h"
-static void nsgtk_search_set_status(bool found, void *p);
-static void nsgtk_search_set_hourglass(bool active, void *p);
-static void nsgtk_search_add_recent(const char *string, void *p);
+#include "gtk/compat.h"
+#include "gtk/search.h"
+#include "gtk/scaffolding.h"
+#include "gtk/window.h"
-static struct gui_search_callbacks nsgtk_search_callbacks = {
- nsgtk_search_set_forward_state,
- nsgtk_search_set_back_state,
- nsgtk_search_set_status,
- nsgtk_search_set_hourglass,
- nsgtk_search_add_recent
-};
+/**
+ * activate search forwards button in gui.
+ *
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+static void nsgtk_search_set_forward_state(bool active, struct gui_window *gw)
+{
+ if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) {
+ struct gtk_scaffolding *g = nsgtk_get_scaffold(gw);
+ gtk_widget_set_sensitive(
+ GTK_WIDGET(nsgtk_scaffolding_search(g)->buttons[1]),
+ active);
+ }
+}
+
+/**
+ * activate search back button in gui.
+ *
+ * \param active activate/inactivate
+ * \param p the pointer sent to search_verify_new() / search_create_context()
+ */
+static void nsgtk_search_set_back_state(bool active, struct gui_window *gw)
+{
+ if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) {
+ struct gtk_scaffolding *g = nsgtk_get_scaffold(gw);
+ gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search(
+ g)->buttons[0]), active);
+ }
+}
/** connected to the search forward button */
@@ -70,7 +90,7 @@ gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data)
nsgtk_scaffolding_search(g)->checkAll)) ?
SEARCH_FLAG_SHOWALL : 0);
- browser_window_search(bw, &nsgtk_search_callbacks, (void *)gw, flags,
+ browser_window_search(bw, gw, flags,
gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry));
return TRUE;
}
@@ -93,7 +113,7 @@ gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data)
nsgtk_scaffolding_search(g)->checkAll)) ?
SEARCH_FLAG_SHOWALL : 0);
- browser_window_search(bw, &nsgtk_search_callbacks, (void *)gw, flags,
+ browser_window_search(bw, gw, flags,
gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry));
return TRUE;
}
@@ -117,8 +137,8 @@ gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data)
assert(bw != NULL);
- nsgtk_search_set_forward_state(true, (void *)bw);
- nsgtk_search_set_back_state(true, (void *)bw);
+ nsgtk_search_set_forward_state(true, gw);
+ nsgtk_search_set_back_state(true, gw);
search_flags_t flags = SEARCH_FLAG_FORWARDS |
(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(
@@ -128,7 +148,7 @@ gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data)
nsgtk_scaffolding_search(g)->checkAll)) ?
SEARCH_FLAG_SHOWALL : 0);
- browser_window_search(bw, &nsgtk_search_callbacks, (void *)gw, flags,
+ browser_window_search(bw, gw, flags,
gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry));
return TRUE;
}
@@ -151,7 +171,7 @@ gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data)
nsgtk_scaffolding_search(g)->checkAll)) ?
SEARCH_FLAG_SHOWALL : 0);
- browser_window_search(bw, &nsgtk_search_callbacks, (void *)gw, flags,
+ browser_window_search(bw, gw, flags,
gtk_entry_get_text(nsgtk_scaffolding_search(g)->entry));
return FALSE;
}
@@ -197,67 +217,11 @@ gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f,
return TRUE;
}
-/**
-* Change the displayed search status.
-* \param found search pattern matched in text
-* \param p the pointer sent to search_verify_new() / search_create_context()
-*/
-
-void nsgtk_search_set_status(bool found, void *p)
-{
-}
-
-/**
-* display hourglass while searching
-* \param active start/stop indicator
-* \param p the pointer sent to search_verify_new() / search_create_context()
-*/
-void nsgtk_search_set_hourglass(bool active, void *p)
-{
-}
-/**
-* add search string to recent searches list
-* front is at liberty how to implement the bare notification
-* should normally store a strdup() of the string;
-* core gives no guarantee of the integrity of the const char *
-* \param string search pattern
-* \param p the pointer sent to search_verify_new() / search_create_context()
-*/
-
-void nsgtk_search_add_recent(const char *string, void *p)
-{
-}
-
-/**
-* activate search forwards button in gui
-* \param active activate/inactivate
-* \param p the pointer sent to search_verify_new() / search_create_context()
-*/
-
-void nsgtk_search_set_forward_state(bool active, void *p)
-{
- struct gui_window *gw = (struct gui_window *)p;
- if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) {
- struct gtk_scaffolding *g = nsgtk_get_scaffold(gw);
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search(
- g)->buttons[1]), active);
- }
-}
-
-/**
-* activate search back button in gui
-* \param active activate/inactivate
-* \param p the pointer sent to search_verify_new() / search_create_context()
-*/
+static struct gui_search_table search_table = {
+ .forward_state = (void *)nsgtk_search_set_forward_state,
+ .back_state = (void *)nsgtk_search_set_back_state,
+};
-void nsgtk_search_set_back_state(bool active, void *p)
-{
- struct gui_window *gw = (struct gui_window *)p;
- if (gw != NULL && nsgtk_get_browser_window(gw) != NULL) {
- struct gtk_scaffolding *g = nsgtk_get_scaffold(gw);
- gtk_widget_set_sensitive(GTK_WIDGET(nsgtk_scaffolding_search(
- g)->buttons[0]), active);
- }
-}
+struct gui_search_table *nsgtk_search_table = &search_table;
diff --git a/gtk/search.h b/gtk/search.h
index 869a3cd..470ebb3 100644
--- a/gtk/search.h
+++ b/gtk/search.h
@@ -19,21 +19,18 @@
#ifndef _NETSURF_GTK_SEARCH_H_
#define _NETSURF_GTK_SEARCH_H_
-#include <gtk/gtk.h>
-#include "gtk/scaffolding.h"
+struct gui_search_table *nsgtk_search_table;
+
+struct gtk_scaffolding;
void nsgtk_search_bar_toggle_visibility(struct gtk_scaffolding * g);
gboolean nsgtk_search_entry_changed(GtkWidget *widget, gpointer data);
gboolean nsgtk_search_entry_activate(GtkWidget *widget, gpointer data);
-gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event,
- gpointer data);
+gboolean nsgtk_search_entry_key(GtkWidget *widget, GdkEventKey *event, gpointer data);
gboolean nsgtk_search_forward_button_clicked(GtkWidget *widget, gpointer data);
gboolean nsgtk_search_back_button_clicked(GtkWidget *widget, gpointer data);
gboolean nsgtk_search_close_button_clicked(GtkWidget *widget, gpointer data);
gboolean nsgtk_websearch_activate(GtkWidget *widget, gpointer data);
-gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f,
- gpointer data);
-void nsgtk_search_set_forward_state(bool active, void *p);
-void nsgtk_search_set_back_state(bool active, void *p);
+gboolean nsgtk_websearch_clear(GtkWidget *widget, GdkEventFocus *f, gpointer data);
#endif
diff --git a/gtk/window.c b/gtk/window.c
index 2da346b..a3d6d49 100644
--- a/gtk/window.c
+++ b/gtk/window.c
@@ -1154,9 +1154,21 @@ static void gui_window_place_caret(struct gui_window *g, int x, int y, int heigh
{
nsgtk_redraw_caret(g);
+ y += 1;
+ height -= 1;
+
+ if (y < clip->y0) {
+ height -= clip->y0 - y;
+ y = clip->y0;
+ }
+
+ if (y + height > clip->y1) {
+ height = clip->y1 - y + 1;
+ }
+
g->caretx = x;
- g->carety = y + 1;
- g->careth = height - 2;
+ g->carety = y;
+ g->careth = height;
nsgtk_redraw_caret(g);
diff --git a/monkey/Makefile.defaults b/monkey/Makefile.defaults
index 659c1e3..bbe4c6c 100644
--- a/monkey/Makefile.defaults
+++ b/monkey/Makefile.defaults
@@ -2,12 +2,13 @@
# Monkey-specific options
# ----------------------------------------------------------------------------
- # How did I get mixed up with this fucking monkey anyhow?
- NETSURF_MONKEY_RESOURCES := $(PREFIX)/share/netsurf/
- NETSURF_MONKEY_BIN := $(PREFIX)/bin/
- NETSURF_USE_RSVG := NO
- NETSURF_USE_NSSVG := NO
- NETSURF_USE_ROSPRITE := NO
- NETSURF_USE_HARU_PDF := NO
- NETSURF_USE_LIBICONV_PLUG := NO
- CFLAGS += -O2
+# How did I get mixed up with this fucking monkey anyhow?
+NETSURF_MONKEY_RESOURCES := $(PREFIX)/share/netsurf/
+NETSURF_MONKEY_BIN := $(PREFIX)/bin/
+NETSURF_USE_RSVG := NO
+NETSURF_USE_NSSVG := NO
+NETSURF_USE_ROSPRITE := NO
+NETSURF_USE_HARU_PDF := NO
+NETSURF_USE_LIBICONV_PLUG := NO
+
+CFLAGS += -O2
diff --git a/monkey/main.c b/monkey/main.c
index 96476d2..004ebae 100644
--- a/monkey/main.c
+++ b/monkey/main.c
@@ -151,7 +151,7 @@ main(int argc, char **argv)
/* common initialisation */
messages = filepath_find(respaths, "Messages");
- ret = netsurf_init(messages, &monkey_gui_table);
+ ret = netsurf_init(messages, NULL, &monkey_gui_table);
free(messages);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
diff --git a/render/box_normalise.c b/render/box_normalise.c
index 5a4b625..0c91fa3 100644
--- a/render/box_normalise.c
+++ b/render/box_normalise.c
@@ -42,6 +42,8 @@
struct span_info {
/** Number of rows this cell spans */
unsigned int row_span;
+ /** Row group of cell */
+ struct box *rg;
/** The cell in this column spans all rows until the end of the table */
bool auto_row;
};
@@ -72,7 +74,7 @@ static bool box_normalise_table_row(struct box *row,
html_content *c);
static bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
- unsigned int *start_column);
+ unsigned int *start_column, struct box *cell);
static bool box_normalise_inline_container(struct box *cont, html_content *c);
/**
@@ -419,6 +421,7 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
struct box *table_row;
struct box *table_cell;
unsigned int rows_left = table->rows;
+ unsigned int group_rows_left;
unsigned int col;
nscss_select_ctx ctx;
@@ -427,20 +430,37 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
/* Scan table, filling in width and height of table cells with
* colspan = 0 and rowspan = 0. Also generate empty cells */
- for (table_row_group = table->children; table_row_group != NULL;
- table_row_group = table_row_group->next) {
- for (table_row = table_row_group->children; table_row != NULL;
- table_row = table_row->next){
- for (table_cell = table_row->children;
- table_cell != NULL;
- table_cell = table_cell->next) {
+ for (table_row_group = table->children;
+ table_row_group != NULL;
+ table_row_group = table_row_group->next) {
+
+ group_rows_left = table_row_group->rows;
+
+ for (table_row = table_row_group->children;
+ table_row != NULL;
+ table_row = table_row->next) {
+
+ for (table_cell = table_row->children;
+ table_cell != NULL;
+ table_cell = table_cell->next) {
+
/* colspan = 0 -> colspan = 1 */
- if (table_cell->columns == 0)
+ if (table_cell->columns == 0) {
table_cell->columns = 1;
+ }
+
+ /* if rowspan is 0 it is expanded to
+ * the number of rows left in the row
+ * group
+ */
+ if (table_cell->rows == 0) {
+ table_cell->rows = group_rows_left;
+ }
- /* rowspan = 0 -> rowspan = rows_left */
- if (table_cell->rows == 0)
- table_cell->rows = rows_left;
+ /* limit rowspans within group */
+ if (table_cell->rows > group_rows_left) {
+ table_cell->rows = group_rows_left;
+ }
/* Record span information */
for (col = table_cell->start_column;
@@ -540,6 +560,8 @@ bool box_normalise_table_spans(struct box *table, struct span_info *spans,
rows_left--;
}
+
+ group_rows_left--;
}
return true;
@@ -555,6 +577,7 @@ bool box_normalise_table_row_group(struct box *row_group,
struct box *row;
css_computed_style *style;
nscss_select_ctx ctx;
+ unsigned int group_row_count = 0;
assert(row_group != 0);
assert(row_group->type == BOX_TABLE_ROW_GROUP);
@@ -569,6 +592,7 @@ bool box_normalise_table_row_group(struct box *row_group,
switch (child->type) {
case BOX_TABLE_ROW:
/* ok */
+ group_row_count++;
if (box_normalise_table_row(child, col_info,
c) == false)
return false;
@@ -628,6 +652,7 @@ bool box_normalise_table_row_group(struct box *row_group,
row_group->last = row;
row->parent = row_group;
+ group_row_count++;
if (box_normalise_table_row(row, col_info,
c) == false)
return false;
@@ -676,10 +701,14 @@ bool box_normalise_table_row_group(struct box *row_group,
row->parent = row_group;
row_group->children = row_group->last = row;
+ group_row_count = 1;
+
/* Keep table's row count in sync */
col_info->num_rows++;
}
+ row_group->rows = group_row_count;
+
#ifdef BOX_NORMALISE_DEBUG
LOG(("row_group %p done", row_group));
#endif
@@ -790,7 +819,7 @@ bool box_normalise_table_row(struct box *row,
}
if (calculate_table_row(col_info, cell->columns, cell->rows,
- &cell->start_column) == false)
+ &cell->start_column, cell) == false)
return false;
}
@@ -827,21 +856,27 @@ bool box_normalise_table_row(struct box *row,
* \param col_span Number of columns that current cell spans
* \param row_span Number of rows that current cell spans
* \param start_column Pointer to location to receive column index
+ * \param cell Box for current table cell
* \return true on success, false on memory exhaustion
*/
bool calculate_table_row(struct columns *col_info,
unsigned int col_span, unsigned int row_span,
- unsigned int *start_column)
+ unsigned int *start_column, struct box *cell)
{
unsigned int cell_start_col = col_info->current_column;
unsigned int cell_end_col;
unsigned int i;
struct span_info *spans;
+ struct box *rg = cell->parent->parent; /* Cell's row group */
/* Skip columns with cells spanning from above */
- while (col_info->spans[cell_start_col].row_span != 0)
+ /* TODO: Need to ignore cells spanning from above that belong to
+ * different row group. We don't have that info here. */
+ while (col_info->spans[cell_start_col].row_span != 0 &&
+ col_info->spans[cell_start_col].rg == rg) {
cell_start_col++;
+ }
/* Update current column with calculated start */
col_info->current_column = cell_start_col;
@@ -876,6 +911,7 @@ bool calculate_table_row(struct columns *col_info,
for (i = cell_start_col; i < cell_end_col; i++) {
col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
col_info->spans[i].auto_row = (row_span == 0);
+ col_info->spans[i].rg = rg;
}
/* Update current column with calculated end. */
diff --git a/render/html.c b/render/html.c
index bb24e58..95037a2 100644
--- a/render/html.c
+++ b/render/html.c
@@ -1791,8 +1791,8 @@ static void html__set_file_gadget_filename(struct content *c,
char *utf8_fn, *oldfile = NULL;
html_content *html = (html_content *)c;
struct box *file_box = gadget->box;
-
- ret = guit->utf8->local_to_utf8(fn,0, &utf8_fn);
+
+ ret = guit->utf8->local_to_utf8(fn, 0, &utf8_fn);
if (ret != NSERROR_OK) {
assert(ret != NSERROR_BAD_ENCODING);
LOG(("utf8 to local encoding conversion failed"));
@@ -1887,7 +1887,7 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
/* Handle the drop */
if (file_box) {
/* File dropped on file input */
- html__set_file_gadget_filename(c, box->gadget, file);
+ html__set_file_gadget_filename(c, file_box->gadget, file);
} else {
/* File dropped on text input */
diff --git a/render/html_interaction.c b/render/html_interaction.c
index a2baf2d..e030e57 100644
--- a/render/html_interaction.c
+++ b/render/html_interaction.c
@@ -1072,13 +1072,11 @@ bool html_keypress(struct content *c, uint32_t key)
* Handle search.
*
* \param c content of type HTML
- * \param gui_callbacks vtable for updating front end
- * \param gui_data front end private data
+ * \param context front end private data
* \param flags search flags
* \param string search string
*/
-void html_search(struct content *c,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+void html_search(struct content *c, void *context,
search_flags_t flags, const char *string)
{
html_content *html = (html_content *)c;
@@ -1103,8 +1101,7 @@ void html_search(struct content *c,
html->search = NULL;
}
- html->search = search_create_context(c, CONTENT_HTML,
- gui_callbacks, gui_data);
+ html->search = search_create_context(c, CONTENT_HTML, context);
if (html->search == NULL)
return;
@@ -1135,8 +1132,9 @@ void html_search_clear(struct content *c)
free(html->search_string);
html->search_string = NULL;
- if (html->search != NULL)
+ if (html->search != NULL) {
search_destroy_context(html->search);
+ }
html->search = NULL;
}
@@ -1263,6 +1261,7 @@ void html_set_focus(html_content *html, html_focus_type focus_type,
union content_msg_data msg_data;
int x_off = 0;
int y_off = 0;
+ struct rect cr;
bool textarea_lost_focus = html->focus_type == HTML_FOCUS_TEXTAREA &&
focus_type != HTML_FOCUS_TEXTAREA;
@@ -1293,7 +1292,6 @@ void html_set_focus(html_content *html, html_focus_type focus_type,
} else if (focus_type != HTML_FOCUS_SELF && hide_caret) {
msg_data.caret.type = CONTENT_CARET_HIDE;
} else {
- struct rect cr;
if (clip != NULL) {
cr = *clip;
cr.x0 += x_off;
diff --git a/render/html_internal.h b/render/html_internal.h
index e7768e3..05a085e 100644
--- a/render/html_internal.h
+++ b/render/html_internal.h
@@ -254,8 +254,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
bool html_keypress(struct content *c, uint32_t key);
void html_overflow_scroll_callback(void *client_data,
struct scrollbar_msg_data *scrollbar_data);
-void html_search(struct content *c,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+void html_search(struct content *c, void *context,
search_flags_t flags, const char *string);
void html_search_clear(struct content *c);
diff --git a/render/search.c b/render/search.c
index 46ec7d1..3bec9e1 100644
--- a/render/search.c
+++ b/render/search.c
@@ -21,27 +21,26 @@
/** \file
* Free text search (core)
*/
-#include "utils/config.h"
#include <ctype.h>
#include <string.h>
-
#include <dom/dom.h>
+#include "utils/config.h"
+#include "utils/log.h"
+#include "utils/messages.h"
+#include "utils/url.h"
+#include "utils/utils.h"
#include "content/content.h"
#include "content/hlcache.h"
#include "desktop/selection.h"
+#include "desktop/gui_factory.h"
+
#include "render/box.h"
#include "render/html.h"
#include "render/html_internal.h"
#include "render/search.h"
#include "render/textplain.h"
-#include "utils/config.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/url.h"
-#include "utils/utils.h"
-
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
@@ -62,7 +61,6 @@ struct list_entry {
};
struct search_context {
- struct gui_search_callbacks *gui;
void *gui_p;
struct content *c;
struct list_entry *found;
@@ -76,8 +74,7 @@ struct search_context {
/* Exported function documented in search.h */
struct search_context * search_create_context(struct content *c,
- content_type type, struct gui_search_callbacks *callbacks,
- void *gui_data)
+ content_type type, void *gui_data)
{
struct search_context *context;
struct list_entry *search_head;
@@ -114,7 +111,6 @@ struct search_context * search_create_context(struct content *c,
context->newsearch = true;
context->c = c;
context->is_html = (type == CONTENT_HTML) ? true : false;
- context->gui = callbacks;
context->gui_p = gui_data;
return context;
@@ -468,8 +464,7 @@ static void search_text(const char *string, int string_len,
context->string[string_len] = '\0';
}
- if ((context->gui != NULL) && (context->gui->hourglass != NULL))
- context->gui->hourglass(true, context->gui_p);
+ guit->search->hourglass(true, context->gui_p);
if (context->is_html == true) {
res = find_occurrences_html(string, string_len,
@@ -481,14 +476,10 @@ static void search_text(const char *string, int string_len,
if (!res) {
free_matches(context);
- if ((context->gui != NULL) &&
- (context->gui->hourglass != NULL))
- context->gui->hourglass(false, context->gui_p);
+ guit->search->hourglass(false, context->gui_p);
return;
}
- if ((context->gui != NULL) &&
- (context->gui->hourglass != NULL))
- context->gui->hourglass(false, context->gui_p);
+ guit->search->hourglass(false, context->gui_p);
context->prev_case_sens = case_sensitive;
@@ -507,20 +498,14 @@ static void search_text(const char *string, int string_len,
}
}
- if (context->gui == NULL)
- return;
- if (context->gui->status != NULL)
- context->gui->status((context->current != NULL),
- context->gui_p);
+ guit->search->status((context->current != NULL), context->gui_p);
search_show_all(showall, context);
- if (context->gui->back_state != NULL)
- context->gui->back_state((context->current != NULL) &&
+ guit->search->back_state((context->current != NULL) &&
(context->current->prev != NULL),
context->gui_p);
- if (context->gui->forward_state != NULL)
- context->gui->forward_state((context->current != NULL) &&
+ guit->search->forward_state((context->current != NULL) &&
(context->current->next != NULL),
context->gui_p);
@@ -557,13 +542,12 @@ void search_step(struct search_context *context, search_flags_t flags,
int string_len;
int i = 0;
- if ((context == NULL) || (context->gui == NULL)) {
+ if (context == NULL) {
warn_user("SearchError", 0);
return;
}
- if (context->gui->add_recent != NULL)
- context->gui->add_recent(string, context->gui_p);
+ guit->search->add_recent(string, context->gui_p);
string_len = strlen(string);
for (i = 0; i < string_len; i++)
@@ -572,12 +556,10 @@ void search_step(struct search_context *context, search_flags_t flags,
if (i >= string_len) {
union content_msg_data msg_data;
free_matches(context);
- if (context->gui->status != NULL)
- context->gui->status(true, context->gui_p);
- if (context->gui->back_state != NULL)
- context->gui->back_state(false, context->gui_p);
- if (context->gui->forward_state != NULL)
- context->gui->forward_state(false, context->gui_p);
+
+ guit->search->status(true, context->gui_p);
+ guit->search->back_state(false, context->gui_p);
+ guit->search->forward_state(false, context->gui_p);
msg_data.scroll.area = false;
msg_data.scroll.x0 = 0;
@@ -653,11 +635,14 @@ void search_destroy_context(struct search_context *context)
{
assert(context != NULL);
- if ((context->string != NULL) && (context->gui != NULL) &&
- (context->gui->add_recent != NULL)) {
- context->gui->add_recent(context->string, context->gui_p);
+ if (context->string != NULL) {
+ guit->search->add_recent(context->string, context->gui_p);
free(context->string);
}
+
+ guit->search->forward_state(true, context->gui_p);
+ guit->search->back_state(true, context->gui_p);
+
free_matches(context);
free(context);
}
diff --git a/render/search.h b/render/search.h
index 43c93b3..a8354e7 100644
--- a/render/search.h
+++ b/render/search.h
@@ -36,8 +36,7 @@ struct search_context;
* \return true for success
*/
struct search_context * search_create_context(struct content *c,
- content_type type, struct gui_search_callbacks *callbacks,
- void *gui_data);
+ content_type type, void *context);
/**
* Ends the search process, invalidating all state
diff --git a/render/table.c b/render/table.c
index 5eba544..22b5afd 100644
--- a/render/table.c
+++ b/render/table.c
@@ -337,7 +337,7 @@ void table_used_left_border_for_cell(struct box *cell)
if (cell->prev == NULL) {
struct box *row;
- /* Spanned from a previous row */
+ /* Spanned from a previous row in current row group */
for (row = cell->parent; row != NULL; row = row->prev) {
for (prev = row->children; prev != NULL;
prev = prev->next) {
@@ -954,12 +954,12 @@ bool table_cell_top_process_row(struct box *cell, struct box *row,
while (processed == false) {
for (c = row->children; c != NULL; c = c->next) {
/* Ignore cells to the left */
- if (c->start_column + c->columns <
+ if (c->start_column + c->columns - 1 <
cell->start_column)
continue;
/* Ignore cells to the right */
- if (c->start_column >= cell->start_column +
- cell->columns)
+ if (c->start_column > cell->start_column +
+ cell->columns - 1)
continue;
/* Flag that we've processed a cell */
diff --git a/render/textplain.c b/render/textplain.c
index b459efc..e08a045 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -112,8 +112,7 @@ static void textplain_mouse_track(struct content *c, struct browser_window *bw,
static void textplain_mouse_action(struct content *c, struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
static bool textplain_keypress(struct content *c, uint32_t key);
-static void textplain_search(struct content *c,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+static void textplain_search(struct content *c, void *gui_data,
search_flags_t flags, const char *string);
static void textplain_search_clear(struct content *c);
static void textplain_reformat(struct content *c, int width, int height);
@@ -760,8 +759,7 @@ bool textplain_keypress(struct content *c, uint32_t key)
* \param flags search flags
* \param string search string
*/
-void textplain_search(struct content *c,
- struct gui_search_callbacks *gui_callbacks, void *gui_data,
+void textplain_search(struct content *c, void *gui_data,
search_flags_t flags, const char *string)
{
textplain_content *text = (textplain_content *) c;
@@ -787,7 +785,7 @@ void textplain_search(struct content *c,
}
text->search = search_create_context(c, CONTENT_TEXTPLAIN,
- gui_callbacks, gui_data);
+ gui_data);
if (text->search == NULL)
return;
diff --git a/riscos/Makefile.defaults b/riscos/Makefile.defaults
index f48024f..8081e5c 100644
--- a/riscos/Makefile.defaults
+++ b/riscos/Makefile.defaults
@@ -2,30 +2,29 @@
# RISC OS-specific options
# ----------------------------------------------------------------------------
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO
- NETSURF_USE_NSSVG := YES
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO
+NETSURF_USE_NSSVG := YES
- # Enable NetSurf's support for displaying RISC OS Draw files
- # Valid options: YES, NO
- NETSURF_USE_DRAW := YES
+# Enable NetSurf's support for displaying RISC OS Draw files
+# Valid options: YES, NO
+NETSURF_USE_DRAW := YES
- # Enable NetSurf's support for displaying RISC OS Sprites
- # Valid options: YES, NO
- NETSURF_USE_SPRITE := YES
+# Enable NetSurf's support for displaying RISC OS Sprites
+# Valid options: YES, NO
+NETSURF_USE_SPRITE := YES
- # Enable NetSurf's use of AWRender for displaying ArtWorks files
- # Valid options: YES, NO
- NETSURF_USE_ARTWORKS := YES
+# Enable NetSurf's use of AWRender for displaying ArtWorks files
+# Valid options: YES, NO
+NETSURF_USE_ARTWORKS := YES
- # Enable NetSurf's support for the Acorn plugin protocol
- # Valid options: YES, NO
- NETSURF_USE_PLUGINS := NO
+# Enable NetSurf's support for the Acorn plugin protocol
+# Valid options: YES, NO
+NETSURF_USE_PLUGINS := NO
- # Enable NetSurf's use of pencil for Drawfile export
- # Valid options: YES, NO
- NETSURF_USE_DRAW_EXPORT := YES
-
- # Optimisation levels
- CFLAGS += -O2
+# Enable NetSurf's use of pencil for Drawfile export
+# Valid options: YES, NO
+NETSURF_USE_DRAW_EXPORT := YES
+# Optimisation levels
+CFLAGS += -O2
diff --git a/riscos/download.c b/riscos/download.c
index 804a664..6cba17e 100644
--- a/riscos/download.c
+++ b/riscos/download.c
@@ -379,6 +379,8 @@ static struct gui_download_window *gui_download_window_create(download_context *
snprintf(dw->path, RO_DOWNLOAD_MAX_PATH_LEN, "%s",
filename);
+ free(filename);
+
err = utf8_to_local_encoding(dw->path, 0, &local_path);
if (err != NSERROR_OK) {
/* badenc should never happen */
diff --git a/riscos/gui.c b/riscos/gui.c
index 59a0138..a4deca7 100644
--- a/riscos/gui.c
+++ b/riscos/gui.c
@@ -1594,6 +1594,7 @@ char *ro_gui_uri_file_parse(const char *file_name, char **uri_title)
/* URI */
if (!ro_gui_uri_file_parse_line(fp, line))
goto uri_syntax_error;
+
url = strdup(line);
if (!url) {
warn_user("NoMemory", 0);
@@ -1603,7 +1604,7 @@ char *ro_gui_uri_file_parse(const char *file_name, char **uri_title)
/* title */
if (!ro_gui_uri_file_parse_line(fp, line))
- goto uri_syntax_error;
+ goto uri_free;
if (uri_title && line[0] && ((line[0] != '*') || line[1])) {
*uri_title = strdup(line);
if (!*uri_title) /* non-fatal */
@@ -1613,6 +1614,9 @@ char *ro_gui_uri_file_parse(const char *file_name, char **uri_title)
return url;
+uri_free:
+ free(url);
+
uri_syntax_error:
fclose(fp);
warn_user("URIError", 0);
@@ -2094,6 +2098,7 @@ void ro_gui_view_source(hlcache_handle *c)
warn_user("NoMemory", 0);
return;
}
+
snprintf(full_name, 256, "%s/%s", TEMP_FILENAME_PREFIX,
filename);
full_name[255] = '\0';
@@ -2104,6 +2109,7 @@ void ro_gui_view_source(hlcache_handle *c)
return;
}
message.file_name[211] = '\0';
+
error = xosfile_save_stamped(message.file_name,
ro_content_filetype(c),
(byte *) source_data,
@@ -2387,6 +2393,7 @@ int main(int argc, char** argv)
.download = riscos_download_table,
.fetch = &riscos_fetch_table,
.utf8 = riscos_utf8_table,
+ .search = riscos_search_table,
};
/* Consult NetSurf$Logging environment variable to decide if logging
@@ -2432,7 +2439,7 @@ int main(int argc, char** argv)
}
/* common initialisation */
- ret = netsurf_init(path, &riscos_gui_table);
+ ret = netsurf_init(path, NULL, &riscos_gui_table);
if (ret != NSERROR_OK) {
die("NetSurf failed to initialise");
}
diff --git a/riscos/gui.h b/riscos/gui.h
index 3ea0c0b..548d030 100644
--- a/riscos/gui.h
+++ b/riscos/gui.h
@@ -203,6 +203,7 @@ nserror riscos_schedule(int t, void (*callback)(void *p), void *p);
/* in search.c */
void ro_gui_search_init(void);
void ro_gui_search_prepare(struct browser_window *g);
+struct gui_search_table *riscos_search_table;
/* in print.c */
void ro_gui_print_init(void);
diff --git a/riscos/mouse.c b/riscos/mouse.c
index a20965e..e934c1c 100644
--- a/riscos/mouse.c
+++ b/riscos/mouse.c
@@ -163,9 +163,11 @@ void ro_mouse_drag_end(wimp_dragged *dragged)
* Start tracking the mouse in a window, providing a function to be called on
* null polls and optionally one to be called when it leaves the window.
*
- * \param *drag_end Callback for when the pointer leaves the window, or
- * NULL for none.
- * \param *drag_track Callback for mouse tracking while the pointer remains
+ * \param *poll_end Callback for when the pointer leaves the window, or
+ * NULL for none. Claimants can receive *leaving==NULL if
+ * a new tracker is started before a PointerLeaving event
+ * is received.
+ * \param *poll_track Callback for mouse tracking while the pointer remains
* in the window, or NULL for none.
* \param *data Data to be passed to the callback functions, or NULL.
*/
@@ -175,12 +177,31 @@ void ro_mouse_track_start(void (*poll_end)(wimp_leaving *leaving, void *data),
void *data)
{
/* It should never be possible for the mouse to be in two windows
- * at the same time!
+ * at the same time! However, some third-party extensions to RISC OS
+ * appear to make this possible (MouseAxess being one), so in the
+ * event that there's still a claimant we tidy them up first and then
+ * log the fact in case there are any unexpected consequences.
+ *
+ * NB: The Poll End callback will get called with *leaving == NULL in
+ * this situation, as there's no PointerLeaving event to pass on.
*/
- assert(ro_mouse_poll_end_callback == NULL &&
- ro_mouse_poll_track_callback == NULL &&
- ro_mouse_poll_data == NULL);
+ if (ro_mouse_poll_end_callback != NULL ||
+ ro_mouse_poll_track_callback != NULL ||
+ ro_mouse_poll_data != NULL) {
+ if (ro_mouse_poll_end_callback != NULL &&
+ ro_mouse_ignore_leaving_event == false)
+ ro_mouse_poll_end_callback(NULL, ro_mouse_poll_data);
+
+ LOG(("Unexpected mouse track termination."));
+
+ ro_mouse_ignore_leaving_event = false;
+ ro_mouse_poll_end_callback = NULL;
+ ro_mouse_poll_track_callback = NULL;
+ ro_mouse_poll_data = NULL;
+ }
+
+ /* Now record details of the new claimant. */
ro_mouse_poll_end_callback = poll_end;
ro_mouse_poll_track_callback = poll_track;
diff --git a/riscos/mouse.h b/riscos/mouse.h
index bcb3b50..8a7405a 100644
--- a/riscos/mouse.h
+++ b/riscos/mouse.h
@@ -65,9 +65,11 @@ void ro_mouse_drag_end(wimp_dragged *dragged);
* Start tracking the mouse in a window, providing a function to be called on
* null polls and optionally one to be called when it leaves the window.
*
- * \param *drag_end Callback for when the pointer leaves the window, or
- * NULL for none.
- * \param *drag_track Callback for mouse tracking while the pointer remains
+ * \param *poll_end Callback for when the pointer leaves the window, or
+ * NULL for none. Claimants can receive *leaving==NULL if
+ * a new tracker is started before a PointerLeaving event
+ * is received.
+ * \param *poll_track Callback for mouse tracking while the pointer remains
* in the window, or NULL for none.
* \param *data Data to be passed to the callback functions, or NULL.
*/
diff --git a/riscos/search.c b/riscos/search.c
index 3d3b7ba..230edc2 100644
--- a/riscos/search.c
+++ b/riscos/search.c
@@ -76,14 +76,16 @@ static void ro_gui_search_set_status(bool found, void *p);
static void ro_gui_search_set_hourglass(bool active, void *p);
static void ro_gui_search_add_recent(const char *string, void *p);
-static struct gui_search_callbacks ro_gui_search_callbacks = {
- ro_gui_search_set_forward_state,
- ro_gui_search_set_back_state,
+static struct gui_search_table search_table = {
ro_gui_search_set_status,
ro_gui_search_set_hourglass,
- ro_gui_search_add_recent
+ ro_gui_search_add_recent,
+ ro_gui_search_set_forward_state,
+ ro_gui_search_set_back_state,
};
+struct gui_search_table *riscos_search_table = &search_table;
+
void ro_gui_search_init(void)
{
dialog_search = ro_gui_dialog_create("search");
@@ -122,8 +124,7 @@ bool ro_gui_search_next(wimp_w w)
search_data.search_insert = true;
search_flags_t flags = SEARCH_FLAG_FORWARDS |
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL, flags,
+ browser_window_search(search_data.search_window, NULL, flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
return false;
@@ -163,8 +164,7 @@ bool ro_gui_search_click(wimp_pointer *pointer)
search_data.search_insert = true;
flags = ~SEARCH_FLAG_FORWARDS &
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -172,8 +172,7 @@ bool ro_gui_search_click(wimp_pointer *pointer)
case ICON_SEARCH_CASE_SENSITIVE:
flags = SEARCH_FLAG_FORWARDS |
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -182,8 +181,7 @@ bool ro_gui_search_click(wimp_pointer *pointer)
flags = ro_gui_get_icon_selected_state(
pointer->w, pointer->i) ?
SEARCH_FLAG_SHOWALL : SEARCH_FLAG_NONE;
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -313,8 +311,7 @@ bool ro_gui_search_keypress(wimp_key *key)
case 1: {
flags = ro_gui_search_update_flags()
^ SEARCH_FLAG_SHOWALL;
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -327,8 +324,7 @@ bool ro_gui_search_keypress(wimp_key *key)
ICON_SEARCH_CASE_SENSITIVE, !state);
flags = SEARCH_FLAG_FORWARDS |
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -337,8 +333,7 @@ bool ro_gui_search_keypress(wimp_key *key)
search_data.search_insert = true;
flags = ~SEARCH_FLAG_FORWARDS &
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -347,8 +342,7 @@ bool ro_gui_search_keypress(wimp_key *key)
search_data.search_insert = true;
flags = SEARCH_FLAG_FORWARDS |
ro_gui_search_update_flags();
- browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ browser_window_search(search_data.search_window, NULL,
flags,
ro_gui_get_icon_string(dialog_search,
ICON_SEARCH_TEXT));
@@ -360,10 +354,6 @@ bool ro_gui_search_keypress(wimp_key *key)
* a new search */
browser_window_search_clear(
search_data.search_window);
- ro_gui_search_set_forward_state(true,
- search_data.search_window);
- ro_gui_search_set_back_state(true,
- search_data.search_window);
search_data.search_insert = true;
}
if (key->c == 8 || /* backspace */
@@ -376,7 +366,7 @@ bool ro_gui_search_keypress(wimp_key *key)
ro_gui_search_set_back_state(true,
search_data.search_window);
browser_window_search(search_data.search_window,
- &ro_gui_search_callbacks, NULL,
+ NULL,
flags,
ro_gui_get_icon_string(
dialog_search,
@@ -396,8 +386,6 @@ bool ro_gui_search_keypress(wimp_key *key)
void ro_gui_search_end(wimp_w w)
{
browser_window_search_clear(search_data.search_window);
- ro_gui_search_set_forward_state(true, search_data.search_window);
- ro_gui_search_set_back_state(true, search_data.search_window);
}
/**
diff --git a/riscos/toolbar.c b/riscos/toolbar.c
index 93c4438..d64db2d 100644
--- a/riscos/toolbar.c
+++ b/riscos/toolbar.c
@@ -1579,7 +1579,7 @@ bool ro_toolbar_set_button_order(struct toolbar *toolbar, char order[])
void ro_toolbar_set_button_shaded_state(struct toolbar *toolbar,
button_bar_action action, bool shaded)
{
- if (toolbar == NULL && toolbar->buttons == NULL)
+ if (toolbar == NULL || toolbar->buttons == NULL)
return;
ro_gui_button_bar_shade_button(toolbar->buttons, action, shaded);
@@ -1686,7 +1686,7 @@ void ro_toolbar_set_content_favicon(struct toolbar *toolbar,
void ro_toolbar_update_urlsuggest(struct toolbar *toolbar)
{
- if (toolbar != NULL && toolbar->url != NULL)
+ if (toolbar == NULL || toolbar->url == NULL)
return;
ro_gui_url_bar_update_urlsuggest(toolbar->url);
diff --git a/riscos/treeview.c b/riscos/treeview.c
index 4cf3d42..0c16626 100644
--- a/riscos/treeview.c
+++ b/riscos/treeview.c
@@ -435,14 +435,15 @@ void ro_treeview_redraw_loop(wimp_draw *redraw, ro_treeview *tv, osbool more)
};
while (more) {
- ro_plot_origin_x = redraw->box.x0 + tv->origin.x -
- redraw->xscroll;
- ro_plot_origin_y = redraw->box.y1 + tv->origin.y -
- redraw->yscroll;
if (tv != NULL && tv->tree != NULL) {
struct rect clip;
+ ro_plot_origin_x = redraw->box.x0 + tv->origin.x -
+ redraw->xscroll;
+ ro_plot_origin_y = redraw->box.y1 + tv->origin.y -
+ redraw->yscroll;
+
clip.x0 = (redraw->clip.x0 - ro_plot_origin_x) / 2;
clip.y0 = (ro_plot_origin_y - redraw->clip.y1) / 2;
diff --git a/riscos/ucstables.c b/riscos/ucstables.c
index cc6fe05..f9b6b36 100644
--- a/riscos/ucstables.c
+++ b/riscos/ucstables.c
@@ -481,7 +481,7 @@ nserror utf8_to_local_encoding(const char *string, size_t len, char **result)
/* get encoding name */
enc = (alphabet <= CONT_ENC_END ? localencodings[alphabet - 100]
: (alphabet == 120 ?
- localencodings[CONT_ENC_END + 1]
+ localencodings[CONT_ENC_END - 100 + 1]
: localencodings[0]));
/* create output buffer */
@@ -591,7 +591,7 @@ nserror utf8_from_local_encoding(const char *string, size_t len, char **result)
/* get encoding name */
enc = (alphabet <= CONT_ENC_END ? localencodings[alphabet - 100]
: (alphabet == 120 ?
- localencodings[CONT_ENC_END + 1]
+ localencodings[CONT_ENC_END - 100 + 1]
: localencodings[0]));
/* create output buffer (oversized) */
diff --git a/test/Makefile b/test/Makefile
index 825b582..acf9d4e 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -2,7 +2,6 @@ CFLAGS := -std=c99 -g -O0 -D_BSD_SOURCE -D_POSIX_C_SOURCE -I.. \
$(shell pkg-config --cflags libcurl)
LDFLAGS := $(shell pkg-config --libs libcurl) -lz
-
llcache_CFLAGS := $(shell pkg-config --cflags libparserutils libwapcaplet libdom) -O2
llcache_LDFLAGS := $(shell pkg-config --libs libparserutils libwapcaplet libdom)
@@ -15,7 +14,6 @@ llcache_SRCS := content/fetch.c content/fetchers/curl.c \
utils/log.c utils/nsurl.c utils/messages.c utils/url.c \
utils/useragent.c utils/utils.c test/llcache.c
-
urldbtest_SRCS := content/urldb.c utils/url.c utils/utils.c utils/log.c \
desktop/options.c utils/messages.c utils/hashtable.c \
utils/filename.c utils/nsurl.c utils/corestrings.c \
@@ -24,22 +22,16 @@ urldbtest_SRCS := content/urldb.c utils/url.c utils/utils.c utils/log.c \
urldbtest_CFLAGS := $(shell pkg-config --cflags libwapcaplet libdom) -O2
urldbtest_LDFLAGS := $(shell pkg-config --libs libwapcaplet libdom)
-
nsurl_SRCS := utils/corestrings.c utils/log.c utils/nsurl.c test/nsurl.c
nsurl_CFLAGS := $(shell pkg-config --cflags libwapcaplet libdom)
nsurl_LDFLAGS := $(shell pkg-config --libs libwapcaplet libdom)
-
nsoption_SRCS := utils/log.c utils/nsoption.c test/nsoption.c
nsoption_CFLAGS := -Dnsgtk
-sha1_SRCS := utils/sha1.c utils/log.c test/sha1.c
-sha1_CFLAGS :=
-sha1_LDFLAGS :=
-
.PHONY: all
-all: llcache urldbtest nsurl nsoption sha1
+all: llcache urldbtest nsurl nsoption
llcache: $(addprefix ../,$(llcache_SRCS))
$(CC) $(CFLAGS) $(llcache_CFLAGS) $^ -o $@ $(LDFLAGS) $(llcache_LDFLAGS)
@@ -53,9 +45,6 @@ nsurl: $(addprefix ../,$(nsurl_SRCS))
nsoption: $(addprefix ../,$(nsoption_SRCS))
$(CC) $(CFLAGS) $(nsoption_CFLAGS) $^ -o $@ $(LDFLAGS) $(nsoption_LDFLAGS)
-sha1: $(addprefix ../,$(sha1_SRCS))
- $(CC) $(CFLAGS) $(sha1_CFLAGS) $^ -o $@ $(LDFLAGS) $(sha1_LDFLAGS)
-
.PHONY: clean
clean:
diff --git a/test/sha1.c b/test/sha1.c
deleted file mode 100644
index be31836..0000000
--- a/test/sha1.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <assert.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-
-#include "utils/log.h"
-#include "utils/sha1.h"
-
-
-struct {
- const char *text;
- const uint8_t hash[NSSHA1_DIGEST_SIZE];
-} checks[] = {
- {
- "The quick brown fox jumps over the lazy dog",
- { 0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84,
- 0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12 }
- },
- {
- "The quick brown fox jumps over the lazy cog",
- { 0xde, 0x9f, 0x2c, 0x7f, 0xd2, 0x5e, 0x1b, 0x3a, 0xfa, 0xd3,
- 0xe8, 0x5a, 0x0b, 0xd1, 0x7d, 0x9b, 0x10, 0x0d, 0xb4, 0xb3 }
- },
- {
- "",
- { 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
- 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }
- },
- {
- "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789",
- { 0x29, 0xb0, 0xe7, 0x87, 0x82, 0x71, 0x64, 0x5f, 0xff, 0xb7,
- 0xee, 0xc7, 0xdb, 0x4a, 0x74, 0x73, 0xa1, 0xc0, 0x0b, 0xc1 }
- },
- { NULL, {0} },
-};
-
-int main(int argc, char **argv)
-{
- uint8_t res[NSSHA1_DIGEST_SIZE];
- int chk_loop = 0;
-
- verbose_log = true;
-
- while (checks[chk_loop].text != NULL) {
-
- NSSHA1(checks[chk_loop].text, strlen(checks[chk_loop].text), res);
- if (memcmp(res, &checks[chk_loop].hash, NSSHA1_DIGEST_SIZE) == 0) {
- LOG(("Test %d: PASS", chk_loop));
- } else {
- LOG(("Test %d: FAIL", chk_loop));
- }
- chk_loop++;
- }
-}
diff --git a/utils/Makefile b/utils/Makefile
index 48bba98..aef5799 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -2,6 +2,6 @@
S_UTILS := base64.c corestrings.c filename.c filepath.c hashtable.c \
libdom.c locale.c log.c messages.c nsurl.c talloc.c url.c \
- utf8.c utils.c useragent.c bloom.c nsoption.c sha1.c
+ utf8.c utils.c useragent.c bloom.c nsoption.c
S_UTILS := $(addprefix utils/,$(S_UTILS))
diff --git a/utils/errors.h b/utils/errors.h
index c38e4b9..4c02adb 100644
--- a/utils/errors.h
+++ b/utils/errors.h
@@ -37,6 +37,8 @@ typedef enum {
NSERROR_NOT_FOUND, /**< Requested item not found */
+ NSERROR_NOT_DIRECTORY, /**< Missing directory */
+
NSERROR_SAVE_FAILED, /**< Failed to save data */
NSERROR_CLONE_FAILED, /**< Failed to clone handle */
@@ -69,7 +71,9 @@ typedef enum {
NSERROR_BAD_CONTENT, /**< Bad Content */
- NSERROR_FRAME_DEPTH /**< Exceeded frame depth */
+ NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */
+
+ NSERROR_PERMISSION /**< Permission error */
} nserror;
#endif
diff --git a/utils/filename.c b/utils/filename.c
index 5306418..a89a1ab 100644
--- a/utils/filename.c
+++ b/utils/filename.c
@@ -183,10 +183,12 @@ bool filename_initialise(void)
for (start = directory; *start != '\0'; start++) {
if (*start == '/') {
*start = '\0';
+ LOG(("Creating \"%s\"", directory));
ret = nsmkdir(directory, S_IRWXU);
- if (ret != 0) {
+ if (ret != 0 && errno != EEXIST) {
+ LOG(("Failed to create directory \"%s\"",
+ directory));
free(directory);
-
return false;
}
diff --git a/utils/filepath.c b/utils/filepath.c
index d088777..68e8d7e 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <string.h>
+#include "utils/utils.h"
#include "utils/config.h"
#include "utils/filepath.h"
@@ -202,7 +203,13 @@ filepath_generate(char * const *pathv, const char * const *langv)
return respath;
}
-/* expand ${} in a string into environment variables */
+/**
+ * expand ${} in a string into environment variables.
+ *
+ * @param path The pathname to expand.
+ * @param pathlen The length of the path element.
+ * @return A string with the expanded path or NULL on empty expansion or error.
+ */
static char *
expand_path(const char *path, int pathlen)
{
@@ -317,3 +324,80 @@ void filepath_free_strvec(char **pathv)
}
free(pathv);
}
+
+/* exported interface documented in filepath.h */
+char *filepath_append(const char *path, const char *leaf)
+{
+ int dirname_len;
+ char *dirname;
+
+ if ((path == NULL) || (leaf == NULL)) {
+ return NULL;
+ }
+
+ dirname_len = strlen(path) + strlen(leaf) + 2;
+ dirname = malloc(dirname_len);
+ if (dirname != NULL) {
+ snprintf(dirname, dirname_len, "%s/%s", path, leaf);
+ }
+
+ return dirname;
+}
+
+/* exported interface documented in filepath.h */
+nserror filepath_mkdir_all(const char *fname)
+{
+ char *dname;
+ char *sep;
+ struct stat sb;
+
+ dname = strdup(fname);
+
+ sep = strrchr(dname, '/');
+ if (sep == NULL) {
+ /* no directory separator path is just filename so its ok */
+ free(dname);
+ return NSERROR_OK;
+ }
+
+ *sep = 0; /* null terminate directory path */
+
+ if (stat(dname, &sb) == 0) {
+ free(dname);
+ if (S_ISDIR(sb.st_mode)) {
+ /* path to file exists and is a directory */
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_DIRECTORY;
+ }
+ *sep = '/'; /* restore separator */
+
+ sep = dname;
+ while (*sep == '/') {
+ sep++;
+ }
+ while ((sep = strchr(sep, '/')) != NULL) {
+ *sep = 0;
+ if (stat(dname, &sb) != 0) {
+ if (nsmkdir(dname, S_IRWXU) != 0) {
+ /* could not create path element */
+ free(dname);
+ return NSERROR_NOT_FOUND;
+ }
+ } else {
+ if (! S_ISDIR(sb.st_mode)) {
+ /* path element not a directory */
+ free(dname);
+ return NSERROR_NOT_DIRECTORY;
+ }
+ }
+ *sep = '/'; /* restore separator */
+ /* skip directory separators */
+ while (*sep == '/') {
+ sep++;
+ }
+ }
+
+ free(dname);
+ return NSERROR_OK;
+}
diff --git a/utils/filepath.h b/utils/filepath.h
index ff3ebe9..56e9eff 100644
--- a/utils/filepath.h
+++ b/utils/filepath.h
@@ -16,9 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * \file utils/filepath.h
- * \brief Utility routines to obtain paths to file resources.
+/**
+ * @file utils/filepath.h
+ * @brief Utility routines to obtain paths to file resources.
*/
#ifndef _NETSURF_UTILS_FILEPATH_H_
@@ -26,8 +26,10 @@
#include <stdarg.h>
+#include "utils/errors.h"
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* If the file described by the format exists and is accessible the
* normalised path is placed in str and a pointer to str returned
@@ -43,14 +45,16 @@
char *filepath_vsfindfile(char *str, const char *format, va_list ap);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to vsfindfile but takes variadic (printf like) parameters
*/
char *filepath_sfindfile(char *str, const char *format, ...);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to sfindfile but allocates its own storage for the
* returned string. The caller must free this sorage.
@@ -58,7 +62,8 @@ char *filepath_sfindfile(char *str, const char *format, ...);
char *filepath_findfile(const char *format, ...);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Iterates through a vector of resource paths and returns the
* normalised file name of the first acessible file or NULL if no file
@@ -72,7 +77,8 @@ char *filepath_findfile(const char *format, ...);
char *filepath_sfind(char **respathv, char *filepath, const char *filename);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Similar to filepath_sfind except it allocates its own storage for
* the returned string. The caller must free this sorage.
@@ -80,7 +86,8 @@ char *filepath_sfind(char **respathv, char *filepath, const char *filename);
char *filepath_find(char **respathv, const char *filename);
-/** Searches an array of resource paths for a file optionally forcing a default.
+/**
+ * Searches an array of resource paths for a file optionally forcing a default.
*
* Similar to filepath_sfind except if no resource is found the default
* is used as an additional path element to search, if that still
@@ -91,7 +98,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
const char *def);
-/** Merge two string vectors into a resource search path vector.
+/**
+ * Merge two string vectors into a resource search path vector.
*
* @param pathv A string vector containing path elemets to scan.
* @param langv A string vector containing language names to enumerate.
@@ -101,7 +109,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
char **filepath_generate(char * const *pathv, const char * const *langv);
-/** Convert a colon separated list of path elements into a string vector.
+/**
+ * Convert a colon separated list of path elements into a string vector.
*
* @param path A colon separated path.
* @return A pointer to a NULL terminated string vector of valid
@@ -110,10 +119,32 @@ char **filepath_generate(char * const *pathv, const char * const *langv);
char **filepath_path_to_strvec(const char *path);
-/** Free a string vector
+/**
+ * Free a string vector.
*
* Free a string vector allocated by filepath_path_to_strvec
*/
void filepath_free_strvec(char **pathv);
+
+/**
+ * generate a new filename from a path and leaf.
+ *
+ * @param path The base path.
+ * @param leaf The leaf to add.
+ * @return The combined path in a new string must be freed by caller
+ * or NULL on failiure to allocte memory.
+ */
+char *filepath_append(const char *path, const char *leaf);
+
+
+/**
+ * Ensure that all directory elements needed to store a filename exist.
+ *
+ * @param fname The filename to ensure the path to exists.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+nserror filepath_mkdir_all(const char *fname);
+
+
#endif /* _NETSURF_UTILS_FILEPATH_H_ */
diff --git a/utils/libdom.c b/utils/libdom.c
index a1465af..245c9b2 100644
--- a/utils/libdom.c
+++ b/utils/libdom.c
@@ -50,58 +50,42 @@ bool libdom_treewalk(dom_node *root,
break;
}
- if (next != NULL) { /* 1. children */
+ if (next != NULL) {
+ /* 1. Got children */
dom_node_unref(node);
node = next;
} else {
- exc = dom_node_get_next_sibling(node, &next);
- if (exc != DOM_NO_ERR) {
- dom_node_unref(node);
- break;
- }
-
- if (next != NULL) { /* 2. siblings */
- dom_node_unref(node);
- node = next;
- } else { /* 3. ancestor siblings */
- while (node != NULL) {
- exc = dom_node_get_next_sibling(node,
- &next);
- if (exc != DOM_NO_ERR) {
- dom_node_unref(node);
- node = NULL;
- break;
- }
-
- if (next != NULL) {
- dom_node_unref(next);
- break;
- }
-
- exc = dom_node_get_parent_node(node,
- &next);
- if (exc != DOM_NO_ERR) {
- dom_node_unref(node);
- node = NULL;
- break;
- }
-
+ /* No children; siblings & ancestor's siblings */
+ while (node != NULL) {
+ exc = dom_node_get_next_sibling(node, &next);
+ if (exc != DOM_NO_ERR) {
dom_node_unref(node);
- node = next;
+ node = NULL;
+ break;
}
- if (node == NULL)
+ if (next != NULL) {
+ /* 2. Got sibling */
break;
+ }
- exc = dom_node_get_next_sibling(node, &next);
+ exc = dom_node_get_parent_node(node, &next);
if (exc != DOM_NO_ERR) {
dom_node_unref(node);
+ node = NULL;
break;
}
+ /* 3. Try parent */
dom_node_unref(node);
node = next;
}
+
+ if (node == NULL)
+ break;
+
+ dom_node_unref(node);
+ node = next;
}
assert(node != NULL);
diff --git a/utils/sha1.c b/utils/sha1.c
deleted file mode 100644
index e59c8ed..0000000
--- a/utils/sha1.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- SHA-1 in C
- By Steve Reid <sreid(a)sea-to-sky.net>
- 100% Public Domain
-
- -----------------
- Modified 7/98
- By James H. Brown <jbrown(a)burgoyne.com>
- Still 100% Public Domain
-
- Corrected a problem which generated improper hash values on 16 bit machines
- Routine SHA1Update changed from
- void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
- len)
- to
- void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
- long len)
-
- The 'len' parameter was declared an int which works fine on 32 bit machines.
- However, on 16 bit machines an int is too small for the shifts being done
- against
- it. This caused the hash function to generate incorrect values if len was
- greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
-
- Since the file IO in main() reads 16K at a time, any file 8K or larger would
- be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
- "a"s).
-
- I also changed the declaration of variables i & j in SHA1Update to
- unsigned long from unsigned int for the same reason.
-
- These changes should make no difference to any 32 bit implementations since
- an
- int and a long are the same size in those environments.
-
- --
- I also corrected a few compiler warnings generated by Borland C.
- 1. Added #include <process.h> for exit() prototype
- 2. Removed unused variable 'j' in SHA1Final
- 3. Changed exit(0) to return(0) at end of main.
-
- ALL changes I made can be located by searching for comments containing 'JHB'
- -----------------
- Modified 8/98
- By Steve Reid <sreid(a)sea-to-sky.net>
- Still 100% public domain
-
- 1- Removed #include <process.h> and used return() instead of exit()
- 2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
- 3- Changed email address from steve(a)edmweb.com to sreid(a)sea-to-sky.net
-
- -----------------
- Modified 4/01
- By Saul Kravitz <Saul.Kravitz(a)celera.com>
- Still 100% PD
- Modified to run on Compaq Alpha hardware.
-
- -----------------
- Modified 07/2002
- By Ralph Giles <giles(a)ghostscript.com>
- Still 100% public domain
- modified for use with stdint types, autoconf
- code cleanup, removed attribution comments
- switched SHA1Final() argument order for consistency
- use SHA1_ prefix for public api
- move public api to sha1.h
-*/
-
-/** \file
- * steve reid's public domain SHA-1 implementation.
- *
- * Modified by Vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This is a sligly modified version of this public domain
- * implementation changes were made to:
- * - introduce suitable prefixes to avoid namespace conflicts.
- * - make the context structure self contained.
- * - make the function signatures more suitable for this use case
- */
-
-
-/* see https://en.wikipedia.org/wiki/SHA-1 */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include "utils/errors.h"
-#include "utils/sha1.h"
-
-struct nssha1_ctx {
- uint32_t state[5];
- uint32_t count[2];
- uint8_t buffer[64];
-} ;
-
-#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
-
-/* blk0() and blk() perform the initial expand. */
-/* I got the idea of expanding during the round function from SSLeay */
-/* FIXME: can we do this in an endian-proof way? */
-#ifdef WORDS_BIGENDIAN
-#define blk0(i) block->l[i]
-#else
-#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
- |(rol(block->l[i],8)&0x00FF00FF))
-#endif
-#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
- ^block->l[(i+2)&15]^block->l[i&15],1))
-
-/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
-#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
-#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
-#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
-#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
-
-
-
-/* Hash a single 512-bit block. This is the core of the algorithm. */
-static void SHA1_Transform(uint32_t state[5], const uint8_t buffer[64])
-{
- uint32_t a, b, c, d, e;
-
- typedef union {
- uint8_t c[64];
- uint32_t l[16];
- } CHAR64LONG16;
- CHAR64LONG16* block;
-
- static uint8_t workspace[64];
- block = (CHAR64LONG16*)workspace;
- memcpy(block, buffer, 64);
-
- /* Copy context->state[] to working vars */
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
-
- /* 4 rounds of 20 operations each. Loop unrolled. */
- R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
- R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
- R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
- R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
- R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
- R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
- R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
- R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
- R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
- R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
- R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
- R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
- R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
- R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
- R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
- R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
- R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
- R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
- R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
- R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
-
- /* Add the working vars back into context.state[] */
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
-
- /* Wipe variables */
- a = b = c = d = e = 0;
-}
-
-
-/* SHA1Init - Initialize new context */
-nserror
-NSSHA1_Init(struct nssha1_ctx **ret_ctx)
-{
- struct nssha1_ctx *context;
-
- context = calloc(1, sizeof(struct nssha1_ctx));
- if (context == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
-
- *ret_ctx = context;
-
- return NSERROR_OK;
-}
-
-
-/* Run your data through this. */
-nserror
-NSSHA1_Update(struct nssha1_ctx *context, const uint8_t *data, const size_t len)
-{
- size_t i, j;
-
- j = (context->count[0] >> 3) & 63;
- if ((context->count[0] += len << 3) < (len << 3)) {
- context->count[1]++;
- }
- context->count[1] += (len >> 29);
- if ((j + len) > 63) {
- memcpy(&context->buffer[j], data, (i = 64-j));
- SHA1_Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64) {
- SHA1_Transform(context->state, data + i);
- }
- j = 0;
- } else {
- i = 0;
- }
- memcpy(&context->buffer[j], &data[i], len - i);
-
- return NSERROR_OK;
-}
-
-
-/* Add padding and return the message digest. */
-nserror
-NSSHA1_Final(struct nssha1_ctx *context, uint8_t digest[NSSHA1_DIGEST_SIZE])
-{
- uint32_t i;
- uint8_t finalcount[8];
-
- for (i = 0; i < 8; i++) {
- finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */
- }
- NSSHA1_Update(context, (uint8_t *)"\200", 1);
- while ((context->count[0] & 504) != 448) {
- NSSHA1_Update(context, (uint8_t *)"\0", 1);
- }
- NSSHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */
- for (i = 0; i < NSSHA1_DIGEST_SIZE; i++) {
- digest[i] = (uint8_t)
- ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
- }
-
- free(context);
-
- return NSERROR_OK;
-}
-
-nserror
-NSSHA1(const uint8_t *data, const size_t len, uint8_t digest[NSSHA1_DIGEST_SIZE])
-{
- struct nssha1_ctx *context;
- nserror error;
-
- error = NSSHA1_Init(&context);
- if (error != NSERROR_OK)
- return error;
- NSSHA1_Update(context, data, len);
- NSSHA1_Final(context, digest);
-
- return NSERROR_OK;
-}
diff --git a/utils/sha1.h b/utils/sha1.h
deleted file mode 100644
index e9f930c..0000000
--- a/utils/sha1.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2014 vincent Sanders <vince(a)netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * interface for steve reid's public domain SHA-1 implementation.
- *
- * The exposed API makes only minimal changes to the public domain
- * implementation, mainly adding a prefix so this implementation is
- * not confused with any other similarly named version that might be
- * linked.
- */
-
-#ifndef _NETSURF_UTILS_SHA1_H_
-#define _NETSURF_UTILS_SHA1_H_
-
-struct nssha1_ctx;
-
-#define NSSHA1_DIGEST_SIZE 20
-
-/**
- * Initialise a SHA1 context ready to take updates
- *
- * The context is allocated by this routine and destroyed by the finaliser.
- *
- * @param context receives an initialised SHA1 context.
- * @return NSERROR_OK and \a context updated on sucess or
- * NSERROR_NOMEM on memory exhaustion.
- */
-nserror NSSHA1_Init(struct nssha1_ctx **context);
-
-/**
- * Update an SHA1 context with additional data.
- *
- * @param context The context created by NSSHA1_Init
- * @param data The data to hash.
- * @param len The length of data to hash.
- * @return NSERROR_OK
- */
-nserror NSSHA1_Update(struct nssha1_ctx *context, const uint8_t *data, const size_t len);
-
-/**
- * Finalise a SHA1 hash.
- *
- * Frees the context.
- *
- * @param context The context created by NSSHA1_Init
- * @param digest a buffer to store the results in.
- * @return NSERROR_OK
- */
-nserror NSSHA1_Final(struct nssha1_ctx *context, uint8_t digest[NSSHA1_DIGEST_SIZE]);
-
-/**
- * Generate SHA1 of some data
- */
-nserror NSSHA1(const uint8_t *data, const size_t len, uint8_t digest[NSSHA1_DIGEST_SIZE]);
-
-#endif
diff --git a/utils/utils.h b/utils/utils.h
index ed19cb3..db26ed1 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -60,10 +60,13 @@ struct dirent;
#define PRId64 "lld"
#endif
+/* Windows does not have POSIX formating codes or mkdir so work around that */
#if defined(_WIN32)
#define SSIZET_FMT "Iu"
+#define nsmkdir(dir, mode) mkdir((dir))
#else
#define SSIZET_FMT "zd"
+#define nsmkdir(dir, mode) mkdir((dir), (mode))
#endif
#if defined(__GNUC__) && (__GNUC__ < 3)
@@ -105,12 +108,6 @@ typedef struct
void (*cancel)(query_id, enum query_response res, void *pw);
} query_callback;
-#ifdef HAVE_MKDIR
-#define nsmkdir(dir, mode) mkdir((dir), (mode))
-#else
-#define nsmkdir(dir, mode) mkdir((dir))
-#endif
-
#ifndef timeradd
#define timeradd(a, aa, result) \
do { \
diff --git a/windows/Makefile.defaults b/windows/Makefile.defaults
index 10c9abb..85472ba 100644
--- a/windows/Makefile.defaults
+++ b/windows/Makefile.defaults
@@ -2,20 +2,20 @@
# windows-specific options
# ----------------------------------------------------------------------------
- # Enable NetSurf's use of librosprite for displaying RISC OS Sprites
- # Valid options: YES, NO, AUTO
- NETSURF_USE_ROSPRITE := NO
+# Enable NetSurf's use of librosprite for displaying RISC OS Sprites
+# Valid options: YES, NO, AUTO
+NETSURF_USE_ROSPRITE := NO
- # Enable NetSurf's use of libsvgtiny for displaying SVGs
- # Valid options: YES, NO
- NETSURF_USE_NSSVG := NO
+# Enable NetSurf's use of libsvgtiny for displaying SVGs
+# Valid options: YES, NO
+NETSURF_USE_NSSVG := NO
- # Force using glibc internal iconv implementation instead of external libiconv
- # Valid options: YES, NO
- NETSURF_USE_LIBICONV_PLUG := NO
+# Force using glibc internal iconv implementation instead of external libiconv
+# Valid options: YES, NO
+NETSURF_USE_LIBICONV_PLUG := NO
- # no pdf support
- NETSURF_USE_HARU_PDF := NO
+# no pdf support
+NETSURF_USE_HARU_PDF := NO
- # Optimisation levels
- CFLAGS += -O2
+# Optimisation levels
+CFLAGS += -O2
diff --git a/windows/main.c b/windows/main.c
index 19cd44a..b7066a6 100644
--- a/windows/main.c
+++ b/windows/main.c
@@ -160,7 +160,7 @@ WinMain(HINSTANCE hInstance, HINSTANCE hLastInstance, LPSTR lpcli, int ncmd)
/* common initialisation */
messages = filepath_find(respaths, "messages");
- ret = netsurf_init(messages, &win32_gui_table);
+ ret = netsurf_init(messages, NULL, &win32_gui_table);
free(messages);
if (ret != NSERROR_OK) {
free(options_file_location);
--
NetSurf Browser
9 years, 1 month
netsurf: branch master updated. release/3.1-5-g1822b7c
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/1822b7c1633671cd41e60...
...commit http://git.netsurf-browser.org/netsurf.git/commit/1822b7c1633671cd41e60a0...
...tree http://git.netsurf-browser.org/netsurf.git/tree/1822b7c1633671cd41e60a04f...
The branch, master has been updated
via 1822b7c1633671cd41e60a04f7eeaf86dcec4141 (commit)
from 5dd6fa6f228f022d3e2e3e1ee7a21b3d4f17724e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=1822b7c1633671cd41e...
commit 1822b7c1633671cd41e60a04f7eeaf86dcec4141
Author: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Commit: Chris Young <chris(a)unsatisfactorysoftware.co.uk>
Update some version numbers for 3.2-dev.
The minor version of 3 here is correct, it is only used internally to conform to AmigaOS versioning conventions.
diff --git a/amiga/dist/netsurf.readme b/amiga/dist/netsurf.readme
index bd37b2e..a16400a 100755
--- a/amiga/dist/netsurf.readme
+++ b/amiga/dist/netsurf.readme
@@ -2,23 +2,21 @@ Short: Fast CSS capable web browser
Uploader: chris(a)unsatisfactorysoftware.co.uk (Chris Young)
Author: NetSurf contributors (OS4 port by Chris Young)
Type: comm/www
-Version: 3.1 development
+Version: 3.2 development
Architecture: ppc-amigaos >= 4.0.0
-This is a test build of NetSurf 3.1 for AmigaOS 4.
-It is beta software, which means it is unstable and missing
-features - use at your own risk!
-
-This is provided for testing purposes only. For the latest
-stable version, visit http://www.netsurf-browser.org
+This is a test build of NetSurf 3.2 for AmigaOS 4.
+For the latest version, visit http://www.netsurf-browser.org
Please report bugs to chris(a)unsatisfactorysoftware.co.uk,
on the Amigans.net forums or on the NetSurf mailing list.
-See http://www.netsurf-browser.org for more information about NetSurf.
+See http://www.netsurf-browser.org for more information about
+NetSurf.
This software is licensed under the GPL, and the sources are
available from http://www.netsurf-browser.org. A copy can
also be obtained directly from the maintainer of this port,
chris(a)unsatisfactorysoftware.co.uk, in the event that the
website is unavailable.
+
diff --git a/amiga/version.c b/amiga/version.c
index dbddbb0..167ae07 100644
--- a/amiga/version.c
+++ b/amiga/version.c
@@ -27,7 +27,7 @@
#if defined(CI_BUILD)
#define NETSURF_VERSION_MINOR CI_BUILD
#else
-#define NETSURF_VERSION_MINOR "2"
+#define NETSURF_VERSION_MINOR "3"
#endif
-----------------------------------------------------------------------
Summary of changes:
amiga/dist/netsurf.readme | 14 ++++++--------
amiga/version.c | 2 +-
2 files changed, 7 insertions(+), 9 deletions(-)
diff --git a/amiga/dist/netsurf.readme b/amiga/dist/netsurf.readme
index bd37b2e..a16400a 100755
--- a/amiga/dist/netsurf.readme
+++ b/amiga/dist/netsurf.readme
@@ -2,23 +2,21 @@ Short: Fast CSS capable web browser
Uploader: chris(a)unsatisfactorysoftware.co.uk (Chris Young)
Author: NetSurf contributors (OS4 port by Chris Young)
Type: comm/www
-Version: 3.1 development
+Version: 3.2 development
Architecture: ppc-amigaos >= 4.0.0
-This is a test build of NetSurf 3.1 for AmigaOS 4.
-It is beta software, which means it is unstable and missing
-features - use at your own risk!
-
-This is provided for testing purposes only. For the latest
-stable version, visit http://www.netsurf-browser.org
+This is a test build of NetSurf 3.2 for AmigaOS 4.
+For the latest version, visit http://www.netsurf-browser.org
Please report bugs to chris(a)unsatisfactorysoftware.co.uk,
on the Amigans.net forums or on the NetSurf mailing list.
-See http://www.netsurf-browser.org for more information about NetSurf.
+See http://www.netsurf-browser.org for more information about
+NetSurf.
This software is licensed under the GPL, and the sources are
available from http://www.netsurf-browser.org. A copy can
also be obtained directly from the maintainer of this port,
chris(a)unsatisfactorysoftware.co.uk, in the event that the
website is unavailable.
+
diff --git a/amiga/version.c b/amiga/version.c
index dbddbb0..167ae07 100644
--- a/amiga/version.c
+++ b/amiga/version.c
@@ -27,7 +27,7 @@
#if defined(CI_BUILD)
#define NETSURF_VERSION_MINOR CI_BUILD
#else
-#define NETSURF_VERSION_MINOR "2"
+#define NETSURF_VERSION_MINOR "3"
#endif
--
NetSurf Browser
9 years, 1 month
netsurf: branch master updated. release/3.1-4-g5dd6fa6
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/5dd6fa6f228f022d3e2e3...
...commit http://git.netsurf-browser.org/netsurf.git/commit/5dd6fa6f228f022d3e2e3e1...
...tree http://git.netsurf-browser.org/netsurf.git/tree/5dd6fa6f228f022d3e2e3e1ee...
The branch, master has been updated
via 5dd6fa6f228f022d3e2e3e1ee7a21b3d4f17724e (commit)
from 1fd565cba706d6a9e809d14f79ceb92633b62ead (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=5dd6fa6f228f022d3e2...
commit 5dd6fa6f228f022d3e2e3e1ee7a21b3d4f17724e
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
use compatability macro for mkdir
diff --git a/utils/filepath.c b/utils/filepath.c
index d82dfc6..68e8d7e 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <string.h>
+#include "utils/utils.h"
#include "utils/config.h"
#include "utils/filepath.h"
@@ -378,7 +379,7 @@ nserror filepath_mkdir_all(const char *fname)
while ((sep = strchr(sep, '/')) != NULL) {
*sep = 0;
if (stat(dname, &sb) != 0) {
- if (mkdir(dname, S_IRWXU) != 0) {
+ if (nsmkdir(dname, S_IRWXU) != 0) {
/* could not create path element */
free(dname);
return NSERROR_NOT_FOUND;
diff --git a/utils/utils.h b/utils/utils.h
index ed19cb3..db26ed1 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -60,10 +60,13 @@ struct dirent;
#define PRId64 "lld"
#endif
+/* Windows does not have POSIX formating codes or mkdir so work around that */
#if defined(_WIN32)
#define SSIZET_FMT "Iu"
+#define nsmkdir(dir, mode) mkdir((dir))
#else
#define SSIZET_FMT "zd"
+#define nsmkdir(dir, mode) mkdir((dir), (mode))
#endif
#if defined(__GNUC__) && (__GNUC__ < 3)
@@ -105,12 +108,6 @@ typedef struct
void (*cancel)(query_id, enum query_response res, void *pw);
} query_callback;
-#ifdef HAVE_MKDIR
-#define nsmkdir(dir, mode) mkdir((dir), (mode))
-#else
-#define nsmkdir(dir, mode) mkdir((dir))
-#endif
-
#ifndef timeradd
#define timeradd(a, aa, result) \
do { \
-----------------------------------------------------------------------
Summary of changes:
utils/filepath.c | 3 ++-
utils/utils.h | 9 +++------
2 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/utils/filepath.c b/utils/filepath.c
index d82dfc6..68e8d7e 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -31,6 +31,7 @@
#include <unistd.h>
#include <string.h>
+#include "utils/utils.h"
#include "utils/config.h"
#include "utils/filepath.h"
@@ -378,7 +379,7 @@ nserror filepath_mkdir_all(const char *fname)
while ((sep = strchr(sep, '/')) != NULL) {
*sep = 0;
if (stat(dname, &sb) != 0) {
- if (mkdir(dname, S_IRWXU) != 0) {
+ if (nsmkdir(dname, S_IRWXU) != 0) {
/* could not create path element */
free(dname);
return NSERROR_NOT_FOUND;
diff --git a/utils/utils.h b/utils/utils.h
index ed19cb3..db26ed1 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -60,10 +60,13 @@ struct dirent;
#define PRId64 "lld"
#endif
+/* Windows does not have POSIX formating codes or mkdir so work around that */
#if defined(_WIN32)
#define SSIZET_FMT "Iu"
+#define nsmkdir(dir, mode) mkdir((dir))
#else
#define SSIZET_FMT "zd"
+#define nsmkdir(dir, mode) mkdir((dir), (mode))
#endif
#if defined(__GNUC__) && (__GNUC__ < 3)
@@ -105,12 +108,6 @@ typedef struct
void (*cancel)(query_id, enum query_response res, void *pw);
} query_callback;
-#ifdef HAVE_MKDIR
-#define nsmkdir(dir, mode) mkdir((dir), (mode))
-#else
-#define nsmkdir(dir, mode) mkdir((dir))
-#endif
-
#ifndef timeradd
#define timeradd(a, aa, result) \
do { \
--
NetSurf Browser
9 years, 1 month
netsurf: branch master updated. release/3.1-3-g1fd565c
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf.git/shortlog/1fd565cba706d6a9e809d...
...commit http://git.netsurf-browser.org/netsurf.git/commit/1fd565cba706d6a9e809d14...
...tree http://git.netsurf-browser.org/netsurf.git/tree/1fd565cba706d6a9e809d14f7...
The branch, master has been updated
via 1fd565cba706d6a9e809d14f79ceb92633b62ead (commit)
from c0ac05d39c10ff39c8f4874bdbbe192dca07e910 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf.git/commit/?id=1fd565cba706d6a9e80...
commit 1fd565cba706d6a9e809d14f79ceb92633b62ead
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
make GTK configuration handling conform to XDG specification.
diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c
index a8ff674..fcf30c8 100644
--- a/gtk/dialogs/preferences.c
+++ b/gtk/dialogs/preferences.c
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <math.h>
+#include "utils/filepath.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
@@ -1001,8 +1002,14 @@ nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
{
+ char *choices;
+
if (resid == GTK_RESPONSE_CLOSE) {
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
gtk_widget_hide(GTK_WIDGET(dlg));
}
}
@@ -1011,18 +1018,32 @@ G_MODULE_EXPORT gboolean
nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
gtk_widget_hide(GTK_WIDGET(dlg));
- /* delt with it by hiding window, no need to destory widget by
- * default */
+ /* Delt with it by hiding window, no need to destory widget by
+ * default.
+ */
return TRUE;
}
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
}
diff --git a/gtk/gui.c b/gtk/gui.c
index fa16900..1c108a1 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -79,13 +79,13 @@
#include "utils/utf8.h"
#include "utils/utils.h"
-char *options_file_location;
char *toolbar_indices_file_location;
char *res_dir_location;
-char *print_options_file_location;
char *languages_file_location;
char *themelist_file_location;
+char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+
GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
struct glade_file_location_s *glade_file_location;
@@ -243,48 +243,55 @@ nsgtk_init_glade(char **respath)
}
/**
- * Set option defaults for gtk frontend
+ * Set option defaults for gtk frontend.
*
* @param defaults The option table to update.
* @return error status.
*/
static nserror set_defaults(struct nsoption_s *defaults)
{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
+ char *fname;
- /* Set defaults for absent option strings */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Cookies", hdir);
- nsoption_setnull_charp(cookie_file, strdup(buf));
- nsoption_setnull_charp(cookie_jar, strdup(buf));
- if (nsoption_charp(cookie_file) == NULL ||
- nsoption_charp(cookie_jar) == NULL) {
- LOG(("Failed initialising cookie options"));
- return NSERROR_BAD_PARAMETER;
+ /* cookie file default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_file, fname);
+ }
+
+ /* cookie jar default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_jar, fname);
}
- if (nsoption_charp(downloads_directory) == NULL) {
- snprintf(buf, PATH_MAX, "%s/", hdir);
- nsoption_set_charp(downloads_directory, strdup(buf));
+ /* url database default */
+ fname = filepath_append(nsgtk_config_home, "URLs");
+ if (fname != NULL) {
+ nsoption_setnull_charp(url_file, fname);
}
- if (nsoption_charp(url_file) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/URLs", hdir);
- nsoption_set_charp(url_file, strdup(buf));
+ /* bookmark database default */
+ fname = filepath_append(nsgtk_config_home, "Hotlist");
+ if (fname != NULL) {
+ nsoption_setnull_charp(hotlist_path, fname);
}
- if (nsoption_charp(hotlist_path) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/Hotlist", hdir);
- nsoption_set_charp(hotlist_path, strdup(buf));
+ /* download directory default */
+ fname = filepath_append(getenv("HOME"), "");
+ if (fname != NULL) {
+ nsoption_setnull_charp(downloads_directory, fname);
}
+ /* default path to certificates */
nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs"));
- if (nsoption_charp(url_file) == NULL ||
- nsoption_charp(ca_path) == NULL ||
- nsoption_charp(downloads_directory) == NULL ||
- nsoption_charp(hotlist_path) == NULL) {
- LOG(("Failed initialising string options"));
+ if ((nsoption_charp(cookie_file) == NULL) ||
+ (nsoption_charp(cookie_jar) == NULL) ||
+ (nsoption_charp(url_file) == NULL) ||
+ (nsoption_charp(hotlist_path) == NULL) ||
+ (nsoption_charp(downloads_directory) == NULL) ||
+ (nsoption_charp(ca_path) == NULL)) {
+ LOG(("Failed initialising default resource paths"));
return NSERROR_BAD_PARAMETER;
}
@@ -298,32 +305,6 @@ static nserror set_defaults(struct nsoption_s *defaults)
return NSERROR_OK;
}
-static void check_options(char **respath)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
- nsoption_set_bool(core_select_menu, true);
-
- /* Attempt to handle nonsense status bar widths. These may exist
- * in people's Choices as the GTK front end used to abuse the
- * status bar width option by using it for an absolute value in px.
- * The GTK front end now correctly uses it as a proportion of window
- * width. Here we assume that a value of less than 15% is wrong
- * and set to the default two thirds. */
- if (nsoption_int(toolbar_status_size) < 1500) {
- nsoption_set_int(toolbar_status_size, 6667);
- }
-
- /* user options should be stored in the users home directory */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Choices", hdir);
- options_file_location = strdup(buf);
-
- filepath_sfinddef(respath, buf, "Print", "~/.netsurf/");
- LOG(("Using '%s' as Print Settings file", buf));
- print_options_file_location = strdup(buf);
-
-
-}
@@ -481,34 +462,6 @@ static void gui_init(int argc, char** argv, char **respath)
}
-/**
- * Check that ~/.netsurf/ exists, and if it doesn't, create it.
- */
-static void nsgtk_check_homedir(void)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
-
- if (hdir == NULL) {
- /* we really can't continue without a home directory. */
- LOG(("HOME is not set - nowhere to store state!"));
- die("NetSurf requires HOME to be set in order to run.\n");
-
- }
-
- snprintf(buf, PATH_MAX, "%s/.netsurf", hdir);
- if (access(buf, F_OK) != 0) {
- LOG(("You don't have a ~/.netsurf - creating one for you."));
- if (mkdir(buf, S_IRWXU) == -1) {
- LOG(("Unable to create %s", buf));
- die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n");
- }
- } else {
- if (chmod(buf, S_IRWXU) != 0) {
- LOG(("Unable to set permissions on %s", buf));
- }
- }
-}
/**
* Ensures output logging stream is correctly configured
@@ -601,10 +554,13 @@ static void gui_quit(void)
nsgtk_cookies_destroy();
nsgtk_history_destroy();
nsgtk_hotlist_destroy();
- free(print_options_file_location);
+
free(search_engines_file_location);
free(search_default_ico_location);
free(toolbar_indices_file_location);
+
+ free(nsgtk_config_home);
+
gtk_fetch_filetype_fin();
}
@@ -990,6 +946,198 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
}
+/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname;
+ struct stat dirname_stat;
+
+ dirname = filepath_append(path, leaf);
+ if (dirname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;;
+}
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ LOG(("\"%s\"", config_home));
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG(("\"%s\"", config_home));
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ LOG(("Attempting to create configuration directory"));
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ config_home = filepath_append(home_dir, ".config/netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ config_home = filepath_append(xdg_config_dir, "netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = filepath_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* select menus generated by core code */
+ nsoption_set_bool(core_select_menu, true);
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
static struct gui_browser_table nsgtk_browser_table = {
.poll = nsgtk_poll,
.schedule = nsgtk_schedule,
@@ -1008,7 +1156,6 @@ static struct gui_browser_table nsgtk_browser_table = {
int main(int argc, char** argv)
{
char *messages;
- char *options;
nserror ret;
struct gui_table nsgtk_gui_table = {
.browser = &nsgtk_browser_table,
@@ -1019,11 +1166,21 @@ int main(int argc, char** argv)
.search = nsgtk_search_table,
};
- /* check home directory is available */
- nsgtk_check_homedir();
-
+ /* build the common resource path list */
respaths = nsgtk_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"GTK_RESPATH":./gtk/res");
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG(("Unable to locate a configuration directory."));
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
gtk_init(&argc, &argv);
/* initialise logging. Not fatal if it fails but not much we
@@ -1031,21 +1188,18 @@ int main(int argc, char** argv)
*/
nslog_init(nslog_stream_configure, &argc, argv);
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ /* Initialise user options */
+ ret = nsgtk_option_init(&argc, argv);
if (ret != NSERROR_OK) {
fprintf(stderr, "Options failed to initialise (%s)\n",
messages_get_errorcode(ret));
return 1;
}
- options = filepath_find(respaths, "Choices");
- nsoption_read(options, nsoptions);
- free(options);
- nsoption_commandline(&argc, argv, nsoptions);
- check_options(respaths); /* check user options */
- /* common initialisation */
+ /* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
+
+ /* core initialisation */
ret = netsurf_init(messages, &nsgtk_gui_table);
free(messages);
if (ret != NSERROR_OK) {
diff --git a/gtk/gui.h b/gtk/gui.h
index dc1f2b3..a9a98c6 100644
--- a/gtk/gui.h
+++ b/gtk/gui.h
@@ -52,11 +52,12 @@ extern struct glade_file_location_s *glade_file_location;
extern char *languages_file_location;
extern char *toolbar_indices_file_location;
-extern char *options_file_location; /**< location where user options are written */
extern char *res_dir_location;
-extern char *print_options_file_location;
extern char *themelist_file_location;
+/** Directory where all configuration files are held. */
+extern char *nsgtk_config_home;
+
extern GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
extern char **respaths; /** resource search path vector */
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index c5dd524..436830b 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "utils/filepath.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/log.h"
@@ -863,9 +864,10 @@ MULTIHANDLER(print)
GtkPrintOperation *print_op;
GtkPageSetup *page_setup;
- GtkPrintSettings *gtk_print_settings;
+ GtkPrintSettings *print_settings;
GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
- struct print_settings *settings;
+ struct print_settings *nssettings;
+ char *settings_fname;
print_op = gtk_print_operation_new();
if (print_op == NULL) {
@@ -874,14 +876,16 @@ MULTIHANDLER(print)
}
/* use previously saved settings if any */
- gtk_print_settings = gtk_print_settings_new_from_file(
- print_options_file_location, NULL);
- if (gtk_print_settings != NULL) {
- gtk_print_operation_set_print_settings(print_op,
- gtk_print_settings);
-
- /* We're not interested in the settings any more */
- g_object_unref(gtk_print_settings);
+ settings_fname = filepath_append(nsgtk_config_home, "Print");
+ if (settings_fname != NULL) {
+ print_settings = gtk_print_settings_new_from_file(settings_fname, NULL);
+ if (print_settings != NULL) {
+ gtk_print_operation_set_print_settings(print_op,
+ print_settings);
+
+ /* We're not interested in the settings any more */
+ g_object_unref(print_settings);
+ }
}
content_to_print = bw->current_content;
@@ -889,33 +893,40 @@ MULTIHANDLER(print)
page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL);
if (page_setup == NULL) {
warn_user(messages_get("NoMemory"), 0);
+ free(settings_fname);
g_object_unref(print_op);
return TRUE;
}
gtk_print_operation_set_default_page_setup(print_op, page_setup);
- settings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
+ nssettings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
g_signal_connect(print_op, "begin_print",
- G_CALLBACK(gtk_print_signal_begin_print), settings);
+ G_CALLBACK(gtk_print_signal_begin_print), nssettings);
g_signal_connect(print_op, "draw_page",
G_CALLBACK(gtk_print_signal_draw_page), NULL);
g_signal_connect(print_op, "end_print",
- G_CALLBACK(gtk_print_signal_end_print), settings);
- if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN)
+ G_CALLBACK(gtk_print_signal_end_print), nssettings);
+
+ if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN) {
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
g->window,
NULL);
+ }
/* if the settings were used save them for future use */
- if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
- /* Don't ref the settings, as we don't want to own them */
- gtk_print_settings = gtk_print_operation_get_print_settings(
- print_op);
-
- gtk_print_settings_to_file(gtk_print_settings,
- print_options_file_location, NULL);
+ if (settings_fname != NULL) {
+ if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+ /* Do not increment the settings reference */
+ print_settings =
+ gtk_print_operation_get_print_settings(print_op);
+
+ gtk_print_settings_to_file(print_settings,
+ settings_fname,
+ NULL);
+ }
+ free(settings_fname);
}
/* Our print_settings object is destroyed by the end print handler */
@@ -1249,6 +1260,7 @@ MULTIHANDLER(downloads)
MULTIHANDLER(savewindowsize)
{
int x,y,w,h;
+ char *choices;
gtk_window_get_position(g->window, &x, &y);
gtk_window_get_size(g->window, &w, &h);
@@ -1258,7 +1270,11 @@ MULTIHANDLER(savewindowsize)
nsoption_set_int(window_x, x);
nsoption_set_int(window_y, y);
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
return TRUE;
}
diff --git a/utils/errors.h b/utils/errors.h
index c38e4b9..4c02adb 100644
--- a/utils/errors.h
+++ b/utils/errors.h
@@ -37,6 +37,8 @@ typedef enum {
NSERROR_NOT_FOUND, /**< Requested item not found */
+ NSERROR_NOT_DIRECTORY, /**< Missing directory */
+
NSERROR_SAVE_FAILED, /**< Failed to save data */
NSERROR_CLONE_FAILED, /**< Failed to clone handle */
@@ -69,7 +71,9 @@ typedef enum {
NSERROR_BAD_CONTENT, /**< Bad Content */
- NSERROR_FRAME_DEPTH /**< Exceeded frame depth */
+ NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */
+
+ NSERROR_PERMISSION /**< Permission error */
} nserror;
#endif
diff --git a/utils/filepath.c b/utils/filepath.c
index d088777..d82dfc6 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -202,7 +202,13 @@ filepath_generate(char * const *pathv, const char * const *langv)
return respath;
}
-/* expand ${} in a string into environment variables */
+/**
+ * expand ${} in a string into environment variables.
+ *
+ * @param path The pathname to expand.
+ * @param pathlen The length of the path element.
+ * @return A string with the expanded path or NULL on empty expansion or error.
+ */
static char *
expand_path(const char *path, int pathlen)
{
@@ -317,3 +323,80 @@ void filepath_free_strvec(char **pathv)
}
free(pathv);
}
+
+/* exported interface documented in filepath.h */
+char *filepath_append(const char *path, const char *leaf)
+{
+ int dirname_len;
+ char *dirname;
+
+ if ((path == NULL) || (leaf == NULL)) {
+ return NULL;
+ }
+
+ dirname_len = strlen(path) + strlen(leaf) + 2;
+ dirname = malloc(dirname_len);
+ if (dirname != NULL) {
+ snprintf(dirname, dirname_len, "%s/%s", path, leaf);
+ }
+
+ return dirname;
+}
+
+/* exported interface documented in filepath.h */
+nserror filepath_mkdir_all(const char *fname)
+{
+ char *dname;
+ char *sep;
+ struct stat sb;
+
+ dname = strdup(fname);
+
+ sep = strrchr(dname, '/');
+ if (sep == NULL) {
+ /* no directory separator path is just filename so its ok */
+ free(dname);
+ return NSERROR_OK;
+ }
+
+ *sep = 0; /* null terminate directory path */
+
+ if (stat(dname, &sb) == 0) {
+ free(dname);
+ if (S_ISDIR(sb.st_mode)) {
+ /* path to file exists and is a directory */
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_DIRECTORY;
+ }
+ *sep = '/'; /* restore separator */
+
+ sep = dname;
+ while (*sep == '/') {
+ sep++;
+ }
+ while ((sep = strchr(sep, '/')) != NULL) {
+ *sep = 0;
+ if (stat(dname, &sb) != 0) {
+ if (mkdir(dname, S_IRWXU) != 0) {
+ /* could not create path element */
+ free(dname);
+ return NSERROR_NOT_FOUND;
+ }
+ } else {
+ if (! S_ISDIR(sb.st_mode)) {
+ /* path element not a directory */
+ free(dname);
+ return NSERROR_NOT_DIRECTORY;
+ }
+ }
+ *sep = '/'; /* restore separator */
+ /* skip directory separators */
+ while (*sep == '/') {
+ sep++;
+ }
+ }
+
+ free(dname);
+ return NSERROR_OK;
+}
diff --git a/utils/filepath.h b/utils/filepath.h
index ff3ebe9..56e9eff 100644
--- a/utils/filepath.h
+++ b/utils/filepath.h
@@ -16,9 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * \file utils/filepath.h
- * \brief Utility routines to obtain paths to file resources.
+/**
+ * @file utils/filepath.h
+ * @brief Utility routines to obtain paths to file resources.
*/
#ifndef _NETSURF_UTILS_FILEPATH_H_
@@ -26,8 +26,10 @@
#include <stdarg.h>
+#include "utils/errors.h"
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* If the file described by the format exists and is accessible the
* normalised path is placed in str and a pointer to str returned
@@ -43,14 +45,16 @@
char *filepath_vsfindfile(char *str, const char *format, va_list ap);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to vsfindfile but takes variadic (printf like) parameters
*/
char *filepath_sfindfile(char *str, const char *format, ...);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to sfindfile but allocates its own storage for the
* returned string. The caller must free this sorage.
@@ -58,7 +62,8 @@ char *filepath_sfindfile(char *str, const char *format, ...);
char *filepath_findfile(const char *format, ...);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Iterates through a vector of resource paths and returns the
* normalised file name of the first acessible file or NULL if no file
@@ -72,7 +77,8 @@ char *filepath_findfile(const char *format, ...);
char *filepath_sfind(char **respathv, char *filepath, const char *filename);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Similar to filepath_sfind except it allocates its own storage for
* the returned string. The caller must free this sorage.
@@ -80,7 +86,8 @@ char *filepath_sfind(char **respathv, char *filepath, const char *filename);
char *filepath_find(char **respathv, const char *filename);
-/** Searches an array of resource paths for a file optionally forcing a default.
+/**
+ * Searches an array of resource paths for a file optionally forcing a default.
*
* Similar to filepath_sfind except if no resource is found the default
* is used as an additional path element to search, if that still
@@ -91,7 +98,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
const char *def);
-/** Merge two string vectors into a resource search path vector.
+/**
+ * Merge two string vectors into a resource search path vector.
*
* @param pathv A string vector containing path elemets to scan.
* @param langv A string vector containing language names to enumerate.
@@ -101,7 +109,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
char **filepath_generate(char * const *pathv, const char * const *langv);
-/** Convert a colon separated list of path elements into a string vector.
+/**
+ * Convert a colon separated list of path elements into a string vector.
*
* @param path A colon separated path.
* @return A pointer to a NULL terminated string vector of valid
@@ -110,10 +119,32 @@ char **filepath_generate(char * const *pathv, const char * const *langv);
char **filepath_path_to_strvec(const char *path);
-/** Free a string vector
+/**
+ * Free a string vector.
*
* Free a string vector allocated by filepath_path_to_strvec
*/
void filepath_free_strvec(char **pathv);
+
+/**
+ * generate a new filename from a path and leaf.
+ *
+ * @param path The base path.
+ * @param leaf The leaf to add.
+ * @return The combined path in a new string must be freed by caller
+ * or NULL on failiure to allocte memory.
+ */
+char *filepath_append(const char *path, const char *leaf);
+
+
+/**
+ * Ensure that all directory elements needed to store a filename exist.
+ *
+ * @param fname The filename to ensure the path to exists.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+nserror filepath_mkdir_all(const char *fname);
+
+
#endif /* _NETSURF_UTILS_FILEPATH_H_ */
-----------------------------------------------------------------------
Summary of changes:
gtk/dialogs/preferences.c | 31 ++++-
gtk/gui.c | 342 ++++++++++++++++++++++++++++++++-------------
gtk/gui.h | 5 +-
gtk/scaffolding.c | 60 +++++---
utils/errors.h | 6 +-
utils/filepath.c | 85 +++++++++++-
utils/filepath.h | 55 ++++++--
7 files changed, 447 insertions(+), 137 deletions(-)
diff --git a/gtk/dialogs/preferences.c b/gtk/dialogs/preferences.c
index a8ff674..fcf30c8 100644
--- a/gtk/dialogs/preferences.c
+++ b/gtk/dialogs/preferences.c
@@ -19,6 +19,7 @@
#include <stdint.h>
#include <math.h>
+#include "utils/filepath.h"
#include "utils/log.h"
#include "utils/utils.h"
#include "utils/messages.h"
@@ -1001,8 +1002,14 @@ nsgtk_preferences_fileChooserDownloads_realize(GtkWidget *widget,
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_response(GtkDialog *dlg, gint resid)
{
+ char *choices;
+
if (resid == GTK_RESPONSE_CLOSE) {
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
gtk_widget_hide(GTK_WIDGET(dlg));
}
}
@@ -1011,18 +1018,32 @@ G_MODULE_EXPORT gboolean
nsgtk_preferences_dialogPreferences_deleteevent(GtkDialog *dlg,
struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
+
gtk_widget_hide(GTK_WIDGET(dlg));
- /* delt with it by hiding window, no need to destory widget by
- * default */
+ /* Delt with it by hiding window, no need to destory widget by
+ * default.
+ */
return TRUE;
}
G_MODULE_EXPORT void
nsgtk_preferences_dialogPreferences_destroy(GtkDialog *dlg, struct ppref *priv)
{
- nsoption_write(options_file_location, NULL, NULL);
+ char *choices;
+
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
}
diff --git a/gtk/gui.c b/gtk/gui.c
index fa16900..1c108a1 100644
--- a/gtk/gui.c
+++ b/gtk/gui.c
@@ -79,13 +79,13 @@
#include "utils/utf8.h"
#include "utils/utils.h"
-char *options_file_location;
char *toolbar_indices_file_location;
char *res_dir_location;
-char *print_options_file_location;
char *languages_file_location;
char *themelist_file_location;
+char *nsgtk_config_home; /* exported global defined in gtk/gui.h */
+
GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
struct glade_file_location_s *glade_file_location;
@@ -243,48 +243,55 @@ nsgtk_init_glade(char **respath)
}
/**
- * Set option defaults for gtk frontend
+ * Set option defaults for gtk frontend.
*
* @param defaults The option table to update.
* @return error status.
*/
static nserror set_defaults(struct nsoption_s *defaults)
{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
+ char *fname;
- /* Set defaults for absent option strings */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Cookies", hdir);
- nsoption_setnull_charp(cookie_file, strdup(buf));
- nsoption_setnull_charp(cookie_jar, strdup(buf));
- if (nsoption_charp(cookie_file) == NULL ||
- nsoption_charp(cookie_jar) == NULL) {
- LOG(("Failed initialising cookie options"));
- return NSERROR_BAD_PARAMETER;
+ /* cookie file default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_file, fname);
+ }
+
+ /* cookie jar default */
+ fname = filepath_append(nsgtk_config_home, "Cookies");
+ if (fname != NULL) {
+ nsoption_setnull_charp(cookie_jar, fname);
}
- if (nsoption_charp(downloads_directory) == NULL) {
- snprintf(buf, PATH_MAX, "%s/", hdir);
- nsoption_set_charp(downloads_directory, strdup(buf));
+ /* url database default */
+ fname = filepath_append(nsgtk_config_home, "URLs");
+ if (fname != NULL) {
+ nsoption_setnull_charp(url_file, fname);
}
- if (nsoption_charp(url_file) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/URLs", hdir);
- nsoption_set_charp(url_file, strdup(buf));
+ /* bookmark database default */
+ fname = filepath_append(nsgtk_config_home, "Hotlist");
+ if (fname != NULL) {
+ nsoption_setnull_charp(hotlist_path, fname);
}
- if (nsoption_charp(hotlist_path) == NULL) {
- snprintf(buf, PATH_MAX, "%s/.netsurf/Hotlist", hdir);
- nsoption_set_charp(hotlist_path, strdup(buf));
+ /* download directory default */
+ fname = filepath_append(getenv("HOME"), "");
+ if (fname != NULL) {
+ nsoption_setnull_charp(downloads_directory, fname);
}
+ /* default path to certificates */
nsoption_setnull_charp(ca_path, strdup("/etc/ssl/certs"));
- if (nsoption_charp(url_file) == NULL ||
- nsoption_charp(ca_path) == NULL ||
- nsoption_charp(downloads_directory) == NULL ||
- nsoption_charp(hotlist_path) == NULL) {
- LOG(("Failed initialising string options"));
+ if ((nsoption_charp(cookie_file) == NULL) ||
+ (nsoption_charp(cookie_jar) == NULL) ||
+ (nsoption_charp(url_file) == NULL) ||
+ (nsoption_charp(hotlist_path) == NULL) ||
+ (nsoption_charp(downloads_directory) == NULL) ||
+ (nsoption_charp(ca_path) == NULL)) {
+ LOG(("Failed initialising default resource paths"));
return NSERROR_BAD_PARAMETER;
}
@@ -298,32 +305,6 @@ static nserror set_defaults(struct nsoption_s *defaults)
return NSERROR_OK;
}
-static void check_options(char **respath)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
- nsoption_set_bool(core_select_menu, true);
-
- /* Attempt to handle nonsense status bar widths. These may exist
- * in people's Choices as the GTK front end used to abuse the
- * status bar width option by using it for an absolute value in px.
- * The GTK front end now correctly uses it as a proportion of window
- * width. Here we assume that a value of less than 15% is wrong
- * and set to the default two thirds. */
- if (nsoption_int(toolbar_status_size) < 1500) {
- nsoption_set_int(toolbar_status_size, 6667);
- }
-
- /* user options should be stored in the users home directory */
- snprintf(buf, PATH_MAX, "%s/.netsurf/Choices", hdir);
- options_file_location = strdup(buf);
-
- filepath_sfinddef(respath, buf, "Print", "~/.netsurf/");
- LOG(("Using '%s' as Print Settings file", buf));
- print_options_file_location = strdup(buf);
-
-
-}
@@ -481,34 +462,6 @@ static void gui_init(int argc, char** argv, char **respath)
}
-/**
- * Check that ~/.netsurf/ exists, and if it doesn't, create it.
- */
-static void nsgtk_check_homedir(void)
-{
- char *hdir = getenv("HOME");
- char buf[PATH_MAX];
-
- if (hdir == NULL) {
- /* we really can't continue without a home directory. */
- LOG(("HOME is not set - nowhere to store state!"));
- die("NetSurf requires HOME to be set in order to run.\n");
-
- }
-
- snprintf(buf, PATH_MAX, "%s/.netsurf", hdir);
- if (access(buf, F_OK) != 0) {
- LOG(("You don't have a ~/.netsurf - creating one for you."));
- if (mkdir(buf, S_IRWXU) == -1) {
- LOG(("Unable to create %s", buf));
- die("NetSurf requires ~/.netsurf to exist, but it cannot be created.\n");
- }
- } else {
- if (chmod(buf, S_IRWXU) != 0) {
- LOG(("Unable to set permissions on %s", buf));
- }
- }
-}
/**
* Ensures output logging stream is correctly configured
@@ -601,10 +554,13 @@ static void gui_quit(void)
nsgtk_cookies_destroy();
nsgtk_history_destroy();
nsgtk_hotlist_destroy();
- free(print_options_file_location);
+
free(search_engines_file_location);
free(search_default_ico_location);
free(toolbar_indices_file_location);
+
+ free(nsgtk_config_home);
+
gtk_fetch_filetype_fin();
}
@@ -990,6 +946,198 @@ uint32_t gtk_gui_gdkkey_to_nskey(GdkEventKey *key)
}
+/**
+ * create directory name and check it is acessible and a directory.
+ */
+static nserror
+check_dirname(const char *path, const char *leaf, char **dirname_out)
+{
+ nserror ret;
+ char *dirname;
+ struct stat dirname_stat;
+
+ dirname = filepath_append(path, leaf);
+ if (dirname == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* ensure access is possible and the entry is actualy
+ * a directory.
+ */
+ if (stat(dirname, &dirname_stat) == 0) {
+ if (S_ISDIR(dirname_stat.st_mode)) {
+ if (access(dirname, R_OK | W_OK) == 0) {
+ *dirname_out = dirname;
+ return NSERROR_OK;
+ } else {
+ ret = NSERROR_PERMISSION;
+ }
+ } else {
+ ret = NSERROR_NOT_DIRECTORY;
+ }
+ } else {
+ ret = NSERROR_NOT_FOUND;
+ }
+
+ free(dirname);
+
+ return ret;;
+}
+
+/**
+ * Get the path to the config directory.
+ *
+ * @param config_home_out Path to configuration directory.
+ * @return NSERROR_OK on sucess and \a config_home_out updated else error code.
+ */
+static nserror get_config_home(char **config_home_out)
+{
+ nserror ret;
+ char *home_dir;
+ char *xdg_config_dir;
+ char *config_home;
+
+ home_dir = getenv("HOME");
+
+ /* The old $HOME/.netsurf/ directory should be used if it
+ * exists and is accessible.
+ */
+ if (home_dir != NULL) {
+ ret = check_dirname(home_dir, ".netsurf", &config_home);
+ if (ret == NSERROR_OK) {
+ LOG(("\"%s\"", config_home));
+ *config_home_out = config_home;
+ return ret;
+ }
+ }
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ /* If $XDG_CONFIG_HOME is either not set or empty, a
+ * default equal to $HOME/.config should be used.
+ */
+
+ /** @todo the meaning of empty is never defined so I
+ * am assuming it is a zero length string but is it
+ * supposed to mean "whitespace" and if so what counts
+ * as whitespace? (are tabs etc. counted or should
+ * isspace() be used)
+ */
+
+ /* the HOME envvar is required */
+ if (home_dir == NULL) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ ret = check_dirname(home_dir, ".config/netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ } else {
+ ret = check_dirname(xdg_config_dir, "netsurf", &config_home);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+ }
+
+ LOG(("\"%s\"", config_home));
+
+ *config_home_out = config_home;
+ return NSERROR_OK;
+}
+
+static nserror create_config_home(char **config_home_out)
+{
+ char *config_home;
+ char *home_dir;
+ char *xdg_config_dir;
+ nserror ret;
+
+ LOG(("Attempting to create configuration directory"));
+
+ /* $XDG_CONFIG_HOME defines the base directory
+ * relative to which user specific configuration files
+ * should be stored.
+ */
+ xdg_config_dir = getenv("XDG_CONFIG_HOME");
+
+ if ((xdg_config_dir == NULL) || (*xdg_config_dir == 0)) {
+ home_dir = getenv("HOME");
+
+ if ((home_dir == NULL) || (*home_dir == 0)) {
+ return NSERROR_NOT_DIRECTORY;
+ }
+
+ config_home = filepath_append(home_dir, ".config/netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ config_home = filepath_append(xdg_config_dir, "netsurf/");
+ if (config_home == NULL) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ /* ensure all elements of path exist (the trailing / is required) */
+ ret = filepath_mkdir_all(config_home);
+ if (ret != NSERROR_OK) {
+ free(config_home);
+ return ret;
+ }
+
+ /* strip the trailing separator */
+ config_home[strlen(config_home) - 1] = 0;
+
+ *config_home_out = config_home;
+
+ return NSERROR_OK;
+}
+
+static nserror nsgtk_option_init(int *pargc, char** argv)
+{
+ nserror ret;
+ char *choices;
+
+ /* user options setup */
+ ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ if (ret != NSERROR_OK) {
+ return ret;
+ }
+
+ /* Attempt to load the user choices */
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_read(choices, nsoptions);
+ free(choices);
+ }
+
+ /* overide loaded options with those from commandline */
+ nsoption_commandline(pargc, argv, nsoptions);
+
+ /* ensure all options fall within sensible bounds */
+
+ /* select menus generated by core code */
+ nsoption_set_bool(core_select_menu, true);
+
+ /* Attempt to handle nonsense status bar widths. These may exist
+ * in people's Choices as the GTK front end used to abuse the
+ * status bar width option by using it for an absolute value in px.
+ * The GTK front end now correctly uses it as a proportion of window
+ * width. Here we assume that a value of less than 15% is wrong
+ * and set to the default two thirds. */
+ if (nsoption_int(toolbar_status_size) < 1500) {
+ nsoption_set_int(toolbar_status_size, 6667);
+ }
+
+ return NSERROR_OK;
+}
+
static struct gui_browser_table nsgtk_browser_table = {
.poll = nsgtk_poll,
.schedule = nsgtk_schedule,
@@ -1008,7 +1156,6 @@ static struct gui_browser_table nsgtk_browser_table = {
int main(int argc, char** argv)
{
char *messages;
- char *options;
nserror ret;
struct gui_table nsgtk_gui_table = {
.browser = &nsgtk_browser_table,
@@ -1019,11 +1166,21 @@ int main(int argc, char** argv)
.search = nsgtk_search_table,
};
- /* check home directory is available */
- nsgtk_check_homedir();
-
+ /* build the common resource path list */
respaths = nsgtk_init_resource("${HOME}/.netsurf/:${NETSURFRES}:"GTK_RESPATH":./gtk/res");
+ /* Locate the correct user configuration directory path */
+ ret = get_config_home(&nsgtk_config_home);
+ if (ret == NSERROR_NOT_FOUND) {
+ /* no config directory exists yet so try to create one */
+ ret = create_config_home(&nsgtk_config_home);
+ }
+ if (ret != NSERROR_OK) {
+ LOG(("Unable to locate a configuration directory."));
+ nsgtk_config_home = NULL;
+ }
+
+ /* Initialise gtk */
gtk_init(&argc, &argv);
/* initialise logging. Not fatal if it fails but not much we
@@ -1031,21 +1188,18 @@ int main(int argc, char** argv)
*/
nslog_init(nslog_stream_configure, &argc, argv);
- /* user options setup */
- ret = nsoption_init(set_defaults, &nsoptions, &nsoptions_default);
+ /* Initialise user options */
+ ret = nsgtk_option_init(&argc, argv);
if (ret != NSERROR_OK) {
fprintf(stderr, "Options failed to initialise (%s)\n",
messages_get_errorcode(ret));
return 1;
}
- options = filepath_find(respaths, "Choices");
- nsoption_read(options, nsoptions);
- free(options);
- nsoption_commandline(&argc, argv, nsoptions);
- check_options(respaths); /* check user options */
- /* common initialisation */
+ /* Obtain path to messages */
messages = filepath_find(respaths, "Messages");
+
+ /* core initialisation */
ret = netsurf_init(messages, &nsgtk_gui_table);
free(messages);
if (ret != NSERROR_OK) {
diff --git a/gtk/gui.h b/gtk/gui.h
index dc1f2b3..a9a98c6 100644
--- a/gtk/gui.h
+++ b/gtk/gui.h
@@ -52,11 +52,12 @@ extern struct glade_file_location_s *glade_file_location;
extern char *languages_file_location;
extern char *toolbar_indices_file_location;
-extern char *options_file_location; /**< location where user options are written */
extern char *res_dir_location;
-extern char *print_options_file_location;
extern char *themelist_file_location;
+/** Directory where all configuration files are held. */
+extern char *nsgtk_config_home;
+
extern GdkPixbuf *favicon_pixbuf; /* favicon default pixbuf */
extern char **respaths; /** resource search path vector */
diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c
index c5dd524..436830b 100644
--- a/gtk/scaffolding.c
+++ b/gtk/scaffolding.c
@@ -25,6 +25,7 @@
#include <gtk/gtk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
+#include "utils/filepath.h"
#include "utils/messages.h"
#include "utils/url.h"
#include "utils/log.h"
@@ -863,9 +864,10 @@ MULTIHANDLER(print)
GtkPrintOperation *print_op;
GtkPageSetup *page_setup;
- GtkPrintSettings *gtk_print_settings;
+ GtkPrintSettings *print_settings;
GtkPrintOperationResult res = GTK_PRINT_OPERATION_RESULT_ERROR;
- struct print_settings *settings;
+ struct print_settings *nssettings;
+ char *settings_fname;
print_op = gtk_print_operation_new();
if (print_op == NULL) {
@@ -874,14 +876,16 @@ MULTIHANDLER(print)
}
/* use previously saved settings if any */
- gtk_print_settings = gtk_print_settings_new_from_file(
- print_options_file_location, NULL);
- if (gtk_print_settings != NULL) {
- gtk_print_operation_set_print_settings(print_op,
- gtk_print_settings);
-
- /* We're not interested in the settings any more */
- g_object_unref(gtk_print_settings);
+ settings_fname = filepath_append(nsgtk_config_home, "Print");
+ if (settings_fname != NULL) {
+ print_settings = gtk_print_settings_new_from_file(settings_fname, NULL);
+ if (print_settings != NULL) {
+ gtk_print_operation_set_print_settings(print_op,
+ print_settings);
+
+ /* We're not interested in the settings any more */
+ g_object_unref(print_settings);
+ }
}
content_to_print = bw->current_content;
@@ -889,33 +893,40 @@ MULTIHANDLER(print)
page_setup = gtk_print_run_page_setup_dialog(g->window, NULL, NULL);
if (page_setup == NULL) {
warn_user(messages_get("NoMemory"), 0);
+ free(settings_fname);
g_object_unref(print_op);
return TRUE;
}
gtk_print_operation_set_default_page_setup(print_op, page_setup);
- settings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
+ nssettings = print_make_settings(PRINT_DEFAULT, NULL, &nsfont);
g_signal_connect(print_op, "begin_print",
- G_CALLBACK(gtk_print_signal_begin_print), settings);
+ G_CALLBACK(gtk_print_signal_begin_print), nssettings);
g_signal_connect(print_op, "draw_page",
G_CALLBACK(gtk_print_signal_draw_page), NULL);
g_signal_connect(print_op, "end_print",
- G_CALLBACK(gtk_print_signal_end_print), settings);
- if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN)
+ G_CALLBACK(gtk_print_signal_end_print), nssettings);
+
+ if (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN) {
res = gtk_print_operation_run(print_op,
GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
g->window,
NULL);
+ }
/* if the settings were used save them for future use */
- if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
- /* Don't ref the settings, as we don't want to own them */
- gtk_print_settings = gtk_print_operation_get_print_settings(
- print_op);
-
- gtk_print_settings_to_file(gtk_print_settings,
- print_options_file_location, NULL);
+ if (settings_fname != NULL) {
+ if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+ /* Do not increment the settings reference */
+ print_settings =
+ gtk_print_operation_get_print_settings(print_op);
+
+ gtk_print_settings_to_file(print_settings,
+ settings_fname,
+ NULL);
+ }
+ free(settings_fname);
}
/* Our print_settings object is destroyed by the end print handler */
@@ -1249,6 +1260,7 @@ MULTIHANDLER(downloads)
MULTIHANDLER(savewindowsize)
{
int x,y,w,h;
+ char *choices;
gtk_window_get_position(g->window, &x, &y);
gtk_window_get_size(g->window, &w, &h);
@@ -1258,7 +1270,11 @@ MULTIHANDLER(savewindowsize)
nsoption_set_int(window_x, x);
nsoption_set_int(window_y, y);
- nsoption_write(options_file_location, NULL, NULL);
+ choices = filepath_append(nsgtk_config_home, "Choices");
+ if (choices != NULL) {
+ nsoption_write(choices, NULL, NULL);
+ free(choices);
+ }
return TRUE;
}
diff --git a/utils/errors.h b/utils/errors.h
index c38e4b9..4c02adb 100644
--- a/utils/errors.h
+++ b/utils/errors.h
@@ -37,6 +37,8 @@ typedef enum {
NSERROR_NOT_FOUND, /**< Requested item not found */
+ NSERROR_NOT_DIRECTORY, /**< Missing directory */
+
NSERROR_SAVE_FAILED, /**< Failed to save data */
NSERROR_CLONE_FAILED, /**< Failed to clone handle */
@@ -69,7 +71,9 @@ typedef enum {
NSERROR_BAD_CONTENT, /**< Bad Content */
- NSERROR_FRAME_DEPTH /**< Exceeded frame depth */
+ NSERROR_FRAME_DEPTH, /**< Exceeded frame depth */
+
+ NSERROR_PERMISSION /**< Permission error */
} nserror;
#endif
diff --git a/utils/filepath.c b/utils/filepath.c
index d088777..d82dfc6 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -202,7 +202,13 @@ filepath_generate(char * const *pathv, const char * const *langv)
return respath;
}
-/* expand ${} in a string into environment variables */
+/**
+ * expand ${} in a string into environment variables.
+ *
+ * @param path The pathname to expand.
+ * @param pathlen The length of the path element.
+ * @return A string with the expanded path or NULL on empty expansion or error.
+ */
static char *
expand_path(const char *path, int pathlen)
{
@@ -317,3 +323,80 @@ void filepath_free_strvec(char **pathv)
}
free(pathv);
}
+
+/* exported interface documented in filepath.h */
+char *filepath_append(const char *path, const char *leaf)
+{
+ int dirname_len;
+ char *dirname;
+
+ if ((path == NULL) || (leaf == NULL)) {
+ return NULL;
+ }
+
+ dirname_len = strlen(path) + strlen(leaf) + 2;
+ dirname = malloc(dirname_len);
+ if (dirname != NULL) {
+ snprintf(dirname, dirname_len, "%s/%s", path, leaf);
+ }
+
+ return dirname;
+}
+
+/* exported interface documented in filepath.h */
+nserror filepath_mkdir_all(const char *fname)
+{
+ char *dname;
+ char *sep;
+ struct stat sb;
+
+ dname = strdup(fname);
+
+ sep = strrchr(dname, '/');
+ if (sep == NULL) {
+ /* no directory separator path is just filename so its ok */
+ free(dname);
+ return NSERROR_OK;
+ }
+
+ *sep = 0; /* null terminate directory path */
+
+ if (stat(dname, &sb) == 0) {
+ free(dname);
+ if (S_ISDIR(sb.st_mode)) {
+ /* path to file exists and is a directory */
+ return NSERROR_OK;
+ }
+ return NSERROR_NOT_DIRECTORY;
+ }
+ *sep = '/'; /* restore separator */
+
+ sep = dname;
+ while (*sep == '/') {
+ sep++;
+ }
+ while ((sep = strchr(sep, '/')) != NULL) {
+ *sep = 0;
+ if (stat(dname, &sb) != 0) {
+ if (mkdir(dname, S_IRWXU) != 0) {
+ /* could not create path element */
+ free(dname);
+ return NSERROR_NOT_FOUND;
+ }
+ } else {
+ if (! S_ISDIR(sb.st_mode)) {
+ /* path element not a directory */
+ free(dname);
+ return NSERROR_NOT_DIRECTORY;
+ }
+ }
+ *sep = '/'; /* restore separator */
+ /* skip directory separators */
+ while (*sep == '/') {
+ sep++;
+ }
+ }
+
+ free(dname);
+ return NSERROR_OK;
+}
diff --git a/utils/filepath.h b/utils/filepath.h
index ff3ebe9..56e9eff 100644
--- a/utils/filepath.h
+++ b/utils/filepath.h
@@ -16,9 +16,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-/**
- * \file utils/filepath.h
- * \brief Utility routines to obtain paths to file resources.
+/**
+ * @file utils/filepath.h
+ * @brief Utility routines to obtain paths to file resources.
*/
#ifndef _NETSURF_UTILS_FILEPATH_H_
@@ -26,8 +26,10 @@
#include <stdarg.h>
+#include "utils/errors.h"
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* If the file described by the format exists and is accessible the
* normalised path is placed in str and a pointer to str returned
@@ -43,14 +45,16 @@
char *filepath_vsfindfile(char *str, const char *format, va_list ap);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to vsfindfile but takes variadic (printf like) parameters
*/
char *filepath_sfindfile(char *str, const char *format, ...);
-/** Create a normalised file name.
+/**
+ * Create a normalised file name.
*
* Similar to sfindfile but allocates its own storage for the
* returned string. The caller must free this sorage.
@@ -58,7 +62,8 @@ char *filepath_sfindfile(char *str, const char *format, ...);
char *filepath_findfile(const char *format, ...);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Iterates through a vector of resource paths and returns the
* normalised file name of the first acessible file or NULL if no file
@@ -72,7 +77,8 @@ char *filepath_findfile(const char *format, ...);
char *filepath_sfind(char **respathv, char *filepath, const char *filename);
-/** Searches an array of resource paths for a file.
+/**
+ * Searches an array of resource paths for a file.
*
* Similar to filepath_sfind except it allocates its own storage for
* the returned string. The caller must free this sorage.
@@ -80,7 +86,8 @@ char *filepath_sfind(char **respathv, char *filepath, const char *filename);
char *filepath_find(char **respathv, const char *filename);
-/** Searches an array of resource paths for a file optionally forcing a default.
+/**
+ * Searches an array of resource paths for a file optionally forcing a default.
*
* Similar to filepath_sfind except if no resource is found the default
* is used as an additional path element to search, if that still
@@ -91,7 +98,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
const char *def);
-/** Merge two string vectors into a resource search path vector.
+/**
+ * Merge two string vectors into a resource search path vector.
*
* @param pathv A string vector containing path elemets to scan.
* @param langv A string vector containing language names to enumerate.
@@ -101,7 +109,8 @@ char *filepath_sfinddef(char **respathv, char *filepath, const char *filename,
char **filepath_generate(char * const *pathv, const char * const *langv);
-/** Convert a colon separated list of path elements into a string vector.
+/**
+ * Convert a colon separated list of path elements into a string vector.
*
* @param path A colon separated path.
* @return A pointer to a NULL terminated string vector of valid
@@ -110,10 +119,32 @@ char **filepath_generate(char * const *pathv, const char * const *langv);
char **filepath_path_to_strvec(const char *path);
-/** Free a string vector
+/**
+ * Free a string vector.
*
* Free a string vector allocated by filepath_path_to_strvec
*/
void filepath_free_strvec(char **pathv);
+
+/**
+ * generate a new filename from a path and leaf.
+ *
+ * @param path The base path.
+ * @param leaf The leaf to add.
+ * @return The combined path in a new string must be freed by caller
+ * or NULL on failiure to allocte memory.
+ */
+char *filepath_append(const char *path, const char *leaf);
+
+
+/**
+ * Ensure that all directory elements needed to store a filename exist.
+ *
+ * @param fname The filename to ensure the path to exists.
+ * @return NSERROR_OK on success or error code on failure.
+ */
+nserror filepath_mkdir_all(const char *fname);
+
+
#endif /* _NETSURF_UTILS_FILEPATH_H_ */
--
NetSurf Browser
9 years, 1 month
netsurf-website: branch master updated. 5e7269550d57618ac40c5c1eaa7fd819713d1b33
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-website.git/shortlog/5e7269550d576...
...commit http://git.netsurf-browser.org/netsurf-website.git/commit/5e7269550d57618...
...tree http://git.netsurf-browser.org/netsurf-website.git/tree/5e7269550d57618ac...
The branch, master has been updated
via 5e7269550d57618ac40c5c1eaa7fd819713d1b33 (commit)
from bcb8a3b22e04747b29e9c9420c6c2ec796190a7d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-website.git/commit/?id=5e7269550d5...
commit 5e7269550d57618ac40c5c1eaa7fd819713d1b33
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Correct download file sizes and path.
diff --git a/downloads/riscos/index.en b/downloads/riscos/index.en
index 205abf0..3dd548b 100644
--- a/downloads/riscos/index.en
+++ b/downloads/riscos/index.en
@@ -63,7 +63,7 @@
<div class="downloadlatestouter">
<div class="downloadlatest">
<div class="downloadlatestbox">
-<p class="downloadmain downloadfirst"><a href="http://download.netsurf-browser.org/netsurf/releases/pre-built/riscos/net..."><span>NetSurf 3.1 for RISC OS</span> <span>(2.8MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
+<p class="downloadmain downloadfirst"><a href="http://download.netsurf-browser.org/netsurf/releases/pre-built/riscos/net..."><span>NetSurf 3.1 for RISC OS</span> <span>(3.3MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
<p class="downloadinstructions"><a href="/documentation/roinfo#GettingStartedInstallation">Installation instructions</a></p>
<p class="preul">Binary download includes:</p>
<ul>
@@ -81,7 +81,7 @@
</div>
<div class="downloadlatestbox downloadlast">
-<p class="downloadmain"><a href="http://download.netsurf-browser.org/netsurf/releases/source/netsurf-3.1-s..."><span>NetSurf 3.1 source code</span> <span>(2.5MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
+<p class="downloadmain"><a href="http://download.netsurf-browser.org/netsurf/releases/source/netsurf-3.1-s..."><span>NetSurf 3.1 source code</span> <span>(2.9MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
<p class="preul">Build NetSurf for:</p>
<ul>
diff --git a/downloads/source/index.en b/downloads/source/index.en
index baa0ff4..c90ebd5 100644
--- a/downloads/source/index.en
+++ b/downloads/source/index.en
@@ -56,7 +56,7 @@
<p>The source code for each release version of NetSurf is available.</p>
<ul>
-<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.1 source code</a> (26 Apr 2014)</li>
+<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.1 source code</a> (26 Apr 2014)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.0 source code</a> (20 Apr 2013)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 2.9 source code</a> (27 Mar 2012)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 2.8 source code</a> (21 Sep 2011)</li>
-----------------------------------------------------------------------
Summary of changes:
downloads/riscos/index.en | 4 ++--
downloads/source/index.en | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/downloads/riscos/index.en b/downloads/riscos/index.en
index 205abf0..3dd548b 100644
--- a/downloads/riscos/index.en
+++ b/downloads/riscos/index.en
@@ -63,7 +63,7 @@
<div class="downloadlatestouter">
<div class="downloadlatest">
<div class="downloadlatestbox">
-<p class="downloadmain downloadfirst"><a href="http://download.netsurf-browser.org/netsurf/releases/pre-built/riscos/net..."><span>NetSurf 3.1 for RISC OS</span> <span>(2.8MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
+<p class="downloadmain downloadfirst"><a href="http://download.netsurf-browser.org/netsurf/releases/pre-built/riscos/net..."><span>NetSurf 3.1 for RISC OS</span> <span>(3.3MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
<p class="downloadinstructions"><a href="/documentation/roinfo#GettingStartedInstallation">Installation instructions</a></p>
<p class="preul">Binary download includes:</p>
<ul>
@@ -81,7 +81,7 @@
</div>
<div class="downloadlatestbox downloadlast">
-<p class="downloadmain"><a href="http://download.netsurf-browser.org/netsurf/releases/source/netsurf-3.1-s..."><span>NetSurf 3.1 source code</span> <span>(2.5MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
+<p class="downloadmain"><a href="http://download.netsurf-browser.org/netsurf/releases/source/netsurf-3.1-s..."><span>NetSurf 3.1 source code</span> <span>(2.9MB)</span> <span class="downloaddate">26 Apr 2014</span></a></p>
<p class="downloadinstructions"><a href="/downloads/source/#BuildInstructions">Build instructions</a></p>
<p class="preul">Build NetSurf for:</p>
<ul>
diff --git a/downloads/source/index.en b/downloads/source/index.en
index baa0ff4..c90ebd5 100644
--- a/downloads/source/index.en
+++ b/downloads/source/index.en
@@ -56,7 +56,7 @@
<p>The source code for each release version of NetSurf is available.</p>
<ul>
-<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.1 source code</a> (26 Apr 2014)</li>
+<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.1 source code</a> (26 Apr 2014)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 3.0 source code</a> (20 Apr 2013)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 2.9 source code</a> (27 Mar 2012)</li>
<li><a href="http://download.netsurf-browser.org/netsurf/releases/source-full/netsurf-...">NetSurf 2.8 source code</a> (21 Sep 2011)</li>
--
NetSurf website source for *.netsurf-browser.org
9 years, 1 month
libsvgtiny: branch master updated. release/0.1.1-1-g21b4836
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/libsvgtiny.git/shortlog/21b4836ac9d6c67255...
...commit http://git.netsurf-browser.org/libsvgtiny.git/commit/21b4836ac9d6c6725590...
...tree http://git.netsurf-browser.org/libsvgtiny.git/tree/21b4836ac9d6c6725590a9...
The branch, master has been updated
via 21b4836ac9d6c6725590a925daa5d17eda9843e9 (commit)
from 7ef85fcc24ca9220427d0276a7b60ed8ba40ff95 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/libsvgtiny.git/commit/?id=21b4836ac9d6c672...
commit 21b4836ac9d6c6725590a925daa5d17eda9843e9
Author: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Commit: Daniel Silverstone <dsilvers(a)digital-scurf.org>
Hopefully silence warnings about inlines and non inlines calling one
another.
diff --git a/src/colors.gperf b/src/colors.gperf
index 89152d2..96d5b9e 100644
--- a/src/colors.gperf
+++ b/src/colors.gperf
@@ -16,6 +16,15 @@
#include <string.h>
#include "svgtiny.h"
#include "svgtiny_internal.h"
+
+/* This unusual define shennanigan is to try and prevent the gperf
+ * generated function from being inlined. This is pointless given
+ * it (a) is in a separate .c file and (b) has external linkage.
+ */
+#ifdef __inline
+#undef __inline
+#define __inline
+#endif
%}
struct svgtiny_named_color;
-----------------------------------------------------------------------
Summary of changes:
src/colors.gperf | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/src/colors.gperf b/src/colors.gperf
index 89152d2..96d5b9e 100644
--- a/src/colors.gperf
+++ b/src/colors.gperf
@@ -16,6 +16,15 @@
#include <string.h>
#include "svgtiny.h"
#include "svgtiny_internal.h"
+
+/* This unusual define shennanigan is to try and prevent the gperf
+ * generated function from being inlined. This is pointless given
+ * it (a) is in a separate .c file and (b) has external linkage.
+ */
+#ifdef __inline
+#undef __inline
+#define __inline
+#endif
%}
struct svgtiny_named_color;
--
NetSurf SVG decoder
9 years, 1 month
netsurf-all: branch master updated. release/3.1-6-gef5ffaf
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-all.git/shortlog/ef5ffaf00951a72d4...
...commit http://git.netsurf-browser.org/netsurf-all.git/commit/ef5ffaf00951a72d45d...
...tree http://git.netsurf-browser.org/netsurf-all.git/tree/ef5ffaf00951a72d45d82...
The branch, master has been updated
via ef5ffaf00951a72d45d8280b6f75302058b106fd (commit)
from 46840d2c35febda16867844c2c25917492eb9eef (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-all.git/commit/?id=ef5ffaf00951a72...
commit ef5ffaf00951a72d45d8280b6f75302058b106fd
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
add package target
diff --git a/Makefile b/Makefile
index 975e0a3..1fb4fba 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,9 @@ endif
$(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET)
touch $@
+package: $(TMP_PREFIX)/build-stamp
+ $(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET) package
+
install: $(TMP_PREFIX)/build-stamp
$(MAKE) install --directory=$(NETSURF_TARG) TARGET=$(TARGET) PREFIX=$(PREFIX) DESTDIR=$(DESTDIR)
-----------------------------------------------------------------------
Summary of changes:
Makefile | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
index 975e0a3..1fb4fba 100644
--- a/Makefile
+++ b/Makefile
@@ -47,6 +47,9 @@ endif
$(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET)
touch $@
+package: $(TMP_PREFIX)/build-stamp
+ $(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET) package
+
install: $(TMP_PREFIX)/build-stamp
$(MAKE) install --directory=$(NETSURF_TARG) TARGET=$(TARGET) PREFIX=$(PREFIX) DESTDIR=$(DESTDIR)
--
NetSurf 'all' tree. Typically used for releases
9 years, 1 month
netsurf-all: branch master updated. release/3.1-5-g46840d2
by NetSurf Browser Project
Gitweb links:
...log http://git.netsurf-browser.org/netsurf-all.git/shortlog/46840d2c35febda16...
...commit http://git.netsurf-browser.org/netsurf-all.git/commit/46840d2c35febda1686...
...tree http://git.netsurf-browser.org/netsurf-all.git/tree/46840d2c35febda168678...
The branch, master has been updated
via 46840d2c35febda16867844c2c25917492eb9eef (commit)
via 663bc87911cb8d2d63b3f5b3791a1d0199db9f88 (commit)
from 1814d2c431e221545e0a3c3a34566f97eed265d1 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commitdiff http://git.netsurf-browser.org/netsurf-all.git/commit/?id=46840d2c35febda...
commit 46840d2c35febda16867844c2c25917492eb9eef
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
update revisions for RISCOS libs for 3.1 release
diff --git a/libpencil b/libpencil
index ec183ab..bb8c0f1 160000
--- a/libpencil
+++ b/libpencil
@@ -1 +1 @@
-Subproject commit ec183abb7864c5ec35cdeae87feaa74be6e6bb3e
+Subproject commit bb8c0f1b0eed9443db1037382782d9ab90e1218b
diff --git a/librufl b/librufl
index e9b4a06..9392f7f 160000
--- a/librufl
+++ b/librufl
@@ -1 +1 @@
-Subproject commit e9b4a065e0d0975d9ec4ba655cf321834665514a
+Subproject commit 9392f7f5f4fd3bc246c3ec63ba22b699298f427f
commitdiff http://git.netsurf-browser.org/netsurf-all.git/commit/?id=663bc87911cb8d2...
commit 663bc87911cb8d2d63b3f5b3791a1d0199db9f88
Author: Vincent Sanders <vince(a)kyllikki.org>
Commit: Vincent Sanders <vince(a)kyllikki.org>
allow for RISC OS extra libraries
diff --git a/Makefile b/Makefile
index 08971db..975e0a3 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,8 @@ NSGENBIND_TARG := nsgenbind
NSLIB_TARG := buildsystem libwapcaplet libparserutils libcss libhubbub libdom libnsbmp libnsgif librosprite libnsfb libsvgtiny
+NSLIB_RO_TARG := librufl libpencil
+
# clean macro for each sub target
define do_clean
$(MAKE) distclean --directory=$1 TARGET=$(TARGET)
@@ -38,6 +40,9 @@ $(TMP_PREFIX)/build-stamp:
mkdir -p $(TMP_PREFIX)/lib
mkdir -p $(TMP_PREFIX)/bin
$(foreach L,$(NSLIB_TARG),$(call do_prefix_install,$(L)))
+ifeq ($(TARGET),riscos)
+ $(foreach L,$(NSLIB_RO_TARG),$(call do_prefix_install,$(L)))
+endif
$(MAKE) install --directory=$(NSGENBIND_TARG) PREFIX=$(TMP_PREFIX) TARGET=$(shell uname -s)
$(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET)
touch $@
@@ -48,10 +53,13 @@ install: $(TMP_PREFIX)/build-stamp
clean:
$(RM) -r $(TMP_PREFIX)
$(foreach L,$(NSLIB_TARG),$(call do_clean,$(L)))
+ifeq ($(TARGET),riscos)
+ $(foreach L,$(NSLIB_RO_TARG),$(call do_clean,$(L)))
+endif
$(MAKE) clean --directory=$(NSGENBIND_TARG) TARGET=$(TARGET)
$(MAKE) clean --directory=$(NETSURF_TARG) TARGET=$(TARGET)
-release-checkout: $(NSLIB_TARG) $(NETSURF_TARG) $(NSGENBIND_TARG)
+release-checkout: $(NSLIB_TARG) $(NETSURF_TARG) $(NSGENBIND_TARG) $(NSLIB_RO_TARG)
for x in $^; do cd $$x; (git checkout origin/HEAD && git checkout $$(git describe --abbrev=0 --match="release/*" )); cd ..; done
dist:
-----------------------------------------------------------------------
Summary of changes:
Makefile | 10 +++++++++-
libpencil | 2 +-
librufl | 2 +-
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/Makefile b/Makefile
index 08971db..975e0a3 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,8 @@ NSGENBIND_TARG := nsgenbind
NSLIB_TARG := buildsystem libwapcaplet libparserutils libcss libhubbub libdom libnsbmp libnsgif librosprite libnsfb libsvgtiny
+NSLIB_RO_TARG := librufl libpencil
+
# clean macro for each sub target
define do_clean
$(MAKE) distclean --directory=$1 TARGET=$(TARGET)
@@ -38,6 +40,9 @@ $(TMP_PREFIX)/build-stamp:
mkdir -p $(TMP_PREFIX)/lib
mkdir -p $(TMP_PREFIX)/bin
$(foreach L,$(NSLIB_TARG),$(call do_prefix_install,$(L)))
+ifeq ($(TARGET),riscos)
+ $(foreach L,$(NSLIB_RO_TARG),$(call do_prefix_install,$(L)))
+endif
$(MAKE) install --directory=$(NSGENBIND_TARG) PREFIX=$(TMP_PREFIX) TARGET=$(shell uname -s)
$(MAKE) --directory=$(NETSURF_TARG) PREFIX=$(PREFIX) TARGET=$(TARGET)
touch $@
@@ -48,10 +53,13 @@ install: $(TMP_PREFIX)/build-stamp
clean:
$(RM) -r $(TMP_PREFIX)
$(foreach L,$(NSLIB_TARG),$(call do_clean,$(L)))
+ifeq ($(TARGET),riscos)
+ $(foreach L,$(NSLIB_RO_TARG),$(call do_clean,$(L)))
+endif
$(MAKE) clean --directory=$(NSGENBIND_TARG) TARGET=$(TARGET)
$(MAKE) clean --directory=$(NETSURF_TARG) TARGET=$(TARGET)
-release-checkout: $(NSLIB_TARG) $(NETSURF_TARG) $(NSGENBIND_TARG)
+release-checkout: $(NSLIB_TARG) $(NETSURF_TARG) $(NSGENBIND_TARG) $(NSLIB_RO_TARG)
for x in $^; do cd $$x; (git checkout origin/HEAD && git checkout $$(git describe --abbrev=0 --match="release/*" )); cd ..; done
dist:
diff --git a/libpencil b/libpencil
index ec183ab..bb8c0f1 160000
--- a/libpencil
+++ b/libpencil
@@ -1 +1 @@
-Subproject commit ec183abb7864c5ec35cdeae87feaa74be6e6bb3e
+Subproject commit bb8c0f1b0eed9443db1037382782d9ab90e1218b
diff --git a/librufl b/librufl
index e9b4a06..9392f7f 160000
--- a/librufl
+++ b/librufl
@@ -1 +1 @@
-Subproject commit e9b4a065e0d0975d9ec4ba655cf321834665514a
+Subproject commit 9392f7f5f4fd3bc246c3ec63ba22b699298f427f
--
NetSurf 'all' tree. Typically used for releases
9 years, 1 month