1
2 // book_merge.c
3
4 // includes
5
6 #include <errno.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "book_merge.h"
12 #include "util.h"
13 #include "pgheader.h"
14
15 // macros
16
17 #define MAXVARIANTS 50
18
19 // types
20
21 typedef struct {
22 FILE * file;
23 int size;
24 } book_t;
25
26 typedef struct {
27 uint64 key;
28 uint16 move;
29 uint16 count;
30 uint16 n;
31 uint16 sum;
32 } entry_t;
33
34 // variables
35
36 static book_t In1[1];
37 static book_t In2[1];
38 static book_t Out[1];
39
40 static const char *default_header="@PG@\n1.0\n1\nnormal\n";
41
42 // prototypes
43
44 static void book_clear (book_t * book);
45
46 static void book_open (book_t * book, const char file_name[], const char mode[]);
47 static void book_close (book_t * book);
48
49 static bool read_entry (book_t * book, entry_t * entry, int n);
50 static void write_entry (book_t * book, const entry_t * entry);
51
52 static uint64 read_integer (FILE * file, int size);
53 static void write_integer (FILE * file, int size, uint64 n);
54
55 // functions
56
57 // variants_merge()
58
variants_merge(char ** variants,char * variants1,char * variants2)59 static void variants_merge(char ** variants, char *variants1, char *variants2){
60
61 char *token;
62 int ret,i,j;
63 int count;
64 char *variants1_dup;
65 char *variants2_dup;
66 char *variant;
67 char *variants_list;
68
69
70 // Step 1: Initial malloc
71
72 *variants=malloc(strlen(variants1)+strlen(variants2)+1+1);
73 (*variants)[0]='\0';
74
75 // Step 2: Loop through the variant names
76
77 variants1_dup=strdup(variants1);
78 variants2_dup=strdup(variants2);
79
80 for(i=0;i<2;i++){
81 variants_list=(i==0)?variants1_dup:variants2_dup;
82 variant=strtok(variants_list,"\x0a");
83 while(variant){
84 // TODO: this does not take into account that one variant name
85 // may be contained in another.
86 if(!strstr(*variants,variant)){
87 if((*variants)[0]!=0){
88 strcat(*variants,"\x0a");
89 }
90 strcat(*variants,variant);
91 }
92 variant=strtok(NULL,"\x0a");
93 }
94 }
95 free(variants1_dup);
96 free(variants2_dup);
97
98 }
99
100
101 // book_merge()
102
book_merge(int argc,char * argv[])103 void book_merge(int argc, char * argv[]) {
104
105 int i;
106 const char * in_file_1;
107 const char * in_file_2;
108 const char * out_file;
109 char *header1;
110 char *header2;
111 char *header;
112 char *variants;
113 char *comment;
114 char *variants1;
115 char *variants2;
116 char *raw_header;
117 int size;
118 char ret;
119 int i1, i2;
120 bool b1, b2;
121 entry_t e1[1], e2[1];
122 int skip;
123
124 in_file_1 = NULL;
125 my_string_clear(&in_file_1);
126
127 in_file_2 = NULL;
128 my_string_clear(&in_file_2);
129
130 out_file = NULL;
131 my_string_set(&out_file,"out.bin");
132
133 for (i = 1; i < argc; i++) {
134
135 if (FALSE) {
136
137 } else if (my_string_equal(argv[i],"merge-book")) {
138
139 // skip
140
141 } else if (my_string_equal(argv[i],"-in1")) {
142
143 i++;
144 if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");
145
146 my_string_set(&in_file_1,argv[i]);
147
148 } else if (my_string_equal(argv[i],"-in2")) {
149
150 i++;
151 if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");
152
153 my_string_set(&in_file_2,argv[i]);
154
155 } else if (my_string_equal(argv[i],"-out")) {
156
157 i++;
158 if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");
159
160 my_string_set(&out_file,argv[i]);
161
162 } else {
163
164 my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]);
165 }
166 }
167
168
169 ret=pgheader_read(&header1,in_file_1);
170 if(ret){
171 switch(ret){
172 case PGHEADER_NO_HEADER:
173 pgheader_create(&header1,"normal","");
174 break;
175 case PGHEADER_OS_ERROR:
176 my_fatal("book_merge(): %s: %s\n",in_file_1,strerror(errno));
177 default:
178 my_fatal("book_merge(): Could not read header of %s\n",in_file_1);
179 }
180 }
181 ret=pgheader_read(&header2,in_file_2);
182 if(ret){
183 switch(ret){
184 case PGHEADER_NO_HEADER:
185 pgheader_create(&header2,"normal","");
186 break;
187 case PGHEADER_OS_ERROR:
188 my_fatal("book_merge(): %s: %s\n",in_file_2,strerror(errno));
189 default:
190 my_fatal("book_merge(): Could not read header of %s\n",in_file_2);
191 }
192 }
193
194 pgheader_parse(header1,&variants1,&comment);
195 free(header1);
196 free(comment);
197 pgheader_parse(header2,&variants2,&comment);
198 free(header2);
199 free(comment);
200 variants_merge(&variants,variants1,variants2);
201 free(variants1);
202 free(variants2);
203
204 pgheader_create(&header,variants,"Created by Polyglot.");
205 free(variants);
206 pgheader_create_raw(&raw_header,header,&size);
207 free(header);
208
209 book_clear(In1);
210 book_clear(In2);
211 book_clear(Out);
212
213 book_open(In1,in_file_1,"rb");
214 book_open(In2,in_file_2,"rb");
215 book_open(Out,out_file,"wb");
216
217 // write header
218
219 for(i=0;i<size;i++){
220 fputc(raw_header[i],Out->file);
221 }
222 free(raw_header);
223
224 skip = 0;
225
226 i1 = 0;
227 i2 = 0;
228
229
230
231 while (TRUE) {
232
233 do{
234 b1 = read_entry(In1,e1,i1);
235 }while(b1 && e1->key==U64(0x0) && (++i1));
236
237 do{
238 b2 = read_entry(In2,e2,i2);
239 }while(b2 && e2->key==U64(0x0) && (++i2));
240
241 if (FALSE) {
242
243 } else if (!b1 && !b2) {
244
245 break;
246
247 } else if (b1 && !b2) {
248 write_entry(Out,e1);
249 i1++;
250
251 } else if (b2 && !b1) {
252
253 write_entry(Out,e2);
254 i2++;
255
256 } else {
257
258 ASSERT(b1);
259 ASSERT(b2);
260
261 if (FALSE) {
262 } else if (e1->key < e2->key) {
263 write_entry(Out,e1);
264 i1++;
265 } else if (e1->key > e2->key) {
266 write_entry(Out,e2);
267 i2++;
268 } else {
269 ASSERT(e1->key==e2->key);
270 skip++;
271 i2++;
272 }
273 }
274 }
275
276 book_close(In1);
277 book_close(In2);
278 book_close(Out);
279
280 if (skip != 0) {
281 printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y");
282 }
283
284 printf("done!\n");
285 }
286
287 // book_clear()
288
book_clear(book_t * book)289 static void book_clear(book_t * book) {
290
291 ASSERT(book!=NULL);
292
293 book->file = NULL;
294 book->size = 0;
295 }
296
297 // book_open()
298
book_open(book_t * book,const char file_name[],const char mode[])299 static void book_open(book_t * book, const char file_name[], const char mode[]) {
300
301 ASSERT(book!=NULL);
302 ASSERT(file_name!=NULL);
303 ASSERT(mode!=NULL);
304
305 book->file = fopen(file_name,mode);
306 if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));
307
308 if (fseek(book->file,0,SEEK_END) == -1) {
309 my_fatal("book_open(): fseek(): %s\n",strerror(errno));
310 }
311
312 book->size = ftell(book->file) / 16;
313 }
314
315 // book_close()
316
book_close(book_t * book)317 static void book_close(book_t * book) {
318
319 ASSERT(book!=NULL);
320
321 if (fclose(book->file) == EOF) {
322 my_fatal("book_close(): fclose(): %s\n",strerror(errno));
323 }
324 }
325
326 // read_entry()
327
read_entry(book_t * book,entry_t * entry,int n)328 static bool read_entry(book_t * book, entry_t * entry, int n) {
329
330 ASSERT(book!=NULL);
331 ASSERT(entry!=NULL);
332
333 if (n < 0 || n >= book->size) return FALSE;
334
335 ASSERT(n>=0&&n<book->size);
336
337 if (fseek(book->file,n*16,SEEK_SET) == -1) {
338 my_fatal("read_entry(): fseek(): %s\n",strerror(errno));
339 }
340
341 entry->key = read_integer(book->file,8);
342 entry->move = read_integer(book->file,2);
343 entry->count = read_integer(book->file,2);
344 entry->n = read_integer(book->file,2);
345 entry->sum = read_integer(book->file,2);
346
347 return TRUE;
348 }
349
350 // write_entry()
351
write_entry(book_t * book,const entry_t * entry)352 static void write_entry(book_t * book, const entry_t * entry) {
353
354 ASSERT(book!=NULL);
355 ASSERT(entry!=NULL);
356
357 write_integer(book->file,8,entry->key);
358 write_integer(book->file,2,entry->move);
359 write_integer(book->file,2,entry->count);
360 write_integer(book->file,2,entry->n);
361 write_integer(book->file,2,entry->sum);
362 }
363
364
365
366 // read_integer()
367
read_integer(FILE * file,int size)368 static uint64 read_integer(FILE * file, int size) {
369
370 uint64 n;
371 int i;
372 int b;
373
374 ASSERT(file!=NULL);
375 ASSERT(size>0&&size<=8);
376
377 n = 0;
378
379 for (i = 0; i < size; i++) {
380
381 b = fgetc(file);
382
383 if (b == EOF) {
384 if (feof(file)) {
385 my_fatal("read_integer(): fgetc(): EOF reached\n");
386 } else { // error
387 my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));
388 }
389 }
390
391 ASSERT(b>=0&&b<256);
392 n = (n << 8) | b;
393 }
394
395 return n;
396 }
397
398 // write_integer()
399
write_integer(FILE * file,int size,uint64 n)400 static void write_integer(FILE * file, int size, uint64 n) {
401
402 int i;
403 int b;
404
405 ASSERT(file!=NULL);
406 ASSERT(size>0&&size<=8);
407 ASSERT(size==8||n>>(size*8)==0);
408
409 for (i = size-1; i >= 0; i--) {
410
411 b = (n >> (i*8)) & 0xFF;
412 ASSERT(b>=0&&b<256);
413
414 if (fputc(b,file) == EOF) {
415 my_fatal("write_integer(): fputc(): %s\n",strerror(errno));
416 }
417 }
418 }
419
420 // end of book_merge.cpp
421
422