0da792b680fa672d2821caebf3255ef099fbcdf2
[project/luci.git] / libs / web / src / po2lmo.c
1 /*
2 * lmo - Lua Machine Objects - PO to LMO conversion tool
3 *
4 * Copyright (C) 2009-2012 Jo-Philipp Wich <xm@subsignal.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 "template_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 if( fwrite(ptr, size, nmemb, stream) == 0 )
36 die("Failed to write stdout");
37 }
38
39 static int extract_string(const char *src, char *dest, int len)
40 {
41 int pos = 0;
42 int esc = 0;
43 int off = -1;
44
45 for( pos = 0; (pos < strlen(src)) && (pos < len); pos++ )
46 {
47 if( (off == -1) && (src[pos] == '"') )
48 {
49 off = pos + 1;
50 }
51 else if( off >= 0 )
52 {
53 if( esc == 1 )
54 {
55 switch (src[pos])
56 {
57 case '"':
58 case '\\':
59 off++;
60 break;
61 }
62 dest[pos-off] = src[pos];
63 esc = 0;
64 }
65 else if( src[pos] == '\\' )
66 {
67 dest[pos-off] = src[pos];
68 esc = 1;
69 }
70 else if( src[pos] != '"' )
71 {
72 dest[pos-off] = src[pos];
73 }
74 else
75 {
76 dest[pos-off] = '\0';
77 break;
78 }
79 }
80 }
81
82 return (off > -1) ? strlen(dest) : -1;
83 }
84
85 static int cmp_index(const void *a, const void *b)
86 {
87 uint32_t x = ((const lmo_entry_t *)a)->key_id;
88 uint32_t y = ((const lmo_entry_t *)b)->key_id;
89
90 if (x < y)
91 return -1;
92 else if (x > y)
93 return 1;
94
95 return 0;
96 }
97
98 static void print_uint32(uint32_t x, FILE *out)
99 {
100 uint32_t y = htonl(x);
101 print(&y, sizeof(uint32_t), 1, out);
102 }
103
104 static void print_index(void *array, int n, FILE *out)
105 {
106 lmo_entry_t *e;
107
108 qsort(array, n, sizeof(*e), cmp_index);
109
110 for (e = array; n > 0; n--, e++)
111 {
112 print_uint32(e->key_id, out);
113 print_uint32(e->val_id, out);
114 print_uint32(e->offset, out);
115 print_uint32(e->length, out);
116 }
117 }
118
119 int main(int argc, char *argv[])
120 {
121 char line[4096];
122 char key[4096];
123 char val[4096];
124 char tmp[4096];
125 int state = 0;
126 int offset = 0;
127 int length = 0;
128 int n_entries = 0;
129 void *array = NULL;
130 lmo_entry_t *entry = NULL;
131 uint32_t key_id, val_id;
132
133 FILE *in;
134 FILE *out;
135
136 if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
137 usage(argv[0]);
138
139 memset(line, 0, sizeof(key));
140 memset(key, 0, sizeof(val));
141 memset(val, 0, sizeof(val));
142
143 while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
144 {
145 if( state == 0 && strstr(line, "msgid \"") == line )
146 {
147 switch(extract_string(line, key, sizeof(key)))
148 {
149 case -1:
150 die("Syntax error in msgid");
151 case 0:
152 state = 1;
153 break;
154 default:
155 state = 2;
156 }
157 }
158 else if( state == 1 || state == 2 )
159 {
160 if( strstr(line, "msgstr \"") == line || state == 2 )
161 {
162 switch(extract_string(line, val, sizeof(val)))
163 {
164 case -1:
165 state = 4;
166 break;
167 default:
168 state = 3;
169 }
170 }
171 else
172 {
173 switch(extract_string(line, tmp, sizeof(tmp)))
174 {
175 case -1:
176 state = 2;
177 break;
178 default:
179 strcat(key, tmp);
180 }
181 }
182 }
183 else if( state == 3 )
184 {
185 switch(extract_string(line, tmp, sizeof(tmp)))
186 {
187 case -1:
188 state = 4;
189 break;
190 default:
191 strcat(val, tmp);
192 }
193 }
194
195 if( state == 4 )
196 {
197 if( strlen(key) > 0 && strlen(val) > 0 )
198 {
199 key_id = sfh_hash(key, strlen(key));
200 val_id = sfh_hash(val, strlen(val));
201
202 if( key_id != val_id )
203 {
204 n_entries++;
205 array = realloc(array, n_entries * sizeof(lmo_entry_t));
206 entry = (lmo_entry_t *)array + n_entries - 1;
207
208 if (!array)
209 die("Out of memory");
210
211 entry->key_id = key_id;
212 entry->val_id = val_id;
213 entry->offset = offset;
214 entry->length = strlen(val);
215
216 length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
217
218 print(val, length, 1, out);
219 offset += length;
220 }
221 }
222
223 state = 0;
224 memset(key, 0, sizeof(key));
225 memset(val, 0, sizeof(val));
226 }
227
228 memset(line, 0, sizeof(line));
229 }
230
231 print_index(array, n_entries, out);
232
233 if( offset > 0 )
234 {
235 print_uint32(offset, out);
236 fsync(fileno(out));
237 fclose(out);
238 }
239 else
240 {
241 fclose(out);
242 unlink(argv[2]);
243 }
244
245 fclose(in);
246 return(0);
247 }