~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source3/intl/lang_tdb.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   tdb based replacement for gettext 
 
4
   Copyright (C) Andrew Tridgell 2001
 
5
   
 
6
   This program is free software; you can redistribute it and/or modify
 
7
   it under the terms of the GNU General Public License as published by
 
8
   the Free Software Foundation; either version 3 of the License, or
 
9
   (at your option) any later version.
 
10
   
 
11
   This program is distributed in the hope that it will be useful,
 
12
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
   GNU General Public License for more details.
 
15
   
 
16
   You should have received a copy of the GNU General Public License
 
17
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include "includes.h"
 
21
 
 
22
static TDB_CONTEXT *tdb;
 
23
 
 
24
/* the currently selected language */
 
25
static char *current_lang;
 
26
 
 
27
 
 
28
/* load a msg file into the tdb */
 
29
static bool load_msg(const char *msg_file)
 
30
{
 
31
        char **lines;
 
32
        int num_lines, i;
 
33
        char *msgid, *msgstr;
 
34
        TDB_DATA data;
 
35
 
 
36
        lines = file_lines_load(msg_file, &num_lines, 0, NULL);
 
37
 
 
38
        if (!lines) {
 
39
                return False;
 
40
        }
 
41
 
 
42
        if (tdb_lockall(tdb) != 0) {
 
43
                TALLOC_FREE(lines);
 
44
                return False;
 
45
        }
 
46
 
 
47
        /* wipe the db */
 
48
        tdb_wipe_all(tdb);
 
49
 
 
50
        msgid = NULL;
 
51
        
 
52
        for (i=0;i<num_lines;i++) {
 
53
                if (strncmp(lines[i], "msgid \"", 7) == 0) {
 
54
                        msgid = lines[i] + 7;
 
55
                }
 
56
                if (msgid && strncmp(lines[i], "msgstr \"", 8) == 0) {
 
57
                        msgstr = lines[i] + 8;
 
58
                        trim_char(msgid, '\0', '\"');
 
59
                        trim_char(msgstr, '\0', '\"');
 
60
                        if (*msgstr == 0) {
 
61
                                msgstr = msgid;
 
62
                        }
 
63
                        all_string_sub(msgid, "\\n", "\n", 0);
 
64
                        all_string_sub(msgstr, "\\n", "\n", 0);
 
65
                        data = string_term_tdb_data(msgstr);
 
66
                        tdb_store_bystring(tdb, msgid, data, 0);
 
67
                        msgid = NULL;
 
68
                }
 
69
        }
 
70
 
 
71
        TALLOC_FREE(lines);
 
72
        tdb_unlockall(tdb);
 
73
 
 
74
        return True;
 
75
}
 
76
 
 
77
 
 
78
/* work out what language to use from locale variables */
 
79
static const char *get_lang(void)
 
80
{
 
81
        const char *vars[] = {"LANGUAGE", "LC_ALL", "LC_LANG", "LANG", NULL};
 
82
        int i;
 
83
        char *p;
 
84
 
 
85
        for (i=0; vars[i]; i++) {
 
86
                if ((p = getenv(vars[i]))) {
 
87
                        return p;
 
88
                }
 
89
        }
 
90
 
 
91
        return NULL;
 
92
}
 
93
 
 
94
/* initialise the message translation subsystem. If the "lang" argument
 
95
   is NULL then get the language from the normal environment variables */
 
96
bool lang_tdb_init(const char *lang)
 
97
{
 
98
        char *path = NULL;
 
99
        char *msg_path = NULL;
 
100
        struct stat st;
 
101
        static int initialised;
 
102
        time_t loadtime;
 
103
        bool result = False;
 
104
 
 
105
        /* we only want to init once per process, unless given
 
106
           an override */
 
107
        if (initialised && !lang) 
 
108
                return True;
 
109
 
 
110
        if (initialised) {
 
111
                /* we are re-initialising, free up any old init */
 
112
                if (tdb) {
 
113
                        tdb_close(tdb);
 
114
                        tdb = NULL;
 
115
                }
 
116
                SAFE_FREE(current_lang);
 
117
        }
 
118
 
 
119
        initialised = 1;
 
120
 
 
121
        if (!lang) {
 
122
                /* no lang given, use environment */
 
123
                lang = get_lang();
 
124
        }
 
125
 
 
126
        /* if no lang then we don't translate */
 
127
        if (!lang) 
 
128
                return True;
 
129
 
 
130
        if (asprintf(&msg_path, "%s.msg",
 
131
                     data_path((const char *)lang)) == -1) {
 
132
                DEBUG(0, ("asprintf failed\n"));
 
133
                goto done;
 
134
        }
 
135
        if (stat(msg_path, &st) != 0) {
 
136
                /* the msg file isn't available */
 
137
                DEBUG(10, ("lang_tdb_init: %s: %s\n", msg_path, 
 
138
                           strerror(errno)));
 
139
                goto done;
 
140
        }
 
141
        
 
142
        if (asprintf(&path, "%s%s.tdb", lock_path("lang_"), lang) == -1) {
 
143
                DEBUG(0, ("asprintf failed\n"));
 
144
                goto done;
 
145
        }
 
146
 
 
147
        DEBUG(10, ("lang_tdb_init: loading %s\n", path));
 
148
 
 
149
        tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0644);
 
