summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2013-05-07 14:56:42 +0100
committerMichael Drake <tlsa@netsurf-browser.org>2013-05-07 14:56:42 +0100
commit8b6665fe0383fd565ac7d7cd6a2bf6243ebc9937 (patch)
treeffa2ae68c2f87f19cbbd13b7e79a632a682202ee
parent3afd9c97310d58c0c6588d18887244328590731e (diff)
parentf4af0d86e240948bb37a1d318d4e2559f04c6a79 (diff)
downloadnetsurf-8b6665fe0383fd565ac7d7cd6a2bf6243ebc9937.tar.gz
netsurf-8b6665fe0383fd565ac7d7cd6a2bf6243ebc9937.tar.bz2
Merge branch 'master' of git://git.netsurf-browser.org/netsurf into tlsa/selection-search-refactor
-rw-r--r--Docs/env.sh11
-rw-r--r--Makefile.defaults4
-rw-r--r--content/content.c32
-rw-r--r--content/llcache.c1
-rw-r--r--css/dump.c4
-rw-r--r--desktop/browser.c2
-rw-r--r--desktop/cookies.c48
-rw-r--r--desktop/history_global_core.c23
-rw-r--r--desktop/hotlist.c40
-rw-r--r--desktop/sslcert.c15
-rw-r--r--desktop/tree.c106
-rw-r--r--desktop/tree.h27
-rw-r--r--desktop/tree_url_node.c47
-rw-r--r--gtk/res/cookies.gtk3.ui1
-rw-r--r--gtk/res/hotlist.gtk3.ui1
-rw-r--r--gtk/res/tabcontents.gtk2.ui4
-rw-r--r--gtk/window.c112
-rw-r--r--resources/FatMessages6
-rw-r--r--utils/fetch-transifex.pl124
-rw-r--r--utils/filepath.c10
-rw-r--r--utils/import-messages.pl301
-rw-r--r--utils/utils.c38
22 files changed, 681 insertions, 276 deletions
diff --git a/Docs/env.sh b/Docs/env.sh
index 5d6096353..db2729c0c 100644
--- a/Docs/env.sh
+++ b/Docs/env.sh
@@ -43,8 +43,10 @@ NS_GIT="git://git.netsurf-browser.org"
NS_INTERNAL_LIBS="buildsystem libwapcaplet libparserutils libhubbub libdom libcss libnsgif libnsbmp libsvgtiny librosprite"
# internal libraries only required by some frontends
NS_FRONTEND_LIBS="libnsfb"
+# internal libraries required for the risc os target abi
+NS_RISCOS_LIBS="librufl libpencil"
# tools required to build the browser
-NS_TOOLS="nsgenjsbind"
+NS_TOOLS="nsgenbind"
# The browser itself
NS_BROWSER="netsurf"
@@ -53,6 +55,11 @@ NS_DEV_DEB="build-essential pkg-config git gperf"
NS_TOOL_DEB="flex bison"
NS_GTK_DEB="libgtk2.0-dev libcurl3-dev libmng-dev librsvg2-dev liblcms1-dev libjpeg-dev libmozjs-dev"
+#add target specific libraries
+if [ "x${TARGET_ABI}" = "xriscos" ]; then
+ NS_FRONTEND_LIBS="${NS_FRONTEND_LIBS} ${NS_RISCOS_LIBS}"
+fi
+
# apt get commandline to install necessary dev packages
ns-apt-get-install()
{
@@ -76,7 +83,7 @@ ns-pull()
ns-clone()
{
mkdir -p ${TARGET_WORKSPACE}
- for REPO in $(echo ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
+ for REPO in $(echo ${NS_INTERNAL_LIBS} ${NS_FRONTEND_LIBS} ${NS_RISCOS_LIBS} ${NS_TOOLS} ${NS_BROWSER}) ; do
echo -n " GIT: Cloning ${REPO}: "
if [ -f ${TARGET_WORKSPACE}/${REPO}/.git/config ]; then
echo "Repository already present"
diff --git a/Makefile.defaults b/Makefile.defaults
index d8f5b9b0c..515f4a042 100644
--- a/Makefile.defaults
+++ b/Makefile.defaults
@@ -63,9 +63,9 @@ NETSURF_USE_VIDEO := NO
# Enable NetSurf's use of spidermonkey for javascript
# Valid options: YES, NO, AUTO
-NETSURF_USE_JS := NO
+NETSURF_USE_JS := AUTO
# Javascript support in older debian/ubuntu versions
-NETSURF_USE_MOZJS := NO
+NETSURF_USE_MOZJS := AUTO
# Enable NetSurf's use of libharu for PDF export and GTK printing support.
# There is no auto-detection available for this, as it does not have a
diff --git a/content/content.c b/content/content.c
index 74abdbfab..9bf4312ef 100644
--- a/content/content.c
+++ b/content/content.c
@@ -92,6 +92,7 @@ nserror content__init(struct content *c, const content_handler *handler,
if (fallback_charset != NULL) {
c->fallback_charset = strdup(fallback_charset);
if (c->fallback_charset == NULL) {
+ free(user_sentinel);
return NSERROR_NOMEM;
}
}
@@ -1349,39 +1350,33 @@ struct content *content_clone(struct content *c)
*/
nserror content__clone(const struct content *c, struct content *nc)
{
- struct content_user *user_sentinel;
nserror error;
- user_sentinel = calloc(1, sizeof(struct content_user));
- if (user_sentinel == NULL) {
- return NSERROR_NOMEM;
- }
-
error = llcache_handle_clone(c->llcache, &(nc->llcache));
if (error != NSERROR_OK) {
return error;
}
-
- llcache_handle_change_callback(nc->llcache,
- content_llcache_callback, nc);
+
+ llcache_handle_change_callback(nc->llcache,
+ content_llcache_callback, nc);
nc->mime_type = lwc_string_ref(c->mime_type);
nc->handler = c->handler;
nc->status = c->status;
-
+
nc->width = c->width;
nc->height = c->height;
nc->available_width = c->available_width;
nc->quirks = c->quirks;
-
+
if (c->fallback_charset != NULL) {
nc->fallback_charset = strdup(c->fallback_charset);
if (nc->fallback_charset == NULL) {
return NSERROR_NOMEM;
}
}
-
+
if (c->refresh != NULL) {
nc->refresh = nsurl_ref(c->refresh);
if (nc->refresh == NULL) {
@@ -1392,21 +1387,24 @@ nserror content__clone(const struct content *c, struct content *nc)
nc->time = c->time;
nc->reformat_time = c->reformat_time;
nc->size = c->size;
-
+
if (c->title != NULL) {
nc->title = strdup(c->title);
if (nc->title == NULL) {
return NSERROR_NOMEM;
}
}
-
+
nc->active = c->active;
- nc->user_list = user_sentinel;
-
+ nc->user_list = calloc(1, sizeof(struct content_user));
+ if (nc->user_list == NULL) {
+ return NSERROR_NOMEM;
+ }
+
memcpy(&(nc->status_message), &(c->status_message), 120);
memcpy(&(nc->sub_status), &(c->sub_status), 80);
-
+
nc->locked = c->locked;
nc->total_size = c->total_size;
nc->http_code = c->http_code;
diff --git a/content/llcache.c b/content/llcache.c
index 171ae15fc..938f1e8f6 100644
--- a/content/llcache.c
+++ b/content/llcache.c
@@ -1185,6 +1185,7 @@ static nserror llcache_object_add_user(llcache_object *object,
{
assert(user->next == NULL);
assert(user->prev == NULL);
+ assert(user->handle != NULL);
user->handle->object = object;
diff --git a/css/dump.c b/css/dump.c
index 1fe887400..fa34284e0 100644
--- a/css/dump.c
+++ b/css/dump.c
@@ -576,7 +576,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
/* counter-increment */
val = css_computed_counter_increment(style, &counter);
- if (counter == NULL) {
+ if ((val == CSS_COUNTER_INCREMENT_NONE) || (counter == NULL)) {
fprintf(stream, "counter-increment: none ");
} else {
fprintf(stream, "counter-increment:");
@@ -596,7 +596,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style)
/* counter-reset */
val = css_computed_counter_reset(style, &counter);
- if (counter == NULL) {
+ if ((val == CSS_COUNTER_RESET_NONE) || (counter == NULL)) {
fprintf(stream, "counter-reset: none ");
} else {
fprintf(stream, "counter-reset:");
diff --git a/desktop/browser.c b/desktop/browser.c
index a02807eeb..12cc9c830 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -2889,6 +2889,8 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
{
+ assert(bw != NULL);
+
browser_window_set_drag_type(bw, DRAGGING_PAGE_SCROLL, NULL);
bw->drag_start_x = x;
diff --git a/desktop/cookies.c b/desktop/cookies.c
index 581e1cc5b..197b3fbd1 100644
--- a/desktop/cookies.c
+++ b/desktop/cookies.c
@@ -264,19 +264,12 @@ static struct node *cookies_create_cookie_node(struct node *parent,
const struct cookie_data *data)
{
struct node *node;
- char *name;
- name = strdup(data->name);
- if (name == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return NULL;
- }
-
- node = tree_create_leaf_node(cookies_tree, NULL, name,
+ node = tree_create_leaf_node(cookies_tree,
+ NULL,
+ data->name,
false, false, false);
if (node == NULL) {
- free(name);
return NULL;
}
@@ -329,44 +322,33 @@ static void cookies_schedule_callback(const void *scheduled_data)
const struct cookie_data *data = scheduled_data;
struct node *node = NULL;
struct node *cookie_node = NULL;
- char *domain_cp;
assert(data != NULL);
node = cookies_find(cookies_tree_root, data->domain);
if (node == NULL) {
- domain_cp = strdup(data->domain);
- if (domain_cp == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return;
- }
- /* ownership of domain_cp passed to tree, if node creation
- * does not fail */
node = tree_create_folder_node(cookies_tree,
- cookies_tree_root, domain_cp,
+ cookies_tree_root,
+ data->domain,
false, false, false);
if (node != NULL) {
- tree_set_node_user_callback(node, cookies_node_callback,
+ tree_set_node_user_callback(node,
+ cookies_node_callback,
NULL);
tree_set_node_icon(cookies_tree, node, folder_icon);
-
- } else {
- free(domain_cp);
}
}
- if (node == NULL)
- return;
-
- cookie_node = cookies_find(node, data->name);
- if (cookie_node == NULL)
- cookies_create_cookie_node(node, data);
- else
- cookies_update_cookie_node(cookie_node, data);
+ if (node != NULL) {
+ cookie_node = cookies_find(node, data->name);
+ if (cookie_node == NULL) {
+ cookies_create_cookie_node(node, data);
+ } else {
+ cookies_update_cookie_node(cookie_node, data);
+ }
- return;
+ }
}
/**
diff --git a/desktop/history_global_core.c b/desktop/history_global_core.c
index 3222dc7b8..2a941e05d 100644
--- a/desktop/history_global_core.c
+++ b/desktop/history_global_core.c
@@ -175,33 +175,24 @@ static bool history_global_initialise_node(const char *title,
time_t base, int days_back)
{
struct tm *full_time;
- char *buffer;
struct node *node;
base += days_back * 60 * 60 * 24;
if (title == NULL) {
full_time = localtime(&base);
- buffer = strdup(messages_get(weekday_msg_name[full_time->tm_wday]));
- } else {
- buffer = strdup(title);
+ title = messages_get(weekday_msg_name[full_time->tm_wday]);
}
- if (buffer == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return false;
- }
-
- node = tree_create_folder_node(NULL, NULL, buffer,
- false, true, true);
+ node = tree_create_folder_node(NULL, NULL, title, false, true, true);
if (node == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- free(buffer);
+ warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
return false;
}
- if (folder_icon != NULL)
+
+ if (folder_icon != NULL) {
tree_set_node_icon(global_history_tree, node, folder_icon);
+ }
+
tree_set_node_user_callback(node, history_global_node_callback, NULL);
global_history_base_node[global_history_base_node_count] = node;
diff --git a/desktop/hotlist.c b/desktop/hotlist.c
index e2386fc8e..20cc8ea26 100644
--- a/desktop/hotlist.c
+++ b/desktop/hotlist.c
@@ -121,7 +121,6 @@ bool hotlist_initialise(struct tree *tree, const char *hotlist_path,
{
struct node *node;
const struct url_data *url_data;
- char *name;
int hlst_loop;
/* Either load or create a hotlist */
@@ -143,18 +142,15 @@ bool hotlist_initialise(struct tree *tree, const char *hotlist_path,
return true;
}
-
/* failed to load hotlist file, use default list */
- name = strdup("NetSurf");
- if (name == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return false;
- }
- node = tree_create_folder_node(hotlist_tree, hotlist_tree_root,
- name, true, false, false);
+ node = tree_create_folder_node(hotlist_tree,
+ hotlist_tree_root,
+ messages_get("NetSurf"),
+ true,
+ false,
+ false);
if (node == NULL) {
- free(name);
+ warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
return false;
}
@@ -373,14 +369,7 @@ void hotlist_collapse_addresses(void)
void hotlist_add_folder(bool selected)
{
struct node *node, *parent = NULL;
- struct node_element *element;
- char *title = strdup("Untitled");
- if (title == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return;
- }
creating_node = true;
if (selected == true) {
@@ -394,16 +383,21 @@ void hotlist_add_folder(bool selected)
parent = tree_get_default_folder_node(hotlist_tree);
}
- node = tree_create_folder_node(hotlist_tree, parent, title,
- true, false, false);
+ node = tree_create_folder_node(hotlist_tree,
+ parent,
+ messages_get("Untitled"),
+ true,
+ false,
+ false);
if (node == NULL) {
- free(title);
+ warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
return;
}
+
tree_set_node_user_callback(node, hotlist_node_callback, NULL);
tree_set_node_icon(hotlist_tree, node, folder_icon);
- element = tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL);
- tree_start_edit(hotlist_tree, element);
+ tree_start_edit(hotlist_tree,
+ tree_node_find_element(node, TREE_ELEMENT_TITLE, NULL));
}
/**
diff --git a/desktop/sslcert.c b/desktop/sslcert.c
index b7a424465..2b4d726e0 100644
--- a/desktop/sslcert.c
+++ b/desktop/sslcert.c
@@ -119,19 +119,22 @@ static node_callback_resp sslcert_node_callback(void *user_data,
static struct node *sslcert_create_node(const struct ssl_cert_info *cert)
{
- struct node *node;
+ struct node *node = NULL;
struct node_element *element;
char *text;
text = messages_get_buff("SSL_Certificate_Subject", cert->subject);
- if (text == NULL)
- return NULL;
-
- node = tree_create_leaf_node(NULL, NULL, text, false, false, false);
- if (node == NULL) {
+ if (text != NULL) {
+ node = tree_create_leaf_node(NULL,
+ NULL,
+ text,
+ false, false, false);
free(text);
+ }
+ if (node == NULL) {
return NULL;
}
+
tree_set_node_user_callback(node, sslcert_node_callback, NULL);
/* add issuer node */
diff --git a/desktop/tree.c b/desktop/tree.c
index af64be83b..c62793e02 100644
--- a/desktop/tree.c
+++ b/desktop/tree.c
@@ -117,7 +117,7 @@ struct node_element {
struct node *parent; /**< Parent node */
node_element_type type; /**< Element type */
struct node_element_box box; /**< Element bounding box */
- const char *text; /**< Text for the element */
+ char *text; /**< Text for the element */
void *bitmap; /**< Bitmap for the element */
struct node_element *next; /**< Next node element */
unsigned int flag; /**< Client specified flag for data
@@ -233,26 +233,19 @@ struct tree *tree_create(unsigned int flags,
const struct treeview_table *callbacks, void *client_data)
{
struct tree *tree;
- char *title;
tree = calloc(sizeof(struct tree), 1);
if (tree == NULL) {
LOG(("calloc failed"));
- warn_user("NoMemory", 0);
+ warn_user(messages_get_errorcode(NSERROR_NOMEM), 0);
return NULL;
}
- title = strdup("Root");
- if (title == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- free(tree);
- return NULL;
- }
- tree->root = tree_create_folder_node(NULL, NULL, title,
+ tree->root = tree_create_folder_node(NULL,
+ NULL,
+ messages_get("Root"),
false, false, false);
if (tree->root == NULL) {
- free(title);
free(tree);
return NULL;
}
@@ -553,18 +546,7 @@ static void tree_recalculate_node_sizes(struct tree *tree, struct node *node,
}
-/**
- * Creates a folder node with the specified title, and optionally links it into
- * the tree.
- *
- * \param tree the owner tree of 'parent', may be NULL
- * \param parent the parent node, or NULL not to link
- * \param title the node title (not copied, used directly)
- * \param editable if true, the node title will be editable
- * \param retain_in_memory if true, the node will stay in memory after deletion
- * \param deleted if true, the node is created with the deleted flag
- * \return the newly created node.
- */
+/* exported interface documented in desktop/tree.h */
struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted)
@@ -575,16 +557,20 @@ struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
node = calloc(sizeof(struct node), 1);
if (node == NULL) {
- LOG(("calloc failed"));
- warn_user("NoMemory", 0);
return NULL;
}
+
+ node->data.text = strdup(title);
+ if (node->data.text == NULL) {
+ free(node);
+ return NULL;
+ }
+
node->folder = true;
node->retain_in_memory = retain_in_memory;
node->deleted = deleted;
node->data.parent = node;
node->data.type = NODE_ELEMENT_TEXT;
- node->data.text = title;
node->data.flag = TREE_ELEMENT_TITLE;
node->data.editable = editable;
node->sort = NULL;
@@ -592,25 +578,14 @@ struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
node->previous = NULL;
tree_recalculate_node_sizes(tree, node, true);
- if (parent != NULL)
+ if (parent != NULL) {
tree_link_node(tree, parent, node, false);
+ }
return node;
}
-
-/**
- * Creates a leaf node with the specified title, and optionally links it into
- * the tree.
- *
- * \param tree the owner tree of 'parent', may be NULL
- * \param parent the parent node, or NULL not to link
- * \param title the node title (not copied, used directly)
- * \param editable if true, the node title will be editable
- * \param retain_in_memory if true, the node will stay in memory after deletion
- * \param deleted if true, the node is created with the deleted flag
- * \return the newly created node.
- */
+/* exported interface documented in desktop/tree.h */
struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted)
@@ -621,8 +596,12 @@ struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
node = calloc(sizeof(struct node), 1);
if (node == NULL) {
- LOG(("calloc failed"));
- warn_user("NoMemory", 0);
+ return NULL;
+ }
+
+ node->data.text = strdup(title);
+ if (node->data.text == NULL) {
+ free(node);
return NULL;
}
@@ -631,7 +610,6 @@ struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
node->deleted = deleted;
node->data.parent = node;
node->data.type = NODE_ELEMENT_TEXT;
- node->data.text = title;
node->data.flag = TREE_ELEMENT_TITLE;
node->data.editable = editable;
node->sort = NULL;
@@ -639,8 +617,9 @@ struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
node->previous = NULL;
tree_recalculate_node_sizes(tree, node, true);
- if (parent != NULL)
+ if (parent != NULL) {
tree_link_node(tree, parent, node, false);
+ }
return node;
}
@@ -1502,18 +1481,20 @@ void tree_update_node_element(struct tree *tree, struct node_element *element,
assert(element != NULL);
- if (tree != NULL && element == tree->editing)
+ if ((tree != NULL) && (element == tree->editing)) {
tree_stop_edit(tree, false);
+ }
- if (text != NULL && (element->type == NODE_ELEMENT_TEXT ||
- element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
+ if ((text != NULL) &&
+ (element->type == NODE_ELEMENT_TEXT ||
+ element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
if (element->text != NULL) {
- if(strcmp(element->text, text) == 0) text_changed = true;
-
+ if (strcmp(element->text, text) == 0) {
+ text_changed = true;
+ }
response = NODE_CALLBACK_NOT_HANDLED;
- if (!element->editable &&
- element->parent->user_callback !=
- NULL) {
+ if ((!element->editable) &&
+ (element->parent->user_callback != NULL)) {
msg_data.msg = NODE_DELETE_ELEMENT_TXT;
msg_data.flag = element->flag;
msg_data.node = element->parent;
@@ -1522,14 +1503,16 @@ void tree_update_node_element(struct tree *tree, struct node_element *element,
element->parent->callback_data,
&msg_data);
}
- if (response != NODE_CALLBACK_HANDLED)
- free((void *)element->text);
+ if (response != NODE_CALLBACK_HANDLED) {
+ free(element->text);
+ }
}
- element->text = text;
+ element->text = (char *)text;
}
- if (bitmap != NULL && (element->type == NODE_ELEMENT_BITMAP ||
- element->type == NODE_ELEMENT_TEXT_PLUS_ICON)) {
+ if ((bitmap != NULL) &&
+ ((element->type == NODE_ELEMENT_BITMAP) ||
+ (element->type == NODE_ELEMENT_TEXT_PLUS_ICON))) {
if (element->bitmap != NULL) {
response = NODE_CALLBACK_NOT_HANDLED;
if (element->parent->user_callback != NULL) {
@@ -1541,10 +1524,11 @@ void tree_update_node_element(struct tree *tree, struct node_element *element,
element->parent->callback_data,
&msg_data);
}
- if (response != NODE_CALLBACK_HANDLED)
+
+ if (response != NODE_CALLBACK_HANDLED) {
free(element->bitmap);
- }
- else {
+ }
+ } else {
/* Increase the box width to accomodate the new icon */
element->box.width += NODE_INSTEP;
}
diff --git a/desktop/tree.h b/desktop/tree.h
index 8ac505783..00ac99984 100644
--- a/desktop/tree.h
+++ b/desktop/tree.h
@@ -137,12 +137,39 @@ void tree_setup_colours(void);
struct tree *tree_create(unsigned int flags,
const struct treeview_table *callbacks,
void *client_data);
+
+/**
+ * Creates a folder node with the specified title, and optionally links it into
+ * the tree.
+ *
+ * \param tree the owner tree of 'parent', may be NULL
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title
+ * \param editable if true, the node title will be editable
+ * \param retain_in_memory if true, the node will stay in memory after deletion
+ * \param deleted if true, the node is created with the deleted flag
+ * \return the newly created node or NULL on error.
+ */
struct node *tree_create_folder_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted);
+
+/**
+ * Creates a leaf node with the specified title, and optionally links it into
+ * the tree.
+ *
+ * \param tree the owner tree of 'parent', may be NULL
+ * \param parent the parent node, or NULL not to link
+ * \param title the node title.
+ * \param editable if true, the node title will be editable
+ * \param retain_in_memory if true, the node will stay in memory after deletion
+ * \param deleted if true, the node is created with the deleted flag
+ * \return the newly created node or NULL on error.
+ */
struct node *tree_create_leaf_node(struct tree *tree, struct node *parent,
const char *title, bool editable, bool retain_in_memory,
bool deleted);
+
struct node_element *tree_create_node_element(struct node *parent,
node_element_type type, unsigned int flag, bool editable);
void tree_link_node(struct tree *tree, struct node *link, struct node *node,
diff --git a/desktop/tree_url_node.c b/desktop/tree_url_node.c
index 76bc8a47c..938cd1d69 100644
--- a/desktop/tree_url_node.c
+++ b/desktop/tree_url_node.c
@@ -126,35 +126,41 @@ void tree_url_node_cleanup()
* \param parent the node to link to
* \param url the URL (copied)
* \param data the URL data to use
- * \param title the custom title to use
+ * \param title custom title to use or NULL to use url
* \return the node created, or NULL for failure
*/
struct node *tree_create_URL_node(struct tree *tree, struct node *parent,
nsurl *url, const char *title,
tree_node_user_callback user_callback, void *callback_data)
{
- struct node *node;
+ struct node *node = NULL;
struct node_element *element;
- char *text_cp, *squashed;
- squashed = squash_whitespace(title ? title : nsurl_access(url));
- text_cp = strdup(squashed);
- if (text_cp == NULL) {
- LOG(("malloc failed"));
- warn_user("NoMemory", 0);
- return NULL;
+ if (title == NULL) {
+ node = tree_create_leaf_node(tree,
+ parent,
+ nsurl_access(url),
+ true, false, false);
+ } else {
+ char *squashed;
+
+ squashed = squash_whitespace(title);
+ if (squashed != NULL) {
+ node = tree_create_leaf_node(tree,
+ parent,
+ squashed,
+ true, false, false);
+ free(squashed);
+ }
}
- free(squashed);
- node = tree_create_leaf_node(tree, parent, text_cp, true, false,
- false);
if (node == NULL) {
- free(text_cp);
return NULL;
}
- if (user_callback != NULL)
+ if (user_callback != NULL) {
tree_set_node_user_callback(node, user_callback,
callback_data);
+ }
tree_create_node_element(node, NODE_ELEMENT_BITMAP,
TREE_ELEMENT_THUMBNAIL, false);
@@ -165,7 +171,7 @@ struct node *tree_create_URL_node(struct tree *tree, struct node *parent,
element = tree_create_node_element(node, NODE_ELEMENT_TEXT,
TREE_ELEMENT_URL, true);
if (element != NULL) {
- text_cp = strdup(nsurl_access(url));
+ char *text_cp = strdup(nsurl_access(url));
if (text_cp == NULL) {
tree_delete_node(tree, node, false);
LOG(("malloc failed"));
@@ -194,22 +200,18 @@ struct node *tree_create_URL_node_readonly(struct tree *tree,
{
struct node *node;
struct node_element *element;
- char *title;
+ const char *title;
assert(url && data);
if (data->title != NULL) {
- title = strdup(data->title);
+ title = data->title;
} else {
- title = strdup(nsurl_access(url));
+ title = nsurl_access(url);
}
- if (title == NULL)
- return NULL;
-
node = tree_create_leaf_node(tree, parent, title, false, false, false);
if (node == NULL) {
- free(title);
return NULL;
}
@@ -683,6 +685,7 @@ static bool tree_url_load_directory_cb(dom_node *node, void *ctx)
dir = tree_create_folder_node(tctx->tree, tctx->directory,
title, true, false, false);
+ free(title);
if (dir == NULL) {
dom_string_unref(name);
return false;
diff --git a/gtk/res/cookies.gtk3.ui b/gtk/res/cookies.gtk3.ui
index 3ccc04bce..44dcb80b8 100644
--- a/gtk/res/cookies.gtk3.ui
+++ b/gtk/res/cookies.gtk3.ui
@@ -188,6 +188,7 @@
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
</object>
</child>
</object>
diff --git a/gtk/res/hotlist.gtk3.ui b/gtk/res/hotlist.gtk3.ui
index 78a81672b..b0e075c4b 100644
--- a/gtk/res/hotlist.gtk3.ui
+++ b/gtk/res/hotlist.gtk3.ui
@@ -237,6 +237,7 @@
<object class="GtkDrawingArea" id="hotlistDrawingArea">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="events">GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_STRUCTURE_MASK</property>
</object>
</child>
</object>
diff --git a/gtk/res/tabcontents.gtk2.ui b/gtk/res/tabcontents.gtk2.ui
index e87249e74..63e290e8b 100644
--- a/gtk/res/tabcontents.gtk2.ui
+++ b/gtk/res/tabcontents.gtk2.ui
@@ -79,13 +79,13 @@
</object>
<object class="GtkAdjustment" id="layouthadjustment">
<property name="upper">100</property>
- <property name="step_increment">1</property>
+ <property name="step_increment">30</property>
<property name="page_increment">10</property>
<property name="page_size">10</property>
</object>
<object class="GtkAdjustment" id="layoutvadjustment">
<property name="upper">100</property>
- <property name="step_increment">1</property>
+ <property name="step_increment">30</property>
<property name="page_increment">10</property>
<property name="page_size">10</property>
</object>
diff --git a/gtk/window.c b/gtk/window.c
index 7642e3b82..663ff32a3 100644
--- a/gtk/window.c
+++ b/gtk/window.c
@@ -384,105 +384,91 @@ static gboolean nsgtk_window_button_release_event(GtkWidget *widget,
return TRUE;
}
-static gboolean nsgtk_window_scroll_event(GtkWidget *widget,
- GdkEventScroll *event, gpointer data)
+static gboolean
+nsgtk_window_scroll_event(GtkWidget *widget,
+ GdkEventScroll *event,
+ gpointer data)
{
struct gui_window *g = data;
double value;
+ double deltax = 0;
+ double deltay = 0;
GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout);
GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout);
GtkAllocation alloc;
- LOG(("%d", event->direction));
switch (event->direction) {
case GDK_SCROLL_LEFT:
- if (browser_window_scroll_at_point(g->bw,
- event->x / g->bw->scale,
- event->y / g->bw->scale,
- -100, 0) != true) {
- /* core did not handle event do horizontal scroll */
-
- value = gtk_adjustment_get_value(hscroll) -
- (nsgtk_adjustment_get_step_increment(hscroll) *2);
-
- if (value < nsgtk_adjustment_get_lower(hscroll)) {
- value = nsgtk_adjustment_get_lower(hscroll);
- }
-
- gtk_adjustment_set_value(hscroll, value);
- }
+ deltax = -1.0;
break;
case GDK_SCROLL_UP:
- if (browser_window_scroll_at_point(g->bw,
- event->x / g->bw->scale,
- event->y / g->bw->scale,
- 0, -100) != true) {
- /* core did not handle event change vertical
- * adjustment.
- */
+ deltay = -1.0;
+ break;
- value = gtk_adjustment_get_value(vscroll) -
- (nsgtk_adjustment_get_step_increment(vscroll) * 2);
+ case GDK_SCROLL_RIGHT:
+ deltax = 1.0;
+ break;
- if (value < nsgtk_adjustment_get_lower(vscroll)) {
- value = nsgtk_adjustment_get_lower(vscroll);
- }
+ case GDK_SCROLL_DOWN:
+ deltay = 1.0;
+ break;
- gtk_adjustment_set_value(vscroll, value);
- }
+#if GTK_CHECK_VERSION(3,4,0)
+ case GDK_SCROLL_SMOOTH:
+ gdk_event_get_scroll_deltas((GdkEvent *)event, &deltax, &deltay);
break;
+#endif
+ default:
+ LOG(("Unhandled mouse scroll direction"));
+ return TRUE;
+ }
- case GDK_SCROLL_RIGHT:
- if (browser_window_scroll_at_point(g->bw,
- event->x / g->bw->scale,
- event->y / g->bw->scale,
- 100, 0) != true) {
+ deltax *= nsgtk_adjustment_get_step_increment(hscroll);
+ deltay *= nsgtk_adjustment_get_step_increment(vscroll);
+
+ LOG(("Scrolling %f, %f", deltax, deltay));
- /* core did not handle event change horizontal
- * adjustment.
- */
+ if (browser_window_scroll_at_point(g->bw,
+ event->x / g->bw->scale,
+ event->y / g->bw->scale,
+ deltax, deltay) != true) {
- value = gtk_adjustment_get_value(hscroll) +
- (nsgtk_adjustment_get_step_increment(hscroll) * 2);
+ /* core did not handle event so change adjustments */
+
+ /* Horizontal */
+ if (deltax != 0) {
+ value = gtk_adjustment_get_value(hscroll) + deltax;
/* @todo consider gtk_widget_get_allocated_width() */
nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc);
if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) {
- value = nsgtk_adjustment_get_upper(hscroll) -
- alloc.width;
+ value = nsgtk_adjustment_get_upper(hscroll) - alloc.width;
+ }
+ if (value < nsgtk_adjustment_get_lower(hscroll)) {
+ value = nsgtk_adjustment_get_lower(hscroll);
}
gtk_adjustment_set_value(hscroll, value);
}
- break;
- case GDK_SCROLL_DOWN:
- if (browser_window_scroll_at_point(g->bw,
- event->x / g->bw->scale,
- event->y / g->bw->scale,
- 0, 100) != true) {
- /* core did not handle event change vertical
- * adjustment.
- */
-
- value = gtk_adjustment_get_value(vscroll) +
- (nsgtk_adjustment_get_step_increment(vscroll) * 2);
+ /* Vertical */
+ if (deltay != 0) {
+ value = gtk_adjustment_get_value(vscroll) + deltay;
+
/* @todo consider gtk_widget_get_allocated_height */
nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc);
- if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) {
- value = nsgtk_adjustment_get_upper(vscroll) -
- alloc.height;
+ if (value > (nsgtk_adjustment_get_upper(vscroll) - alloc.height)) {
+ value = nsgtk_adjustment_get_upper(vscroll) - alloc.height;
+ }
+ if (value < nsgtk_adjustment_get_lower(vscroll)) {
+ value = nsgtk_adjustment_get_lower(vscroll);
}
gtk_adjustment_set_value(vscroll, value);
}
- break;
-
- default:
- break;
}
return TRUE;
diff --git a/resources/FatMessages b/resources/FatMessages
index 32acda877..82c64ce9c 100644
--- a/resources/FatMessages
+++ b/resources/FatMessages
@@ -2334,7 +2334,7 @@ nl.all.SSLCerts:SSL certificates
en.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
de.all.SSLError:NetSurf konnte ein SSL Zertifikat nicht prüfen. Bitte die Details unten beachten.
fr.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
-it.all.SSLError:NetSurf non è stato in grado di verificare l'autenticità di questo certificato SSL, per favore verifica i dettagli presenti di seguito
+it.all.SSLError:NetSurf non è stato in grado di verificare l'autenticità di questo certificato SSL, per favore verifica i dettagli presenti di seguito
nl.all.SSLError:NetSurf failed to verify the authenticity of an SSL certificate. Please verify the details presented below.
en.all.SSL_Certificate_Subject:Subject: %s
de.all.SSL_Certificate_Subject:Subject: %s
@@ -2744,7 +2744,7 @@ nl.all.HotlistSaveError:The hotlist was unable to be correctly saved.
en.all.TreeLoadError:The tree was unable to be correctly loaded.
de.all.TreeLoadError:The tree was unable to be correctly loaded.
fr.all.TreeLoadError:The tree was unable to be correctly loaded.
-it.all.TreeLoadError:L'albero non è stato caricato correttamente.
+it.all.TreeLoadError:L'albero non è stato caricato correttamente.
nl.all.TreeLoadError:The tree was unable to be correctly loaded.
en.all.NoDirError:%s is not a directory
de.all.NoDirError:%s ist kein Verzeichnis.
@@ -5011,7 +5011,7 @@ nl.ro.HelpInterfaceConfig13:\Ssave these settings and close the \w.|M\Asave thes
en.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
de.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
fr.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
-it.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
+it.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
nl.ro.HelpInterfaceConfig16:This indicates whether NetSurf will use an external hotlist client if available, in preference to the internal hotlist.
en.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
de.ro.HelpInterfaceConfig18:\Tthe path to a hotlist application which will be used to display the hotlist.
diff --git a/utils/fetch-transifex.pl b/utils/fetch-transifex.pl
new file mode 100644
index 000000000..d8d588285
--- /dev/null
+++ b/utils/fetch-transifex.pl
@@ -0,0 +1,124 @@
+#!/usr/bin/perl
+#
+# Copyright © 2013 Vincent Sanders <vince@netsurf-browser.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# * The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+=head1
+
+retrive resource from transifex service
+
+=cut
+
+use strict;
+use Getopt::Long ();
+use LWP::UserAgent;
+use JSON qw( decode_json );
+use Data::Dumper;
+use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_APPEND O_RDONLY O_WRONLY );
+
+use constant GETOPT_OPTS => qw( auto_abbrev no_getopt_compat bundling );
+use constant GETOPT_SPEC =>
+ qw( output|o=s
+ lang|l=s
+ resource|res|r=s
+ project|prj|p=s
+ user|u=s
+ password|w=s
+ help|h|? );
+
+# default option values:
+my %opt = qw( resource messagesany project netsurf user netsurf );
+
+sub output_stream ();
+sub usage ();
+
+sub main ()
+{
+ my $output;
+ my $opt_ok;
+
+ # option parsing:
+ Getopt::Long::Configure( GETOPT_OPTS );
+ $opt_ok = Getopt::Long::GetOptions( \%opt, GETOPT_SPEC );
+
+ if( $opt_ok )
+ {
+ $output = output_stream();
+ }
+
+ # double check the options are sane (and we weren't asked for the help)
+ if( !$opt_ok || $opt{help} || $opt{lang} !~ /^[a-z]{2}$/ )
+ {
+ usage();
+ }
+
+ my $transifexurl = "https://www.transifex.com/api/2/project/" . $opt{project} . "/resource/" . $opt{resource} . "/translation/" . $opt{lang} . "/";
+
+ my $ua = LWP::UserAgent->new;
+ $ua->credentials(
+ 'www.transifex.com:443',
+ 'Transifex API',
+ $opt{user} => $opt{password}
+ );
+
+ my $response = $ua->get( $transifexurl );
+ if (!$response->is_success) {
+ die $response->status_line . " When fetching " . $transifexurl;
+ }
+
+ # Decode the entire JSON
+ my $decoded_json = decode_json( $response->decoded_content );
+
+ print ( $output $decoded_json->{'content'} );
+}
+
+main();
+
+sub usage ()
+{
+ print(STDERR <<TXT );
+usage:
+ $0 -l lang-code \
+ [-o output-file] [-r resource] [-p project] [-u user] [-w password]
+
+ lang-code : en fr ko ... (no default)
+ project : transifex project (default 'netsurf')
+ resource : transifex resource (default 'messagesany')
+ user : transifex resource (default 'netsurf')
+ password : transifex resource (no default)
+ output-file: defaults to standard output
+TXT
+ exit(1);
+}
+
+sub output_stream ()
+{
+ if( $opt{output} )
+ {
+ my $ofh;
+
+ sysopen( $ofh, $opt{output}, O_CREAT|O_EXCL|O_APPEND|O_WRONLY ) ||
+ die( "$0: Failed to open output file $opt{output}: $!\n" );
+
+ return $ofh;
+ }
+
+ return \*STDOUT;
+}
diff --git a/utils/filepath.c b/utils/filepath.c
index 21a965949..f0aa19585 100644
--- a/utils/filepath.c
+++ b/utils/filepath.c
@@ -89,21 +89,13 @@ char *filepath_sfindfile(char *str, const char *format, ...)
/* exported interface documented in filepath.h */
char *filepath_findfile(const char *format, ...)
{
- char *str;
char *ret;
va_list ap;
- str = malloc(PATH_MAX);
- if (str == NULL)
- return NULL; /* unable to allocate memory */
-
va_start(ap, format);
- ret = filepath_vsfindfile(str, format, ap);
+ ret = filepath_vsfindfile(NULL, format, ap);
va_end(ap);
- if (ret == NULL)
- free(str);
-
return ret;
}
diff --git a/utils/import-messages.pl b/utils/import-messages.pl
new file mode 100644
index 000000000..1c30e7fce
--- /dev/null
+++ b/utils/import-messages.pl
@@ -0,0 +1,301 @@
+#!/usr/bin/perl
+#
+# Copyright © 2013 Vivek Dasmohapatra <vivek@collabora.co.uk>
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# * The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+=head1
+
+Take a single-language messages file and merge it back in to the
+NetSurf master messaged (i10n) file.
+
+=cut
+
+use strict;
+
+use Getopt::Long ();
+use Fcntl qw( O_CREAT O_EXCL O_WRONLY O_APPEND O_RDONLY O_WRONLY O_TRUNC );
+
+use constant GETOPT_OPTS => qw( auto_abbrev no_getopt_compat bundling );
+use constant GETOPT_SPEC =>
+ qw( output|o=s
+ input|i=s
+ lang|l=s
+ plat|platform|p=s
+ format|fmt|f=s
+ import|I=s
+ help|h|? );
+
+# default option values:
+my %opt = qw( plat any format messages );
+
+sub input_stream ($;$);
+sub output_stream ();
+sub usage ();
+sub parser ();
+
+sub main ()
+{
+ my $input;
+ my $output;
+ my $import;
+ my $parser;
+ my $opt_ok;
+ my @input;
+ my %message;
+
+ # option parsing:
+ Getopt::Long::Configure( GETOPT_OPTS );
+ $opt_ok = Getopt::Long::GetOptions( \%opt, GETOPT_SPEC );
+
+ # allow input, import & output to be specified as non-option arguments:
+ if( @ARGV ) { $opt{input } ||= shift( @ARGV ) }
+ if( @ARGV ) { $opt{import} ||= shift( @ARGV ) }
+ if( @ARGV ) { $opt{output} ||= shift( @ARGV ) }
+
+ # open the appropriate streams and get the formatter and headers:
+ if( $opt_ok )
+ {
+ $input = input_stream( $opt{input} );
+ $import = input_stream( $opt{import}, 'import-file' );
+ $parser = parser();
+ $opt{plat} ||= 'any';
+ }
+
+ # double check the options are sane (and we weren't asked for the help)
+ if( !$opt_ok || $opt{help} || $opt{lang} !~ /^[a-z]{2}$/ )
+ {
+ usage();
+ }
+
+ @input = <$input>;
+ $output = output_stream();
+
+ $parser->( \%message, $import );
+
+ foreach ( @input )
+ {
+ use bytes;
+
+ if( !/#/ &&
+ !/^\s*$/ &&
+ /^([a-z]{2})\.([^.]+)\.([^:]+):/ )
+ {
+ my( $lang, $plat, $key ) = ( $1, $2, $3 );
+
+ if( $lang eq $opt{lang} )
+ {
+ my $val = $message{ $key };
+ if( $val &&
+ ( $opt{plat} eq 'any' || # all platforms ok
+ $opt{plat} eq $plat ) ) # specified platform matched
+ {
+ print( $output $val ? qq|$1.$2.$3:$val\n| : $_ );
+ next;
+ }
+ }
+ }
+
+ print( $output $_ );
+ }
+}
+
+main();
+
+sub usage ()
+{
+ my @fmt = map { s/::$//; $_ } keys(%{$::{'msgfmt::'}});
+ print( STDERR <<TXT );
+usage:
+ $0 -l lang-code \
+ [-p platform] [-f format] \
+ [-o output-file] [-i input-file] [-I import-file]
+
+ $0 -l lang-code … [input-file [import-file [output-file]]]
+
+ lang-code : en fr ko … (no default)
+ platform : any gtk ami (default 'any')
+ format : @fmt (default 'messages')
+ input-file : defaults to standard input
+ output-file: defaults to standard output
+ import-file: no default
+
+ The input-file may be the same as the output-file, in which case
+ it will be altered in place.
+TXT
+ exit(1);
+}
+
+sub input_stream ($;$)
+{
+ my $file = shift();
+ my $must_exist = shift();
+
+ if( $file )
+ {
+ my $ifh;
+
+ sysopen( $ifh, $file, O_RDONLY ) ||
+ die( "$0: Failed to open input file $file: $!\n" );
+
+ return $ifh;
+ }
+
+ if( $must_exist )
+ {
+ print( STDERR "No file specified for $must_exist\n" );
+ usage();
+ }
+
+ return \*STDIN;
+}
+
+sub output_stream ()
+{
+ if( $opt{output} )
+ {
+ my $ofh;
+
+ sysopen( $ofh, $opt{output}, O_CREAT|O_TRUNC|O_WRONLY ) ||
+ die( "$0: Failed to open output file $opt{output}: $!\n" );
+
+ return $ofh;
+ }
+
+ return \*STDOUT;
+}
+
+sub parser ()
+{
+ my $name = $opt{format};
+ my $func = "msgfmt::$name"->UNIVERSAL::can("parse");
+
+ return $func || die( "No handler found for format '$name'\n" );
+}
+
+# format implementations:
+{
+ package msgfmt::java;
+
+ sub unescape { $_[0] =~ s/\\([\\':])/$1/g; $_[0] }
+ sub parse
+ {
+ my $cache = shift();
+ my $stream = shift();
+
+ while ( <$stream> )
+ {
+ if( /(\S+)\s*=\s?(.*)/ )
+ {
+ my $key = $1;
+ my $val = $2;
+ $cache->{ $key } = unescape( $val );
+ }
+ }
+ }
+}
+
+{
+ package msgfmt::messages; # native netsurf format
+
+ sub parse
+ {
+ my $cache = shift();
+ my $stream = shift();
+
+ while ( <$stream> )
+ {
+ if( /^([a-z]{2})\.([^.]+)\.([^:]+):(.*)/ )
+ {
+ my( $lang, $plat, $key, $val ) = ( $1, $2, $3, $4 );
+
+ if( $lang ne $opt{lang} ) { next }
+ if( $opt{plat} ne 'any' &&
+ $opt{plat} ne $plat &&
+ 'all' ne $plat ) { next }
+
+ $cache->{ $key } = $val;
+ }
+ }
+ }
+}
+
+{
+ package msgfmt::transifex;
+ use base 'msgfmt::java';
+
+ # the differences between transifex and java properties only matter in
+ # the outward direction: During import they can be treated the same way
+}
+
+{
+ package msgfmt::android;
+
+ ANDROID_XML:
+ {
+ package msgfmt::android::xml;
+
+ my @stack;
+ my $data;
+ my $key;
+ our $cache;
+
+ sub StartDocument ($) { @stack = (); $key = '' }
+ sub Text ($) { if( $key ) { $data .= $_ } }
+ sub PI ($$$) { }
+ sub EndDocument ($) { }
+
+ sub EndTag ($$)
+ {
+ pop( @stack );
+
+ if( !$key ) { return; }
+
+ $cache->{ $key } = $data;
+ $data = $key = '';
+ }
+
+ sub StartTag ($$)
+ {
+ push( @stack, $_[1] );
+
+ if( "@stack" eq "resources string" )
+ {
+ $data = '';
+ $key = $_{ name };
+ }
+ }
+ }
+
+ sub parse
+ {
+ require XML::Parser;
+
+ if( !$XML::Parser::VERSION )
+ {
+ die("XML::Parser required for android format support\n");
+ }
+
+ $msgfmt::android::xml::cache = shift();
+ my $stream = shift();
+ my $parser = XML::Parser->new( Style => 'Stream',
+ Pkg => 'msgfmt::android::xml' );
+ $parser->parse( $stream );
+ }
+}
diff --git a/utils/utils.c b/utils/utils.c
index 3398a7df8..8155f4af1 100644
--- a/utils/utils.c
+++ b/utils/utils.c
@@ -98,26 +98,34 @@ char *remove_underscores(const char *s, bool replacespace)
/**
* Replace consecutive whitespace with a single space.
*
+ * @todo determine if squash_whitespace utf-8 safe and that it needs to be
+ *
* \param s source string
- * \return heap allocated result, or 0 on memory exhaustion
+ * \return heap allocated result, or NULL on memory exhaustion
*/
-char * squash_whitespace(const char *s)
+char *squash_whitespace(const char *s)
{
- char *c = malloc(strlen(s) + 1);
+ char *c;
int i = 0, j = 0;
- if (!c)
- return 0;
- do {
- if (s[i] == ' ' || s[i] == '\n' || s[i] == '\r' ||
- s[i] == '\t') {
- c[j++] = ' ';
- while (s[i] == ' ' || s[i] == '\n' || s[i] == '\r' ||
- s[i] == '\t')
- i++;
- }
- c[j++] = s[i++];
- } while (s[i - 1] != 0);
+
+ c = malloc(strlen(s) + 1);
+ if (c != NULL) {
+ do {
+ if (s[i] == ' ' ||
+ s[i] == '\n' ||
+ s[i] == '\r' ||
+ s[i] == '\t') {
+ c[j++] = ' ';
+ while (s[i] == ' ' ||
+ s[i] == '\n' ||
+ s[i] == '\r' ||
+ s[i] == '\t')
+ i++;
+ }
+ c[j++] = s[i++];
+ } while (s[i - 1] != 0);
+ }
return c;
}