diff options
Diffstat (limited to 'source3/intl')
-rw-r--r-- | source3/intl/lang_tdb.c | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/source3/intl/lang_tdb.c b/source3/intl/lang_tdb.c new file mode 100644 index 0000000000..52a84d59a2 --- /dev/null +++ b/source3/intl/lang_tdb.c @@ -0,0 +1,181 @@ +/* + Unix SMB/Netbios implementation. + Version 3.0 + 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 02139, USA. +*/ + +#include "includes.h" + +static TDB_CONTEXT *tdb; + +/* load a po file into the tdb */ +static BOOL load_po(const char *po_file) +{ + char **lines; + int num_lines, i; + char *msgid, *msgstr; + TDB_DATA key, data; + + lines = file_lines_load(po_file, &num_lines); + + if (!lines) { + return False; + } + + if (tdb_lockall(tdb) != 0) return False; + + /* wipe the db */ + tdb_traverse(tdb, (tdb_traverse_func) tdb_delete, NULL); + + for (i=0;i<num_lines;i++) { + if (strncmp(lines[i], "msgid \"", 7) == 0) { + msgid = lines[i] + 7; + } + if (strncmp(lines[i], "msgstr \"", 8) == 0) { + msgstr = lines[i] + 8; + trim_string(msgid, NULL, "\""); + trim_string(msgstr, NULL, "\""); + if (*msgstr == 0) { + msgstr = msgid; + } + key.dptr = msgid; + key.dsize = strlen(msgid)+1; + data.dptr = msgstr; + data.dsize = strlen(msgstr)+1; + tdb_store(tdb, key, data, 0); + } + } + + file_lines_free(lines); + tdb_unlockall(tdb); + + return True; +} + + +/* work out what language to use from locale variables */ +static char *get_lang(void) +{ + char *vars[] = {"LANGUAGE", "LC_ALL", "LC_LANG", "LANG", NULL}; + int i; + char *p; + + for (i=0; vars[i]; i++) { + if ((p = getenv(vars[i]))) { + return p; + } + } + + return NULL; +} + +/* initialise the message translation subsystem */ +void lang_tdb_init(void) +{ + char *lang; + char *path = NULL; + struct stat st; + static int initialised; + time_t loadtime; + + /* we only want to init once per process */ + if (initialised) return; + initialised = 1; + + lang = get_lang(); + + /* if no lang then we don't translate */ + if (!lang) return; + + asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang); + + 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); + free(path); + return; + } + + free(path); + + asprintf(&path, "%s.po", lock_path(lang)); + + loadtime = tdb_fetch_int(tdb, "/LOADTIME/"); + + if (stat(path, &st) == 0 && (loadtime == -1 || loadtime < st.st_mtime)) { + load_po(path); + tdb_store_int(tdb, "/LOADTIME/", (int)time(NULL)); + } + free(path); +} + +/* 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) +{ + TDB_DATA key, data; + + lang_tdb_init(); + + if (!tdb) return msgid; + + key.dptr = (char *)msgid; + key.dsize = strlen(msgid)+1; + + data = tdb_fetch(tdb, key); + + /* if the message isn't found then we still need to return a pointer + that can be freed. Pity. */ + if (!data.dptr) return strdup(msgid); + + return (const char *)data.dptr; +} + + +/* free up a string from lang_msg() */ +void lang_msg_free(const char *msgstr) +{ + if (!tdb) return; + free((void *)msgstr); +} + + +/* + 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) +{ +#define NUM_LANG_BUFS 4 + char *msgstr; + static pstring bufs[NUM_LANG_BUFS]; + static int next; + + msgstr = lang_msg(msgid); + if (!msgstr) return msgid; + + pstrcpy(bufs[next], msgstr); + msgstr = bufs[next]; + + next = (next+1) % NUM_LANG_BUFS; + + return msgstr; +} |