Add forgotten files 1.4.70b
[polyglot.git] / book_merge.c
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
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
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
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
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
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
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
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
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
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