--- /dev/null
+\r
+// book_merge.c\r
+\r
+// includes\r
+\r
+#include <errno.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+#include "book_merge.h"\r
+#include "util.h"\r
+\r
+// types\r
+\r
+typedef struct {\r
+ FILE * file;\r
+ int size;\r
+} book_t;\r
+\r
+typedef struct {\r
+ uint64 key;\r
+ uint16 move;\r
+ uint16 count;\r
+ uint16 n;\r
+ uint16 sum;\r
+} entry_t;\r
+\r
+// variables\r
+\r
+static book_t In1[1];\r
+static book_t In2[1];\r
+static book_t Out[1];\r
+\r
+// prototypes\r
+\r
+static void book_clear (book_t * book);\r
+\r
+static void book_open (book_t * book, const char file_name[], const char mode[]);\r
+static void book_close (book_t * book);\r
+\r
+static bool read_entry (book_t * book, entry_t * entry, int n);\r
+static void write_entry (book_t * book, const entry_t * entry);\r
+\r
+static uint64 read_integer (FILE * file, int size);\r
+static void write_integer (FILE * file, int size, uint64 n);\r
+\r
+// functions\r
+\r
+// book_merge()\r
+\r
+void book_merge(int argc, char * argv[]) {\r
+\r
+ int i;\r
+ const char * in_file_1;\r
+ const char * in_file_2;\r
+ const char * out_file;\r
+ int i1, i2;\r
+ bool b1, b2;\r
+ entry_t e1[1], e2[1];\r
+ int skip;\r
+\r
+ in_file_1 = NULL;\r
+ my_string_clear(&in_file_1);\r
+\r
+ in_file_2 = NULL;\r
+ my_string_clear(&in_file_2);\r
+\r
+ out_file = NULL;\r
+ my_string_set(&out_file,"out.bin");\r
+\r
+ for (i = 1; i < argc; i++) {\r
+\r
+ if (FALSE) {\r
+\r
+ } else if (my_string_equal(argv[i],"merge-book")) {\r
+\r
+ // skip\r
+\r
+ } else if (my_string_equal(argv[i],"-in1")) {\r
+\r
+ i++;\r
+ if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+ my_string_set(&in_file_1,argv[i]);\r
+\r
+ } else if (my_string_equal(argv[i],"-in2")) {\r
+\r
+ i++;\r
+ if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+ my_string_set(&in_file_2,argv[i]);\r
+\r
+ } else if (my_string_equal(argv[i],"-out")) {\r
+\r
+ i++;\r
+ if (argv[i] == NULL) my_fatal("book_merge(): missing argument\n");\r
+\r
+ my_string_set(&out_file,argv[i]);\r
+\r
+ } else {\r
+\r
+ my_fatal("book_merge(): unknown option \"%s\"\n",argv[i]);\r
+ }\r
+ }\r
+\r
+ book_clear(In1);\r
+ book_clear(In2);\r
+ book_clear(Out);\r
+\r
+ book_open(In1,in_file_1,"rb");\r
+ book_open(In2,in_file_2,"rb");\r
+ book_open(Out,out_file,"wb");\r
+\r
+ skip = 0;\r
+\r
+ i1 = 0;\r
+ i2 = 0;\r
+\r
+ while (TRUE) {\r
+\r
+ b1 = read_entry(In1,e1,i1);\r
+ b2 = read_entry(In2,e2,i2);\r
+\r
+ if (FALSE) {\r
+\r
+ } else if (!b1 && !b2) {\r
+\r
+ break;\r
+\r
+ } else if (b1 && !b2) {\r
+\r
+ write_entry(Out,e1);\r
+ i1++;\r
+\r
+ } else if (b2 && !b1) {\r
+\r
+ write_entry(Out,e2);\r
+ i2++;\r
+\r
+ } else {\r
+\r
+ ASSERT(b1);\r
+ ASSERT(b2);\r
+\r
+ if (FALSE) {\r
+ } else if (e1->key < e2->key) {\r
+ write_entry(Out,e1);\r
+ i1++;\r
+ } else if (e1->key > e2->key) {\r
+ write_entry(Out,e2);\r
+ i2++;\r
+ } else {\r
+ ASSERT(e1->key==e2->key);\r
+ skip++;\r
+ i2++;\r
+ }\r
+ }\r
+ }\r
+\r
+ book_close(In1);\r
+ book_close(In2);\r
+ book_close(Out);\r
+\r
+ if (skip != 0) {\r
+ printf("skipped %d entr%s.\n",skip,(skip>1)?"ies":"y");\r
+ }\r
+\r
+ printf("done!\n");\r
+}\r
+\r
+// book_clear()\r
+\r
+static void book_clear(book_t * book) {\r
+\r
+ ASSERT(book!=NULL);\r
+\r
+ book->file = NULL;\r
+ book->size = 0;\r
+}\r
+\r
+// book_open()\r
+\r
+static void book_open(book_t * book, const char file_name[], const char mode[]) {\r
+\r
+ ASSERT(book!=NULL);\r
+ ASSERT(file_name!=NULL);\r
+ ASSERT(mode!=NULL);\r
+\r
+ book->file = fopen(file_name,mode);\r
+ if (book->file == NULL) my_fatal("book_open(): can't open file \"%s\": %s\n",file_name,strerror(errno));\r
+\r
+ if (fseek(book->file,0,SEEK_END) == -1) {\r
+ my_fatal("book_open(): fseek(): %s\n",strerror(errno));\r
+ }\r
+\r
+ book->size = ftell(book->file) / 16;\r
+}\r
+\r
+// book_close()\r
+\r
+static void book_close(book_t * book) {\r
+\r
+ ASSERT(book!=NULL);\r
+\r
+ if (fclose(book->file) == EOF) {\r
+ my_fatal("book_close(): fclose(): %s\n",strerror(errno));\r
+ }\r
+}\r
+\r
+// read_entry()\r
+\r
+static bool read_entry(book_t * book, entry_t * entry, int n) {\r
+\r
+ ASSERT(book!=NULL);\r
+ ASSERT(entry!=NULL);\r
+\r
+ if (n < 0 || n >= book->size) return FALSE;\r
+\r
+ ASSERT(n>=0&&n<book->size);\r
+\r
+ if (fseek(book->file,n*16,SEEK_SET) == -1) {\r
+ my_fatal("read_entry(): fseek(): %s\n",strerror(errno));\r
+ }\r
+\r
+ entry->key = read_integer(book->file,8);\r
+ entry->move = read_integer(book->file,2);\r
+ entry->count = read_integer(book->file,2);\r
+ entry->n = read_integer(book->file,2);\r
+ entry->sum = read_integer(book->file,2);\r
+\r
+ return TRUE;\r
+}\r
+\r
+// write_entry()\r
+\r
+static void write_entry(book_t * book, const entry_t * entry) {\r
+\r
+ ASSERT(book!=NULL);\r
+ ASSERT(entry!=NULL);\r
+\r
+ write_integer(book->file,8,entry->key);\r
+ write_integer(book->file,2,entry->move);\r
+ write_integer(book->file,2,entry->count);\r
+ write_integer(book->file,2,entry->n);\r
+ write_integer(book->file,2,entry->sum);\r
+}\r
+\r
+// read_integer()\r
+\r
+static uint64 read_integer(FILE * file, int size) {\r
+\r
+ uint64 n;\r
+ int i;\r
+ int b;\r
+\r
+ ASSERT(file!=NULL);\r
+ ASSERT(size>0&&size<=8);\r
+\r
+ n = 0;\r
+\r
+ for (i = 0; i < size; i++) {\r
+\r
+ b = fgetc(file);\r
+\r
+ if (b == EOF) {\r
+ if (feof(file)) {\r
+ my_fatal("read_integer(): fgetc(): EOF reached\n");\r
+ } else { // error\r
+ my_fatal("read_integer(): fgetc(): %s\n",strerror(errno));\r
+ }\r
+ }\r
+\r
+ ASSERT(b>=0&&b<256);\r
+ n = (n << 8) | b;\r
+ }\r
+\r
+ return n;\r
+}\r
+\r
+// write_integer()\r
+\r
+static void write_integer(FILE * file, int size, uint64 n) {\r
+\r
+ int i;\r
+ int b;\r
+\r
+ ASSERT(file!=NULL);\r
+ ASSERT(size>0&&size<=8);\r
+ ASSERT(size==8||n>>(size*8)==0);\r
+\r
+ for (i = size-1; i >= 0; i--) {\r
+\r
+ b = (n >> (i*8)) & 0xFF;\r
+ ASSERT(b>=0&&b<256);\r
+\r
+ if (fputc(b,file) == EOF) {\r
+ my_fatal("write_integer(): fputc(): %s\n",strerror(errno));\r
+ }\r
+ }\r
+}\r
+\r
+// end of book_merge.cpp\r
+\r