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 }