Translated using Weblate (Lithuanian)
[project/luci.git] / modules / luci-base / src / po2lmo.c
1 /*
2 * lmo - Lua Machine Objects - PO to LMO conversion tool
3 *
4 * Copyright (C) 2009-2012 Jo-Philipp Wich <jow@openwrt.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 #include "lib/lmo.h"
20
21 static void die(const char *msg)
22 {
23 fprintf(stderr, "Error: %s\n", msg);
24 exit(1);
25 }
26
27 static void usage(const char *name)
28 {
29 fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
30 exit(1);
31 }
32
33 static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
34 {
35 int i;
36
37 if (fwrite(ptr, size, nmemb, stream) == 0)
38 die("Failed to write");
39
40 for (i = 0; i < ((4 - (size % 4)) % 4); i++)
41 if (fputc(0, stream))
42 die("Failed to write");
43 }
44
45 static int extract_string(const char *src, char *dest, int len)
46 {
47 int pos = 0;
48 int esc = 0;
49 int off = -1;
50
51 if (*src == '#')
52 return -1;
53
54 for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
55 {
56 if( (off == -1) && (src[pos] == '"') )
57 {
58 off = pos + 1;
59 }
60 else if( off >= 0 )
61 {
62 if( esc == 1 )
63 {
64 switch (src[pos])
65 {
66 case '"':
67 case '\\':
68 off++;
69 break;
70 }
71 dest[pos-off] = src[pos];
72 esc = 0;
73 }
74 else if( src[pos] == '\\' )
75 {
76 dest[pos-off] = src[pos];
77 esc = 1;
78 }
79 else if( src[pos] != '"' )
80 {
81 dest[pos-off] = src[pos];
82 }
83 else
84 {
85 dest[pos-off] = '\0';
86 break;
87 }
88 }
89 }
90
91 return (off > -1) ? strlen(dest) : -1;
92 }
93
94 static int cmp_index(const void *a, const void *b)
95 {
96 uint32_t x = ((const lmo_entry_t *)a)->key_id;
97 uint32_t y = ((const lmo_entry_t *)b)->key_id;
98
99 if (x < y)
100 return -1;
101 else if (x > y)
102 return 1;
103
104 return 0;
105 }
106
107 static void print_uint32(uint32_t x, FILE *out)
108 {
109 uint32_t y = htonl(x);
110 print(&y, sizeof(uint32_t), 1, out);
111 }
112
113 static void print_index(void *array, int n, FILE *out)
114 {
115 lmo_entry_t *e;
116
117 qsort(array, n, sizeof(*e), cmp_index);
118
119 for (e = array; n > 0; n--, e++)
120 {
121 print_uint32(e->key_id, out);
122 print_uint32(e->val_id, out);
123 print_uint32(e->offset, out);
124 print_uint32(e->length, out);
125 }
126 }
127
128 enum fieldtype {
129 UNSPEC = 0,
130 MSG_CTXT = 1,
131 MSG_ID = 2,
132 MSG_ID_PLURAL = 3,
133 MSG_STR = 4
134 };
135
136 struct msg {
137 int plural_num;
138 char *ctxt;
139 char *id;
140 char *id_plural;
141 char *val[10];
142 size_t len;
143 char **cur;
144 };
145
146 static void *array = NULL;
147 static int n_entries = 0;
148 static size_t offset = 0;
149
150 static void print_msg(struct msg *msg, FILE *out)
151 {
152 char key[4096], *field, *p;
153 uint32_t key_id, val_id;
154 lmo_entry_t *entry;
155 size_t len;
156 int esc, i;
157
158 if (msg->id && msg->val[0]) {
159 for (i = 0; i <= msg->plural_num; i++) {
160 if (!msg->val[i])
161 continue;
162
163 if (msg->ctxt && msg->id_plural)
164 snprintf(key, sizeof(key), "%s\1%s\2%d", msg->ctxt, msg->id, i);
165 else if (msg->ctxt)
166 snprintf(key, sizeof(key), "%s\1%s", msg->ctxt, msg->id);
167 else if (msg->id_plural)
168 snprintf(key, sizeof(key), "%s\2%d", msg->id, i);
169 else
170 snprintf(key, sizeof(key), "%s", msg->id);
171
172 len = strlen(key);
173 key_id = sfh_hash(key, len, len);
174
175 len = strlen(msg->val[i]);
176 val_id = sfh_hash(msg->val[i], len, len);
177
178 if (key_id != val_id) {
179 n_entries++;
180 array = realloc(array, n_entries * sizeof(lmo_entry_t));
181
182 if (!array)
183 die("Out of memory");
184
185 entry = (lmo_entry_t *)array + n_entries - 1;
186 entry->key_id = key_id;
187 entry->val_id = msg->plural_num + 1;
188 entry->offset = offset;
189 entry->length = strlen(msg->val[i]);
190
191 len = entry->length + ((4 - (entry->length % 4)) % 4);
192
193 print(msg->val[i], entry->length, 1, out);
194 offset += len;
195 }
196 }
197 }
198 else if (msg->val[0]) {
199 for (field = msg->val[0], p = field, esc = 0; *p; p++) {
200 if (esc) {
201 if (*p == 'n') {
202 p[-1] = 0;
203
204 if (!strncasecmp(field, "Plural-Forms: ", 14)) {
205 field += 14;
206
207 n_entries++;
208 array = realloc(array, n_entries * sizeof(lmo_entry_t));
209
210 if (!array)
211 die("Out of memory");
212
213 entry = (lmo_entry_t *)array + n_entries - 1;
214 entry->key_id = 0;
215 entry->val_id = 0;
216 entry->offset = offset;
217 entry->length = strlen(field);
218
219 len = entry->length + ((4 - (entry->length % 4)) % 4);
220
221 print(field, entry->length, 1, out);
222 offset += len;
223 break;
224 }
225
226 field = p + 1;
227 }
228
229 esc = 0;
230 }
231 else if (*p == '\\') {
232 esc = 1;
233 }
234 }
235 }
236
237 free(msg->ctxt);
238 free(msg->id);
239 free(msg->id_plural);
240
241 for (i = 0; i < sizeof(msg->val) / sizeof(msg->val[0]); i++)
242 free(msg->val[i]);
243
244 memset(msg, 0, sizeof(*msg));
245 }
246
247 int main(int argc, char *argv[])
248 {
249 struct msg msg = { .plural_num = -1 };
250 char line[4096], tmp[4096];
251 FILE *in, *out;
252 ssize_t len;
253 int eof;
254
255 if ((argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL))
256 usage(argv[0]);
257
258 while (1) {
259 line[0] = 0;
260 eof = !fgets(line, sizeof(line), in);
261
262 if (!strncmp(line, "msgctxt \"", 9)) {
263 if (msg.id || msg.val[0])
264 print_msg(&msg, out);
265 else
266 free(msg.ctxt);
267
268 msg.ctxt = NULL;
269 msg.cur = &msg.ctxt;
270 msg.len = 0;
271 }
272 else if (eof || !strncmp(line, "msgid \"", 7)) {
273 if (msg.id || msg.val[0])
274 print_msg(&msg, out);
275 else
276 free(msg.id);
277
278 msg.id = NULL;
279 msg.cur = &msg.id;
280 msg.len = 0;
281 }
282 else if (!strncmp(line, "msgid_plural \"", 14)) {
283 free(msg.id_plural);
284 msg.id_plural = NULL;
285 msg.cur = &msg.id_plural;
286 msg.len = 0;
287 }
288 else if (!strncmp(line, "msgstr \"", 8) || !strncmp(line, "msgstr[", 7)) {
289 if (line[6] == '[')
290 msg.plural_num = strtoul(line + 7, NULL, 10);
291 else
292 msg.plural_num = 0;
293
294 if (msg.plural_num >= 10)
295 die("Too many plural forms");
296
297 free(msg.val[msg.plural_num]);
298 msg.val[msg.plural_num] = NULL;
299 msg.cur = &msg.val[msg.plural_num];
300 msg.len = 0;
301 }
302
303 if (eof)
304 break;
305
306 if (msg.cur) {
307 len = extract_string(line, tmp, sizeof(tmp));
308
309 if (len > 0) {
310 *msg.cur = realloc(*msg.cur, msg.len + len + 1);
311
312 if (!*msg.cur)
313 die("Out of memory");
314
315 memcpy(*msg.cur + msg.len, tmp, len + 1);
316 msg.len += len;
317 }
318 }
319 }
320
321 print_index(array, n_entries, out);
322
323 if (offset > 0) {
324 print_uint32(offset, out);
325 fsync(fileno(out));
326 fclose(out);
327 }
328 else {
329 fclose(out);
330 unlink(argv[2]);
331 }
332
333 fclose(in);
334 return(0);
335 }