Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
  3.  * Copyright 2006 Rob Kendrick <rjek@rjek.com>
  4.  *
  5.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  6.  *
  7.  * NetSurf is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; version 2 of the License.
  10.  *
  11.  * NetSurf is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18.  */
  19.  
  20. /** \file
  21.  * Localised message support (implementation).
  22.  *
  23.  * Native language messages are loaded from a file and stored hashed by key for
  24.  * fast access.
  25.  */
  26.  
  27. #include <assert.h>
  28. #include <errno.h>
  29. #include <stdio.h>
  30. #include <stdbool.h>
  31. #include <string.h>
  32. #include <zlib.h>
  33. #include <stdarg.h>
  34.  
  35. #include "utils/log.h"
  36. #include "utils/messages.h"
  37. #include "utils/utils.h"
  38. #include "utils/hashtable.h"
  39.  
  40. /** We store the messages in a fixed-size hash table. */
  41. #define HASH_SIZE 101
  42.  
  43. /** The hash table used to store the standard Messages file for the old API */
  44. static struct hash_table *messages_hash = NULL;
  45.  
  46. /**
  47.  * Read keys and values from messages file.
  48.  *
  49.  * \param  path  pathname of messages file
  50.  * \param  ctx   struct hash_table to merge with, or NULL for a new one.
  51.  * \return struct hash_table containing the context or NULL in case of error.
  52.  */
  53.  
  54. struct hash_table *messages_load_ctx(const char *path, struct hash_table *ctx)
  55. {
  56.         char s[400];
  57.         gzFile fp;
  58.  
  59.         assert(path != NULL);
  60.  
  61.         ctx = (ctx != NULL) ? ctx : hash_create(HASH_SIZE);
  62.  
  63.         if (ctx == NULL) {
  64.                 LOG(("Unable to create hash table for messages file %s", path));
  65.                 return NULL;
  66.         }
  67.  
  68.         fp = gzopen(path, "r");
  69.         if (!fp) {
  70.                 snprintf(s, sizeof s, "Unable to open messages file "
  71.                                 "\"%.100s\": %s", path, strerror(errno));
  72.                 s[sizeof s - 1] = 0;
  73.                 LOG(("%s", s));
  74.                 hash_destroy(ctx);
  75.                 return NULL;
  76.         }
  77.  
  78.         while (gzgets(fp, s, sizeof s)) {
  79.                 char *colon, *value;
  80.  
  81.                 if (s[0] == 0 || s[0] == '#')
  82.                         continue;
  83.  
  84.                 s[strlen(s) - 1] = 0;  /* remove \n at end */
  85.                 colon = strchr(s, ':');
  86.                 if (!colon)
  87.                         continue;
  88.                 *colon = 0;  /* terminate key */
  89.                 value = colon + 1;
  90.  
  91.                 if (hash_add(ctx, s, value) == false) {
  92.                         LOG(("Unable to add %s:%s to hash table of %s",
  93.                                 s, value, path));
  94.                         gzclose(fp);
  95.                         hash_destroy(ctx);
  96.                         return NULL;
  97.                 }
  98.         }
  99.  
  100.         gzclose(fp);
  101.  
  102.         return ctx;
  103. }
  104.  
  105. /**
  106.  * Read keys and values from messages file into the standard Messages hash.
  107.  *
  108.  * \param  path  pathname of messages file
  109.  *
  110.  * The messages are merged with any previously loaded messages. Any keys which
  111.  * are present already are replaced with the new value.
  112.  *
  113.  * Exits through die() in case of error.
  114.  */
  115.  
  116. void messages_load(const char *path)
  117. {
  118.         struct hash_table *m;
  119.         char s[400];
  120.  
  121.         if (path == NULL)
  122.                 return;
  123.                        
  124.         LOG(("Loading Messages from '%s'", path));
  125.        
  126.         m = messages_load_ctx(path, messages_hash);
  127.         if (m == NULL) {
  128.                 LOG(("Unable to open Messages file '%s'.  Possible reason: %s",
  129.                                 path, strerror(errno)));
  130.                 snprintf(s, sizeof s,
  131.                                 "Unable to open Messages file '%s'.", path);
  132.                 die(s);
  133.         }
  134.  
  135.         messages_hash = m;
  136. }
  137.  
  138. /**
  139.  * Fast lookup of a message by key.
  140.  *
  141.  * \param  key  key of message
  142.  * \param  ctx  context of messages file to look up in
  143.  * \return value of message, or key if not found
  144.  */
  145.  
  146. const char *messages_get_ctx(const char *key, struct hash_table *ctx)
  147. {
  148.         const char *r;
  149.  
  150.         assert(key != NULL);
  151.  
  152.         /* If we're called with no context, it's nicer to return the
  153.          * key rather than explode - this allows attempts to get messages
  154.          * before messages_hash is set up to fail gracefully, for example */
  155.         if (ctx == NULL)
  156.                 return key;
  157.  
  158.         r = hash_get(ctx, key);
  159.  
  160.         return r ? r : key;
  161. }
  162.  
  163. /* exported interface documented in messages.h */
  164. char *messages_get_buff(const char *key, ...)
  165. {
  166.         const char *msg_fmt;
  167.         char *buff = NULL; /* formatted buffer to return */
  168.         int buff_len = 0;
  169.         va_list ap;
  170.  
  171.         msg_fmt = messages_get_ctx(key, messages_hash);
  172.  
  173.         va_start(ap, key);
  174.         buff_len = vsnprintf(buff, buff_len, msg_fmt, ap);
  175.         va_end(ap);
  176.  
  177.         buff = malloc(buff_len + 1);
  178.  
  179.         if (buff == NULL) {
  180.                 LOG(("malloc failed"));
  181.                 warn_user("NoMemory", 0);              
  182.         } else {
  183.                 va_start(ap, key);
  184.                 vsnprintf(buff, buff_len + 1, msg_fmt, ap);
  185.                 va_end(ap);
  186.         }
  187.  
  188.         return buff;
  189. }
  190.  
  191.  
  192. /**
  193.  * Fast lookup of a message by key from the standard Messages hash.
  194.  *
  195.  * \param  key  key of message
  196.  * \return value of message, or key if not found
  197.  */
  198.  
  199. const char *messages_get(const char *key)
  200. {
  201.         return messages_get_ctx(key, messages_hash);
  202. }
  203.  
  204.  
  205. /**
  206.  * lookup of a message by errorcode from the standard Messages hash.
  207.  *
  208.  * \param code errorcode of message
  209.  * \return message text
  210.  */
  211.  
  212. const char *messages_get_errorcode(nserror code)
  213. {
  214.         switch (code) {
  215.         case NSERROR_OK:
  216.                 /**< No error */
  217.                 return messages_get_ctx("OK", messages_hash);
  218.  
  219.         case NSERROR_NOMEM:
  220.                 /**< Memory exhaustion */
  221.                 return messages_get_ctx("NoMemory", messages_hash);
  222.  
  223.         case NSERROR_NO_FETCH_HANDLER:
  224.                 /**< No fetch handler for URL scheme */
  225.                 return messages_get_ctx("NoHandler", messages_hash);
  226.  
  227.         case NSERROR_NOT_FOUND:
  228.                 /**< Requested item not found */
  229.                 return messages_get_ctx("NotFound", messages_hash);
  230.  
  231.         case NSERROR_SAVE_FAILED:
  232.                 /**< Failed to save data */
  233.                 return messages_get_ctx("SaveFailed", messages_hash);
  234.  
  235.         case NSERROR_CLONE_FAILED:
  236.                 /**< Failed to clone handle */
  237.                 return messages_get_ctx("CloneFailed", messages_hash);
  238.  
  239.         case NSERROR_INIT_FAILED:
  240.                 /**< Initialisation failed */
  241.                 return messages_get_ctx("InitFailed", messages_hash);
  242.  
  243.         case NSERROR_MNG_ERROR:
  244.                 /**< An MNG error occurred */
  245.                 return messages_get_ctx("MNGError", messages_hash);
  246.  
  247.         case NSERROR_BAD_ENCODING:
  248.                 /**< The character set is unknown */
  249.                 return messages_get_ctx("BadEncoding", messages_hash);
  250.  
  251.         case NSERROR_NEED_DATA:
  252.                 /**< More data needed */
  253.                 return messages_get_ctx("NeedData", messages_hash);
  254.  
  255.         case NSERROR_ENCODING_CHANGE:
  256.                 /**< The character set encoding change was unhandled */
  257.                 return messages_get_ctx("EncodingChanged", messages_hash);
  258.  
  259.         case NSERROR_BAD_PARAMETER:
  260.                 /**< Bad Parameter */
  261.                 return messages_get_ctx("BadParameter", messages_hash);
  262.  
  263.         case NSERROR_INVALID:
  264.                 /**< Invalid data */
  265.                 return messages_get_ctx("Invalid", messages_hash);
  266.  
  267.         case NSERROR_BOX_CONVERT:
  268.                 /**< Box conversion failed */
  269.                 return messages_get_ctx("BoxConvert", messages_hash);
  270.  
  271.         case NSERROR_STOPPED:
  272.                 /**< Content conversion stopped */
  273.                 return messages_get_ctx("Stopped", messages_hash);
  274.  
  275.         case NSERROR_DOM:
  276.                 /**< DOM call returned error */
  277.                 return messages_get_ctx("ParsingFail", messages_hash);
  278.  
  279.         case NSERROR_CSS:
  280.                 /**< CSS call returned error */
  281.                 return messages_get_ctx("CSSGeneric", messages_hash);
  282.  
  283.         case NSERROR_CSS_BASE:
  284.                 /**< CSS base sheet failed */
  285.                 return messages_get_ctx("CSSBase", messages_hash);
  286.  
  287.         case NSERROR_BAD_URL:
  288.                 /**< Bad URL */
  289.                 return messages_get_ctx("BadURL", messages_hash);
  290.  
  291.         default:
  292.         case NSERROR_UNKNOWN:
  293.                 break;
  294.         }
  295.  
  296.         /**< Unknown error */
  297.         return messages_get_ctx("Unknown", messages_hash);
  298. }
  299.