diff options
Diffstat (limited to 'source3/intl')
-rw-r--r-- | source3/intl/lang_tdb.c | 246 | ||||
-rw-r--r-- | source3/intl/linux-msg.sed | 99 |
2 files changed, 345 insertions, 0 deletions
diff --git a/source3/intl/lang_tdb.c b/source3/intl/lang_tdb.c new file mode 100644 index 0000000000..499b9eb87d --- /dev/null +++ b/source3/intl/lang_tdb.c @@ -0,0 +1,246 @@ +/* + Unix SMB/CIFS implementation. + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" + +static TDB_CONTEXT *tdb; + +/* the currently selected language */ +static char *current_lang; + + +/* load a msg file into the tdb */ +static bool load_msg(const char *msg_file) +{ + char **lines; + int num_lines, i; + char *msgid, *msgstr; + TDB_DATA data; + + lines = file_lines_load(msg_file, &num_lines,0); + + if (!lines) { + return False; + } + + if (tdb_lockall(tdb) != 0) { + file_lines_free(lines); + return False; + } + + /* wipe the db */ + tdb_wipe_all(tdb); + + msgid = NULL; + + for (i=0;i<num_lines;i++) { + if (strncmp(lines[i], "msgid \"", 7) == 0) { + msgid = lines[i] + 7; + } + if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) { + msgstr = lines[i] + 8; + trim_char(msgid, '\0', '\"'); + trim_char(msgstr, '\0', '\"'); + if (*msgstr == 0) { + msgstr = msgid; + } + all_string_sub(msgid, "\\n", "\n", 0); + all_string_sub(msgstr, "\\n", "\n", 0); + data = string_term_tdb_data(msgstr); + tdb_store_bystring(tdb, msgid, data, 0); + msgid = NULL; + } + } + + file_lines_free(lines); + tdb_unlockall(tdb); + + return True; +} + + +/* work out what language to use from locale variables */ +static const char *get_lang(void) +{ + const 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. If the "lang" argument + is NULL then get the language from the normal environment variables */ +bool lang_tdb_init(const char *lang) +{ + char *path = NULL; + char *msg_path = NULL; + struct stat st; + static int initialised; + time_t loadtime; + bool result = False; + + /* we only want to init once per process, unless given + an override */ + if (initialised && !lang) + return True; + + if (initialised) { + /* we are re-initialising, free up any old init */ + if (tdb) { + tdb_close(tdb); + tdb = NULL; + } + SAFE_FREE(current_lang); + } + + initialised = 1; + + if (!lang) { + /* no lang given, use environment */ + lang = get_lang(); + } + + /* if no lang then we don't translate */ + if (!lang) + return True; + + if (asprintf(&msg_path, "%s.msg", + data_path((const char *)lang)) == -1) { + DEBUG(0, ("asprintf failed\n")); + goto done; + } + if (stat(msg_path, &st) != 0) { + /* the msg file isn't available */ + DEBUG(10, ("lang_tdb_init: %s: %s\n", msg_path, + strerror(errno))); + goto done; + } + + if (asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang) == -1) { + DEBUG(0, ("asprintf failed\n")); + goto done; + } + + DEBUG(10, ("lang_tdb_init: loading %s\n", path)); + + 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); + if (!tdb) { + DEBUG(10, ("lang_tdb_init: %s: %s\n", path, + strerror(errno))); + goto done; + } + current_lang = SMB_STRDUP(lang); + result = True; + goto done; + } + + loadtime = tdb_fetch_int32(tdb, "/LOADTIME/"); + + if (loadtime == -1 || loadtime < st.st_mtime) { + load_msg(msg_path); + tdb_store_int32(tdb, "/LOADTIME/", (int)time(NULL)); + } + + current_lang = SMB_STRDUP(lang); + result = True; + + done: + SAFE_FREE(msg_path); + SAFE_FREE(path); + + return result; +} + +/* 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 data; + const char *p; + char *q, *msgid_quoted; + int count; + + lang_tdb_init(NULL); + + if (!tdb) return msgid; + + /* 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++; + } + + if (!(msgid_quoted = (char *)SMB_MALLOC(strlen(msgid) + count + 1))) + 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; + + data = tdb_fetch_bystring(tdb, msgid_quoted); + + free(msgid_quoted); + + /* if the message isn't found then we still need to return a pointer + that can be freed. Pity. */ + if (!data.dptr) + return SMB_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); +} + +/* + return the current language - needed for language file mappings +*/ +char *lang_tdb_current(void) +{ + return current_lang; +} diff --git a/source3/intl/linux-msg.sed b/source3/intl/linux-msg.sed new file mode 100644 index 0000000000..19505b8a5d --- /dev/null +++ b/source3/intl/linux-msg.sed @@ -0,0 +1,99 @@ +# po2msg.sed - Convert Uniforum style .po file to Linux style .msg file +# Copyright (C) 1995 Free Software Foundation, Inc. +# Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. +# +# 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, 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, see <http://www.gnu.org/licenses/>. +# +# +# The first directive in the .msg should be the definition of the +# message set number. We use always set number 1. +# +1 { + i\ +$set 1 # Automatically created by po2msg.sed + h + s/.*/0/ + x +} +# +# Mitch's old catalog format does not allow comments. +# +# We copy the original message as a comment into the .msg file. +# +/^msgid/ { + s/msgid[ ]*"// +# +# This does not work now with the new format. +# /"$/! { +# s/\\$// +# s/$/ ... (more lines following)"/ +# } + x +# The following nice solution is by +# Bruno <Haible@ma2s2.mathematik.uni-karlsruhe.de> + td +# Increment a decimal number in pattern space. +# First hide trailing `9' digits. + :d + s/9\(_*\)$/_\1/ + td +# Assure at least one digit is available. + s/^\(_*\)$/0\1/ +# Increment the last digit. + s/8\(_*\)$/9\1/ + s/7\(_*\)$/8\1/ + s/6\(_*\)$/7\1/ + s/5\(_*\)$/6\1/ + s/4\(_*\)$/5\1/ + s/3\(_*\)$/4\1/ + s/2\(_*\)$/3\1/ + s/1\(_*\)$/2\1/ + s/0\(_*\)$/1\1/ +# Convert the hidden `9' digits to `0's. + s/_/0/g + x + G + s/\(.*\)"\n\([0-9]*\)/$ #\2 Original Message:(\1)/p +} +# +# The .msg file contains, other then the .po file, only the translations +# but each given a unique ID. Starting from 1 and incrementing by 1 for +# each message we assign them to the messages. +# It is important that the .po file used to generate the cat-id-tbl.c file +# (with po-to-tbl) is the same as the one used here. (At least the order +# of declarations must not be changed.) +# +/^msgstr/ { + s/msgstr[ ]*"\(.*\)"/# \1/ +# Clear substitution flag. + tb +# Append the next line. + :b + N +# Look whether second part is continuation line. + s/\(.*\n\)"\(.*\)"/\1\2/ +# Yes, then branch. + ta + P + D +# Note that D includes a jump to the start!! +# We found a continuation line. But before printing insert '\'. + :a + s/\(.*\)\(\n.*\)/\1\\\2/ + P +# We cannot use D here. + s/.*\n\(.*\)/\1/ + tb +} +d |