2003-08-16 22:39:10 +04:00
|
|
|
/*
|
2004-05-08 22:13:27 +04:00
|
|
|
* Copyright 2004 James Bursa <bursa@users.sourceforge.net>
|
2006-08-22 02:07:10 +04:00
|
|
|
* Copyright 2006 Rob Kendrick <rjek@rjek.com>
|
2007-08-08 20:16:03 +04:00
|
|
|
*
|
|
|
|
* 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/>.
|
2004-05-08 22:13:27 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
/** \file
|
|
|
|
* Localised message support (implementation).
|
|
|
|
*
|
|
|
|
* Native language messages are loaded from a file and stored hashed by key for
|
|
|
|
* fast access.
|
2003-08-16 22:39:10 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <assert.h>
|
2004-05-08 22:13:27 +04:00
|
|
|
#include <errno.h>
|
2003-08-16 22:39:10 +04:00
|
|
|
#include <stdio.h>
|
2006-08-22 02:07:10 +04:00
|
|
|
#include <stdbool.h>
|
2003-08-16 22:39:10 +04:00
|
|
|
#include <string.h>
|
2008-07-26 19:18:21 +04:00
|
|
|
#include <zlib.h>
|
2010-10-05 23:14:46 +04:00
|
|
|
#include <stdarg.h>
|
|
|
|
|
2007-05-31 02:39:54 +04:00
|
|
|
#include "utils/log.h"
|
|
|
|
#include "utils/messages.h"
|
|
|
|
#include "utils/utils.h"
|
|
|
|
#include "utils/hashtable.h"
|
2003-08-16 22:39:10 +04:00
|
|
|
|
2004-05-08 22:13:27 +04:00
|
|
|
/** We store the messages in a fixed-size hash table. */
|
2006-08-20 03:37:58 +04:00
|
|
|
#define HASH_SIZE 101
|
2003-08-16 22:39:10 +04:00
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
/** The hash table used to store the standard Messages file for the old API */
|
|
|
|
static struct hash_table *messages_hash = NULL;
|
2003-08-16 22:39:10 +04:00
|
|
|
|
|
|
|
/**
|
2004-05-08 22:13:27 +04:00
|
|
|
* Read keys and values from messages file.
|
|
|
|
*
|
|
|
|
* \param path pathname of messages file
|
2006-08-22 02:07:10 +04:00
|
|
|
* \param ctx struct hash_table to merge with, or NULL for a new one.
|
|
|
|
* \return struct hash_table containing the context or NULL in case of error.
|
2003-08-16 22:39:10 +04:00
|
|
|
*/
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
struct hash_table *messages_load_ctx(const char *path, struct hash_table *ctx)
|
2003-08-16 22:39:10 +04:00
|
|
|
{
|
2005-07-16 18:35:25 +04:00
|
|
|
char s[400];
|
2012-03-14 20:42:02 +04:00
|
|
|
gzFile fp;
|
2006-10-12 18:00:40 +04:00
|
|
|
|
|
|
|
assert(path != NULL);
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
ctx = (ctx != NULL) ? ctx : hash_create(HASH_SIZE);
|
2006-10-12 18:00:40 +04:00
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
if (ctx == NULL) {
|
|
|
|
LOG(("Unable to create hash table for messages file %s", path));
|
|
|
|
return NULL;
|
|
|
|
}
|
2003-08-16 22:39:10 +04:00
|
|
|
|
2008-07-26 19:18:21 +04:00
|
|
|
fp = gzopen(path, "r");
|
2004-05-08 22:13:27 +04:00
|
|
|
if (!fp) {
|
|
|
|
snprintf(s, sizeof s, "Unable to open messages file "
|
|
|
|
"\"%.100s\": %s", path, strerror(errno));
|
|
|
|
s[sizeof s - 1] = 0;
|
|
|
|
LOG(("%s", s));
|
2008-07-26 19:18:21 +04:00
|
|
|
hash_destroy(ctx);
|
2006-08-22 02:07:10 +04:00
|
|
|
return NULL;
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|
|
|
|
|
2008-07-26 19:18:21 +04:00
|
|
|
while (gzgets(fp, s, sizeof s)) {
|
2004-05-08 22:13:27 +04:00
|
|
|
char *colon, *value;
|
2003-08-16 22:39:10 +04:00
|
|
|
|
|
|
|
if (s[0] == 0 || s[0] == '#')
|
|
|
|
continue;
|
2004-05-08 22:13:27 +04:00
|
|
|
|
|
|
|
s[strlen(s) - 1] = 0; /* remove \n at end */
|
2003-08-16 22:39:10 +04:00
|
|
|
colon = strchr(s, ':');
|
2004-05-08 22:13:27 +04:00
|
|
|
if (!colon)
|
2003-08-16 22:39:10 +04:00
|
|
|
continue;
|
|
|
|
*colon = 0; /* terminate key */
|
2004-05-08 22:13:27 +04:00
|
|
|
value = colon + 1;
|
2006-10-12 18:00:40 +04:00
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
if (hash_add(ctx, s, value) == false) {
|
|
|
|
LOG(("Unable to add %s:%s to hash table of %s",
|
|
|
|
s, value, path));
|
2008-07-26 19:18:21 +04:00
|
|
|
gzclose(fp);
|
|
|
|
hash_destroy(ctx);
|
2006-08-22 02:07:10 +04:00
|
|
|
return NULL;
|
2004-05-08 22:13:27 +04:00
|
|
|
}
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|
|
|
|
|
2008-07-26 19:18:21 +04:00
|
|
|
gzclose(fp);
|
2006-10-12 18:00:40 +04:00
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
return ctx;
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-08-22 02:07:10 +04:00
|
|
|
* Read keys and values from messages file into the standard Messages hash.
|
2004-05-08 22:13:27 +04:00
|
|
|
*
|
2006-08-22 02:07:10 +04:00
|
|
|
* \param path pathname of messages file
|
|
|
|
*
|
|
|
|
* The messages are merged with any previously loaded messages. Any keys which
|
|
|
|
* are present already are replaced with the new value.
|
|
|
|
*
|
|
|
|
* Exits through die() in case of error.
|
2003-08-16 22:39:10 +04:00
|
|
|
*/
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
void messages_load(const char *path)
|
2003-08-16 22:39:10 +04:00
|
|
|
{
|
2006-08-22 02:07:10 +04:00
|
|
|
struct hash_table *m;
|
|
|
|
char s[400];
|
2006-10-12 18:00:40 +04:00
|
|
|
|
2010-07-28 19:22:44 +04:00
|
|
|
if (path == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
LOG(("Loading Messages from '%s'", path));
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
m = messages_load_ctx(path, messages_hash);
|
|
|
|
if (m == NULL) {
|
|
|
|
LOG(("Unable to open Messages file '%s'. Possible reason: %s",
|
|
|
|
path, strerror(errno)));
|
2006-10-12 18:00:40 +04:00
|
|
|
snprintf(s, sizeof s,
|
|
|
|
"Unable to open Messages file '%s'.", path);
|
2006-08-22 02:07:10 +04:00
|
|
|
die(s);
|
|
|
|
}
|
2006-10-12 18:00:40 +04:00
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
messages_hash = m;
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2006-08-22 02:07:10 +04:00
|
|
|
* Fast lookup of a message by key.
|
|
|
|
*
|
|
|
|
* \param key key of message
|
|
|
|
* \param ctx context of messages file to look up in
|
|
|
|
* \return value of message, or key if not found
|
2003-08-16 22:39:10 +04:00
|
|
|
*/
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
const char *messages_get_ctx(const char *key, struct hash_table *ctx)
|
2003-08-16 22:39:10 +04:00
|
|
|
{
|
2006-10-12 18:00:40 +04:00
|
|
|
const char *r;
|
|
|
|
|
|
|
|
assert(key != NULL);
|
|
|
|
|
|
|
|
/* If we're called with no context, it's nicer to return the
|
|
|
|
* key rather than explode - this allows attempts to get messages
|
|
|
|
* before messages_hash is set up to fail gracefully, for example */
|
|
|
|
if (ctx == NULL)
|
|
|
|
return key;
|
|
|
|
|
|
|
|
r = hash_get(ctx, key);
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
return r ? r : key;
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|
|
|
|
|
2010-10-05 23:14:46 +04:00
|
|
|
/* exported interface documented in messages.h */
|
|
|
|
char *messages_get_buff(const char *key, ...)
|
|
|
|
{
|
|
|
|
const char *msg_fmt;
|
|
|
|
char *buff = NULL; /* formatted buffer to return */
|
|
|
|
int buff_len = 0;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
msg_fmt = messages_get_ctx(key, messages_hash);
|
|
|
|
|
|
|
|
va_start(ap, key);
|
|
|
|
buff_len = vsnprintf(buff, buff_len, msg_fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
buff = malloc(buff_len + 1);
|
|
|
|
|
|
|
|
if (buff == NULL) {
|
|
|
|
LOG(("malloc failed"));
|
|
|
|
warn_user("NoMemory", 0);
|
|
|
|
} else {
|
|
|
|
va_start(ap, key);
|
|
|
|
vsnprintf(buff, buff_len + 1, msg_fmt, ap);
|
|
|
|
va_end(ap);
|
|
|
|
}
|
|
|
|
|
|
|
|
return buff;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-08-16 22:39:10 +04:00
|
|
|
/**
|
2006-08-22 02:07:10 +04:00
|
|
|
* Fast lookup of a message by key from the standard Messages hash.
|
|
|
|
*
|
|
|
|
* \param key key of message
|
|
|
|
* \return value of message, or key if not found
|
2003-08-16 22:39:10 +04:00
|
|
|
*/
|
|
|
|
|
2006-08-22 02:07:10 +04:00
|
|
|
const char *messages_get(const char *key)
|
2003-08-16 22:39:10 +04:00
|
|
|
{
|
2006-08-22 02:07:10 +04:00
|
|
|
return messages_get_ctx(key, messages_hash);
|
2003-08-16 22:39:10 +04:00
|
|
|
}
|