libs/lmo: skip all entries with identical key and value when generating lmo archives
[project/luci.git] / libs / lmo / src / lmo_po2lmo.c
1 /*
2 * lmo - Lua Machine Objects - PO to LMO conversion tool
3 *
4 * Copyright (C) 2009-2011 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 "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 dest[pos-off] = src[pos];
56 esc = 0;
57 }
58 else if( src[pos] == '\\' )
59 {
60 off++;
61 esc = 1;
62 }
63 else if( src[pos] != '"' )
64 {
65 dest[pos-off] = src[pos];
66 }
67 else
68 {
69 dest[pos-off] = '\0';
70 break;
71 }
72 }
73 }
74
75 return (off > -1) ? strlen(dest) : -1;
76 }
77
78 int main(int argc, char *argv[])
79 {
80 char line[4096];
81 char key[4096];
82 char val[4096];
83 char tmp[4096];
84 int state = 0;
85 int offset = 0;
86 int length = 0;
87 uint32_t key_id, val_id;
88
89 FILE *in;
90 FILE *out;
91
92 lmo_entry_t *head = NULL;
93 lmo_entry_t *entry = NULL;
94
95 if( (argc != 3) || ((in = fopen(argv[1], "r")) == NULL) || ((out = fopen(argv[2], "w")) == NULL) )
96 usage(argv[0]);
97
98 memset(line, 0, sizeof(key));
99 memset(key, 0, sizeof(val));
100 memset(val, 0, sizeof(val));
101
102 while( (NULL != fgets(line, sizeof(line), in)) || (state >= 2 && feof(in)) )
103 {
104 if( state == 0 && strstr(line, "msgid \"") == line )
105 {
106 switch(extract_string(line, key, sizeof(key)))
107 {
108 case -1:
109 die("Syntax error in msgid");
110 case 0:
111 state = 1;
112 break;
113 default:
114 state = 2;
115 }
116 }
117 else if( state == 1 || state == 2 )
118 {
119 if( strstr(line, "msgstr \"") == line || state == 2 )
120 {
121 switch(extract_string(line, val, sizeof(val)))
122 {
123 case -1:
124 state = 4;
125 break;
126 default:
127 state = 3;
128 }
129 }
130 else
131 {
132 switch(extract_string(line, tmp, sizeof(tmp)))
133 {
134 case -1:
135 state = 2;
136 break;
137 default:
138 strcat(key, tmp);
139 }
140 }
141 }
142 else if( state == 3 )
143 {
144 switch(extract_string(line, tmp, sizeof(tmp)))
145 {
146 case -1:
147 state = 4;
148 break;
149 default:
150 strcat(val, tmp);
151 }
152 }
153
154 if( state == 4 )
155 {
156 if( strlen(key) > 0 && strlen(val) > 0 )
157 {
158 key_id = sfh_hash(key, strlen(key));
159 val_id = sfh_hash(val, strlen(val));
160
161 if( key_id != val_id )
162 {
163 if( (entry = (lmo_entry_t *) malloc(sizeof(lmo_entry_t))) != NULL )
164 {
165 memset(entry, 0, sizeof(entry));
166 length = strlen(val) + ((4 - (strlen(val) % 4)) % 4);
167
168 entry->key_id = htonl(key_id);
169 entry->val_id = htonl(val_id);
170 entry->offset = htonl(offset);
171 entry->length = htonl(strlen(val));
172
173 print(val, length, 1, out);
174 offset += length;
175
176 entry->next = head;
177 head = entry;
178 }
179 else
180 {
181 die("Out of memory");
182 }
183 }
184 }
185
186 state = 0;
187 memset(key, 0, sizeof(key));
188 memset(val, 0, sizeof(val));
189 }
190
191 memset(line, 0, sizeof(line));
192 }
193
194 entry = head;
195 while( entry != NULL )
196 {
197 print(&entry->key_id, sizeof(uint32_t), 1, out);
198 print(&entry->val_id, sizeof(uint32_t), 1, out);
199 print(&entry->offset, sizeof(uint32_t), 1, out);
200 print(&entry->length, sizeof(uint32_t), 1, out);
201 entry = entry->next;
202 }
203
204 if( offset > 0 )
205 {
206 offset = htonl(offset);
207 print(&offset, sizeof(uint32_t), 1, out);
208 fsync(fileno(out));
209 fclose(out);
210 }
211 else
212 {
213 fclose(out);
214 unlink(argv[2]);
215 }
216
217 fclose(in);
218 return(0);
219 }