Gitweb links:
...log
http://git.netsurf-browser.org/netsurf.git/shortlog/7996c29b0c3df81d37ed6...
...commit
http://git.netsurf-browser.org/netsurf.git/commit/7996c29b0c3df81d37ed686...
...tree
http://git.netsurf-browser.org/netsurf.git/tree/7996c29b0c3df81d37ed686fd...
The branch, tlsa/nsurl has been updated
discards e1f12eeaa22c529cfd96a53ee26976e6a5c71a52 (commit)
discards 3c4906859fe457fc4890889a3b88368e0b355995 (commit)
discards e9768b4d0c9093a4b70089ac942ee26d6603d5d1 (commit)
discards fdd9fae30549f5321aada39c7696107392bd6afd (commit)
discards 400c6e658f284c95d9b1cd18dd1d5841305b8ddc (commit)
discards da6e045c669ab1241b49b396484eb2666e16afba (commit)
discards 58d16d68188e445cf59c7f4d455f1e1ddaf78aef (commit)
via 7996c29b0c3df81d37ed686fd6fd8f5d28f92981 (commit)
via 3f5d8d1a2e844c8833eeb046fd7a84b72a3d3a1f (commit)
via 5c8f4c9c8c98c0af71dfb2e41d8947a6edf09f47 (commit)
via 91a7fffd5637574aea7a1b52308968a99dee888c (commit)
via 2acd90e28a37a80f20e2780be7972764c699d9a0 (commit)
via 95e5ede775fc842324b87d797ca00c7576b9a359 (commit)
via 4c47f9c04626811e455bee76fd15622bd8dc6ca0 (commit)
via 299a85fa7a4ee259e757b8ffd6e482410e6726f1 (commit)
via f1c98ccfa404f1890fa6299a69b165a226dc4d35 (commit)
via 57fec3504f29753128204bbf03cc92767f501fd4 (commit)
via 8e9751d3b6cd555119ca195e6751c2675beb3b7d (commit)
via 2858aec1c2bf32d0793cbafff6849cf91625b31b (commit)
via 51062e55b00b8b307d9f45cb150dcefa4d710cfc (commit)
via 4b3f2bb946ad201f99a20ddaff980ecea05e5ebc (commit)
via 108cc0cebdca9a3300c9b524d3409eb10fa09b05 (commit)
via 10f1b7a1aaec183defb6ae724576910494026954 (commit)
via 1f52b2d514ac12bfbcb97f4ed3eb556d5e38739d (commit)
via b23f55c81bca21de7841111ace809df0f6408d65 (commit)
via e96bf013394c0dd06cb25e666e8c68d22c12a318 (commit)
via 6075feb4875ed2035de460fcdc7858f314ad0bef (commit)
via 11f11e0a7f8f7dd03d5b1fc22a8e54af305fbe6f (commit)
via 10248264ff43a917dd18796daa61ee5a5f1229d5 (commit)
via d1246c20612c6f6ad23b0e47497949bf2c0ec0a6 (commit)
via 70d700b26c13e04b601c4ac3db09514db473d01c (commit)
via a99c7a5c44fdd3f6ee1a0ec2b9beb5a1d6a32501 (commit)
via 2083375ec45d159a916caee3b7b570aa6670684c (commit)
via 53ce28c170ac5264405a7a12a718cf57a382518d (commit)
via d871be3ea00ef74ab28b936526768bbf121e3eb0 (commit)
via d843f78c202900409b0cd0c16397f6dae77bbe2b (commit)
via 9e814fd0f0f03584debb43b6d8acf144bd8675a2 (commit)
via b78d6f458e5d5cb9c78d7430aacf10abd227eb32 (commit)
via b8640956d48af03f2f7f6c07e66958fa825a4972 (commit)
via 8e7603e6a263eb765df4886a321537f209d88245 (commit)
via 606cc0c2196f5934a7c48e89ab05da7d5e05081f (commit)
via 52f98c9fb2b3dc04412ad25b7c24fa8cf357e78d (commit)
via 24fed9d51ccf3e786e59983ae84b4f13e68b0ea4 (commit)
via b6f7ea536cececaa07fb2c46c129675d91167177 (commit)
via e4d6d9a972736bbea70eb0af62a430e77cc05ee5 (commit)
via 313aaabdde2e6f0bb1f0dfe571b77261cc697a95 (commit)
via 9f10babe645fe67b02fae90f852d5e4cdfcbb70e (commit)
via 0d9023148d2a34bd908aac38e44d449359b03438 (commit)
via 439deddba14f509fa0be90beff07481643178b69 (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 (e1f12eeaa22c529cfd96a53ee26976e6a5c71a52)
\
N -- N -- N (7996c29b0c3df81d37ed686fd6fd8f5d28f92981)
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=7996c29b0c3df81d37e...
commit 7996c29b0c3df81d37ed686fd6fd8f5d28f92981
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
Test: Fix up for rearranged nsurl source.
diff --git a/test/Makefile b/test/Makefile
index d5e9d00..1f884dc 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -13,12 +13,15 @@ TESTS := \
time #llcache
# nsurl sources
-nsurl_SRCS := utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
+nsurl_SRCS := utils/corestrings.c utils/nsurl/nsurl.c \
+ utils/nsurl/parse.c \
+ utils/idna.c utils/punycode.c \
test/log.c test/nsurl.c
# url database test sources
urldbtest_SRCS := content/urldb.c \
- utils/idna.c utils/bloom.c utils/nsoption.c utils/nsurl.c \
+ utils/idna.c utils/bloom.c utils/nsoption.c \
+ utils/nsurl/nsurl.c utils/nsurl/parse.c \
utils/corestrings.c utils/punycode.c \
utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
test/log.c test/urldbtest.c
@@ -30,7 +33,8 @@ llcache_SRCS := content/fetch.c content/fetchers/curl.c \
content/urldb.c \
image/image_cache.c \
utils/base64.c utils/corestrings.c utils/hashtable.c \
- utils/nsurl.c utils/messages.c utils/url.c utils/useragent.c \
+ utils/nsurl/nsurl.c utils/nsurl/parse.c \
+ utils/messages.c utils/url.c utils/useragent.c \
utils/utils.c \
test/log.c test/llcache.c
@@ -51,7 +55,8 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/nsurl.c utils/idna.c utils/punycode.c \
+ utils/corestrings.c utils/nsurl/nsurl.c \
+ utils/nsurl/parse.c utils/idna.c utils/punycode.c \
test/log.c test/utils.c
# time test sources
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=3f5d8d1a2e844c8833e...
commit 3f5d8d1a2e844c8833eeb046fd7a84b72a3d3a1f
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Tidy up shared components code.
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index 68188fb..7166a27 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -63,39 +63,6 @@
}
-/**
- * Destroy components
- *
- * \param c url components
- */
-static void nsurl_destroy_components(struct nsurl_components *c)
-{
- if (c->scheme)
- lwc_string_unref(c->scheme);
-
- if (c->username)
- lwc_string_unref(c->username);
-
- if (c->password)
- lwc_string_unref(c->password);
-
- if (c->host)
- lwc_string_unref(c->host);
-
- if (c->port)
- lwc_string_unref(c->port);
-
- if (c->path)
- lwc_string_unref(c->path);
-
- if (c->query)
- lwc_string_unref(c->query);
-
- if (c->fragment)
- lwc_string_unref(c->fragment);
-}
-
-
/******************************************************************************
* NetSurf URL Public API *
@@ -126,7 +93,7 @@ void nsurl_unref(nsurl *url)
#endif
/* Release lwc strings */
- nsurl_destroy_components(&url->components);
+ nsurl__components_destroy(&url->components);
/* Free the NetSurf URL */
free(url);
@@ -219,7 +186,8 @@ nserror nsurl_get(const nsurl *url, nsurl_component parts,
{
assert(url != NULL);
- return nsurl__string(&(url->components), parts, 0, url_s, url_l);
+ return nsurl__components_to_string(&(url->components), parts, 0,
+ url_s, url_l);
}
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
index 6ec02fc..89a10d2 100644
--- a/utils/nsurl/parse.c
+++ b/utils/nsurl/parse.c
@@ -1169,7 +1169,7 @@ static void nsurl__get_string(const struct nsurl_components *url,
char *url_s,
/* exported interface, documented in nsurl.h */
-nserror nsurl__string(
+nserror nsurl__components_to_string(
const struct nsurl_components *components,
nsurl_component parts, size_t pre_padding,
char **url_s_out, size_t *url_l_out)
@@ -1239,39 +1239,6 @@ void nsurl__calc_hash(nsurl *url)
}
-/**
- * Destroy components
- *
- * \param c url components
- */
-static void nsurl_destroy_components(struct nsurl_components *c)
-{
- if (c->scheme)
- lwc_string_unref(c->scheme);
-
- if (c->username)
- lwc_string_unref(c->username);
-
- if (c->password)
- lwc_string_unref(c->password);
-
- if (c->host)
- lwc_string_unref(c->host);
-
- if (c->port)
- lwc_string_unref(c->port);
-
- if (c->path)
- lwc_string_unref(c->path);
-
- if (c->query)
- lwc_string_unref(c->query);
-
- if (c->fragment)
- lwc_string_unref(c->fragment);
-}
-
-
/******************************************************************************
* NetSurf URL Public API *
******************************************************************************/
@@ -1314,7 +1281,7 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
free(buff);
if (e != NSERROR_OK) {
- nsurl_destroy_components(&c);
+ nsurl__components_destroy(&c);
return NSERROR_NOMEM;
}
@@ -1325,12 +1292,12 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
&match) == lwc_error_ok && match == true)) {
/* http, https must have host */
if (c.host == NULL) {
- nsurl_destroy_components(&c);
+ nsurl__components_destroy(&c);
return NSERROR_BAD_URL;
}
}
- e = nsurl__string(&c, NSURL_WITH_FRAGMENT,
+ e = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT,
sizeof(nsurl), (char **)url, &length);
if (e != NSERROR_OK) {
return e;
@@ -1568,7 +1535,7 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl
**joined)
return error;
}
- error = nsurl__string(&c, NSURL_WITH_FRAGMENT,
+ error = nsurl__components_to_string(&c, NSURL_WITH_FRAGMENT,
sizeof(nsurl), (char **)joined, &length);
if (error != NSERROR_OK) {
return error;
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index 67945e2..e78f830 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -128,7 +128,7 @@ enum nsurl_string_flags {
* \param[out] url_l_out Returns byte length of string, excluding pre_padding.
* \return NSERROR_OK on success, appropriate error otherwise.
*/
-nserror nsurl__string(
+nserror nsurl__components_to_string(
const struct nsurl_components *components,
nsurl_component parts, size_t pre_padding,
char **url_s_out, size_t *url_l_out);
@@ -142,6 +142,41 @@ void nsurl__calc_hash(nsurl *url);
+
+/**
+ * Destroy components
+ *
+ * \param c url components
+ */
+static inline void nsurl__components_destroy(struct nsurl_components *c)
+{
+ if (c->scheme)
+ lwc_string_unref(c->scheme);
+
+ if (c->username)
+ lwc_string_unref(c->username);
+
+ if (c->password)
+ lwc_string_unref(c->password);
+
+ if (c->host)
+ lwc_string_unref(c->host);
+
+ if (c->port)
+ lwc_string_unref(c->port);
+
+ if (c->path)
+ lwc_string_unref(c->path);
+
+ if (c->query)
+ lwc_string_unref(c->query);
+
+ if (c->fragment)
+ lwc_string_unref(c->fragment);
+}
+
+
+
#ifdef NSURL_DEBUG
/**
* Dump a NetSurf URL's internal components
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=5c8f4c9c8c98c0af71d...
commit 5c8f4c9c8c98c0af71dfb2e41d8947a6edf09f47
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Rationalise debug build option.
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index 137a5ac..68188fb 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -46,9 +46,6 @@
#include "utils/nsurl.h"
#include "utils/utils.h"
-/* Define to enable NSURL debugging */
-#undef NSURL_DEBUG
-
/**
* Compare two component values.
@@ -99,39 +96,6 @@ static void nsurl_destroy_components(struct nsurl_components *c)
}
-#ifdef NSURL_DEBUG
-/**
- * Dump a NetSurf URL's internal components
- *
- * \param url The NetSurf URL to dump components of
- */
-static void nsurl__dump(const nsurl *url)
-{
- if (url->components.scheme)
- LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
-
- if (url->components.username)
- LOG("Username: %s", lwc_string_data(url->components.username));
-
- if (url->components.password)
- LOG("Password: %s", lwc_string_data(url->components.password));
-
- if (url->components.host)
- LOG(" Host: %s", lwc_string_data(url->components.host));
-
- if (url->components.port)
- LOG(" Port: %s", lwc_string_data(url->components.port));
-
- if (url->components.path)
- LOG(" Path: %s", lwc_string_data(url->components.path));
-
- if (url->components.query)
- LOG(" Query: %s", lwc_string_data(url->components.query));
-
- if (url->components.fragment)
- LOG("Fragment: %s", lwc_string_data(url->components.fragment));
-}
-#endif
/******************************************************************************
* NetSurf URL Public API *
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
index 2d74ea9..6ec02fc 100644
--- a/utils/nsurl/parse.c
+++ b/utils/nsurl/parse.c
@@ -46,9 +46,6 @@
#include "utils/nsurl/private.h"
#include "utils/utils.h"
-/* Define to enable NSURL debugging */
-#undef NSURL_DEBUG
-
/** Marker set, indicating positions of sections within a URL string */
struct url_markers {
@@ -1275,40 +1272,6 @@ static void nsurl_destroy_components(struct nsurl_components *c)
}
-#ifdef NSURL_DEBUG
-/**
- * Dump a NetSurf URL's internal components
- *
- * \param url The NetSurf URL to dump components of
- */
-static void nsurl__dump(const nsurl *url)
-{
- if (url->components.scheme)
- LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
-
- if (url->components.username)
- LOG("Username: %s", lwc_string_data(url->components.username));
-
- if (url->components.password)
- LOG("Password: %s", lwc_string_data(url->components.password));
-
- if (url->components.host)
- LOG(" Host: %s", lwc_string_data(url->components.host));
-
- if (url->components.port)
- LOG(" Port: %s", lwc_string_data(url->components.port));
-
- if (url->components.path)
- LOG(" Path: %s", lwc_string_data(url->components.path));
-
- if (url->components.query)
- LOG(" Query: %s", lwc_string_data(url->components.query));
-
- if (url->components.fragment)
- LOG("Fragment: %s", lwc_string_data(url->components.fragment));
-}
-#endif
-
/******************************************************************************
* NetSurf URL Public API *
******************************************************************************/
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index a5291af..67945e2 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -24,6 +24,11 @@
#include "utils/nsurl.h"
#include "utils/utils.h"
+
+/* Define to enable NSURL debugging */
+#undef NSURL_DEBUG
+
+
/** A type for URL schemes */
enum nsurl_scheme_type {
NSURL_SCHEME_OTHER,
@@ -135,4 +140,41 @@ nserror nsurl__string(
*/
void nsurl__calc_hash(nsurl *url);
+
+
+#ifdef NSURL_DEBUG
+/**
+ * Dump a NetSurf URL's internal components
+ *
+ * \param url The NetSurf URL to dump components of
+ */
+static inline void nsurl__dump(const nsurl *url)
+{
+ if (url->components.scheme)
+ LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
+
+ if (url->components.username)
+ LOG("Username: %s", lwc_string_data(url->components.username));
+
+ if (url->components.password)
+ LOG("Password: %s", lwc_string_data(url->components.password));
+
+ if (url->components.host)
+ LOG(" Host: %s", lwc_string_data(url->components.host));
+
+ if (url->components.port)
+ LOG(" Port: %s", lwc_string_data(url->components.port));
+
+ if (url->components.path)
+ LOG(" Path: %s", lwc_string_data(url->components.path));
+
+ if (url->components.query)
+ LOG(" Query: %s", lwc_string_data(url->components.query));
+
+ if (url->components.fragment)
+ LOG("Fragment: %s", lwc_string_data(url->components.fragment));
+}
+#endif
+
+
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=91a7fffd5637574aea7...
commit 91a7fffd5637574aea7a1b52308968a99dee888c
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Tidy up component helper macros.
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index 79dc716..137a5ac 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -50,8 +50,13 @@
#undef NSURL_DEBUG
-#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
-
+/**
+ * Compare two component values.
+ *
+ * Sets match to false if the components are not the same.
+ * Does nothing if the components are the same, so ensure match is
+ * preset to true.
+ */
#define nsurl__component_compare(c1, c2, match) \
if (c1 && c2 && lwc_error_ok == \
lwc_string_isequal(c1, c2, match)) { \
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
index e242689..2d74ea9 100644
--- a/utils/nsurl/parse.c
+++ b/utils/nsurl/parse.c
@@ -81,16 +81,6 @@ enum url_sections {
};
-#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
-
-#define nsurl__component_compare(c1, c2, match) \
- if (c1 && c2 && lwc_error_ok == \
- lwc_string_isequal(c1, c2, match)) { \
- /* do nothing */ \
- } else if (c1 || c2) { \
- *match = false; \
- }
-
/**
* Return a hex digit for the given numerical value.
*
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index bc3eb8c..a5291af 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -107,6 +107,11 @@ enum nsurl_string_flags {
NSURL_F_FRAGMENT = (1 << 11)
};
+/**
+ * NULL-safe lwc_string_ref
+ */
+#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
+
/**
* Convert a set of nsurl components to a single string
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=2acd90e28a37a80f20e...
commit 2acd90e28a37a80f20e2780be7972764c699d9a0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Consolidate conversion to string.
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index b60eb07..79dc716 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -248,29 +248,9 @@ bool nsurl_compare(const nsurl *url1, const nsurl *url2,
nsurl_component parts)
nserror nsurl_get(const nsurl *url, nsurl_component parts,
char **url_s, size_t *url_l)
{
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
-
assert(url != NULL);
- /* Get the string length and find which parts of url need copied */
- nsurl__get_string_data(&(url->components), parts, url_l,
- &str_len, &str_flags);
-
- if (*url_l == 0) {
- return NSERROR_BAD_URL;
- }
-
- /* Allocate memory for url string */
- *url_s = malloc(*url_l + 1); /* adding 1 for '\0' */
- if (*url_s == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Copy the required parts into the url string */
- nsurl__get_string(&(url->components), *url_s, &str_len, str_flags);
-
- return NSERROR_OK;
+ return nsurl__string(&(url->components), parts, 0, url_s, url_l);
}
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
index 0cdbbd4..e242689 100644
--- a/utils/nsurl/parse.c
+++ b/utils/nsurl/parse.c
@@ -997,8 +997,16 @@ static nserror nsurl__create_from_section(const char * const url_s,
}
-/* Exported function, documented in utils/nsurl/private.h */
-void nsurl__get_string_data(const struct nsurl_components *url,
+/**
+ * Get nsurl string info; total length, component lengths, & components present
+ *
+ * \param url NetSurf URL components
+ * \param parts Which parts of the URL are required in the string
+ * \param url_l Updated to total string length
+ * \param lengths Updated with individual component lengths
+ * \param pflags Updated to contain relevant string flags
+ */
+static void nsurl__get_string_data(const struct nsurl_components *url,
nsurl_component parts, size_t *url_l,
struct nsurl_component_lengths *lengths,
enum nsurl_string_flags *pflags)
@@ -1095,8 +1103,15 @@ void nsurl__get_string_data(const struct nsurl_components *url,
}
-/* Exported function, documented in utils/nsurl/private.h */
-void nsurl__get_string(const struct nsurl_components *url, char *url_s,
+/**
+ * Copy url string into provided buffer
+ *
+ * \param url NetSurf URL components
+ * \param url_s Updated to contain the string
+ * \param l Individual component lengths
+ * \param flags String flags
+ */
+static void nsurl__get_string(const struct nsurl_components *url, char *url_s,
struct nsurl_component_lengths *l,
enum nsurl_string_flags flags)
{
@@ -1166,6 +1181,43 @@ void nsurl__get_string(const struct nsurl_components *url, char
*url_s,
}
+/* exported interface, documented in nsurl.h */
+nserror nsurl__string(
+ const struct nsurl_components *components,
+ nsurl_component parts, size_t pre_padding,
+ char **url_s_out, size_t *url_l_out)
+{
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ size_t url_l;
+ char *url_s;
+
+ assert(components != NULL);
+
+ /* Get the string length and find which parts of url need copied */
+ nsurl__get_string_data(components, parts, &url_l,
+ &str_len, &str_flags);
+
+ if (url_l == 0) {
+ return NSERROR_BAD_URL;
+ }
+
+ /* Allocate memory for url string */
+ url_s = malloc(pre_padding + url_l + 1); /* adding 1 for '\0' */
+ if (url_s == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Copy the required parts into the url string */
+ nsurl__get_string(components, url_s + pre_padding, &str_len, str_flags);
+
+ *url_s_out = url_s;
+ *url_l_out = url_l;
+
+ return NSERROR_OK;
+}
+
+
/**
* Calculate hash value
*
@@ -1278,8 +1330,6 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
struct nsurl_components c;
size_t length;
char *buff;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
nserror e = NSERROR_OK;
bool match;
@@ -1327,23 +1377,15 @@ nserror nsurl_create(const char * const url_s, nsurl **url)
}
}
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*url == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
+ e = nsurl__string(&c, NSURL_WITH_FRAGMENT,
+ sizeof(nsurl), (char **)url, &length);
+ if (e != NSERROR_OK) {
+ return e;
}
(*url)->components = c;
(*url)->length = length;
- /* Fill out the url string */
- nsurl__get_string(&c, (*url)->string, &str_len, str_flags);
-
/* Get the nsurl's hash */
nsurl__calc_hash(*url);
@@ -1363,8 +1405,6 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl
**joined)
char *buff;
char *buff_pos;
char *buff_start;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
nserror error = 0;
enum {
NSURL_F_REL = 0,
@@ -1575,22 +1615,15 @@ nserror nsurl_join(const nsurl *base, const char *rel, nsurl
**joined)
return error;
}
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*joined == NULL) {
- return NSERROR_NOMEM;
+ error = nsurl__string(&c, NSURL_WITH_FRAGMENT,
+ sizeof(nsurl), (char **)joined, &length);
+ if (error != NSERROR_OK) {
+ return error;
}
(*joined)->components = c;
(*joined)->length = length;
- /* Fill out the url string */
- nsurl__get_string(&c, (*joined)->string, &str_len, str_flags);
-
/* Get the nsurl's hash */
nsurl__calc_hash(*joined);
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index f8ba51f..bc3eb8c 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -107,31 +107,21 @@ enum nsurl_string_flags {
NSURL_F_FRAGMENT = (1 << 11)
};
-/**
- * Get nsurl string info; total length, component lengths, & components present
- *
- * \param url NetSurf URL components
- * \param url_s Updated to contain the string
- * \param l Individual component lengths
- * \param flags String flags
- */
-void nsurl__get_string(const struct nsurl_components *url, char *url_s,
- struct nsurl_component_lengths *l,
- enum nsurl_string_flags flags);
/**
- * Get nsurl string info; total length, component lengths, & components present
+ * Convert a set of nsurl components to a single string
*
- * \param url NetSurf URL components
- * \param parts Which parts of the URL are required in the string
- * \param url_l Updated to total string length
- * \param lengths Updated with individual component lengths
- * \param pflags Updated to contain relevant string flags
+ * \param[in] components The URL components to stitch together.
+ * \param[in] parts The set of parts wanted in the string.
+ * \param[in] pre_padding Amount in bytes to pad the start of the string by.
+ * \param[out] url_s_out Returns allocated URL string.
+ * \param[out] url_l_out Returns byte length of string, excluding pre_padding.
+ * \return NSERROR_OK on success, appropriate error otherwise.
*/
-void nsurl__get_string_data(const struct nsurl_components *url,
- nsurl_component parts, size_t *url_l,
- struct nsurl_component_lengths *lengths,
- enum nsurl_string_flags *pflags);
+nserror nsurl__string(
+ const struct nsurl_components *components,
+ nsurl_component parts, size_t pre_padding,
+ char **url_s_out, size_t *url_l_out);
/**
* Calculate hash value
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=95e5ede775fc842324b...
commit 95e5ede775fc842324b87d797ca00c7576b9a359
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Split out URL parsing.
diff --git a/utils/nsurl/Makefile b/utils/nsurl/Makefile
index 08656f3..71304b2 100644
--- a/utils/nsurl/Makefile
+++ b/utils/nsurl/Makefile
@@ -1,6 +1,7 @@
# nsurl utils sources
S_NSURL := \
- nsurl.c
+ nsurl.c \
+ parse.c
S_NSURL := $(addprefix utils/nsurl/,$(S_NSURL))
\ No newline at end of file
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index bc77c58..b60eb07 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -50,71 +50,6 @@
#undef NSURL_DEBUG
-/** Marker set, indicating positions of sections within a URL string */
-struct url_markers {
- size_t start; /** start of URL */
- size_t scheme_end;
- size_t authority;
-
- size_t colon_first;
- size_t at;
- size_t colon_last;
-
- size_t path;
- size_t query;
- size_t fragment;
-
- size_t end; /** end of URL */
-
- enum nsurl_scheme_type scheme_type;
-};
-
-
-/** Marker set, indicating positions of sections within a URL string */
-struct nsurl_component_lengths {
- size_t scheme;
- size_t username;
- size_t password;
- size_t host;
- size_t port;
- size_t path;
- size_t query;
- size_t fragment;
-};
-
-
-/** Flags indicating which parts of a URL string are required for a nsurl */
-enum nsurl_string_flags {
- NSURL_F_SCHEME = (1 << 0),
- NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
- NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
- NSURL_F_USERNAME = (1 << 3),
- NSURL_F_PASSWORD = (1 << 4),
- NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
- NSURL_F_HOST = (1 << 6),
- NSURL_F_PORT = (1 << 7),
- NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
- NSURL_F_PASSWORD |
- NSURL_F_HOST |
- NSURL_F_PORT),
- NSURL_F_PATH = (1 << 8),
- NSURL_F_QUERY = (1 << 9),
- NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
- NSURL_F_FRAGMENT = (1 << 11)
-};
-
-
-/** Sections of a URL */
-enum url_sections {
- URL_SCHEME,
- URL_CREDENTIALS,
- URL_HOST,
- URL_PATH,
- URL_QUERY,
- URL_FRAGMENT
-};
-
-
#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
#define nsurl__component_compare(c1, c2, match) \
@@ -125,1129 +60,6 @@ enum url_sections {
*match = false; \
}
-/**
- * Return a hex digit for the given numerical value.
- *
- * \param digit the value to get the hex digit for.
- * \return character in range 0-9A-F
- */
-inline static char digit2uppercase_hex(unsigned char digit) {
- assert(digit < 16);
- return "0123456789ABCDEF"[digit];
-}
-
-/**
- * determine if a character is unreserved
- *
- * \param c character to classify.
- * \return true if the character is unreserved else false.
- */
-static bool nsurl__is_unreserved(unsigned char c)
-{
- /* From RFC3986 section 2.3 (unreserved characters)
- *
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" /
"~"
- *
- */
- static const bool unreserved[256] = {
- false, false, false, false, false, false, false, false, /* 00 */
- false, false, false, false, false, false, false, false, /* 08 */
- false, false, false, false, false, false, false, false, /* 10 */
- false, false, false, false, false, false, false, false, /* 18 */
- false, false, false, false, false, false, false, false, /* 20 */
- false, false, false, false, false, true, true, false, /* 28 */
- true, true, true, true, true, true, true, true, /* 30 */
- true, true, false, false, false, false, false, false, /* 38 */
- false, true, true, true, true, true, true, true, /* 40 */
- true, true, true, true, true, true, true, true, /* 48 */
- true, true, true, true, true, true, true, true, /* 50 */
- true, true, true, false, false, false, false, true, /* 58 */
- false, true, true, true, true, true, true, true, /* 60 */
- true, true, true, true, true, true, true, true, /* 68 */
- true, true, true, true, true, true, true, true, /* 70 */
- true, true, true, false, false, false, true, false, /* 78 */
- false, false, false, false, false, false, false, false, /* 80 */
- false, false, false, false, false, false, false, false, /* 88 */
- false, false, false, false, false, false, false, false, /* 90 */
- false, false, false, false, false, false, false, false, /* 98 */
- false, false, false, false, false, false, false, false, /* A0 */
- false, false, false, false, false, false, false, false, /* A8 */
- false, false, false, false, false, false, false, false, /* B0 */
- false, false, false, false, false, false, false, false, /* B8 */
- false, false, false, false, false, false, false, false, /* C0 */
- false, false, false, false, false, false, false, false, /* C8 */
- false, false, false, false, false, false, false, false, /* D0 */
- false, false, false, false, false, false, false, false, /* D8 */
- false, false, false, false, false, false, false, false, /* E0 */
- false, false, false, false, false, false, false, false, /* E8 */
- false, false, false, false, false, false, false, false, /* F0 */
- false, false, false, false, false, false, false, false /* F8 */
- };
- return unreserved[c];
-}
-
-/**
- * determine if a character should be percent escaped.
- *
- * The ASCII codes which should not be percent escaped
- *
- * \param c character to classify.
- * \return true if the character should not be escaped else false.
- */
-static bool nsurl__is_no_escape(unsigned char c)
-{
- static const bool no_escape[256] = {
- false, false, false, false, false, false, false, false, /* 00 */
- false, false, false, false, false, false, false, false, /* 08 */
- false, false, false, false, false, false, false, false, /* 10 */
- false, false, false, false, false, false, false, false, /* 18 */
- false, true, false, true, true, false, true, true, /* 20 */
- true, true, true, true, true, true, true, true, /* 28 */
- true, true, true, true, true, true, true, true, /* 30 */
- true, true, true, true, false, true, false, true, /* 38 */
- true, true, true, true, true, true, true, true, /* 40 */
- true, true, true, true, true, true, true, true, /* 48 */
- true, true, true, true, true, true, true, true, /* 50 */
- true, true, true, true, false, true, false, true, /* 58 */
- false, true, true, true, true, true, true, true, /* 60 */
- true, true, true, true, true, true, true, true, /* 68 */
- true, true, true, true, true, true, true, true, /* 70 */
- true, true, true, false, true, false, true, false, /* 78 */
- false, false, false, false, false, false, false, false, /* 80 */
- false, false, false, false, false, false, false, false, /* 88 */
- false, false, false, false, false, false, false, false, /* 90 */
- false, false, false, false, false, false, false, false, /* 98 */
- false, false, false, false, false, false, false, false, /* A0 */
- false, false, false, false, false, false, false, false, /* A8 */
- false, false, false, false, false, false, false, false, /* B0 */
- false, false, false, false, false, false, false, false, /* B8 */
- false, false, false, false, false, false, false, false, /* C0 */
- false, false, false, false, false, false, false, false, /* C8 */
- false, false, false, false, false, false, false, false, /* D0 */
- false, false, false, false, false, false, false, false, /* D8 */
- false, false, false, false, false, false, false, false, /* E0 */
- false, false, false, false, false, false, false, false, /* E8 */
- false, false, false, false, false, false, false, false, /* F0 */
- false, false, false, false, false, false, false, false, /* F8 */
- };
- return no_escape[c];
-}
-
-
-/**
- * Obtains a set of markers delimiting sections in a URL string
- *
- * \param url_s URL string
- * \param markers Updated to mark sections in the URL string
- * \param joining True iff URL string is a relative URL for joining
- */
-static void nsurl__get_string_markers(const char * const url_s,
- struct url_markers *markers, bool joining)
-{
- const char *pos = url_s; /** current position in url_s */
- bool is_http = false;
- bool trailing_whitespace = false;
-
- /* Initialise marker set */
- struct url_markers marker = { 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, NSURL_SCHEME_OTHER };
-
- /* Skip any leading whitespace in url_s */
- while (ascii_is_space(*pos))
- pos++;
-
- /* Record start point */
- marker.start = pos - url_s;
-
- marker.scheme_end = marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path = marker.start;
-
- if (*pos == '\0') {
- /* Nothing but whitespace, early exit */
- marker.query = marker.fragment = marker.end = marker.path;
- *markers = marker;
- return;
- }
-
- /* Get scheme */
- if (ascii_is_alpha(*pos)) {
- pos++;
-
- while (*pos != ':' && *pos != '\0') {
- if (!ascii_is_alphanumerical(*pos) && (*pos != '+') &&
- (*pos != '-') && (*pos != '.')) {
- /* This character is not valid in the
- * scheme */
- break;
- }
- pos++;
- }
-
- if (*pos == ':') {
- /* This delimits the end of the scheme */
- size_t off;
-
- marker.scheme_end = pos - url_s;
-
- off = marker.scheme_end - marker.start;
-
- /* Detect http(s) and mailto for scheme specifc
- * normalisation */
- if (off == SLEN("http") &&
- (((*(pos - off + 0) == 'h') ||
- (*(pos - off + 0) == 'H')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 't') ||
- (*(pos - off + 2) == 'T')) &&
- ((*(pos - off + 3) == 'p') ||
- (*(pos - off + 3) == 'P')))) {
- marker.scheme_type = NSURL_SCHEME_HTTP;
- is_http = true;
- } else if (off == SLEN("https") &&
- (((*(pos - off + 0) == 'h') ||
- (*(pos - off + 0) == 'H')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 't') ||
- (*(pos - off + 2) == 'T')) &&
- ((*(pos - off + 3) == 'p') ||
- (*(pos - off + 3) == 'P')) &&
- ((*(pos - off + 4) == 's') ||
- (*(pos - off + 4) == 'S')))) {
- marker.scheme_type = NSURL_SCHEME_HTTPS;
- is_http = true;
- } else if (off == SLEN("ftp") &&
- (((*(pos - off + 0) == 'f') ||
- (*(pos - off + 0) == 'F')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 'p') ||
- (*(pos - off + 2) == 'P')))) {
- marker.scheme_type = NSURL_SCHEME_FTP;
- } else if (off == SLEN("mailto") &&
- (((*(pos - off + 0) == 'm') ||
- (*(pos - off + 0) == 'M')) &&
- ((*(pos - off + 1) == 'a') ||
- (*(pos - off + 1) == 'A')) &&
- ((*(pos - off + 2) == 'i') ||
- (*(pos - off + 2) == 'I')) &&
- ((*(pos - off + 3) == 'l') ||
- (*(pos - off + 3) == 'L')) &&
- ((*(pos - off + 4) == 't') ||
- (*(pos - off + 4) == 'T')) &&
- ((*(pos - off + 5) == 'o') ||
- (*(pos - off + 5) == 'O')))) {
- marker.scheme_type = NSURL_SCHEME_MAILTO;
- }
-
- /* Skip over colon */
- pos++;
-
- /* Mark place as start of authority */
- marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path =
- pos - url_s;
-
- } else {
- /* Not found a scheme */
- if (joining == false) {
- /* Assuming no scheme == http */
- marker.scheme_type = NSURL_SCHEME_HTTP;
- is_http = true;
- }
- }
- }
-
- /* Get authority
- *
- * Two slashes always indicates the start of an authority.
- *
- * We are more relaxed in the case of http:
- * a. when joining, one or more slashes indicates start of authority
- * b. when not joining, we assume authority if no scheme was present
- * and in the case of mailto: when we assume there is an authority.
- */
- if ((*pos == '/' && *(pos + 1) == '/') ||
- (is_http && ((joining && *pos == '/') ||
- (joining == false &&
- marker.scheme_end != marker.start))) ||
- marker.scheme_type == NSURL_SCHEME_MAILTO) {
-
- /* Skip over leading slashes */
- if (*pos == '/') {
- if (is_http == false) {
- if (*pos == '/') pos++;
- if (*pos == '/') pos++;
- } else {
- while (*pos == '/')
- pos++;
- }
-
- marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path =
- pos - url_s;
- }
-
- /* Need to get (or complete) the authority */
- while (*pos != '\0') {
- if (*pos == '/' || *pos == '?' || *pos == '#') {
- /* End of the authority */
- break;
-
- } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
- *pos == ':' && marker.colon_first ==
- marker.authority) {
- /* could be username:password or host:port
- * separator */
- marker.colon_first = pos - url_s;
-
- } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
- *pos == ':' && marker.colon_first !=
- marker.authority) {
- /* could be host:port separator */
- marker.colon_last = pos - url_s;
-
- } else if (*pos == '@' && marker.at ==
- marker.authority) {
- /* Credentials @ host separator */
- marker.at = pos - url_s;
- }
-
- pos++;
- }
-
- marker.path = pos - url_s;
-
- } else if ((*pos == '\0' || *pos == '/') &&
- joining == false && is_http == true) {
- marker.path = pos - url_s;
- }
-
- /* Get path
- *
- * Needs to start with '/' if there's no authority
- */
- if (*pos == '/' || ((marker.path == marker.authority) &&
- (*pos != '?') && (*pos != '#') && (*pos !=
'\0'))) {
- while (*(++pos) != '\0') {
- if (*pos == '?' || *pos == '#') {
- /* End of the path */
- break;
- }
- }
- }
-
- marker.query = pos - url_s;
-
- /* Get query */
- if (*pos == '?') {
- while (*(++pos) != '\0') {
- if (*pos == '#') {
- /* End of the query */
- break;
- }
- }
- }
-
- marker.fragment = pos - url_s;
-
- /* Get fragment */
- if (*pos == '#') {
- while (*(++pos) != '\0')
- ;
- }
-
- /* We got to the end of url_s.
- * Need to skip back over trailing whitespace to find end of URL */
- pos--;
- if (pos >= url_s && ascii_is_space(*pos)) {
- trailing_whitespace = true;
- while (pos >= url_s && ascii_is_space(*pos))
- pos--;
- }
-
- marker.end = pos + 1 - url_s;
-
- if (trailing_whitespace == true) {
- /* Ensure last url section doesn't pass end */
- if (marker.fragment > marker.end)
- marker.fragment = marker.end;
- if (marker.query > marker.end)
- marker.query = marker.end;
- if (marker.path > marker.end)
- marker.path = marker.end;
- if (marker.colon_last > marker.end)
- marker.colon_last = marker.end;
- if (marker.at > marker.end)
- marker.at = marker.end;
- if (marker.colon_last > marker.end)
- marker.colon_last = marker.end;
- if (marker.fragment > marker.end)
- marker.fragment = marker.end;
- }
-
-#ifdef NSURL_DEBUG
- LOG("marker.start: %i", marker.start);
- LOG("marker.scheme_end: %i", marker.scheme_end);
- LOG("marker.authority: %i", marker.authority);
-
- LOG("marker.colon_first: %i", marker.colon_first);
- LOG("marker.at: %i", marker.at);
- LOG("marker.colon_last: %i", marker.colon_last);
-
- LOG("marker.path: %i", marker.path);
- LOG("marker.query: %i", marker.query);
- LOG("marker.fragment: %i", marker.fragment);
-
- LOG("marker.end: %i", marker.end);
-#endif
-
- /* Got all the URL components pegged out now */
- *markers = marker;
-}
-
-
-/**
- * Remove dot segments from a path, as per rfc 3986, 5.2.4
- *
- * \param path path to remove dot segments from ('\0' terminated)
- * \param output path with dot segments removed
- * \return size of output
- */
-static size_t nsurl__remove_dot_segments(char *path, char *output)
-{
- char *path_pos = path;
- char *output_pos = output;
-
- while (*path_pos != '\0') {
-#ifdef NSURL_DEBUG
- LOG(" in:%s", path_pos);
- LOG("out:%.*s", output_pos - output, output);
-#endif
- if (*path_pos == '.') {
- if (*(path_pos + 1) == '.' &&
- *(path_pos + 2) == '/') {
- /* Found prefix of "../" */
- path_pos += SLEN("../");
- continue;
-
- } else if (*(path_pos + 1) == '/') {
- /* Found prefix of "./" */
- path_pos += SLEN("./");
- continue;
- }
- } else if (*path_pos == '/' && *(path_pos + 1) == '.') {
- if (*(path_pos + 2) == '/') {
- /* Found prefix of "/./" */
- path_pos += SLEN("/.");
- continue;
-
- } else if (*(path_pos + 2) == '\0') {
- /* Found "/." at end of path */
- *(output_pos++) = '/';
-
- /* End of input path */
- break;
-
- } else if (*(path_pos + 2) == '.') {
- if (*(path_pos + 3) == '/') {
- /* Found prefix of "/../" */
- path_pos += SLEN("/..");
-
- if (output_pos > output)
- output_pos--;
- while (output_pos > output &&
- *output_pos != '/')
- output_pos--;
-
- continue;
-
- } else if (*(path_pos + 3) == '\0') {
- /* Found "/.." at end of path */
-
- while (output_pos > output &&
- *(output_pos -1 ) !='/')
- output_pos--;
-
- /* End of input path */
- break;
- }
- }
- } else if (*path_pos == '.') {
- if (*(path_pos + 1) == '\0') {
- /* Found "." at end of path */
-
- /* End of input path */
- break;
-
- } else if (*(path_pos + 1) == '.' &&
- *(path_pos + 2) == '\0') {
- /* Found ".." at end of path */
-
- /* End of input path */
- break;
- }
- }
- /* Copy first character into output path */
- *output_pos++ = *path_pos++;
-
- /* Copy up to but not including next '/' */
- while ((*path_pos != '/') && (*path_pos != '\0'))
- *output_pos++ = *path_pos++;
- }
-
- return output_pos - output;
-}
-
-
-/**
- * Get the length of the longest section
- *
- * \param m markers delimiting url sections in a string
- * \return the length of the longest section
- */
-static size_t nsurl__get_longest_section(struct url_markers *m)
-{
- size_t length = m->scheme_end - m->start; /* scheme */
-
- if (length < m->at - m->authority) /* credentials */
- length = m->at - m->authority;
-
- if (length < m->path - m->at) /* host */
- length = m->path - m->at;
-
- if (length < m->query - m->path) /* path */
- length = m->query - m->path;
-
- if (length < m->fragment - m->query) /* query */
- length = m->fragment - m->query;
-
- if (length < m->end - m->fragment) /* fragment */
- length = m->end - m->fragment;
-
- return length;
-}
-
-
-/**
- * Converts two hexadecimal digits to a single number
- *
- * \param c1 most significant hex digit
- * \param c2 least significant hex digit
- * \return the total value of the two digit hex number, or -ve if input not hex
- *
- * For unescaping url encoded characters.
- */
-static inline int nsurl__get_ascii_offset(char c1, char c2)
-{
- int offset;
-
- /* Use 1st char as most significant hex digit */
- if (ascii_is_digit(c1))
- offset = 16 * (c1 - '0');
- else if (c1 >= 'a' && c1 <= 'f')
- offset = 16 * (c1 - 'a' + 10);
- else if (c1 >= 'A' && c1 <= 'F')
- offset = 16 * (c1 - 'A' + 10);
- else
- /* Not valid hex */
- return -1;
-
- /* Use 2nd char as least significant hex digit and sum */
- if (ascii_is_digit(c2))
- offset += c2 - '0';
- else if (c2 >= 'a' && c2 <= 'f')
- offset += c2 - 'a' + 10;
- else if (c2 >= 'A' && c2 <= 'F')
- offset += c2 - 'A' + 10;
- else
- /* Not valid hex */
- return -1;
-
- return offset;
-}
-
-
-/**
- * Create the components of a NetSurf URL object for a section of a URL string
- *
- * \param url_s URL string
- * \param section Sets which section of URL string is to be normalised
- * \param pegs Set of markers delimiting the URL string's sections
- * \param pos_norm A buffer large enough for the normalised string (*3 + 1)
- * \param url A NetSurf URL object, to which components may be added
- * \return NSERROR_OK on success, appropriate error otherwise
- *
- * The section of url_s is normalised appropriately.
- */
-static nserror nsurl__create_from_section(const char * const url_s,
- const enum url_sections section,
- const struct url_markers *pegs,
- char *pos_norm,
- struct nsurl_components *url)
-{
- nserror ret;
- int ascii_offset;
- int start = 0;
- int end = 0;
- const char *pos;
- const char *pos_url_s;
- char *norm_start = pos_norm;
- char *host;
- size_t copy_len;
- size_t length;
- size_t host_len;
- enum {
- NSURL_F_NO_PORT = (1 << 0)
- } flags = 0;
-
- switch (section) {
- case URL_SCHEME:
- start = pegs->start;
- end = pegs->scheme_end;
- break;
-
- case URL_CREDENTIALS:
- start = pegs->authority;
- end = pegs->at;
- break;
-
- case URL_HOST:
- start = (pegs->at == pegs->authority &&
- *(url_s + pegs->at) != '@') ?
- pegs->at :
- pegs->at + 1;
- end = pegs->path;
- break;
-
- case URL_PATH:
- start = pegs->path;
- end = pegs->query;
- break;
-
- case URL_QUERY:
- start = pegs->query;
- end = pegs->fragment;
- break;
-
- case URL_FRAGMENT:
- start = (*(url_s + pegs->fragment) != '#') ?
- pegs->fragment :
- pegs->fragment + 1;
- end = pegs->end;
- break;
- }
-
- if (end < start)
- end = start;
-
- length = end - start;
-
- /* Stage 1: Normalise the required section */
-
- pos = pos_url_s = url_s + start;
- copy_len = 0;
- for (; pos < url_s + end; pos++) {
- if (*pos == '%' && (pos + 2 < url_s + end)) {
- /* Might be an escaped character needing unescaped */
-
- /* Find which character which was escaped */
- ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
- *(pos + 2));
-
- if (ascii_offset < 0) {
- /* % with invalid hex digits. */
- copy_len++;
- continue;
- }
-
- if ((section != URL_SCHEME && section != URL_HOST) &&
- (nsurl__is_unreserved(ascii_offset) == false)) {
- /* This character should be escaped after all,
- * just let it get copied */
- copy_len += 3;
- pos += 2;
- continue;
- }
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
-
- /* Put the unescaped character in the normalised URL */
- *(pos_norm++) = (char)ascii_offset;
- pos += 2;
- pos_url_s = pos + 1;
-
- length -= 2;
-
- } else if ((section != URL_SCHEME && section != URL_HOST) &&
- (nsurl__is_no_escape(*pos) == false)) {
-
- /* This needs to be escaped */
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
-
- /* escape */
- *(pos_norm++) = '%';
- *(pos_norm++) = digit2uppercase_hex(
- ((unsigned char)*pos) >> 4);
- *(pos_norm++) = digit2uppercase_hex(
- ((unsigned char)*pos) & 0xf);
- pos_url_s = pos + 1;
-
- length += 2;
-
- } else if ((section == URL_SCHEME || section == URL_HOST) &&
- ascii_is_alpha_upper(*pos)) {
- /* Lower case this letter */
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
- /* Copy lower cased letter into normalised URL */
- *(pos_norm++) = ascii_to_lower(*pos);
- pos_url_s = pos + 1;
-
- } else {
- /* This character is safe in normalised URL */
- copy_len++;
- }
- }
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- }
-
- /* Mark end of section */
- (*pos_norm) = '\0';
-
- /* Stage 2: Create the URL components for the required section */
- switch (section) {
- case URL_SCHEME:
- if (length == 0) {
- /* No scheme, assuming http */
- url->scheme = lwc_string_ref(corestring_lwc_http);
- } else {
- /* Add scheme to URL */
- if (lwc_intern_string(norm_start, length,
- &url->scheme) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
-
- break;
-
- case URL_CREDENTIALS:
- url->username = NULL;
- url->password = NULL;
-
- if (length != 0 && *norm_start != ':') {
- char *sec_start = norm_start;
- if (pegs->colon_first != pegs->authority &&
- pegs->at > pegs->colon_first + 1) {
- /* there's a password */
- sec_start += pegs->colon_first -
- pegs->authority + 1;
- if (lwc_intern_string(sec_start,
- pegs->at - pegs->colon_first -1,
- &url->password) !=
- lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- /* update start pos and length for username */
- sec_start = norm_start;
- length -= pegs->at - pegs->colon_first;
- } else if (pegs->colon_first != pegs->authority &&
- pegs->at == pegs->colon_first + 1) {
- /* strip username colon */
- length--;
- }
-
- /* Username */
- if (lwc_intern_string(sec_start, length,
- &url->username) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
-
- break;
-
- case URL_HOST:
- url->host = NULL;
- url->port = NULL;
-
- if (length != 0) {
- size_t colon = 0;
- char *sec_start = norm_start;
- if (pegs->at < pegs->colon_first &&
- pegs->colon_last == pegs->authority) {
- /* There's one colon and it's after @ marker */
- colon = pegs->colon_first;
- } else if (pegs->colon_last != pegs->authority) {
- /* There's more than one colon */
- colon = pegs->colon_last;
- } else {
- /* There's no colon that could be a port
- * separator */
- flags |= NSURL_F_NO_PORT;
- }
-
- if (!(flags & NSURL_F_NO_PORT)) {
- /* Determine whether colon is a port separator
- */
- sec_start += colon - pegs->at;
- while (++sec_start < norm_start + length) {
- if (!ascii_is_digit(*sec_start)) {
- /* Character after port isn't a
- * digit; not a port separator
- */
- flags |= NSURL_F_NO_PORT;
- break;
- }
- }
- }
-
- if (!(flags & NSURL_F_NO_PORT)) {
- /* There's a port */
- size_t skip = (pegs->at == pegs->authority) ?
- 1 : 0;
- sec_start = norm_start + colon - pegs->at +
- skip;
- if (url->scheme != NULL &&
- url->scheme_type ==
- NSURL_SCHEME_HTTP &&
- length -
- (colon - pegs->at + skip) == 2 &&
- *sec_start == '8' &&
- *(sec_start + 1) == '0') {
- /* Scheme is http, and port is default
- * (80) */
- flags |= NSURL_F_NO_PORT;
- }
-
- if (length <= (colon - pegs->at + skip)) {
- /* No space for a port after the colon
- */
- flags |= NSURL_F_NO_PORT;
- }
-
- /* Add non-redundant ports to NetSurf URL */
- sec_start = norm_start + colon - pegs->at +
- skip;
- if (!(flags & NSURL_F_NO_PORT) &&
- lwc_intern_string(sec_start,
- length -
- (colon - pegs->at + skip),
- &url->port) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- /* update length for host */
- skip = (pegs->at == pegs->authority) ? 0 : 1;
- length = colon - pegs->at - skip;
- }
-
- /* host */
- /* Encode host according to IDNA2008 */
- ret = idna_encode(norm_start, length, &host, &host_len);
- if (ret == NSERROR_OK) {
- /* valid idna encoding */
- if (lwc_intern_string(host, host_len,
- &url->host) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- free(host);
- } else {
- /* fall back to straight interning */
- if (lwc_intern_string(norm_start, length,
- &url->host) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
- }
-
- break;
-
- case URL_PATH:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->path) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else if (url->host != NULL &&
- url->scheme_type != NSURL_SCHEME_MAILTO) {
- /* Set empty path to "/", if there's a host */
- if (lwc_intern_string("/", SLEN("/"),
- &url->path) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->path = NULL;
- }
-
- break;
-
- case URL_QUERY:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->query) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->query = NULL;
- }
-
- break;
-
- case URL_FRAGMENT:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->fragment) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->fragment = NULL;
- }
-
- break;
- }
-
- return NSERROR_OK;
-}
-
-
-/**
- * Get nsurl string info; total length, component lengths, & components present
- *
- * \param url NetSurf URL components
- * \param parts Which parts of the URL are required in the string
- * \param url_l Updated to total string length
- * \param lengths Updated with individual component lengths
- * \param pflags Updated to contain relevant string flags
- */
-static void nsurl__get_string_data(const struct nsurl_components *url,
- nsurl_component parts, size_t *url_l,
- struct nsurl_component_lengths *lengths,
- enum nsurl_string_flags *pflags)
-{
- enum nsurl_string_flags flags = *pflags;
- *url_l = 0;
-
- /* Intersection of required parts and available parts gives
- * the output parts */
- if (url->scheme && parts & NSURL_SCHEME) {
- flags |= NSURL_F_SCHEME;
-
- lengths->scheme = lwc_string_length(url->scheme);
- *url_l += lengths->scheme;
- }
-
- if (url->username && parts & NSURL_USERNAME) {
- flags |= NSURL_F_USERNAME;
-
- lengths->username = lwc_string_length(url->username);
- *url_l += lengths->username;
- }
-
- if (url->password && parts & NSURL_PASSWORD) {
- flags |= NSURL_F_PASSWORD;
-
- lengths->password = lwc_string_length(url->password);
- *url_l += SLEN(":") + lengths->password;
- }
-
- if (url->host && parts & NSURL_HOST) {
- flags |= NSURL_F_HOST;
-
- lengths->host = lwc_string_length(url->host);
- *url_l += lengths->host;
- }
-
- if (url->port && parts & NSURL_PORT) {
- flags |= NSURL_F_PORT;
-
- lengths->port = lwc_string_length(url->port);
- *url_l += SLEN(":") + lengths->port;
- }
-
- if (url->path && parts & NSURL_PATH) {
- flags |= NSURL_F_PATH;
-
- lengths->path = lwc_string_length(url->path);
- *url_l += lengths->path;
- }
-
- if (url->query && parts & NSURL_QUERY) {
- flags |= NSURL_F_QUERY;
-
- lengths->query = lwc_string_length(url->query);
- *url_l += lengths->query;
- }
-
- if (url->fragment && parts & NSURL_FRAGMENT) {
- flags |= NSURL_F_FRAGMENT;
-
- lengths->fragment = lwc_string_length(url->fragment);
- *url_l += lengths->fragment;
- }
-
- /* Turn on any spanned punctuation */
- if ((flags & NSURL_F_SCHEME) && (parts > NSURL_SCHEME)) {
- flags |= NSURL_F_SCHEME_PUNCTUATION;
-
- *url_l += SLEN(":");
- }
-
- if ((flags & NSURL_F_SCHEME) && (flags > NSURL_F_SCHEME) &&
- url->path && lwc_string_data(url->path)[0] == '/') {
- flags |= NSURL_F_AUTHORITY_PUNCTUATION;
-
- *url_l += SLEN("//");
- }
-
- if ((flags & (NSURL_F_USERNAME | NSURL_F_PASSWORD)) &&
- flags & NSURL_F_HOST) {
- flags |= NSURL_F_CREDENTIALS_PUNCTUATION;
-
- *url_l += SLEN("@");
- }
-
- if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
- flags |= NSURL_F_FRAGMENT_PUNCTUATION;
-
- *url_l += SLEN("#");
- }
-
- *pflags = flags;
-}
-
-
-/**
- * Get nsurl string info; total length, component lengths, & components present
- *
- * \param url NetSurf URL components
- * \param url_s Updated to contain the string
- * \param l Individual component lengths
- * \param flags String flags
- */
-static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
- struct nsurl_component_lengths *l,
- enum nsurl_string_flags flags)
-{
- char *pos;
-
- /* Copy the required parts into the url string */
- pos = url_s;
-
- if (flags & NSURL_F_SCHEME) {
- memcpy(pos, lwc_string_data(url->scheme), l->scheme);
- pos += l->scheme;
- }
-
- if (flags & NSURL_F_SCHEME_PUNCTUATION) {
- *(pos++) = ':';
- }
-
- if (flags & NSURL_F_AUTHORITY_PUNCTUATION) {
- *(pos++) = '/';
- *(pos++) = '/';
- }
-
- if (flags & NSURL_F_USERNAME) {
- memcpy(pos, lwc_string_data(url->username), l->username);
- pos += l->username;
- }
-
- if (flags & NSURL_F_PASSWORD) {
- *(pos++) = ':';
- memcpy(pos, lwc_string_data(url->password), l->password);
- pos += l->password;
- }
-
- if (flags & NSURL_F_CREDENTIALS_PUNCTUATION) {
- *(pos++) = '@';
- }
-
- if (flags & NSURL_F_HOST) {
- memcpy(pos, lwc_string_data(url->host), l->host);
- pos += l->host;
- }
-
- if (flags & NSURL_F_PORT) {
- *(pos++) = ':';
- memcpy(pos, lwc_string_data(url->port), l->port);
- pos += l->port;
- }
-
- if (flags & NSURL_F_PATH) {
- memcpy(pos, lwc_string_data(url->path), l->path);
- pos += l->path;
- }
-
- if (flags & NSURL_F_QUERY) {
- memcpy(pos, lwc_string_data(url->query), l->query);
- pos += l->query;
- }
-
- if (flags & NSURL_F_FRAGMENT) {
- if (flags & NSURL_F_FRAGMENT_PUNCTUATION)
- *(pos++) = '#';
- memcpy(pos, lwc_string_data(url->fragment), l->fragment);
- pos += l->fragment;
- }
-
- *pos = '\0';
-}
-
-
-/**
- * Calculate hash value
- *
- * \param url NetSurf URL object to set hash value for
- */
-static void nsurl_calc_hash(nsurl *url)
-{
- uint32_t hash = 0;
-
- if (url->components.scheme)
- hash ^= lwc_string_hash_value(url->components.scheme);
-
- if (url->components.username)
- hash ^= lwc_string_hash_value(url->components.username);
-
- if (url->components.password)
- hash ^= lwc_string_hash_value(url->components.password);
-
- if (url->components.host)
- hash ^= lwc_string_hash_value(url->components.host);
-
- if (url->components.port)
- hash ^= lwc_string_hash_value(url->components.port);
-
- if (url->components.path)
- hash ^= lwc_string_hash_value(url->components.path);
-
- if (url->components.query)
- hash ^= lwc_string_hash_value(url->components.query);
-
- url->hash = hash;
-}
-
/**
* Destroy components
@@ -1321,89 +133,6 @@ static void nsurl__dump(const nsurl *url)
******************************************************************************/
/* exported interface, documented in nsurl.h */
-nserror nsurl_create(const char * const url_s, nsurl **url)
-{
- struct url_markers m;
- struct nsurl_components c;
- size_t length;
- char *buff;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
- nserror e = NSERROR_OK;
- bool match;
-
- assert(url_s != NULL);
-
- /* Peg out the URL sections */
- nsurl__get_string_markers(url_s, &m, false);
-
- /* Get the length of the longest section */
- length = nsurl__get_longest_section(&m);
-
- /* Allocate enough memory to url escape the longest section */
- buff = malloc(length * 3 + 1);
- if (buff == NULL)
- return NSERROR_NOMEM;
-
- /* Set scheme type */
- c.scheme_type = m.scheme_type;
-
- /* Build NetSurf URL object from sections */
- e |= nsurl__create_from_section(url_s, URL_SCHEME, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_CREDENTIALS, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_HOST, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_PATH, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_QUERY, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_FRAGMENT, &m, buff, &c);
-
- /* Finished with buffer */
- free(buff);
-
- if (e != NSERROR_OK) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
- }
-
- /* Validate URL */
- if ((lwc_string_isequal(c.scheme, corestring_lwc_http,
- &match) == lwc_error_ok && match == true) ||
- (lwc_string_isequal(c.scheme, corestring_lwc_https,
- &match) == lwc_error_ok && match == true)) {
- /* http, https must have host */
- if (c.host == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_BAD_URL;
- }
- }
-
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*url == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
- }
-
- (*url)->components = c;
- (*url)->length = length;
-
- /* Fill out the url string */
- nsurl_get_string(&c, (*url)->string, &str_len, str_flags);
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*url);
-
- /* Give the URL a reference */
- (*url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
nsurl *nsurl_ref(nsurl *url)
{
assert(url != NULL);
@@ -1539,7 +268,7 @@ nserror nsurl_get(const nsurl *url, nsurl_component parts,
}
/* Copy the required parts into the url string */
- nsurl_get_string(&(url->components), *url_s, &str_len, str_flags);
+ nsurl__get_string(&(url->components), *url_s, &str_len, str_flags);
return NSERROR_OK;
}
@@ -1780,253 +509,6 @@ uint32_t nsurl_hash(const nsurl *url)
/* exported interface, documented in nsurl.h */
-nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
-{
- struct url_markers m;
- struct nsurl_components c;
- size_t length;
- char *buff;
- char *buff_pos;
- char *buff_start;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
- nserror error = 0;
- enum {
- NSURL_F_REL = 0,
- NSURL_F_BASE_SCHEME = (1 << 0),
- NSURL_F_BASE_AUTHORITY = (1 << 1),
- NSURL_F_BASE_PATH = (1 << 2),
- NSURL_F_MERGED_PATH = (1 << 3),
- NSURL_F_BASE_QUERY = (1 << 4)
- } joined_parts;
-
- assert(base != NULL);
- assert(rel != NULL);
-
-#ifdef NSURL_DEBUG
- LOG("base: \"%s\", rel: \"%s\"", nsurl_access(base),
rel);
-#endif
-
- /* Peg out the URL sections */
- nsurl__get_string_markers(rel, &m, true);
-
- /* Get the length of the longest section */
- length = nsurl__get_longest_section(&m);
-
- /* Initially assume that the joined URL can be formed entierly from
- * the relative URL.
- */
- joined_parts = NSURL_F_REL;
-
- /* Update joined_compnents to indicate any required parts from the
- * base URL.
- */
- if (m.scheme_end - m.start <= 0) {
- /* The relative url has no scheme.
- * Use base URL's scheme. */
- joined_parts |= NSURL_F_BASE_SCHEME;
-
- if (m.path - m.authority <= 0) {
- /* The relative URL has no authority.
- * Use base URL's authority. */
- joined_parts |= NSURL_F_BASE_AUTHORITY;
-
- if (m.query - m.path <= 0) {
- /* The relative URL has no path.
- * Use base URL's path. */
- joined_parts |= NSURL_F_BASE_PATH;
-
- if (m.fragment - m.query <= 0) {
- /* The relative URL has no query.
- * Use base URL's query. */
- joined_parts |= NSURL_F_BASE_QUERY;
- }
-
- } else if (*(rel + m.path) != '/') {
- /* Relative URL has relative path */
- joined_parts |= NSURL_F_MERGED_PATH;
- }
- }
- }
-
- /* Allocate enough memory to url escape the longest section, plus
- * space for path merging (if required).
- */
- if (joined_parts & NSURL_F_MERGED_PATH) {
- /* Need to merge paths */
- length += (base->components.path != NULL) ?
- lwc_string_length(base->components.path) : 0;
- }
- length *= 4;
- /* Plus space for removing dots from path */
- length += (m.query - m.path) + ((base->components.path != NULL) ?
- lwc_string_length(base->components.path) : 0);
-
- buff = malloc(length + 5);
- if (buff == NULL) {
- return NSERROR_NOMEM;
- }
-
- buff_pos = buff;
-
- /* Form joined URL from base or rel components, as appropriate */
-
- if (joined_parts & NSURL_F_BASE_SCHEME) {
- c.scheme_type = base->components.scheme_type;
-
- c.scheme = nsurl__component_copy(base->components.scheme);
- } else {
- c.scheme_type = m.scheme_type;
-
- error = nsurl__create_from_section(rel, URL_SCHEME, &m, buff, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_AUTHORITY) {
- c.username = nsurl__component_copy(base->components.username);
- c.password = nsurl__component_copy(base->components.password);
- c.host = nsurl__component_copy(base->components.host);
- c.port = nsurl__component_copy(base->components.port);
- } else {
- error = nsurl__create_from_section(rel, URL_CREDENTIALS, &m,
- buff, &c);
- if (error == NSERROR_OK) {
- error = nsurl__create_from_section(rel, URL_HOST, &m,
- buff, &c);
- }
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_PATH) {
- c.path = nsurl__component_copy(base->components.path);
-
- } else if (joined_parts & NSURL_F_MERGED_PATH) {
- struct url_markers m_path;
- size_t new_length;
-
- if (base->components.host != NULL &&
- base->components.path == NULL) {
- /* Append relative path to "/". */
- *(buff_pos++) = '/';
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
-
- } else {
- /* Append relative path to all but last segment of
- * base path. */
- size_t path_end = lwc_string_length(
- base->components.path);
- const char *path = lwc_string_data(
- base->components.path);
-
- while (*(path + path_end) != '/' &&
- path_end != 0) {
- path_end--;
- }
- if (*(path + path_end) == '/')
- path_end++;
-
- /* Copy the base part */
- memcpy(buff_pos, path, path_end);
- buff_pos += path_end;
-
- /* Copy the relative part */
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
- }
-
- /* add termination to string */
- *buff_pos++ = '\0';
-
- new_length = nsurl__remove_dot_segments(buff, buff_pos);
-
- m_path.path = 0;
- m_path.query = new_length;
-
- buff_start = buff_pos + new_length;
- error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
- buff_start, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
-
- } else {
- struct url_markers m_path;
- size_t new_length;
-
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
- *(buff_pos++) = '\0';
-
- new_length = nsurl__remove_dot_segments(buff, buff_pos);
-
- m_path.path = 0;
- m_path.query = new_length;
-
- buff_start = buff_pos + new_length;
-
- error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
- buff_start, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_QUERY) {
- c.query = nsurl__component_copy(base->components.query);
- } else {
- error = nsurl__create_from_section(rel, URL_QUERY, &m,
- buff, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- error = nsurl__create_from_section(rel, URL_FRAGMENT, &m, buff, &c);
-
- /* Free temporary buffer */
- free(buff);
-
- if (error != NSERROR_OK) {
- return error;
- }
-
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*joined == NULL) {
- return NSERROR_NOMEM;
- }
-
- (*joined)->components = c;
- (*joined)->length = length;
-
- /* Fill out the url string */
- nsurl_get_string(&c, (*joined)->string, &str_len, str_flags);
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*joined);
-
- /* Give the URL a reference */
- (*joined)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
{
size_t length;
@@ -2083,7 +565,7 @@ nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
*pos = '\0';
/* Get the nsurl's hash */
- nsurl_calc_hash(*no_frag);
+ nsurl__calc_hash(*no_frag);
/* Give the URL a reference */
(*no_frag)->count = 1;
@@ -2151,7 +633,7 @@ nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl
**new_url)
(*new_url)->components.scheme_type = url->components.scheme_type;
/* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
+ nsurl__calc_hash(*new_url);
/* Give the URL a reference */
(*new_url)->count = 1;
@@ -2238,7 +720,7 @@ nserror nsurl_replace_query(const nsurl *url, const char *query,
(*new_url)->components.scheme_type = url->components.scheme_type;
/* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
+ nsurl__calc_hash(*new_url);
/* Give the URL a reference */
(*new_url)->count = 1;
@@ -2441,7 +923,7 @@ nserror nsurl_parent(const nsurl *url, nsurl **new_url)
(*new_url)->components.scheme_type = url->components.scheme_type;
/* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
+ nsurl__calc_hash(*new_url);
/* Give the URL a reference */
(*new_url)->count = 1;
diff --git a/utils/nsurl/parse.c b/utils/nsurl/parse.c
new file mode 100644
index 0000000..0cdbbd4
--- /dev/null
+++ b/utils/nsurl/parse.c
@@ -0,0 +1,1602 @@
+/*
+ * Copyright 2011 Michael Drake <tlsa(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
+ * NetSurf URL handling implementation.
+ *
+ * This is the common implementation of all URL handling within the
+ * browser. This implementation is based upon RFC3986 although this has
+ * been superceeded by
https://url.spec.whatwg.org/ which is based on
+ * actual contemporary implementations.
+ *
+ * Care must be taken with character encodings within this module as
+ * the specifications work with specific ascii ranges and must not be
+ * affected by locale. Hence the c library character type functions
+ * are not used.
+ */
+
+#include <assert.h>
+#include <libwapcaplet/libwapcaplet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "utils/ascii.h"
+#include "utils/corestrings.h"
+#include "utils/errors.h"
+#include "utils/idna.h"
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "utils/nsurl/private.h"
+#include "utils/utils.h"
+
+/* Define to enable NSURL debugging */
+#undef NSURL_DEBUG
+
+
+/** Marker set, indicating positions of sections within a URL string */
+struct url_markers {
+ size_t start; /** start of URL */
+ size_t scheme_end;
+ size_t authority;
+
+ size_t colon_first;
+ size_t at;
+ size_t colon_last;
+
+ size_t path;
+ size_t query;
+ size_t fragment;
+
+ size_t end; /** end of URL */
+
+ enum nsurl_scheme_type scheme_type;
+};
+
+
+/** Sections of a URL */
+enum url_sections {
+ URL_SCHEME,
+ URL_CREDENTIALS,
+ URL_HOST,
+ URL_PATH,
+ URL_QUERY,
+ URL_FRAGMENT
+};
+
+
+#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
+
+#define nsurl__component_compare(c1, c2, match) \
+ if (c1 && c2 && lwc_error_ok == \
+ lwc_string_isequal(c1, c2, match)) { \
+ /* do nothing */ \
+ } else if (c1 || c2) { \
+ *match = false; \
+ }
+
+/**
+ * Return a hex digit for the given numerical value.
+ *
+ * \param digit the value to get the hex digit for.
+ * \return character in range 0-9A-F
+ */
+inline static char digit2uppercase_hex(unsigned char digit) {
+ assert(digit < 16);
+ return "0123456789ABCDEF"[digit];
+}
+
+/**
+ * determine if a character is unreserved
+ *
+ * \param c character to classify.
+ * \return true if the character is unreserved else false.
+ */
+static bool nsurl__is_unreserved(unsigned char c)
+{
+ /* From RFC3986 section 2.3 (unreserved characters)
+ *
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" /
"~"
+ *
+ */
+ static const bool unreserved[256] = {
+ false, false, false, false, false, false, false, false, /* 00 */
+ false, false, false, false, false, false, false, false, /* 08 */
+ false, false, false, false, false, false, false, false, /* 10 */
+ false, false, false, false, false, false, false, false, /* 18 */
+ false, false, false, false, false, false, false, false, /* 20 */
+ false, false, false, false, false, true, true, false, /* 28 */
+ true, true, true, true, true, true, true, true, /* 30 */
+ true, true, false, false, false, false, false, false, /* 38 */
+ false, true, true, true, true, true, true, true, /* 40 */
+ true, true, true, true, true, true, true, true, /* 48 */
+ true, true, true, true, true, true, true, true, /* 50 */
+ true, true, true, false, false, false, false, true, /* 58 */
+ false, true, true, true, true, true, true, true, /* 60 */
+ true, true, true, true, true, true, true, true, /* 68 */
+ true, true, true, true, true, true, true, true, /* 70 */
+ true, true, true, false, false, false, true, false, /* 78 */
+ false, false, false, false, false, false, false, false, /* 80 */
+ false, false, false, false, false, false, false, false, /* 88 */
+ false, false, false, false, false, false, false, false, /* 90 */
+ false, false, false, false, false, false, false, false, /* 98 */
+ false, false, false, false, false, false, false, false, /* A0 */
+ false, false, false, false, false, false, false, false, /* A8 */
+ false, false, false, false, false, false, false, false, /* B0 */
+ false, false, false, false, false, false, false, false, /* B8 */
+ false, false, false, false, false, false, false, false, /* C0 */
+ false, false, false, false, false, false, false, false, /* C8 */
+ false, false, false, false, false, false, false, false, /* D0 */
+ false, false, false, false, false, false, false, false, /* D8 */
+ false, false, false, false, false, false, false, false, /* E0 */
+ false, false, false, false, false, false, false, false, /* E8 */
+ false, false, false, false, false, false, false, false, /* F0 */
+ false, false, false, false, false, false, false, false /* F8 */
+ };
+ return unreserved[c];
+}
+
+/**
+ * determine if a character should be percent escaped.
+ *
+ * The ASCII codes which should not be percent escaped
+ *
+ * \param c character to classify.
+ * \return true if the character should not be escaped else false.
+ */
+static bool nsurl__is_no_escape(unsigned char c)
+{
+ static const bool no_escape[256] = {
+ false, false, false, false, false, false, false, false, /* 00 */
+ false, false, false, false, false, false, false, false, /* 08 */
+ false, false, false, false, false, false, false, false, /* 10 */
+ false, false, false, false, false, false, false, false, /* 18 */
+ false, true, false, true, true, false, true, true, /* 20 */
+ true, true, true, true, true, true, true, true, /* 28 */
+ true, true, true, true, true, true, true, true, /* 30 */
+ true, true, true, true, false, true, false, true, /* 38 */
+ true, true, true, true, true, true, true, true, /* 40 */
+ true, true, true, true, true, true, true, true, /* 48 */
+ true, true, true, true, true, true, true, true, /* 50 */
+ true, true, true, true, false, true, false, true, /* 58 */
+ false, true, true, true, true, true, true, true, /* 60 */
+ true, true, true, true, true, true, true, true, /* 68 */
+ true, true, true, true, true, true, true, true, /* 70 */
+ true, true, true, false, true, false, true, false, /* 78 */
+ false, false, false, false, false, false, false, false, /* 80 */
+ false, false, false, false, false, false, false, false, /* 88 */
+ false, false, false, false, false, false, false, false, /* 90 */
+ false, false, false, false, false, false, false, false, /* 98 */
+ false, false, false, false, false, false, false, false, /* A0 */
+ false, false, false, false, false, false, false, false, /* A8 */
+ false, false, false, false, false, false, false, false, /* B0 */
+ false, false, false, false, false, false, false, false, /* B8 */
+ false, false, false, false, false, false, false, false, /* C0 */
+ false, false, false, false, false, false, false, false, /* C8 */
+ false, false, false, false, false, false, false, false, /* D0 */
+ false, false, false, false, false, false, false, false, /* D8 */
+ false, false, false, false, false, false, false, false, /* E0 */
+ false, false, false, false, false, false, false, false, /* E8 */
+ false, false, false, false, false, false, false, false, /* F0 */
+ false, false, false, false, false, false, false, false, /* F8 */
+ };
+ return no_escape[c];
+}
+
+
+/**
+ * Obtains a set of markers delimiting sections in a URL string
+ *
+ * \param url_s URL string
+ * \param markers Updated to mark sections in the URL string
+ * \param joining True iff URL string is a relative URL for joining
+ */
+static void nsurl__get_string_markers(const char * const url_s,
+ struct url_markers *markers, bool joining)
+{
+ const char *pos = url_s; /** current position in url_s */
+ bool is_http = false;
+ bool trailing_whitespace = false;
+
+ /* Initialise marker set */
+ struct url_markers marker = { 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, NSURL_SCHEME_OTHER };
+
+ /* Skip any leading whitespace in url_s */
+ while (ascii_is_space(*pos))
+ pos++;
+
+ /* Record start point */
+ marker.start = pos - url_s;
+
+ marker.scheme_end = marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path = marker.start;
+
+ if (*pos == '\0') {
+ /* Nothing but whitespace, early exit */
+ marker.query = marker.fragment = marker.end = marker.path;
+ *markers = marker;
+ return;
+ }
+
+ /* Get scheme */
+ if (ascii_is_alpha(*pos)) {
+ pos++;
+
+ while (*pos != ':' && *pos != '\0') {
+ if (!ascii_is_alphanumerical(*pos) && (*pos != '+') &&
+ (*pos != '-') && (*pos != '.')) {
+ /* This character is not valid in the
+ * scheme */
+ break;
+ }
+ pos++;
+ }
+
+ if (*pos == ':') {
+ /* This delimits the end of the scheme */
+ size_t off;
+
+ marker.scheme_end = pos - url_s;
+
+ off = marker.scheme_end - marker.start;
+
+ /* Detect http(s) and mailto for scheme specifc
+ * normalisation */
+ if (off == SLEN("http") &&
+ (((*(pos - off + 0) == 'h') ||
+ (*(pos - off + 0) == 'H')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 't') ||
+ (*(pos - off + 2) == 'T')) &&
+ ((*(pos - off + 3) == 'p') ||
+ (*(pos - off + 3) == 'P')))) {
+ marker.scheme_type = NSURL_SCHEME_HTTP;
+ is_http = true;
+ } else if (off == SLEN("https") &&
+ (((*(pos - off + 0) == 'h') ||
+ (*(pos - off + 0) == 'H')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 't') ||
+ (*(pos - off + 2) == 'T')) &&
+ ((*(pos - off + 3) == 'p') ||
+ (*(pos - off + 3) == 'P')) &&
+ ((*(pos - off + 4) == 's') ||
+ (*(pos - off + 4) == 'S')))) {
+ marker.scheme_type = NSURL_SCHEME_HTTPS;
+ is_http = true;
+ } else if (off == SLEN("ftp") &&
+ (((*(pos - off + 0) == 'f') ||
+ (*(pos - off + 0) == 'F')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 'p') ||
+ (*(pos - off + 2) == 'P')))) {
+ marker.scheme_type = NSURL_SCHEME_FTP;
+ } else if (off == SLEN("mailto") &&
+ (((*(pos - off + 0) == 'm') ||
+ (*(pos - off + 0) == 'M')) &&
+ ((*(pos - off + 1) == 'a') ||
+ (*(pos - off + 1) == 'A')) &&
+ ((*(pos - off + 2) == 'i') ||
+ (*(pos - off + 2) == 'I')) &&
+ ((*(pos - off + 3) == 'l') ||
+ (*(pos - off + 3) == 'L')) &&
+ ((*(pos - off + 4) == 't') ||
+ (*(pos - off + 4) == 'T')) &&
+ ((*(pos - off + 5) == 'o') ||
+ (*(pos - off + 5) == 'O')))) {
+ marker.scheme_type = NSURL_SCHEME_MAILTO;
+ }
+
+ /* Skip over colon */
+ pos++;
+
+ /* Mark place as start of authority */
+ marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path =
+ pos - url_s;
+
+ } else {
+ /* Not found a scheme */
+ if (joining == false) {
+ /* Assuming no scheme == http */
+ marker.scheme_type = NSURL_SCHEME_HTTP;
+ is_http = true;
+ }
+ }
+ }
+
+ /* Get authority
+ *
+ * Two slashes always indicates the start of an authority.
+ *
+ * We are more relaxed in the case of http:
+ * a. when joining, one or more slashes indicates start of authority
+ * b. when not joining, we assume authority if no scheme was present
+ * and in the case of mailto: when we assume there is an authority.
+ */
+ if ((*pos == '/' && *(pos + 1) == '/') ||
+ (is_http && ((joining && *pos == '/') ||
+ (joining == false &&
+ marker.scheme_end != marker.start))) ||
+ marker.scheme_type == NSURL_SCHEME_MAILTO) {
+
+ /* Skip over leading slashes */
+ if (*pos == '/') {
+ if (is_http == false) {
+ if (*pos == '/') pos++;
+ if (*pos == '/') pos++;
+ } else {
+ while (*pos == '/')
+ pos++;
+ }
+
+ marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path =
+ pos - url_s;
+ }
+
+ /* Need to get (or complete) the authority */
+ while (*pos != '\0') {
+ if (*pos == '/' || *pos == '?' || *pos == '#') {
+ /* End of the authority */
+ break;
+
+ } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
+ *pos == ':' && marker.colon_first ==
+ marker.authority) {
+ /* could be username:password or host:port
+ * separator */
+ marker.colon_first = pos - url_s;
+
+ } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
+ *pos == ':' && marker.colon_first !=
+ marker.authority) {
+ /* could be host:port separator */
+ marker.colon_last = pos - url_s;
+
+ } else if (*pos == '@' && marker.at ==
+ marker.authority) {
+ /* Credentials @ host separator */
+ marker.at = pos - url_s;
+ }
+
+ pos++;
+ }
+
+ marker.path = pos - url_s;
+
+ } else if ((*pos == '\0' || *pos == '/') &&
+ joining == false && is_http == true) {
+ marker.path = pos - url_s;
+ }
+
+ /* Get path
+ *
+ * Needs to start with '/' if there's no authority
+ */
+ if (*pos == '/' || ((marker.path == marker.authority) &&
+ (*pos != '?') && (*pos != '#') && (*pos !=
'\0'))) {
+ while (*(++pos) != '\0') {
+ if (*pos == '?' || *pos == '#') {
+ /* End of the path */
+ break;
+ }
+ }
+ }
+
+ marker.query = pos - url_s;
+
+ /* Get query */
+ if (*pos == '?') {
+ while (*(++pos) != '\0') {
+ if (*pos == '#') {
+ /* End of the query */
+ break;
+ }
+ }
+ }
+
+ marker.fragment = pos - url_s;
+
+ /* Get fragment */
+ if (*pos == '#') {
+ while (*(++pos) != '\0')
+ ;
+ }
+
+ /* We got to the end of url_s.
+ * Need to skip back over trailing whitespace to find end of URL */
+ pos--;
+ if (pos >= url_s && ascii_is_space(*pos)) {
+ trailing_whitespace = true;
+ while (pos >= url_s && ascii_is_space(*pos))
+ pos--;
+ }
+
+ marker.end = pos + 1 - url_s;
+
+ if (trailing_whitespace == true) {
+ /* Ensure last url section doesn't pass end */
+ if (marker.fragment > marker.end)
+ marker.fragment = marker.end;
+ if (marker.query > marker.end)
+ marker.query = marker.end;
+ if (marker.path > marker.end)
+ marker.path = marker.end;
+ if (marker.colon_last > marker.end)
+ marker.colon_last = marker.end;
+ if (marker.at > marker.end)
+ marker.at = marker.end;
+ if (marker.colon_last > marker.end)
+ marker.colon_last = marker.end;
+ if (marker.fragment > marker.end)
+ marker.fragment = marker.end;
+ }
+
+#ifdef NSURL_DEBUG
+ LOG("marker.start: %i", marker.start);
+ LOG("marker.scheme_end: %i", marker.scheme_end);
+ LOG("marker.authority: %i", marker.authority);
+
+ LOG("marker.colon_first: %i", marker.colon_first);
+ LOG("marker.at: %i", marker.at);
+ LOG("marker.colon_last: %i", marker.colon_last);
+
+ LOG("marker.path: %i", marker.path);
+ LOG("marker.query: %i", marker.query);
+ LOG("marker.fragment: %i", marker.fragment);
+
+ LOG("marker.end: %i", marker.end);
+#endif
+
+ /* Got all the URL components pegged out now */
+ *markers = marker;
+}
+
+
+/**
+ * Remove dot segments from a path, as per rfc 3986, 5.2.4
+ *
+ * \param path path to remove dot segments from ('\0' terminated)
+ * \param output path with dot segments removed
+ * \return size of output
+ */
+static size_t nsurl__remove_dot_segments(char *path, char *output)
+{
+ char *path_pos = path;
+ char *output_pos = output;
+
+ while (*path_pos != '\0') {
+#ifdef NSURL_DEBUG
+ LOG(" in:%s", path_pos);
+ LOG("out:%.*s", output_pos - output, output);
+#endif
+ if (*path_pos == '.') {
+ if (*(path_pos + 1) == '.' &&
+ *(path_pos + 2) == '/') {
+ /* Found prefix of "../" */
+ path_pos += SLEN("../");
+ continue;
+
+ } else if (*(path_pos + 1) == '/') {
+ /* Found prefix of "./" */
+ path_pos += SLEN("./");
+ continue;
+ }
+ } else if (*path_pos == '/' && *(path_pos + 1) == '.') {
+ if (*(path_pos + 2) == '/') {
+ /* Found prefix of "/./" */
+ path_pos += SLEN("/.");
+ continue;
+
+ } else if (*(path_pos + 2) == '\0') {
+ /* Found "/." at end of path */
+ *(output_pos++) = '/';
+
+ /* End of input path */
+ break;
+
+ } else if (*(path_pos + 2) == '.') {
+ if (*(path_pos + 3) == '/') {
+ /* Found prefix of "/../" */
+ path_pos += SLEN("/..");
+
+ if (output_pos > output)
+ output_pos--;
+ while (output_pos > output &&
+ *output_pos != '/')
+ output_pos--;
+
+ continue;
+
+ } else if (*(path_pos + 3) == '\0') {
+ /* Found "/.." at end of path */
+
+ while (output_pos > output &&
+ *(output_pos -1 ) !='/')
+ output_pos--;
+
+ /* End of input path */
+ break;
+ }
+ }
+ } else if (*path_pos == '.') {
+ if (*(path_pos + 1) == '\0') {
+ /* Found "." at end of path */
+
+ /* End of input path */
+ break;
+
+ } else if (*(path_pos + 1) == '.' &&
+ *(path_pos + 2) == '\0') {
+ /* Found ".." at end of path */
+
+ /* End of input path */
+ break;
+ }
+ }
+ /* Copy first character into output path */
+ *output_pos++ = *path_pos++;
+
+ /* Copy up to but not including next '/' */
+ while ((*path_pos != '/') && (*path_pos != '\0'))
+ *output_pos++ = *path_pos++;
+ }
+
+ return output_pos - output;
+}
+
+
+/**
+ * Get the length of the longest section
+ *
+ * \param m markers delimiting url sections in a string
+ * \return the length of the longest section
+ */
+static size_t nsurl__get_longest_section(struct url_markers *m)
+{
+ size_t length = m->scheme_end - m->start; /* scheme */
+
+ if (length < m->at - m->authority) /* credentials */
+ length = m->at - m->authority;
+
+ if (length < m->path - m->at) /* host */
+ length = m->path - m->at;
+
+ if (length < m->query - m->path) /* path */
+ length = m->query - m->path;
+
+ if (length < m->fragment - m->query) /* query */
+ length = m->fragment - m->query;
+
+ if (length < m->end - m->fragment) /* fragment */
+ length = m->end - m->fragment;
+
+ return length;
+}
+
+
+/**
+ * Converts two hexadecimal digits to a single number
+ *
+ * \param c1 most significant hex digit
+ * \param c2 least significant hex digit
+ * \return the total value of the two digit hex number, or -ve if input not hex
+ *
+ * For unescaping url encoded characters.
+ */
+static inline int nsurl__get_ascii_offset(char c1, char c2)
+{
+ int offset;
+
+ /* Use 1st char as most significant hex digit */
+ if (ascii_is_digit(c1))
+ offset = 16 * (c1 - '0');
+ else if (c1 >= 'a' && c1 <= 'f')
+ offset = 16 * (c1 - 'a' + 10);
+ else if (c1 >= 'A' && c1 <= 'F')
+ offset = 16 * (c1 - 'A' + 10);
+ else
+ /* Not valid hex */
+ return -1;
+
+ /* Use 2nd char as least significant hex digit and sum */
+ if (ascii_is_digit(c2))
+ offset += c2 - '0';
+ else if (c2 >= 'a' && c2 <= 'f')
+ offset += c2 - 'a' + 10;
+ else if (c2 >= 'A' && c2 <= 'F')
+ offset += c2 - 'A' + 10;
+ else
+ /* Not valid hex */
+ return -1;
+
+ return offset;
+}
+
+
+/**
+ * Create the components of a NetSurf URL object for a section of a URL string
+ *
+ * \param url_s URL string
+ * \param section Sets which section of URL string is to be normalised
+ * \param pegs Set of markers delimiting the URL string's sections
+ * \param pos_norm A buffer large enough for the normalised string (*3 + 1)
+ * \param url A NetSurf URL object, to which components may be added
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * The section of url_s is normalised appropriately.
+ */
+static nserror nsurl__create_from_section(const char * const url_s,
+ const enum url_sections section,
+ const struct url_markers *pegs,
+ char *pos_norm,
+ struct nsurl_components *url)
+{
+ nserror ret;
+ int ascii_offset;
+ int start = 0;
+ int end = 0;
+ const char *pos;
+ const char *pos_url_s;
+ char *norm_start = pos_norm;
+ char *host;
+ size_t copy_len;
+ size_t length;
+ size_t host_len;
+ enum {
+ NSURL_F_NO_PORT = (1 << 0)
+ } flags = 0;
+
+ switch (section) {
+ case URL_SCHEME:
+ start = pegs->start;
+ end = pegs->scheme_end;
+ break;
+
+ case URL_CREDENTIALS:
+ start = pegs->authority;
+ end = pegs->at;
+ break;
+
+ case URL_HOST:
+ start = (pegs->at == pegs->authority &&
+ *(url_s + pegs->at) != '@') ?
+ pegs->at :
+ pegs->at + 1;
+ end = pegs->path;
+ break;
+
+ case URL_PATH:
+ start = pegs->path;
+ end = pegs->query;
+ break;
+
+ case URL_QUERY:
+ start = pegs->query;
+ end = pegs->fragment;
+ break;
+
+ case URL_FRAGMENT:
+ start = (*(url_s + pegs->fragment) != '#') ?
+ pegs->fragment :
+ pegs->fragment + 1;
+ end = pegs->end;
+ break;
+ }
+
+ if (end < start)
+ end = start;
+
+ length = end - start;
+
+ /* Stage 1: Normalise the required section */
+
+ pos = pos_url_s = url_s + start;
+ copy_len = 0;
+ for (; pos < url_s + end; pos++) {
+ if (*pos == '%' && (pos + 2 < url_s + end)) {
+ /* Might be an escaped character needing unescaped */
+
+ /* Find which character which was escaped */
+ ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
+ *(pos + 2));
+
+ if (ascii_offset < 0) {
+ /* % with invalid hex digits. */
+ copy_len++;
+ continue;
+ }
+
+ if ((section != URL_SCHEME && section != URL_HOST) &&
+ (nsurl__is_unreserved(ascii_offset) == false)) {
+ /* This character should be escaped after all,
+ * just let it get copied */
+ copy_len += 3;
+ pos += 2;
+ continue;
+ }
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+
+ /* Put the unescaped character in the normalised URL */
+ *(pos_norm++) = (char)ascii_offset;
+ pos += 2;
+ pos_url_s = pos + 1;
+
+ length -= 2;
+
+ } else if ((section != URL_SCHEME && section != URL_HOST) &&
+ (nsurl__is_no_escape(*pos) == false)) {
+
+ /* This needs to be escaped */
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+
+ /* escape */
+ *(pos_norm++) = '%';
+ *(pos_norm++) = digit2uppercase_hex(
+ ((unsigned char)*pos) >> 4);
+ *(pos_norm++) = digit2uppercase_hex(
+ ((unsigned char)*pos) & 0xf);
+ pos_url_s = pos + 1;
+
+ length += 2;
+
+ } else if ((section == URL_SCHEME || section == URL_HOST) &&
+ ascii_is_alpha_upper(*pos)) {
+ /* Lower case this letter */
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+ /* Copy lower cased letter into normalised URL */
+ *(pos_norm++) = ascii_to_lower(*pos);
+ pos_url_s = pos + 1;
+
+ } else {
+ /* This character is safe in normalised URL */
+ copy_len++;
+ }
+ }
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ }
+
+ /* Mark end of section */
+ (*pos_norm) = '\0';
+
+ /* Stage 2: Create the URL components for the required section */
+ switch (section) {
+ case URL_SCHEME:
+ if (length == 0) {
+ /* No scheme, assuming http */
+ url->scheme = lwc_string_ref(corestring_lwc_http);
+ } else {
+ /* Add scheme to URL */
+ if (lwc_intern_string(norm_start, length,
+ &url->scheme) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ break;
+
+ case URL_CREDENTIALS:
+ url->username = NULL;
+ url->password = NULL;
+
+ if (length != 0 && *norm_start != ':') {
+ char *sec_start = norm_start;
+ if (pegs->colon_first != pegs->authority &&
+ pegs->at > pegs->colon_first + 1) {
+ /* there's a password */
+ sec_start += pegs->colon_first -
+ pegs->authority + 1;
+ if (lwc_intern_string(sec_start,
+ pegs->at - pegs->colon_first -1,
+ &url->password) !=
+ lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+
+ /* update start pos and length for username */
+ sec_start = norm_start;
+ length -= pegs->at - pegs->colon_first;
+ } else if (pegs->colon_first != pegs->authority &&
+ pegs->at == pegs->colon_first + 1) {
+ /* strip username colon */
+ length--;
+ }
+
+ /* Username */
+ if (lwc_intern_string(sec_start, length,
+ &url->username) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ break;
+
+ case URL_HOST:
+ url->host = NULL;
+ url->port = NULL;
+
+ if (length != 0) {
+ size_t colon = 0;
+ char *sec_start = norm_start;
+ if (pegs->at < pegs->colon_first &&
+ pegs->colon_last == pegs->authority) {
+ /* There's one colon and it's after @ marker */
+ colon = pegs->colon_first;
+ } else if (pegs->colon_last != pegs->authority) {
+ /* There's more than one colon */
+ colon = pegs->colon_last;
+ } else {
+ /* There's no colon that could be a port
+ * separator */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ if (!(flags & NSURL_F_NO_PORT)) {
+ /* Determine whether colon is a port separator
+ */
+ sec_start += colon - pegs->at;
+ while (++sec_start < norm_start + length) {
+ if (!ascii_is_digit(*sec_start)) {
+ /* Character after port isn't a
+ * digit; not a port separator
+ */
+ flags |= NSURL_F_NO_PORT;
+ break;
+ }
+ }
+ }
+
+ if (!(flags & NSURL_F_NO_PORT)) {
+ /* There's a port */
+ size_t skip = (pegs->at == pegs->authority) ?
+ 1 : 0;
+ sec_start = norm_start + colon - pegs->at +
+ skip;
+ if (url->scheme != NULL &&
+ url->scheme_type ==
+ NSURL_SCHEME_HTTP &&
+ length -
+ (colon - pegs->at + skip) == 2 &&
+ *sec_start == '8' &&
+ *(sec_start + 1) == '0') {
+ /* Scheme is http, and port is default
+ * (80) */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ if (length <= (colon - pegs->at + skip)) {
+ /* No space for a port after the colon
+ */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ /* Add non-redundant ports to NetSurf URL */
+ sec_start = norm_start + colon - pegs->at +
+ skip;
+ if (!(flags & NSURL_F_NO_PORT) &&
+ lwc_intern_string(sec_start,
+ length -
+ (colon - pegs->at + skip),
+ &url->port) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+
+ /* update length for host */
+ skip = (pegs->at == pegs->authority) ? 0 : 1;
+ length = colon - pegs->at - skip;
+ }
+
+ /* host */
+ /* Encode host according to IDNA2008 */
+ ret = idna_encode(norm_start, length, &host, &host_len);
+ if (ret == NSERROR_OK) {
+ /* valid idna encoding */
+ if (lwc_intern_string(host, host_len,
+ &url->host) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ free(host);
+ } else {
+ /* fall back to straight interning */
+ if (lwc_intern_string(norm_start, length,
+ &url->host) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+ }
+
+ break;
+
+ case URL_PATH:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->path) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else if (url->host != NULL &&
+ url->scheme_type != NSURL_SCHEME_MAILTO) {
+ /* Set empty path to "/", if there's a host */
+ if (lwc_intern_string("/", SLEN("/"),
+ &url->path) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->path = NULL;
+ }
+
+ break;
+
+ case URL_QUERY:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->query) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->query = NULL;
+ }
+
+ break;
+
+ case URL_FRAGMENT:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->fragment) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->fragment = NULL;
+ }
+
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/* Exported function, documented in utils/nsurl/private.h */
+void nsurl__get_string_data(const struct nsurl_components *url,
+ nsurl_component parts, size_t *url_l,
+ struct nsurl_component_lengths *lengths,
+ enum nsurl_string_flags *pflags)
+{
+ enum nsurl_string_flags flags = *pflags;
+ *url_l = 0;
+
+ /* Intersection of required parts and available parts gives
+ * the output parts */
+ if (url->scheme && parts & NSURL_SCHEME) {
+ flags |= NSURL_F_SCHEME;
+
+ lengths->scheme = lwc_string_length(url->scheme);
+ *url_l += lengths->scheme;
+ }
+
+ if (url->username && parts & NSURL_USERNAME) {
+ flags |= NSURL_F_USERNAME;
+
+ lengths->username = lwc_string_length(url->username);
+ *url_l += lengths->username;
+ }
+
+ if (url->password && parts & NSURL_PASSWORD) {
+ flags |= NSURL_F_PASSWORD;
+
+ lengths->password = lwc_string_length(url->password);
+ *url_l += SLEN(":") + lengths->password;
+ }
+
+ if (url->host && parts & NSURL_HOST) {
+ flags |= NSURL_F_HOST;
+
+ lengths->host = lwc_string_length(url->host);
+ *url_l += lengths->host;
+ }
+
+ if (url->port && parts & NSURL_PORT) {
+ flags |= NSURL_F_PORT;
+
+ lengths->port = lwc_string_length(url->port);
+ *url_l += SLEN(":") + lengths->port;
+ }
+
+ if (url->path && parts & NSURL_PATH) {
+ flags |= NSURL_F_PATH;
+
+ lengths->path = lwc_string_length(url->path);
+ *url_l += lengths->path;
+ }
+
+ if (url->query && parts & NSURL_QUERY) {
+ flags |= NSURL_F_QUERY;
+
+ lengths->query = lwc_string_length(url->query);
+ *url_l += lengths->query;
+ }
+
+ if (url->fragment && parts & NSURL_FRAGMENT) {
+ flags |= NSURL_F_FRAGMENT;
+
+ lengths->fragment = lwc_string_length(url->fragment);
+ *url_l += lengths->fragment;
+ }
+
+ /* Turn on any spanned punctuation */
+ if ((flags & NSURL_F_SCHEME) && (parts > NSURL_SCHEME)) {
+ flags |= NSURL_F_SCHEME_PUNCTUATION;
+
+ *url_l += SLEN(":");
+ }
+
+ if ((flags & NSURL_F_SCHEME) && (flags > NSURL_F_SCHEME) &&
+ url->path && lwc_string_data(url->path)[0] == '/') {
+ flags |= NSURL_F_AUTHORITY_PUNCTUATION;
+
+ *url_l += SLEN("//");
+ }
+
+ if ((flags & (NSURL_F_USERNAME | NSURL_F_PASSWORD)) &&
+ flags & NSURL_F_HOST) {
+ flags |= NSURL_F_CREDENTIALS_PUNCTUATION;
+
+ *url_l += SLEN("@");
+ }
+
+ if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
+ flags |= NSURL_F_FRAGMENT_PUNCTUATION;
+
+ *url_l += SLEN("#");
+ }
+
+ *pflags = flags;
+}
+
+
+/* Exported function, documented in utils/nsurl/private.h */
+void nsurl__get_string(const struct nsurl_components *url, char *url_s,
+ struct nsurl_component_lengths *l,
+ enum nsurl_string_flags flags)
+{
+ char *pos;
+
+ /* Copy the required parts into the url string */
+ pos = url_s;
+
+ if (flags & NSURL_F_SCHEME) {
+ memcpy(pos, lwc_string_data(url->scheme), l->scheme);
+ pos += l->scheme;
+ }
+
+ if (flags & NSURL_F_SCHEME_PUNCTUATION) {
+ *(pos++) = ':';
+ }
+
+ if (flags & NSURL_F_AUTHORITY_PUNCTUATION) {
+ *(pos++) = '/';
+ *(pos++) = '/';
+ }
+
+ if (flags & NSURL_F_USERNAME) {
+ memcpy(pos, lwc_string_data(url->username), l->username);
+ pos += l->username;
+ }
+
+ if (flags & NSURL_F_PASSWORD) {
+ *(pos++) = ':';
+ memcpy(pos, lwc_string_data(url->password), l->password);
+ pos += l->password;
+ }
+
+ if (flags & NSURL_F_CREDENTIALS_PUNCTUATION) {
+ *(pos++) = '@';
+ }
+
+ if (flags & NSURL_F_HOST) {
+ memcpy(pos, lwc_string_data(url->host), l->host);
+ pos += l->host;
+ }
+
+ if (flags & NSURL_F_PORT) {
+ *(pos++) = ':';
+ memcpy(pos, lwc_string_data(url->port), l->port);
+ pos += l->port;
+ }
+
+ if (flags & NSURL_F_PATH) {
+ memcpy(pos, lwc_string_data(url->path), l->path);
+ pos += l->path;
+ }
+
+ if (flags & NSURL_F_QUERY) {
+ memcpy(pos, lwc_string_data(url->query), l->query);
+ pos += l->query;
+ }
+
+ if (flags & NSURL_F_FRAGMENT) {
+ if (flags & NSURL_F_FRAGMENT_PUNCTUATION)
+ *(pos++) = '#';
+ memcpy(pos, lwc_string_data(url->fragment), l->fragment);
+ pos += l->fragment;
+ }
+
+ *pos = '\0';
+}
+
+
+/**
+ * Calculate hash value
+ *
+ * \param url NetSurf URL object to set hash value for
+ */
+void nsurl__calc_hash(nsurl *url)
+{
+ uint32_t hash = 0;
+
+ if (url->components.scheme)
+ hash ^= lwc_string_hash_value(url->components.scheme);
+
+ if (url->components.username)
+ hash ^= lwc_string_hash_value(url->components.username);
+
+ if (url->components.password)
+ hash ^= lwc_string_hash_value(url->components.password);
+
+ if (url->components.host)
+ hash ^= lwc_string_hash_value(url->components.host);
+
+ if (url->components.port)
+ hash ^= lwc_string_hash_value(url->components.port);
+
+ if (url->components.path)
+ hash ^= lwc_string_hash_value(url->components.path);
+
+ if (url->components.query)
+ hash ^= lwc_string_hash_value(url->components.query);
+
+ url->hash = hash;
+}
+
+
+/**
+ * Destroy components
+ *
+ * \param c url components
+ */
+static void nsurl_destroy_components(struct nsurl_components *c)
+{
+ if (c->scheme)
+ lwc_string_unref(c->scheme);
+
+ if (c->username)
+ lwc_string_unref(c->username);
+
+ if (c->password)
+ lwc_string_unref(c->password);
+
+ if (c->host)
+ lwc_string_unref(c->host);
+
+ if (c->port)
+ lwc_string_unref(c->port);
+
+ if (c->path)
+ lwc_string_unref(c->path);
+
+ if (c->query)
+ lwc_string_unref(c->query);
+
+ if (c->fragment)
+ lwc_string_unref(c->fragment);
+}
+
+
+#ifdef NSURL_DEBUG
+/**
+ * Dump a NetSurf URL's internal components
+ *
+ * \param url The NetSurf URL to dump components of
+ */
+static void nsurl__dump(const nsurl *url)
+{
+ if (url->components.scheme)
+ LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
+
+ if (url->components.username)
+ LOG("Username: %s", lwc_string_data(url->components.username));
+
+ if (url->components.password)
+ LOG("Password: %s", lwc_string_data(url->components.password));
+
+ if (url->components.host)
+ LOG(" Host: %s", lwc_string_data(url->components.host));
+
+ if (url->components.port)
+ LOG(" Port: %s", lwc_string_data(url->components.port));
+
+ if (url->components.path)
+ LOG(" Path: %s", lwc_string_data(url->components.path));
+
+ if (url->components.query)
+ LOG(" Query: %s", lwc_string_data(url->components.query));
+
+ if (url->components.fragment)
+ LOG("Fragment: %s", lwc_string_data(url->components.fragment));
+}
+#endif
+
+/******************************************************************************
+ * NetSurf URL Public API *
+ ******************************************************************************/
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_create(const char * const url_s, nsurl **url)
+{
+ struct url_markers m;
+ struct nsurl_components c;
+ size_t length;
+ char *buff;
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ nserror e = NSERROR_OK;
+ bool match;
+
+ assert(url_s != NULL);
+
+ /* Peg out the URL sections */
+ nsurl__get_string_markers(url_s, &m, false);
+
+ /* Get the length of the longest section */
+ length = nsurl__get_longest_section(&m);
+
+ /* Allocate enough memory to url escape the longest section */
+ buff = malloc(length * 3 + 1);
+ if (buff == NULL)
+ return NSERROR_NOMEM;
+
+ /* Set scheme type */
+ c.scheme_type = m.scheme_type;
+
+ /* Build NetSurf URL object from sections */
+ e |= nsurl__create_from_section(url_s, URL_SCHEME, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_CREDENTIALS, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_HOST, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_PATH, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_QUERY, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_FRAGMENT, &m, buff, &c);
+
+ /* Finished with buffer */
+ free(buff);
+
+ if (e != NSERROR_OK) {
+ nsurl_destroy_components(&c);
+ return NSERROR_NOMEM;
+ }
+
+ /* Validate URL */
+ if ((lwc_string_isequal(c.scheme, corestring_lwc_http,
+ &match) == lwc_error_ok && match == true) ||
+ (lwc_string_isequal(c.scheme, corestring_lwc_https,
+ &match) == lwc_error_ok && match == true)) {
+ /* http, https must have host */
+ if (c.host == NULL) {
+ nsurl_destroy_components(&c);
+ return NSERROR_BAD_URL;
+ }
+ }
+
+ /* Get the string length and find which parts of url are present */
+ nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
+ &str_len, &str_flags);
+
+ /* Create NetSurf URL object */
+ *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*url == NULL) {
+ nsurl_destroy_components(&c);
+ return NSERROR_NOMEM;
+ }
+
+ (*url)->components = c;
+ (*url)->length = length;
+
+ /* Fill out the url string */
+ nsurl__get_string(&c, (*url)->string, &str_len, str_flags);
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*url);
+
+ /* Give the URL a reference */
+ (*url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
+{
+ struct url_markers m;
+ struct nsurl_components c;
+ size_t length;
+ char *buff;
+ char *buff_pos;
+ char *buff_start;
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ nserror error = 0;
+ enum {
+ NSURL_F_REL = 0,
+ NSURL_F_BASE_SCHEME = (1 << 0),
+ NSURL_F_BASE_AUTHORITY = (1 << 1),
+ NSURL_F_BASE_PATH = (1 << 2),
+ NSURL_F_MERGED_PATH = (1 << 3),
+ NSURL_F_BASE_QUERY = (1 << 4)
+ } joined_parts;
+
+ assert(base != NULL);
+ assert(rel != NULL);
+
+#ifdef NSURL_DEBUG
+ LOG("base: \"%s\", rel: \"%s\"", nsurl_access(base),
rel);
+#endif
+
+ /* Peg out the URL sections */
+ nsurl__get_string_markers(rel, &m, true);
+
+ /* Get the length of the longest section */
+ length = nsurl__get_longest_section(&m);
+
+ /* Initially assume that the joined URL can be formed entierly from
+ * the relative URL.
+ */
+ joined_parts = NSURL_F_REL;
+
+ /* Update joined_compnents to indicate any required parts from the
+ * base URL.
+ */
+ if (m.scheme_end - m.start <= 0) {
+ /* The relative url has no scheme.
+ * Use base URL's scheme. */
+ joined_parts |= NSURL_F_BASE_SCHEME;
+
+ if (m.path - m.authority <= 0) {
+ /* The relative URL has no authority.
+ * Use base URL's authority. */
+ joined_parts |= NSURL_F_BASE_AUTHORITY;
+
+ if (m.query - m.path <= 0) {
+ /* The relative URL has no path.
+ * Use base URL's path. */
+ joined_parts |= NSURL_F_BASE_PATH;
+
+ if (m.fragment - m.query <= 0) {
+ /* The relative URL has no query.
+ * Use base URL's query. */
+ joined_parts |= NSURL_F_BASE_QUERY;
+ }
+
+ } else if (*(rel + m.path) != '/') {
+ /* Relative URL has relative path */
+ joined_parts |= NSURL_F_MERGED_PATH;
+ }
+ }
+ }
+
+ /* Allocate enough memory to url escape the longest section, plus
+ * space for path merging (if required).
+ */
+ if (joined_parts & NSURL_F_MERGED_PATH) {
+ /* Need to merge paths */
+ length += (base->components.path != NULL) ?
+ lwc_string_length(base->components.path) : 0;
+ }
+ length *= 4;
+ /* Plus space for removing dots from path */
+ length += (m.query - m.path) + ((base->components.path != NULL) ?
+ lwc_string_length(base->components.path) : 0);
+
+ buff = malloc(length + 5);
+ if (buff == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ buff_pos = buff;
+
+ /* Form joined URL from base or rel components, as appropriate */
+
+ if (joined_parts & NSURL_F_BASE_SCHEME) {
+ c.scheme_type = base->components.scheme_type;
+
+ c.scheme = nsurl__component_copy(base->components.scheme);
+ } else {
+ c.scheme_type = m.scheme_type;
+
+ error = nsurl__create_from_section(rel, URL_SCHEME, &m, buff, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_AUTHORITY) {
+ c.username = nsurl__component_copy(base->components.username);
+ c.password = nsurl__component_copy(base->components.password);
+ c.host = nsurl__component_copy(base->components.host);
+ c.port = nsurl__component_copy(base->components.port);
+ } else {
+ error = nsurl__create_from_section(rel, URL_CREDENTIALS, &m,
+ buff, &c);
+ if (error == NSERROR_OK) {
+ error = nsurl__create_from_section(rel, URL_HOST, &m,
+ buff, &c);
+ }
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_PATH) {
+ c.path = nsurl__component_copy(base->components.path);
+
+ } else if (joined_parts & NSURL_F_MERGED_PATH) {
+ struct url_markers m_path;
+ size_t new_length;
+
+ if (base->components.host != NULL &&
+ base->components.path == NULL) {
+ /* Append relative path to "/". */
+ *(buff_pos++) = '/';
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+
+ } else {
+ /* Append relative path to all but last segment of
+ * base path. */
+ size_t path_end = lwc_string_length(
+ base->components.path);
+ const char *path = lwc_string_data(
+ base->components.path);
+
+ while (*(path + path_end) != '/' &&
+ path_end != 0) {
+ path_end--;
+ }
+ if (*(path + path_end) == '/')
+ path_end++;
+
+ /* Copy the base part */
+ memcpy(buff_pos, path, path_end);
+ buff_pos += path_end;
+
+ /* Copy the relative part */
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+ }
+
+ /* add termination to string */
+ *buff_pos++ = '\0';
+
+ new_length = nsurl__remove_dot_segments(buff, buff_pos);
+
+ m_path.path = 0;
+ m_path.query = new_length;
+
+ buff_start = buff_pos + new_length;
+ error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
+ buff_start, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+
+ } else {
+ struct url_markers m_path;
+ size_t new_length;
+
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+ *(buff_pos++) = '\0';
+
+ new_length = nsurl__remove_dot_segments(buff, buff_pos);
+
+ m_path.path = 0;
+ m_path.query = new_length;
+
+ buff_start = buff_pos + new_length;
+
+ error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
+ buff_start, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_QUERY) {
+ c.query = nsurl__component_copy(base->components.query);
+ } else {
+ error = nsurl__create_from_section(rel, URL_QUERY, &m,
+ buff, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ error = nsurl__create_from_section(rel, URL_FRAGMENT, &m, buff, &c);
+
+ /* Free temporary buffer */
+ free(buff);
+
+ if (error != NSERROR_OK) {
+ return error;
+ }
+
+ /* Get the string length and find which parts of url are present */
+ nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
+ &str_len, &str_flags);
+
+ /* Create NetSurf URL object */
+ *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*joined == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*joined)->components = c;
+ (*joined)->length = length;
+
+ /* Fill out the url string */
+ nsurl__get_string(&c, (*joined)->string, &str_len, str_flags);
+
+ /* Get the nsurl's hash */
+ nsurl__calc_hash(*joined);
+
+ /* Give the URL a reference */
+ (*joined)->count = 1;
+
+ return NSERROR_OK;
+}
+
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
index b8132c5..f8ba51f 100644
--- a/utils/nsurl/private.h
+++ b/utils/nsurl/private.h
@@ -21,6 +21,7 @@
#include <libwapcaplet/libwapcaplet.h>
+#include "utils/nsurl.h"
#include "utils/utils.h"
/** A type for URL schemes */
@@ -72,4 +73,71 @@ struct nsurl {
char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
};
+
+/** Marker set, indicating positions of sections within a URL string */
+struct nsurl_component_lengths {
+ size_t scheme;
+ size_t username;
+ size_t password;
+ size_t host;
+ size_t port;
+ size_t path;
+ size_t query;
+ size_t fragment;
+};
+
+
+/** Flags indicating which parts of a URL string are required for a nsurl */
+enum nsurl_string_flags {
+ NSURL_F_SCHEME = (1 << 0),
+ NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
+ NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
+ NSURL_F_USERNAME = (1 << 3),
+ NSURL_F_PASSWORD = (1 << 4),
+ NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
+ NSURL_F_HOST = (1 << 6),
+ NSURL_F_PORT = (1 << 7),
+ NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
+ NSURL_F_PASSWORD |
+ NSURL_F_HOST |
+ NSURL_F_PORT),
+ NSURL_F_PATH = (1 << 8),
+ NSURL_F_QUERY = (1 << 9),
+ NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
+ NSURL_F_FRAGMENT = (1 << 11)
+};
+
+/**
+ * Get nsurl string info; total length, component lengths, & components present
+ *
+ * \param url NetSurf URL components
+ * \param url_s Updated to contain the string
+ * \param l Individual component lengths
+ * \param flags String flags
+ */
+void nsurl__get_string(const struct nsurl_components *url, char *url_s,
+ struct nsurl_component_lengths *l,
+ enum nsurl_string_flags flags);
+
+/**
+ * Get nsurl string info; total length, component lengths, & components present
+ *
+ * \param url NetSurf URL components
+ * \param parts Which parts of the URL are required in the string
+ * \param url_l Updated to total string length
+ * \param lengths Updated with individual component lengths
+ * \param pflags Updated to contain relevant string flags
+ */
+void nsurl__get_string_data(const struct nsurl_components *url,
+ nsurl_component parts, size_t *url_l,
+ struct nsurl_component_lengths *lengths,
+ enum nsurl_string_flags *pflags);
+
+/**
+ * Calculate hash value
+ *
+ * \param url NetSurf URL object to set hash value for
+ */
+void nsurl__calc_hash(nsurl *url);
+
#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=4c47f9c04626811e455...
commit 4c47f9c04626811e455bee76fd15622bd8dc6ca0
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nsurl: Split internal structure out into private header.
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
index c5c614c..bc77c58 100644
--- a/utils/nsurl/nsurl.c
+++ b/utils/nsurl/nsurl.c
@@ -42,62 +42,13 @@
#include "utils/errors.h"
#include "utils/idna.h"
#include "utils/log.h"
+#include "utils/nsurl/private.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
/* Define to enable NSURL debugging */
#undef NSURL_DEBUG
-/**
- * nsurl scheme type
- */
-enum scheme_type {
- NSURL_SCHEME_OTHER,
- NSURL_SCHEME_HTTP,
- NSURL_SCHEME_HTTPS,
- NSURL_SCHEME_FTP,
- NSURL_SCHEME_MAILTO
-};
-
-/**
- * nsurl components
- *
- * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
- *
- * Note:
- * "path" string includes preceding '/', if needed for the scheme
- * "query" string always includes preceding '?'
- *
- * The other spanned punctuation is to be inserted when building URLs from
- * components.
- */
-struct nsurl_components {
- lwc_string *scheme;
- lwc_string *username;
- lwc_string *password;
- lwc_string *host;
- lwc_string *port;
- lwc_string *path;
- lwc_string *query;
- lwc_string *fragment;
-
- enum scheme_type scheme_type;
-};
-
-
-/**
- * NetSurf URL object
- */
-struct nsurl {
- struct nsurl_components components;
-
- int count; /* Number of references to NetSurf URL object */
- uint32_t hash; /* Hash value for nsurl identification */
-
- size_t length; /* Length of string */
- char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
-};
-
/** Marker set, indicating positions of sections within a URL string */
struct url_markers {
@@ -115,7 +66,7 @@ struct url_markers {
size_t end; /** end of URL */
- enum scheme_type scheme_type;
+ enum nsurl_scheme_type scheme_type;
};
diff --git a/utils/nsurl/private.h b/utils/nsurl/private.h
new file mode 100644
index 0000000..b8132c5
--- /dev/null
+++ b/utils/nsurl/private.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011-2017 Michael Drake <tlsa(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/>.
+ */
+
+#ifndef NETSURF_UTILS_NSURL_PRIVATE_H_
+#define NETSURF_UTILS_NSURL_PRIVATE_H_
+
+#include <libwapcaplet/libwapcaplet.h>
+
+#include "utils/utils.h"
+
+/** A type for URL schemes */
+enum nsurl_scheme_type {
+ NSURL_SCHEME_OTHER,
+ NSURL_SCHEME_HTTP,
+ NSURL_SCHEME_HTTPS,
+ NSURL_SCHEME_FTP,
+ NSURL_SCHEME_MAILTO
+};
+
+
+/**
+ * nsurl components
+ *
+ * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
+ *
+ * Note:
+ * "path" string includes preceding '/', if needed for the scheme
+ * "query" string always includes preceding '?'
+ *
+ * The other spanned punctuation is to be inserted when building URLs from
+ * components.
+ */
+struct nsurl_components {
+ lwc_string *scheme;
+ lwc_string *username;
+ lwc_string *password;
+ lwc_string *host;
+ lwc_string *port;
+ lwc_string *path;
+ lwc_string *query;
+ lwc_string *fragment;
+
+ enum nsurl_scheme_type scheme_type;
+};
+
+
+/**
+ * NetSurf URL object
+ */
+struct nsurl {
+ struct nsurl_components components;
+
+ int count; /* Number of references to NetSurf URL object */
+ uint32_t hash; /* Hash value for nsurl identification */
+
+ size_t length; /* Length of string */
+ char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
+};
+
+#endif
commitdiff
http://git.netsurf-browser.org/netsurf.git/commit/?id=299a85fa7a4ee259e75...
commit 299a85fa7a4ee259e757b8ffd6e482410e6726f1
Author: Michael Drake <tlsa(a)netsurf-browser.org>
Commit: Michael Drake <tlsa(a)netsurf-browser.org>
nusrl: Move into utils/nsurl directory.
diff --git a/Makefile b/Makefile
index 5f2697f..97a8128 100644
--- a/Makefile
+++ b/Makefile
@@ -621,12 +621,22 @@ include utils/Makefile
# http utility sources
include utils/http/Makefile
+# nsurl utility sources
+include utils/nsurl/Makefile
+
# Desktop sources
include desktop/Makefile
# S_COMMON are sources common to all builds
-S_COMMON := $(S_CONTENT) $(S_FETCHERS) $(S_RENDER) $(S_UTILS) $(S_HTTP) \
- $(S_DESKTOP) $(S_JAVASCRIPT_BINDING)
+S_COMMON := \
+ $(S_CONTENT) \
+ $(S_FETCHERS) \
+ $(S_RENDER) \
+ $(S_UTILS) \
+ $(S_HTTP) \
+ $(S_NSURL) \
+ $(S_DESKTOP) \
+ $(S_JAVASCRIPT_BINDING)
# ----------------------------------------------------------------------------
diff --git a/utils/Makefile b/utils/Makefile
index 62b7e05..2f59501 100644
--- a/utils/Makefile
+++ b/utils/Makefile
@@ -12,7 +12,6 @@ S_UTILS := \
log.c \
messages.c \
nsoption.c \
- nsurl.c \
punycode.c \
talloc.c \
time.c \
diff --git a/utils/nsurl.c b/utils/nsurl.c
deleted file mode 100644
index c5c614c..0000000
--- a/utils/nsurl.c
+++ /dev/null
@@ -1,2500 +0,0 @@
-/*
- * Copyright 2011 Michael Drake <tlsa(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
- * NetSurf URL handling implementation.
- *
- * This is the common implementation of all URL handling within the
- * browser. This implementation is based upon RFC3986 although this has
- * been superceeded by
https://url.spec.whatwg.org/ which is based on
- * actual contemporary implementations.
- *
- * Care must be taken with character encodings within this module as
- * the specifications work with specific ascii ranges and must not be
- * affected by locale. Hence the c library character type functions
- * are not used.
- */
-
-#include <assert.h>
-#include <libwapcaplet/libwapcaplet.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-#include "utils/ascii.h"
-#include "utils/corestrings.h"
-#include "utils/errors.h"
-#include "utils/idna.h"
-#include "utils/log.h"
-#include "utils/nsurl.h"
-#include "utils/utils.h"
-
-/* Define to enable NSURL debugging */
-#undef NSURL_DEBUG
-
-/**
- * nsurl scheme type
- */
-enum scheme_type {
- NSURL_SCHEME_OTHER,
- NSURL_SCHEME_HTTP,
- NSURL_SCHEME_HTTPS,
- NSURL_SCHEME_FTP,
- NSURL_SCHEME_MAILTO
-};
-
-/**
- * nsurl components
- *
- * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
- *
- * Note:
- * "path" string includes preceding '/', if needed for the scheme
- * "query" string always includes preceding '?'
- *
- * The other spanned punctuation is to be inserted when building URLs from
- * components.
- */
-struct nsurl_components {
- lwc_string *scheme;
- lwc_string *username;
- lwc_string *password;
- lwc_string *host;
- lwc_string *port;
- lwc_string *path;
- lwc_string *query;
- lwc_string *fragment;
-
- enum scheme_type scheme_type;
-};
-
-
-/**
- * NetSurf URL object
- */
-struct nsurl {
- struct nsurl_components components;
-
- int count; /* Number of references to NetSurf URL object */
- uint32_t hash; /* Hash value for nsurl identification */
-
- size_t length; /* Length of string */
- char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
-};
-
-
-/** Marker set, indicating positions of sections within a URL string */
-struct url_markers {
- size_t start; /** start of URL */
- size_t scheme_end;
- size_t authority;
-
- size_t colon_first;
- size_t at;
- size_t colon_last;
-
- size_t path;
- size_t query;
- size_t fragment;
-
- size_t end; /** end of URL */
-
- enum scheme_type scheme_type;
-};
-
-
-/** Marker set, indicating positions of sections within a URL string */
-struct nsurl_component_lengths {
- size_t scheme;
- size_t username;
- size_t password;
- size_t host;
- size_t port;
- size_t path;
- size_t query;
- size_t fragment;
-};
-
-
-/** Flags indicating which parts of a URL string are required for a nsurl */
-enum nsurl_string_flags {
- NSURL_F_SCHEME = (1 << 0),
- NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
- NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
- NSURL_F_USERNAME = (1 << 3),
- NSURL_F_PASSWORD = (1 << 4),
- NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
- NSURL_F_HOST = (1 << 6),
- NSURL_F_PORT = (1 << 7),
- NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
- NSURL_F_PASSWORD |
- NSURL_F_HOST |
- NSURL_F_PORT),
- NSURL_F_PATH = (1 << 8),
- NSURL_F_QUERY = (1 << 9),
- NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
- NSURL_F_FRAGMENT = (1 << 11)
-};
-
-
-/** Sections of a URL */
-enum url_sections {
- URL_SCHEME,
- URL_CREDENTIALS,
- URL_HOST,
- URL_PATH,
- URL_QUERY,
- URL_FRAGMENT
-};
-
-
-#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
-
-#define nsurl__component_compare(c1, c2, match) \
- if (c1 && c2 && lwc_error_ok == \
- lwc_string_isequal(c1, c2, match)) { \
- /* do nothing */ \
- } else if (c1 || c2) { \
- *match = false; \
- }
-
-/**
- * Return a hex digit for the given numerical value.
- *
- * \param digit the value to get the hex digit for.
- * \return character in range 0-9A-F
- */
-inline static char digit2uppercase_hex(unsigned char digit) {
- assert(digit < 16);
- return "0123456789ABCDEF"[digit];
-}
-
-/**
- * determine if a character is unreserved
- *
- * \param c character to classify.
- * \return true if the character is unreserved else false.
- */
-static bool nsurl__is_unreserved(unsigned char c)
-{
- /* From RFC3986 section 2.3 (unreserved characters)
- *
- * unreserved = ALPHA / DIGIT / "-" / "." / "_" /
"~"
- *
- */
- static const bool unreserved[256] = {
- false, false, false, false, false, false, false, false, /* 00 */
- false, false, false, false, false, false, false, false, /* 08 */
- false, false, false, false, false, false, false, false, /* 10 */
- false, false, false, false, false, false, false, false, /* 18 */
- false, false, false, false, false, false, false, false, /* 20 */
- false, false, false, false, false, true, true, false, /* 28 */
- true, true, true, true, true, true, true, true, /* 30 */
- true, true, false, false, false, false, false, false, /* 38 */
- false, true, true, true, true, true, true, true, /* 40 */
- true, true, true, true, true, true, true, true, /* 48 */
- true, true, true, true, true, true, true, true, /* 50 */
- true, true, true, false, false, false, false, true, /* 58 */
- false, true, true, true, true, true, true, true, /* 60 */
- true, true, true, true, true, true, true, true, /* 68 */
- true, true, true, true, true, true, true, true, /* 70 */
- true, true, true, false, false, false, true, false, /* 78 */
- false, false, false, false, false, false, false, false, /* 80 */
- false, false, false, false, false, false, false, false, /* 88 */
- false, false, false, false, false, false, false, false, /* 90 */
- false, false, false, false, false, false, false, false, /* 98 */
- false, false, false, false, false, false, false, false, /* A0 */
- false, false, false, false, false, false, false, false, /* A8 */
- false, false, false, false, false, false, false, false, /* B0 */
- false, false, false, false, false, false, false, false, /* B8 */
- false, false, false, false, false, false, false, false, /* C0 */
- false, false, false, false, false, false, false, false, /* C8 */
- false, false, false, false, false, false, false, false, /* D0 */
- false, false, false, false, false, false, false, false, /* D8 */
- false, false, false, false, false, false, false, false, /* E0 */
- false, false, false, false, false, false, false, false, /* E8 */
- false, false, false, false, false, false, false, false, /* F0 */
- false, false, false, false, false, false, false, false /* F8 */
- };
- return unreserved[c];
-}
-
-/**
- * determine if a character should be percent escaped.
- *
- * The ASCII codes which should not be percent escaped
- *
- * \param c character to classify.
- * \return true if the character should not be escaped else false.
- */
-static bool nsurl__is_no_escape(unsigned char c)
-{
- static const bool no_escape[256] = {
- false, false, false, false, false, false, false, false, /* 00 */
- false, false, false, false, false, false, false, false, /* 08 */
- false, false, false, false, false, false, false, false, /* 10 */
- false, false, false, false, false, false, false, false, /* 18 */
- false, true, false, true, true, false, true, true, /* 20 */
- true, true, true, true, true, true, true, true, /* 28 */
- true, true, true, true, true, true, true, true, /* 30 */
- true, true, true, true, false, true, false, true, /* 38 */
- true, true, true, true, true, true, true, true, /* 40 */
- true, true, true, true, true, true, true, true, /* 48 */
- true, true, true, true, true, true, true, true, /* 50 */
- true, true, true, true, false, true, false, true, /* 58 */
- false, true, true, true, true, true, true, true, /* 60 */
- true, true, true, true, true, true, true, true, /* 68 */
- true, true, true, true, true, true, true, true, /* 70 */
- true, true, true, false, true, false, true, false, /* 78 */
- false, false, false, false, false, false, false, false, /* 80 */
- false, false, false, false, false, false, false, false, /* 88 */
- false, false, false, false, false, false, false, false, /* 90 */
- false, false, false, false, false, false, false, false, /* 98 */
- false, false, false, false, false, false, false, false, /* A0 */
- false, false, false, false, false, false, false, false, /* A8 */
- false, false, false, false, false, false, false, false, /* B0 */
- false, false, false, false, false, false, false, false, /* B8 */
- false, false, false, false, false, false, false, false, /* C0 */
- false, false, false, false, false, false, false, false, /* C8 */
- false, false, false, false, false, false, false, false, /* D0 */
- false, false, false, false, false, false, false, false, /* D8 */
- false, false, false, false, false, false, false, false, /* E0 */
- false, false, false, false, false, false, false, false, /* E8 */
- false, false, false, false, false, false, false, false, /* F0 */
- false, false, false, false, false, false, false, false, /* F8 */
- };
- return no_escape[c];
-}
-
-
-/**
- * Obtains a set of markers delimiting sections in a URL string
- *
- * \param url_s URL string
- * \param markers Updated to mark sections in the URL string
- * \param joining True iff URL string is a relative URL for joining
- */
-static void nsurl__get_string_markers(const char * const url_s,
- struct url_markers *markers, bool joining)
-{
- const char *pos = url_s; /** current position in url_s */
- bool is_http = false;
- bool trailing_whitespace = false;
-
- /* Initialise marker set */
- struct url_markers marker = { 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, NSURL_SCHEME_OTHER };
-
- /* Skip any leading whitespace in url_s */
- while (ascii_is_space(*pos))
- pos++;
-
- /* Record start point */
- marker.start = pos - url_s;
-
- marker.scheme_end = marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path = marker.start;
-
- if (*pos == '\0') {
- /* Nothing but whitespace, early exit */
- marker.query = marker.fragment = marker.end = marker.path;
- *markers = marker;
- return;
- }
-
- /* Get scheme */
- if (ascii_is_alpha(*pos)) {
- pos++;
-
- while (*pos != ':' && *pos != '\0') {
- if (!ascii_is_alphanumerical(*pos) && (*pos != '+') &&
- (*pos != '-') && (*pos != '.')) {
- /* This character is not valid in the
- * scheme */
- break;
- }
- pos++;
- }
-
- if (*pos == ':') {
- /* This delimits the end of the scheme */
- size_t off;
-
- marker.scheme_end = pos - url_s;
-
- off = marker.scheme_end - marker.start;
-
- /* Detect http(s) and mailto for scheme specifc
- * normalisation */
- if (off == SLEN("http") &&
- (((*(pos - off + 0) == 'h') ||
- (*(pos - off + 0) == 'H')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 't') ||
- (*(pos - off + 2) == 'T')) &&
- ((*(pos - off + 3) == 'p') ||
- (*(pos - off + 3) == 'P')))) {
- marker.scheme_type = NSURL_SCHEME_HTTP;
- is_http = true;
- } else if (off == SLEN("https") &&
- (((*(pos - off + 0) == 'h') ||
- (*(pos - off + 0) == 'H')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 't') ||
- (*(pos - off + 2) == 'T')) &&
- ((*(pos - off + 3) == 'p') ||
- (*(pos - off + 3) == 'P')) &&
- ((*(pos - off + 4) == 's') ||
- (*(pos - off + 4) == 'S')))) {
- marker.scheme_type = NSURL_SCHEME_HTTPS;
- is_http = true;
- } else if (off == SLEN("ftp") &&
- (((*(pos - off + 0) == 'f') ||
- (*(pos - off + 0) == 'F')) &&
- ((*(pos - off + 1) == 't') ||
- (*(pos - off + 1) == 'T')) &&
- ((*(pos - off + 2) == 'p') ||
- (*(pos - off + 2) == 'P')))) {
- marker.scheme_type = NSURL_SCHEME_FTP;
- } else if (off == SLEN("mailto") &&
- (((*(pos - off + 0) == 'm') ||
- (*(pos - off + 0) == 'M')) &&
- ((*(pos - off + 1) == 'a') ||
- (*(pos - off + 1) == 'A')) &&
- ((*(pos - off + 2) == 'i') ||
- (*(pos - off + 2) == 'I')) &&
- ((*(pos - off + 3) == 'l') ||
- (*(pos - off + 3) == 'L')) &&
- ((*(pos - off + 4) == 't') ||
- (*(pos - off + 4) == 'T')) &&
- ((*(pos - off + 5) == 'o') ||
- (*(pos - off + 5) == 'O')))) {
- marker.scheme_type = NSURL_SCHEME_MAILTO;
- }
-
- /* Skip over colon */
- pos++;
-
- /* Mark place as start of authority */
- marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path =
- pos - url_s;
-
- } else {
- /* Not found a scheme */
- if (joining == false) {
- /* Assuming no scheme == http */
- marker.scheme_type = NSURL_SCHEME_HTTP;
- is_http = true;
- }
- }
- }
-
- /* Get authority
- *
- * Two slashes always indicates the start of an authority.
- *
- * We are more relaxed in the case of http:
- * a. when joining, one or more slashes indicates start of authority
- * b. when not joining, we assume authority if no scheme was present
- * and in the case of mailto: when we assume there is an authority.
- */
- if ((*pos == '/' && *(pos + 1) == '/') ||
- (is_http && ((joining && *pos == '/') ||
- (joining == false &&
- marker.scheme_end != marker.start))) ||
- marker.scheme_type == NSURL_SCHEME_MAILTO) {
-
- /* Skip over leading slashes */
- if (*pos == '/') {
- if (is_http == false) {
- if (*pos == '/') pos++;
- if (*pos == '/') pos++;
- } else {
- while (*pos == '/')
- pos++;
- }
-
- marker.authority = marker.colon_first = marker.at =
- marker.colon_last = marker.path =
- pos - url_s;
- }
-
- /* Need to get (or complete) the authority */
- while (*pos != '\0') {
- if (*pos == '/' || *pos == '?' || *pos == '#') {
- /* End of the authority */
- break;
-
- } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
- *pos == ':' && marker.colon_first ==
- marker.authority) {
- /* could be username:password or host:port
- * separator */
- marker.colon_first = pos - url_s;
-
- } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
- *pos == ':' && marker.colon_first !=
- marker.authority) {
- /* could be host:port separator */
- marker.colon_last = pos - url_s;
-
- } else if (*pos == '@' && marker.at ==
- marker.authority) {
- /* Credentials @ host separator */
- marker.at = pos - url_s;
- }
-
- pos++;
- }
-
- marker.path = pos - url_s;
-
- } else if ((*pos == '\0' || *pos == '/') &&
- joining == false && is_http == true) {
- marker.path = pos - url_s;
- }
-
- /* Get path
- *
- * Needs to start with '/' if there's no authority
- */
- if (*pos == '/' || ((marker.path == marker.authority) &&
- (*pos != '?') && (*pos != '#') && (*pos !=
'\0'))) {
- while (*(++pos) != '\0') {
- if (*pos == '?' || *pos == '#') {
- /* End of the path */
- break;
- }
- }
- }
-
- marker.query = pos - url_s;
-
- /* Get query */
- if (*pos == '?') {
- while (*(++pos) != '\0') {
- if (*pos == '#') {
- /* End of the query */
- break;
- }
- }
- }
-
- marker.fragment = pos - url_s;
-
- /* Get fragment */
- if (*pos == '#') {
- while (*(++pos) != '\0')
- ;
- }
-
- /* We got to the end of url_s.
- * Need to skip back over trailing whitespace to find end of URL */
- pos--;
- if (pos >= url_s && ascii_is_space(*pos)) {
- trailing_whitespace = true;
- while (pos >= url_s && ascii_is_space(*pos))
- pos--;
- }
-
- marker.end = pos + 1 - url_s;
-
- if (trailing_whitespace == true) {
- /* Ensure last url section doesn't pass end */
- if (marker.fragment > marker.end)
- marker.fragment = marker.end;
- if (marker.query > marker.end)
- marker.query = marker.end;
- if (marker.path > marker.end)
- marker.path = marker.end;
- if (marker.colon_last > marker.end)
- marker.colon_last = marker.end;
- if (marker.at > marker.end)
- marker.at = marker.end;
- if (marker.colon_last > marker.end)
- marker.colon_last = marker.end;
- if (marker.fragment > marker.end)
- marker.fragment = marker.end;
- }
-
-#ifdef NSURL_DEBUG
- LOG("marker.start: %i", marker.start);
- LOG("marker.scheme_end: %i", marker.scheme_end);
- LOG("marker.authority: %i", marker.authority);
-
- LOG("marker.colon_first: %i", marker.colon_first);
- LOG("marker.at: %i", marker.at);
- LOG("marker.colon_last: %i", marker.colon_last);
-
- LOG("marker.path: %i", marker.path);
- LOG("marker.query: %i", marker.query);
- LOG("marker.fragment: %i", marker.fragment);
-
- LOG("marker.end: %i", marker.end);
-#endif
-
- /* Got all the URL components pegged out now */
- *markers = marker;
-}
-
-
-/**
- * Remove dot segments from a path, as per rfc 3986, 5.2.4
- *
- * \param path path to remove dot segments from ('\0' terminated)
- * \param output path with dot segments removed
- * \return size of output
- */
-static size_t nsurl__remove_dot_segments(char *path, char *output)
-{
- char *path_pos = path;
- char *output_pos = output;
-
- while (*path_pos != '\0') {
-#ifdef NSURL_DEBUG
- LOG(" in:%s", path_pos);
- LOG("out:%.*s", output_pos - output, output);
-#endif
- if (*path_pos == '.') {
- if (*(path_pos + 1) == '.' &&
- *(path_pos + 2) == '/') {
- /* Found prefix of "../" */
- path_pos += SLEN("../");
- continue;
-
- } else if (*(path_pos + 1) == '/') {
- /* Found prefix of "./" */
- path_pos += SLEN("./");
- continue;
- }
- } else if (*path_pos == '/' && *(path_pos + 1) == '.') {
- if (*(path_pos + 2) == '/') {
- /* Found prefix of "/./" */
- path_pos += SLEN("/.");
- continue;
-
- } else if (*(path_pos + 2) == '\0') {
- /* Found "/." at end of path */
- *(output_pos++) = '/';
-
- /* End of input path */
- break;
-
- } else if (*(path_pos + 2) == '.') {
- if (*(path_pos + 3) == '/') {
- /* Found prefix of "/../" */
- path_pos += SLEN("/..");
-
- if (output_pos > output)
- output_pos--;
- while (output_pos > output &&
- *output_pos != '/')
- output_pos--;
-
- continue;
-
- } else if (*(path_pos + 3) == '\0') {
- /* Found "/.." at end of path */
-
- while (output_pos > output &&
- *(output_pos -1 ) !='/')
- output_pos--;
-
- /* End of input path */
- break;
- }
- }
- } else if (*path_pos == '.') {
- if (*(path_pos + 1) == '\0') {
- /* Found "." at end of path */
-
- /* End of input path */
- break;
-
- } else if (*(path_pos + 1) == '.' &&
- *(path_pos + 2) == '\0') {
- /* Found ".." at end of path */
-
- /* End of input path */
- break;
- }
- }
- /* Copy first character into output path */
- *output_pos++ = *path_pos++;
-
- /* Copy up to but not including next '/' */
- while ((*path_pos != '/') && (*path_pos != '\0'))
- *output_pos++ = *path_pos++;
- }
-
- return output_pos - output;
-}
-
-
-/**
- * Get the length of the longest section
- *
- * \param m markers delimiting url sections in a string
- * \return the length of the longest section
- */
-static size_t nsurl__get_longest_section(struct url_markers *m)
-{
- size_t length = m->scheme_end - m->start; /* scheme */
-
- if (length < m->at - m->authority) /* credentials */
- length = m->at - m->authority;
-
- if (length < m->path - m->at) /* host */
- length = m->path - m->at;
-
- if (length < m->query - m->path) /* path */
- length = m->query - m->path;
-
- if (length < m->fragment - m->query) /* query */
- length = m->fragment - m->query;
-
- if (length < m->end - m->fragment) /* fragment */
- length = m->end - m->fragment;
-
- return length;
-}
-
-
-/**
- * Converts two hexadecimal digits to a single number
- *
- * \param c1 most significant hex digit
- * \param c2 least significant hex digit
- * \return the total value of the two digit hex number, or -ve if input not hex
- *
- * For unescaping url encoded characters.
- */
-static inline int nsurl__get_ascii_offset(char c1, char c2)
-{
- int offset;
-
- /* Use 1st char as most significant hex digit */
- if (ascii_is_digit(c1))
- offset = 16 * (c1 - '0');
- else if (c1 >= 'a' && c1 <= 'f')
- offset = 16 * (c1 - 'a' + 10);
- else if (c1 >= 'A' && c1 <= 'F')
- offset = 16 * (c1 - 'A' + 10);
- else
- /* Not valid hex */
- return -1;
-
- /* Use 2nd char as least significant hex digit and sum */
- if (ascii_is_digit(c2))
- offset += c2 - '0';
- else if (c2 >= 'a' && c2 <= 'f')
- offset += c2 - 'a' + 10;
- else if (c2 >= 'A' && c2 <= 'F')
- offset += c2 - 'A' + 10;
- else
- /* Not valid hex */
- return -1;
-
- return offset;
-}
-
-
-/**
- * Create the components of a NetSurf URL object for a section of a URL string
- *
- * \param url_s URL string
- * \param section Sets which section of URL string is to be normalised
- * \param pegs Set of markers delimiting the URL string's sections
- * \param pos_norm A buffer large enough for the normalised string (*3 + 1)
- * \param url A NetSurf URL object, to which components may be added
- * \return NSERROR_OK on success, appropriate error otherwise
- *
- * The section of url_s is normalised appropriately.
- */
-static nserror nsurl__create_from_section(const char * const url_s,
- const enum url_sections section,
- const struct url_markers *pegs,
- char *pos_norm,
- struct nsurl_components *url)
-{
- nserror ret;
- int ascii_offset;
- int start = 0;
- int end = 0;
- const char *pos;
- const char *pos_url_s;
- char *norm_start = pos_norm;
- char *host;
- size_t copy_len;
- size_t length;
- size_t host_len;
- enum {
- NSURL_F_NO_PORT = (1 << 0)
- } flags = 0;
-
- switch (section) {
- case URL_SCHEME:
- start = pegs->start;
- end = pegs->scheme_end;
- break;
-
- case URL_CREDENTIALS:
- start = pegs->authority;
- end = pegs->at;
- break;
-
- case URL_HOST:
- start = (pegs->at == pegs->authority &&
- *(url_s + pegs->at) != '@') ?
- pegs->at :
- pegs->at + 1;
- end = pegs->path;
- break;
-
- case URL_PATH:
- start = pegs->path;
- end = pegs->query;
- break;
-
- case URL_QUERY:
- start = pegs->query;
- end = pegs->fragment;
- break;
-
- case URL_FRAGMENT:
- start = (*(url_s + pegs->fragment) != '#') ?
- pegs->fragment :
- pegs->fragment + 1;
- end = pegs->end;
- break;
- }
-
- if (end < start)
- end = start;
-
- length = end - start;
-
- /* Stage 1: Normalise the required section */
-
- pos = pos_url_s = url_s + start;
- copy_len = 0;
- for (; pos < url_s + end; pos++) {
- if (*pos == '%' && (pos + 2 < url_s + end)) {
- /* Might be an escaped character needing unescaped */
-
- /* Find which character which was escaped */
- ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
- *(pos + 2));
-
- if (ascii_offset < 0) {
- /* % with invalid hex digits. */
- copy_len++;
- continue;
- }
-
- if ((section != URL_SCHEME && section != URL_HOST) &&
- (nsurl__is_unreserved(ascii_offset) == false)) {
- /* This character should be escaped after all,
- * just let it get copied */
- copy_len += 3;
- pos += 2;
- continue;
- }
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
-
- /* Put the unescaped character in the normalised URL */
- *(pos_norm++) = (char)ascii_offset;
- pos += 2;
- pos_url_s = pos + 1;
-
- length -= 2;
-
- } else if ((section != URL_SCHEME && section != URL_HOST) &&
- (nsurl__is_no_escape(*pos) == false)) {
-
- /* This needs to be escaped */
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
-
- /* escape */
- *(pos_norm++) = '%';
- *(pos_norm++) = digit2uppercase_hex(
- ((unsigned char)*pos) >> 4);
- *(pos_norm++) = digit2uppercase_hex(
- ((unsigned char)*pos) & 0xf);
- pos_url_s = pos + 1;
-
- length += 2;
-
- } else if ((section == URL_SCHEME || section == URL_HOST) &&
- ascii_is_alpha_upper(*pos)) {
- /* Lower case this letter */
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- copy_len = 0;
- }
- /* Copy lower cased letter into normalised URL */
- *(pos_norm++) = ascii_to_lower(*pos);
- pos_url_s = pos + 1;
-
- } else {
- /* This character is safe in normalised URL */
- copy_len++;
- }
- }
-
- if (copy_len > 0) {
- /* Copy up to here */
- memcpy(pos_norm, pos_url_s, copy_len);
- pos_norm += copy_len;
- }
-
- /* Mark end of section */
- (*pos_norm) = '\0';
-
- /* Stage 2: Create the URL components for the required section */
- switch (section) {
- case URL_SCHEME:
- if (length == 0) {
- /* No scheme, assuming http */
- url->scheme = lwc_string_ref(corestring_lwc_http);
- } else {
- /* Add scheme to URL */
- if (lwc_intern_string(norm_start, length,
- &url->scheme) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
-
- break;
-
- case URL_CREDENTIALS:
- url->username = NULL;
- url->password = NULL;
-
- if (length != 0 && *norm_start != ':') {
- char *sec_start = norm_start;
- if (pegs->colon_first != pegs->authority &&
- pegs->at > pegs->colon_first + 1) {
- /* there's a password */
- sec_start += pegs->colon_first -
- pegs->authority + 1;
- if (lwc_intern_string(sec_start,
- pegs->at - pegs->colon_first -1,
- &url->password) !=
- lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- /* update start pos and length for username */
- sec_start = norm_start;
- length -= pegs->at - pegs->colon_first;
- } else if (pegs->colon_first != pegs->authority &&
- pegs->at == pegs->colon_first + 1) {
- /* strip username colon */
- length--;
- }
-
- /* Username */
- if (lwc_intern_string(sec_start, length,
- &url->username) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
-
- break;
-
- case URL_HOST:
- url->host = NULL;
- url->port = NULL;
-
- if (length != 0) {
- size_t colon = 0;
- char *sec_start = norm_start;
- if (pegs->at < pegs->colon_first &&
- pegs->colon_last == pegs->authority) {
- /* There's one colon and it's after @ marker */
- colon = pegs->colon_first;
- } else if (pegs->colon_last != pegs->authority) {
- /* There's more than one colon */
- colon = pegs->colon_last;
- } else {
- /* There's no colon that could be a port
- * separator */
- flags |= NSURL_F_NO_PORT;
- }
-
- if (!(flags & NSURL_F_NO_PORT)) {
- /* Determine whether colon is a port separator
- */
- sec_start += colon - pegs->at;
- while (++sec_start < norm_start + length) {
- if (!ascii_is_digit(*sec_start)) {
- /* Character after port isn't a
- * digit; not a port separator
- */
- flags |= NSURL_F_NO_PORT;
- break;
- }
- }
- }
-
- if (!(flags & NSURL_F_NO_PORT)) {
- /* There's a port */
- size_t skip = (pegs->at == pegs->authority) ?
- 1 : 0;
- sec_start = norm_start + colon - pegs->at +
- skip;
- if (url->scheme != NULL &&
- url->scheme_type ==
- NSURL_SCHEME_HTTP &&
- length -
- (colon - pegs->at + skip) == 2 &&
- *sec_start == '8' &&
- *(sec_start + 1) == '0') {
- /* Scheme is http, and port is default
- * (80) */
- flags |= NSURL_F_NO_PORT;
- }
-
- if (length <= (colon - pegs->at + skip)) {
- /* No space for a port after the colon
- */
- flags |= NSURL_F_NO_PORT;
- }
-
- /* Add non-redundant ports to NetSurf URL */
- sec_start = norm_start + colon - pegs->at +
- skip;
- if (!(flags & NSURL_F_NO_PORT) &&
- lwc_intern_string(sec_start,
- length -
- (colon - pegs->at + skip),
- &url->port) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- /* update length for host */
- skip = (pegs->at == pegs->authority) ? 0 : 1;
- length = colon - pegs->at - skip;
- }
-
- /* host */
- /* Encode host according to IDNA2008 */
- ret = idna_encode(norm_start, length, &host, &host_len);
- if (ret == NSERROR_OK) {
- /* valid idna encoding */
- if (lwc_intern_string(host, host_len,
- &url->host) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- free(host);
- } else {
- /* fall back to straight interning */
- if (lwc_intern_string(norm_start, length,
- &url->host) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- }
- }
-
- break;
-
- case URL_PATH:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->path) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else if (url->host != NULL &&
- url->scheme_type != NSURL_SCHEME_MAILTO) {
- /* Set empty path to "/", if there's a host */
- if (lwc_intern_string("/", SLEN("/"),
- &url->path) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->path = NULL;
- }
-
- break;
-
- case URL_QUERY:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->query) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->query = NULL;
- }
-
- break;
-
- case URL_FRAGMENT:
- if (length != 0) {
- if (lwc_intern_string(norm_start, length,
- &url->fragment) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
- } else {
- url->fragment = NULL;
- }
-
- break;
- }
-
- return NSERROR_OK;
-}
-
-
-/**
- * Get nsurl string info; total length, component lengths, & components present
- *
- * \param url NetSurf URL components
- * \param parts Which parts of the URL are required in the string
- * \param url_l Updated to total string length
- * \param lengths Updated with individual component lengths
- * \param pflags Updated to contain relevant string flags
- */
-static void nsurl__get_string_data(const struct nsurl_components *url,
- nsurl_component parts, size_t *url_l,
- struct nsurl_component_lengths *lengths,
- enum nsurl_string_flags *pflags)
-{
- enum nsurl_string_flags flags = *pflags;
- *url_l = 0;
-
- /* Intersection of required parts and available parts gives
- * the output parts */
- if (url->scheme && parts & NSURL_SCHEME) {
- flags |= NSURL_F_SCHEME;
-
- lengths->scheme = lwc_string_length(url->scheme);
- *url_l += lengths->scheme;
- }
-
- if (url->username && parts & NSURL_USERNAME) {
- flags |= NSURL_F_USERNAME;
-
- lengths->username = lwc_string_length(url->username);
- *url_l += lengths->username;
- }
-
- if (url->password && parts & NSURL_PASSWORD) {
- flags |= NSURL_F_PASSWORD;
-
- lengths->password = lwc_string_length(url->password);
- *url_l += SLEN(":") + lengths->password;
- }
-
- if (url->host && parts & NSURL_HOST) {
- flags |= NSURL_F_HOST;
-
- lengths->host = lwc_string_length(url->host);
- *url_l += lengths->host;
- }
-
- if (url->port && parts & NSURL_PORT) {
- flags |= NSURL_F_PORT;
-
- lengths->port = lwc_string_length(url->port);
- *url_l += SLEN(":") + lengths->port;
- }
-
- if (url->path && parts & NSURL_PATH) {
- flags |= NSURL_F_PATH;
-
- lengths->path = lwc_string_length(url->path);
- *url_l += lengths->path;
- }
-
- if (url->query && parts & NSURL_QUERY) {
- flags |= NSURL_F_QUERY;
-
- lengths->query = lwc_string_length(url->query);
- *url_l += lengths->query;
- }
-
- if (url->fragment && parts & NSURL_FRAGMENT) {
- flags |= NSURL_F_FRAGMENT;
-
- lengths->fragment = lwc_string_length(url->fragment);
- *url_l += lengths->fragment;
- }
-
- /* Turn on any spanned punctuation */
- if ((flags & NSURL_F_SCHEME) && (parts > NSURL_SCHEME)) {
- flags |= NSURL_F_SCHEME_PUNCTUATION;
-
- *url_l += SLEN(":");
- }
-
- if ((flags & NSURL_F_SCHEME) && (flags > NSURL_F_SCHEME) &&
- url->path && lwc_string_data(url->path)[0] == '/') {
- flags |= NSURL_F_AUTHORITY_PUNCTUATION;
-
- *url_l += SLEN("//");
- }
-
- if ((flags & (NSURL_F_USERNAME | NSURL_F_PASSWORD)) &&
- flags & NSURL_F_HOST) {
- flags |= NSURL_F_CREDENTIALS_PUNCTUATION;
-
- *url_l += SLEN("@");
- }
-
- if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
- flags |= NSURL_F_FRAGMENT_PUNCTUATION;
-
- *url_l += SLEN("#");
- }
-
- *pflags = flags;
-}
-
-
-/**
- * Get nsurl string info; total length, component lengths, & components present
- *
- * \param url NetSurf URL components
- * \param url_s Updated to contain the string
- * \param l Individual component lengths
- * \param flags String flags
- */
-static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
- struct nsurl_component_lengths *l,
- enum nsurl_string_flags flags)
-{
- char *pos;
-
- /* Copy the required parts into the url string */
- pos = url_s;
-
- if (flags & NSURL_F_SCHEME) {
- memcpy(pos, lwc_string_data(url->scheme), l->scheme);
- pos += l->scheme;
- }
-
- if (flags & NSURL_F_SCHEME_PUNCTUATION) {
- *(pos++) = ':';
- }
-
- if (flags & NSURL_F_AUTHORITY_PUNCTUATION) {
- *(pos++) = '/';
- *(pos++) = '/';
- }
-
- if (flags & NSURL_F_USERNAME) {
- memcpy(pos, lwc_string_data(url->username), l->username);
- pos += l->username;
- }
-
- if (flags & NSURL_F_PASSWORD) {
- *(pos++) = ':';
- memcpy(pos, lwc_string_data(url->password), l->password);
- pos += l->password;
- }
-
- if (flags & NSURL_F_CREDENTIALS_PUNCTUATION) {
- *(pos++) = '@';
- }
-
- if (flags & NSURL_F_HOST) {
- memcpy(pos, lwc_string_data(url->host), l->host);
- pos += l->host;
- }
-
- if (flags & NSURL_F_PORT) {
- *(pos++) = ':';
- memcpy(pos, lwc_string_data(url->port), l->port);
- pos += l->port;
- }
-
- if (flags & NSURL_F_PATH) {
- memcpy(pos, lwc_string_data(url->path), l->path);
- pos += l->path;
- }
-
- if (flags & NSURL_F_QUERY) {
- memcpy(pos, lwc_string_data(url->query), l->query);
- pos += l->query;
- }
-
- if (flags & NSURL_F_FRAGMENT) {
- if (flags & NSURL_F_FRAGMENT_PUNCTUATION)
- *(pos++) = '#';
- memcpy(pos, lwc_string_data(url->fragment), l->fragment);
- pos += l->fragment;
- }
-
- *pos = '\0';
-}
-
-
-/**
- * Calculate hash value
- *
- * \param url NetSurf URL object to set hash value for
- */
-static void nsurl_calc_hash(nsurl *url)
-{
- uint32_t hash = 0;
-
- if (url->components.scheme)
- hash ^= lwc_string_hash_value(url->components.scheme);
-
- if (url->components.username)
- hash ^= lwc_string_hash_value(url->components.username);
-
- if (url->components.password)
- hash ^= lwc_string_hash_value(url->components.password);
-
- if (url->components.host)
- hash ^= lwc_string_hash_value(url->components.host);
-
- if (url->components.port)
- hash ^= lwc_string_hash_value(url->components.port);
-
- if (url->components.path)
- hash ^= lwc_string_hash_value(url->components.path);
-
- if (url->components.query)
- hash ^= lwc_string_hash_value(url->components.query);
-
- url->hash = hash;
-}
-
-
-/**
- * Destroy components
- *
- * \param c url components
- */
-static void nsurl_destroy_components(struct nsurl_components *c)
-{
- if (c->scheme)
- lwc_string_unref(c->scheme);
-
- if (c->username)
- lwc_string_unref(c->username);
-
- if (c->password)
- lwc_string_unref(c->password);
-
- if (c->host)
- lwc_string_unref(c->host);
-
- if (c->port)
- lwc_string_unref(c->port);
-
- if (c->path)
- lwc_string_unref(c->path);
-
- if (c->query)
- lwc_string_unref(c->query);
-
- if (c->fragment)
- lwc_string_unref(c->fragment);
-}
-
-
-#ifdef NSURL_DEBUG
-/**
- * Dump a NetSurf URL's internal components
- *
- * \param url The NetSurf URL to dump components of
- */
-static void nsurl__dump(const nsurl *url)
-{
- if (url->components.scheme)
- LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
-
- if (url->components.username)
- LOG("Username: %s", lwc_string_data(url->components.username));
-
- if (url->components.password)
- LOG("Password: %s", lwc_string_data(url->components.password));
-
- if (url->components.host)
- LOG(" Host: %s", lwc_string_data(url->components.host));
-
- if (url->components.port)
- LOG(" Port: %s", lwc_string_data(url->components.port));
-
- if (url->components.path)
- LOG(" Path: %s", lwc_string_data(url->components.path));
-
- if (url->components.query)
- LOG(" Query: %s", lwc_string_data(url->components.query));
-
- if (url->components.fragment)
- LOG("Fragment: %s", lwc_string_data(url->components.fragment));
-}
-#endif
-
-/******************************************************************************
- * NetSurf URL Public API *
- ******************************************************************************/
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_create(const char * const url_s, nsurl **url)
-{
- struct url_markers m;
- struct nsurl_components c;
- size_t length;
- char *buff;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
- nserror e = NSERROR_OK;
- bool match;
-
- assert(url_s != NULL);
-
- /* Peg out the URL sections */
- nsurl__get_string_markers(url_s, &m, false);
-
- /* Get the length of the longest section */
- length = nsurl__get_longest_section(&m);
-
- /* Allocate enough memory to url escape the longest section */
- buff = malloc(length * 3 + 1);
- if (buff == NULL)
- return NSERROR_NOMEM;
-
- /* Set scheme type */
- c.scheme_type = m.scheme_type;
-
- /* Build NetSurf URL object from sections */
- e |= nsurl__create_from_section(url_s, URL_SCHEME, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_CREDENTIALS, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_HOST, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_PATH, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_QUERY, &m, buff, &c);
- e |= nsurl__create_from_section(url_s, URL_FRAGMENT, &m, buff, &c);
-
- /* Finished with buffer */
- free(buff);
-
- if (e != NSERROR_OK) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
- }
-
- /* Validate URL */
- if ((lwc_string_isequal(c.scheme, corestring_lwc_http,
- &match) == lwc_error_ok && match == true) ||
- (lwc_string_isequal(c.scheme, corestring_lwc_https,
- &match) == lwc_error_ok && match == true)) {
- /* http, https must have host */
- if (c.host == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_BAD_URL;
- }
- }
-
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*url == NULL) {
- nsurl_destroy_components(&c);
- return NSERROR_NOMEM;
- }
-
- (*url)->components = c;
- (*url)->length = length;
-
- /* Fill out the url string */
- nsurl_get_string(&c, (*url)->string, &str_len, str_flags);
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*url);
-
- /* Give the URL a reference */
- (*url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nsurl *nsurl_ref(nsurl *url)
-{
- assert(url != NULL);
-
- url->count++;
-
- return url;
-}
-
-
-/* exported interface, documented in nsurl.h */
-void nsurl_unref(nsurl *url)
-{
- assert(url != NULL);
- assert(url->count > 0);
-
- if (--url->count > 0)
- return;
-
-#ifdef NSURL_DEBUG
- nsurl__dump(url);
-#endif
-
- /* Release lwc strings */
- nsurl_destroy_components(&url->components);
-
- /* Free the NetSurf URL */
- free(url);
-}
-
-
-/* exported interface, documented in nsurl.h */
-bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
-{
- bool match = true;
-
- assert(url1 != NULL);
- assert(url2 != NULL);
-
- /* Compare URL components */
-
- /* Path, host and query first, since they're most likely to differ */
-
- if (parts & NSURL_PATH) {
- nsurl__component_compare(url1->components.path,
- url2->components.path, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_HOST) {
- nsurl__component_compare(url1->components.host,
- url2->components.host, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_QUERY) {
- nsurl__component_compare(url1->components.query,
- url2->components.query, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_SCHEME) {
- nsurl__component_compare(url1->components.scheme,
- url2->components.scheme, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_USERNAME) {
- nsurl__component_compare(url1->components.username,
- url2->components.username, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_PASSWORD) {
- nsurl__component_compare(url1->components.password,
- url2->components.password, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_PORT) {
- nsurl__component_compare(url1->components.port,
- url2->components.port, &match);
-
- if (match == false)
- return false;
- }
-
- if (parts & NSURL_FRAGMENT) {
- nsurl__component_compare(url1->components.fragment,
- url2->components.fragment, &match);
-
- if (match == false)
- return false;
- }
-
- return true;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_get(const nsurl *url, nsurl_component parts,
- char **url_s, size_t *url_l)
-{
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
-
- assert(url != NULL);
-
- /* Get the string length and find which parts of url need copied */
- nsurl__get_string_data(&(url->components), parts, url_l,
- &str_len, &str_flags);
-
- if (*url_l == 0) {
- return NSERROR_BAD_URL;
- }
-
- /* Allocate memory for url string */
- *url_s = malloc(*url_l + 1); /* adding 1 for '\0' */
- if (*url_s == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Copy the required parts into the url string */
- nsurl_get_string(&(url->components), *url_s, &str_len, str_flags);
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part)
-{
- assert(url != NULL);
-
- switch (part) {
- case NSURL_SCHEME:
- return (url->components.scheme != NULL) ?
- lwc_string_ref(url->components.scheme) : NULL;
-
- case NSURL_USERNAME:
- return (url->components.username != NULL) ?
- lwc_string_ref(url->components.username) : NULL;
-
- case NSURL_PASSWORD:
- return (url->components.password != NULL) ?
- lwc_string_ref(url->components.password) : NULL;
-
- case NSURL_HOST:
- return (url->components.host != NULL) ?
- lwc_string_ref(url->components.host) : NULL;
-
- case NSURL_PORT:
- return (url->components.port != NULL) ?
- lwc_string_ref(url->components.port) : NULL;
-
- case NSURL_PATH:
- return (url->components.path != NULL) ?
- lwc_string_ref(url->components.path) : NULL;
-
- case NSURL_QUERY:
- return (url->components.query != NULL) ?
- lwc_string_ref(url->components.query) : NULL;
-
- case NSURL_FRAGMENT:
- return (url->components.fragment != NULL) ?
- lwc_string_ref(url->components.fragment) : NULL;
-
- default:
- LOG("Unsupported value passed to part param.");
- assert(0);
- }
-
- return NULL;
-}
-
-
-/* exported interface, documented in nsurl.h */
-bool nsurl_has_component(const nsurl *url, nsurl_component part)
-{
- assert(url != NULL);
-
- switch (part) {
- case NSURL_SCHEME:
- if (url->components.scheme != NULL)
- return true;
- else
- return false;
-
- case NSURL_CREDENTIALS:
- /* Only username required for credentials section */
- /* Fall through */
- case NSURL_USERNAME:
- if (url->components.username != NULL)
- return true;
- else
- return false;
-
- case NSURL_PASSWORD:
- if (url->components.password != NULL)
- return true;
- else
- return false;
-
- case NSURL_HOST:
- if (url->components.host != NULL)
- return true;
- else
- return false;
-
- case NSURL_PORT:
- if (url->components.port != NULL)
- return true;
- else
- return false;
-
- case NSURL_PATH:
- if (url->components.path != NULL)
- return true;
- else
- return false;
-
- case NSURL_QUERY:
- if (url->components.query != NULL)
- return true;
- else
- return false;
-
- case NSURL_FRAGMENT:
- if (url->components.fragment != NULL)
- return true;
- else
- return false;
-
- default:
- LOG("Unsupported value passed to part param.");
- assert(0);
- }
-
- return false;
-}
-
-
-/* exported interface, documented in nsurl.h */
-const char *nsurl_access(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->string;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l)
-{
- nserror err;
- lwc_string *host;
- char *idna_host = NULL;
- size_t idna_host_len;
- char *scheme = NULL;
- size_t scheme_len;
- char *path = NULL;
- size_t path_len;
-
- assert(url != NULL);
-
- if (url->components.host == NULL) {
- return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l);
- }
-
- host = url->components.host;
- err = idna_decode(lwc_string_data(host), lwc_string_length(host),
- &idna_host, &idna_host_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- err = nsurl_get(url,
- NSURL_SCHEME | NSURL_CREDENTIALS,
- &scheme, &scheme_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- err = nsurl_get(url,
- NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT,
- &path, &path_len);
- if (err != NSERROR_OK) {
- goto cleanup;
- }
-
- *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */
- *url_s = malloc(*url_l);
-
- if (*url_s == NULL) {
- err = NSERROR_NOMEM;
- goto cleanup;
- }
-
- snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path);
-
- err = NSERROR_OK;
-
-cleanup:
- free(idna_host);
- free(scheme);
- free(path);
-
- return err;
-}
-
-
-/* exported interface, documented in nsurl.h */
-const char *nsurl_access_leaf(const nsurl *url)
-{
- size_t path_len;
- const char *path;
- const char *leaf;
-
- assert(url != NULL);
-
- if (url->components.path == NULL)
- return "";
-
- path = lwc_string_data(url->components.path);
- path_len = lwc_string_length(url->components.path);
-
- if (path_len == 0)
- return "";
-
- if (path_len == 1 && *path == '/')
- return "/";
-
- leaf = path + path_len;
-
- do {
- leaf--;
- } while ((leaf != path) && (*leaf != '/'));
-
- if (*leaf == '/')
- leaf++;
-
- return leaf;
-}
-
-
-/* exported interface, documented in nsurl.h */
-size_t nsurl_length(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->length;
-}
-
-
-/* exported interface, documented in nsurl.h */
-uint32_t nsurl_hash(const nsurl *url)
-{
- assert(url != NULL);
-
- return url->hash;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
-{
- struct url_markers m;
- struct nsurl_components c;
- size_t length;
- char *buff;
- char *buff_pos;
- char *buff_start;
- struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
- enum nsurl_string_flags str_flags = 0;
- nserror error = 0;
- enum {
- NSURL_F_REL = 0,
- NSURL_F_BASE_SCHEME = (1 << 0),
- NSURL_F_BASE_AUTHORITY = (1 << 1),
- NSURL_F_BASE_PATH = (1 << 2),
- NSURL_F_MERGED_PATH = (1 << 3),
- NSURL_F_BASE_QUERY = (1 << 4)
- } joined_parts;
-
- assert(base != NULL);
- assert(rel != NULL);
-
-#ifdef NSURL_DEBUG
- LOG("base: \"%s\", rel: \"%s\"", nsurl_access(base),
rel);
-#endif
-
- /* Peg out the URL sections */
- nsurl__get_string_markers(rel, &m, true);
-
- /* Get the length of the longest section */
- length = nsurl__get_longest_section(&m);
-
- /* Initially assume that the joined URL can be formed entierly from
- * the relative URL.
- */
- joined_parts = NSURL_F_REL;
-
- /* Update joined_compnents to indicate any required parts from the
- * base URL.
- */
- if (m.scheme_end - m.start <= 0) {
- /* The relative url has no scheme.
- * Use base URL's scheme. */
- joined_parts |= NSURL_F_BASE_SCHEME;
-
- if (m.path - m.authority <= 0) {
- /* The relative URL has no authority.
- * Use base URL's authority. */
- joined_parts |= NSURL_F_BASE_AUTHORITY;
-
- if (m.query - m.path <= 0) {
- /* The relative URL has no path.
- * Use base URL's path. */
- joined_parts |= NSURL_F_BASE_PATH;
-
- if (m.fragment - m.query <= 0) {
- /* The relative URL has no query.
- * Use base URL's query. */
- joined_parts |= NSURL_F_BASE_QUERY;
- }
-
- } else if (*(rel + m.path) != '/') {
- /* Relative URL has relative path */
- joined_parts |= NSURL_F_MERGED_PATH;
- }
- }
- }
-
- /* Allocate enough memory to url escape the longest section, plus
- * space for path merging (if required).
- */
- if (joined_parts & NSURL_F_MERGED_PATH) {
- /* Need to merge paths */
- length += (base->components.path != NULL) ?
- lwc_string_length(base->components.path) : 0;
- }
- length *= 4;
- /* Plus space for removing dots from path */
- length += (m.query - m.path) + ((base->components.path != NULL) ?
- lwc_string_length(base->components.path) : 0);
-
- buff = malloc(length + 5);
- if (buff == NULL) {
- return NSERROR_NOMEM;
- }
-
- buff_pos = buff;
-
- /* Form joined URL from base or rel components, as appropriate */
-
- if (joined_parts & NSURL_F_BASE_SCHEME) {
- c.scheme_type = base->components.scheme_type;
-
- c.scheme = nsurl__component_copy(base->components.scheme);
- } else {
- c.scheme_type = m.scheme_type;
-
- error = nsurl__create_from_section(rel, URL_SCHEME, &m, buff, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_AUTHORITY) {
- c.username = nsurl__component_copy(base->components.username);
- c.password = nsurl__component_copy(base->components.password);
- c.host = nsurl__component_copy(base->components.host);
- c.port = nsurl__component_copy(base->components.port);
- } else {
- error = nsurl__create_from_section(rel, URL_CREDENTIALS, &m,
- buff, &c);
- if (error == NSERROR_OK) {
- error = nsurl__create_from_section(rel, URL_HOST, &m,
- buff, &c);
- }
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_PATH) {
- c.path = nsurl__component_copy(base->components.path);
-
- } else if (joined_parts & NSURL_F_MERGED_PATH) {
- struct url_markers m_path;
- size_t new_length;
-
- if (base->components.host != NULL &&
- base->components.path == NULL) {
- /* Append relative path to "/". */
- *(buff_pos++) = '/';
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
-
- } else {
- /* Append relative path to all but last segment of
- * base path. */
- size_t path_end = lwc_string_length(
- base->components.path);
- const char *path = lwc_string_data(
- base->components.path);
-
- while (*(path + path_end) != '/' &&
- path_end != 0) {
- path_end--;
- }
- if (*(path + path_end) == '/')
- path_end++;
-
- /* Copy the base part */
- memcpy(buff_pos, path, path_end);
- buff_pos += path_end;
-
- /* Copy the relative part */
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
- }
-
- /* add termination to string */
- *buff_pos++ = '\0';
-
- new_length = nsurl__remove_dot_segments(buff, buff_pos);
-
- m_path.path = 0;
- m_path.query = new_length;
-
- buff_start = buff_pos + new_length;
- error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
- buff_start, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
-
- } else {
- struct url_markers m_path;
- size_t new_length;
-
- memcpy(buff_pos, rel + m.path, m.query - m.path);
- buff_pos += m.query - m.path;
- *(buff_pos++) = '\0';
-
- new_length = nsurl__remove_dot_segments(buff, buff_pos);
-
- m_path.path = 0;
- m_path.query = new_length;
-
- buff_start = buff_pos + new_length;
-
- error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
- buff_start, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- if (joined_parts & NSURL_F_BASE_QUERY) {
- c.query = nsurl__component_copy(base->components.query);
- } else {
- error = nsurl__create_from_section(rel, URL_QUERY, &m,
- buff, &c);
- if (error != NSERROR_OK) {
- free(buff);
- return error;
- }
- }
-
- error = nsurl__create_from_section(rel, URL_FRAGMENT, &m, buff, &c);
-
- /* Free temporary buffer */
- free(buff);
-
- if (error != NSERROR_OK) {
- return error;
- }
-
- /* Get the string length and find which parts of url are present */
- nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
- &str_len, &str_flags);
-
- /* Create NetSurf URL object */
- *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*joined == NULL) {
- return NSERROR_NOMEM;
- }
-
- (*joined)->components = c;
- (*joined)->length = length;
-
- /* Fill out the url string */
- nsurl_get_string(&c, (*joined)->string, &str_len, str_flags);
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*joined);
-
- /* Give the URL a reference */
- (*joined)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
-{
- size_t length;
- char *pos;
-
- assert(url != NULL);
-
- /* check for source url having no fragment already */
- if (url->components.fragment == NULL) {
- *no_frag = (nsurl *)url;
-
- (*no_frag)->count++;
-
- return NSERROR_OK;
- }
-
- /* Find the change in length from url to new_url */
- length = url->length;
- if (url->components.fragment != NULL) {
- length -= 1 + lwc_string_length(url->components.fragment);
- }
-
- /* Create NetSurf URL object */
- *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
- if (*no_frag == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Copy components */
- (*no_frag)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*no_frag)->components.username =
- nsurl__component_copy(url->components.username);
- (*no_frag)->components.password =
- nsurl__component_copy(url->components.password);
- (*no_frag)->components.host =
- nsurl__component_copy(url->components.host);
- (*no_frag)->components.port =
- nsurl__component_copy(url->components.port);
- (*no_frag)->components.path =
- nsurl__component_copy(url->components.path);
- (*no_frag)->components.query =
- nsurl__component_copy(url->components.query);
- (*no_frag)->components.fragment = NULL;
-
- (*no_frag)->components.scheme_type = url->components.scheme_type;
-
- (*no_frag)->length = length;
-
- /* Fill out the url string */
- pos = (*no_frag)->string;
- memcpy(pos, url->string, length);
- pos += length;
- *pos = '\0';
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*no_frag);
-
- /* Give the URL a reference */
- (*no_frag)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
-{
- int frag_len;
- int base_len;
- char *pos;
- size_t len;
-
- assert(url != NULL);
- assert(frag != NULL);
-
- /* Find the change in length from url to new_url */
- base_len = url->length;
- if (url->components.fragment != NULL) {
- base_len -= 1 + lwc_string_length(url->components.fragment);
- }
- frag_len = lwc_string_length(frag);
-
- /* Set new_url's length */
- len = base_len + 1 /* # */ + frag_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, base_len);
- pos += base_len;
- *pos = '#';
- memcpy(++pos, lwc_string_data(frag), frag_len);
- pos += frag_len;
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path =
- nsurl__component_copy(url->components.path);
- (*new_url)->components.query =
- nsurl__component_copy(url->components.query);
- (*new_url)->components.fragment =
- lwc_string_ref(frag);
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_replace_query(const nsurl *url, const char *query,
- nsurl **new_url)
-{
- int query_len; /* Length of new query string, including '?' */
- int frag_len = 0; /* Length of fragment, including '#' */
- int base_len; /* Length of URL up to start of query */
- char *pos;
- size_t len;
- lwc_string *lwc_query;
-
- assert(url != NULL);
- assert(query != NULL);
- assert(query[0] == '?');
-
- /* Get the length of the new query */
- query_len = strlen(query);
-
- /* Find the change in length from url to new_url */
- base_len = url->length;
- if (url->components.query != NULL) {
- base_len -= lwc_string_length(url->components.query);
- }
- if (url->components.fragment != NULL) {
- frag_len = 1 + lwc_string_length(url->components.fragment);
- base_len -= frag_len;
- }
-
- /* Set new_url's length */
- len = base_len + query_len + frag_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
- free(*new_url);
- return NSERROR_NOMEM;
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, base_len);
- pos += base_len;
- memcpy(pos, query, query_len);
- pos += query_len;
- if (url->components.fragment != NULL) {
- const char *frag = lwc_string_data(url->components.fragment);
- *pos = '#';
- memcpy(++pos, frag, frag_len - 1);
- pos += frag_len - 1;
- }
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path =
- nsurl__component_copy(url->components.path);
- (*new_url)->components.query = lwc_query;
- (*new_url)->components.fragment =
- nsurl__component_copy(url->components.fragment);
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
-
-/* exported interface documented in utils/nsurl.h */
-nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
-{
- const char *data;
- size_t len;
- size_t pos;
- bool match;
- char *name;
-
- assert(url != NULL);
-
- *result = 0;
-
- /* extract the last component of the path, if possible */
- if ((url->components.path != NULL) &&
- (lwc_string_length(url->components.path) != 0) &&
- (lwc_string_isequal(url->components.path,
- corestring_lwc_slash_, &match) == lwc_error_ok) &&
- (match == false)) {
- bool first = true;
- bool keep_looking;
-
- /* Get hold of the string data we're examining */
- data = lwc_string_data(url->components.path);
- len = lwc_string_length(url->components.path);
- pos = len;
-
- do {
- keep_looking = false;
- pos--;
-
- /* Find last '/' with stuff after it */
- while (pos != 0) {
- if (data[pos] == '/' && pos < len - 1) {
- break;
- }
- pos--;
- }
-
- if (pos == 0) {
- break;
- }
-
- if (first) {
- if (strncasecmp("/default.", data + pos,
- SLEN("/default.")) == 0) {
- keep_looking = true;
-
- } else if (strncasecmp("/index.",
- data + pos,
- 6) == 0) {
- keep_looking = true;
-
- }
- first = false;
- }
-
- } while (keep_looking);
-
- if (data[pos] == '/')
- pos++;
-
- if (strncasecmp("default.", data + pos, 8) != 0 &&
- strncasecmp("index.", data + pos, 6) != 0) {
- size_t end = pos;
- while (data[end] != '\0' && data[end] != '/') {
- end++;
- }
- if (end - pos != 0) {
- name = malloc(end - pos + 1);
- if (name == NULL) {
- return NSERROR_NOMEM;
- }
- memcpy(name, data + pos, end - pos);
- name[end - pos] = '\0';
- if (remove_extensions) {
- /* strip any extenstion */
- char *dot = strchr(name, '.');
- if (dot && dot != name) {
- *dot = '\0';
- }
- }
- *result = name;
- return NSERROR_OK;
- }
- }
- }
-
- if (url->components.host != NULL) {
- name = strdup(lwc_string_data(url->components.host));
-
- for (pos = 0; name[pos] != '\0'; pos++) {
- if (name[pos] == '.') {
- name[pos] = '_';
- }
- }
-
- *result = name;
- return NSERROR_OK;
- }
-
- return NSERROR_NOT_FOUND;
-}
-
-
-/* exported interface, documented in nsurl.h */
-nserror nsurl_parent(const nsurl *url, nsurl **new_url)
-{
- lwc_string *lwc_path;
- size_t old_path_len, new_path_len;
- size_t len;
- const char* path = NULL;
- char *pos;
-
- assert(url != NULL);
-
- old_path_len = (url->components.path == NULL) ? 0 :
- lwc_string_length(url->components.path);
-
- /* Find new path length */
- if (old_path_len == 0) {
- new_path_len = old_path_len;
- } else {
- path = lwc_string_data(url->components.path);
-
- new_path_len = old_path_len;
- if (old_path_len > 1) {
- /* Skip over any trailing / */
- if (path[new_path_len - 1] == '/')
- new_path_len--;
-
- /* Work back to next / */
- while (new_path_len > 0 &&
- path[new_path_len - 1] != '/')
- new_path_len--;
- }
- }
-
- /* Find the length of new_url */
- len = url->length;
- if (url->components.query != NULL) {
- len -= lwc_string_length(url->components.query);
- }
- if (url->components.fragment != NULL) {
- len -= 1; /* # */
- len -= lwc_string_length(url->components.fragment);
- }
- len -= old_path_len - new_path_len;
-
- /* Create NetSurf URL object */
- *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
- if (*new_url == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Make new path */
- if (old_path_len == 0) {
- lwc_path = NULL;
- } else if (old_path_len == new_path_len) {
- lwc_path = lwc_string_ref(url->components.path);
- } else {
- if (lwc_intern_string(path, old_path_len - new_path_len,
- &lwc_path) != lwc_error_ok) {
- free(*new_url);
- return NSERROR_NOMEM;
- }
- }
-
- (*new_url)->length = len;
-
- /* Set string */
- pos = (*new_url)->string;
- memcpy(pos, url->string, len);
- pos += len;
- *pos = '\0';
-
- /* Copy components */
- (*new_url)->components.scheme =
- nsurl__component_copy(url->components.scheme);
- (*new_url)->components.username =
- nsurl__component_copy(url->components.username);
- (*new_url)->components.password =
- nsurl__component_copy(url->components.password);
- (*new_url)->components.host =
- nsurl__component_copy(url->components.host);
- (*new_url)->components.port =
- nsurl__component_copy(url->components.port);
- (*new_url)->components.path = lwc_path;
- (*new_url)->components.query = NULL;
- (*new_url)->components.fragment = NULL;
-
- (*new_url)->components.scheme_type = url->components.scheme_type;
-
- /* Get the nsurl's hash */
- nsurl_calc_hash(*new_url);
-
- /* Give the URL a reference */
- (*new_url)->count = 1;
-
- return NSERROR_OK;
-}
-
diff --git a/utils/nsurl/Makefile b/utils/nsurl/Makefile
new file mode 100644
index 0000000..08656f3
--- /dev/null
+++ b/utils/nsurl/Makefile
@@ -0,0 +1,6 @@
+# nsurl utils sources
+
+S_NSURL := \
+ nsurl.c
+
+S_NSURL := $(addprefix utils/nsurl/,$(S_NSURL))
\ No newline at end of file
diff --git a/utils/nsurl/nsurl.c b/utils/nsurl/nsurl.c
new file mode 100644
index 0000000..c5c614c
--- /dev/null
+++ b/utils/nsurl/nsurl.c
@@ -0,0 +1,2500 @@
+/*
+ * Copyright 2011 Michael Drake <tlsa(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
+ * NetSurf URL handling implementation.
+ *
+ * This is the common implementation of all URL handling within the
+ * browser. This implementation is based upon RFC3986 although this has
+ * been superceeded by
https://url.spec.whatwg.org/ which is based on
+ * actual contemporary implementations.
+ *
+ * Care must be taken with character encodings within this module as
+ * the specifications work with specific ascii ranges and must not be
+ * affected by locale. Hence the c library character type functions
+ * are not used.
+ */
+
+#include <assert.h>
+#include <libwapcaplet/libwapcaplet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+#include "utils/ascii.h"
+#include "utils/corestrings.h"
+#include "utils/errors.h"
+#include "utils/idna.h"
+#include "utils/log.h"
+#include "utils/nsurl.h"
+#include "utils/utils.h"
+
+/* Define to enable NSURL debugging */
+#undef NSURL_DEBUG
+
+/**
+ * nsurl scheme type
+ */
+enum scheme_type {
+ NSURL_SCHEME_OTHER,
+ NSURL_SCHEME_HTTP,
+ NSURL_SCHEME_HTTPS,
+ NSURL_SCHEME_FTP,
+ NSURL_SCHEME_MAILTO
+};
+
+/**
+ * nsurl components
+ *
+ * [scheme]://[username]:[password]@[host]:[port][path][?query]#[fragment]
+ *
+ * Note:
+ * "path" string includes preceding '/', if needed for the scheme
+ * "query" string always includes preceding '?'
+ *
+ * The other spanned punctuation is to be inserted when building URLs from
+ * components.
+ */
+struct nsurl_components {
+ lwc_string *scheme;
+ lwc_string *username;
+ lwc_string *password;
+ lwc_string *host;
+ lwc_string *port;
+ lwc_string *path;
+ lwc_string *query;
+ lwc_string *fragment;
+
+ enum scheme_type scheme_type;
+};
+
+
+/**
+ * NetSurf URL object
+ */
+struct nsurl {
+ struct nsurl_components components;
+
+ int count; /* Number of references to NetSurf URL object */
+ uint32_t hash; /* Hash value for nsurl identification */
+
+ size_t length; /* Length of string */
+ char string[FLEX_ARRAY_LEN_DECL]; /* Full URL as a string */
+};
+
+
+/** Marker set, indicating positions of sections within a URL string */
+struct url_markers {
+ size_t start; /** start of URL */
+ size_t scheme_end;
+ size_t authority;
+
+ size_t colon_first;
+ size_t at;
+ size_t colon_last;
+
+ size_t path;
+ size_t query;
+ size_t fragment;
+
+ size_t end; /** end of URL */
+
+ enum scheme_type scheme_type;
+};
+
+
+/** Marker set, indicating positions of sections within a URL string */
+struct nsurl_component_lengths {
+ size_t scheme;
+ size_t username;
+ size_t password;
+ size_t host;
+ size_t port;
+ size_t path;
+ size_t query;
+ size_t fragment;
+};
+
+
+/** Flags indicating which parts of a URL string are required for a nsurl */
+enum nsurl_string_flags {
+ NSURL_F_SCHEME = (1 << 0),
+ NSURL_F_SCHEME_PUNCTUATION = (1 << 1),
+ NSURL_F_AUTHORITY_PUNCTUATION = (1 << 2),
+ NSURL_F_USERNAME = (1 << 3),
+ NSURL_F_PASSWORD = (1 << 4),
+ NSURL_F_CREDENTIALS_PUNCTUATION = (1 << 5),
+ NSURL_F_HOST = (1 << 6),
+ NSURL_F_PORT = (1 << 7),
+ NSURL_F_AUTHORITY = (NSURL_F_USERNAME |
+ NSURL_F_PASSWORD |
+ NSURL_F_HOST |
+ NSURL_F_PORT),
+ NSURL_F_PATH = (1 << 8),
+ NSURL_F_QUERY = (1 << 9),
+ NSURL_F_FRAGMENT_PUNCTUATION = (1 << 10),
+ NSURL_F_FRAGMENT = (1 << 11)
+};
+
+
+/** Sections of a URL */
+enum url_sections {
+ URL_SCHEME,
+ URL_CREDENTIALS,
+ URL_HOST,
+ URL_PATH,
+ URL_QUERY,
+ URL_FRAGMENT
+};
+
+
+#define nsurl__component_copy(c) (c == NULL) ? NULL : lwc_string_ref(c)
+
+#define nsurl__component_compare(c1, c2, match) \
+ if (c1 && c2 && lwc_error_ok == \
+ lwc_string_isequal(c1, c2, match)) { \
+ /* do nothing */ \
+ } else if (c1 || c2) { \
+ *match = false; \
+ }
+
+/**
+ * Return a hex digit for the given numerical value.
+ *
+ * \param digit the value to get the hex digit for.
+ * \return character in range 0-9A-F
+ */
+inline static char digit2uppercase_hex(unsigned char digit) {
+ assert(digit < 16);
+ return "0123456789ABCDEF"[digit];
+}
+
+/**
+ * determine if a character is unreserved
+ *
+ * \param c character to classify.
+ * \return true if the character is unreserved else false.
+ */
+static bool nsurl__is_unreserved(unsigned char c)
+{
+ /* From RFC3986 section 2.3 (unreserved characters)
+ *
+ * unreserved = ALPHA / DIGIT / "-" / "." / "_" /
"~"
+ *
+ */
+ static const bool unreserved[256] = {
+ false, false, false, false, false, false, false, false, /* 00 */
+ false, false, false, false, false, false, false, false, /* 08 */
+ false, false, false, false, false, false, false, false, /* 10 */
+ false, false, false, false, false, false, false, false, /* 18 */
+ false, false, false, false, false, false, false, false, /* 20 */
+ false, false, false, false, false, true, true, false, /* 28 */
+ true, true, true, true, true, true, true, true, /* 30 */
+ true, true, false, false, false, false, false, false, /* 38 */
+ false, true, true, true, true, true, true, true, /* 40 */
+ true, true, true, true, true, true, true, true, /* 48 */
+ true, true, true, true, true, true, true, true, /* 50 */
+ true, true, true, false, false, false, false, true, /* 58 */
+ false, true, true, true, true, true, true, true, /* 60 */
+ true, true, true, true, true, true, true, true, /* 68 */
+ true, true, true, true, true, true, true, true, /* 70 */
+ true, true, true, false, false, false, true, false, /* 78 */
+ false, false, false, false, false, false, false, false, /* 80 */
+ false, false, false, false, false, false, false, false, /* 88 */
+ false, false, false, false, false, false, false, false, /* 90 */
+ false, false, false, false, false, false, false, false, /* 98 */
+ false, false, false, false, false, false, false, false, /* A0 */
+ false, false, false, false, false, false, false, false, /* A8 */
+ false, false, false, false, false, false, false, false, /* B0 */
+ false, false, false, false, false, false, false, false, /* B8 */
+ false, false, false, false, false, false, false, false, /* C0 */
+ false, false, false, false, false, false, false, false, /* C8 */
+ false, false, false, false, false, false, false, false, /* D0 */
+ false, false, false, false, false, false, false, false, /* D8 */
+ false, false, false, false, false, false, false, false, /* E0 */
+ false, false, false, false, false, false, false, false, /* E8 */
+ false, false, false, false, false, false, false, false, /* F0 */
+ false, false, false, false, false, false, false, false /* F8 */
+ };
+ return unreserved[c];
+}
+
+/**
+ * determine if a character should be percent escaped.
+ *
+ * The ASCII codes which should not be percent escaped
+ *
+ * \param c character to classify.
+ * \return true if the character should not be escaped else false.
+ */
+static bool nsurl__is_no_escape(unsigned char c)
+{
+ static const bool no_escape[256] = {
+ false, false, false, false, false, false, false, false, /* 00 */
+ false, false, false, false, false, false, false, false, /* 08 */
+ false, false, false, false, false, false, false, false, /* 10 */
+ false, false, false, false, false, false, false, false, /* 18 */
+ false, true, false, true, true, false, true, true, /* 20 */
+ true, true, true, true, true, true, true, true, /* 28 */
+ true, true, true, true, true, true, true, true, /* 30 */
+ true, true, true, true, false, true, false, true, /* 38 */
+ true, true, true, true, true, true, true, true, /* 40 */
+ true, true, true, true, true, true, true, true, /* 48 */
+ true, true, true, true, true, true, true, true, /* 50 */
+ true, true, true, true, false, true, false, true, /* 58 */
+ false, true, true, true, true, true, true, true, /* 60 */
+ true, true, true, true, true, true, true, true, /* 68 */
+ true, true, true, true, true, true, true, true, /* 70 */
+ true, true, true, false, true, false, true, false, /* 78 */
+ false, false, false, false, false, false, false, false, /* 80 */
+ false, false, false, false, false, false, false, false, /* 88 */
+ false, false, false, false, false, false, false, false, /* 90 */
+ false, false, false, false, false, false, false, false, /* 98 */
+ false, false, false, false, false, false, false, false, /* A0 */
+ false, false, false, false, false, false, false, false, /* A8 */
+ false, false, false, false, false, false, false, false, /* B0 */
+ false, false, false, false, false, false, false, false, /* B8 */
+ false, false, false, false, false, false, false, false, /* C0 */
+ false, false, false, false, false, false, false, false, /* C8 */
+ false, false, false, false, false, false, false, false, /* D0 */
+ false, false, false, false, false, false, false, false, /* D8 */
+ false, false, false, false, false, false, false, false, /* E0 */
+ false, false, false, false, false, false, false, false, /* E8 */
+ false, false, false, false, false, false, false, false, /* F0 */
+ false, false, false, false, false, false, false, false, /* F8 */
+ };
+ return no_escape[c];
+}
+
+
+/**
+ * Obtains a set of markers delimiting sections in a URL string
+ *
+ * \param url_s URL string
+ * \param markers Updated to mark sections in the URL string
+ * \param joining True iff URL string is a relative URL for joining
+ */
+static void nsurl__get_string_markers(const char * const url_s,
+ struct url_markers *markers, bool joining)
+{
+ const char *pos = url_s; /** current position in url_s */
+ bool is_http = false;
+ bool trailing_whitespace = false;
+
+ /* Initialise marker set */
+ struct url_markers marker = { 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, NSURL_SCHEME_OTHER };
+
+ /* Skip any leading whitespace in url_s */
+ while (ascii_is_space(*pos))
+ pos++;
+
+ /* Record start point */
+ marker.start = pos - url_s;
+
+ marker.scheme_end = marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path = marker.start;
+
+ if (*pos == '\0') {
+ /* Nothing but whitespace, early exit */
+ marker.query = marker.fragment = marker.end = marker.path;
+ *markers = marker;
+ return;
+ }
+
+ /* Get scheme */
+ if (ascii_is_alpha(*pos)) {
+ pos++;
+
+ while (*pos != ':' && *pos != '\0') {
+ if (!ascii_is_alphanumerical(*pos) && (*pos != '+') &&
+ (*pos != '-') && (*pos != '.')) {
+ /* This character is not valid in the
+ * scheme */
+ break;
+ }
+ pos++;
+ }
+
+ if (*pos == ':') {
+ /* This delimits the end of the scheme */
+ size_t off;
+
+ marker.scheme_end = pos - url_s;
+
+ off = marker.scheme_end - marker.start;
+
+ /* Detect http(s) and mailto for scheme specifc
+ * normalisation */
+ if (off == SLEN("http") &&
+ (((*(pos - off + 0) == 'h') ||
+ (*(pos - off + 0) == 'H')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 't') ||
+ (*(pos - off + 2) == 'T')) &&
+ ((*(pos - off + 3) == 'p') ||
+ (*(pos - off + 3) == 'P')))) {
+ marker.scheme_type = NSURL_SCHEME_HTTP;
+ is_http = true;
+ } else if (off == SLEN("https") &&
+ (((*(pos - off + 0) == 'h') ||
+ (*(pos - off + 0) == 'H')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 't') ||
+ (*(pos - off + 2) == 'T')) &&
+ ((*(pos - off + 3) == 'p') ||
+ (*(pos - off + 3) == 'P')) &&
+ ((*(pos - off + 4) == 's') ||
+ (*(pos - off + 4) == 'S')))) {
+ marker.scheme_type = NSURL_SCHEME_HTTPS;
+ is_http = true;
+ } else if (off == SLEN("ftp") &&
+ (((*(pos - off + 0) == 'f') ||
+ (*(pos - off + 0) == 'F')) &&
+ ((*(pos - off + 1) == 't') ||
+ (*(pos - off + 1) == 'T')) &&
+ ((*(pos - off + 2) == 'p') ||
+ (*(pos - off + 2) == 'P')))) {
+ marker.scheme_type = NSURL_SCHEME_FTP;
+ } else if (off == SLEN("mailto") &&
+ (((*(pos - off + 0) == 'm') ||
+ (*(pos - off + 0) == 'M')) &&
+ ((*(pos - off + 1) == 'a') ||
+ (*(pos - off + 1) == 'A')) &&
+ ((*(pos - off + 2) == 'i') ||
+ (*(pos - off + 2) == 'I')) &&
+ ((*(pos - off + 3) == 'l') ||
+ (*(pos - off + 3) == 'L')) &&
+ ((*(pos - off + 4) == 't') ||
+ (*(pos - off + 4) == 'T')) &&
+ ((*(pos - off + 5) == 'o') ||
+ (*(pos - off + 5) == 'O')))) {
+ marker.scheme_type = NSURL_SCHEME_MAILTO;
+ }
+
+ /* Skip over colon */
+ pos++;
+
+ /* Mark place as start of authority */
+ marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path =
+ pos - url_s;
+
+ } else {
+ /* Not found a scheme */
+ if (joining == false) {
+ /* Assuming no scheme == http */
+ marker.scheme_type = NSURL_SCHEME_HTTP;
+ is_http = true;
+ }
+ }
+ }
+
+ /* Get authority
+ *
+ * Two slashes always indicates the start of an authority.
+ *
+ * We are more relaxed in the case of http:
+ * a. when joining, one or more slashes indicates start of authority
+ * b. when not joining, we assume authority if no scheme was present
+ * and in the case of mailto: when we assume there is an authority.
+ */
+ if ((*pos == '/' && *(pos + 1) == '/') ||
+ (is_http && ((joining && *pos == '/') ||
+ (joining == false &&
+ marker.scheme_end != marker.start))) ||
+ marker.scheme_type == NSURL_SCHEME_MAILTO) {
+
+ /* Skip over leading slashes */
+ if (*pos == '/') {
+ if (is_http == false) {
+ if (*pos == '/') pos++;
+ if (*pos == '/') pos++;
+ } else {
+ while (*pos == '/')
+ pos++;
+ }
+
+ marker.authority = marker.colon_first = marker.at =
+ marker.colon_last = marker.path =
+ pos - url_s;
+ }
+
+ /* Need to get (or complete) the authority */
+ while (*pos != '\0') {
+ if (*pos == '/' || *pos == '?' || *pos == '#') {
+ /* End of the authority */
+ break;
+
+ } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
+ *pos == ':' && marker.colon_first ==
+ marker.authority) {
+ /* could be username:password or host:port
+ * separator */
+ marker.colon_first = pos - url_s;
+
+ } else if (marker.scheme_type != NSURL_SCHEME_MAILTO &&
+ *pos == ':' && marker.colon_first !=
+ marker.authority) {
+ /* could be host:port separator */
+ marker.colon_last = pos - url_s;
+
+ } else if (*pos == '@' && marker.at ==
+ marker.authority) {
+ /* Credentials @ host separator */
+ marker.at = pos - url_s;
+ }
+
+ pos++;
+ }
+
+ marker.path = pos - url_s;
+
+ } else if ((*pos == '\0' || *pos == '/') &&
+ joining == false && is_http == true) {
+ marker.path = pos - url_s;
+ }
+
+ /* Get path
+ *
+ * Needs to start with '/' if there's no authority
+ */
+ if (*pos == '/' || ((marker.path == marker.authority) &&
+ (*pos != '?') && (*pos != '#') && (*pos !=
'\0'))) {
+ while (*(++pos) != '\0') {
+ if (*pos == '?' || *pos == '#') {
+ /* End of the path */
+ break;
+ }
+ }
+ }
+
+ marker.query = pos - url_s;
+
+ /* Get query */
+ if (*pos == '?') {
+ while (*(++pos) != '\0') {
+ if (*pos == '#') {
+ /* End of the query */
+ break;
+ }
+ }
+ }
+
+ marker.fragment = pos - url_s;
+
+ /* Get fragment */
+ if (*pos == '#') {
+ while (*(++pos) != '\0')
+ ;
+ }
+
+ /* We got to the end of url_s.
+ * Need to skip back over trailing whitespace to find end of URL */
+ pos--;
+ if (pos >= url_s && ascii_is_space(*pos)) {
+ trailing_whitespace = true;
+ while (pos >= url_s && ascii_is_space(*pos))
+ pos--;
+ }
+
+ marker.end = pos + 1 - url_s;
+
+ if (trailing_whitespace == true) {
+ /* Ensure last url section doesn't pass end */
+ if (marker.fragment > marker.end)
+ marker.fragment = marker.end;
+ if (marker.query > marker.end)
+ marker.query = marker.end;
+ if (marker.path > marker.end)
+ marker.path = marker.end;
+ if (marker.colon_last > marker.end)
+ marker.colon_last = marker.end;
+ if (marker.at > marker.end)
+ marker.at = marker.end;
+ if (marker.colon_last > marker.end)
+ marker.colon_last = marker.end;
+ if (marker.fragment > marker.end)
+ marker.fragment = marker.end;
+ }
+
+#ifdef NSURL_DEBUG
+ LOG("marker.start: %i", marker.start);
+ LOG("marker.scheme_end: %i", marker.scheme_end);
+ LOG("marker.authority: %i", marker.authority);
+
+ LOG("marker.colon_first: %i", marker.colon_first);
+ LOG("marker.at: %i", marker.at);
+ LOG("marker.colon_last: %i", marker.colon_last);
+
+ LOG("marker.path: %i", marker.path);
+ LOG("marker.query: %i", marker.query);
+ LOG("marker.fragment: %i", marker.fragment);
+
+ LOG("marker.end: %i", marker.end);
+#endif
+
+ /* Got all the URL components pegged out now */
+ *markers = marker;
+}
+
+
+/**
+ * Remove dot segments from a path, as per rfc 3986, 5.2.4
+ *
+ * \param path path to remove dot segments from ('\0' terminated)
+ * \param output path with dot segments removed
+ * \return size of output
+ */
+static size_t nsurl__remove_dot_segments(char *path, char *output)
+{
+ char *path_pos = path;
+ char *output_pos = output;
+
+ while (*path_pos != '\0') {
+#ifdef NSURL_DEBUG
+ LOG(" in:%s", path_pos);
+ LOG("out:%.*s", output_pos - output, output);
+#endif
+ if (*path_pos == '.') {
+ if (*(path_pos + 1) == '.' &&
+ *(path_pos + 2) == '/') {
+ /* Found prefix of "../" */
+ path_pos += SLEN("../");
+ continue;
+
+ } else if (*(path_pos + 1) == '/') {
+ /* Found prefix of "./" */
+ path_pos += SLEN("./");
+ continue;
+ }
+ } else if (*path_pos == '/' && *(path_pos + 1) == '.') {
+ if (*(path_pos + 2) == '/') {
+ /* Found prefix of "/./" */
+ path_pos += SLEN("/.");
+ continue;
+
+ } else if (*(path_pos + 2) == '\0') {
+ /* Found "/." at end of path */
+ *(output_pos++) = '/';
+
+ /* End of input path */
+ break;
+
+ } else if (*(path_pos + 2) == '.') {
+ if (*(path_pos + 3) == '/') {
+ /* Found prefix of "/../" */
+ path_pos += SLEN("/..");
+
+ if (output_pos > output)
+ output_pos--;
+ while (output_pos > output &&
+ *output_pos != '/')
+ output_pos--;
+
+ continue;
+
+ } else if (*(path_pos + 3) == '\0') {
+ /* Found "/.." at end of path */
+
+ while (output_pos > output &&
+ *(output_pos -1 ) !='/')
+ output_pos--;
+
+ /* End of input path */
+ break;
+ }
+ }
+ } else if (*path_pos == '.') {
+ if (*(path_pos + 1) == '\0') {
+ /* Found "." at end of path */
+
+ /* End of input path */
+ break;
+
+ } else if (*(path_pos + 1) == '.' &&
+ *(path_pos + 2) == '\0') {
+ /* Found ".." at end of path */
+
+ /* End of input path */
+ break;
+ }
+ }
+ /* Copy first character into output path */
+ *output_pos++ = *path_pos++;
+
+ /* Copy up to but not including next '/' */
+ while ((*path_pos != '/') && (*path_pos != '\0'))
+ *output_pos++ = *path_pos++;
+ }
+
+ return output_pos - output;
+}
+
+
+/**
+ * Get the length of the longest section
+ *
+ * \param m markers delimiting url sections in a string
+ * \return the length of the longest section
+ */
+static size_t nsurl__get_longest_section(struct url_markers *m)
+{
+ size_t length = m->scheme_end - m->start; /* scheme */
+
+ if (length < m->at - m->authority) /* credentials */
+ length = m->at - m->authority;
+
+ if (length < m->path - m->at) /* host */
+ length = m->path - m->at;
+
+ if (length < m->query - m->path) /* path */
+ length = m->query - m->path;
+
+ if (length < m->fragment - m->query) /* query */
+ length = m->fragment - m->query;
+
+ if (length < m->end - m->fragment) /* fragment */
+ length = m->end - m->fragment;
+
+ return length;
+}
+
+
+/**
+ * Converts two hexadecimal digits to a single number
+ *
+ * \param c1 most significant hex digit
+ * \param c2 least significant hex digit
+ * \return the total value of the two digit hex number, or -ve if input not hex
+ *
+ * For unescaping url encoded characters.
+ */
+static inline int nsurl__get_ascii_offset(char c1, char c2)
+{
+ int offset;
+
+ /* Use 1st char as most significant hex digit */
+ if (ascii_is_digit(c1))
+ offset = 16 * (c1 - '0');
+ else if (c1 >= 'a' && c1 <= 'f')
+ offset = 16 * (c1 - 'a' + 10);
+ else if (c1 >= 'A' && c1 <= 'F')
+ offset = 16 * (c1 - 'A' + 10);
+ else
+ /* Not valid hex */
+ return -1;
+
+ /* Use 2nd char as least significant hex digit and sum */
+ if (ascii_is_digit(c2))
+ offset += c2 - '0';
+ else if (c2 >= 'a' && c2 <= 'f')
+ offset += c2 - 'a' + 10;
+ else if (c2 >= 'A' && c2 <= 'F')
+ offset += c2 - 'A' + 10;
+ else
+ /* Not valid hex */
+ return -1;
+
+ return offset;
+}
+
+
+/**
+ * Create the components of a NetSurf URL object for a section of a URL string
+ *
+ * \param url_s URL string
+ * \param section Sets which section of URL string is to be normalised
+ * \param pegs Set of markers delimiting the URL string's sections
+ * \param pos_norm A buffer large enough for the normalised string (*3 + 1)
+ * \param url A NetSurf URL object, to which components may be added
+ * \return NSERROR_OK on success, appropriate error otherwise
+ *
+ * The section of url_s is normalised appropriately.
+ */
+static nserror nsurl__create_from_section(const char * const url_s,
+ const enum url_sections section,
+ const struct url_markers *pegs,
+ char *pos_norm,
+ struct nsurl_components *url)
+{
+ nserror ret;
+ int ascii_offset;
+ int start = 0;
+ int end = 0;
+ const char *pos;
+ const char *pos_url_s;
+ char *norm_start = pos_norm;
+ char *host;
+ size_t copy_len;
+ size_t length;
+ size_t host_len;
+ enum {
+ NSURL_F_NO_PORT = (1 << 0)
+ } flags = 0;
+
+ switch (section) {
+ case URL_SCHEME:
+ start = pegs->start;
+ end = pegs->scheme_end;
+ break;
+
+ case URL_CREDENTIALS:
+ start = pegs->authority;
+ end = pegs->at;
+ break;
+
+ case URL_HOST:
+ start = (pegs->at == pegs->authority &&
+ *(url_s + pegs->at) != '@') ?
+ pegs->at :
+ pegs->at + 1;
+ end = pegs->path;
+ break;
+
+ case URL_PATH:
+ start = pegs->path;
+ end = pegs->query;
+ break;
+
+ case URL_QUERY:
+ start = pegs->query;
+ end = pegs->fragment;
+ break;
+
+ case URL_FRAGMENT:
+ start = (*(url_s + pegs->fragment) != '#') ?
+ pegs->fragment :
+ pegs->fragment + 1;
+ end = pegs->end;
+ break;
+ }
+
+ if (end < start)
+ end = start;
+
+ length = end - start;
+
+ /* Stage 1: Normalise the required section */
+
+ pos = pos_url_s = url_s + start;
+ copy_len = 0;
+ for (; pos < url_s + end; pos++) {
+ if (*pos == '%' && (pos + 2 < url_s + end)) {
+ /* Might be an escaped character needing unescaped */
+
+ /* Find which character which was escaped */
+ ascii_offset = nsurl__get_ascii_offset(*(pos + 1),
+ *(pos + 2));
+
+ if (ascii_offset < 0) {
+ /* % with invalid hex digits. */
+ copy_len++;
+ continue;
+ }
+
+ if ((section != URL_SCHEME && section != URL_HOST) &&
+ (nsurl__is_unreserved(ascii_offset) == false)) {
+ /* This character should be escaped after all,
+ * just let it get copied */
+ copy_len += 3;
+ pos += 2;
+ continue;
+ }
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+
+ /* Put the unescaped character in the normalised URL */
+ *(pos_norm++) = (char)ascii_offset;
+ pos += 2;
+ pos_url_s = pos + 1;
+
+ length -= 2;
+
+ } else if ((section != URL_SCHEME && section != URL_HOST) &&
+ (nsurl__is_no_escape(*pos) == false)) {
+
+ /* This needs to be escaped */
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+
+ /* escape */
+ *(pos_norm++) = '%';
+ *(pos_norm++) = digit2uppercase_hex(
+ ((unsigned char)*pos) >> 4);
+ *(pos_norm++) = digit2uppercase_hex(
+ ((unsigned char)*pos) & 0xf);
+ pos_url_s = pos + 1;
+
+ length += 2;
+
+ } else if ((section == URL_SCHEME || section == URL_HOST) &&
+ ascii_is_alpha_upper(*pos)) {
+ /* Lower case this letter */
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ copy_len = 0;
+ }
+ /* Copy lower cased letter into normalised URL */
+ *(pos_norm++) = ascii_to_lower(*pos);
+ pos_url_s = pos + 1;
+
+ } else {
+ /* This character is safe in normalised URL */
+ copy_len++;
+ }
+ }
+
+ if (copy_len > 0) {
+ /* Copy up to here */
+ memcpy(pos_norm, pos_url_s, copy_len);
+ pos_norm += copy_len;
+ }
+
+ /* Mark end of section */
+ (*pos_norm) = '\0';
+
+ /* Stage 2: Create the URL components for the required section */
+ switch (section) {
+ case URL_SCHEME:
+ if (length == 0) {
+ /* No scheme, assuming http */
+ url->scheme = lwc_string_ref(corestring_lwc_http);
+ } else {
+ /* Add scheme to URL */
+ if (lwc_intern_string(norm_start, length,
+ &url->scheme) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ break;
+
+ case URL_CREDENTIALS:
+ url->username = NULL;
+ url->password = NULL;
+
+ if (length != 0 && *norm_start != ':') {
+ char *sec_start = norm_start;
+ if (pegs->colon_first != pegs->authority &&
+ pegs->at > pegs->colon_first + 1) {
+ /* there's a password */
+ sec_start += pegs->colon_first -
+ pegs->authority + 1;
+ if (lwc_intern_string(sec_start,
+ pegs->at - pegs->colon_first -1,
+ &url->password) !=
+ lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+
+ /* update start pos and length for username */
+ sec_start = norm_start;
+ length -= pegs->at - pegs->colon_first;
+ } else if (pegs->colon_first != pegs->authority &&
+ pegs->at == pegs->colon_first + 1) {
+ /* strip username colon */
+ length--;
+ }
+
+ /* Username */
+ if (lwc_intern_string(sec_start, length,
+ &url->username) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+
+ break;
+
+ case URL_HOST:
+ url->host = NULL;
+ url->port = NULL;
+
+ if (length != 0) {
+ size_t colon = 0;
+ char *sec_start = norm_start;
+ if (pegs->at < pegs->colon_first &&
+ pegs->colon_last == pegs->authority) {
+ /* There's one colon and it's after @ marker */
+ colon = pegs->colon_first;
+ } else if (pegs->colon_last != pegs->authority) {
+ /* There's more than one colon */
+ colon = pegs->colon_last;
+ } else {
+ /* There's no colon that could be a port
+ * separator */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ if (!(flags & NSURL_F_NO_PORT)) {
+ /* Determine whether colon is a port separator
+ */
+ sec_start += colon - pegs->at;
+ while (++sec_start < norm_start + length) {
+ if (!ascii_is_digit(*sec_start)) {
+ /* Character after port isn't a
+ * digit; not a port separator
+ */
+ flags |= NSURL_F_NO_PORT;
+ break;
+ }
+ }
+ }
+
+ if (!(flags & NSURL_F_NO_PORT)) {
+ /* There's a port */
+ size_t skip = (pegs->at == pegs->authority) ?
+ 1 : 0;
+ sec_start = norm_start + colon - pegs->at +
+ skip;
+ if (url->scheme != NULL &&
+ url->scheme_type ==
+ NSURL_SCHEME_HTTP &&
+ length -
+ (colon - pegs->at + skip) == 2 &&
+ *sec_start == '8' &&
+ *(sec_start + 1) == '0') {
+ /* Scheme is http, and port is default
+ * (80) */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ if (length <= (colon - pegs->at + skip)) {
+ /* No space for a port after the colon
+ */
+ flags |= NSURL_F_NO_PORT;
+ }
+
+ /* Add non-redundant ports to NetSurf URL */
+ sec_start = norm_start + colon - pegs->at +
+ skip;
+ if (!(flags & NSURL_F_NO_PORT) &&
+ lwc_intern_string(sec_start,
+ length -
+ (colon - pegs->at + skip),
+ &url->port) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+
+ /* update length for host */
+ skip = (pegs->at == pegs->authority) ? 0 : 1;
+ length = colon - pegs->at - skip;
+ }
+
+ /* host */
+ /* Encode host according to IDNA2008 */
+ ret = idna_encode(norm_start, length, &host, &host_len);
+ if (ret == NSERROR_OK) {
+ /* valid idna encoding */
+ if (lwc_intern_string(host, host_len,
+ &url->host) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ free(host);
+ } else {
+ /* fall back to straight interning */
+ if (lwc_intern_string(norm_start, length,
+ &url->host) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ }
+ }
+
+ break;
+
+ case URL_PATH:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->path) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else if (url->host != NULL &&
+ url->scheme_type != NSURL_SCHEME_MAILTO) {
+ /* Set empty path to "/", if there's a host */
+ if (lwc_intern_string("/", SLEN("/"),
+ &url->path) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->path = NULL;
+ }
+
+ break;
+
+ case URL_QUERY:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->query) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->query = NULL;
+ }
+
+ break;
+
+ case URL_FRAGMENT:
+ if (length != 0) {
+ if (lwc_intern_string(norm_start, length,
+ &url->fragment) != lwc_error_ok) {
+ return NSERROR_NOMEM;
+ }
+ } else {
+ url->fragment = NULL;
+ }
+
+ break;
+ }
+
+ return NSERROR_OK;
+}
+
+
+/**
+ * Get nsurl string info; total length, component lengths, & components present
+ *
+ * \param url NetSurf URL components
+ * \param parts Which parts of the URL are required in the string
+ * \param url_l Updated to total string length
+ * \param lengths Updated with individual component lengths
+ * \param pflags Updated to contain relevant string flags
+ */
+static void nsurl__get_string_data(const struct nsurl_components *url,
+ nsurl_component parts, size_t *url_l,
+ struct nsurl_component_lengths *lengths,
+ enum nsurl_string_flags *pflags)
+{
+ enum nsurl_string_flags flags = *pflags;
+ *url_l = 0;
+
+ /* Intersection of required parts and available parts gives
+ * the output parts */
+ if (url->scheme && parts & NSURL_SCHEME) {
+ flags |= NSURL_F_SCHEME;
+
+ lengths->scheme = lwc_string_length(url->scheme);
+ *url_l += lengths->scheme;
+ }
+
+ if (url->username && parts & NSURL_USERNAME) {
+ flags |= NSURL_F_USERNAME;
+
+ lengths->username = lwc_string_length(url->username);
+ *url_l += lengths->username;
+ }
+
+ if (url->password && parts & NSURL_PASSWORD) {
+ flags |= NSURL_F_PASSWORD;
+
+ lengths->password = lwc_string_length(url->password);
+ *url_l += SLEN(":") + lengths->password;
+ }
+
+ if (url->host && parts & NSURL_HOST) {
+ flags |= NSURL_F_HOST;
+
+ lengths->host = lwc_string_length(url->host);
+ *url_l += lengths->host;
+ }
+
+ if (url->port && parts & NSURL_PORT) {
+ flags |= NSURL_F_PORT;
+
+ lengths->port = lwc_string_length(url->port);
+ *url_l += SLEN(":") + lengths->port;
+ }
+
+ if (url->path && parts & NSURL_PATH) {
+ flags |= NSURL_F_PATH;
+
+ lengths->path = lwc_string_length(url->path);
+ *url_l += lengths->path;
+ }
+
+ if (url->query && parts & NSURL_QUERY) {
+ flags |= NSURL_F_QUERY;
+
+ lengths->query = lwc_string_length(url->query);
+ *url_l += lengths->query;
+ }
+
+ if (url->fragment && parts & NSURL_FRAGMENT) {
+ flags |= NSURL_F_FRAGMENT;
+
+ lengths->fragment = lwc_string_length(url->fragment);
+ *url_l += lengths->fragment;
+ }
+
+ /* Turn on any spanned punctuation */
+ if ((flags & NSURL_F_SCHEME) && (parts > NSURL_SCHEME)) {
+ flags |= NSURL_F_SCHEME_PUNCTUATION;
+
+ *url_l += SLEN(":");
+ }
+
+ if ((flags & NSURL_F_SCHEME) && (flags > NSURL_F_SCHEME) &&
+ url->path && lwc_string_data(url->path)[0] == '/') {
+ flags |= NSURL_F_AUTHORITY_PUNCTUATION;
+
+ *url_l += SLEN("//");
+ }
+
+ if ((flags & (NSURL_F_USERNAME | NSURL_F_PASSWORD)) &&
+ flags & NSURL_F_HOST) {
+ flags |= NSURL_F_CREDENTIALS_PUNCTUATION;
+
+ *url_l += SLEN("@");
+ }
+
+ if ((flags & ~NSURL_F_FRAGMENT) && (flags & NSURL_F_FRAGMENT)) {
+ flags |= NSURL_F_FRAGMENT_PUNCTUATION;
+
+ *url_l += SLEN("#");
+ }
+
+ *pflags = flags;
+}
+
+
+/**
+ * Get nsurl string info; total length, component lengths, & components present
+ *
+ * \param url NetSurf URL components
+ * \param url_s Updated to contain the string
+ * \param l Individual component lengths
+ * \param flags String flags
+ */
+static void nsurl_get_string(const struct nsurl_components *url, char *url_s,
+ struct nsurl_component_lengths *l,
+ enum nsurl_string_flags flags)
+{
+ char *pos;
+
+ /* Copy the required parts into the url string */
+ pos = url_s;
+
+ if (flags & NSURL_F_SCHEME) {
+ memcpy(pos, lwc_string_data(url->scheme), l->scheme);
+ pos += l->scheme;
+ }
+
+ if (flags & NSURL_F_SCHEME_PUNCTUATION) {
+ *(pos++) = ':';
+ }
+
+ if (flags & NSURL_F_AUTHORITY_PUNCTUATION) {
+ *(pos++) = '/';
+ *(pos++) = '/';
+ }
+
+ if (flags & NSURL_F_USERNAME) {
+ memcpy(pos, lwc_string_data(url->username), l->username);
+ pos += l->username;
+ }
+
+ if (flags & NSURL_F_PASSWORD) {
+ *(pos++) = ':';
+ memcpy(pos, lwc_string_data(url->password), l->password);
+ pos += l->password;
+ }
+
+ if (flags & NSURL_F_CREDENTIALS_PUNCTUATION) {
+ *(pos++) = '@';
+ }
+
+ if (flags & NSURL_F_HOST) {
+ memcpy(pos, lwc_string_data(url->host), l->host);
+ pos += l->host;
+ }
+
+ if (flags & NSURL_F_PORT) {
+ *(pos++) = ':';
+ memcpy(pos, lwc_string_data(url->port), l->port);
+ pos += l->port;
+ }
+
+ if (flags & NSURL_F_PATH) {
+ memcpy(pos, lwc_string_data(url->path), l->path);
+ pos += l->path;
+ }
+
+ if (flags & NSURL_F_QUERY) {
+ memcpy(pos, lwc_string_data(url->query), l->query);
+ pos += l->query;
+ }
+
+ if (flags & NSURL_F_FRAGMENT) {
+ if (flags & NSURL_F_FRAGMENT_PUNCTUATION)
+ *(pos++) = '#';
+ memcpy(pos, lwc_string_data(url->fragment), l->fragment);
+ pos += l->fragment;
+ }
+
+ *pos = '\0';
+}
+
+
+/**
+ * Calculate hash value
+ *
+ * \param url NetSurf URL object to set hash value for
+ */
+static void nsurl_calc_hash(nsurl *url)
+{
+ uint32_t hash = 0;
+
+ if (url->components.scheme)
+ hash ^= lwc_string_hash_value(url->components.scheme);
+
+ if (url->components.username)
+ hash ^= lwc_string_hash_value(url->components.username);
+
+ if (url->components.password)
+ hash ^= lwc_string_hash_value(url->components.password);
+
+ if (url->components.host)
+ hash ^= lwc_string_hash_value(url->components.host);
+
+ if (url->components.port)
+ hash ^= lwc_string_hash_value(url->components.port);
+
+ if (url->components.path)
+ hash ^= lwc_string_hash_value(url->components.path);
+
+ if (url->components.query)
+ hash ^= lwc_string_hash_value(url->components.query);
+
+ url->hash = hash;
+}
+
+
+/**
+ * Destroy components
+ *
+ * \param c url components
+ */
+static void nsurl_destroy_components(struct nsurl_components *c)
+{
+ if (c->scheme)
+ lwc_string_unref(c->scheme);
+
+ if (c->username)
+ lwc_string_unref(c->username);
+
+ if (c->password)
+ lwc_string_unref(c->password);
+
+ if (c->host)
+ lwc_string_unref(c->host);
+
+ if (c->port)
+ lwc_string_unref(c->port);
+
+ if (c->path)
+ lwc_string_unref(c->path);
+
+ if (c->query)
+ lwc_string_unref(c->query);
+
+ if (c->fragment)
+ lwc_string_unref(c->fragment);
+}
+
+
+#ifdef NSURL_DEBUG
+/**
+ * Dump a NetSurf URL's internal components
+ *
+ * \param url The NetSurf URL to dump components of
+ */
+static void nsurl__dump(const nsurl *url)
+{
+ if (url->components.scheme)
+ LOG(" Scheme: %s", lwc_string_data(url->components.scheme));
+
+ if (url->components.username)
+ LOG("Username: %s", lwc_string_data(url->components.username));
+
+ if (url->components.password)
+ LOG("Password: %s", lwc_string_data(url->components.password));
+
+ if (url->components.host)
+ LOG(" Host: %s", lwc_string_data(url->components.host));
+
+ if (url->components.port)
+ LOG(" Port: %s", lwc_string_data(url->components.port));
+
+ if (url->components.path)
+ LOG(" Path: %s", lwc_string_data(url->components.path));
+
+ if (url->components.query)
+ LOG(" Query: %s", lwc_string_data(url->components.query));
+
+ if (url->components.fragment)
+ LOG("Fragment: %s", lwc_string_data(url->components.fragment));
+}
+#endif
+
+/******************************************************************************
+ * NetSurf URL Public API *
+ ******************************************************************************/
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_create(const char * const url_s, nsurl **url)
+{
+ struct url_markers m;
+ struct nsurl_components c;
+ size_t length;
+ char *buff;
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ nserror e = NSERROR_OK;
+ bool match;
+
+ assert(url_s != NULL);
+
+ /* Peg out the URL sections */
+ nsurl__get_string_markers(url_s, &m, false);
+
+ /* Get the length of the longest section */
+ length = nsurl__get_longest_section(&m);
+
+ /* Allocate enough memory to url escape the longest section */
+ buff = malloc(length * 3 + 1);
+ if (buff == NULL)
+ return NSERROR_NOMEM;
+
+ /* Set scheme type */
+ c.scheme_type = m.scheme_type;
+
+ /* Build NetSurf URL object from sections */
+ e |= nsurl__create_from_section(url_s, URL_SCHEME, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_CREDENTIALS, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_HOST, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_PATH, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_QUERY, &m, buff, &c);
+ e |= nsurl__create_from_section(url_s, URL_FRAGMENT, &m, buff, &c);
+
+ /* Finished with buffer */
+ free(buff);
+
+ if (e != NSERROR_OK) {
+ nsurl_destroy_components(&c);
+ return NSERROR_NOMEM;
+ }
+
+ /* Validate URL */
+ if ((lwc_string_isequal(c.scheme, corestring_lwc_http,
+ &match) == lwc_error_ok && match == true) ||
+ (lwc_string_isequal(c.scheme, corestring_lwc_https,
+ &match) == lwc_error_ok && match == true)) {
+ /* http, https must have host */
+ if (c.host == NULL) {
+ nsurl_destroy_components(&c);
+ return NSERROR_BAD_URL;
+ }
+ }
+
+ /* Get the string length and find which parts of url are present */
+ nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
+ &str_len, &str_flags);
+
+ /* Create NetSurf URL object */
+ *url = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*url == NULL) {
+ nsurl_destroy_components(&c);
+ return NSERROR_NOMEM;
+ }
+
+ (*url)->components = c;
+ (*url)->length = length;
+
+ /* Fill out the url string */
+ nsurl_get_string(&c, (*url)->string, &str_len, str_flags);
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*url);
+
+ /* Give the URL a reference */
+ (*url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nsurl *nsurl_ref(nsurl *url)
+{
+ assert(url != NULL);
+
+ url->count++;
+
+ return url;
+}
+
+
+/* exported interface, documented in nsurl.h */
+void nsurl_unref(nsurl *url)
+{
+ assert(url != NULL);
+ assert(url->count > 0);
+
+ if (--url->count > 0)
+ return;
+
+#ifdef NSURL_DEBUG
+ nsurl__dump(url);
+#endif
+
+ /* Release lwc strings */
+ nsurl_destroy_components(&url->components);
+
+ /* Free the NetSurf URL */
+ free(url);
+}
+
+
+/* exported interface, documented in nsurl.h */
+bool nsurl_compare(const nsurl *url1, const nsurl *url2, nsurl_component parts)
+{
+ bool match = true;
+
+ assert(url1 != NULL);
+ assert(url2 != NULL);
+
+ /* Compare URL components */
+
+ /* Path, host and query first, since they're most likely to differ */
+
+ if (parts & NSURL_PATH) {
+ nsurl__component_compare(url1->components.path,
+ url2->components.path, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_HOST) {
+ nsurl__component_compare(url1->components.host,
+ url2->components.host, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_QUERY) {
+ nsurl__component_compare(url1->components.query,
+ url2->components.query, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_SCHEME) {
+ nsurl__component_compare(url1->components.scheme,
+ url2->components.scheme, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_USERNAME) {
+ nsurl__component_compare(url1->components.username,
+ url2->components.username, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_PASSWORD) {
+ nsurl__component_compare(url1->components.password,
+ url2->components.password, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_PORT) {
+ nsurl__component_compare(url1->components.port,
+ url2->components.port, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ if (parts & NSURL_FRAGMENT) {
+ nsurl__component_compare(url1->components.fragment,
+ url2->components.fragment, &match);
+
+ if (match == false)
+ return false;
+ }
+
+ return true;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_get(const nsurl *url, nsurl_component parts,
+ char **url_s, size_t *url_l)
+{
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+
+ assert(url != NULL);
+
+ /* Get the string length and find which parts of url need copied */
+ nsurl__get_string_data(&(url->components), parts, url_l,
+ &str_len, &str_flags);
+
+ if (*url_l == 0) {
+ return NSERROR_BAD_URL;
+ }
+
+ /* Allocate memory for url string */
+ *url_s = malloc(*url_l + 1); /* adding 1 for '\0' */
+ if (*url_s == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Copy the required parts into the url string */
+ nsurl_get_string(&(url->components), *url_s, &str_len, str_flags);
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+lwc_string *nsurl_get_component(const nsurl *url, nsurl_component part)
+{
+ assert(url != NULL);
+
+ switch (part) {
+ case NSURL_SCHEME:
+ return (url->components.scheme != NULL) ?
+ lwc_string_ref(url->components.scheme) : NULL;
+
+ case NSURL_USERNAME:
+ return (url->components.username != NULL) ?
+ lwc_string_ref(url->components.username) : NULL;
+
+ case NSURL_PASSWORD:
+ return (url->components.password != NULL) ?
+ lwc_string_ref(url->components.password) : NULL;
+
+ case NSURL_HOST:
+ return (url->components.host != NULL) ?
+ lwc_string_ref(url->components.host) : NULL;
+
+ case NSURL_PORT:
+ return (url->components.port != NULL) ?
+ lwc_string_ref(url->components.port) : NULL;
+
+ case NSURL_PATH:
+ return (url->components.path != NULL) ?
+ lwc_string_ref(url->components.path) : NULL;
+
+ case NSURL_QUERY:
+ return (url->components.query != NULL) ?
+ lwc_string_ref(url->components.query) : NULL;
+
+ case NSURL_FRAGMENT:
+ return (url->components.fragment != NULL) ?
+ lwc_string_ref(url->components.fragment) : NULL;
+
+ default:
+ LOG("Unsupported value passed to part param.");
+ assert(0);
+ }
+
+ return NULL;
+}
+
+
+/* exported interface, documented in nsurl.h */
+bool nsurl_has_component(const nsurl *url, nsurl_component part)
+{
+ assert(url != NULL);
+
+ switch (part) {
+ case NSURL_SCHEME:
+ if (url->components.scheme != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_CREDENTIALS:
+ /* Only username required for credentials section */
+ /* Fall through */
+ case NSURL_USERNAME:
+ if (url->components.username != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PASSWORD:
+ if (url->components.password != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_HOST:
+ if (url->components.host != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PORT:
+ if (url->components.port != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_PATH:
+ if (url->components.path != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_QUERY:
+ if (url->components.query != NULL)
+ return true;
+ else
+ return false;
+
+ case NSURL_FRAGMENT:
+ if (url->components.fragment != NULL)
+ return true;
+ else
+ return false;
+
+ default:
+ LOG("Unsupported value passed to part param.");
+ assert(0);
+ }
+
+ return false;
+}
+
+
+/* exported interface, documented in nsurl.h */
+const char *nsurl_access(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->string;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_get_utf8(const nsurl *url, char **url_s, size_t *url_l)
+{
+ nserror err;
+ lwc_string *host;
+ char *idna_host = NULL;
+ size_t idna_host_len;
+ char *scheme = NULL;
+ size_t scheme_len;
+ char *path = NULL;
+ size_t path_len;
+
+ assert(url != NULL);
+
+ if (url->components.host == NULL) {
+ return nsurl_get(url, NSURL_WITH_FRAGMENT, url_s, url_l);
+ }
+
+ host = url->components.host;
+ err = idna_decode(lwc_string_data(host), lwc_string_length(host),
+ &idna_host, &idna_host_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ err = nsurl_get(url,
+ NSURL_SCHEME | NSURL_CREDENTIALS,
+ &scheme, &scheme_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ err = nsurl_get(url,
+ NSURL_PORT | NSURL_PATH | NSURL_QUERY | NSURL_FRAGMENT,
+ &path, &path_len);
+ if (err != NSERROR_OK) {
+ goto cleanup;
+ }
+
+ *url_l = scheme_len + idna_host_len + path_len + 1; /* +1 for \0 */
+ *url_s = malloc(*url_l);
+
+ if (*url_s == NULL) {
+ err = NSERROR_NOMEM;
+ goto cleanup;
+ }
+
+ snprintf(*url_s, *url_l, "%s%s%s", scheme, idna_host, path);
+
+ err = NSERROR_OK;
+
+cleanup:
+ free(idna_host);
+ free(scheme);
+ free(path);
+
+ return err;
+}
+
+
+/* exported interface, documented in nsurl.h */
+const char *nsurl_access_leaf(const nsurl *url)
+{
+ size_t path_len;
+ const char *path;
+ const char *leaf;
+
+ assert(url != NULL);
+
+ if (url->components.path == NULL)
+ return "";
+
+ path = lwc_string_data(url->components.path);
+ path_len = lwc_string_length(url->components.path);
+
+ if (path_len == 0)
+ return "";
+
+ if (path_len == 1 && *path == '/')
+ return "/";
+
+ leaf = path + path_len;
+
+ do {
+ leaf--;
+ } while ((leaf != path) && (*leaf != '/'));
+
+ if (*leaf == '/')
+ leaf++;
+
+ return leaf;
+}
+
+
+/* exported interface, documented in nsurl.h */
+size_t nsurl_length(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->length;
+}
+
+
+/* exported interface, documented in nsurl.h */
+uint32_t nsurl_hash(const nsurl *url)
+{
+ assert(url != NULL);
+
+ return url->hash;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_join(const nsurl *base, const char *rel, nsurl **joined)
+{
+ struct url_markers m;
+ struct nsurl_components c;
+ size_t length;
+ char *buff;
+ char *buff_pos;
+ char *buff_start;
+ struct nsurl_component_lengths str_len = { 0, 0, 0, 0, 0, 0, 0, 0 };
+ enum nsurl_string_flags str_flags = 0;
+ nserror error = 0;
+ enum {
+ NSURL_F_REL = 0,
+ NSURL_F_BASE_SCHEME = (1 << 0),
+ NSURL_F_BASE_AUTHORITY = (1 << 1),
+ NSURL_F_BASE_PATH = (1 << 2),
+ NSURL_F_MERGED_PATH = (1 << 3),
+ NSURL_F_BASE_QUERY = (1 << 4)
+ } joined_parts;
+
+ assert(base != NULL);
+ assert(rel != NULL);
+
+#ifdef NSURL_DEBUG
+ LOG("base: \"%s\", rel: \"%s\"", nsurl_access(base),
rel);
+#endif
+
+ /* Peg out the URL sections */
+ nsurl__get_string_markers(rel, &m, true);
+
+ /* Get the length of the longest section */
+ length = nsurl__get_longest_section(&m);
+
+ /* Initially assume that the joined URL can be formed entierly from
+ * the relative URL.
+ */
+ joined_parts = NSURL_F_REL;
+
+ /* Update joined_compnents to indicate any required parts from the
+ * base URL.
+ */
+ if (m.scheme_end - m.start <= 0) {
+ /* The relative url has no scheme.
+ * Use base URL's scheme. */
+ joined_parts |= NSURL_F_BASE_SCHEME;
+
+ if (m.path - m.authority <= 0) {
+ /* The relative URL has no authority.
+ * Use base URL's authority. */
+ joined_parts |= NSURL_F_BASE_AUTHORITY;
+
+ if (m.query - m.path <= 0) {
+ /* The relative URL has no path.
+ * Use base URL's path. */
+ joined_parts |= NSURL_F_BASE_PATH;
+
+ if (m.fragment - m.query <= 0) {
+ /* The relative URL has no query.
+ * Use base URL's query. */
+ joined_parts |= NSURL_F_BASE_QUERY;
+ }
+
+ } else if (*(rel + m.path) != '/') {
+ /* Relative URL has relative path */
+ joined_parts |= NSURL_F_MERGED_PATH;
+ }
+ }
+ }
+
+ /* Allocate enough memory to url escape the longest section, plus
+ * space for path merging (if required).
+ */
+ if (joined_parts & NSURL_F_MERGED_PATH) {
+ /* Need to merge paths */
+ length += (base->components.path != NULL) ?
+ lwc_string_length(base->components.path) : 0;
+ }
+ length *= 4;
+ /* Plus space for removing dots from path */
+ length += (m.query - m.path) + ((base->components.path != NULL) ?
+ lwc_string_length(base->components.path) : 0);
+
+ buff = malloc(length + 5);
+ if (buff == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ buff_pos = buff;
+
+ /* Form joined URL from base or rel components, as appropriate */
+
+ if (joined_parts & NSURL_F_BASE_SCHEME) {
+ c.scheme_type = base->components.scheme_type;
+
+ c.scheme = nsurl__component_copy(base->components.scheme);
+ } else {
+ c.scheme_type = m.scheme_type;
+
+ error = nsurl__create_from_section(rel, URL_SCHEME, &m, buff, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_AUTHORITY) {
+ c.username = nsurl__component_copy(base->components.username);
+ c.password = nsurl__component_copy(base->components.password);
+ c.host = nsurl__component_copy(base->components.host);
+ c.port = nsurl__component_copy(base->components.port);
+ } else {
+ error = nsurl__create_from_section(rel, URL_CREDENTIALS, &m,
+ buff, &c);
+ if (error == NSERROR_OK) {
+ error = nsurl__create_from_section(rel, URL_HOST, &m,
+ buff, &c);
+ }
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_PATH) {
+ c.path = nsurl__component_copy(base->components.path);
+
+ } else if (joined_parts & NSURL_F_MERGED_PATH) {
+ struct url_markers m_path;
+ size_t new_length;
+
+ if (base->components.host != NULL &&
+ base->components.path == NULL) {
+ /* Append relative path to "/". */
+ *(buff_pos++) = '/';
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+
+ } else {
+ /* Append relative path to all but last segment of
+ * base path. */
+ size_t path_end = lwc_string_length(
+ base->components.path);
+ const char *path = lwc_string_data(
+ base->components.path);
+
+ while (*(path + path_end) != '/' &&
+ path_end != 0) {
+ path_end--;
+ }
+ if (*(path + path_end) == '/')
+ path_end++;
+
+ /* Copy the base part */
+ memcpy(buff_pos, path, path_end);
+ buff_pos += path_end;
+
+ /* Copy the relative part */
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+ }
+
+ /* add termination to string */
+ *buff_pos++ = '\0';
+
+ new_length = nsurl__remove_dot_segments(buff, buff_pos);
+
+ m_path.path = 0;
+ m_path.query = new_length;
+
+ buff_start = buff_pos + new_length;
+ error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
+ buff_start, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+
+ } else {
+ struct url_markers m_path;
+ size_t new_length;
+
+ memcpy(buff_pos, rel + m.path, m.query - m.path);
+ buff_pos += m.query - m.path;
+ *(buff_pos++) = '\0';
+
+ new_length = nsurl__remove_dot_segments(buff, buff_pos);
+
+ m_path.path = 0;
+ m_path.query = new_length;
+
+ buff_start = buff_pos + new_length;
+
+ error = nsurl__create_from_section(buff_pos, URL_PATH, &m_path,
+ buff_start, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ if (joined_parts & NSURL_F_BASE_QUERY) {
+ c.query = nsurl__component_copy(base->components.query);
+ } else {
+ error = nsurl__create_from_section(rel, URL_QUERY, &m,
+ buff, &c);
+ if (error != NSERROR_OK) {
+ free(buff);
+ return error;
+ }
+ }
+
+ error = nsurl__create_from_section(rel, URL_FRAGMENT, &m, buff, &c);
+
+ /* Free temporary buffer */
+ free(buff);
+
+ if (error != NSERROR_OK) {
+ return error;
+ }
+
+ /* Get the string length and find which parts of url are present */
+ nsurl__get_string_data(&c, NSURL_WITH_FRAGMENT, &length,
+ &str_len, &str_flags);
+
+ /* Create NetSurf URL object */
+ *joined = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*joined == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*joined)->components = c;
+ (*joined)->length = length;
+
+ /* Fill out the url string */
+ nsurl_get_string(&c, (*joined)->string, &str_len, str_flags);
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*joined);
+
+ /* Give the URL a reference */
+ (*joined)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_defragment(const nsurl *url, nsurl **no_frag)
+{
+ size_t length;
+ char *pos;
+
+ assert(url != NULL);
+
+ /* check for source url having no fragment already */
+ if (url->components.fragment == NULL) {
+ *no_frag = (nsurl *)url;
+
+ (*no_frag)->count++;
+
+ return NSERROR_OK;
+ }
+
+ /* Find the change in length from url to new_url */
+ length = url->length;
+ if (url->components.fragment != NULL) {
+ length -= 1 + lwc_string_length(url->components.fragment);
+ }
+
+ /* Create NetSurf URL object */
+ *no_frag = malloc(sizeof(nsurl) + length + 1); /* Add 1 for \0 */
+ if (*no_frag == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Copy components */
+ (*no_frag)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*no_frag)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*no_frag)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*no_frag)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*no_frag)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*no_frag)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*no_frag)->components.query =
+ nsurl__component_copy(url->components.query);
+ (*no_frag)->components.fragment = NULL;
+
+ (*no_frag)->components.scheme_type = url->components.scheme_type;
+
+ (*no_frag)->length = length;
+
+ /* Fill out the url string */
+ pos = (*no_frag)->string;
+ memcpy(pos, url->string, length);
+ pos += length;
+ *pos = '\0';
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*no_frag);
+
+ /* Give the URL a reference */
+ (*no_frag)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_refragment(const nsurl *url, lwc_string *frag, nsurl **new_url)
+{
+ int frag_len;
+ int base_len;
+ char *pos;
+ size_t len;
+
+ assert(url != NULL);
+ assert(frag != NULL);
+
+ /* Find the change in length from url to new_url */
+ base_len = url->length;
+ if (url->components.fragment != NULL) {
+ base_len -= 1 + lwc_string_length(url->components.fragment);
+ }
+ frag_len = lwc_string_length(frag);
+
+ /* Set new_url's length */
+ len = base_len + 1 /* # */ + frag_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, base_len);
+ pos += base_len;
+ *pos = '#';
+ memcpy(++pos, lwc_string_data(frag), frag_len);
+ pos += frag_len;
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*new_url)->components.query =
+ nsurl__component_copy(url->components.query);
+ (*new_url)->components.fragment =
+ lwc_string_ref(frag);
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_replace_query(const nsurl *url, const char *query,
+ nsurl **new_url)
+{
+ int query_len; /* Length of new query string, including '?' */
+ int frag_len = 0; /* Length of fragment, including '#' */
+ int base_len; /* Length of URL up to start of query */
+ char *pos;
+ size_t len;
+ lwc_string *lwc_query;
+
+ assert(url != NULL);
+ assert(query != NULL);
+ assert(query[0] == '?');
+
+ /* Get the length of the new query */
+ query_len = strlen(query);
+
+ /* Find the change in length from url to new_url */
+ base_len = url->length;
+ if (url->components.query != NULL) {
+ base_len -= lwc_string_length(url->components.query);
+ }
+ if (url->components.fragment != NULL) {
+ frag_len = 1 + lwc_string_length(url->components.fragment);
+ base_len -= frag_len;
+ }
+
+ /* Set new_url's length */
+ len = base_len + query_len + frag_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ if (lwc_intern_string(query, query_len, &lwc_query) != lwc_error_ok) {
+ free(*new_url);
+ return NSERROR_NOMEM;
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, base_len);
+ pos += base_len;
+ memcpy(pos, query, query_len);
+ pos += query_len;
+ if (url->components.fragment != NULL) {
+ const char *frag = lwc_string_data(url->components.fragment);
+ *pos = '#';
+ memcpy(++pos, frag, frag_len - 1);
+ pos += frag_len - 1;
+ }
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path =
+ nsurl__component_copy(url->components.path);
+ (*new_url)->components.query = lwc_query;
+ (*new_url)->components.fragment =
+ nsurl__component_copy(url->components.fragment);
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
+
+/* exported interface documented in utils/nsurl.h */
+nserror nsurl_nice(const nsurl *url, char **result, bool remove_extensions)
+{
+ const char *data;
+ size_t len;
+ size_t pos;
+ bool match;
+ char *name;
+
+ assert(url != NULL);
+
+ *result = 0;
+
+ /* extract the last component of the path, if possible */
+ if ((url->components.path != NULL) &&
+ (lwc_string_length(url->components.path) != 0) &&
+ (lwc_string_isequal(url->components.path,
+ corestring_lwc_slash_, &match) == lwc_error_ok) &&
+ (match == false)) {
+ bool first = true;
+ bool keep_looking;
+
+ /* Get hold of the string data we're examining */
+ data = lwc_string_data(url->components.path);
+ len = lwc_string_length(url->components.path);
+ pos = len;
+
+ do {
+ keep_looking = false;
+ pos--;
+
+ /* Find last '/' with stuff after it */
+ while (pos != 0) {
+ if (data[pos] == '/' && pos < len - 1) {
+ break;
+ }
+ pos--;
+ }
+
+ if (pos == 0) {
+ break;
+ }
+
+ if (first) {
+ if (strncasecmp("/default.", data + pos,
+ SLEN("/default.")) == 0) {
+ keep_looking = true;
+
+ } else if (strncasecmp("/index.",
+ data + pos,
+ 6) == 0) {
+ keep_looking = true;
+
+ }
+ first = false;
+ }
+
+ } while (keep_looking);
+
+ if (data[pos] == '/')
+ pos++;
+
+ if (strncasecmp("default.", data + pos, 8) != 0 &&
+ strncasecmp("index.", data + pos, 6) != 0) {
+ size_t end = pos;
+ while (data[end] != '\0' && data[end] != '/') {
+ end++;
+ }
+ if (end - pos != 0) {
+ name = malloc(end - pos + 1);
+ if (name == NULL) {
+ return NSERROR_NOMEM;
+ }
+ memcpy(name, data + pos, end - pos);
+ name[end - pos] = '\0';
+ if (remove_extensions) {
+ /* strip any extenstion */
+ char *dot = strchr(name, '.');
+ if (dot && dot != name) {
+ *dot = '\0';
+ }
+ }
+ *result = name;
+ return NSERROR_OK;
+ }
+ }
+ }
+
+ if (url->components.host != NULL) {
+ name = strdup(lwc_string_data(url->components.host));
+
+ for (pos = 0; name[pos] != '\0'; pos++) {
+ if (name[pos] == '.') {
+ name[pos] = '_';
+ }
+ }
+
+ *result = name;
+ return NSERROR_OK;
+ }
+
+ return NSERROR_NOT_FOUND;
+}
+
+
+/* exported interface, documented in nsurl.h */
+nserror nsurl_parent(const nsurl *url, nsurl **new_url)
+{
+ lwc_string *lwc_path;
+ size_t old_path_len, new_path_len;
+ size_t len;
+ const char* path = NULL;
+ char *pos;
+
+ assert(url != NULL);
+
+ old_path_len = (url->components.path == NULL) ? 0 :
+ lwc_string_length(url->components.path);
+
+ /* Find new path length */
+ if (old_path_len == 0) {
+ new_path_len = old_path_len;
+ } else {
+ path = lwc_string_data(url->components.path);
+
+ new_path_len = old_path_len;
+ if (old_path_len > 1) {
+ /* Skip over any trailing / */
+ if (path[new_path_len - 1] == '/')
+ new_path_len--;
+
+ /* Work back to next / */
+ while (new_path_len > 0 &&
+ path[new_path_len - 1] != '/')
+ new_path_len--;
+ }
+ }
+
+ /* Find the length of new_url */
+ len = url->length;
+ if (url->components.query != NULL) {
+ len -= lwc_string_length(url->components.query);
+ }
+ if (url->components.fragment != NULL) {
+ len -= 1; /* # */
+ len -= lwc_string_length(url->components.fragment);
+ }
+ len -= old_path_len - new_path_len;
+
+ /* Create NetSurf URL object */
+ *new_url = malloc(sizeof(nsurl) + len + 1); /* Add 1 for \0 */
+ if (*new_url == NULL) {
+ return NSERROR_NOMEM;
+ }
+
+ /* Make new path */
+ if (old_path_len == 0) {
+ lwc_path = NULL;
+ } else if (old_path_len == new_path_len) {
+ lwc_path = lwc_string_ref(url->components.path);
+ } else {
+ if (lwc_intern_string(path, old_path_len - new_path_len,
+ &lwc_path) != lwc_error_ok) {
+ free(*new_url);
+ return NSERROR_NOMEM;
+ }
+ }
+
+ (*new_url)->length = len;
+
+ /* Set string */
+ pos = (*new_url)->string;
+ memcpy(pos, url->string, len);
+ pos += len;
+ *pos = '\0';
+
+ /* Copy components */
+ (*new_url)->components.scheme =
+ nsurl__component_copy(url->components.scheme);
+ (*new_url)->components.username =
+ nsurl__component_copy(url->components.username);
+ (*new_url)->components.password =
+ nsurl__component_copy(url->components.password);
+ (*new_url)->components.host =
+ nsurl__component_copy(url->components.host);
+ (*new_url)->components.port =
+ nsurl__component_copy(url->components.port);
+ (*new_url)->components.path = lwc_path;
+ (*new_url)->components.query = NULL;
+ (*new_url)->components.fragment = NULL;
+
+ (*new_url)->components.scheme_type = url->components.scheme_type;
+
+ /* Get the nsurl's hash */
+ nsurl_calc_hash(*new_url);
+
+ /* Give the URL a reference */
+ (*new_url)->count = 1;
+
+ return NSERROR_OK;
+}
+
-----------------------------------------------------------------------
Summary of changes:
Docs/UnimplementedJavascript.txt | 3 -
content/content.c | 4 +-
content/fetch.c | 8 -
content/fetch.h | 7 -
content/fetchers/data.c | 1 +
content/fetchers/file.c | 1 +
content/fetchers/resource.c | 1 +
content/fs_backing_store.c | 31 +-
content/handlers/image/image_cache.c | 2 +-
content/handlers/image/png.c | 1 +
.../handlers/javascript/duktape/EventTarget.bnd | 277 ++++++
content/handlers/javascript/duktape/Node.bnd | 1 +
content/handlers/javascript/duktape/dukky.c | 198 +++-
content/handlers/javascript/duktape/dukky.h | 13 +-
content/handlers/javascript/duktape/netsurf.bnd | 1 +
content/llcache.c | 4 +-
desktop/netsurf.c | 2 +-
desktop/textarea.h | 1 -
desktop/treeview.c | 1 +
frontends/amiga/Makefile | 2 +-
frontends/amiga/clipboard.c | 8 +-
frontends/amiga/cookies.c | 39 +-
frontends/amiga/dist/NetSurf.guide | 4 +-
frontends/amiga/gui.c | 39 +-
frontends/amiga/gui.h | 4 +-
frontends/amiga/{menu.c => gui_menu.c} | 971 +++++++++---------
frontends/amiga/{menu.h => gui_menu.h} | 81 +-
frontends/amiga/gui_options.c | 7 +-
frontends/amiga/history.c | 43 +-
frontends/amiga/hotlist.c | 51 +-
frontends/amiga/iff_dr2d.c | 2 +-
frontends/amiga/menu.c | 1027 +++-----------------
frontends/amiga/menu.h | 153 +--
frontends/atari/bitmap.c | 2 +-
frontends/atari/cookies.c | 1 +
frontends/atari/deskmenu.c | 1 +
frontends/atari/download.c | 2 +-
frontends/atari/font.c | 2 +-
frontends/atari/gemtk/guiwin.c | 94 +-
frontends/atari/gemtk/objc.c | 2 +
frontends/atari/gui.c | 14 +-
frontends/atari/hotlist.c | 10 +-
frontends/atari/plot/font_freetype.c | 5 +-
frontends/atari/plot/font_internal.c | 2 +-
frontends/atari/redrawslots.h | 4 +-
frontends/atari/rootwin.c | 4 +-
frontends/atari/settings.c | 5 +-
frontends/atari/treeview.c | 23 +-
frontends/cocoa/FormSelectMenu.m | 2 +-
frontends/framebuffer/font_freetype.c | 2 +-
frontends/gtk/corewindow.c | 1 -
frontends/gtk/gui.c | 6 +
frontends/gtk/hotlist.c | 2 +-
frontends/gtk/plotters.c | 1 -
frontends/gtk/toolbar.c | 1 -
frontends/gtk/window.c | 3 +-
frontends/riscos/corewindow.c | 2 +-
frontends/riscos/gui/url_bar.c | 1 -
frontends/riscos/plotters.c | 1 -
frontends/riscos/print.c | 1 -
frontends/riscos/save_draw.c | 1 -
frontends/riscos/url_complete.h | 3 +-
frontends/riscos/window.c | 3 +-
frontends/windows/about.c | 1 -
frontends/windows/corewindow.c | 2 +-
frontends/windows/drawable.c | 1 -
frontends/windows/filetype.c | 1 -
frontends/windows/font.c | 2 +-
frontends/windows/gui.c | 1 -
frontends/windows/localhistory.c | 1 -
frontends/windows/plot.c | 1 -
frontends/windows/pointers.c | 1 -
frontends/windows/prefs.c | 1 -
frontends/windows/schedule.c | 1 -
include/netsurf/{types.h => inttypes.h} | 44 +-
include/netsurf/types.h | 8 +
render/box.c | 6 +-
render/box_construct.c | 1 -
render/form.c | 4 +-
render/html.c | 1 +
render/html_css_fetcher.c | 10 +-
render/imagemap.c | 6 +-
render/search.c | 3 +-
test/Makefile | 28 +-
test/hashtable.c | 7 +
test/js/dom-change-event.html | 17 +
test/js/index.html | 1 +
utils/corestrings.c | 26 +
utils/corestrings.h | 10 +-
utils/http/primitives.c | 2 +-
utils/idna.c | 2 +
utils/utils.h | 33 +-
92 files changed, 1479 insertions(+), 1932 deletions(-)
create mode 100644 content/handlers/javascript/duktape/EventTarget.bnd
copy frontends/amiga/{menu.c => gui_menu.c} (54%)
copy frontends/amiga/{menu.h => gui_menu.h} (56%)
copy include/netsurf/{types.h => inttypes.h} (55%)
create mode 100644 test/js/dom-change-event.html
diff --git a/Docs/UnimplementedJavascript.txt b/Docs/UnimplementedJavascript.txt
index 2b3a7d9..1b851b8 100644
--- a/Docs/UnimplementedJavascript.txt
+++ b/Docs/UnimplementedJavascript.txt
@@ -439,9 +439,6 @@ setter EventSource::onopen(user);\n
getter EventSource::readyState(unsigned short);\n
getter EventSource::url(string);\n
getter EventSource::withCredentials(boolean);\n
-method EventTarget::addEventListener();\n
-method EventTarget::dispatchEvent();\n
-method EventTarget::removeEventListener();\n
getter Event::timeStamp(user);\n
method External::AddSearchProvider();\n
method External::IsSearchProviderInstalled();\n
diff --git a/content/content.c b/content/content.c
index f650af2..2eb035c 100644
--- a/content/content.c
+++ b/content/content.c
@@ -21,11 +21,11 @@
* Content handling implementation.
*/
-#include <inttypes.h>
+#include <stdint.h>
#include <stdlib.h>
#include <nsutils/time.h>
-#include "utils/utils.h"
+#include "netsurf/inttypes.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "netsurf/browser_window.h"
diff --git a/content/fetch.c b/content/fetch.c
index 93c7de2..a1542eb 100644
--- a/content/fetch.c
+++ b/content/fetch.c
@@ -46,7 +46,6 @@
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/nsurl.h"
-#include "utils/utils.h"
#include "utils/ring.h"
#include "netsurf/misc.h"
#include "desktop/gui_internal.h"
@@ -643,13 +642,6 @@ long fetch_http_code(struct fetch *fetch)
return fetch->http_code;
}
-/* exported interface documented in content/fetch.h */
-bool fetch_get_verifiable(struct fetch *fetch)
-{
- assert(fetch);
-
- return fetch->verifiable;
-}
/* exported interface documented in content/fetch.h */
struct fetch_multipart_data *
diff --git a/content/fetch.h b/content/fetch.h
index 51e08cf..5521778 100644
--- a/content/fetch.h
+++ b/content/fetch.h
@@ -158,13 +158,6 @@ void fetch_change_callback(struct fetch *fetch, fetch_callback
callback, void *p
*/
long fetch_http_code(struct fetch *fetch);
-/**
- * Determine if a fetch was verifiable
- *
- * \param fetch Fetch to consider
- * \return Verifiable status of fetch
- */
-bool fetch_get_verifiable(struct fetch *fetch);
/**
* Free a linked list of fetch_multipart_data.
diff --git a/content/fetchers/data.c b/content/fetchers/data.c
index 139d09a..cb99e6f 100644
--- a/content/fetchers/data.c
+++ b/content/fetchers/data.c
@@ -27,6 +27,7 @@
#include <libwapcaplet/libwapcaplet.h>
#include <nsutils/base64.h>
+#include "netsurf/inttypes.h"
#include "utils/url.h"
#include "utils/nsurl.h"
#include "utils/corestrings.h"
diff --git a/content/fetchers/file.c b/content/fetchers/file.c
index 6ffa638..4fa1a21 100644
--- a/content/fetchers/file.c
+++ b/content/fetchers/file.c
@@ -44,6 +44,7 @@
#endif
#include <libwapcaplet/libwapcaplet.h>
+#include "netsurf/inttypes.h"
#include "utils/nsurl.h"
#include "utils/dirent.h"
#include "utils/corestrings.h"
diff --git a/content/fetchers/resource.c b/content/fetchers/resource.c
index 21ad8c7..b8b4b19 100644
--- a/content/fetchers/resource.c
+++ b/content/fetchers/resource.c
@@ -29,6 +29,7 @@
#include <stdarg.h>
#include <libwapcaplet/libwapcaplet.h>
+#include "netsurf/inttypes.h"
#include "utils/nsurl.h"
#include "utils/corestrings.h"
#include "utils/log.h"
diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c
index 635f917..bcb97d2 100644
--- a/content/fs_backing_store.c
+++ b/content/fs_backing_store.c
@@ -43,11 +43,11 @@
#include <stdlib.h>
#include <nsutils/unistd.h>
+#include "netsurf/inttypes.h"
#include "utils/filepath.h"
#include "utils/file.h"
#include "utils/nsurl.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/messages.h"
#include "desktop/gui_internal.h"
#include "netsurf/misc.h"
@@ -620,7 +620,7 @@ static nserror store_evict(struct store_state *state)
return NSERROR_OK;
}
- LOG("Evicting entries to reduce %"PRIu64" by %zd",
+ LOG("Evicting entries to reduce %"PRIu64" by %"PRIsizet,
state->total_alloc, state->hysteresis);
/* allocate storage for the list */
@@ -658,7 +658,7 @@ static nserror store_evict(struct store_state *state)
free(elist);
- LOG("removed %zd in %d entries", removed, ent);
+ LOG("removed %"PRIsizet" in %d entries", removed, ent);
return ret;
}
@@ -1204,7 +1204,7 @@ read_entries(struct store_state *state)
entries_size = (1 << state->entry_bits) * sizeof(struct store_entry);
- LOG("Allocating %zd bytes for max of %d entries of %ld length elements %ld
length",
+ LOG("Allocating %"PRIsizet" bytes for max of %d entries of %ld length
elements %ld length",
entries_size, 1 << state->entry_bits,
sizeof(struct store_entry),
sizeof(struct store_entry_element));
@@ -1560,13 +1560,13 @@ initialise(const struct llcache_store_parameters *parameters)
LOG("FS backing store init successful");
- LOG("path:%s limit:%zd hyst:%zd addr:%d entries:%d",
+ LOG("path:%s limit:%"PRIsizet" hyst:%"PRIsizet" addr:%d
entries:%d",
newstate->path,
newstate->limit,
newstate->hysteresis,
newstate->ident_bits,
newstate->entry_bits);
- LOG("Using %"PRIu64"/%zd", newstate->total_alloc,
newstate->limit);
+ LOG("Using %"PRIu64"/%"PRIsizet, newstate->total_alloc,
newstate->limit);
return NSERROR_OK;
}
@@ -1605,7 +1605,7 @@ finalise(void)
/* avoid division by zero */
if (op_count > 0) {
- LOG("Cache total/hit/miss/fail (counts) %d/%zd/%zd/%d
(100%%/%zd%%/%zd%%/%d%%)",
+ LOG("Cache total/hit/miss/fail (counts)
%d/%"PRIsizet"/%"PRIsizet"/%d
(100%%/%"PRIsizet"%%/%"PRIsizet"%%/%d%%)",
op_count,
storestate->hit_count,
storestate->miss_count,
@@ -1661,7 +1661,7 @@ static nserror store_write_block(struct store_state *state,
bse->elem[elem_idx].size,
offst);
if (wr != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Write failed %zd of %d bytes from %p at 0x%jx block %d errno %d",
+ LOG("Write failed %"PRIssizet" of %d bytes from %p at 0x%jx block %d
errno %d",
wr,
bse->elem[elem_idx].size,
bse->elem[elem_idx].data,
@@ -1671,7 +1671,7 @@ static nserror store_write_block(struct store_state *state,
return NSERROR_SAVE_FAILED;
}
- LOG("Wrote %zd bytes from %p at 0x%jx block %d",
+ LOG("Wrote %"PRIssizet" bytes from %p at 0x%jx block %d",
wr,
bse->elem[elem_idx].data,
(uintmax_t)offst,
@@ -1708,7 +1708,7 @@ static nserror store_write_file(struct store_state *state,
close(fd);
if (wr != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Write failed %zd of %d bytes from %p errno %d",
+ LOG("Write failed %"PRIssizet" of %d bytes from %p errno %d",
wr,
bse->elem[elem_idx].size,
bse->elem[elem_idx].data,
@@ -1718,7 +1718,7 @@ static nserror store_write_file(struct store_state *state,
return NSERROR_SAVE_FAILED;
}
- LOG("Wrote %zd bytes from %p", wr, bse->elem[elem_idx].data);
+ LOG("Wrote %"PRIssizet" bytes from %p", wr,
bse->elem[elem_idx].data);
return NSERROR_OK;
}
@@ -1829,7 +1829,7 @@ static nserror store_read_block(struct store_state *state,
bse->elem[elem_idx].size,
offst);
if (rd != (ssize_t)bse->elem[elem_idx].size) {
- LOG("Failed reading %zd of %d bytes into %p from 0x%jx block %d errno %d",
+ LOG("Failed reading %"PRIssizet" of %d bytes into %p from 0x%jx block %d
errno %d",
rd,
bse->elem[elem_idx].size,
bse->elem[elem_idx].data,
@@ -1839,7 +1839,7 @@ static nserror store_read_block(struct store_state *state,
return NSERROR_SAVE_FAILED;
}
- LOG("Read %zd bytes into %p from 0x%jx block %d",
+ LOG("Read %"PRIssizet" bytes into %p from 0x%jx block %d",
rd,
bse->elem[elem_idx].data,
(uintmax_t)offst,
@@ -1878,7 +1878,8 @@ static nserror store_read_file(struct store_state *state,
bse->elem[elem_idx].data + tot,
bse->elem[elem_idx].size - tot);
if (rd <= 0) {
- LOG("read error returned %zd errno %d", rd, errno);
+ LOG("read error returned %"PRIssizet" errno %d",
+ rd, errno);
ret = NSERROR_NOT_FOUND;
break;
}
@@ -1887,7 +1888,7 @@ static nserror store_read_file(struct store_state *state,
close(fd);
- LOG("Read %zd bytes into %p", tot, bse->elem[elem_idx].data);
+ LOG("Read %"PRIsizet" bytes into %p", tot,
bse->elem[elem_idx].data);
return ret;
}
diff --git a/content/handlers/image/image_cache.c b/content/handlers/image/image_cache.c
index 9c7ce22..02107f7 100644
--- a/content/handlers/image/image_cache.c
+++ b/content/handlers/image/image_cache.c
@@ -22,12 +22,12 @@
*/
#include <assert.h>
-#include <inttypes.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
+#include "netsurf/inttypes.h"
#include "utils/utils.h"
#include "utils/log.h"
#include "netsurf/misc.h"
diff --git a/content/handlers/image/png.c b/content/handlers/image/png.c
index 93185c1..0baf411 100644
--- a/content/handlers/image/png.c
+++ b/content/handlers/image/png.c
@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <png.h>
+#include "netsurf/inttypes.h"
#include "utils/utils.h"
#include "utils/log.h"
#include "utils/messages.h"
diff --git a/content/handlers/javascript/duktape/EventTarget.bnd
b/content/handlers/javascript/duktape/EventTarget.bnd
new file mode 100644
index 0000000..92e2ac8
--- /dev/null
+++ b/content/handlers/javascript/duktape/EventTarget.bnd
@@ -0,0 +1,277 @@
+/* Event Target binding for browser using duktape and libdom
+ *
+ * Copyright 2016 Daniel Silverstone <dsilvers(a)digital-scurf.org>
+ *
+ * This file is part of NetSurf,
http://www.netsurf-browser.org/
+ *
+ * Released under the terms of the MIT License,
+ *
http://www.opensource.org/licenses/mit-license
+ */
+
+class EventTarget {
+ private bool is_node;
+ private bool capture_registered;
+ private bool bubbling_registered;
+};
+
+prologue EventTarget()
+%{
+
+static event_listener_flags event_listener_pop_options(duk_context *ctx)
+{
+ event_listener_flags ret = ELF_NONE;
+ /* ... options */
+ duk_get_prop_string(ctx, -1, "capture");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_CAPTURE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "passive");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_PASSIVE;
+ duk_pop(ctx);
+ duk_get_prop_string(ctx, -1, "once");
+ if (duk_to_boolean(ctx, -1))
+ ret |= ELF_ONCE;
+ duk_pop_2(ctx);
+ /* ... */
+ return ret;
+}
+
+static void event_target_register_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is already present,
+ * we do not re-add it, otherwise we need to add to listeners
+ * a tuple of the callback and flags
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* already present, nothing to do */
+ duk_pop_n(ctx, 5);
+ /* ... */
+ return;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_array(ctx);
+ /* ... listeners callback newcandidate */
+ duk_insert(ctx, -2);
+ /* ... listeners newcandidate callback */
+ duk_put_prop_index(ctx, -2, 0);
+ /* ... listeners newcandidate */
+ duk_push_int(ctx, (duk_int_t)flags);
+ /* ... listeners newcandidate flags */
+ duk_put_prop_index(ctx, -2, 1);
+ /* ... listeners newcandidate */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+static void event_target_unregister_listener(duk_context *ctx,
+ event_listener_flags flags)
+{
+ /* ... listeners callback */
+ /* If the given callback with the given flags is present,
+ * we remove it and shuffle the rest up.
+ */
+ duk_uarridx_t idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx)) {
+ /* ... listeners callback candidate */
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ if (duk_strict_equals(ctx, -1, -3) &&
+ duk_get_int(ctx, -1) == (duk_int_t)flags) {
+ /* present */
+ duk_pop(ctx);
+ /* ... listeners callback candidate candidatecallback */
+ duk_put_prop_index(ctx, -2, 2);
+ /* ... listeners callback candidate */
+ duk_pop(ctx);
+ /* ... listeners callback */
+ duk_push_int(ctx, idx);
+ /* ... listeners callback found_at */
+ break;
+ }
+ /* ... listeners callback candidate candidatecallback candidateflags */
+ duk_pop_3(ctx);
+ /* ... listeners callback */
+ idx++;
+ }
+ /* ... listeners callback undefined/found_at */
+ if (duk_is_undefined(ctx, -1)) {
+ /* not found, clean up and come out */
+ duk_pop_3(ctx);
+ return;
+ }
+ idx = duk_to_int(ctx, -1);
+ duk_pop_2(ctx);
+ /* ... listeners */
+ dukky_shuffle_array(ctx, idx);
+ /* ... listeners */
+ duk_pop(ctx);
+ /* ... */
+}
+
+
+%}
+
+init EventTarget()
+%{
+ priv->is_node = false;
+ priv->capture_registered = false;
+ priv->bubbling_registered = false;
+%}
+
+method EventTarget::addEventListener()
+%{
+ dom_exception exc;
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, false) && priv->is_node) {
+ /* Take a moment to register a JS callback */
+ duk_size_t ev_ty_l;
+ const char *ev_ty = duk_to_lstring(ctx, -3, &ev_ty_l);
+ dom_string *ev_ty_s;
+ exc = dom_string_create((const uint8_t*)ev_ty, ev_ty_l,
+ &ev_ty_s);
+ if (exc != DOM_NO_ERR) {
+ LOG("Oh dear, failed to create dom_string in addEventListener()");
+ return 0;
+ }
+ dukky_register_event_listener_for(
+ ctx, (dom_element *)((node_private_t *)priv)->node,
+ ev_ty_s,
+ !!(flags & ELF_CAPTURE));
+ dom_string_unref(ev_ty_s);
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_register_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+method EventTarget::removeEventListener()
+%{
+ event_listener_flags flags = ELF_NONE;
+ /* Incoming stack is: type callback [options] */
+ if (duk_get_top(ctx) < 2) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) > 3) return 0; /* Bad arguments */
+ if (duk_get_top(ctx) == 2) {
+ duk_push_object(ctx);
+ /* type callback options */
+ }
+ if (duk_get_type(ctx, -1) != DUK_TYPE_OBJECT) {
+ /* legacy support, if not object, it's the capture value */
+ duk_push_object(ctx);
+ /* ... capture options */
+ duk_insert(ctx, -2);
+ /* ... options capture */
+ duk_put_prop_string(ctx, -2, "capture");
+ /* ... options */
+ }
+ /* type callback options */
+ flags = event_listener_pop_options(ctx);
+ /* type callback */
+ duk_dup(ctx, -2);
+ /* type callback type */
+ duk_push_this(ctx);
+ /* type callback type this(=EventTarget) */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* nothing to do because the listener wasn't there at all */
+ duk_pop_3(ctx);
+ return 0;
+ }
+ /* type callback typelisteners */
+ duk_insert(ctx, -2);
+ /* type typelisteners callback */
+ event_target_unregister_listener(ctx, flags);
+ /* type */
+ return 0;
+%}
+
+
+
+method EventTarget::dispatchEvent()
+%{
+ dom_exception exc;
+ if (!dukky_instanceof(ctx, 0, PROTO_NAME(EVENT))) return 0;
+
+ duk_get_prop_string(ctx, 0, PRIVATE_MAGIC);
+ event_private_t *evpriv = duk_get_pointer(ctx, -1);
+ duk_pop(ctx);
+
+ dom_event *evt = evpriv->evt;
+
+ /* Dispatch event logic, see:
+ *
https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent
+ */
+ bool in_dispatch;
+ if (dom_event_in_dispatch(evt, &in_dispatch) != DOM_NO_ERR) return 0;
+ if (in_dispatch) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ bool is_initialised;
+ if (dom_event_is_initialised(evt, &is_initialised) != DOM_NO_ERR) return 0;
+ if (is_initialised == false) {
+ /** \todo Raise InvalidStateException */
+ return 0;
+ }
+
+ if (dom_event_set_is_trusted(evt, false) != DOM_NO_ERR) return 0;
+
+ /** \todo work out how to dispatch against non-node things */
+ if (priv->is_node == false) return 0;
+
+ bool success;
+ /* Event prepared, dispatch against ourselves */
+ exc = dom_event_target_dispatch_event(
+ ((node_private_t *)priv)->node,
+ evt,
+ &success);
+ if (exc != DOM_NO_ERR) return 0; /**< \todo raise correct exception */
+
+ duk_push_boolean(ctx, success);
+ return 1;
+%}
diff --git a/content/handlers/javascript/duktape/Node.bnd
b/content/handlers/javascript/duktape/Node.bnd
index f237c87..f14cfc1 100644
--- a/content/handlers/javascript/duktape/Node.bnd
+++ b/content/handlers/javascript/duktape/Node.bnd
@@ -16,6 +16,7 @@ init Node(struct dom_node *node)
%{
priv->node = node;
dom_node_ref(node);
+ priv->parent.is_node = true;
%}
fini Node()
diff --git a/content/handlers/javascript/duktape/dukky.c
b/content/handlers/javascript/duktape/dukky.c
index 7dd3bd7..4a6b9c3 100644
--- a/content/handlers/javascript/duktape/dukky.c
+++ b/content/handlers/javascript/duktape/dukky.c
@@ -23,16 +23,15 @@
* Duktapeish implementation of javascript engine functions.
*/
-#include <inttypes.h>
-
+#include <stdint.h>
#include <nsutils/time.h>
-#include "content/content.h"
-
+#include "netsurf/inttypes.h"
#include "utils/utils.h"
#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/corestrings.h"
+#include "content/content.h"
#include "javascript/js.h"
#include "javascript/content.h"
@@ -47,6 +46,7 @@
#define EVENT_MAGIC MAGIC(EVENT_MAP)
#define HANDLER_LISTENER_MAGIC MAGIC(HANDLER_LISTENER_MAP)
#define HANDLER_MAGIC MAGIC(HANDLER_MAP)
+#define EVENT_LISTENER_JS_MAGIC MAGIC(EVENT_LISTENER_JS_MAP)
static duk_ret_t dukky_populate_object(duk_context *ctx)
{
@@ -810,6 +810,8 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_exception exc;
dom_event_target *targ;
dom_event_flow_phase phase;
+ duk_uarridx_t idx;
+ event_listener_flags flags;
/* Retrieve the JS context from the Duktape context */
duk_get_memory_functions(ctx, &funcs);
@@ -841,6 +843,12 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
return;
}
+ /* If we're capturing right now, we skip the 'event handler'
+ * and go straight to the extras
+ */
+ if (phase == DOM_CAPTURING_PHASE)
+ goto handle_extras;
+
/* ... */
if (dukky_push_node(ctx, (dom_node *)targ) == false) {
dom_string_unref(name);
@@ -851,13 +859,9 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
/* ... node */
if (dukky_get_current_value_of_event_handler(
ctx, name, (dom_event_target *)targ) == false) {
- dom_node_unref(targ);
- dom_string_unref(name);
- return;
+ /* ... */
+ goto handle_extras;
}
- /** @todo handle other kinds of event than the generic case */
- dom_node_unref(targ);
- dom_string_unref(name);
/* ... handler node */
dukky_push_event(ctx, evt);
/* ... handler node event */
@@ -883,7 +887,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
duk_pop_n(ctx, 6);
/* ... */
- return;
+ goto handle_extras;
}
/* ... result */
if (duk_is_boolean(ctx, -1) &&
@@ -891,12 +895,113 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw)
dom_event_prevent_default(evt);
}
duk_pop(ctx);
+handle_extras:
/* ... */
+ duk_push_lstring(ctx, dom_string_data(name), dom_string_length(name));
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... type node */
+ if (dukky_event_target_push_listeners(ctx, true)) {
+ /* Nothing to do */
+ duk_pop(ctx);
+ goto out;
+ }
+ /* ... sublisteners */
+ duk_push_array(ctx);
+ /* ... sublisteners copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -2, idx)) {
+ /* ... sublisteners copy handler */
+ duk_get_prop_index(ctx, -1, 1);
+ /* ... sublisteners copy handler flags */
+ if ((event_listener_flags)duk_to_int(ctx, -1) & ELF_ONCE) {
+ duk_dup(ctx, -4);
+ /* ... subl copy handler flags subl */
+ dukky_shuffle_array(ctx, idx);
+ duk_pop(ctx);
+ /* ... subl copy handler flags */
+ }
+ duk_pop(ctx);
+ /* ... sublisteners copy handler */
+ duk_put_prop_index(ctx, -2, idx);
+ /* ... sublisteners copy */
+ idx++;
+ }
+ /* ... sublisteners copy undefined */
+ duk_pop(ctx);
+ /* ... sublisteners copy */
+ duk_insert(ctx, -2);
+ /* ... copy sublisteners */
+ duk_pop(ctx);
+ /* ... copy */
+ idx = 0;
+ while (duk_get_prop_index(ctx, -1, idx++)) {
+ /* ... copy handler */
+ if (duk_get_prop_index(ctx, -1, 2)) {
+ /* ... copy handler meh */
+ duk_pop_2(ctx);
+ continue;
+ }
+ duk_pop(ctx);
+ duk_get_prop_index(ctx, -1, 0);
+ duk_get_prop_index(ctx, -2, 1);
+ /* ... copy handler callback flags */
+ flags = (event_listener_flags)duk_get_int(ctx, -1);
+ duk_pop(ctx);
+ /* ... copy handler callback */
+ if (((phase == DOM_CAPTURING_PHASE) && !(flags & ELF_CAPTURE)) ||
+ ((phase != DOM_CAPTURING_PHASE) && (flags & ELF_CAPTURE))) {
+ duk_pop_2(ctx);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler callback */
+ dukky_push_node(ctx, (dom_node *)targ);
+ /* ... copy handler callback node */
+ dukky_push_event(ctx, evt);
+ /* ... copy handler callback node event */
+ (void) nsu_getmonotonic_ms(&jsctx->exec_start_time);
+ if (duk_pcall_method(ctx, 1) != 0) {
+ /* Failed to run the method */
+ /* ... copy handler err */
+ LOG("OH NOES! An error running a callback. Meh.");
+ exc = dom_event_stop_immediate_propagation(evt);
+ if (exc != DOM_NO_ERR)
+ LOG("WORSE! could not stop propagation");
+ duk_get_prop_string(ctx, -1, "name");
+ duk_get_prop_string(ctx, -2, "message");
+ duk_get_prop_string(ctx, -3, "fileName");
+ duk_get_prop_string(ctx, -4, "lineNumber");
+ duk_get_prop_string(ctx, -5, "stack");
+ /* ... err name message fileName lineNumber stack */
+ LOG("Uncaught error in JS: %s: %s", duk_safe_to_string(ctx, -5),
+ duk_safe_to_string(ctx, -4));
+ LOG(" was at: %s line %s", duk_safe_to_string(ctx, -3),
+ duk_safe_to_string(ctx, -2));
+ LOG(" Stack trace: %s", duk_safe_to_string(ctx, -1));
+
+ duk_pop_n(ctx, 7);
+ /* ... copy */
+ continue;
+ }
+ /* ... copy handler result */
+ if (duk_is_boolean(ctx, -1) &&
+ duk_to_boolean(ctx, -1) == 0) {
+ dom_event_prevent_default(evt);
+ }
+ duk_pop_2(ctx);
+ /* ... copy */
+ }
+ duk_pop_2(ctx);
+out:
+ /* ... */
+ dom_node_unref(targ);
+ dom_string_unref(name);
}
void dukky_register_event_listener_for(duk_context *ctx,
struct dom_element *ele,
- dom_string *name)
+ dom_string *name,
+ bool capture)
{
dom_event_listener *listen = NULL;
dom_exception exc;
@@ -928,7 +1033,7 @@ void dukky_register_event_listener_for(duk_context *ctx,
&listen);
if (exc != DOM_NO_ERR) return;
exc = dom_event_target_add_event_listener(
- ele, name, listen, false);
+ ele, name, listen, capture);
if (exc != DOM_NO_ERR) {
LOG("Unable to register listener for %p.%*s",
ele, dom_string_length(name), dom_string_data(name));
@@ -939,6 +1044,71 @@ void dukky_register_event_listener_for(duk_context *ctx,
dom_event_listener_unref(listen);
}
+/* The sub-listeners are a list of {callback,flags} tuples */
+/* We return true if we created a new sublistener table */
+/* If we're told to not create, but we want to, we still return true */
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create)
+{
+ bool ret = false;
+ /* ... type this */
+ duk_get_prop_string(ctx, -1, EVENT_LISTENER_JS_MAGIC);
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... type this null */
+ duk_pop(ctx);
+ duk_push_object(ctx);
+ duk_dup(ctx, -1);
+ /* ... type this listeners listeners */
+ duk_put_prop_string(ctx, -3, EVENT_LISTENER_JS_MAGIC);
+ /* ... type this listeners */
+ }
+ /* ... type this listeners */
+ duk_insert(ctx, -3);
+ /* ... listeners type this */
+ duk_pop(ctx);
+ /* ... listeners type */
+ duk_dup(ctx, -1);
+ /* ... listeners type type */
+ duk_get_prop(ctx, -3);
+ /* ... listeners type ??? */
+ if (duk_is_undefined(ctx, -1)) {
+ /* ... listeners type ??? */
+ if (dont_create == true) {
+ duk_pop_3(ctx);
+ duk_push_undefined(ctx);
+ return true;
+ }
+ duk_pop(ctx);
+ duk_push_array(ctx);
+ duk_dup(ctx, -2);
+ duk_dup(ctx, -2);
+ /* ... listeners type sublisteners type sublisteners */
+ duk_put_prop(ctx, -5);
+ /* ... listeners type sublisteners */
+ ret = true;
+ }
+ duk_insert(ctx, -3);
+ /* ... sublisteners listeners type */
+ duk_pop_2(ctx);
+ /* ... sublisteners */
+ return ret;
+}
+
+/* Shuffle a duktape array "down" one. This involves iterating from
+ * the index provided, shuffling elements down, until we reach an
+ * undefined
+ */
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx)
+{
+ /* ... somearr */
+ while (duk_get_prop_index(ctx, -1, idx + 1)) {
+ duk_put_prop_index(ctx, -2, idx);
+ idx++;
+ }
+ /* ... somearr undefined */
+ duk_del_prop_index(ctx, -2, idx + 1);
+ duk_pop(ctx);
+}
+
void js_handle_new_element(jscontext *ctx, struct dom_element *node)
{
@@ -996,7 +1166,7 @@ void js_handle_new_element(jscontext *ctx, struct dom_element *node)
&sub);
if (exc == DOM_NO_ERR) {
dukky_register_event_listener_for(
- CTX, node, sub);
+ CTX, node, sub, false);
dom_string_unref(sub);
}
}
diff --git a/content/handlers/javascript/duktape/dukky.h
b/content/handlers/javascript/duktape/dukky.h
index 0c3ff0e..b5809aa 100644
--- a/content/handlers/javascript/duktape/dukky.h
+++ b/content/handlers/javascript/duktape/dukky.h
@@ -37,9 +37,20 @@ duk_bool_t dukky_push_node(duk_context *ctx, struct dom_node *node);
void dukky_inject_not_ctr(duk_context *ctx, int idx, const char *name);
void dukky_register_event_listener_for(duk_context *ctx,
struct dom_element *ele,
- dom_string *name);
+ dom_string *name,
+ bool capture);
bool dukky_get_current_value_of_event_handler(duk_context *ctx,
dom_string *name,
dom_event_target *et);
+bool dukky_event_target_push_listeners(duk_context *ctx, bool dont_create);
+
+typedef enum {
+ ELF_CAPTURE = 1 << 0,
+ ELF_PASSIVE = 1 << 1,
+ ELF_ONCE = 1 << 2,
+ ELF_NONE = 0
+} event_listener_flags;
+
+void dukky_shuffle_array(duk_context *ctx, duk_uarridx_t idx);
#endif
diff --git a/content/handlers/javascript/duktape/netsurf.bnd
b/content/handlers/javascript/duktape/netsurf.bnd
index 4aca475..2a56ccc 100644
--- a/content/handlers/javascript/duktape/netsurf.bnd
+++ b/content/handlers/javascript/duktape/netsurf.bnd
@@ -54,6 +54,7 @@ struct dom_html_br_element;
};
+#include "EventTarget.bnd"
#include "Console.bnd"
#include "Window.bnd"
#include "Document.bnd"
diff --git a/content/llcache.c b/content/llcache.c
index 4bd6eb3..eb30053 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -35,12 +35,10 @@
#include <stdint.h>
#include <string.h>
#include <strings.h>
-#include <inttypes.h>
-
#include <nsutils/time.h>
+#include "netsurf/inttypes.h"
#include "utils/config.h"
-
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/messages.h"
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
index 4a14737..0f597aa 100644
--- a/desktop/netsurf.c
+++ b/desktop/netsurf.c
@@ -25,12 +25,12 @@
#include <stdlib.h>
#include <libwapcaplet/libwapcaplet.h>
+#include "netsurf/inttypes.h"
#include "utils/config.h"
#include "utils/nsoption.h"
#include "utils/corestrings.h"
#include "utils/log.h"
#include "utils/utf8.h"
-#include "utils/utils.h"
#include "utils/messages.h"
#include "content/content_factory.h"
#include "content/fetchers.h"
diff --git a/desktop/textarea.h b/desktop/textarea.h
index 19162ff..65e2594 100644
--- a/desktop/textarea.h
+++ b/desktop/textarea.h
@@ -27,7 +27,6 @@
#include <stdint.h>
#include <stdbool.h>
-#include "utils/utils.h"
#include "netsurf/plot_style.h"
#include "netsurf/mouse.h"
diff --git a/desktop/treeview.c b/desktop/treeview.c
index 1d0ac52..4d8fbaa 100644
--- a/desktop/treeview.c
+++ b/desktop/treeview.c
@@ -22,6 +22,7 @@
* Treeview handling implementation.
*/
+#include "utils/utils.h"
#include "utils/log.h"
#include "utils/nsurl.h"
#include "utils/nsoption.h"
diff --git a/frontends/amiga/Makefile b/frontends/amiga/Makefile
index 985a085..f57b4ef 100644
--- a/frontends/amiga/Makefile
+++ b/frontends/amiga/Makefile
@@ -46,7 +46,7 @@ S_FRONTEND := gui.c history.c hotlist.c schedule.c file.c \
stringview/stringview.c stringview/urlhistory.c rtg.c \
agclass/amigaguide_class.c os3support.c font_diskfont.c \
selectmenu.c hash/xxhash.c font_cache.c font_bullet.c \
- nsoption.c corewindow.c
+ nsoption.c corewindow.c gui_menu.c
# This is the final source build list
# Note this is deliberately *not* expanded here as common and image
diff --git a/frontends/amiga/clipboard.c b/frontends/amiga/clipboard.c
index 9489110..27b8015 100644
--- a/frontends/amiga/clipboard.c
+++ b/frontends/amiga/clipboard.c
@@ -44,7 +44,7 @@
#include "amiga/gui.h"
#include "amiga/iff_cset.h"
#include "amiga/iff_dr2d.h"
-#include "amiga/menu.h"
+#include "amiga/gui_menu.h"
#include "amiga/utf8.h"
#define ID_UTF8 MAKE_ID('U','T','F','8')
@@ -89,11 +89,11 @@ void gui_start_selection(struct gui_window *g)
if(!g->shared->win) return;
if(nsoption_bool(kiosk_mode) == true) return;
- OnMenu(g->shared->win, AMI_MENU_CLEAR);
- OnMenu(g->shared->win, AMI_MENU_COPY);
+ ami_gui_menu_set_disabled(g->shared->win, g->shared->imenu, M_COPY, false);
+ ami_gui_menu_set_disabled(g->shared->win, g->shared->imenu, M_CLEAR,
false);
if (browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_CUT)
- OnMenu(g->shared->win, AMI_MENU_CUT);
+ ami_gui_menu_set_disabled(g->shared->win, g->shared->imenu, M_CUT, false);
}
static char *ami_clipboard_cat_collection(struct CollectionItem *ci, LONG codeset, size_t
*text_length)
diff --git a/frontends/amiga/cookies.c b/frontends/amiga/cookies.c
index 74c89cb..877805c 100644
--- a/frontends/amiga/cookies.c
+++ b/frontends/amiga/cookies.c
@@ -43,6 +43,7 @@
#include "amiga/cookies.h"
#include "amiga/corewindow.h"
#include "amiga/libs.h"
+#include "amiga/menu.h"
#include "amiga/utf8.h"
enum {
@@ -239,38 +240,38 @@ HOOKF(void, ami_cookies_menu_item_edit_delete, APTR, window, struct
IntuiMessage
static void ami_cookies_menulabs(struct ami_menu_data **md)
{
- ami_menu_alloc_item(md, AMI_COOKIE_M_PROJECT, NM_TITLE, "Tree", 0, NULL,
NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND, NM_ITEM, "Expand", 0,
"TBImages:list_folderunfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_ALL, NM_SUB, "All", '+',
NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_PROJECT, NM_TITLE, "Tree", NULL, NULL,
NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND, NM_ITEM, "Expand", NULL,
"TBImages:list_folderunfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_ALL, NM_SUB, "All",
"+", NULL,
ami_cookies_menu_item_project_expand_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_DOMAINS, NM_SUB, "Domains", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_DOMAINS, NM_SUB, "Domains",
NULL, NULL,
ami_cookies_menu_item_project_expand_domains, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_COOKIES, NM_SUB, "Cookies", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_EXPAND_COOKIES, NM_SUB, "Cookies",
NULL, NULL,
ami_cookies_menu_item_project_expand_cookies, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE, NM_ITEM, "Collapse", 0,
"TBImages:list_folderfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_ALL, NM_SUB, "All",
'-', NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE, NM_ITEM, "Collapse", NULL,
"TBImages:list_folderfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_ALL, NM_SUB, "All",
"-", NULL,
ami_cookies_menu_item_project_collapse_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_DOMAINS, NM_SUB, "Domains", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_DOMAINS, NM_SUB, "Domains",
NULL, NULL,
ami_cookies_menu_item_project_collapse_domains, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_COOKIES, NM_SUB, "Cookies", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_COLLAPSE_COOKIES, NM_SUB, "Cookies",
NULL, NULL,
ami_cookies_menu_item_project_collapse_cookies, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_P1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_SNAPSHOT, NM_ITEM, "SnapshotWindow", 0,
"TBImages:list_hold",
+ ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_P1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_SNAPSHOT, NM_ITEM, "SnapshotWindow",
NULL, "TBImages:list_hold",
ami_cookies_menu_item_project_snapshot, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_P2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_CLOSE, NM_ITEM, "CloseWindow",
'K', "TBImages:list_cancel",
+ ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_P2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_CLOSE, NM_ITEM, "CloseWindow",
"K", "TBImages:list_cancel",
ami_cookies_menu_item_project_close, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_EDIT, NM_TITLE, "Edit", 0, NULL,
NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_SELECTALL, NM_ITEM, "SelectAllNS",
'A', NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_EDIT, NM_TITLE, "Edit", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_SELECTALL, NM_ITEM, "SelectAllNS",
"A", NSA_SPACE,
ami_cookies_menu_item_edit_select_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_CLEAR, NM_ITEM, "ClearNS", 0,
NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_COOKIE_M_CLEAR, NM_ITEM, "ClearNS", NULL,
NSA_SPACE,
ami_cookies_menu_item_edit_clear, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_E1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_DELETE, NM_ITEM, "TreeDelete", 0,
"TBImages:list_delete",
+ ami_menu_alloc_item(md, AMI_COOKIE_M_BAR_E1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_DELETE, NM_ITEM, "TreeDelete",
"Del", "TBImages:list_delete",
ami_cookies_menu_item_edit_delete, NULL, 0);
- ami_menu_alloc_item(md, AMI_COOKIE_M_LAST, NM_END, NULL, 0, NULL, NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_COOKIE_M_LAST, NM_END, NULL, NULL, NULL, NULL, NULL, 0);
}
static struct Menu *
diff --git a/frontends/amiga/dist/NetSurf.guide b/frontends/amiga/dist/NetSurf.guide
index 754cdbe..512a264 100755
--- a/frontends/amiga/dist/NetSurf.guide
+++ b/frontends/amiga/dist/NetSurf.guide
@@ -285,11 +285,11 @@ Items from the hotlist can be added to the Hotlist menu as follows:
Select Hotlist => Show hotlist...
-Items in the "Hotlist menu" folder node, up to a maximum (currently) of 40
items, will be added to the Hotlist menu, within the limits of the Intuition menu system.
+Items in the "Hotlist menu" folder node, up to a maximum (currently) of 200
items, will be added to the Hotlist menu, within the limits of the Intuition menu system.
Items in folders within the Menu folder node will be converted to subitems in the menu.
-Folders more than one level down in the heirarchy will become menu items with no action.
Items deeper will not be included in the menu at all (until we switch to using
menuclass).
+When using a version of AmigaOS older than OS4.1FE, folders more than one level down in
the heirarchy will become menu items with no action. Items deeper will not be included in
the menu at all.
Folders with no items in them will show up disabled in the menu. If they are named
"--" they will be displayed as separator bars.
diff --git a/frontends/amiga/gui.c b/frontends/amiga/gui.c
index 6627e87..b2a489e 100644
--- a/frontends/amiga/gui.c
+++ b/frontends/amiga/gui.c
@@ -1206,16 +1206,12 @@ static void ami_update_buttons(struct gui_window_2 *gwin)
if(!browser_window_reload_available(gwin->gw->bw))
reload=TRUE;
- if(nsoption_bool(kiosk_mode) == false)
- {
- if(gwin->tabs <= 1)
- {
+ if(nsoption_bool(kiosk_mode) == false) {
+ if(gwin->tabs <= 1) {
tabclose=TRUE;
- OffMenu(gwin->win,AMI_MENU_CLOSETAB);
- }
- else
- {
- OnMenu(gwin->win,AMI_MENU_CLOSETAB);
+ ami_gui_menu_set_disabled(gwin->win, gwin->imenu, M_CLOSETAB, true);
+ } else {
+ ami_gui_menu_set_disabled(gwin->win, gwin->imenu, M_CLOSETAB, false);
}
}
@@ -1641,7 +1637,7 @@ static void ami_gui_menu_update_all(void)
if(node->Type == AMINS_WINDOW)
{
- ami_menu_update_checked(gwin);
+ ami_gui_menu_update_checked(gwin);
}
} while((node = nnode));
}
@@ -1968,11 +1964,11 @@ static BOOL ami_handle_msg(void)
}
} while((node = nnode));
- if(ami_menu_quit_selected() == true) {
+ if(ami_gui_menu_quit_selected() == true) {
ami_quit_netsurf();
}
- if(ami_menu_get_check_toggled() == true) {
+ if(ami_gui_menu_get_check_toggled() == true) {
ami_gui_menu_update_all();
}
@@ -2907,7 +2903,7 @@ void ami_switch_tab(struct gui_window_2 *gwin, bool redraw)
ami_plot_release_pens(gwin->shared_pens);
ami_update_buttons(gwin);
- ami_menu_update_disabled(gwin->gw, browser_window_get_content(gwin->gw->bw));
+ ami_gui_menu_update_disabled(gwin->gw,
browser_window_get_content(gwin->gw->bw));
if(redraw)
{
@@ -3331,16 +3327,16 @@ void ami_gui_hotlist_update_all(void)
if(IsMinListEmpty(window_list)) return;
+ ami_gui_menu_refresh_hotlist();
+
node = (struct nsObject *)GetHead((struct List *)window_list);
do {
nnode=(struct nsObject *)GetSucc((struct Node *)node);
gwin = node->objstruct;
- if(node->Type == AMINS_WINDOW)
- {
+ if(node->Type == AMINS_WINDOW) {
ami_gui_hotlist_toolbar_update(gwin);
- ami_menu_refresh(gwin);
}
} while((node = nnode));
}
@@ -3989,7 +3985,7 @@ gui_window_create(struct browser_window *bw,
iconifygadget = TRUE;
LOG("Creating menu");
- struct Menu *menu = ami_menu_create(g->shared);
+ struct Menu *menu = ami_gui_menu_create(g->shared);
NewList(&g->shared->tab_list);
g->tab_node = AllocClickTabNode(TNA_Text,messages_get("NetSurf"),
@@ -4607,8 +4603,7 @@ static void gui_window_destroy(struct gui_window *g)
DisposeObject((Object *)g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_BACK]);
DisposeObject((Object *)g->shared->history_ctxmenu[AMI_CTXMENU_HISTORY_FORWARD]);
ami_ctxmenu_release_hook(g->shared->ctxmenu_hook);
- ami_free_menulabs(g->shared->menu_data);
- ami_menu_free(g->shared);
+ ami_gui_menu_free(g->shared);
free(g->shared->wintitle);
ami_utf8_free(g->shared->status);
@@ -5262,7 +5257,7 @@ static void gui_window_place_caret(struct gui_window *g, int x, int
y, int heigh
g->c_h = height;
if((nsoption_bool(kiosk_mode) == false))
- OnMenu(g->shared->win, AMI_MENU_PASTE);
+ ami_gui_menu_set_disabled(g->shared->win, g->shared->imenu, M_PASTE,
false);
}
static void gui_window_remove_caret(struct gui_window *g)
@@ -5271,7 +5266,7 @@ static void gui_window_remove_caret(struct gui_window *g)
if(g->c_h == 0) return;
if((nsoption_bool(kiosk_mode) == false))
- OffMenu(g->shared->win, AMI_MENU_PASTE);
+ ami_gui_menu_set_disabled(g->shared->win, g->shared->imenu, M_PASTE,
true);
ami_do_redraw_limits(g, g->bw, false, g->c_x, g->c_y,
g->c_x + g->c_w + 1, g->c_y + g->c_h + 1);
@@ -5295,7 +5290,7 @@ static void gui_window_new_content(struct gui_window *g)
g->shared->oldv = 0;
g->favicon = NULL;
ami_plot_release_pens(g->shared->shared_pens);
- ami_menu_update_disabled(g, c);
+ ami_gui_menu_update_disabled(g, c);
ami_gui_update_hotlist_button(g->shared);
ami_gui_scroller_update(g->shared);
}
diff --git a/frontends/amiga/gui.h b/frontends/amiga/gui.h
index a176df1..07ff922 100644
--- a/frontends/amiga/gui.h
+++ b/frontends/amiga/gui.h
@@ -28,7 +28,7 @@
#include "netsurf/window.h"
#include "netsurf/mouse.h"
-#include "amiga/menu.h"
+#include "amiga/gui_menu.h"
#include "amiga/object.h"
#include "amiga/os3support.h"
@@ -134,7 +134,7 @@ struct gui_window_2 {
int temp;
bool redraw_scroll;
bool new_content;
- struct ami_menu_data *menu_data[AMI_MENU_AREXX_MAX + 1];
+ struct ami_menu_data *menu_data[AMI_MENU_AREXX_MAX + 1]; /* only for GadTools menus */
ULONG hotlist_items;
Object *restrict hotlist_toolbar_lab[AMI_GUI_TOOLBAR_MAX];
struct List hotlist_toolbar_list;
diff --git a/frontends/amiga/menu.c b/frontends/amiga/gui_menu.c
similarity index 54%
copy from frontends/amiga/menu.c
copy to frontends/amiga/gui_menu.c
index c354fef..6b9b207 100644
--- a/frontends/amiga/menu.c
+++ b/frontends/amiga/gui_menu.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-9, 2013, 2017 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2017 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf,
http://www.netsurf-browser.org/
*
@@ -33,6 +33,9 @@
#endif
#include <libraries/gadtools.h>
+#ifdef __amigaos4__
+#include <intuition/menuclass.h>
+#endif
#include <classes/window.h>
#include <proto/label.h>
@@ -62,6 +65,7 @@
#include "amiga/file.h"
#include "amiga/filetype.h"
#include "amiga/gui.h"
+#include "amiga/gui_menu.h"
#include "amiga/gui_options.h"
#include "amiga/history.h"
#include "amiga/history_local.h"
@@ -76,31 +80,14 @@
#include "amiga/utf8.h"
#include "amiga/schedule.h"
-#define NSA_MAX_HOTLIST_MENU_LEN 100
-
-enum {
- NSA_GLYPH_SUBMENU,
- NSA_GLYPH_AMIGAKEY,
- NSA_GLYPH_CHECKMARK,
- NSA_GLYPH_MX,
- NSA_GLYPH_MAX
-};
-
-struct ami_menu_data {
- char *restrict menulab;
- Object *restrict menuobj;
- char menukey;
- char *restrict menuicon;
- struct Hook menu_hook;
- UBYTE menutype;
- UWORD flags;
-};
+#ifdef __amigaos4__
+static struct Menu *restrict gui_menu = NULL;
+static int gui_menu_count = 0;
+struct ami_menu_data *gui_menu_data[AMI_MENU_AREXX_MAX + 1];
+#endif
-static bool menu_quit = false;
static bool ami_menu_check_toggled = false;
-static Object *restrict menu_glyph[NSA_GLYPH_MAX];
-static int menu_glyph_width[NSA_GLYPH_MAX];
-static bool menu_glyphs_loaded = false;
+static bool menu_quit = false;
const char * const netsurf_version;
const char * const verdate;
@@ -108,23 +95,6 @@ const char * const verdate;
static nserror ami_menu_scan(struct ami_menu_data **md);
void ami_menu_arexx_scan(struct ami_menu_data **md);
-void ami_menu_set_check_toggled(void)
-{
- ami_menu_check_toggled = true;
-}
-
-bool ami_menu_get_check_toggled(void)
-{
- bool check_toggled = ami_menu_check_toggled;
- ami_menu_check_toggled = false;
- return check_toggled;
-}
-
-bool ami_menu_quit_selected(void)
-{
- return menu_quit;
-}
-
/*
* The below functions are called automatically by window.class when menu items are
selected.
*/
@@ -375,10 +345,10 @@ HOOKF(void, ami_menu_item_browser_foreimg, APTR, window, struct
IntuiMessage *)
bool checked = false;
GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
-
+ checked = ami_menu_get_selected(menustrip, msg);
+
nsoption_set_bool(foreground_images, checked);
- ami_menu_set_check_toggled();
+ ami_gui_menu_set_check_toggled();
}
HOOKF(void, ami_menu_item_browser_backimg, APTR, window, struct IntuiMessage *)
@@ -387,10 +357,10 @@ HOOKF(void, ami_menu_item_browser_backimg, APTR, window, struct
IntuiMessage *)
bool checked = false;
GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
+ checked = ami_menu_get_selected(menustrip, msg);
nsoption_set_bool(background_images, checked);
- ami_menu_set_check_toggled();
+ ami_gui_menu_set_check_toggled();
}
HOOKF(void, ami_menu_item_browser_enablejs, APTR, window, struct IntuiMessage *)
@@ -399,10 +369,10 @@ HOOKF(void, ami_menu_item_browser_enablejs, APTR, window, struct
IntuiMessage *)
bool checked = false;
GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
+ checked = ami_menu_get_selected(menustrip, msg);
nsoption_set_bool(enable_javascript, checked);
- ami_menu_set_check_toggled();
+ ami_gui_menu_set_check_toggled();
}
HOOKF(void, ami_menu_item_browser_scale_decrease, APTR, window, struct IntuiMessage *)
@@ -541,461 +511,296 @@ HOOKF(void, ami_menu_item_arexx_entries, APTR, window, struct
IntuiMessage *)
}
}
+/* normal GUI-specific menu functions */
-/* menu creation code */
-static void ami_menu_free_labs(struct ami_menu_data **md, int max)
+ULONG ami_gui_menu_number(int item)
{
- int i;
+ /* horrible, horrible, horrible */
+ ULONG menu_num;
- for(i = 0; i <= max; i++) {
- if(md[i] == NULL) continue;
- if(md[i]->menulab && (md[i]->menulab != NM_BARLABEL)) {
- if(md[i]->menutype & MENU_IMAGE) {
- if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
- }
-
- ami_utf8_free(md[i]->menulab);
- }
+ switch(item) {
+ case M_SAVETXT:
+ menu_num = FULLMENUNUM(0,4,1);
+ break;
- md[i]->menulab = NULL;
- md[i]->menuobj = NULL;
- md[i]->menukey = 0;
- md[i]->menutype = 0;
- free(md[i]);
- }
-}
+ case M_SAVECOMP:
+ menu_num = FULLMENUNUM(0,4,2);
+ break;
-void ami_free_menulabs(struct ami_menu_data **md)
-{
- int i;
+ case M_SAVEIFF:
+ menu_num = FULLMENUNUM(0,4,3);
+ break;
+#ifdef WITH_PDF_EXPORT
+ case M_SAVEPDF:
+ menu_num = FULLMENUNUM(0,4,4);
+ break;
+#endif
+ case M_CLOSETAB:
+ menu_num = FULLMENUNUM(0,8,0);
+ break;
- for(i=0;i<=AMI_MENU_AREXX_MAX;i++) {
- if(md[i] == NULL) continue;
- if(md[i]->menulab && (md[i]->menulab != NM_BARLABEL)) {
- if(md[i]->menutype & MENU_IMAGE) {
- if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
- }
+ case M_CUT:
+ menu_num = FULLMENUNUM(1,0,0);
+ break;
- ami_utf8_free(md[i]->menulab);
+ case M_COPY:
+ menu_num = FULLMENUNUM(1,1,0);
+ break;
- if(i >= AMI_MENU_AREXX) {
- if(md[i]->menu_hook.h_Data) free(md[i]->menu_hook.h_Data);
- md[i]->menu_hook.h_Data = NULL;
- }
- }
+ case M_PASTE:
+ menu_num = FULLMENUNUM(1,2,0);
+ break;
- md[i]->menulab = NULL;
- md[i]->menuobj = NULL;
- md[i]->menukey = 0;
- md[i]->menutype = 0;
- free(md[i]);
- }
-}
+ case M_SELALL:
+ menu_num = FULLMENUNUM(1,4,0);
+ break;
-void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE type,
- const char *restrict label, char key, const char *restrict icon,
- void *restrict func, void *restrict hookdata, UWORD flags)
-{
- char menu_icon[1024];
+ case M_CLEAR:
+ menu_num = FULLMENUNUM(1,5,0);
+ break;
- md[num] = calloc(1, sizeof(struct ami_menu_data));
- md[num]->menutype = type;
- md[num]->flags = flags;
-
- if(type == NM_END) return;
-
- if((label == NM_BARLABEL) || (strcmp(label, "--") == 0)) {
- md[num]->menulab = NM_BARLABEL;
- } else { /* horrid non-generic stuff */
- if((num >= AMI_MENU_HOTLIST) && (num <= AMI_MENU_HOTLIST_MAX)) {
- utf8_from_local_encoding(label,
- (strlen(label) < NSA_MAX_HOTLIST_MENU_LEN) ? strlen(label) :
NSA_MAX_HOTLIST_MENU_LEN,
- (char **)&md[num]->menulab);
- } else if((num >= AMI_MENU_AREXX) && (num < AMI_MENU_AREXX_MAX)) {
- md[num]->menulab = strdup(label);
- } else {
- md[num]->menulab = ami_utf8_easy(messages_get(label));
- }
- }
+ case M_UNDO:
+ menu_num = FULLMENUNUM(1,8,0);
+ break;
- md[num]->menuicon = NULL;
- if(key) md[num]->menukey = key;
- if(func) md[num]->menu_hook.h_Entry = (HOOKFUNC)func;
- if(hookdata) md[num]->menu_hook.h_Data = hookdata;
+ case M_REDO:
+ menu_num = FULLMENUNUM(1,9,0);
+ break;
-#ifdef __amigaos4__
- if(LIB_IS_AT_LEAST((struct Library *)GadToolsBase, 53, 7)) {
- if(icon) {
- if(ami_locate_resource(menu_icon, icon) == true) {
- md[num]->menuicon = (char *)strdup(menu_icon);
- } else {
- /* If the requested icon can't be found, put blank space in instead */
- md[num]->menuicon = (char *)strdup(NSA_SPACE);
- }
- }
- }
-#endif
-}
+ case M_FIND:
+ menu_num = FULLMENUNUM(2,0,0);
+ break;
-static void ami_init_menulabs(struct ami_menu_data **md)
-{
- UWORD js_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(enable_javascript) == true)
- js_flags |= CHECKED;
+ case M_IMGFORE:
+ menu_num = FULLMENUNUM(2,8,0);
+ break;
- UWORD imgfore_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(foreground_images) == true)
- imgfore_flags |= CHECKED;
+ case M_IMGBACK:
+ menu_num = FULLMENUNUM(2,8,1);
+ break;
- UWORD imgback_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(background_images) == true)
- imgback_flags |= CHECKED;
+ case M_JS:
+ menu_num = FULLMENUNUM(2,9,0);
+ break;
- ami_menu_alloc_item(md, M_PROJECT, NM_TITLE, "Project", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_NEWWIN, NM_ITEM, "NewWindowNS", 'N',
"TBImages:list_app",
- ami_menu_item_project_newwin, NULL, 0);
- ami_menu_alloc_item(md, M_NEWTAB, NM_ITEM, "NewTab", 'T',
"TBImages:list_tab",
- ami_menu_item_project_newtab, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_OPEN, NM_ITEM, "OpenFile", 'O',
"TBImages:list_folder_misc",
- ami_menu_item_project_open, NULL, 0);
- ami_menu_alloc_item(md, M_SAVEAS, NM_ITEM, "SaveAsNS", 0,
"TBImages:list_saveas", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SAVESRC, NM_SUB, "Source", 'S',
NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_SOURCE, 0);
- ami_menu_alloc_item(md, M_SAVETXT, NM_SUB, "TextNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_TEXT, 0);
- ami_menu_alloc_item(md, M_SAVECOMP, NM_SUB, "SaveCompNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_COMPLETE, 0);
-#ifdef WITH_PDF_EXPORT
- ami_menu_alloc_item(md, M_SAVEPDF, NM_SUB, "PDFNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_PDF, 0);
-#endif
- ami_menu_alloc_item(md, M_SAVEIFF, NM_SUB, "IFF", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_IFF, 0);
- ami_menu_alloc_item(md, M_BAR_P2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_PRINT, NM_ITEM, "PrintNS", 'P',
"TBImages:list_print",
- ami_menu_item_project_print, NULL, NM_ITEMDISABLED);
- ami_menu_alloc_item(md, M_BAR_P3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_CLOSETAB, NM_ITEM, "CloseTab", 'K',
"TBImages:list_remove",
- ami_menu_item_project_closetab, NULL, 0);
- ami_menu_alloc_item(md, M_CLOSEWIN, NM_ITEM, "CloseWindow", 0,
"TBImages:list_cancel",
- ami_menu_item_project_closewin, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P4, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, M_ABOUT, NM_ITEM, "About", '?',
"TBImages:list_info",
- ami_menu_item_project_about, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P5, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, M_QUIT, NM_ITEM, "Quit", 'Q',
"TBImages:list_warning",
- ami_menu_item_project_quit, NULL, 0);
+ default:
+ LOG("WARNING: Unrecognised menu item %d", item);
+ menu_num = 0;
+ break;
+ }
- ami_menu_alloc_item(md, M_EDIT, NM_TITLE, "Edit", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_CUT, NM_ITEM, "CutNS", 'X',
"TBImages:list_cut",
- ami_menu_item_edit_cut, NULL, 0);
- ami_menu_alloc_item(md, M_COPY, NM_ITEM, "CopyNS", 'C',
"TBImages:list_copy",
- ami_menu_item_edit_copy, NULL, 0);
- ami_menu_alloc_item(md, M_PASTE, NM_ITEM, "PasteNS", 'V',
"TBImages:list_paste",
- ami_menu_item_edit_paste, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_E1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SELALL, NM_ITEM, "SelectAllNS", 'A',
NSA_SPACE,
- ami_menu_item_edit_selectall, NULL, 0);
- ami_menu_alloc_item(md, M_CLEAR, NM_ITEM, "ClearNS", 0, NSA_SPACE,
- ami_menu_item_edit_clearsel, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_E2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_UNDO, NM_ITEM, "Undo", 'Z',
"TBImages:list_undo",
- ami_menu_item_edit_undo, NULL, 0);
- ami_menu_alloc_item(md, M_REDO, NM_ITEM, "Redo", 'Y',
"TBImages:list_redo",
- ami_menu_item_edit_redo, NULL, 0);
+ return menu_num;
+}
- ami_menu_alloc_item(md, M_BROWSER, NM_TITLE, "Browser", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_FIND, NM_ITEM, "FindTextNS", 'F',
"TBImages:list_search",
- ami_menu_item_browser_find, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_HISTLOCL, NM_ITEM, "HistLocalNS", 0,
"TBImages:list_history",
- ami_menu_item_browser_localhistory, NULL, 0);
- ami_menu_alloc_item(md, M_HISTGLBL, NM_ITEM, "HistGlobalNS", 0,
"TBImages:list_history",
- ami_menu_item_browser_globalhistory, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_COOKIES, NM_ITEM, "ShowCookiesNS", 0,
"TBImages:list_internet",
- ami_menu_item_browser_cookies, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SCALE, NM_ITEM, "ScaleNS", 0,
"TBImages:list_preview", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SCALEDEC, NM_SUB, "ScaleDec", '-',
"TBImages:list_zoom_out",
- ami_menu_item_browser_scale_decrease, NULL, 0);
- ami_menu_alloc_item(md, M_SCALENRM, NM_SUB, "ScaleNorm", '=',
"TBImages:list_zoom_100",
- ami_menu_item_browser_scale_normal, NULL, 0);
- ami_menu_alloc_item(md, M_SCALEINC, NM_SUB, "ScaleInc", '+',
"TBImages:list_zoom_in",
- ami_menu_item_browser_scale_increase, NULL, 0);
- ami_menu_alloc_item(md, M_IMAGES, NM_ITEM, "Images", 0,
"TBImages:list_image", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_IMGFORE, NM_SUB, "ForeImg", 0, NULL,
- ami_menu_item_browser_foreimg, NULL, imgfore_flags);
- ami_menu_alloc_item(md, M_IMGBACK, NM_SUB, "BackImg", 0, NULL,
- ami_menu_item_browser_backimg, NULL, imgback_flags);
- ami_menu_alloc_item(md, M_JS, NM_ITEM, "EnableJS", 0, NULL,
- ami_menu_item_browser_enablejs, NULL, js_flags);
- ami_menu_alloc_item(md, M_BAR_B4, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_REDRAW, NM_ITEM, "Redraw", 0,
"TBImages:list_wand",
- ami_menu_item_browser_redraw, NULL, 0);
+#ifdef __amigaos4__
+static void ami_gui_menu_set_checked_mc(struct Menu *menu, int item, bool check)
+{
+ ULONG check_state = MS_CHECKED;
- ami_menu_alloc_item(md, M_HOTLIST, NM_TITLE, "Hotlist", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_HLADD, NM_ITEM, "HotlistAdd", 'B',
"TBImages:list_favouriteadd",
- ami_menu_item_hotlist_add, NULL, 0);
- ami_menu_alloc_item(md, M_HLSHOW, NM_ITEM,"HotlistShowNS",'H',
"TBImages:list_favourite",
- ami_menu_item_hotlist_show, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_H1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
+ if(check == false) {
+ check_state = 0;
+ }
- ami_menu_alloc_item(md, M_PREFS, NM_TITLE, "Settings", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_PREDIT, NM_ITEM, "SettingsEdit", 0,
"TBImages:list_prefs",
- ami_menu_item_settings_edit, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_S1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SNAPSHOT, NM_ITEM, "SnapshotWindow",0,
"TBImages:list_hold",
- ami_menu_item_settings_snapshot, NULL, 0);
- ami_menu_alloc_item(md, M_PRSAVE, NM_ITEM, "SettingsSave", 0,
"TBImages:list_use",
- ami_menu_item_settings_save, NULL, 0);
+ if(menu == NULL) {
+ menu = gui_menu;
+ }
- ami_menu_alloc_item(md, M_AREXX, NM_TITLE, "ARexx", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_AREXXEX, NM_ITEM, "ARexxExecute",'E',
"TBImages:list_arexx",
- ami_menu_item_arexx_execute, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_A1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_MENU_AREXX_MAX, NM_END, NULL, 0, NULL, NULL, NULL,
0);
+ IDoMethod((Object *)menu, MM_SETSTATE, 0, item, MS_CHECKED, check_state);
}
+#endif
-/* Menu refresh for hotlist */
-void ami_menu_refresh(struct gui_window_2 *gwin)
+static void ami_gui_menu_set_checked_gt(struct Menu *menu, int item, bool check)
{
- return; /**\todo fix this after migrating to menuclass */
-
- struct Menu *menu;
+ if(menu == NULL) {
+ return;
+ }
- LOG("Clearing MenuStrip");
- SetAttrs(gwin->objects[OID_MAIN],
- WINDOW_MenuStrip, NULL,
- TAG_DONE);
+ if(check == true) {
+ if((ItemAddress(menu, ami_gui_menu_number(item))->Flags & CHECKED) == 0)
+ ItemAddress(menu, ami_gui_menu_number(item))->Flags ^= CHECKED;
+ } else {
+ if(ItemAddress(menu, ami_gui_menu_number(item))->Flags & CHECKED)
+ ItemAddress(menu, ami_gui_menu_number(item))->Flags ^= CHECKED;
+ }
+}
- LOG("Freeing menu");
- ami_menu_free(gwin);
+void ami_gui_menu_set_checked(struct Menu *menu, int item, bool check)
+{
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+#ifdef __amigaos4__
+ return ami_gui_menu_set_checked_mc(menu, item, check);
+#endif
+ } else {
+ return ami_gui_menu_set_checked_gt(menu, item, check);
+ }
+}
- LOG("Freeing menu labels");
- ami_free_menulabs(gwin->menu_data);
+#ifdef __amigaos4__
+static void ami_gui_menu_set_disabled_mc(struct Window *win, struct Menu *menu, int item,
bool disable)
+{
+ ULONG disable_state = MS_DISABLED;
- LOG("Creating new menu");
- menu = ami_menu_create(gwin);
+ if(disable == false) {
+ disable_state = 0;
+ }
- LOG("Attaching MenuStrip %p to %p", menu, gwin->objects[OID_MAIN]);
- SetAttrs(gwin->objects[OID_MAIN],
- WINDOW_MenuStrip, menu,
- TAG_DONE);
+ IDoMethod((Object *)menu, MM_SETSTATE, 0, item, MS_DISABLED, disable_state);
}
+#endif
-static void ami_menu_load_glyphs(struct DrawInfo *dri)
+static void ami_gui_menu_set_disabled_gt(struct Window *win, struct Menu *menu, int item,
bool disable)
{
-#ifdef __amigaos4__
- if(LIB_IS_AT_LEAST((struct Library *)GadToolsBase, 53, 7)) {
- for(int i = 0; i < NSA_GLYPH_MAX; i++)
- menu_glyph[i] = NULL;
-
- menu_glyph[NSA_GLYPH_SUBMENU] = NewObject(NULL, "sysiclass",
- SYSIA_Which, MENUSUB,
- SYSIA_DrawInfo, dri,
- TAG_DONE);
- menu_glyph[NSA_GLYPH_AMIGAKEY] = NewObject(NULL, "sysiclass",
- SYSIA_Which, AMIGAKEY,
- SYSIA_DrawInfo, dri,
- TAG_DONE);
- GetAttr(IA_Width, menu_glyph[NSA_GLYPH_SUBMENU],
- (ULONG *)&menu_glyph_width[NSA_GLYPH_SUBMENU]);
- GetAttr(IA_Width, menu_glyph[NSA_GLYPH_AMIGAKEY],
- (ULONG *)&menu_glyph_width[NSA_GLYPH_AMIGAKEY]);
-
- menu_glyphs_loaded = true;
+ ULONG menu_num = ami_gui_menu_number(item);
+
+ if(disable == false) {
+ OnMenu(win, menu_num);
+ } else {
+ OffMenu(win, menu_num);
}
-#endif
}
-void ami_menu_free_glyphs(void)
+void ami_gui_menu_set_disabled(struct Window *win, struct Menu *menu, int item, bool
disable)
{
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
#ifdef __amigaos4__
- if(LIB_IS_AT_LEAST((struct Library *)GadToolsBase, 53, 7)) {
- int i;
- if(menu_glyphs_loaded == false) return;
-
- for(i = 0; i < NSA_GLYPH_MAX; i++) {
- if(menu_glyph[i]) DisposeObject(menu_glyph[i]);
- menu_glyph[i] = NULL;
- };
-
- menu_glyphs_loaded = false;
+ return ami_gui_menu_set_disabled_mc(win, menu, item, disable);
+#endif
+ } else {
+ return ami_gui_menu_set_disabled_gt(win, menu, item, disable);
}
-#endif
}
-static int ami_menu_calc_item_width(struct ami_menu_data **md, int j, struct RastPort
*rp)
+
+void ami_gui_menu_update_checked(struct gui_window_2 *gwin)
{
- int space_width = TextLength(rp, " ", 1);
- int item_size;
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ /* Irrelevant when using MenuClass */
+ return;
+ }
- item_size = TextLength(rp, md[j]->menulab, strlen(md[j]->menulab));
- item_size += space_width;
+ struct Menu *menustrip;
- if(md[j]->menukey) {
- item_size += TextLength(rp, &md[j]->menukey, 1);
- item_size += menu_glyph_width[NSA_GLYPH_AMIGAKEY];
- /**TODO: take account of the size of other imagery too
- */
+ GetAttr(WINDOW_MenuStrip, gwin->objects[OID_MAIN], (ULONG *)&menustrip);
+ if(!menustrip) return;
+ if(nsoption_bool(enable_javascript) == true) {
+ if((ItemAddress(menustrip, ami_gui_menu_number(M_JS))->Flags & CHECKED) == 0)
+ ItemAddress(menustrip, ami_gui_menu_number(M_JS))->Flags ^= CHECKED;
+ } else {
+ if(ItemAddress(menustrip, ami_gui_menu_number(M_JS))->Flags & CHECKED)
+ ItemAddress(menustrip, ami_gui_menu_number(M_JS))->Flags ^= CHECKED;
+ }
+ if(nsoption_bool(foreground_images) == true) {
+ if((ItemAddress(menustrip, ami_gui_menu_number(M_IMGFORE))->Flags & CHECKED) ==
0)
+ ItemAddress(menustrip, ami_gui_menu_number(M_IMGFORE))->Flags ^= CHECKED;
} else {
- /* assume worst case - it doesn't really matter if we make menus wider */
- item_size += TextLength(rp, "M", 1);
- item_size += menu_glyph_width[NSA_GLYPH_AMIGAKEY];
+ if(ItemAddress(menustrip, ami_gui_menu_number(M_IMGFORE))->Flags & CHECKED)
+ ItemAddress(menustrip, ami_gui_menu_number(M_IMGFORE))->Flags ^= CHECKED;
}
- if(md[j]->menuicon) {
- item_size += 16;
+ if(nsoption_bool(background_images) == true) {
+ if((ItemAddress(menustrip, ami_gui_menu_number(M_IMGBACK))->Flags & CHECKED) ==
0)
+ ItemAddress(menustrip, ami_gui_menu_number(M_IMGBACK))->Flags ^= CHECKED;
+ } else {
+ if(ItemAddress(menustrip, ami_gui_menu_number(M_IMGBACK))->Flags & CHECKED)
+ ItemAddress(menustrip, ami_gui_menu_number(M_IMGBACK))->Flags ^= CHECKED;
}
- return item_size;
+ ResetMenuStrip(gwin->win, menustrip);
}
-
-struct Menu *ami_menu_layout(struct ami_menu_data **md, int max)
+void ami_gui_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c)
{
- int i, j;
- int txtlen = 0;
- int left_posn = 0;
- struct NewMenu *nm;
- struct Menu *imenu = NULL;
- struct VisualInfo *vi;
- struct RastPort *rp = &scrn->RastPort;
- struct DrawInfo *dri = GetScreenDrawInfo(scrn);
- int space_width = TextLength(rp, " ", 1);
-
- if(menu_glyphs_loaded == false)
- ami_menu_load_glyphs(dri);
-
- nm = calloc(1, sizeof(struct NewMenu) * (max + 1));
- if(nm == NULL) return NULL;
-
- for(i = 0; i < max; i++) {
- if(md[i] == NULL) {
- nm[i].nm_Type = NM_IGNORE;
- continue;
- }
+ struct Window *win = g->shared->win;
- if(md[i]->menutype == NM_TITLE) {
- j = i + 1;
- txtlen = 0;
- do {
- if(md[j]->menulab != NM_BARLABEL) {
- if(md[j]->menutype == NM_ITEM) {
- int item_size = ami_menu_calc_item_width(md, j, rp);
- if(item_size > txtlen) {
- txtlen = item_size;
- }
- }
- }
- j++;
- } while((j <= max) && (md[j] != NULL) && (md[j]->menutype !=
NM_TITLE) && (md[j]->menutype != 0));
+ if(nsoption_bool(kiosk_mode) == true) return;
+
+ if(content_get_type(c) <= CONTENT_CSS)
+ {
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVETXT, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVECOMP, false);
+#ifdef WITH_PDF_EXPORT
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVEPDF, false);
+#endif
+#if 0
+ if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY) {
+ OnMenu(win,AMI_MENU_COPY);
+ OnMenu(win,AMI_MENU_CLEAR);
+ } else {
+ OffMenu(win,AMI_MENU_COPY);
+ OffMenu(win,AMI_MENU_CLEAR);
}
-#ifdef __amigaos4__
- if(LIB_IS_AT_LEAST((struct Library *)GadToolsBase, 53, 7)) {
- /* GadTools 53.7+ only. For now we will only create the menu
- using label.image if there's a bitmap associated with the item. */
- if((md[i]->menuicon != NULL) && (md[i]->menulab != NM_BARLABEL)) {
- int icon_width = 0;
- Object *restrict submenuarrow = NULL;
- Object *restrict icon = BitMapObj,
- IA_Scalable, TRUE,
- BITMAP_Screen, scrn,
- BITMAP_SourceFile, md[i]->menuicon,
- BITMAP_Masking, TRUE,
- BitMapEnd;
-
- /* \todo make this scale the bitmap to these dimensions */
- SetAttrs(icon,
- BITMAP_Width, 16,
- BITMAP_Height, 16,
- TAG_DONE);
-
- GetAttr(IA_Width, icon, (ULONG *)&icon_width);
-
- if(md[i]->menutype != NM_SUB) {
- left_posn = txtlen;
- }
- left_posn = left_posn -
- TextLength(rp, md[i]->menulab, strlen(md[i]->menulab)) -
- icon_width - space_width;
+ if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_CUT)
+ OnMenu(win,AMI_MENU_CUT);
+ else
+ OffMenu(win,AMI_MENU_CUT);
+
+ if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_PASTE)
+ OnMenu(win,AMI_MENU_PASTE);
+ else
+ OffMenu(win,AMI_MENU_PASTE);
+#else
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_CUT, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_COPY, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_PASTE, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_CLEAR, false);
+#endif
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SELALL, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_FIND, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVEIFF, true);
+ }
+ else
+ {
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_CUT, true);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_PASTE, true);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_CLEAR, true);
- if((md[i]->menutype == NM_ITEM) && md[i+1] &&
(md[i+1]->menutype == NM_SUB)) {
- left_posn -= menu_glyph_width[NSA_GLYPH_SUBMENU];
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVETXT, true);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVECOMP, true);
+#ifdef WITH_PDF_EXPORT
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVEPDF, true);
+#endif
- submenuarrow = NewObject(NULL, "sysiclass",
- SYSIA_Which, MENUSUB,
- SYSIA_DrawInfo, dri,
- IA_Left, left_posn,
- TAG_DONE);
- }
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SELALL, true);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_FIND, true);
- md[i]->menuobj = LabelObj,
- LABEL_MenuMode, TRUE,
- LABEL_DrawInfo, dri,
- LABEL_DisposeImage, TRUE,
- LABEL_Image, icon,
- LABEL_Text, " ",
- LABEL_Text, md[i]->menulab,
- LABEL_DisposeImage, TRUE,
- LABEL_Image, submenuarrow,
- LabelEnd;
-
- if(md[i]->menuobj) md[i]->menutype |= MENU_IMAGE;
- }
- }
+#ifdef WITH_NS_SVG
+ if(content_get_bitmap(c) || (ami_mime_compare(c, "svg") == true))
+#else
+ if(content_get_bitmap(c))
#endif
- nm[i].nm_Type = md[i]->menutype;
-
- if(md[i]->menuobj)
- nm[i].nm_Label = (void *)md[i]->menuobj;
+ {
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_COPY, false);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVEIFF, false);
+ }
else
- nm[i].nm_Label = md[i]->menulab;
-
- if(md[i]->menukey) nm[i].nm_CommKey = &md[i]->menukey;
- nm[i].nm_Flags = md[i]->flags;
- if(md[i]->menu_hook.h_Entry) nm[i].nm_UserData = &md[i]->menu_hook;
-
- if(md[i]->menuicon) {
- free(md[i]->menuicon);
- md[i]->menuicon = NULL;
+ {
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_COPY, true);
+ ami_gui_menu_set_disabled(win, g->shared->imenu, M_SAVEIFF, true);
}
}
-
- FreeScreenDrawInfo(scrn, dri);
-
- vi = GetVisualInfo(scrn, TAG_DONE);
- imenu = CreateMenus(nm, TAG_DONE);
- LayoutMenus(imenu, vi,
- GTMN_NewLookMenus, TRUE, TAG_DONE);
- free(nm);
- FreeVisualInfo(vi); /* Not using GadTools after layout so shouldn't need this */
-
- return imenu;
}
-void ami_menu_free(struct gui_window_2 *gwin)
+void ami_gui_menu_set_check_toggled(void)
{
- FreeMenus(gwin->imenu);
-}
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ /* Irrelevant when using MenuClass */
+ return;
+ }
-void ami_menu_free_menu(struct ami_menu_data **md, int max, struct Menu *imenu)
-{
- ami_menu_free_labs(md, max);
- FreeMenus(imenu);
+ ami_menu_check_toggled = true;
}
-struct Menu *ami_menu_create(struct gui_window_2 *gwin)
+bool ami_gui_menu_get_check_toggled(void)
{
- ami_init_menulabs(gwin->menu_data);
- ami_menu_scan(gwin->menu_data); //\todo this needs to be MenuClass created
- ami_menu_arexx_scan(gwin->menu_data);
- gwin->imenu = ami_menu_layout(gwin->menu_data, AMI_MENU_AREXX_MAX);
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ /* Irrelevant when using MenuClass */
+ return false;
+ }
- return gwin->imenu;
+ bool check_toggled = ami_menu_check_toggled;
+ ami_menu_check_toggled = false;
+ return check_toggled;
}
void ami_menu_arexx_scan(struct ami_menu_data **md)
@@ -1032,7 +837,7 @@ void ami_menu_arexx_scan(struct ami_menu_data **md)
else
menu_lab = ead->ed_Name;
- ami_menu_alloc_item(md, item, NM_ITEM, menu_lab, 0, NSA_SPACE,
+ ami_menu_alloc_item(md, item, NM_ITEM, menu_lab, NULL, NSA_SPACE,
ami_menu_item_arexx_entries, (void *)strdup(ead->ed_Name), 0);
item++;
@@ -1046,7 +851,7 @@ void ami_menu_arexx_scan(struct ami_menu_data **md)
UnLock(lock);
}
- ami_menu_alloc_item(md, item, NM_END, NULL, 0, NULL, NULL, NULL, 0);
+ ami_menu_alloc_item(md, item, NM_END, NULL, NULL, NULL, NULL, NULL, 0);
}
static bool ami_menu_hotlist_add(void *userdata, int level, int item, const char *title,
nsurl *url, bool is_folder)
@@ -1066,9 +871,12 @@ static bool ami_menu_hotlist_add(void *userdata, int level, int
item, const char
type = NM_SUB;
break;
default:
- /* entries not at level 1 or 2 are not able to be added
- * \todo construct menus using menuclass instead! */
- return false;
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ type = NM_SUB + (level - 2);
+ } else {
+ /* entries not at level 1 or 2 are not able to be added */
+ return false;
+ }
break;
}
@@ -1079,12 +887,14 @@ static bool ami_menu_hotlist_add(void *userdata, int level, int
item, const char
if (icon == NULL) icon = ASPrintf("icons/content.png");
}
- if((is_folder == true) && (type == NM_SUB)) {
- flags = NM_ITEMDISABLED;
+ if(!LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ if((is_folder == true) && (type == NM_SUB)) {
+ flags = NM_ITEMDISABLED;
+ }
}
ami_menu_alloc_item(md, item, type, title,
- 0, icon, ami_menu_item_hotlist_entries, (void *)url, flags);
+ NULL, icon, ami_menu_item_hotlist_entries, (void *)url, flags);
if(icon) FreeVec(icon);
@@ -1093,110 +903,221 @@ static bool ami_menu_hotlist_add(void *userdata, int level, int
item, const char
static nserror ami_menu_scan(struct ami_menu_data **md)
{
+ ami_menu_alloc_item(md, M_HLADD, NM_ITEM, "HotlistAdd", "B",
"TBImages:list_favouriteadd",
+ ami_menu_item_hotlist_add, NULL, 0);
+ ami_menu_alloc_item(md, M_HLSHOW, NM_ITEM,"HotlistShowNS", "H",
"TBImages:list_favourite",
+ ami_menu_item_hotlist_show, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_H1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+
return ami_hotlist_scan((void *)md, AMI_MENU_HOTLIST,
messages_get("HotlistMenu"), ami_menu_hotlist_add);
}
-void ami_menu_update_checked(struct gui_window_2 *gwin)
+static void ami_init_menulabs(struct ami_menu_data **md)
{
- struct Menu *menustrip;
+ UWORD js_flags = CHECKIT | MENUTOGGLE;
+ if(nsoption_bool(enable_javascript) == true)
+ js_flags |= CHECKED;
- GetAttr(WINDOW_MenuStrip, gwin->objects[OID_MAIN], (ULONG *)&menustrip);
- if(!menustrip) return;
- if(nsoption_bool(enable_javascript) == true) {
- if((ItemAddress(menustrip, AMI_MENU_JS)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_JS)->Flags ^= CHECKED;
- } else {
- if(ItemAddress(menustrip, AMI_MENU_JS)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_JS)->Flags ^= CHECKED;
- }
- if(nsoption_bool(foreground_images) == true) {
- if((ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags ^= CHECKED;
- } else {
- if(ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags ^= CHECKED;
- }
+ UWORD imgfore_flags = CHECKIT | MENUTOGGLE;
+ if(nsoption_bool(foreground_images) == true)
+ imgfore_flags |= CHECKED;
- if(nsoption_bool(background_images) == true) {
- if((ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags ^= CHECKED;
+ UWORD imgback_flags = CHECKIT | MENUTOGGLE;
+ if(nsoption_bool(background_images) == true)
+ imgback_flags |= CHECKED;
+
+ ami_menu_alloc_item(md, M_PROJECT, NM_TITLE, "Project", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, M_NEWWIN, NM_ITEM, "NewWindowNS", "N",
"TBImages:list_app",
+ ami_menu_item_project_newwin, NULL, 0);
+ ami_menu_alloc_item(md, M_NEWTAB, NM_ITEM, "NewTab", "T",
"TBImages:list_tab",
+ ami_menu_item_project_newtab, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_P1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_OPEN, NM_ITEM, "OpenFile", "O",
"TBImages:list_folder_misc",
+ ami_menu_item_project_open, NULL, 0);
+ ami_menu_alloc_item(md, M_SAVEAS, NM_ITEM, "SaveAsNS", NULL,
"TBImages:list_saveas", NULL, NULL, 0);
+ ami_menu_alloc_item(md, M_SAVESRC, NM_SUB, "Source", "S",
NULL,
+ ami_menu_item_project_save, (void *)AMINS_SAVE_SOURCE, 0);
+ ami_menu_alloc_item(md, M_SAVETXT, NM_SUB, "TextNS", NULL, NULL,
+ ami_menu_item_project_save, (void *)AMINS_SAVE_TEXT, 0);
+ ami_menu_alloc_item(md, M_SAVECOMP, NM_SUB, "SaveCompNS", NULL, NULL,
+ ami_menu_item_project_save, (void *)AMINS_SAVE_COMPLETE, 0);
+#ifdef WITH_PDF_EXPORT
+ ami_menu_alloc_item(md, M_SAVEPDF, NM_SUB, "PDFNS", NULL, NULL,
+ ami_menu_item_project_save, (void *)AMINS_SAVE_PDF, 0);
+#endif
+ ami_menu_alloc_item(md, M_SAVEIFF, NM_SUB, "IFF", NULL, NULL,
+ ami_menu_item_project_save, (void *)AMINS_SAVE_IFF, 0);
+ ami_menu_alloc_item(md, M_BAR_P2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_PRINT, NM_ITEM, "PrintNS", "P",
"TBImages:list_print",
+ ami_menu_item_project_print, NULL, NM_ITEMDISABLED);
+ ami_menu_alloc_item(md, M_BAR_P3, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_CLOSETAB, NM_ITEM, "CloseTab", "K",
"TBImages:list_remove",
+ ami_menu_item_project_closetab, NULL, 0);
+ ami_menu_alloc_item(md, M_CLOSEWIN, NM_ITEM, "CloseWindow", NULL,
"TBImages:list_cancel",
+ ami_menu_item_project_closewin, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_P4, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_ABOUT, NM_ITEM, "About", "?",
"TBImages:list_info",
+ ami_menu_item_project_about, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_P5, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_QUIT, NM_ITEM, "Quit", "Q",
"TBImages:list_warning",
+ ami_menu_item_project_quit, NULL, 0);
+
+ ami_menu_alloc_item(md, M_EDIT, NM_TITLE, "Edit", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, M_CUT, NM_ITEM, "CutNS", "X",
"TBImages:list_cut",
+ ami_menu_item_edit_cut, NULL, 0);
+ ami_menu_alloc_item(md, M_COPY, NM_ITEM, "CopyNS", "C",
"TBImages:list_copy",
+ ami_menu_item_edit_copy, NULL, 0);
+ ami_menu_alloc_item(md, M_PASTE, NM_ITEM, "PasteNS", "V",
"TBImages:list_paste",
+ ami_menu_item_edit_paste, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_E1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_SELALL, NM_ITEM, "SelectAllNS", "A",
NSA_SPACE,
+ ami_menu_item_edit_selectall, NULL, 0);
+ ami_menu_alloc_item(md, M_CLEAR, NM_ITEM, "ClearNS", NULL, NSA_SPACE,
+ ami_menu_item_edit_clearsel, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_E2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_UNDO, NM_ITEM, "Undo", "Z",
"TBImages:list_undo",
+ ami_menu_item_edit_undo, NULL, 0);
+ ami_menu_alloc_item(md, M_REDO, NM_ITEM, "Redo", "Y",
"TBImages:list_redo",
+ ami_menu_item_edit_redo, NULL, 0);
+
+ ami_menu_alloc_item(md, M_BROWSER, NM_TITLE, "Browser", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, M_FIND, NM_ITEM, "FindTextNS", "F",
"TBImages:list_search",
+ ami_menu_item_browser_find, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_B1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_HISTLOCL, NM_ITEM, "HistLocalNS", NULL,
"TBImages:list_history",
+ ami_menu_item_browser_localhistory, NULL, 0);
+ ami_menu_alloc_item(md, M_HISTGLBL, NM_ITEM, "HistGlobalNS", NULL,
"TBImages:list_history",
+ ami_menu_item_browser_globalhistory, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_B2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_COOKIES, NM_ITEM, "ShowCookiesNS",NULL,
"TBImages:list_internet",
+ ami_menu_item_browser_cookies, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_B3, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_SCALE, NM_ITEM, "ScaleNS", NULL,
"TBImages:list_preview", NULL, NULL, 0);
+ ami_menu_alloc_item(md, M_SCALEDEC, NM_SUB, "ScaleDec", "-",
"TBImages:list_zoom_out",
+ ami_menu_item_browser_scale_decrease, NULL, 0);
+ ami_menu_alloc_item(md, M_SCALENRM, NM_SUB, "ScaleNorm", "=",
"TBImages:list_zoom_100",
+ ami_menu_item_browser_scale_normal, NULL, 0);
+ ami_menu_alloc_item(md, M_SCALEINC, NM_SUB, "ScaleInc", "+",
"TBImages:list_zoom_in",
+ ami_menu_item_browser_scale_increase, NULL, 0);
+ ami_menu_alloc_item(md, M_IMAGES, NM_ITEM, "Images", NULL,
"TBImages:list_image", NULL, NULL, 0);
+ ami_menu_alloc_item(md, M_IMGFORE, NM_SUB, "ForeImg", NULL, NULL,
+ ami_menu_item_browser_foreimg, NULL, imgfore_flags);
+ ami_menu_alloc_item(md, M_IMGBACK, NM_SUB, "BackImg", NULL, NULL,
+ ami_menu_item_browser_backimg, NULL, imgback_flags);
+ ami_menu_alloc_item(md, M_JS, NM_ITEM, "EnableJS", NULL, NULL,
+ ami_menu_item_browser_enablejs, NULL, js_flags);
+ ami_menu_alloc_item(md, M_BAR_B4, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_REDRAW, NM_ITEM, "Redraw", NULL,
"TBImages:list_wand",
+ ami_menu_item_browser_redraw, NULL, 0);
+
+ ami_menu_alloc_item(md, M_HOTLIST, NM_TITLE, "Hotlist", NULL, NULL, NULL,
NULL, 0);
+ /* see ami_menu_scan for the rest of this menu */
+
+ ami_menu_alloc_item(md, M_PREFS, NM_TITLE, "Settings", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, M_PREDIT, NM_ITEM, "SettingsEdit", NULL,
"TBImages:list_prefs",
+ ami_menu_item_settings_edit, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_S1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, M_SNAPSHOT, NM_ITEM, "SnapshotWindow",NULL,
"TBImages:list_hold",
+ ami_menu_item_settings_snapshot, NULL, 0);
+ ami_menu_alloc_item(md, M_PRSAVE, NM_ITEM, "SettingsSave", NULL,
"TBImages:list_use",
+ ami_menu_item_settings_save, NULL, 0);
+
+ ami_menu_alloc_item(md, M_AREXX, NM_TITLE, "ARexx", NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, M_AREXXEX, NM_ITEM, "ARexxExecute", "E",
"TBImages:list_arexx",
+ ami_menu_item_arexx_execute, NULL, 0);
+ ami_menu_alloc_item(md, M_BAR_A1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, AMI_MENU_AREXX_MAX, NM_END, NULL, NULL, NULL, NULL, NULL,
0);
+}
+
+struct Menu *ami_gui_menu_create(struct gui_window_2 *gwin)
+{
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+#ifdef __amigaos4__
+ if(gui_menu != NULL) {
+ gwin->imenu = gui_menu;
+ gui_menu_count++;
+ return gwin->imenu;
+ }
+ ami_init_menulabs(gui_menu_data);
+ ami_menu_scan(gui_menu_data);
+ ami_menu_arexx_scan(gui_menu_data);
+ gwin->imenu = ami_menu_layout(gui_menu_data, AMI_MENU_AREXX_MAX);
+
+ gui_menu = gwin->imenu;
+ gui_menu_count++;
+#endif
} else {
- if(ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags ^= CHECKED;
+ ami_init_menulabs(gwin->menu_data);
+ ami_menu_scan(gwin->menu_data);
+ ami_menu_arexx_scan(gwin->menu_data);
+ gwin->imenu = ami_menu_layout(gwin->menu_data, AMI_MENU_AREXX_MAX);
}
- ResetMenuStrip(gwin->win, menustrip);
+ return gwin->imenu;
}
-void ami_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c)
+static void ami_free_menulabs(struct ami_menu_data **md)
{
- struct Window *win = g->shared->win;
+ int i;
- if(nsoption_bool(kiosk_mode) == true) return;
+ for(i=0;i<=AMI_MENU_AREXX_MAX;i++) {
+ if(md[i] == NULL) continue;
+ if(md[i]->menulab &&
+ (md[i]->menulab != NM_BARLABEL) &&
+ (md[i]->menulab != ML_SEPARATOR)) {
+ if(md[i]->menutype & MENU_IMAGE) {
+ if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
+ }
- if(content_get_type(c) <= CONTENT_CSS)
- {
- OnMenu(win,AMI_MENU_SAVEAS_TEXT);
- OnMenu(win,AMI_MENU_SAVEAS_COMPLETE);
-#ifdef WITH_PDF_EXPORT
- OnMenu(win,AMI_MENU_SAVEAS_PDF);
-#endif
-#if 0
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY) {
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_CLEAR);
- } else {
- OffMenu(win,AMI_MENU_COPY);
- OffMenu(win,AMI_MENU_CLEAR);
+ ami_utf8_free(md[i]->menulab);
+
+ if(i >= AMI_MENU_AREXX) {
+ if(md[i]->menu_hook.h_Data) free(md[i]->menu_hook.h_Data);
+ md[i]->menu_hook.h_Data = NULL;
+ }
}
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_CUT)
- OnMenu(win,AMI_MENU_CUT);
- else
- OffMenu(win,AMI_MENU_CUT);
-
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_PASTE)
- OnMenu(win,AMI_MENU_PASTE);
- else
- OffMenu(win,AMI_MENU_PASTE);
-#else
- OnMenu(win,AMI_MENU_CUT);
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_PASTE);
- OnMenu(win,AMI_MENU_CLEAR);
-#endif
- OnMenu(win,AMI_MENU_SELECTALL);
- OnMenu(win,AMI_MENU_FIND);
- OffMenu(win,AMI_MENU_SAVEAS_IFF);
+ if(md[i]->menukey != NULL) free(md[i]->menukey);
+
+ md[i]->menulab = NULL;
+ md[i]->menuobj = NULL;
+ md[i]->menukey = NULL;
+ md[i]->menutype = 0;
+ free(md[i]);
+ md[i] = NULL;
}
- else
- {
- OffMenu(win,AMI_MENU_CUT);
- OffMenu(win,AMI_MENU_PASTE);
- OffMenu(win,AMI_MENU_CLEAR);
+}
- OffMenu(win,AMI_MENU_SAVEAS_TEXT);
- OffMenu(win,AMI_MENU_SAVEAS_COMPLETE);
-#ifdef WITH_PDF_EXPORT
- OffMenu(win,AMI_MENU_SAVEAS_PDF);
-#endif
- OffMenu(win,AMI_MENU_SELECTALL);
- OffMenu(win,AMI_MENU_FIND);
+void ami_gui_menu_free(struct gui_window_2 *gwin)
+{
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+#ifdef __amigaos4__
+ gui_menu_count--;
-#ifdef WITH_NS_SVG
- if(content_get_bitmap(c) || (ami_mime_compare(c, "svg") == true))
-#else
- if(content_get_bitmap(c))
-#endif
- {
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_SAVEAS_IFF);
- }
- else
- {
- OffMenu(win,AMI_MENU_COPY);
- OffMenu(win,AMI_MENU_SAVEAS_IFF);
+ SetAttrs(gwin->objects[OID_MAIN], WINDOW_MenuStrip, NULL, TAG_DONE);
+
+ if(gui_menu_count == 0) {
+ ami_free_menulabs(gui_menu_data);
+ // if we detach our menu from the window we need to do this manually
+ DisposeObject((Object *)gui_menu);
+ gui_menu = NULL;
}
+#endif
+ } else {
+ ami_free_menulabs(gwin->menu_data);
+ FreeMenus(gwin->imenu);
}
}
+bool ami_gui_menu_quit_selected(void)
+{
+ return menu_quit;
+}
+
+void ami_gui_menu_refresh_hotlist(void)
+{
+#ifdef __amigaos4__
+ ami_menu_refresh(gui_menu, gui_menu_data, M_HOTLIST, AMI_MENU_HOTLIST_MAX,
ami_menu_scan);
+#endif
+}
+
diff --git a/frontends/amiga/menu.h b/frontends/amiga/gui_menu.h
similarity index 56%
copy from frontends/amiga/menu.h
copy to frontends/amiga/gui_menu.h
index ad0e96d..16fc720 100644
--- a/frontends/amiga/menu.h
+++ b/frontends/amiga/gui_menu.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008,2009,2013 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2008-2017 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf,
http://www.netsurf-browser.org/
*
@@ -16,21 +16,11 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#ifndef AMIGA_MENU_H
-#define AMIGA_MENU_H
-
-#include <exec/types.h>
-#include <intuition/intuition.h>
-#include <libraries/gadtools.h>
-
-struct hlcache_handle;
-struct ami_menu_data;
-
-/** empty space */
-#define NSA_SPACE "blankspace.png"
+#ifndef AMIGA_GUI_MENU_H
+#define AMIGA_GUI_MENU_H
/** Maximum number of hotlist items (somewhat arbitrary value) */
-#define AMI_HOTLIST_ITEMS 60
+#define AMI_HOTLIST_ITEMS 200
/** Maximum number of ARexx menu items (somewhat arbitrary value) */
#define AMI_MENU_AREXX_ITEMS 20
@@ -115,49 +105,21 @@ enum {
* only used for freeing the UTF-8 converted menu labels */
#define AMI_MENU_MAX AMI_MENU_AREXX
-/* The Intuition menu numbers of some menus we might need to modify */
-#define AMI_MENU_SAVEAS_TEXT FULLMENUNUM(0,4,1)
-#define AMI_MENU_SAVEAS_COMPLETE FULLMENUNUM(0,4,2)
-#define AMI_MENU_SAVEAS_IFF FULLMENUNUM(0,4,3)
-#define AMI_MENU_SAVEAS_PDF FULLMENUNUM(0,4,4)
-#define AMI_MENU_CLOSETAB FULLMENUNUM(0,8,0)
-#define AMI_MENU_CUT FULLMENUNUM(1,0,0)
-#define AMI_MENU_COPY FULLMENUNUM(1,1,0)
-#define AMI_MENU_PASTE FULLMENUNUM(1,2,0)
-#define AMI_MENU_SELECTALL FULLMENUNUM(1,4,0)
-#define AMI_MENU_CLEAR FULLMENUNUM(1,5,0)
-#define AMI_MENU_UNDO FULLMENUNUM(1,8,0)
-#define AMI_MENU_REDO FULLMENUNUM(1,9,0)
-#define AMI_MENU_FIND FULLMENUNUM(2,0,0)
-#define AMI_MENU_FOREIMG FULLMENUNUM(2,8,0)
-#define AMI_MENU_BACKIMG FULLMENUNUM(2,8,1)
-#define AMI_MENU_JS FULLMENUNUM(2,9,0)
-
struct gui_window;
struct gui_window_2;
+struct hlcache_handle;
-/* cleanup */
-void ami_menu_free_glyphs(void);
-
-/* generic menu alloc/free/layout */
-void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE type,
- const char *restrict label, char key, const char *restrict icon,
- void *restrict func, void *restrict hookdata, UWORD flags);
-struct Menu *ami_menu_layout(struct ami_menu_data **md, int max);
-void ami_menu_free_menu(struct ami_menu_data **md, int max, struct Menu *imenu);
+ULONG ami_gui_menu_number(int item);
+struct Menu *ami_gui_menu_create(struct gui_window_2 *gwin);
+void ami_gui_menu_free(struct gui_window_2 *gwin);
-/* specific to browser windows */
-void ami_free_menulabs(struct ami_menu_data **md);
-struct Menu *ami_menu_create(struct gui_window_2 *gwin);
-void ami_menu_refresh(struct gui_window_2 *gwin);
-void ami_menu_update_checked(struct gui_window_2 *gwin);
-void ami_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c);
-void ami_menu_free(struct gui_window_2 *gwin);
+void ami_gui_menu_update_checked(struct gui_window_2 *gwin);
+void ami_gui_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c);
/**
* Sets that an item linked to a toggle menu item has been changed.
*/
-void ami_menu_set_check_toggled(void);
+void ami_gui_menu_set_check_toggled(void);
/**
* Gets if the menu needs updating because an item linked
@@ -166,13 +128,30 @@ void ami_menu_set_check_toggled(void);
*
* \return true if the menus need refreshing
*/
-bool ami_menu_get_check_toggled(void);
+bool ami_gui_menu_get_check_toggled(void);
+
+/**
+ * Set checked state of a menu item
+ * almost generic, but not quite
+ */
+void ami_gui_menu_set_checked(struct Menu *menu, int item, bool check);
+
+/**
+ * Set disabled state of a menu item
+ * almost generic, but not quite
+ */
+void ami_gui_menu_set_disabled(struct Window *win, struct Menu *menu, int item, bool
disable);
+
+/**
+ * Refresh the Hotlist menu
+ */
+void ami_gui_menu_refresh_hotlist(void);
/**
* Gets if NetSurf has been quit from the menu
*
* \return true if NetSurf has been quit
*/
-bool ami_menu_quit_selected(void);
+bool ami_gui_menu_quit_selected(void);
#endif
diff --git a/frontends/amiga/gui_options.c b/frontends/amiga/gui_options.c
index 698735b..78dea58 100755
--- a/frontends/amiga/gui_options.c
+++ b/frontends/amiga/gui_options.c
@@ -70,6 +70,7 @@
#include "amiga/font.h"
#include "amiga/font_bullet.h"
#include "amiga/gui.h"
+#include "amiga/gui_menu.h"
#include "amiga/gui_options.h"
#include "amiga/help.h"
#include "amiga/libs.h"
@@ -1726,7 +1727,9 @@ static void ami_gui_opts_use(bool save)
} else {
nsoption_set_bool(enable_javascript, false);
}
-
+
+ ami_gui_menu_set_checked(NULL, M_JS, nsoption_bool(enable_javascript));
+
GetAttr(GA_Selected,gow->objects[GID_OPTS_DONOTTRACK],(ULONG *)&data);
if (data) {
nsoption_set_bool(do_not_track, true);
@@ -2066,7 +2069,7 @@ static void ami_gui_opts_use(bool save)
ami_font_savescanner(); /* just in case it has changed and been used only */
}
- ami_menu_set_check_toggled();
+ ami_gui_menu_set_check_toggled();
ami_update_pointer(gow->win, GUI_POINTER_DEFAULT);
}
diff --git a/frontends/amiga/history.c b/frontends/amiga/history.c
index b2a3cc0..12c306a 100644
--- a/frontends/amiga/history.c
+++ b/frontends/amiga/history.c
@@ -49,6 +49,7 @@
#include "amiga/file.h"
#include "amiga/history.h"
#include "amiga/libs.h"
+#include "amiga/menu.h"
#include "amiga/theme.h"
#include "amiga/utf8.h"
@@ -308,41 +309,41 @@ HOOKF(void, ami_history_global_menu_item_edit_delete, APTR, window,
struct Intui
static void ami_history_global_menulabs(struct ami_menu_data **md)
{
- ami_menu_alloc_item(md, AMI_HISTORY_M_PROJECT, NM_TITLE, "Tree", 0,
NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EXPORT, NM_ITEM, "TreeExport",
'S', "TBImages:list_save",
+ ami_menu_alloc_item(md, AMI_HISTORY_M_PROJECT, NM_TITLE, "Tree", NULL, NULL,
NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EXPORT, NM_ITEM, "TreeExport",
"S", "TBImages:list_save",
ami_history_global_menu_item_project_export, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND, NM_ITEM, "Expand", 0,
"TBImages:list_folderunfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_ALL, NM_SUB, "All",
'+', NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND, NM_ITEM, "Expand", NULL,
"TBImages:list_folderunfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_ALL, NM_SUB, "All",
"+", NULL,
ami_history_global_menu_item_project_expand_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_FOLDERS, NM_SUB, "Folders", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_FOLDERS, NM_SUB, "Folders",
NULL, NULL,
ami_history_global_menu_item_project_expand_folders, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_LINKS, NM_SUB, "Links", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EXPAND_LINKS, NM_SUB, "Links", NULL,
NULL,
ami_history_global_menu_item_project_expand_links, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE, NM_ITEM, "Collapse", 0,
"TBImages:list_folderfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_ALL, NM_SUB, "All",
'-', NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE, NM_ITEM, "Collapse", NULL,
"TBImages:list_folderfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_ALL, NM_SUB, "All",
"-", NULL,
ami_history_global_menu_item_project_collapse_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_FOLDERS, NM_SUB, "Folders",
0, NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_FOLDERS, NM_SUB, "Folders",
NULL, NULL,
ami_history_global_menu_item_project_collapse_folders, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_LINKS, NM_SUB, "Links", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_COLLAPSE_LINKS, NM_SUB, "Links", NULL,
NULL,
ami_history_global_menu_item_project_collapse_links, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_SNAPSHOT, NM_ITEM, "SnapshotWindow",
0, "TBImages:list_hold",
+ ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_SNAPSHOT, NM_ITEM, "SnapshotWindow",
NULL, "TBImages:list_hold",
ami_history_global_menu_item_project_snapshot, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_CLOSE, NM_ITEM, "CloseWindow",
'K', "TBImages:list_cancel",
+ ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_P3, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_CLOSE, NM_ITEM, "CloseWindow",
"K", "TBImages:list_cancel",
ami_history_global_menu_item_project_close, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_EDIT, NM_TITLE, "Edit", 0, NULL,
NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_SELECTALL, NM_ITEM, "SelectAllNS",
'A', NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_EDIT, NM_TITLE, "Edit", NULL, NULL,
NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_SELECTALL, NM_ITEM, "SelectAllNS",
"A", NSA_SPACE,
ami_history_global_menu_item_edit_select_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_CLEAR, NM_ITEM, "ClearNS", 0,
NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_HISTORY_M_CLEAR, NM_ITEM, "ClearNS", NULL,
NSA_SPACE,
ami_history_global_menu_item_edit_clear, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_E1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_DELETE, NM_ITEM, "TreeDelete", 0,
"TBImages:list_delete",
+ ami_menu_alloc_item(md, AMI_HISTORY_M_BAR_E1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_DELETE, NM_ITEM, "TreeDelete",
"Del", "TBImages:list_delete",
ami_history_global_menu_item_edit_delete, NULL, 0);
- ami_menu_alloc_item(md, AMI_HISTORY_M_LAST, NM_END, NULL, 0, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, AMI_HISTORY_M_LAST, NM_END, NULL, NULL, NULL, NULL, NULL, 0);
}
static struct Menu *
diff --git a/frontends/amiga/hotlist.c b/frontends/amiga/hotlist.c
index 8aa181b..008e45a 100644
--- a/frontends/amiga/hotlist.c
+++ b/frontends/amiga/hotlist.c
@@ -49,6 +49,7 @@
#include "amiga/file.h"
#include "amiga/hotlist.h"
#include "amiga/libs.h"
+#include "amiga/menu.h"
#include "amiga/theme.h"
#include "amiga/utf8.h"
@@ -404,49 +405,49 @@ HOOKF(void, ami_hotlist_menu_item_edit_delete, APTR, window, struct
IntuiMessage
static void ami_hotlist_menulabs(struct ami_menu_data **md)
{
- ami_menu_alloc_item(md, AMI_HOTLIST_M_PROJECT, NM_TITLE, "Tree", 0,
NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPORT, NM_ITEM, "TreeExport",
'S', "TBImages:list_save",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_PROJECT, NM_TITLE, "Tree", NULL, NULL,
NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPORT, NM_ITEM, "TreeExport",
"S", "TBImages:list_save",
ami_hotlist_menu_item_project_export, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND, NM_ITEM, "Expand", 0,
"TBImages:list_folderunfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_ALL, NM_SUB, "All",
'+', NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND, NM_ITEM, "Expand", NULL,
"TBImages:list_folderunfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_ALL, NM_SUB, "All",
"+", NULL,
ami_hotlist_menu_item_project_expand_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_FOLDERS, NM_SUB, "Folders", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_FOLDERS, NM_SUB, "Folders",
NULL, NULL,
ami_hotlist_menu_item_project_expand_folders, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_LINKS, NM_SUB, "Links", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EXPAND_LINKS, NM_SUB, "Links", NULL,
NULL,
ami_hotlist_menu_item_project_expand_links, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE, NM_ITEM, "Collapse", 0,
"TBImages:list_folderfold", NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_ALL, NM_SUB, "All",
'-', NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE, NM_ITEM, "Collapse", NULL,
"TBImages:list_folderfold", NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_ALL, NM_SUB, "All",
"-", NULL,
ami_hotlist_menu_item_project_collapse_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_FOLDERS, NM_SUB, "Folders",
0, NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_FOLDERS, NM_SUB, "Folders",
NULL, NULL,
ami_hotlist_menu_item_project_collapse_folders, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_LINKS, NM_SUB, "Links", 0,
NULL,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_COLLAPSE_LINKS, NM_SUB, "Links", NULL,
NULL,
ami_hotlist_menu_item_project_collapse_links, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_SNAPSHOT, NM_ITEM, "SnapshotWindow",
0, "TBImages:list_hold",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_SNAPSHOT, NM_ITEM, "SnapshotWindow",
NULL, "TBImages:list_hold",
ami_hotlist_menu_item_project_snapshot, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_CLOSE, NM_ITEM, "CloseWindow",
'K', "TBImages:list_cancel",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_P3, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_CLOSE, NM_ITEM, "CloseWindow",
"K", "TBImages:list_cancel",
ami_hotlist_menu_item_project_close, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EDIT, NM_TITLE, "Edit", 0, NULL,
NULL, NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EDIT, NM_TITLE, "Edit", NULL, NULL,
NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_NEWFOLDER, NM_ITEM, "TreeNewFolder",
'N', "TBImages:list_drawer",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_NEWFOLDER, NM_ITEM, "TreeNewFolder",
"N", "TBImages:list_drawer",
ami_hotlist_menu_item_edit_newfolder, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_NEWLINK, NM_ITEM, "TreeNewLink", 0,
"TBImages:list_favouriteadd",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_NEWLINK, NM_ITEM, "TreeNewLink", NULL,
"TBImages:list_favouriteadd",
ami_hotlist_menu_item_edit_newlink, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_EDIT_EDIT, NM_ITEM, "TreeEdit",
'E', "TBImages:list_edit",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_EDIT_EDIT, NM_ITEM, "TreeEdit",
"E", "TBImages:list_edit",
ami_hotlist_menu_item_edit_edit, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_E1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_SELECTALL, NM_ITEM, "SelectAllNS",
'A', NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_E1, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_SELECTALL, NM_ITEM, "SelectAllNS",
"A", NSA_SPACE,
ami_hotlist_menu_item_edit_select_all, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_CLEAR, NM_ITEM, "ClearNS", 0,
NSA_SPACE,
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_CLEAR, NM_ITEM, "ClearNS", NULL,
NSA_SPACE,
ami_hotlist_menu_item_edit_clear, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_E2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_DELETE, NM_ITEM, "TreeDelete", 0,
"TBImages:list_delete",
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_BAR_E2, NM_ITEM, NM_BARLABEL, NULL, NULL, NULL,
NULL, 0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_DELETE, NM_ITEM, "TreeDelete",
"Del", "TBImages:list_delete",
ami_hotlist_menu_item_edit_delete, NULL, 0);
- ami_menu_alloc_item(md, AMI_HOTLIST_M_LAST, NM_END, NULL, 0, NULL, NULL, NULL,
0);
+ ami_menu_alloc_item(md, AMI_HOTLIST_M_LAST, NM_END, NULL, NULL, NULL, NULL, NULL, 0);
}
static struct Menu *
diff --git a/frontends/amiga/iff_dr2d.c b/frontends/amiga/iff_dr2d.c
index 91973f4..a4c5855 100644
--- a/frontends/amiga/iff_dr2d.c
+++ b/frontends/amiga/iff_dr2d.c
@@ -20,12 +20,12 @@
#include <stdio.h>
#include <stdlib.h>
-#include <inttypes.h>
#include <svgtiny.h>
#include <proto/exec.h>
#include <string.h>
#include <proto/dos.h>
+#include "netsurf/inttypes.h"
#ifndef AMIGA_DR2D_STANDALONE
#include "utils/nsurl.h"
#include "netsurf/content.h"
diff --git a/frontends/amiga/menu.c b/frontends/amiga/menu.c
index c354fef..249ca07 100644
--- a/frontends/amiga/menu.c
+++ b/frontends/amiga/menu.c
@@ -21,18 +21,14 @@
#include <string.h>
#include <stdlib.h>
-#include <proto/dos.h>
-#include <proto/asl.h>
-#include <proto/exec.h>
#include <proto/gadtools.h>
+#include <proto/graphics.h>
#include <proto/intuition.h>
-#include <proto/utility.h>
-#ifdef __amigaos4__
-#include <dos/anchorpath.h>
-#include <dos/obsolete.h> /* Needed for ExAll() */
-#endif
#include <libraries/gadtools.h>
+#ifdef __amigaos4__
+#include <intuition/menuclass.h>
+#endif
#include <classes/window.h>
#include <proto/label.h>
@@ -42,41 +38,13 @@
#include <reaction/reaction_macros.h>
-#include "utils/nsoption.h"
-#include "utils/messages.h"
#include "utils/log.h"
-#include "utils/utils.h"
-#include "utils/nsurl.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/mouse.h"
-#include "netsurf/window.h"
-#include "netsurf/content.h"
-#include "netsurf/keypress.h"
-#include "desktop/hotlist.h"
-#include "desktop/version.h"
-
-#include "amiga/arexx.h"
-#include "amiga/bitmap.h"
-#include "amiga/clipboard.h"
-#include "amiga/cookies.h"
-#include "amiga/file.h"
-#include "amiga/filetype.h"
+#include "utils/messages.h"
+
#include "amiga/gui.h"
-#include "amiga/gui_options.h"
-#include "amiga/history.h"
-#include "amiga/history_local.h"
-#include "amiga/hotlist.h"
#include "amiga/libs.h"
#include "amiga/menu.h"
-#include "amiga/misc.h"
-#include "amiga/nsoption.h"
-#include "amiga/print.h"
-#include "amiga/search.h"
-#include "amiga/theme.h"
#include "amiga/utf8.h"
-#include "amiga/schedule.h"
-
-#define NSA_MAX_HOTLIST_MENU_LEN 100
enum {
NSA_GLYPH_SUBMENU,
@@ -86,518 +54,68 @@ enum {
NSA_GLYPH_MAX
};
-struct ami_menu_data {
- char *restrict menulab;
- Object *restrict menuobj;
- char menukey;
- char *restrict menuicon;
- struct Hook menu_hook;
- UBYTE menutype;
- UWORD flags;
-};
+#define NSA_MAX_HOTLIST_MENU_LEN 100
-static bool menu_quit = false;
-static bool ami_menu_check_toggled = false;
static Object *restrict menu_glyph[NSA_GLYPH_MAX];
static int menu_glyph_width[NSA_GLYPH_MAX];
static bool menu_glyphs_loaded = false;
-const char * const netsurf_version;
-const char * const verdate;
-
-static nserror ami_menu_scan(struct ami_menu_data **md);
-void ami_menu_arexx_scan(struct ami_menu_data **md);
-
-void ami_menu_set_check_toggled(void)
-{
- ami_menu_check_toggled = true;
-}
-
-bool ami_menu_get_check_toggled(void)
-{
- bool check_toggled = ami_menu_check_toggled;
- ami_menu_check_toggled = false;
- return check_toggled;
-}
-
-bool ami_menu_quit_selected(void)
-{
- return menu_quit;
-}
-
-/*
- * The below functions are called automatically by window.class when menu items are
selected.
- */
-
-HOOKF(void, ami_menu_item_project_newwin, APTR, window, struct IntuiMessage *)
-{
- nsurl *url;
- nserror error;
-
- error = nsurl_create(nsoption_charp(homepage_url), &url);
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- amiga_warn_user(messages_get_errorcode(error), 0);
- }
-}
-
-HOOKF(void, ami_menu_item_project_newtab, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
-
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
- ami_gui_new_blank_tab(gwin);
-}
-
-HOOKF(void, ami_menu_item_project_open, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_file_open(gwin);
-}
-
-HOOKF(void, ami_menu_item_project_save, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- ULONG type = (ULONG)hook->h_Data;
-
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_file_save_req(type, gwin, browser_window_get_content(gwin->gw->bw));
-}
-
-HOOKF(void, ami_menu_item_project_closetab, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_destroy(gwin->gw->bw);
-}
-
-HOOKF(void, ami_menu_item_project_closewin, APTR, window, struct IntuiMessage *)
+bool ami_menu_get_selected(struct Menu *menu, struct IntuiMessage *msg)
{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- gwin->closed = true;
-}
-
-HOOKF(void, ami_menu_item_project_print, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_set_pointer(gwin, GUI_POINTER_WAIT, false);
- ami_print_ui(browser_window_get_content(gwin->gw->bw));
- ami_reset_pointer(gwin);
-}
-
-HOOKF(void, ami_menu_item_project_about, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- char *temp, *temp2;
- int sel;
- nsurl *url = NULL;
- nserror error = NSERROR_OK;
-
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_set_pointer(gwin, GUI_POINTER_WAIT, false);
-
- temp = ASPrintf("%s|%s|%s", messages_get("OK"),
- messages_get("HelpCredits"),
- messages_get("HelpLicence"));
+ bool checked = false;
- temp2 = ami_utf8_easy(temp);
- FreeVec(temp);
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
#ifdef __amigaos4__
- sel = TimedDosRequesterTags(TDR_ImageType,TDRIMAGE_INFO,
- TDR_TitleString, messages_get("NetSurf"),
- TDR_Window, gwin->win,
- TDR_GadgetString, temp2,
- TDR_FormatString,"NetSurf %s\nBuild date
%s\n\nhttp://www.netsurf-browser.org",
- TDR_Arg1,netsurf_version,
- TDR_Arg2,verdate,
- TAG_DONE);
-#else
- struct EasyStruct about_req = {
- sizeof(struct EasyStruct),
- 0,
- "NetSurf",
- "NetSurf %s\nBuild date %s\n\nhttp://www.netsurf-browser.org",
- temp2,
- };
-
- sel = EasyRequest(gwin->win, &about_req, NULL, netsurf_version, verdate);
-#endif
- free(temp2);
+ ULONG state;
+ struct ExtIntuiMessage *emsg = (struct ExtIntuiMessage *)msg;
- if(sel == 2) {
- error = nsurl_create("about:credits", &url);
- } else if(sel == 0) {
- error = nsurl_create("about:licence", &url);
- }
-
- if(url) {
- if (error == NSERROR_OK) {
- error = browser_window_create(BW_CREATE_HISTORY,
- url,
- NULL,
- NULL,
- NULL);
- nsurl_unref(url);
- }
- if (error != NSERROR_OK) {
- amiga_warn_user(messages_get_errorcode(error), 0);
- }
+ state = IDoMethod((Object *)menu, MM_GETSTATE, 0, emsg->eim_LongCode, MS_CHECKED);
+ if(state & MS_CHECKED) checked = true;
+#endif
+ } else {
+ if(ItemAddress(menu, msg->Code)->Flags & CHECKED) checked = true;
}
- ami_reset_pointer(gwin);
+ return checked;
}
-HOOKF(void, ami_menu_item_project_quit, APTR, window, struct IntuiMessage *)
-{
- menu_quit = true;
-}
-
-HOOKF(void, ami_menu_item_edit_cut, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_CUT_SELECTION);
-}
-
-HOOKF(void, ami_menu_item_edit_copy, APTR, window, struct IntuiMessage *)
-{
- struct bitmap *bm;
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
+/* menu creation code */
+void ami_menu_free_lab_item(struct ami_menu_data **md, int i)
+{
+ if(md[i] == NULL) return;
+ if(md[i]->menulab &&
+ (md[i]->menulab != NM_BARLABEL) &&
+ (md[i]->menulab != ML_SEPARATOR)) {
+ if(md[i]->menutype & MENU_IMAGE) {
+ if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
+ }
- if(browser_window_can_select(gwin->gw->bw)) {
- browser_window_key_press(gwin->gw->bw, NS_KEY_COPY_SELECTION);
- browser_window_key_press(gwin->gw->bw, NS_KEY_CLEAR_SELECTION);
- }
- else if((bm = content_get_bitmap(browser_window_get_content(gwin->gw->bw)))) {
- /** @todo It should be checked that the lifetime of
- * the objects containing the values returned (and the
- * constness cast away) is safe.
- */
- ami_bitmap_set_url(bm, browser_window_get_url(gwin->gw->bw));
- ami_bitmap_set_title(bm, browser_window_get_title(gwin->gw->bw));
- ami_easy_clipboard_bitmap(bm);
+ ami_utf8_free(md[i]->menulab);
}
-#ifdef WITH_NS_SVG
- else if(ami_mime_compare(browser_window_get_content(gwin->gw->bw),
"svg") == true) {
- ami_easy_clipboard_svg(browser_window_get_content(gwin->gw->bw));
- }
-#endif
-}
-
-HOOKF(void, ami_menu_item_edit_paste, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_PASTE);
-}
-
-HOOKF(void, ami_menu_item_edit_selectall, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_SELECT_ALL);
- gui_start_selection(gwin->gw);
-}
-
-HOOKF(void, ami_menu_item_edit_clearsel, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_CLEAR_SELECTION);
-}
-
-HOOKF(void, ami_menu_item_edit_undo, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_UNDO);
-}
-
-HOOKF(void, ami_menu_item_edit_redo, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- browser_window_key_press(gwin->gw->bw, NS_KEY_REDO);
-}
-
-HOOKF(void, ami_menu_item_browser_find, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_search_open(gwin->gw);
-}
-
-HOOKF(void, ami_menu_item_browser_localhistory, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_history_open(gwin->gw);
-}
-
-HOOKF(void, ami_menu_item_browser_globalhistory, APTR, window, struct IntuiMessage *)
-{
- ami_history_global_present();
-}
-HOOKF(void, ami_menu_item_browser_cookies, APTR, window, struct IntuiMessage *)
-{
- ami_cookies_present();
-}
-
-HOOKF(void, ami_menu_item_browser_foreimg, APTR, window, struct IntuiMessage *)
-{
- struct Menu *menustrip;
- bool checked = false;
+ if(md[i]->menukey != NULL) free(md[i]->menukey);
- GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
-
- nsoption_set_bool(foreground_images, checked);
- ami_menu_set_check_toggled();
+ md[i]->menulab = NULL;
+ md[i]->menuobj = NULL;
+ md[i]->menukey = NULL;
+ md[i]->menutype = 0;
+ free(md[i]);
+ md[i] = NULL;
}
-HOOKF(void, ami_menu_item_browser_backimg, APTR, window, struct IntuiMessage *)
-{
- struct Menu *menustrip;
- bool checked = false;
-
- GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
-
- nsoption_set_bool(background_images, checked);
- ami_menu_set_check_toggled();
-}
-
-HOOKF(void, ami_menu_item_browser_enablejs, APTR, window, struct IntuiMessage *)
-{
- struct Menu *menustrip;
- bool checked = false;
-
- GetAttr(WINDOW_MenuStrip, (Object *)window, (ULONG *)&menustrip);
- if(ItemAddress(menustrip, msg->Code)->Flags & CHECKED) checked = true;
-
- nsoption_set_bool(enable_javascript, checked);
- ami_menu_set_check_toggled();
-}
-
-HOOKF(void, ami_menu_item_browser_scale_decrease, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_gui_set_scale(gwin->gw, gwin->gw->scale - 0.1);
-}
-
-HOOKF(void, ami_menu_item_browser_scale_normal, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_gui_set_scale(gwin->gw, 1.0);
-}
-
-HOOKF(void, ami_menu_item_browser_scale_increase, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_gui_set_scale(gwin->gw, gwin->gw->scale + 0.1);
-}
-
-HOOKF(void, ami_menu_item_browser_redraw, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- ami_schedule_redraw(gwin, true);
- gwin->new_content = true;
-}
-
-HOOKF(void, ami_menu_item_hotlist_add, APTR, window, struct IntuiMessage *)
-{
- struct browser_window *bw;
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- bw = gwin->gw->bw;
-
- if (bw == NULL || browser_window_has_content(bw) == false)
- return;
-
- hotlist_add_url(browser_window_get_url(bw));
- ami_gui_update_hotlist_button(gwin);
-}
-
-HOOKF(void, ami_menu_item_hotlist_show, APTR, window, struct IntuiMessage *)
-{
- ami_hotlist_present();
-}
-
-HOOKF(void, ami_menu_item_hotlist_entries, APTR, window, struct IntuiMessage *)
-{
- nsurl *url = hook->h_Data;
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- if(url == NULL) return;
-
- browser_window_navigate(gwin->gw->bw,
- url,
- NULL,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
-}
-
-HOOKF(void, ami_menu_item_settings_edit, APTR, window, struct IntuiMessage *)
-{
- ami_gui_opts_open();
-}
-
-HOOKF(void, ami_menu_item_settings_snapshot, APTR, window, struct IntuiMessage *)
-{
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- nsoption_set_int(window_x, gwin->win->LeftEdge);
- nsoption_set_int(window_y, gwin->win->TopEdge);
- nsoption_set_int(window_width, gwin->win->Width);
- nsoption_set_int(window_height, gwin->win->Height);
-}
-
-HOOKF(void, ami_menu_item_settings_save, APTR, window, struct IntuiMessage *)
-{
- ami_nsoption_write();
-}
-
-HOOKF(void, ami_menu_item_arexx_execute, APTR, window, struct IntuiMessage *)
-{
- char *temp;
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- if(AslRequestTags(filereq,
- ASLFR_Window, gwin->win,
- ASLFR_SleepWindow, TRUE,
- ASLFR_TitleText, messages_get("NetSurf"),
- ASLFR_Screen, scrn,
- ASLFR_DoSaveMode, FALSE,
- ASLFR_InitialDrawer, nsoption_charp(arexx_dir),
- ASLFR_InitialPattern, "#?.nsrx",
- TAG_DONE)) {
- if((temp = malloc(1024))) {
- strlcpy(temp, filereq->fr_Drawer, 1024);
- AddPart(temp, filereq->fr_File, 1024);
- ami_arexx_execute(temp);
- free(temp);
- }
- }
-}
-
-HOOKF(void, ami_menu_item_arexx_entries, APTR, window, struct IntuiMessage *)
-{
- char *script = hook->h_Data;
- char *temp;
- struct gui_window_2 *gwin;
- GetAttr(WINDOW_UserData, (Object *)window, (ULONG *)&gwin);
-
- if(script) {
- if((temp = malloc(1024))) {
- BPTR lock;
- if((lock = Lock(nsoption_charp(arexx_dir), SHARED_LOCK))) {
- DevNameFromLock(lock, temp, 1024, DN_FULLPATH);
- AddPart(temp, script, 1024);
- ami_arexx_execute(temp);
- free(temp);
- UnLock(lock);
- }
- }
- }
-}
-
-
-/* menu creation code */
static void ami_menu_free_labs(struct ami_menu_data **md, int max)
{
int i;
for(i = 0; i <= max; i++) {
- if(md[i] == NULL) continue;
- if(md[i]->menulab && (md[i]->menulab != NM_BARLABEL)) {
- if(md[i]->menutype & MENU_IMAGE) {
- if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
- }
-
- ami_utf8_free(md[i]->menulab);
- }
-
- md[i]->menulab = NULL;
- md[i]->menuobj = NULL;
- md[i]->menukey = 0;
- md[i]->menutype = 0;
- free(md[i]);
- }
-}
-
-void ami_free_menulabs(struct ami_menu_data **md)
-{
- int i;
-
- for(i=0;i<=AMI_MENU_AREXX_MAX;i++) {
- if(md[i] == NULL) continue;
- if(md[i]->menulab && (md[i]->menulab != NM_BARLABEL)) {
- if(md[i]->menutype & MENU_IMAGE) {
- if(md[i]->menuobj) DisposeObject(md[i]->menuobj);
- }
-
- ami_utf8_free(md[i]->menulab);
-
- if(i >= AMI_MENU_AREXX) {
- if(md[i]->menu_hook.h_Data) free(md[i]->menu_hook.h_Data);
- md[i]->menu_hook.h_Data = NULL;
- }
- }
-
- md[i]->menulab = NULL;
- md[i]->menuobj = NULL;
- md[i]->menukey = 0;
- md[i]->menutype = 0;
- free(md[i]);
+ ami_menu_free_lab_item(md, i);
}
}
void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE type,
- const char *restrict label, char key, const char *restrict icon,
+ const char *restrict label, const char *restrict key, const char *restrict icon,
void *restrict func, void *restrict hookdata, UWORD flags)
{
- char menu_icon[1024];
-
md[num] = calloc(1, sizeof(struct ami_menu_data));
md[num]->menutype = type;
md[num]->flags = flags;
@@ -606,12 +124,9 @@ void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE
type,
if((label == NM_BARLABEL) || (strcmp(label, "--") == 0)) {
md[num]->menulab = NM_BARLABEL;
+ icon = NULL;
} else { /* horrid non-generic stuff */
- if((num >= AMI_MENU_HOTLIST) && (num <= AMI_MENU_HOTLIST_MAX)) {
- utf8_from_local_encoding(label,
- (strlen(label) < NSA_MAX_HOTLIST_MENU_LEN) ? strlen(label) :
NSA_MAX_HOTLIST_MENU_LEN,
- (char **)&md[num]->menulab);
- } else if((num >= AMI_MENU_AREXX) && (num < AMI_MENU_AREXX_MAX)) {
+ if((num >= AMI_MENU_AREXX) && (num < AMI_MENU_AREXX_MAX)) {
md[num]->menulab = strdup(label);
} else {
md[num]->menulab = ami_utf8_easy(messages_get(label));
@@ -619,11 +134,13 @@ void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE
type,
}
md[num]->menuicon = NULL;
- if(key) md[num]->menukey = key;
+ if(key) md[num]->menukey = strdup(key);
if(func) md[num]->menu_hook.h_Entry = (HOOKFUNC)func;
if(hookdata) md[num]->menu_hook.h_Data = hookdata;
#ifdef __amigaos4__
+ char menu_icon[1024];
+
if(LIB_IS_AT_LEAST((struct Library *)GadToolsBase, 53, 7)) {
if(icon) {
if(ami_locate_resource(menu_icon, icon) == true) {
@@ -637,154 +154,6 @@ void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE
type,
#endif
}
-static void ami_init_menulabs(struct ami_menu_data **md)
-{
- UWORD js_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(enable_javascript) == true)
- js_flags |= CHECKED;
-
- UWORD imgfore_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(foreground_images) == true)
- imgfore_flags |= CHECKED;
-
- UWORD imgback_flags = CHECKIT | MENUTOGGLE;
- if(nsoption_bool(background_images) == true)
- imgback_flags |= CHECKED;
-
- ami_menu_alloc_item(md, M_PROJECT, NM_TITLE, "Project", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_NEWWIN, NM_ITEM, "NewWindowNS", 'N',
"TBImages:list_app",
- ami_menu_item_project_newwin, NULL, 0);
- ami_menu_alloc_item(md, M_NEWTAB, NM_ITEM, "NewTab", 'T',
"TBImages:list_tab",
- ami_menu_item_project_newtab, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_OPEN, NM_ITEM, "OpenFile", 'O',
"TBImages:list_folder_misc",
- ami_menu_item_project_open, NULL, 0);
- ami_menu_alloc_item(md, M_SAVEAS, NM_ITEM, "SaveAsNS", 0,
"TBImages:list_saveas", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SAVESRC, NM_SUB, "Source", 'S',
NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_SOURCE, 0);
- ami_menu_alloc_item(md, M_SAVETXT, NM_SUB, "TextNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_TEXT, 0);
- ami_menu_alloc_item(md, M_SAVECOMP, NM_SUB, "SaveCompNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_COMPLETE, 0);
-#ifdef WITH_PDF_EXPORT
- ami_menu_alloc_item(md, M_SAVEPDF, NM_SUB, "PDFNS", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_PDF, 0);
-#endif
- ami_menu_alloc_item(md, M_SAVEIFF, NM_SUB, "IFF", 0, NULL,
- ami_menu_item_project_save, (void *)AMINS_SAVE_IFF, 0);
- ami_menu_alloc_item(md, M_BAR_P2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_PRINT, NM_ITEM, "PrintNS", 'P',
"TBImages:list_print",
- ami_menu_item_project_print, NULL, NM_ITEMDISABLED);
- ami_menu_alloc_item(md, M_BAR_P3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_CLOSETAB, NM_ITEM, "CloseTab", 'K',
"TBImages:list_remove",
- ami_menu_item_project_closetab, NULL, 0);
- ami_menu_alloc_item(md, M_CLOSEWIN, NM_ITEM, "CloseWindow", 0,
"TBImages:list_cancel",
- ami_menu_item_project_closewin, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P4, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, M_ABOUT, NM_ITEM, "About", '?',
"TBImages:list_info",
- ami_menu_item_project_about, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_P5, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL,
0);
- ami_menu_alloc_item(md, M_QUIT, NM_ITEM, "Quit", 'Q',
"TBImages:list_warning",
- ami_menu_item_project_quit, NULL, 0);
-
- ami_menu_alloc_item(md, M_EDIT, NM_TITLE, "Edit", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_CUT, NM_ITEM, "CutNS", 'X',
"TBImages:list_cut",
- ami_menu_item_edit_cut, NULL, 0);
- ami_menu_alloc_item(md, M_COPY, NM_ITEM, "CopyNS", 'C',
"TBImages:list_copy",
- ami_menu_item_edit_copy, NULL, 0);
- ami_menu_alloc_item(md, M_PASTE, NM_ITEM, "PasteNS", 'V',
"TBImages:list_paste",
- ami_menu_item_edit_paste, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_E1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SELALL, NM_ITEM, "SelectAllNS", 'A',
NSA_SPACE,
- ami_menu_item_edit_selectall, NULL, 0);
- ami_menu_alloc_item(md, M_CLEAR, NM_ITEM, "ClearNS", 0, NSA_SPACE,
- ami_menu_item_edit_clearsel, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_E2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_UNDO, NM_ITEM, "Undo", 'Z',
"TBImages:list_undo",
- ami_menu_item_edit_undo, NULL, 0);
- ami_menu_alloc_item(md, M_REDO, NM_ITEM, "Redo", 'Y',
"TBImages:list_redo",
- ami_menu_item_edit_redo, NULL, 0);
-
- ami_menu_alloc_item(md, M_BROWSER, NM_TITLE, "Browser", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_FIND, NM_ITEM, "FindTextNS", 'F',
"TBImages:list_search",
- ami_menu_item_browser_find, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_HISTLOCL, NM_ITEM, "HistLocalNS", 0,
"TBImages:list_history",
- ami_menu_item_browser_localhistory, NULL, 0);
- ami_menu_alloc_item(md, M_HISTGLBL, NM_ITEM, "HistGlobalNS", 0,
"TBImages:list_history",
- ami_menu_item_browser_globalhistory, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B2, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_COOKIES, NM_ITEM, "ShowCookiesNS", 0,
"TBImages:list_internet",
- ami_menu_item_browser_cookies, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_B3, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SCALE, NM_ITEM, "ScaleNS", 0,
"TBImages:list_preview", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SCALEDEC, NM_SUB, "ScaleDec", '-',
"TBImages:list_zoom_out",
- ami_menu_item_browser_scale_decrease, NULL, 0);
- ami_menu_alloc_item(md, M_SCALENRM, NM_SUB, "ScaleNorm", '=',
"TBImages:list_zoom_100",
- ami_menu_item_browser_scale_normal, NULL, 0);
- ami_menu_alloc_item(md, M_SCALEINC, NM_SUB, "ScaleInc", '+',
"TBImages:list_zoom_in",
- ami_menu_item_browser_scale_increase, NULL, 0);
- ami_menu_alloc_item(md, M_IMAGES, NM_ITEM, "Images", 0,
"TBImages:list_image", NULL, NULL, 0);
- ami_menu_alloc_item(md, M_IMGFORE, NM_SUB, "ForeImg", 0, NULL,
- ami_menu_item_browser_foreimg, NULL, imgfore_flags);
- ami_menu_alloc_item(md, M_IMGBACK, NM_SUB, "BackImg", 0, NULL,
- ami_menu_item_browser_backimg, NULL, imgback_flags);
- ami_menu_alloc_item(md, M_JS, NM_ITEM, "EnableJS", 0, NULL,
- ami_menu_item_browser_enablejs, NULL, js_flags);
- ami_menu_alloc_item(md, M_BAR_B4, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_REDRAW, NM_ITEM, "Redraw", 0,
"TBImages:list_wand",
- ami_menu_item_browser_redraw, NULL, 0);
-
- ami_menu_alloc_item(md, M_HOTLIST, NM_TITLE, "Hotlist", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_HLADD, NM_ITEM, "HotlistAdd", 'B',
"TBImages:list_favouriteadd",
- ami_menu_item_hotlist_add, NULL, 0);
- ami_menu_alloc_item(md, M_HLSHOW, NM_ITEM,"HotlistShowNS",'H',
"TBImages:list_favourite",
- ami_menu_item_hotlist_show, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_H1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
-
- ami_menu_alloc_item(md, M_PREFS, NM_TITLE, "Settings", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_PREDIT, NM_ITEM, "SettingsEdit", 0,
"TBImages:list_prefs",
- ami_menu_item_settings_edit, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_S1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, M_SNAPSHOT, NM_ITEM, "SnapshotWindow",0,
"TBImages:list_hold",
- ami_menu_item_settings_snapshot, NULL, 0);
- ami_menu_alloc_item(md, M_PRSAVE, NM_ITEM, "SettingsSave", 0,
"TBImages:list_use",
- ami_menu_item_settings_save, NULL, 0);
-
- ami_menu_alloc_item(md, M_AREXX, NM_TITLE, "ARexx", 0, NULL, NULL,
NULL, 0);
- ami_menu_alloc_item(md, M_AREXXEX, NM_ITEM, "ARexxExecute",'E',
"TBImages:list_arexx",
- ami_menu_item_arexx_execute, NULL, 0);
- ami_menu_alloc_item(md, M_BAR_A1, NM_ITEM, NM_BARLABEL, 0, NULL, NULL, NULL, 0);
- ami_menu_alloc_item(md, AMI_MENU_AREXX_MAX, NM_END, NULL, 0, NULL, NULL, NULL,
0);
-}
-
-/* Menu refresh for hotlist */
-void ami_menu_refresh(struct gui_window_2 *gwin)
-{
- return; /**\todo fix this after migrating to menuclass */
-
- struct Menu *menu;
-
- LOG("Clearing MenuStrip");
- SetAttrs(gwin->objects[OID_MAIN],
- WINDOW_MenuStrip, NULL,
- TAG_DONE);
-
- LOG("Freeing menu");
- ami_menu_free(gwin);
-
- LOG("Freeing menu labels");
- ami_free_menulabs(gwin->menu_data);
-
- LOG("Creating new menu");
- menu = ami_menu_create(gwin);
-
- LOG("Attaching MenuStrip %p to %p", menu, gwin->objects[OID_MAIN]);
- SetAttrs(gwin->objects[OID_MAIN],
- WINDOW_MenuStrip, menu,
- TAG_DONE);
-}
-
static void ami_menu_load_glyphs(struct DrawInfo *dri)
{
#ifdef __amigaos4__
@@ -836,7 +205,7 @@ static int ami_menu_calc_item_width(struct ami_menu_data **md, int j,
struct Ras
item_size += space_width;
if(md[j]->menukey) {
- item_size += TextLength(rp, &md[j]->menukey, 1);
+ item_size += TextLength(rp, md[j]->menukey, 1);
item_size += menu_glyph_width[NSA_GLYPH_AMIGAKEY];
/**TODO: take account of the size of other imagery too
*/
@@ -853,8 +222,73 @@ static int ami_menu_calc_item_width(struct ami_menu_data **md, int j,
struct Ras
return item_size;
}
+#ifdef __amigaos4__
+static int ami_menu_layout_mc_recursive(Object *menu_parent, struct ami_menu_data **md,
int level, int i, int max)
+{
+ int j;
+ Object *menu_item = menu_parent;
+
+ for(j = i; j < max; j++) {
+ /* skip empty entries */
+ if(md[j] == NULL) continue;
+ if(md[j]->menutype == NM_IGNORE) continue;
+
+ if(md[j]->menutype == level) {
+ if(md[j]->menulab == NM_BARLABEL)
+ md[j]->menulab = ML_SEPARATOR;
+
+ if(level == NM_TITLE) {
+ menu_item = NewObject(NULL, "menuclass",
+ MA_Type, T_MENU,
+ MA_ID, j,
+ MA_Label, md[j]->menulab,
+ TAG_DONE);
+ } else {
+ menu_item = NewObject(NULL, "menuclass",
+ MA_Type, T_ITEM,
+ MA_ID, j,
+ MA_Label, md[j]->menulab,
+ MA_Image,
+ BitMapObj,
+ IA_Scalable, TRUE,
+ BITMAP_Screen, scrn,
+ BITMAP_SourceFile, md[j]->menuicon,
+ BITMAP_Masking, TRUE,
+ BitMapEnd,
+ MA_Key, md[j]->menukey,
+ MA_UserData, &md[j]->menu_hook, /* NB: Intentionally UserData */
+ MA_Disabled, (md[j]->flags & NM_ITEMDISABLED),
+ MA_Selected, (md[j]->flags & CHECKED),
+ MA_Toggle, (md[j]->flags & MENUTOGGLE),
+ TAG_DONE);
+ }
-struct Menu *ami_menu_layout(struct ami_menu_data **md, int max)
+ //LOG("Adding item %p ID %d (%s) to parent %p", menu_item, j,
md[j]->menulab, menu_parent);
+ IDoMethod(menu_parent, OM_ADDMEMBER, menu_item);
+ continue;
+ } else if (md[j]->menutype > level) {
+ j = ami_menu_layout_mc_recursive(menu_item, md, md[j]->menutype, j, max);
+ } else {
+ break;
+ }
+ }
+ return (j - 1);
+}
+
+static struct Menu *ami_menu_layout_mc(struct ami_menu_data **md, int max)
+{
+ Object *menu_root = NewObject(NULL, "menuclass",
+ MA_Type, T_ROOT,
+ MA_EmbeddedKey, FALSE,
+ TAG_DONE);
+
+ ami_menu_layout_mc_recursive(menu_root, md, NM_TITLE, 0, max);
+
+ return (struct Menu *)menu_root;
+}
+#endif
+
+static struct Menu *ami_menu_layout_gt(struct ami_menu_data **md, int max)
{
int i, j;
int txtlen = 0;
@@ -955,7 +389,9 @@ struct Menu *ami_menu_layout(struct ami_menu_data **md, int max)
else
nm[i].nm_Label = md[i]->menulab;
- if(md[i]->menukey) nm[i].nm_CommKey = &md[i]->menukey;
+ if((md[i]->menukey) && (strlen(md[i]->menukey) > 1)) {
+ nm[i].nm_CommKey = md[i]->menukey;
+ }
nm[i].nm_Flags = md[i]->flags;
if(md[i]->menu_hook.h_Entry) nm[i].nm_UserData = &md[i]->menu_hook;
@@ -977,226 +413,59 @@ struct Menu *ami_menu_layout(struct ami_menu_data **md, int max)
return imenu;
}
-void ami_menu_free(struct gui_window_2 *gwin)
+struct Menu *ami_menu_layout(struct ami_menu_data **md, int max)
{
- FreeMenus(gwin->imenu);
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+#ifdef __amigaos4__
+ return ami_menu_layout_mc(md, max);
+#endif
+ } else {
+ return ami_menu_layout_gt(md, max);
+ }
}
void ami_menu_free_menu(struct ami_menu_data **md, int max, struct Menu *imenu)
{
ami_menu_free_labs(md, max);
- FreeMenus(imenu);
-}
-
-struct Menu *ami_menu_create(struct gui_window_2 *gwin)
-{
- ami_init_menulabs(gwin->menu_data);
- ami_menu_scan(gwin->menu_data); //\todo this needs to be MenuClass created
- ami_menu_arexx_scan(gwin->menu_data);
- gwin->imenu = ami_menu_layout(gwin->menu_data, AMI_MENU_AREXX_MAX);
-
- return gwin->imenu;
-}
-
-void ami_menu_arexx_scan(struct ami_menu_data **md)
-{
- /**\todo Rewrite this to not use ExAll() **/
- int item = AMI_MENU_AREXX;
- BPTR lock = 0;
- UBYTE *buffer;
- struct ExAllControl *ctrl;
- char matchpatt[16];
- LONG cont;
- struct ExAllData *ead;
- char *menu_lab;
-
- if((lock = Lock(nsoption_charp(arexx_dir), SHARED_LOCK))) {
- if((buffer = malloc(1024))) {
- if((ctrl = AllocDosObject(DOS_EXALLCONTROL,NULL))) {
- ctrl->eac_LastKey = 0;
-
- if(ParsePatternNoCase("#?.nsrx",(char *)&matchpatt,16) != -1) {
- ctrl->eac_MatchString = (char *)&matchpatt;
- }
-
- do {
- cont = ExAll(lock,(struct ExAllData *)buffer,1024,ED_COMMENT,ctrl);
- if((!cont) && (IoErr() != ERROR_NO_MORE_ENTRIES)) break;
- if(!ctrl->eac_Entries) continue;
-
- for(ead = (struct ExAllData *)buffer; ead; ead = ead->ed_Next) {
- if(item >= AMI_MENU_AREXX_MAX) continue;
- if(EAD_IS_FILE(ead)) {
- if(ead->ed_Comment[0] != '\0')
- menu_lab = ead->ed_Comment;
- else
- menu_lab = ead->ed_Name;
-
- ami_menu_alloc_item(md, item, NM_ITEM, menu_lab, 0, NSA_SPACE,
- ami_menu_item_arexx_entries, (void *)strdup(ead->ed_Name), 0);
-
- item++;
- }
- }
- } while(cont);
- FreeDosObject(DOS_EXALLCONTROL,ctrl);
- }
- free(buffer);
- }
- UnLock(lock);
- }
-
- ami_menu_alloc_item(md, item, NM_END, NULL, 0, NULL, NULL, NULL, 0);
-}
-
-static bool ami_menu_hotlist_add(void *userdata, int level, int item, const char *title,
nsurl *url, bool is_folder)
-{
- UBYTE type;
- STRPTR icon;
- UWORD flags = 0;
- struct ami_menu_data **md = (struct ami_menu_data **)userdata;
-
- if(item >= AMI_MENU_HOTLIST_MAX) return false;
-
- switch(level) {
- case 1:
- type = NM_ITEM;
- break;
- case 2:
- type = NM_SUB;
- break;
- default:
- /* entries not at level 1 or 2 are not able to be added
- * \todo construct menus using menuclass instead! */
- return false;
- break;
- }
-
- if(is_folder == true) {
- icon = ASPrintf("icons/directory.png");
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ DisposeObject((Object *)imenu); // if we detach our menu from the window we need to do
this manually
} else {
- icon = ami_gui_get_cache_favicon_name(url, true);
- if (icon == NULL) icon = ASPrintf("icons/content.png");
+ FreeMenus(imenu);
}
-
- if((is_folder == true) && (type == NM_SUB)) {
- flags = NM_ITEMDISABLED;
- }
-
- ami_menu_alloc_item(md, item, type, title,
- 0, icon, ami_menu_item_hotlist_entries, (void *)url, flags);
-
- if(icon) FreeVec(icon);
-
- return true;
-}
-
-static nserror ami_menu_scan(struct ami_menu_data **md)
-{
- return ami_hotlist_scan((void *)md, AMI_MENU_HOTLIST,
messages_get("HotlistMenu"), ami_menu_hotlist_add);
}
-void ami_menu_update_checked(struct gui_window_2 *gwin)
+void ami_menu_refresh(struct Menu *menu, struct ami_menu_data **md, int menu_item, int
max,
+ nserror (*cb)(struct ami_menu_data **md))
{
- struct Menu *menustrip;
-
- GetAttr(WINDOW_MenuStrip, gwin->objects[OID_MAIN], (ULONG *)&menustrip);
- if(!menustrip) return;
- if(nsoption_bool(enable_javascript) == true) {
- if((ItemAddress(menustrip, AMI_MENU_JS)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_JS)->Flags ^= CHECKED;
- } else {
- if(ItemAddress(menustrip, AMI_MENU_JS)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_JS)->Flags ^= CHECKED;
- }
- if(nsoption_bool(foreground_images) == true) {
- if((ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags ^= CHECKED;
- } else {
- if(ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_FOREIMG)->Flags ^= CHECKED;
- }
-
- if(nsoption_bool(background_images) == true) {
- if((ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags & CHECKED) == 0)
- ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags ^= CHECKED;
- } else {
- if(ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags & CHECKED)
- ItemAddress(menustrip, AMI_MENU_BACKIMG)->Flags ^= CHECKED;
- }
+#ifdef __amigaos4__
+ Object *restrict obj;
+ Object *restrict menu_item_obj;
+ int i;
- ResetMenuStrip(gwin->win, menustrip);
-}
+ if(menu == NULL) return;
-void ami_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c)
-{
- struct Window *win = g->shared->win;
+ if(LIB_IS_AT_LEAST((struct Library *)IntuitionBase, 54, 6)) {
+ /* find the address of the menu */
+ menu_item_obj = (Object *)IDoMethod((Object *)menu, MM_FINDID, 0, menu_item);
- if(nsoption_bool(kiosk_mode) == true) return;
+ /* remove all children */
+ while((obj = (Object *)IDoMethod(menu_item_obj, MM_NEXTCHILD, 0, NULL)) != NULL) {
+ IDoMethod(menu_item_obj, OM_REMMEMBER, obj);
+ DisposeObject(obj);
+ }
- if(content_get_type(c) <= CONTENT_CSS)
- {
- OnMenu(win,AMI_MENU_SAVEAS_TEXT);
- OnMenu(win,AMI_MENU_SAVEAS_COMPLETE);
-#ifdef WITH_PDF_EXPORT
- OnMenu(win,AMI_MENU_SAVEAS_PDF);
-#endif
-#if 0
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_COPY) {
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_CLEAR);
- } else {
- OffMenu(win,AMI_MENU_COPY);
- OffMenu(win,AMI_MENU_CLEAR);
+ /* free associated data */
+ for(i = (menu_item + 1); i <= max; i++) {
+ if(md[i] == NULL) continue;
+ ami_menu_free_lab_item(md, i);
}
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_CUT)
- OnMenu(win,AMI_MENU_CUT);
- else
- OffMenu(win,AMI_MENU_CUT);
-
- if(browser_window_get_editor_flags(g->bw) & BW_EDITOR_CAN_PASTE)
- OnMenu(win,AMI_MENU_PASTE);
- else
- OffMenu(win,AMI_MENU_PASTE);
-#else
- OnMenu(win,AMI_MENU_CUT);
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_PASTE);
- OnMenu(win,AMI_MENU_CLEAR);
-#endif
- OnMenu(win,AMI_MENU_SELECTALL);
- OnMenu(win,AMI_MENU_FIND);
- OffMenu(win,AMI_MENU_SAVEAS_IFF);
- }
- else
- {
- OffMenu(win,AMI_MENU_CUT);
- OffMenu(win,AMI_MENU_PASTE);
- OffMenu(win,AMI_MENU_CLEAR);
-
- OffMenu(win,AMI_MENU_SAVEAS_TEXT);
- OffMenu(win,AMI_MENU_SAVEAS_COMPLETE);
-#ifdef WITH_PDF_EXPORT
- OffMenu(win,AMI_MENU_SAVEAS_PDF);
-#endif
- OffMenu(win,AMI_MENU_SELECTALL);
- OffMenu(win,AMI_MENU_FIND);
+ /* get current data */
+ cb(md);
-#ifdef WITH_NS_SVG
- if(content_get_bitmap(c) || (ami_mime_compare(c, "svg") == true))
-#else
- if(content_get_bitmap(c))
-#endif
- {
- OnMenu(win,AMI_MENU_COPY);
- OnMenu(win,AMI_MENU_SAVEAS_IFF);
- }
- else
- {
- OffMenu(win,AMI_MENU_COPY);
- OffMenu(win,AMI_MENU_SAVEAS_IFF);
- }
+ /* re-add items to menu */
+ ami_menu_layout_mc_recursive(menu_item_obj, md, NM_ITEM, (menu_item + 1), max);
}
+#endif
}
diff --git a/frontends/amiga/menu.h b/frontends/amiga/menu.h
index ad0e96d..358faa4 100644
--- a/frontends/amiga/menu.h
+++ b/frontends/amiga/menu.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008,2009,2013 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
+ * Copyright 2017 Chris Young <chris(a)unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf,
http://www.netsurf-browser.org/
*
@@ -23,156 +23,37 @@
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
-struct hlcache_handle;
-struct ami_menu_data;
+struct ami_menu_data {
+ char *restrict menulab;
+ Object *restrict menuobj;
+ char *restrict menukey;
+ char *restrict menuicon;
+ struct Hook menu_hook;
+ UBYTE menutype;
+ UWORD flags;
+};
/** empty space */
#define NSA_SPACE "blankspace.png"
-/** Maximum number of hotlist items (somewhat arbitrary value) */
-#define AMI_HOTLIST_ITEMS 60
-
-/** Maximum number of ARexx menu items (somewhat arbitrary value) */
-#define AMI_MENU_AREXX_ITEMS 20
-
-/** enum menu structure, has to be here as we need it below. */
-enum {
- /* Project menu */
- M_PROJECT = 0,
- M_NEWWIN,
- M_NEWTAB,
- M_BAR_P1,
- M_OPEN,
- M_SAVEAS,
- M_SAVESRC,
- M_SAVETXT,
- M_SAVECOMP,
- M_SAVEIFF,
-#ifdef WITH_PDF_EXPORT
- M_SAVEPDF,
-#endif
- M_BAR_P2,
- M_PRINT,
- M_BAR_P3,
- M_CLOSETAB,
- M_CLOSEWIN,
- M_BAR_P4,
- M_ABOUT,
- M_BAR_P5,
- M_QUIT,
- /* Edit menu */
- M_EDIT,
- M_CUT,
- M_COPY,
- M_PASTE,
- M_BAR_E1,
- M_SELALL,
- M_CLEAR,
- M_BAR_E2,
- M_UNDO,
- M_REDO,
- /* Browser menu */
- M_BROWSER,
- M_FIND,
- M_BAR_B1,
- M_HISTLOCL,
- M_HISTGLBL,
- M_BAR_B2,
- M_COOKIES,
- M_BAR_B3,
- M_SCALE,
- M_SCALEDEC,
- M_SCALENRM,
- M_SCALEINC,
- M_IMAGES,
- M_IMGFORE,
- M_IMGBACK,
- M_JS,
- M_BAR_B4,
- M_REDRAW,
- /* Hotlist menu */
- M_HOTLIST,
- M_HLADD,
- M_HLSHOW,
- M_BAR_H1, // 47
- AMI_MENU_HOTLIST, /* Where the hotlist entries start */
- AMI_MENU_HOTLIST_MAX = AMI_MENU_HOTLIST + AMI_HOTLIST_ITEMS,
- /* Settings menu */
- M_PREFS,
- M_PREDIT,
- M_BAR_S1,
- M_SNAPSHOT,
- M_PRSAVE,
- /* ARexx menu */
- M_AREXX,
- M_AREXXEX,
- M_BAR_A1,
- AMI_MENU_AREXX,
- AMI_MENU_AREXX_MAX = AMI_MENU_AREXX + AMI_MENU_AREXX_ITEMS
-};
-
-/* We can get away with AMI_MENU_MAX falling short as it is
- * only used for freeing the UTF-8 converted menu labels */
-#define AMI_MENU_MAX AMI_MENU_AREXX
-
-/* The Intuition menu numbers of some menus we might need to modify */
-#define AMI_MENU_SAVEAS_TEXT FULLMENUNUM(0,4,1)
-#define AMI_MENU_SAVEAS_COMPLETE FULLMENUNUM(0,4,2)
-#define AMI_MENU_SAVEAS_IFF FULLMENUNUM(0,4,3)
-#define AMI_MENU_SAVEAS_PDF FULLMENUNUM(0,4,4)
-#define AMI_MENU_CLOSETAB FULLMENUNUM(0,8,0)
-#define AMI_MENU_CUT FULLMENUNUM(1,0,0)
-#define AMI_MENU_COPY FULLMENUNUM(1,1,0)
-#define AMI_MENU_PASTE FULLMENUNUM(1,2,0)
-#define AMI_MENU_SELECTALL FULLMENUNUM(1,4,0)
-#define AMI_MENU_CLEAR FULLMENUNUM(1,5,0)
-#define AMI_MENU_UNDO FULLMENUNUM(1,8,0)
-#define AMI_MENU_REDO FULLMENUNUM(1,9,0)
-#define AMI_MENU_FIND FULLMENUNUM(2,0,0)
-#define AMI_MENU_FOREIMG FULLMENUNUM(2,8,0)
-#define AMI_MENU_BACKIMG FULLMENUNUM(2,8,1)
-#define AMI_MENU_JS FULLMENUNUM(2,9,0)
-
-struct gui_window;
-struct gui_window_2;
-
/* cleanup */
void ami_menu_free_glyphs(void);
/* generic menu alloc/free/layout */
void ami_menu_alloc_item(struct ami_menu_data **md, int num, UBYTE type,
- const char *restrict label, char key, const char *restrict icon,
+ const char *restrict label, const char *restrict key, const char *restrict icon,
void *restrict func, void *restrict hookdata, UWORD flags);
struct Menu *ami_menu_layout(struct ami_menu_data **md, int max);
void ami_menu_free_menu(struct ami_menu_data **md, int max, struct Menu *imenu);
+void ami_menu_free_lab_item(struct ami_menu_data **md, int i);
-/* specific to browser windows */
-void ami_free_menulabs(struct ami_menu_data **md);
-struct Menu *ami_menu_create(struct gui_window_2 *gwin);
-void ami_menu_refresh(struct gui_window_2 *gwin);
-void ami_menu_update_checked(struct gui_window_2 *gwin);
-void ami_menu_update_disabled(struct gui_window *g, struct hlcache_handle *c);
-void ami_menu_free(struct gui_window_2 *gwin);
+/* refresh a menu's children */
+void ami_menu_refresh(struct Menu *menu, struct ami_menu_data **md, int menu_item, int
max,
+ nserror (*cb)(struct ami_menu_data **md));
/**
- * Sets that an item linked to a toggle menu item has been changed.
- */
-void ami_menu_set_check_toggled(void);
-
-/**
- * Gets if the menu needs updating because an item linked
- * to a toggle menu item has been changed.
- * NB: This also *clears* the state
- *
- * \return true if the menus need refreshing
- */
-bool ami_menu_get_check_toggled(void);
-
-/**
- * Gets if NetSurf has been quit from the menu
- *
- * \return true if NetSurf has been quit
+ * Get the selected state of a menu item
*/
-bool ami_menu_quit_selected(void);
+bool ami_menu_get_selected(struct Menu *menu, struct IntuiMessage *msg);
#endif
diff --git a/frontends/atari/bitmap.c b/frontends/atari/bitmap.c
index d0de378..cbb7195 100644
--- a/frontends/atari/bitmap.c
+++ b/frontends/atari/bitmap.c
@@ -16,12 +16,12 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#include <inttypes.h>
#include <sys/types.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
+#include "netsurf/inttypes.h"
#include "utils/nsoption.h"
#include "utils/log.h"
#include "netsurf/bitmap.h"
diff --git a/frontends/atari/cookies.c b/frontends/atari/cookies.c
index b7f7309..9045009 100644
--- a/frontends/atari/cookies.c
+++ b/frontends/atari/cookies.c
@@ -18,6 +18,7 @@
#include <assert.h>
+#include "netsurf/inttypes.h"
#include "utils/log.h"
#include "utils/messages.h"
#include "netsurf/mouse.h"
diff --git a/frontends/atari/deskmenu.c b/frontends/atari/deskmenu.c
index 77df4e5..addba27 100644
--- a/frontends/atari/deskmenu.c
+++ b/frontends/atari/deskmenu.c
@@ -23,6 +23,7 @@
#include "utils/nsurl.h"
#include "utils/messages.h"
#include "utils/nsoption.h"
+#include "utils/utils.h"
#include "netsurf/browser_window.h"
#include "netsurf/keypress.h"
#include "desktop/save_complete.h"
diff --git a/frontends/atari/download.c b/frontends/atari/download.c
index 3e7a685..d756e66 100644
--- a/frontends/atari/download.c
+++ b/frontends/atari/download.c
@@ -28,9 +28,9 @@
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
#include "utils/nsoption.h"
#include "utils/string.h"
+#include "netsurf/inttypes.h"
#include "netsurf/browser_window.h"
#include "netsurf/download.h"
#include "desktop/save_complete.h"
diff --git a/frontends/atari/font.c b/frontends/atari/font.c
index 5402e78..7971655 100644
--- a/frontends/atari/font.c
+++ b/frontends/atari/font.c
@@ -16,11 +16,11 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#include <inttypes.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
+#include "netsurf/inttypes.h"
#include "utils/utf8.h"
#include "utils/log.h"
#include "utils/nsoption.h"
diff --git a/frontends/atari/gemtk/guiwin.c b/frontends/atari/gemtk/guiwin.c
index ea0f8f9..84c7af8 100644
--- a/frontends/atari/gemtk/guiwin.c
+++ b/frontends/atari/gemtk/guiwin.c
@@ -127,7 +127,7 @@ error:
*/
static short preproc_wm(GUIWIN * gw, EVMULT_OUT *ev_out, short msg[8])
{
- GRECT g, g_ro, g2;
+ GRECT g, g2;
short retval = 1;
int val = 1;
struct gemtk_wm_scroll_info_s *slid;
@@ -169,7 +169,6 @@ static short preproc_wm(GUIWIN * gw, EVMULT_OUT *ev_out, short
msg[8])
slid = gemtk_wm_get_scroll_info(gw);
gemtk_wm_get_grect(gw, GEMTK_WM_AREA_CONTENT, &g);
- g_ro = g;
switch(msg[4]) {
@@ -471,67 +470,66 @@ static short preproc_mu_keybd(GUIWIN * gw, EVMULT_OUT *ev_out, short
msg[8])
{
short retval = 0;
- if ((gw->toolbar != NULL) && (gw->toolbar_edit_obj > -1)) {
+ if ((gw->toolbar != NULL) && (gw->toolbar_edit_obj > -1)) {
- short next_edit_obj = gw->toolbar_edit_obj;
- short next_char = -1;
- short edit_idx;
- short r;
+ short next_edit_obj = gw->toolbar_edit_obj;
+ short next_char = -1;
+ short edit_idx;
- DEBUG_PRINT(("%s, gw: %p, toolbar_edit_obj: %d\n", __FUNCTION__, gw,
- gw->toolbar_edit_obj));
+ DEBUG_PRINT(("%s, gw: %p, toolbar_edit_obj: %d\n",
+ __FUNCTION__, gw,
+ gw->toolbar_edit_obj));
- r = form_wkeybd(gw->toolbar, gw->toolbar_edit_obj, next_edit_obj,
- ev_out->emo_kreturn,
- &next_edit_obj, &next_char, gw->handle);
+ form_wkeybd(gw->toolbar, gw->toolbar_edit_obj, next_edit_obj,
+ ev_out->emo_kreturn,
+ &next_edit_obj, &next_char, gw->handle);
- if (next_edit_obj != gw->toolbar_edit_obj) {
+ if (next_edit_obj != gw->toolbar_edit_obj) {
gemtk_wm_set_toolbar_edit_obj(gw, next_edit_obj,
- ev_out->emo_kreturn);
- } else {
- if (next_char > 13) {
- r = objc_wedit(gw->toolbar, gw->toolbar_edit_obj,
- ev_out->emo_kreturn, &edit_idx,
- EDCHAR, gw->handle);
- }
- }
- //retval = 1;
- /*gemtk_wm_send_msg(gw, GEMTK_WM_WM_FORM_KEY, gw->toolbar_edit_obj,
- ev_out->emo_kreturn, 0, 0);*/
- }
+ ev_out->emo_kreturn);
+ } else {
+ if (next_char > 13) {
+ objc_wedit(gw->toolbar, gw->toolbar_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDCHAR, gw->handle);
+ }
+ }
+ //retval = 1;
+ /*gemtk_wm_send_msg(gw, GEMTK_WM_WM_FORM_KEY, gw->toolbar_edit_obj,
+ ev_out->emo_kreturn, 0, 0);*/
+ }
- if((gw->form != NULL) && (gw->form_edit_obj > -1) ) {
+ if ((gw->form != NULL) && (gw->form_edit_obj > -1)) {
- short next_edit_obj = gw->form_edit_obj;
- short next_char = -1;
- short edit_idx;
- short r;
+ short next_edit_obj = gw->form_edit_obj;
+ short next_char = -1;
+ short edit_idx;
- r = form_wkeybd(gw->form, gw->form_edit_obj, next_edit_obj,
- ev_out->emo_kreturn,
- &next_edit_obj, &next_char, gw->handle);
+ form_wkeybd(gw->form, gw->form_edit_obj, next_edit_obj,
+ ev_out->emo_kreturn,
+ &next_edit_obj, &next_char, gw->handle);
- if (next_edit_obj != gw->form_edit_obj) {
+ if (next_edit_obj != gw->form_edit_obj) {
if(gw->form_edit_obj != -1) {
objc_wedit(gw->form, gw->form_edit_obj,
- ev_out->emo_kreturn, &edit_idx,
- EDEND, gw->handle);
+ ev_out->emo_kreturn, &edit_idx,
+ EDEND, gw->handle);
}
- gw->form_edit_obj = next_edit_obj;
+ gw->form_edit_obj = next_edit_obj;
- objc_wedit(gw->form, gw->form_edit_obj,
- ev_out->emo_kreturn, &edit_idx,
- EDINIT, gw->handle);
- } else {
- if(next_char > 13)
- r = objc_wedit(gw->form, gw->form_edit_obj,
- ev_out->emo_kreturn, &edit_idx,
- EDCHAR, gw->handle);
- }
- }
- return(retval);
+ objc_wedit(gw->form, gw->form_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDINIT, gw->handle);
+ } else {
+ if(next_char > 13)
+ objc_wedit(gw->form, gw->form_edit_obj,
+ ev_out->emo_kreturn, &edit_idx,
+ EDCHAR, gw->handle);
+ }
+ }
+ return(retval);
}
/**
diff --git a/frontends/atari/gemtk/objc.c b/frontends/atari/gemtk/objc.c
index 855413e..3746892 100644
--- a/frontends/atari/gemtk/objc.c
+++ b/frontends/atari/gemtk/objc.c
@@ -49,6 +49,7 @@ char *gemtk_obj_get_text(OBJECT * tree, short idx)
return (p);
}
+/*
static void set_text(OBJECT *obj, short idx, char * text, int len)
{
char spare[255];
@@ -63,6 +64,7 @@ static void set_text(OBJECT *obj, short idx, char * text, int len)
set_string(obj, idx, spare);
}
+*/
char gemtk_obj_set_str_safe(OBJECT * tree, short idx, const char *txt)
{
diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c
index 1cf51d3..d4a6915 100644
--- a/frontends/atari/gui.c
+++ b/frontends/atari/gui.c
@@ -386,13 +386,13 @@ static void atari_window_reformat(struct gui_window *gw)
static void gui_window_redraw_window(struct gui_window *gw)
{
- CMP_BROWSER b;
- GRECT rect;
- if (gw == NULL)
- return;
- b = gw->browser;
- window_get_grect(gw->root, BROWSER_AREA_CONTENT, &rect);
- window_schedule_redraw_grect(gw->root, &rect);
+ //CMP_BROWSER b;
+ GRECT rect;
+ if (gw == NULL)
+ return;
+ //b = gw->browser;
+ window_get_grect(gw->root, BROWSER_AREA_CONTENT, &rect);
+ window_schedule_redraw_grect(gw->root, &rect);
}
static void gui_window_update_box(struct gui_window *gw, const struct rect *rect)
diff --git a/frontends/atari/hotlist.c b/frontends/atari/hotlist.c
index ee9385d..da59916 100644
--- a/frontends/atari/hotlist.c
+++ b/frontends/atari/hotlist.c
@@ -25,9 +25,9 @@
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
#include "utils/nsoption.h"
#include "utils/nsurl.h"
+#include "netsurf/inttypes.h"
#include "netsurf/keypress.h"
#include "content/content.h"
#include "desktop/hotlist.h"
@@ -91,12 +91,12 @@ static void atari_hotlist_draw(struct core_window *cw, int x,
static void atari_hotlist_keypress(struct core_window *cw, uint32_t ucs4)
{
- GUIWIN *gemtk_win;
- GRECT area;
+ //GUIWIN *gemtk_win;
+ //GRECT area;
LOG("ucs4: %"PRIu32 , ucs4);
hotlist_keypress(ucs4);
- gemtk_win = atari_treeview_get_gemtk_window(cw);
- atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
+ //gemtk_win = atari_treeview_get_gemtk_window(cw);
+ //atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &area);
//gemtk_wm_exec_redraw(gemtk_win, &area);
}
diff --git a/frontends/atari/plot/font_freetype.c b/frontends/atari/plot/font_freetype.c
index 8b535e3..17d3c3b 100644
--- a/frontends/atari/plot/font_freetype.c
+++ b/frontends/atari/plot/font_freetype.c
@@ -262,13 +262,14 @@ static FT_Glyph ft_getglyph(const plot_font_style_t *fstyle,
uint32_t ucs4)
FT_UInt glyph_index;
FTC_ScalerRec srec;
FT_Glyph glyph;
- FT_Error error;
+ //FT_Error error;
ftc_faceid_t *ft_face;
ft_fill_scalar(fstyle, &srec);
ft_face = (ftc_faceid_t *)srec.face_id;
glyph_index = FTC_CMapCache_Lookup(ft_cmap_cache, srec.face_id, ft_face->cidx,
ucs4);
- error = FTC_ImageCache_LookupScaler(ft_image_cache,
+ //error =
+ FTC_ImageCache_LookupScaler(ft_image_cache,
&srec,
FT_LOAD_RENDER |
FT_LOAD_FORCE_AUTOHINT |
diff --git a/frontends/atari/plot/font_internal.c b/frontends/atari/plot/font_internal.c
index 6a811e3..3575bc3 100644
--- a/frontends/atari/plot/font_internal.c
+++ b/frontends/atari/plot/font_internal.c
@@ -161,7 +161,7 @@ static int pixel_pos( FONT_PLOTTER self, const plot_font_style_t *
fstyle,const
static void draw_glyph1(FONT_PLOTTER self, GRECT *inloc, uint8_t *chrp, int pitch,
uint32_t colour )
{
size_t bmpstride;
- GRECT clip;
+ //GRECT clip;
uint32_t * fontdata;
int xloop,yloop;
int stride = pitch / 8;
diff --git a/frontends/atari/redrawslots.h b/frontends/atari/redrawslots.h
index ca72a01..8ea46c4 100644
--- a/frontends/atari/redrawslots.h
+++ b/frontends/atari/redrawslots.h
@@ -22,7 +22,7 @@
#include <mt_gem.h>
-#include "utils/utils.h"
+#include "netsurf/types.h"
/**
* This is the number of redraw requests that the slotlist can store.
@@ -31,8 +31,6 @@
*/
#define MAX_REDRW_SLOTS 32
-struct rect;
-
/**
* This struct holds scheduled redraw requests.
*/
diff --git a/frontends/atari/rootwin.c b/frontends/atari/rootwin.c
index dd41e17..aa8e080 100644
--- a/frontends/atari/rootwin.c
+++ b/frontends/atari/rootwin.c
@@ -680,12 +680,12 @@ void window_close_search(ROOTWIN *rootwin)
struct browser_window *bw;
struct gui_window *gw;
GRECT area;
- OBJECT *obj;
+ //OBJECT *obj;
gw = rootwin->active_gui_window;
bw = gw->browser->bw;
- obj = gemtk_obj_get_tree(TOOLBAR);
+ //obj = gemtk_obj_get_tree(TOOLBAR);
if (gw->search != NULL) {
nsatari_search_session_destroy(gw->search);
diff --git a/frontends/atari/settings.c b/frontends/atari/settings.c
index 5759a89..ed1fb2e 100644
--- a/frontends/atari/settings.c
+++ b/frontends/atari/settings.c
@@ -32,6 +32,7 @@
#include "utils/dirent.h"
#include "utils/nsoption.h"
#include "utils/log.h"
+#include "utils/utils.h"
#include "netsurf/plot_style.h"
#include "atari/gui.h"
@@ -592,7 +593,7 @@ static void form_event(int index, int external)
else
tmp_option_memory_cache_size += 1;
- if( tmp_option_memory_cache_size < 0 )
+ if( tmp_option_memory_cache_size == 0)
tmp_option_memory_cache_size = 1;
if( tmp_option_memory_cache_size > 999 )
tmp_option_memory_cache_size = 999;
@@ -609,7 +610,7 @@ static void form_event(int index, int external)
else
tmp_option_disc_cache_size += 1;
- if( tmp_option_disc_cache_size < 0 )
+ if( tmp_option_disc_cache_size == 0 )
tmp_option_disc_cache_size = 1;
if( tmp_option_disc_cache_size > 9999 )
tmp_option_disc_cache_size = 9999;
diff --git a/frontends/atari/treeview.c b/frontends/atari/treeview.c
index 731c032..93aef6e 100644
--- a/frontends/atari/treeview.c
+++ b/frontends/atari/treeview.c
@@ -16,13 +16,13 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#include <inttypes.h>
#include <sys/types.h>
#include <string.h>
#include "assert.h"
#include "cflib.h"
+#include "netsurf/inttypes.h"
#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/messages.h"
@@ -366,11 +366,11 @@ static void __CDECL on_keybd_event(struct core_window *cw,
EVMULT_OUT *ev_out,
}
-static void __CDECL on_redraw_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8])
+static void __CDECL on_redraw_event(struct core_window *cw,
+ EVMULT_OUT *ev_out,
+ short msg[8])
{
GRECT work, clip;
- struct gemtk_wm_scroll_info_s *slid;
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
if (tv == NULL)
@@ -381,7 +381,7 @@ static void __CDECL on_redraw_event(struct core_window *cw, EVMULT_OUT
*ev_out,
atari_treeview_get_grect(cw, TREEVIEW_AREA_CONTENT, &work);
//dbg_grect("treeview work: ", &work);
- slid = gemtk_wm_get_scroll_info(tv->window);
+ gemtk_wm_get_scroll_info(tv->window);
clip = work;
@@ -390,10 +390,10 @@ static void __CDECL on_redraw_event(struct core_window *cw,
EVMULT_OUT *ev_out,
return;
}
- if (atari_treeview_is_iconified(cw) == true) {
- atari_treeview_redraw_icon(cw, &clip);
- return;
- }
+ if (atari_treeview_is_iconified(cw) == true) {
+ atari_treeview_redraw_icon(cw, &clip);
+ return;
+ }
/* make redraw coords relative to content viewport */
clip.g_x -= work.g_x;
@@ -425,8 +425,9 @@ static void __CDECL on_redraw_event(struct core_window *cw, EVMULT_OUT
*ev_out,
}
}
-static void __CDECL on_mbutton_event(struct core_window *cw, EVMULT_OUT *ev_out,
- short msg[8])
+static void __CDECL on_mbutton_event(struct core_window *cw,
+ EVMULT_OUT *ev_out,
+ short msg[8])
{
struct atari_treeview_window *tv = (struct atari_treeview_window *)cw;
struct gemtk_wm_scroll_info_s *slid;
diff --git a/frontends/cocoa/FormSelectMenu.m b/frontends/cocoa/FormSelectMenu.m
index 3ffd4cb..b7d168e 100644
--- a/frontends/cocoa/FormSelectMenu.m
+++ b/frontends/cocoa/FormSelectMenu.m
@@ -19,7 +19,7 @@
#import "cocoa/FormSelectMenu.h"
#import "cocoa/coordinates.h"
-#import "utils/utils.h"
+#import "netsurf/types.h"
#import "netsurf/browser_window.h"
#import "netsurf/form.h"
diff --git a/frontends/framebuffer/font_freetype.c
b/frontends/framebuffer/font_freetype.c
index ccc60ea..e7c07f5 100644
--- a/frontends/framebuffer/font_freetype.c
+++ b/frontends/framebuffer/font_freetype.c
@@ -17,12 +17,12 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#include <inttypes.h>
#include <assert.h>
#include <ft2build.h>
#include FT_CACHE_H
+#include "netsurf/inttypes.h"
#include "utils/filepath.h"
#include "utils/utf8.h"
#include "utils/log.h"
diff --git a/frontends/gtk/corewindow.c b/frontends/gtk/corewindow.c
index 8af1958..70c3ad1 100644
--- a/frontends/gtk/corewindow.c
+++ b/frontends/gtk/corewindow.c
@@ -39,7 +39,6 @@
#include <gtk/gtk.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/messages.h"
#include "utils/utf8.h"
#include "netsurf/types.h"
diff --git a/frontends/gtk/gui.c b/frontends/gtk/gui.c
index c08ab0a..8d6b422 100644
--- a/frontends/gtk/gui.c
+++ b/frontends/gtk/gui.c
@@ -449,6 +449,12 @@ static void gui_quit(void)
messages_get_errorcode(res));
}
+ res = hotlist_fini(nsoption_charp(hotlist_path));
+ if (res != NSERROR_OK) {
+ LOG("Error finalising hotlist: %s",
+ messages_get_errorcode(res));
+ }
+
free(nsgtk_config_home);
gtk_fetch_filetype_fin();
diff --git a/frontends/gtk/hotlist.c b/frontends/gtk/hotlist.c
index 6ce9060..34a1377 100644
--- a/frontends/gtk/hotlist.c
+++ b/frontends/gtk/hotlist.c
@@ -398,7 +398,7 @@ nserror nsgtk_hotlist_destroy(void)
return NSERROR_OK;
}
- res = hotlist_fini(nsoption_charp(hotlist_path));
+ res = hotlist_manager_fini();
if (res == NSERROR_OK) {
res = nsgtk_corewindow_fini(&hotlist_window->core);
gtk_widget_destroy(GTK_WIDGET(hotlist_window->wnd));
diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c
index 1cebf58..817b728 100644
--- a/frontends/gtk/plotters.c
+++ b/frontends/gtk/plotters.c
@@ -31,7 +31,6 @@
#include <gtk/gtk.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "netsurf/plotters.h"
#include "utils/nsoption.h"
diff --git a/frontends/gtk/toolbar.c b/frontends/gtk/toolbar.c
index e1aeb47..ac24a78 100644
--- a/frontends/gtk/toolbar.c
+++ b/frontends/gtk/toolbar.c
@@ -25,7 +25,6 @@
#include "desktop/searchweb.h"
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
#include "utils/nsoption.h"
#include "gtk/gui.h"
diff --git a/frontends/gtk/window.c b/frontends/gtk/window.c
index ce2644e..326e573 100644
--- a/frontends/gtk/window.c
+++ b/frontends/gtk/window.c
@@ -23,7 +23,6 @@
*/
#include <stdlib.h>
-#include <inttypes.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
@@ -32,9 +31,9 @@
#include <gdk/gdkkeysyms.h>
#include <gdk-pixbuf/gdk-pixdata.h>
+#include "netsurf/inttypes.h"
#include "utils/log.h"
#include "utils/utf8.h"
-#include "utils/utils.h"
#include "utils/nsoption.h"
#include "netsurf/content.h"
#include "netsurf/browser_window.h"
diff --git a/frontends/riscos/corewindow.c b/frontends/riscos/corewindow.c
index 9896069..3219be9 100644
--- a/frontends/riscos/corewindow.c
+++ b/frontends/riscos/corewindow.c
@@ -34,8 +34,8 @@
#include <stdint.h>
#include <oslib/wimp.h>
-#include "utils/utils.h"
#include "utils/log.h"
+#include "netsurf/types.h"
#include "netsurf/mouse.h"
#include "netsurf/keypress.h"
diff --git a/frontends/riscos/gui/url_bar.c b/frontends/riscos/gui/url_bar.c
index 40c5c6f..a5ec3f8 100644
--- a/frontends/riscos/gui/url_bar.c
+++ b/frontends/riscos/gui/url_bar.c
@@ -38,7 +38,6 @@
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/utf8.h"
-#include "utils/utils.h"
#include "utils/nsurl.h"
#include "netsurf/browser_window.h"
#include "netsurf/plotters.h"
diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c
index 9c98138..06e732d 100644
--- a/frontends/riscos/plotters.c
+++ b/frontends/riscos/plotters.c
@@ -27,7 +27,6 @@
#include "oslib/os.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "netsurf/plotters.h"
#include "riscos/bitmap.h"
diff --git a/frontends/riscos/print.c b/frontends/riscos/print.c
index dfdd24c..465627e 100644
--- a/frontends/riscos/print.c
+++ b/frontends/riscos/print.c
@@ -34,7 +34,6 @@
#include "utils/config.h"
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
#include "utils/nsoption.h"
#include "netsurf/browser_window.h"
#include "netsurf/plotters.h"
diff --git a/frontends/riscos/save_draw.c b/frontends/riscos/save_draw.c
index 705551f..7e6c946 100644
--- a/frontends/riscos/save_draw.c
+++ b/frontends/riscos/save_draw.c
@@ -31,7 +31,6 @@
#include <pencil.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "netsurf/plotters.h"
#include "netsurf/content.h"
diff --git a/frontends/riscos/url_complete.h b/frontends/riscos/url_complete.h
index 6a4660e..9243612 100644
--- a/frontends/riscos/url_complete.h
+++ b/frontends/riscos/url_complete.h
@@ -23,9 +23,8 @@
#ifndef _NETSURF_RISCOS_URLCOMPLETE_H_
#define _NETSURF_RISCOS_URLCOMPLETE_H_
-#include <inttypes.h>
#include <stdbool.h>
-#include "oslib/wimp.h"
+#include <oslib/wimp.h>
struct gui_window;
diff --git a/frontends/riscos/window.c b/frontends/riscos/window.c
index 45d5b14..b1ea58a 100644
--- a/frontends/riscos/window.c
+++ b/frontends/riscos/window.c
@@ -29,10 +29,10 @@
#include <assert.h>
#include <ctype.h>
-#include <inttypes.h>
#include <math.h>
#include <stdio.h>
#include <stdbool.h>
+#include <stdint.h>
#include <time.h>
#include <string.h>
#include <oslib/colourtrans.h>
@@ -43,6 +43,7 @@
#include <oslib/wimpspriteop.h>
#include <nsutils/time.h>
+#include "netsurf/inttypes.h"
#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/talloc.h"
diff --git a/frontends/windows/about.c b/frontends/windows/about.c
index 4716a5c..65c81cd 100644
--- a/frontends/windows/about.c
+++ b/frontends/windows/about.c
@@ -28,7 +28,6 @@
#include <windows.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/messages.h"
#include "desktop/version.h"
diff --git a/frontends/windows/corewindow.c b/frontends/windows/corewindow.c
index ff89d92..754e0e5 100644
--- a/frontends/windows/corewindow.c
+++ b/frontends/windows/corewindow.c
@@ -38,9 +38,9 @@
#include <windowsx.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/messages.h"
#include "utils/utf8.h"
+#include "netsurf/types.h"
#include "netsurf/keypress.h"
#include "netsurf/mouse.h"
diff --git a/frontends/windows/drawable.c b/frontends/windows/drawable.c
index ee1c695..cb94291 100644
--- a/frontends/windows/drawable.c
+++ b/frontends/windows/drawable.c
@@ -26,7 +26,6 @@
#include "utils/errors.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "netsurf/browser_window.h"
#include "netsurf/plotters.h"
#include "netsurf/keypress.h"
diff --git a/frontends/windows/filetype.c b/frontends/windows/filetype.c
index aab27ea..ed07dd5 100644
--- a/frontends/windows/filetype.c
+++ b/frontends/windows/filetype.c
@@ -20,7 +20,6 @@
#include <string.h>
#include "utils/log.h"
-#include "utils/utils.h"
#include "content/fetch.h"
#include "netsurf/fetch.h"
diff --git a/frontends/windows/font.c b/frontends/windows/font.c
index 791b8cd..f50ba6e 100644
--- a/frontends/windows/font.c
+++ b/frontends/windows/font.c
@@ -23,10 +23,10 @@
*/
#include "utils/config.h"
-#include <inttypes.h>
#include <assert.h>
#include <windows.h>
+#include "netsurf/inttypes.h"
#include "utils/log.h"
#include "utils/nsoption.h"
#include "utils/utf8.h"
diff --git a/frontends/windows/gui.c b/frontends/windows/gui.c
index 043a93d..f5808de 100644
--- a/frontends/windows/gui.c
+++ b/frontends/windows/gui.c
@@ -26,7 +26,6 @@
#include "utils/errors.h"
#include "utils/nsurl.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/corestrings.h"
#include "utils/url.h"
#include "utils/file.h"
diff --git a/frontends/windows/localhistory.c b/frontends/windows/localhistory.c
index 15705d1..ae3b7f5 100644
--- a/frontends/windows/localhistory.c
+++ b/frontends/windows/localhistory.c
@@ -24,7 +24,6 @@
#include "desktop/browser_history.h"
#include "netsurf/plotters.h"
-#include "utils/utils.h"
#include "utils/log.h"
#include "utils/messages.h"
diff --git a/frontends/windows/plot.c b/frontends/windows/plot.c
index 941ec41..fd29619 100644
--- a/frontends/windows/plot.c
+++ b/frontends/windows/plot.c
@@ -27,7 +27,6 @@
#include "utils/log.h"
#include "utils/utf8.h"
-#include "utils/utils.h"
#include "netsurf/mouse.h"
#include "netsurf/window.h"
#include "netsurf/plotters.h"
diff --git a/frontends/windows/pointers.c b/frontends/windows/pointers.c
index b796a30..a730e4b 100644
--- a/frontends/windows/pointers.c
+++ b/frontends/windows/pointers.c
@@ -25,7 +25,6 @@
#include "utils/errors.h"
#include "utils/nsurl.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/corestrings.h"
#include "utils/url.h"
#include "utils/file.h"
diff --git a/frontends/windows/prefs.c b/frontends/windows/prefs.c
index 286bfb0..03414ee 100644
--- a/frontends/windows/prefs.c
+++ b/frontends/windows/prefs.c
@@ -24,7 +24,6 @@
#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/messages.h"
-#include "utils/utils.h"
#include "utils/file.h"
#include "windows/gui.h"
diff --git a/frontends/windows/schedule.c b/frontends/windows/schedule.c
index 5366add..eae6c1d 100644
--- a/frontends/windows/schedule.c
+++ b/frontends/windows/schedule.c
@@ -21,7 +21,6 @@
#include "utils/sys_time.h"
#include "utils/log.h"
-#include "utils/utils.h"
#include "utils/errors.h"
#include "windows/schedule.h"
diff --git a/include/netsurf/types.h b/include/netsurf/inttypes.h
similarity index 55%
copy from include/netsurf/types.h
copy to include/netsurf/inttypes.h
index 27f2e8f..874d83f 100644
--- a/include/netsurf/types.h
+++ b/include/netsurf/inttypes.h
@@ -18,20 +18,42 @@
/**
* \file
- *
- * NetSurf types.
- *
- * These are convenience types used throughout the browser.
+ * Netsurf additional integer type formatting macros.
*/
-#ifndef NETSURF_TYPES_H
-#define NETSURF_TYPES_H
+#ifndef NETSURF_INTTYPES_H
+#define NETSURF_INTTYPES_H
-#include <stdint.h>
+#include <inttypes.h>
-/**
- * Colour type: XBGR
- */
-typedef uint32_t colour;
+#ifndef PRIxPTR
+#define PRIxPTR "x"
+#endif
+
+#ifndef PRId64
+#define PRId64 "lld"
+#endif
+
+/* Windows does not have sizet formating codes */
+#if defined(_WIN32)
+
+/** windows printf formatting for size_t type */
+#define PRIsizet "Iu"
+
+/** windows printf formatting for ssize_t type */
+#define PRIssizet "Id"
+
+#else
+
+/** c99 standard printf formatting for size_t type */
+#define PRIsizet "zu"
+
+/** c99 standard printf formatting for ssize_t type */
+#define PRIssizet "zd"
#endif
+
+
+
+#endif
+
diff --git a/include/netsurf/types.h b/include/netsurf/types.h
index 27f2e8f..5c9501b 100644
--- a/include/netsurf/types.h
+++ b/include/netsurf/types.h
@@ -34,4 +34,12 @@
*/
typedef uint32_t colour;
+/**
+ * Rectangle coordinates
+ */
+typedef struct rect {
+ int x0, y0; /**< Top left */
+ int x1, y1; /**< Bottom right */
+} rect;
+
#endif
diff --git a/render/box.c b/render/box.c
index f83bbb2..11a24e7 100644
--- a/render/box.c
+++ b/render/box.c
@@ -19,8 +19,9 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-/** \file
- * Box tree manipulation (implementation).
+/**
+ * \file
+ * implementation of box tree manipulation.
*/
#include <assert.h>
@@ -32,7 +33,6 @@
#include "utils/nsoption.h"
#include "utils/log.h"
#include "utils/talloc.h"
-#include "utils/utils.h"
#include "netsurf/misc.h"
#include "netsurf/content.h"
#include "netsurf/mouse.h"
diff --git a/render/box_construct.c b/render/box_construct.c
index d7de68c..f2d0413 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -38,7 +38,6 @@
#include "utils/log.h"
#include "utils/messages.h"
#include "utils/talloc.h"
-#include "utils/utils.h"
#include "utils/string.h"
#include "utils/ascii.h"
#include "netsurf/css.h"
diff --git a/render/form.c b/render/form.c
index 093b11f..6eb1b80 100644
--- a/render/form.c
+++ b/render/form.c
@@ -21,7 +21,8 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-/** \file
+/**
+ * \file
* Form handling functions (implementation).
*/
@@ -38,7 +39,6 @@
#include "utils/talloc.h"
#include "utils/url.h"
#include "utils/utf8.h"
-#include "utils/utils.h"
#include "utils/ascii.h"
#include "netsurf/browser_window.h"
#include "netsurf/mouse.h"
diff --git a/render/html.c b/render/html.c
index 3ddcdc3..6f7ad62 100644
--- a/render/html.c
+++ b/render/html.c
@@ -29,6 +29,7 @@
#include <stdlib.h>
#include <nsutils/time.h>
+#include "utils/utils.h"
#include "utils/config.h"
#include "utils/corestrings.h"
#include "utils/http.h"
diff --git a/render/html_css_fetcher.c b/render/html_css_fetcher.c
index 05aef02..9eda6ae 100644
--- a/render/html_css_fetcher.c
+++ b/render/html_css_fetcher.c
@@ -21,19 +21,19 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-
#include <dom/dom.h>
-
#include <libwapcaplet/libwapcaplet.h>
+#include "netsurf/inttypes.h"
#include "utils/config.h"
-#include "content/fetch.h"
-#include "content/fetchers.h"
-#include "render/html_internal.h"
#include "utils/log.h"
#include "utils/ring.h"
#include "utils/nsurl.h"
#include "utils/utils.h"
+#include "content/fetch.h"
+#include "content/fetchers.h"
+
+#include "render/html_internal.h"
typedef struct html_css_fetcher_item {
uint32_t key;
diff --git a/render/imagemap.c b/render/imagemap.c
index 10b48f1..6e2504b 100644
--- a/render/imagemap.c
+++ b/render/imagemap.c
@@ -27,14 +27,14 @@
#include <dom/dom.h>
+#include "utils/log.h"
+#include "utils/corestrings.h"
#include "content/content_protected.h"
#include "content/hlcache.h"
+
#include "render/box.h"
#include "render/html_internal.h"
#include "render/imagemap.h"
-#include "utils/corestrings.h"
-#include "utils/log.h"
-#include "utils/utils.h"
#define HASH_SIZE 31 /* fixed size hash table */
diff --git a/render/search.c b/render/search.c
index 523f8fb..4af6706 100644
--- a/render/search.c
+++ b/render/search.c
@@ -18,7 +18,8 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
- /** \file
+/**
+ * \file
* Free text search (core)
*/
diff --git a/test/Makefile b/test/Makefile
index 34d8c93..1f884dc 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -13,20 +13,16 @@ TESTS := \
time #llcache
# nsurl sources
-nsurl_SRCS := \
- utils/corestrings.c \
- utils/nsurl/nsurl.c \
- utils/nsurl/parse.c \
- utils/idna.c \
- test/log.c \
- test/nsurl.c
+nsurl_SRCS := utils/corestrings.c utils/nsurl/nsurl.c \
+ utils/nsurl/parse.c \
+ utils/idna.c utils/punycode.c \
+ test/log.c test/nsurl.c
# url database test sources
urldbtest_SRCS := content/urldb.c \
utils/idna.c utils/bloom.c utils/nsoption.c \
- utils/nsurl/nsurl.c \
- utils/nsurl/parse.c \
- utils/corestrings.c \
+ utils/nsurl/nsurl.c utils/nsurl/parse.c \
+ utils/corestrings.c utils/punycode.c \
utils/hashtable.c utils/messages.c utils/time.c utils/utils.c \
test/log.c test/urldbtest.c
@@ -37,8 +33,7 @@ llcache_SRCS := content/fetch.c content/fetchers/curl.c \
content/urldb.c \
image/image_cache.c \
utils/base64.c utils/corestrings.c utils/hashtable.c \
- utils/nsurl/nsurl.c \
- utils/nsurl/parse.c \
+ utils/nsurl/nsurl.c utils/nsurl/parse.c \
utils/messages.c utils/url.c utils/useragent.c \
utils/utils.c \
test/log.c test/llcache.c
@@ -60,9 +55,8 @@ urlescape_SRCS := utils/url.c test/log.c test/urlescape.c
# utility test sources
utils_SRCS := utils/utils.c utils/messages.c utils/hashtable.c \
- utils/corestrings.c utils/idna.c \
- utils/nsurl/nsurl.c \
- utils/nsurl/parse.c \
+ utils/corestrings.c utils/nsurl/nsurl.c \
+ utils/nsurl/parse.c utils/idna.c utils/punycode.c \
test/log.c test/utils.c
# time test sources
@@ -124,11 +118,11 @@ TESTCFLAGS := -std=c99 -g \
-D_XOPEN_SOURCE=600 \
-Itest -Iinclude -Icontent/handlers -Ifrontends -I. -I.. \
-Dnsgtk \
- $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils
libutf8proc libidn) \
+ $(shell pkg-config --cflags libcurl libparserutils libwapcaplet libdom libnsutils
libutf8proc) \
$(LIB_CFLAGS) \
$(COV_CFLAGS)
-TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom
libnsutils libutf8proc libidn) -lz \
+TESTLDFLAGS := $(shell pkg-config --libs libcurl libparserutils libwapcaplet libdom
libnsutils libutf8proc) -lz \
$(LIB_LDFLAGS)\
$(COV_LDFLAGS)
diff --git a/test/hashtable.c b/test/hashtable.c
index 9f46e4c..11c58c6 100644
--- a/test/hashtable.c
+++ b/test/hashtable.c
@@ -32,6 +32,9 @@
#include "utils/hashtable.h"
+/* Limit for hash table tests which use /usr/share/dict/words */
+#define DICT_TEST_WORD_COUNT 100000
+
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
struct test_pairs {
@@ -91,6 +94,7 @@ static void dict_hashtable_create(int dict_hash_size)
{
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -102,6 +106,7 @@ static void dict_hashtable_create(int dict_hash_size)
fscanf(dictf, "%s", keybuf);
fscanf(dictf, "%s", valbuf);
hash_add(dict_hash, keybuf, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
@@ -227,6 +232,7 @@ START_TEST(hashtable_dict_test)
FILE *dictf;
char keybuf[BUFSIZ], valbuf[BUFSIZ];
const char *res;
+ uint32_t counter = 0;
dictf = fopen("/usr/share/dict/words", "r");
ck_assert(dictf != NULL);
@@ -238,6 +244,7 @@ START_TEST(hashtable_dict_test)
res = hash_get(dict_hash, keybuf);
ck_assert(res != NULL);
ck_assert_str_eq(res, valbuf);
+ if (counter++ > DICT_TEST_WORD_COUNT) break;
}
fclose(dictf);
diff --git a/test/js/dom-change-event.html b/test/js/dom-change-event.html
new file mode 100644
index 0000000..a6d77b8
--- /dev/null
+++ b/test/js/dom-change-event.html
@@ -0,0 +1,17 @@
+<html>
+ <head>
+ <title>DOM Change event handling</title>
+ <script type="text/javascript">
+ document.addEventListener("DOMNodeInserted",
+ function(ev) {
+ console.log("\n\nHELLO WORLD!\n\n");
+ console.log(ev);
+ console.log("\n\n");
+ }, false);
+ console.log("Moooo!");
+ </script>
+ </head>
+ <body>
+ <div>I got inserted</div>
+ </body>
+</html>
diff --git a/test/js/index.html b/test/js/index.html
index f282ca4..2abe954 100644
--- a/test/js/index.html
+++ b/test/js/index.html
@@ -90,6 +90,7 @@
<li><a href="event-onload.html">window.onload</a></li>
<li><a
href="event-onloadfrombody.html">body.onload</a></li>
<li><a
href="event-onclick.html">button.onclick</a></li>
+<li><a
href="dom-change-event.html">DOMNodeInserted</a></li>
</ul>
diff --git a/utils/corestrings.c b/utils/corestrings.c
index 363c851..87a3423 100644
--- a/utils/corestrings.c
+++ b/utils/corestrings.c
@@ -277,6 +277,14 @@ dom_string *corestring_dom_onfocus;
dom_string *corestring_dom_onload;
dom_string *corestring_dom_onresize;
dom_string *corestring_dom_onscroll;
+dom_string *corestring_dom_autocomplete;
+dom_string *corestring_dom_autocompleteerror;
+dom_string *corestring_dom_dragexit;
+dom_string *corestring_dom_mouseenter;
+dom_string *corestring_dom_mouseleave;
+dom_string *corestring_dom_wheel;
+dom_string *corestring_dom_sort;
+dom_string *corestring_dom_toggle;
dom_string *corestring_dom___ns_key_box_node_data;
dom_string *corestring_dom___ns_key_libcss_node_data;
dom_string *corestring_dom___ns_key_file_name_node_data;
@@ -563,6 +571,15 @@ void corestrings_fini(void)
CSS_DOM_STRING_UNREF(onload);
CSS_DOM_STRING_UNREF(onresize);
CSS_DOM_STRING_UNREF(onscroll);
+ /* Corestrings used by DOM event registration */
+ CSS_DOM_STRING_UNREF(autocomplete);
+ CSS_DOM_STRING_UNREF(autocompleteerror);
+ CSS_DOM_STRING_UNREF(dragexit);
+ CSS_DOM_STRING_UNREF(mouseenter);
+ CSS_DOM_STRING_UNREF(mouseleave);
+ CSS_DOM_STRING_UNREF(wheel);
+ CSS_DOM_STRING_UNREF(sort);
+ CSS_DOM_STRING_UNREF(toggle);
/* DOM userdata keys, not really CSS */
CSS_DOM_STRING_UNREF(__ns_key_box_node_data);
CSS_DOM_STRING_UNREF(__ns_key_libcss_node_data);
@@ -894,6 +911,15 @@ nserror corestrings_init(void)
CSS_DOM_STRING_INTERN(onload);
CSS_DOM_STRING_INTERN(onresize);
CSS_DOM_STRING_INTERN(onscroll);
+ /* Corestrings used by DOM event registration */
+ CSS_DOM_STRING_INTERN(autocomplete);
+ CSS_DOM_STRING_INTERN(autocompleteerror);
+ CSS_DOM_STRING_INTERN(dragexit);
+ CSS_DOM_STRING_INTERN(mouseenter);
+ CSS_DOM_STRING_INTERN(mouseleave);
+ CSS_DOM_STRING_INTERN(wheel);
+ CSS_DOM_STRING_INTERN(sort);
+ CSS_DOM_STRING_INTERN(toggle);
/* DOM userdata keys, not really CSS */
CSS_DOM_STRING_INTERN(__ns_key_box_node_data);
CSS_DOM_STRING_INTERN(__ns_key_libcss_node_data);
diff --git a/utils/corestrings.h b/utils/corestrings.h
index a02bdda..88dc2ce 100644
--- a/utils/corestrings.h
+++ b/utils/corestrings.h
@@ -295,7 +295,15 @@ extern struct dom_string *corestring_dom_onfocus;
extern struct dom_string *corestring_dom_onload;
extern struct dom_string *corestring_dom_onresize;
extern struct dom_string *corestring_dom_onscroll;
-
+/* Corestrings used by DOM event registration */
+extern struct dom_string *corestring_dom_autocomplete;
+extern struct dom_string *corestring_dom_autocompleteerror;
+extern struct dom_string *corestring_dom_dragexit;
+extern struct dom_string *corestring_dom_mouseenter;
+extern struct dom_string *corestring_dom_mouseleave;
+extern struct dom_string *corestring_dom_wheel;
+extern struct dom_string *corestring_dom_sort;
+extern struct dom_string *corestring_dom_toggle;
/* DOM userdata keys */
extern struct dom_string *corestring_dom___ns_key_box_node_data;
extern struct dom_string *corestring_dom___ns_key_libcss_node_data;
diff --git a/utils/http/primitives.c b/utils/http/primitives.c
index f4c4e05..1e24d2a 100644
--- a/utils/http/primitives.c
+++ b/utils/http/primitives.c
@@ -16,11 +16,11 @@
* along with this program. If not, see <
http://www.gnu.org/licenses/>.
*/
-#include <inttypes.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include "netsurf/inttypes.h"
#include "utils/http/primitives.h"
/**
diff --git a/utils/idna.c b/utils/idna.c
index d75f957..34cc40f 100644
--- a/utils/idna.c
+++ b/utils/idna.c
@@ -28,6 +28,8 @@
#include <string.h>
#include <libutf8proc/utf8proc.h>
+#include "netsurf/inttypes.h"
+
#include "utils/errors.h"
#include "utils/idna.h"
#include "utils/idna_props.h"
diff --git a/utils/utils.h b/utils/utils.h
index 855ef7f..3995071 100644
--- a/utils/utils.h
+++ b/utils/utils.h
@@ -23,20 +23,11 @@
* \todo Many of these functions and macros should have their own headers.
*/
-#ifndef _NETSURF_UTILS_UTILS_H_
-#define _NETSURF_UTILS_UTILS_H_
+#ifndef NETSURF_UTILS_UTILS_H
+#define NETSURF_UTILS_UTILS_H
-#include <inttypes.h>
#include <stdbool.h>
-/** Rectangle coordinates */
-struct rect {
- int x0, y0; /**< Top left */
- int x1, y1; /**< Bottom right */
-};
-
-struct dirent;
-
#ifndef NOF_ELEMENTS
#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
#endif
@@ -60,29 +51,11 @@ struct dirent;
#endif
#endif
-#ifndef PRIxPTR
-#define PRIxPTR "x"
-#endif
-
-#ifndef PRId64
-#define PRId64 "lld"
-#endif
-
-/* Windows does not have sizet formating codes or POSIX mkdir so work
- * around that
- */
+/* Windows does not have POSIX mkdir so work around that */
#if defined(_WIN32)
-/** windows printf formatting for size_t type */
-#define PRIsizet "Iu"
-/** windows printf formatting for ssize_t type */
-#define PRIssizet "Id"
/** windows mkdir function */
#define nsmkdir(dir, mode) mkdir((dir))
#else
-/** c99 standard printf formatting for size_t type */
-#define PRIsizet "zu"
-/** c99 standard printf formatting for ssize_t type */
-#define PRIssizet "zd"
/** POSIX mkdir function */
#define nsmkdir(dir, mode) mkdir((dir), (mode))
#endif
--
NetSurf Browser