2009-10-01 01:10:58 +02:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <gctypes.h>
|
|
|
|
#include "gettext.h"
|
|
|
|
|
2010-09-19 01:16:05 +02:00
|
|
|
typedef struct _MSG
|
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
u32 id;
|
|
|
|
char* msgstr;
|
|
|
|
struct _MSG *next;
|
|
|
|
} MSG;
|
2010-09-19 01:16:05 +02:00
|
|
|
static MSG *baseMSG = 0;
|
2009-10-01 01:10:58 +02:00
|
|
|
|
|
|
|
#define HASHWORDBITS 32
|
|
|
|
|
|
|
|
/* Defines the so called `hashpjw' function by P.J. Weinberger
|
2010-09-24 02:48:03 +02:00
|
|
|
[see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
|
|
|
|
1986, 1987 Bell Telephone Laboratories, Inc.] */
|
|
|
|
static inline u32 hash_string(const char *str_param)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
u32 hval, g;
|
|
|
|
const char *str = str_param;
|
|
|
|
|
|
|
|
/* Compute the hash value for the given string. */
|
|
|
|
hval = 0;
|
2010-09-24 02:48:03 +02:00
|
|
|
while (*str != '\0')
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
hval <<= 4;
|
2010-09-24 02:48:03 +02:00
|
|
|
hval += (u8) *str++;
|
|
|
|
g = hval & ((u32) 0xf << (HASHWORDBITS - 4));
|
|
|
|
if (g != 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
hval ^= g >> (HASHWORDBITS - 8);
|
2009-10-01 01:10:58 +02:00
|
|
|
hval ^= g;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Expand some escape sequences found in the argument string. */
|
|
|
|
static char *
|
2010-09-24 02:48:03 +02:00
|
|
|
expand_escape(const char *str)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
char *retval, *rp;
|
|
|
|
const char *cp = str;
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
retval = (char *) malloc(strlen(str) + 1);
|
|
|
|
if (retval == NULL) return NULL;
|
2009-10-01 01:10:58 +02:00
|
|
|
rp = retval;
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
while (cp[0] != '\0' && cp[0] != '\\')
|
2009-10-01 01:10:58 +02:00
|
|
|
*rp++ = *cp++;
|
2010-09-24 02:48:03 +02:00
|
|
|
if (cp[0] == '\0') goto terminate;
|
2010-09-19 01:16:05 +02:00
|
|
|
do
|
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
|
|
|
|
/* Here cp[0] == '\\'. */
|
2010-09-24 02:48:03 +02:00
|
|
|
switch (*++cp)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
case '\"': /* " */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\"';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'a': /* alert */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\a';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'b': /* backspace */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\b';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'f': /* form feed */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\f';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'n': /* new line */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\n';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'r': /* carriage return */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\r';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 't': /* horizontal tab */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\t';
|
|
|
|
++cp;
|
|
|
|
break;
|
2010-09-24 02:48:03 +02:00
|
|
|
case 'v': /* vertical tab */
|
2010-09-19 01:16:05 +02:00
|
|
|
*rp++ = '\v';
|
|
|
|
++cp;
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
*rp = '\\';
|
|
|
|
++cp;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
case '1':
|
|
|
|
case '2':
|
|
|
|
case '3':
|
|
|
|
case '4':
|
|
|
|
case '5':
|
|
|
|
case '6':
|
|
|
|
case '7':
|
2010-09-24 02:48:03 +02:00
|
|
|
{
|
|
|
|
int ch = *cp++ - '0';
|
|
|
|
|
|
|
|
if (*cp >= '0' && *cp <= '7')
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
ch *= 8;
|
|
|
|
ch += *cp++ - '0';
|
2010-09-19 01:16:05 +02:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
if (*cp >= '0' && *cp <= '7')
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
ch *= 8;
|
|
|
|
ch += *cp++ - '0';
|
|
|
|
}
|
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
*rp = ch;
|
|
|
|
}
|
2010-09-19 01:16:05 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
*rp = '\\';
|
|
|
|
break;
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
while (cp[0] != '\0' && cp[0] != '\\')
|
2009-10-01 01:10:58 +02:00
|
|
|
*rp++ = *cp++;
|
2010-09-24 02:48:03 +02:00
|
|
|
} while (cp[0] != '\0');
|
2009-10-01 01:10:58 +02:00
|
|
|
|
|
|
|
/* Terminate string. */
|
2010-09-24 02:48:03 +02:00
|
|
|
terminate: *rp = '\0';
|
2009-10-01 01:10:58 +02:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static MSG *findMSG(u32 id)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
MSG *msg;
|
2010-09-24 02:48:03 +02:00
|
|
|
for (msg = baseMSG; msg; msg = msg->next)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
if (msg->id == id) return msg;
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
static MSG *setMSG(const char *msgid, const char *msgstr)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
u32 id = hash_string(msgid);
|
|
|
|
MSG *msg = findMSG(id);
|
|
|
|
if (!msg)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
msg = (MSG *) malloc(sizeof(MSG));
|
|
|
|
msg->id = id;
|
2009-10-01 01:10:58 +02:00
|
|
|
msg->msgstr = NULL;
|
2010-09-24 02:48:03 +02:00
|
|
|
msg->next = baseMSG;
|
|
|
|
baseMSG = msg;
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
if (msg)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
if (msgstr)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
if (msg->msgstr) free(msg->msgstr);
|
2009-10-01 01:10:58 +02:00
|
|
|
//msg->msgstr = strdup(msgstr);
|
2010-09-24 02:48:03 +02:00
|
|
|
msg->msgstr = expand_escape(msgstr);
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
void gettextCleanUp(void)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
while (baseMSG)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
|
|
|
MSG *nextMsg = baseMSG->next;
|
2010-09-24 02:48:03 +02:00
|
|
|
free(baseMSG->msgstr);
|
|
|
|
free(baseMSG);
|
2009-10-01 01:10:58 +02:00
|
|
|
baseMSG = nextMsg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
bool gettextLoadLanguage(const char* langFile)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
FILE *f;
|
|
|
|
char line[200];
|
2010-09-19 01:16:05 +02:00
|
|
|
char *lastID = NULL;
|
2009-10-01 01:10:58 +02:00
|
|
|
|
|
|
|
gettextCleanUp();
|
2010-09-24 02:48:03 +02:00
|
|
|
f = fopen(langFile, "r");
|
|
|
|
if (!f) return false;
|
2009-10-01 01:10:58 +02:00
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
while (fgets(line, sizeof(line), f))
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
// lines starting with # are comments
|
2010-09-24 02:48:03 +02:00
|
|
|
if (line[0] == '#')
|
2009-10-01 01:10:58 +02:00
|
|
|
continue;
|
2010-09-24 02:48:03 +02:00
|
|
|
else if (strncmp(line, "msgid \"", 7) == 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
char *msgid, *end;
|
2010-09-24 02:48:03 +02:00
|
|
|
if (lastID)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
free(lastID);
|
2010-09-19 01:16:05 +02:00
|
|
|
lastID = NULL;
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
|
|
|
msgid = &line[7];
|
2010-09-24 02:48:03 +02:00
|
|
|
end = strrchr(msgid, '"');
|
|
|
|
if (end && end - msgid > 1)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
*end = 0;
|
2010-09-24 02:48:03 +02:00
|
|
|
lastID = strdup(msgid);
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
2010-09-19 01:16:05 +02:00
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
else if (strncmp(line, "msgstr \"", 8) == 0)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
char *msgstr, *end;
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
if (lastID == NULL) continue;
|
2009-10-01 01:10:58 +02:00
|
|
|
|
|
|
|
msgstr = &line[8];
|
2010-09-24 02:48:03 +02:00
|
|
|
end = strrchr(msgstr, '"');
|
|
|
|
if (end && end - msgstr > 1)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2009-10-01 01:10:58 +02:00
|
|
|
*end = 0;
|
2010-09-24 02:48:03 +02:00
|
|
|
setMSG(lastID, msgstr);
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
free(lastID);
|
2010-09-19 01:16:05 +02:00
|
|
|
lastID = NULL;
|
2009-10-01 01:10:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-09-24 02:48:03 +02:00
|
|
|
fclose(f);
|
2009-10-01 01:10:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
2010-09-24 02:48:03 +02:00
|
|
|
const char *gettext(const char *msgid)
|
2010-09-19 01:16:05 +02:00
|
|
|
{
|
2010-09-24 02:48:03 +02:00
|
|
|
MSG *msg = findMSG(hash_string(msgid));
|
|
|
|
if (msg && msg->msgstr) return msg->msgstr;
|
2009-10-01 01:10:58 +02:00
|
|
|
return msgid;
|
|
|
|
}
|
|
|
|
|