2001-10-03 16:18:20 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2001-10-03 16:18:20 +04:00
tdb based replacement for gettext
Copyright ( C ) Andrew Tridgell 2001
This program 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 ; either version 2 of the License , or
( at your option ) any later version .
This program 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
static TDB_CONTEXT * tdb ;
2001-10-14 16:10:29 +04:00
/* the currently selected language */
static char * current_lang ;
2001-10-15 12:10:07 +04:00
/* load a msg file into the tdb */
static BOOL load_msg ( const char * msg_file )
2001-10-03 16:18:20 +04:00
{
char * * lines ;
int num_lines , i ;
char * msgid , * msgstr ;
2007-03-27 13:12:47 +04:00
TDB_DATA data ;
2001-10-03 16:18:20 +04:00
2006-02-04 01:19:41 +03:00
lines = file_lines_load ( msg_file , & num_lines , 0 ) ;
2001-10-03 16:18:20 +04:00
if ( ! lines ) {
return False ;
}
2006-03-12 02:58:18 +03:00
if ( tdb_lockall ( tdb ) ! = 0 ) {
file_lines_free ( lines ) ;
return False ;
}
2001-10-03 16:18:20 +04:00
/* wipe the db */
2002-01-04 01:48:48 +03:00
tdb_traverse ( tdb , tdb_traverse_delete_fn , NULL ) ;
2001-10-15 12:10:07 +04:00
msgid = NULL ;
2001-10-03 16:18:20 +04:00
for ( i = 0 ; i < num_lines ; i + + ) {
if ( strncmp ( lines [ i ] , " msgid \" " , 7 ) = = 0 ) {
msgid = lines [ i ] + 7 ;
}
2001-10-15 12:10:07 +04:00
if ( msgid & & strncmp ( lines [ i ] , " msgstr \" " , 8 ) = = 0 ) {
2001-10-03 16:18:20 +04:00
msgstr = lines [ i ] + 8 ;
2003-09-05 23:59:55 +04:00
trim_char ( msgid , ' \0 ' , ' \" ' ) ;
trim_char ( msgstr , ' \0 ' , ' \" ' ) ;
2001-10-03 16:18:20 +04:00
if ( * msgstr = = 0 ) {
msgstr = msgid ;
}
2003-09-22 11:25:19 +04:00
all_string_sub ( msgid , " \\ n " , " \n " , 0 ) ;
all_string_sub ( msgstr , " \\ n " , " \n " , 0 ) ;
2007-03-27 13:12:47 +04:00
data = string_term_tdb_data ( msgstr ) ;
tdb_store_bystring ( tdb , msgid , data , 0 ) ;
2001-10-15 12:10:07 +04:00
msgid = NULL ;
2001-10-03 16:18:20 +04:00
}
}
file_lines_free ( lines ) ;
tdb_unlockall ( tdb ) ;
return True ;
}
/* work out what language to use from locale variables */
2003-01-03 11:28:12 +03:00
static const char * get_lang ( void )
2001-10-03 16:18:20 +04:00
{
2003-01-03 11:28:12 +03:00
const char * vars [ ] = { " LANGUAGE " , " LC_ALL " , " LC_LANG " , " LANG " , NULL } ;
2001-10-03 16:18:20 +04:00
int i ;
char * p ;
for ( i = 0 ; vars [ i ] ; i + + ) {
if ( ( p = getenv ( vars [ i ] ) ) ) {
return p ;
}
}
return NULL ;
}
2001-10-14 16:10:29 +04:00
/* initialise the message translation subsystem. If the "lang" argument
is NULL then get the language from the normal environment variables */
BOOL lang_tdb_init ( const char * lang )
2001-10-03 16:18:20 +04:00
{
char * path = NULL ;
2001-10-15 12:10:07 +04:00
char * msg_path = NULL ;
2001-10-03 16:18:20 +04:00
struct stat st ;
static int initialised ;
time_t loadtime ;
2003-09-19 11:04:29 +04:00
BOOL result = False ;
2001-10-03 16:18:20 +04:00
2001-10-14 16:10:29 +04:00
/* we only want to init once per process, unless given
an override */
2003-09-19 11:04:29 +04:00
if ( initialised & & ! lang )
return True ;
2001-10-14 16:10:29 +04:00
if ( initialised ) {
/* we are re-initialising, free up any old init */
2002-08-17 21:00:51 +04:00
if ( tdb ) {
tdb_close ( tdb ) ;
tdb = NULL ;
}
2001-10-14 16:10:29 +04:00
SAFE_FREE ( current_lang ) ;
}
2001-10-03 16:18:20 +04:00
initialised = 1 ;
2001-10-14 16:10:29 +04:00
if ( ! lang ) {
/* no lang given, use environment */
lang = get_lang ( ) ;
}
2001-10-03 16:18:20 +04:00
/* if no lang then we don't translate */
2003-09-19 11:04:29 +04:00
if ( ! lang )
return True ;
2001-10-14 16:10:29 +04:00
2003-01-03 11:28:12 +03:00
asprintf ( & msg_path , " %s.msg " , lib_path ( ( const char * ) lang ) ) ;
2001-10-15 12:10:07 +04:00
if ( stat ( msg_path , & st ) ! = 0 ) {
/* the msg file isn't available */
2003-11-07 11:29:29 +03:00
DEBUG ( 10 , ( " lang_tdb_init: %s: %s \n " , msg_path ,
2003-09-19 11:04:29 +04:00
strerror ( errno ) ) ) ;
goto done ;
2001-10-14 16:10:29 +04:00
}
2001-10-03 16:18:20 +04:00
asprintf ( & path , " %s%s.tdb " , lock_path ( " lang_ " ) , lang ) ;
2003-09-19 11:04:29 +04:00
DEBUG ( 10 , ( " lang_tdb_init: loading %s \n " , path ) ) ;
2001-10-03 16:18:20 +04:00
tdb = tdb_open_log ( path , 0 , TDB_DEFAULT , O_RDWR | O_CREAT , 0644 ) ;
if ( ! tdb ) {
tdb = tdb_open_log ( path , 0 , TDB_DEFAULT , O_RDONLY , 0 ) ;
2003-09-19 11:04:29 +04:00
if ( ! tdb ) {
DEBUG ( 10 , ( " lang_tdb_init: %s: %s \n " , path ,
strerror ( errno ) ) ) ;
goto done ;
}
2004-12-07 21:25:53 +03:00
current_lang = SMB_STRDUP ( lang ) ;
2003-09-19 11:04:29 +04:00
result = True ;
goto done ;
2001-10-03 16:18:20 +04:00
}
2002-01-09 07:13:30 +03:00
loadtime = tdb_fetch_int32 ( tdb , " /LOADTIME/ " ) ;
2001-10-03 16:18:20 +04:00
2001-10-14 16:10:29 +04:00
if ( loadtime = = - 1 | | loadtime < st . st_mtime ) {
2001-10-15 12:10:07 +04:00
load_msg ( msg_path ) ;
2002-01-09 07:13:30 +03:00
tdb_store_int32 ( tdb , " /LOADTIME/ " , ( int ) time ( NULL ) ) ;
2001-10-03 16:18:20 +04:00
}
2001-10-14 16:10:29 +04:00
2004-12-07 21:25:53 +03:00
current_lang = SMB_STRDUP ( lang ) ;
2003-09-22 21:39:44 +04:00
result = True ;
2001-10-14 16:10:29 +04:00
2003-09-19 11:04:29 +04:00
done :
SAFE_FREE ( msg_path ) ;
SAFE_FREE ( path ) ;
return result ;
2001-10-03 16:18:20 +04:00
}
/* translate a msgid to a message string in the current language
returns a string that must be freed by calling lang_msg_free ( )
*/
const char * lang_msg ( const char * msgid )
{
2007-03-27 13:12:47 +04:00
TDB_DATA data ;
2003-11-13 20:35:00 +03:00
const char * p ;
char * q , * msgid_quoted ;
2003-09-26 05:24:09 +04:00
int count ;
2001-10-03 16:18:20 +04:00
2001-10-14 16:10:29 +04:00
lang_tdb_init ( NULL ) ;
2001-10-03 16:18:20 +04:00
if ( ! tdb ) return msgid ;
2003-09-26 05:24:09 +04:00
/* Due to the way quotes in msgids are escaped in the msg file we
must replace " with \" before doing a lookup in the tdb. */
count = 0 ;
for ( p = msgid ; * p ; p + + ) {
if ( * p = = ' \" ' )
count + + ;
}
2006-08-01 00:51:55 +04:00
if ( ! ( msgid_quoted = ( char * ) SMB_MALLOC ( strlen ( msgid ) + count + 1 ) ) )
2003-09-26 05:24:09 +04:00
return msgid ;
/* string_sub() is unsuitable here as it replaces some punctuation
chars with underscores . */
for ( p = msgid , q = msgid_quoted ; * p ; p + + ) {
if ( * p = = ' \" ' ) {
* q = ' \\ ' ;
q + + ;
}
* q = * p ;
q + + ;
}
* q = 0 ;
2007-03-27 13:12:47 +04:00
data = tdb_fetch_bystring ( tdb , msgid_quoted ) ;
2001-10-03 16:18:20 +04:00
2003-09-26 05:24:09 +04:00
free ( msgid_quoted ) ;
2001-10-03 16:18:20 +04:00
/* if the message isn't found then we still need to return a pointer
that can be freed . Pity . */
2002-11-23 05:52:36 +03:00
if ( ! data . dptr )
2004-12-07 21:25:53 +03:00
return SMB_STRDUP ( msgid ) ;
2001-10-03 16:18:20 +04:00
return ( const char * ) data . dptr ;
}
/* free up a string from lang_msg() */
void lang_msg_free ( const char * msgstr )
{
if ( ! tdb ) return ;
2005-05-31 17:46:45 +04:00
free ( ( void * ) msgstr ) ;
2001-10-03 16:18:20 +04:00
}
/*
when the _ ( ) translation macro is used there is no obvious place to free
the resulting string and there is no easy way to give a static pointer .
All we can do is rotate between some static buffers and hope a single d_printf ( )
doesn ' t have more calls to _ ( ) than the number of buffers
*/
const char * lang_msg_rotate ( const char * msgid )
{
2003-10-18 21:46:41 +04:00
# define NUM_LANG_BUFS 16
2001-10-03 16:18:20 +04:00
char * msgstr ;
static pstring bufs [ NUM_LANG_BUFS ] ;
static int next ;
2005-05-31 17:46:45 +04:00
msgstr = ( char * ) lang_msg ( msgid ) ;
2001-10-03 16:18:20 +04:00
if ( ! msgstr ) return msgid ;
pstrcpy ( bufs [ next ] , msgstr ) ;
msgstr = bufs [ next ] ;
next = ( next + 1 ) % NUM_LANG_BUFS ;
return msgstr ;
}
2001-10-14 16:10:29 +04:00
/*
return the current language - needed for language file mappings
*/
char * lang_tdb_current ( void )
{
return current_lang ;
}