2 * lmo - Lua Machine Objects - PO to LMO conversion tool
4 * Copyright (C) 2009-2012 Jo-Philipp Wich <jow@openwrt.org>
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include "template_lmo.h"
21 static void die(const char *msg)
23 fprintf(stderr, "Error: %s\n", msg);
27 static void usage(const char *name)
29 fprintf(stderr, "Usage: %s input.po output.lmo\n", name);
33 static void print(const void *ptr, size_t size, size_t nmemb, FILE *stream)
37 if (fwrite(ptr, size, nmemb, stream) == 0)
38 die("Failed to write");
40 for (i = 0; i < ((4 - (size % 4)) % 4); i++)
42 die("Failed to write");
45 static int extract_string(const char *src, char *dest, int len)
54 for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
56 if( (off == -1) && (src[pos] == '"') )
71 dest[pos-off] = src[pos];
74 else if( src[pos] == '\\' )
76 dest[pos-off] = src[pos];
79 else if( src[pos] != '"' )
81 dest[pos-off] = src[pos];
91 return (off > -1) ? strlen(dest) : -1;
94 static int cmp_index(const void *a, const void *b)
96 uint32_t x = ((const lmo_entry_t *)a)->key_id;
97 uint32_t y = ((const lmo_entry_t *)b)->key_id;
107 static void print_uint32(uint32_t x, FILE *out)
109 uint32_t y = htonl(x);
110 print(&y, sizeof(uint32_t), 1, out);
113 static void print_index(void *array, int n, FILE *out)
117 qsort(array, n, sizeof(*e), cmp_index);
119 for (e = array; n > 0; n--, e++)
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);
146 static void *array = NULL;
147 static int n_entries = 0;
148 static size_t offset = 0;
150 static void print_msg(struct msg *msg, FILE *out)
152 char key[4096], *field, *p;
153 uint32_t key_id, val_id;
158 if (msg->id && msg->val[0]) {
159 for (i = 0; i <= msg->plural_num; i++) {
163 if (msg->ctxt && msg->id_plural)
164 snprintf(key, sizeof(key), "%s\1%s\2%d", msg->ctxt, msg->id, i);
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);
170 snprintf(key, sizeof(key), "%s", msg->id);
172 key_id = sfh_hash(key, strlen(key));
173 val_id = sfh_hash(msg->val[i], strlen(msg->val[i]));
175 if (key_id != val_id) {
177 array = realloc(array, n_entries * sizeof(lmo_entry_t));
180 die("Out of memory");
182 entry = (lmo_entry_t *)array + n_entries - 1;
183 entry->key_id = key_id;
184 entry->val_id = msg->plural_num + 1;
185 entry->offset = offset;
186 entry->length = strlen(msg->val[i]);
188 len = entry->length + ((4 - (entry->length % 4)) % 4);
190 print(msg->val[i], entry->length, 1, out);
195 else if (msg->val[0]) {
196 for (field = msg->val[0], p = field, esc = 0; *p; p++) {
201 if (!strncasecmp(field, "Plural-Forms: ", 14)) {
205 array = realloc(array, n_entries * sizeof(lmo_entry_t));
208 die("Out of memory");
210 entry = (lmo_entry_t *)array + n_entries - 1;
213 entry->offset = offset;
214 entry->length = strlen(field);
216 len = entry->length + ((4 - (entry->length % 4)) % 4);
218 print(field, entry->length, 1, out);
228 else if (*p == '\\') {
236 free(msg->id_plural);
238 for (i = 0; i < sizeof(msg->val) / sizeof(msg->val[0]); i++)
241 memset(msg, 0, sizeof(*msg));
244 int main(int argc, char *argv[])
246 struct msg msg = { .plural_num = -1 };
247 char line[4096], tmp[4096];
252 if ((argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL))
257 eof = !fgets(line, sizeof(line), in);
259 if (!strncmp(line, "msgctxt \"", 9)) {
260 if (msg.id || msg.val[0])
261 print_msg(&msg, out);
269 else if (eof || !strncmp(line, "msgid \"", 7)) {
270 if (msg.id || msg.val[0])
271 print_msg(&msg, out);
279 else if (!strncmp(line, "msgid_plural \"", 14)) {
281 msg.id_plural = NULL;
282 msg.cur = &msg.id_plural;
285 else if (!strncmp(line, "msgstr \"", 8) || !strncmp(line, "msgstr[", 7)) {
287 msg.plural_num = strtoul(line + 7, NULL, 10);
291 if (msg.plural_num >= 10)
292 die("Too many plural forms");
294 free(msg.val[msg.plural_num]);
295 msg.val[msg.plural_num] = NULL;
296 msg.cur = &msg.val[msg.plural_num];
304 len = extract_string(line, tmp, sizeof(tmp));
307 *msg.cur = realloc(*msg.cur, msg.len + len + 1);
310 die("Out of memory");
312 memcpy(*msg.cur + msg.len, tmp, len + 1);
318 print_index(array, n_entries, out);
321 print_uint32(offset, out);