150
        if (!tdb) {
 
151
                tdb = tdb_open_log(path, 0, TDB_DEFAULT, O_RDONLY, 0);
 
152
                if (!tdb) {
 
153
                        DEBUG(10, ("lang_tdb_init: %s: %s\n", path,
 
154
                                   strerror(errno)));
 
155
                        goto done;
 
156
                }
 
157
                current_lang = SMB_STRDUP(lang);
 
158
                result = True;
 
159
                goto done;
 
160
        }
 
161
 
 
162
        loadtime = tdb_fetch_int32(tdb, "/LOADTIME/");
 
163
 
 
164
        if (loadtime == -1 || loadtime < st.st_mtime) {
 
165
                load_msg(msg_path);
 
166
                tdb_store_int32(tdb, "/LOADTIME/", (int)time(NULL));
 
167
        }
 
168
 
 
169
        current_lang = SMB_STRDUP(lang);
 
170
        result = True;
 
171
 
 
172
 done:
 
173
        SAFE_FREE(msg_path);
 
174
        SAFE_FREE(path);
 
175
 
 
176
        return result;
 
177
}
 
178
 
 
179
/* translate a msgid to a message string in the current language 
 
180
   returns a string that must be freed by calling lang_msg_free()
 
181
*/
 
182
const char *lang_msg(const char *msgid)
 
183
{
 
184
        TDB_DATA data;
 
185
        const char *p;
 
186
        char *q, *msgid_quoted;
 
187
        int count;
 
188
 
 
189
        lang_tdb_init(NULL);
 
190
 
 
191
        if (!tdb) return msgid;
 
192
 
 
193
        /* Due to the way quotes in msgids are escaped in the msg file we
 
194
           must replace " with \" before doing a lookup in the tdb. */
 
195
 
 
196
        count = 0;
 
197
 
 
198
        for(p = msgid; *p; p++) {
 
199
                if (*p == '\"')
 
200
                        count++;
 
201
        }
 
202
 
 
203
        if (!(msgid_quoted = (char *)SMB_MALLOC(strlen(msgid) + count + 1)))
 
204
                return msgid;
 
205
 
 
206
        /* string_sub() is unsuitable here as it replaces some punctuation
 
207
           chars with underscores. */
 
208
 
 
209
        for(p = msgid, q = msgid_quoted; *p; p++) {
 
210
                if (*p == '\"') {
 
211
                        *q = '\\';
 
212
                        q++;
 
213
                }
 
214
                *q = *p;
 
215
                q++;
 
216
        }
 
217
 
 
218
        *q = 0;
 
219
 
 
220
        data = tdb_fetch_bystring(tdb, msgid_quoted);
 
221
 
 
222
        free(msgid_quoted);
 
223
 
 
224
        /* if the message isn't found then we still need to return a pointer
 
225
           that can be freed. Pity. */
 
226
        if (!data.dptr)
 
227
                return SMB_STRDUP(msgid);
 
228
 
 
229
        return (const char *)data.dptr;
 
230
}
 
231
 
 
232
 
 
233
/* free up a string from lang_msg() */
 
234
void lang_msg_free(const char *msgstr)
 
235
{
 
236
        if (!tdb) return;
 
237
        free((void *)msgstr);
 
238
}
 
239
 
 
240
/* 
 
241
   return the current language - needed for language file mappings 
 
242
*/
 
243
char *lang_tdb_current(void)
 
244
{
 
245
        return current_lang;
 
246
}