usbloadergx/source/language/gettext.c

252 lines
5.6 KiB
C
Raw Normal View History

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