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.
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
);
173 key_id
= sfh_hash(key
, len
, len
);
175 len
= strlen(msg
->val
[i
]);
176 val_id
= sfh_hash(msg
->val
[i
], len
, len
);
178 if (key_id
!= val_id
) {
180 array
= realloc(array
, n_entries
* sizeof(lmo_entry_t
));
183 die("Out of memory");
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
]);
191 len
= entry
->length
+ ((4 - (entry
->length
% 4)) % 4);
193 print(msg
->val
[i
], entry
->length
, 1, out
);
198 else if (msg
->val
[0]) {
199 for (field
= msg
->val
[0], p
= field
, esc
= 0; *p
; p
++) {
204 if (!strncasecmp(field
, "Plural-Forms: ", 14)) {
208 array
= realloc(array
, n_entries
* sizeof(lmo_entry_t
));
211 die("Out of memory");
213 entry
= (lmo_entry_t
*)array
+ n_entries
- 1;
216 entry
->offset
= offset
;
217 entry
->length
= strlen(field
);
219 len
= entry
->length
+ ((4 - (entry
->length
% 4)) % 4);
221 print(field
, entry
->length
, 1, out
);
231 else if (*p
== '\\') {
239 free(msg
->id_plural
);
241 for (i
= 0; i
< sizeof(msg
->val
) / sizeof(msg
->val
[0]); i
++)
244 memset(msg
, 0, sizeof(*msg
));
247 int main(int argc
, char *argv
[])
249 struct msg msg
= { .plural_num
= -1 };
250 char line
[4096], tmp
[4096];
255 if ((argc
!= 3) || ((in
= fopen(argv
[1], "r")) == NULL
) || ((out
= fopen(argv
[2], "w")) == NULL
))
260 eof
= !fgets(line
, sizeof(line
), in
);
262 if (!strncmp(line
, "msgctxt \"", 9)) {
263 if (msg
.id
|| msg
.val
[0])
264 print_msg(&msg
, out
);
272 else if (eof
|| !strncmp(line
, "msgid \"", 7)) {
273 if (msg
.id
|| msg
.val
[0])
274 print_msg(&msg
, out
);
282 else if (!strncmp(line
, "msgid_plural \"", 14)) {
284 msg
.id_plural
= NULL
;
285 msg
.cur
= &msg
.id_plural
;
288 else if (!strncmp(line
, "msgstr \"", 8) || !strncmp(line
, "msgstr[", 7)) {
290 msg
.plural_num
= strtoul(line
+ 7, NULL
, 10);
294 if (msg
.plural_num
>= 10)
295 die("Too many plural forms");
297 free(msg
.val
[msg
.plural_num
]);
298 msg
.val
[msg
.plural_num
] = NULL
;
299 msg
.cur
= &msg
.val
[msg
.plural_num
];
307 len
= extract_string(line
, tmp
, sizeof(tmp
));
310 *msg
.cur
= realloc(*msg
.cur
, msg
.len
+ len
+ 1);
313 die("Out of memory");
315 memcpy(*msg
.cur
+ msg
.len
, tmp
, len
+ 1);
321 print_index(array
, n_entries
, out
);
324 print_uint32(offset
, out
);