intl/lang_tdb.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    tdb based replacement for gettext 
00004    Copyright (C) Andrew Tridgell 2001
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 #include "includes.h"
00022 
00023 static TDB_CONTEXT *tdb;
00024 
00025 /* the currently selected language */
00026 static char *current_lang;
00027 
00028 
00029 /* load a msg file into the tdb */
00030 static BOOL load_msg(const char *msg_file)
00031 {
00032         char **lines;
00033         int num_lines, i;
00034         char *msgid, *msgstr;
00035         TDB_DATA key, data;
00036 
00037         lines = file_lines_load(msg_file, &num_lines,0);
00038 
00039         if (!lines) {
00040                 return False;
00041         }
00042 
00043         if (tdb_lockall(tdb) != 0) {
00044                 file_lines_free(lines);
00045                 return False;
00046         }
00047 
00048         /* wipe the db */
00049         tdb_traverse(tdb, tdb_traverse_delete_fn, NULL);
00050 
00051         msgid = NULL;
00052         
00053         for (i=0;i<num_lines;i++) {
00054                 if (strncmp(lines[i], "msgid \"", 7) == 0) {
00055                         msgid = lines[i] + 7;
00056                 }
00057                 if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
00058                         msgstr = lines[i] + 8;
00059                         trim_char(msgid, '\0', '\"');
00060                         trim_char(msgstr, '\0', '\"');
00061                         if (*msgstr == 0) {
00062                                 msgstr = msgid;
00063                         }
00064                         all_string_sub(msgid, "\\n", "\n", 0);
00065                         all_string_sub(msgstr, "\\n", "\n", 0);
00066                         key.dptr = msgid;
00067                         key.dsize = strlen(msgid)+1;
00068                         data.dptr = msgstr;
00069                         data.dsize = strlen(msgstr)+1;
00070                         tdb_store(tdb, key, data, 0);
00071                         msgid = NULL;
00072                 }
00073         }
00074 
00075         file_lines_free(lines);
00076         tdb_unlockall(tdb);
00077 
00078         return True;
00079 }
00080 
00081 
00082 /* work out what language to use from locale variables */
00083 static const char *get_lang(void)
00084 {
00085         const char *vars[] = {"LANGUAGE", "LC_ALL", "LC_LANG", "LANG", NULL};
00086         int i;
00087         char *p;
00088 
00089         for (i=0; vars[i]; i++) {
00090                 if ((p = getenv(vars[i]))) {
00091                         return p;
00092                 }
00093         }
00094 
00095         return NULL;
00096 }
00097 
00098 /* initialise the message translation subsystem. If the "lang" argument
00099    is NULL then get the language from the normal environment variables */
00100 BOOL lang_tdb_init(const char *lang)
00101 {
00102         char *path = NULL;
00103         char *msg_path = NULL;
00104         struct stat st;
00105         static int initialised;
00106         time_t loadtime;
00107         BOOL result = False;
00108 
00109         /* we only want to init once per process, unless given
00110            an override */
00111         if (initialised && !lang) 
00112                 return True;
00113 
00114         if (initialised) {
00115                 /* we are re-initialising, free up any old init */
00116                 if (tdb) {
00117                         tdb_close(tdb);
00118                         tdb = NULL;
00119                 }
00120                 SAFE_FREE(current_lang);
00121         }
00122 
00123         initialised = 1;
00124 
00125         if (!lang) {
00126                 /* no lang given, use environment */
00127                 lang = get_lang();
00128         }
00129 
00130         /* if no lang then we don't translate */
00131         if (!lang) 
00132                 return True;
00133 
00134         asprintf(&msg_path, "%s.msg", lib_path((const char *)lang));
00135         if (stat(msg_path, &st) != 0) {
00136                 /* the msg file isn't available */
00137                 DEBUG(10, ("lang_tdb_init: %s: %s\n", msg_path, 
00138                            strerror(errno)));
00139                 goto done;
00140         }
00141         
00142         asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang);
00143 
00144         DEBUG(10, ("lang_tdb_init: loading %s\n", path));
00145 
00146         tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
00147         if (!tdb) {
00148                 tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDONLY, 0);
00149                 if (!tdb) {
00150                         DEBUG(10, ("lang_tdb_init: %s: %s\n", path,
00151                                    strerror(errno)));
00152                         goto done;
00153                 }
00154                 current_lang = SMB_STRDUP(lang);
00155                 result = True;
00156                 goto done;
00157         }
00158 
00159         loadtime = tdb_fetch_int32(tdb, "/LOADTIME/");
00160 
00161         if (loadtime == -1 || loadtime < st.st_mtime) {
00162                 load_msg(msg_path);
00163                 tdb_store_int32(tdb, "/LOADTIME/", (int)time(NULL));
00164         }
00165 
00166         current_lang = SMB_STRDUP(lang);
00167         result = True;
00168 
00169  done:
00170         SAFE_FREE(msg_path);
00171         SAFE_FREE(path);
00172 
00173         return result;
00174 }
00175 
00176 /* translate a msgid to a message string in the current language 
00177    returns a string that must be freed by calling lang_msg_free()
00178 */
00179 const char *lang_msg(const char *msgid)
00180 {
00181         TDB_DATA key, data;
00182         const char *p;
00183         char *q, *msgid_quoted;
00184         int count;
00185 
00186         lang_tdb_init(NULL);
00187 
00188         if (!tdb) return msgid;
00189 
00190         /* Due to the way quotes in msgids are escaped in the msg file we
00191            must replace " with \" before doing a lookup in the tdb. */
00192 
00193         count = 0;
00194 
00195         for(p = msgid; *p; p++) {
00196                 if (*p == '\"')
00197                         count++;
00198         }
00199 
00200         if (!(msgid_quoted = (char *)SMB_MALLOC(strlen(msgid) + count + 1)))
00201                 return msgid;
00202 
00203         /* string_sub() is unsuitable here as it replaces some punctuation
00204            chars with underscores. */
00205 
00206         for(p = msgid, q = msgid_quoted; *p; p++) {
00207                 if (*p == '\"') {
00208                         *q = '\\';
00209                         q++;
00210                 }
00211                 *q = *p;
00212                 q++;
00213         }
00214 
00215         *q = 0;
00216 
00217         key.dptr = (char *)msgid_quoted;
00218         key.dsize = strlen(msgid_quoted)+1;
00219         
00220         data = tdb_fetch(tdb, key);
00221 
00222         free(msgid_quoted);
00223 
00224         /* if the message isn't found then we still need to return a pointer
00225            that can be freed. Pity. */
00226         if (!data.dptr)
00227                 return SMB_STRDUP(msgid);
00228 
00229         return (const char *)data.dptr;
00230 }
00231 
00232 
00233 /* free up a string from lang_msg() */
00234 void lang_msg_free(const char *msgstr)
00235 {
00236         if (!tdb) return;
00237         free((void *)msgstr);
00238 }
00239 
00240 
00241 /*
00242   when the _() translation macro is used there is no obvious place to free
00243   the resulting string and there is no easy way to give a static pointer.
00244   All we can do is rotate between some static buffers and hope a single d_printf() 
00245   doesn't have more calls to _() than the number of buffers 
00246 */
00247 const char *lang_msg_rotate(const char *msgid)
00248 {
00249 #define NUM_LANG_BUFS 16
00250         char *msgstr;
00251         static pstring bufs[NUM_LANG_BUFS];
00252         static int next;
00253 
00254         msgstr = (char *)lang_msg(msgid);
00255         if (!msgstr) return msgid;
00256 
00257         pstrcpy(bufs[next], msgstr);
00258         msgstr = bufs[next];
00259 
00260         next = (next+1) % NUM_LANG_BUFS;
00261         
00262         return msgstr;
00263 }
00264 
00265 
00266 /* 
00267    return the current language - needed for language file mappings 
00268 */
00269 char *lang_tdb_current(void)
00270 {
00271         return current_lang;
00272 }

Sambaに対してSat Aug 29 21:22:58 2009に生成されました。  doxygen 1.4.7