Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
BibleIO.cpp
00001 /* Bible I/O Class Implementation 00002 * 00003 * Copyright (c) 2011 David R. Van Wagner davervw@yahoo.com 00004 * 00005 * Permission is hereby granted, free of charge, to any person obtaining a copy 00006 * of this software and associated documentation files (the "Software"), to deal 00007 * in the Software without restriction, including without limitation the rights 00008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00009 * copies of the Software, and to permit persons to whom the Software is 00010 * furnished to do so, subject to the following conditions: 00011 * 00012 * The above copyright notice and this permission notice shall be included in 00013 * all copies or substantial portions of the Software. 00014 * 00015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 00021 * THE SOFTWARE. 00022 */ 00023 00024 /* 00025 * This class assumes bible text file is present and in a specific format extracted from source such as: 00026 * http://printkjv.ifbweb.com/AV_txt.zip 00027 */ 00028 00029 #include <mbed.h> // mkdir 00030 #include <stdio.h> 00031 #include <string.h> 00032 #include <stdlib.h> 00033 #include <locale> 00034 #include "BibleIO.h" 00035 00036 //extern Serial console; 00037 00038 BibleIO::BibleIO(char* filename, void (*indexing_callback)(int, void*), void* indexing_context) 00039 { 00040 name = 0; 00041 num_books = 0; 00042 books = 0; 00043 bookmarks = 0; 00044 text_filename = filename; 00045 this->indexing_callback = indexing_callback; 00046 this->indexing_context = indexing_context; 00047 00048 fp = fopen(text_filename, "r"); 00049 load_bookmarks(); 00050 00051 if (!load_index()) 00052 build_index(); 00053 } 00054 00055 BibleIO::~BibleIO() 00056 { 00057 delete [] name; 00058 name = 0; 00059 00060 delete [] books; 00061 books = 0; 00062 00063 delete [] bookmarks; 00064 bookmarks = 0; 00065 00066 fclose(fp); 00067 } 00068 00069 void BibleIO::build_index() 00070 { 00071 read_name(); 00072 read_preface(); 00073 read_books(); 00074 load_index(); 00075 } 00076 00077 void BibleIO::read_name() 00078 { 00079 name = read_line(); 00080 00081 //console.printf("name=%s\n", name); 00082 //lcd.printf("%s\n", name); 00083 } 00084 00085 void BibleIO::read_preface() 00086 { 00087 char* line = 0; 00088 long book_offset = ftell(fp); 00089 long line_offset = book_offset; 00090 00091 do 00092 { 00093 if (line != 0 && *line != 0) 00094 book_offset = line_offset; 00095 delete [] line; 00096 line_offset = ftell(fp); 00097 line = read_line(); 00098 //console.printf("%s\n", line); 00099 } while (strcmp(line, "CHAPTER 1") != 0); 00100 delete [] line; 00101 00102 // read too far, reset file pointer 00103 fseek(fp, book_offset, SEEK_SET); 00104 } 00105 00106 void BibleIO::read_books() 00107 { 00108 char* path = index_path(); 00109 mkdir(path, 0666); 00110 delete [] path; 00111 path = 0; 00112 00113 char* fn = index_path("books"); 00114 FILE* index = fopen(fn, "w"); 00115 delete [] fn; 00116 fn = 0; 00117 00118 long title_offset = 0; 00119 fwrite(&title_offset, sizeof(title_offset), 1, index); 00120 00121 short book = 0; 00122 //lcd.cls(); 00123 if (indexing_callback != 0) 00124 (*indexing_callback)(0, indexing_context); 00125 //lcd.printf("Indexing0%%"); 00126 long offset = ftell(fp); 00127 fseek(fp, 0, SEEK_END); 00128 long filesize = ftell(fp); 00129 fseek(fp, offset, SEEK_SET); 00130 while(read_book(index, book)) 00131 { 00132 offset = ftell(fp); 00133 //lcd.printf("\n\n%d%%", offset*100/filesize); 00134 if (indexing_callback != 0) 00135 (*indexing_callback)(offset*100/filesize, indexing_context); 00136 ++book; 00137 } 00138 //lcd.cls(); 00139 //lcd.printf("Complete100%%"); 00140 if (indexing_callback != 0) 00141 (*indexing_callback)(100, indexing_context); 00142 00143 //printf("%hd books\n", book); 00144 00145 fclose(index); 00146 } 00147 00148 bool BibleIO::read_book(FILE* index, short book) 00149 { 00150 long offset = ftell(fp); 00151 00152 char *book_name = BibleIO::read_line(); 00153 if (book_name == 0 || *(book_name) == 0 || strcmp(book_name, "THE END") == 0 00154 || (book_name[0] >= '0' && book_name[0] <= '9')) 00155 { 00156 delete [] book_name; 00157 return false; 00158 } 00159 00160 fwrite(&offset, sizeof(offset), 1, index); 00161 00162 format_book_name(book_name); 00163 //printf("book=%s\n", book_name); 00164 //lcd.cls(); 00165 //lcd.printf("%s_\n", book_name); 00166 00167 delete [] book_name; 00168 00169 short chapter = 0; 00170 while (read_chapter(book, chapter)) 00171 ++chapter; 00172 00173 //console.printf("%hd chapters\n", chapter); 00174 00175 long num_chapters = chapter; 00176 fwrite(&num_chapters, sizeof(num_chapters), 1, index); 00177 00178 return true; 00179 } 00180 00181 void BibleIO::format_book_name(char* &book_name) 00182 { 00183 char* last_word = strrchr(book_name, ' '); 00184 if (last_word != 0) 00185 { 00186 int number = 0; 00187 if (strstr(book_name, "MOSES") == 0) 00188 { 00189 if (strstr(book_name, " FIRST ") != 0) 00190 number = 1; 00191 else if (strstr(book_name, " SECOND ") != 0) 00192 number = 2; 00193 else if (strstr(book_name, " THIRD ") != 0) 00194 number = 3; 00195 } 00196 if (strstr(book_name, "SONG") != 0 || strstr(book_name, "ACTS ") != 0) 00197 last_word = book_name; 00198 if (strstr(book_name, "ECCLESIASTES") != 0 00199 || strstr(book_name, "LAMENTATIONS") != 0 00200 || strstr(book_name, "ACTS OF") != 0 00201 || strstr(book_name, "REVELATION") != 0) 00202 { 00203 last_word = book_name; 00204 if (strncmp(last_word, "THE ", 4) == 0) 00205 last_word += 4; 00206 char* next_word = strchr(last_word, ' '); 00207 if (next_word != 0) 00208 *next_word = 0; 00209 } 00210 if (strncmp(last_word, "THE ", 4) == 0) 00211 last_word += 4; 00212 if (*last_word == ' ') 00213 ++last_word; 00214 if (last_word[strlen(last_word)-1] < 'A' || last_word[strlen(last_word)-1] > 'Z') 00215 last_word[strlen(last_word)-1] = 0; 00216 char* new_name = new char[strlen(last_word)+((number==0)?1:3)]; 00217 if (number == 0) 00218 strcpy(new_name, last_word); 00219 else 00220 sprintf(new_name, "%d %s", number, last_word); 00221 delete [] book_name; 00222 book_name = new_name; 00223 } 00224 } 00225 00226 bool BibleIO::read_chapter(short book, short chapter) 00227 { 00228 char* line = 0; 00229 long offset; 00230 do 00231 { 00232 delete [] line; 00233 offset = ftell(fp); 00234 line = BibleIO::read_line(); 00235 } while (line != 0 && (*line == 0 || strstr(line, "CALLED,") != 0 || line[0]=='#')); 00236 00237 if (line != 0 && strcmp(line, "THE END OF THE OLD TESTAMENT")==0) 00238 { 00239 do 00240 { 00241 delete [] line; 00242 offset = ftell(fp); 00243 line = BibleIO::read_line(); 00244 } while (line != 0 && strstr(line, "MATTHEW")==0); 00245 } 00246 00247 if (line == 0 || (strncmp(line, "CHAPTER ", 8) != 0 && strncmp(line, "PSALM ", 6) != 0) 00248 || (line[0] == 'P' && atoi(line+6) != chapter+1) 00249 || (line[0] == 'C' && atoi(line+8) != chapter+1)) 00250 { 00251 delete [] line; 00252 fseek(fp, offset, SEEK_SET); 00253 return false; 00254 } 00255 00256 delete [] line; 00257 00258 char* path = index_path(book); 00259 mkdir(path, 0666); 00260 delete [] path; 00261 path = 0; 00262 00263 char* fn = index_path(book, chapter); 00264 FILE* index = fopen(fn, "wb"); 00265 //console.printf("index file pointer=%08lx\n", (long)index); 00266 delete [] fn; 00267 fn = 0; 00268 00269 // chapter name 00270 fwrite(&offset, sizeof(offset), 1, index); 00271 00272 //console.printf("Chapter %d\n", chapter+1); 00273 00274 // support Psalms optional description of chapter 00275 long desc_offset = ftell(fp); 00276 char* chapter_desc = BibleIO::read_line(); 00277 if (chapter_desc == 0 || (chapter_desc[0] >= '0' && chapter_desc[0] <= '9')) 00278 { 00279 delete [] chapter_desc; 00280 chapter_desc = 0; 00281 fseek(fp, desc_offset, SEEK_SET); 00282 } 00283 delete [] chapter_desc; // not currently used 00284 00285 short verse = 0; 00286 while (read_verse(index, book, chapter, verse)) 00287 ++verse; 00288 00289 //console.printf("\n"); 00290 //console.printf("%hd verses\n", verse); 00291 00292 fclose(index); 00293 00294 return true; 00295 } 00296 00297 char* BibleIO::read_line() 00298 { 00299 char* line; 00300 const int size = 4096; 00301 line = new char[size]; 00302 fgets(line, size, fp); 00303 00304 // remove CR/LF 00305 while (strlen(line)>0 && (line[strlen(line)-1] == 0x0a || line[strlen(line)-1] == 0x0d)) 00306 line[strlen(line)-1] = 0; 00307 00308 // resize line to actual size 00309 char* new_line = new char[strlen(line)+1]; 00310 strcpy(new_line, line); 00311 delete [] line; 00312 line = 0; 00313 00314 //console.printf("%s\n", new_line); 00315 00316 return new_line; 00317 } 00318 00319 bool BibleIO::load_index() 00320 { 00321 char* fn = index_path("books"); 00322 FILE* index = fopen(fn, "r"); 00323 delete [] fn; 00324 fn = 0; 00325 00326 if (index == 0) 00327 return false; 00328 00329 fseek(index, 0, SEEK_END); 00330 long filesize = ftell(index); 00331 num_books = (filesize - sizeof(long)) / sizeof(book_index); 00332 delete [] books; 00333 books = (bible_index*)new char[filesize]; 00334 fseek(index, 0, SEEK_SET); 00335 00336 fread(books, filesize, 1, index); 00337 00338 long save_offset = ftell(fp); 00339 fseek(fp, books->title_offset, SEEK_SET); 00340 delete [] name; 00341 name = read_line(); 00342 fseek(fp, save_offset, SEEK_SET); 00343 00344 fclose(index); 00345 return true; 00346 } 00347 00348 short BibleIO::get_num_books() 00349 { 00350 return num_books; 00351 } 00352 00353 short BibleIO::get_num_chapters(short book) 00354 { 00355 return books->books[book].num_chapters; 00356 } 00357 00358 short BibleIO::get_num_verses(short book, short chapter) 00359 { 00360 char* fn = index_path(book, chapter); 00361 FILE* index = fopen(fn, "r"); 00362 delete [] fn; 00363 fn = 0; 00364 00365 fseek(index, 0, SEEK_END); 00366 long filesize = ftell(index); 00367 short num_verses = (filesize - sizeof(long)) / sizeof(chapter_index); 00368 fclose(index); 00369 return num_verses; 00370 } 00371 00372 char* BibleIO::title() 00373 { 00374 char *t = new char[strlen(name)+1]; 00375 strcpy(t, name); 00376 return t; 00377 } 00378 00379 char* BibleIO::title_book(short book) 00380 { 00381 if (book < 0 || book > num_books) 00382 return 0; 00383 00384 long offset = ftell(fp); 00385 long title_offset = books->books[book].title_offset; 00386 fseek(fp, title_offset, SEEK_SET); 00387 char* title = read_line(); 00388 fseek(fp, offset, SEEK_SET); 00389 format_book_name(title); 00390 return title; 00391 } 00392 00393 char* BibleIO::title_chapter(short book, short chapter) 00394 { 00395 char* fn = index_path(book, chapter); 00396 FILE* index = fopen(fn, "r"); 00397 delete [] fn; 00398 fn = 0; 00399 00400 long title_offset; 00401 fread(&title_offset, sizeof(title_offset), 1, index); 00402 fclose(index); 00403 00404 long offset = ftell(fp); 00405 fseek(fp, title_offset, SEEK_SET); 00406 char* title = read_line(); 00407 fseek(fp, offset, SEEK_SET); 00408 00409 return title; 00410 } 00411 00412 char* BibleIO::text_chapter(short book, short chapter) 00413 { 00414 if (book < 0 || book > num_books) 00415 return 0; 00416 00417 char* fn = index_path(book, chapter); 00418 FILE* index = fopen(fn, "r"); 00419 delete [] fn; 00420 fn = 0; 00421 00422 if (index == 0) 00423 return 0; 00424 00425 long title_offset; 00426 fread(&title_offset, sizeof(title_offset), 1, index); 00427 fseek(index, 0, SEEK_END); 00428 long filesize = ftell(index); 00429 short num_verses = (filesize - sizeof(long)) / sizeof(chapter_index); 00430 fseek(index, sizeof(long) + (num_verses-1)*sizeof(long), SEEK_SET); 00431 long verse_offset = -1; 00432 fread(&verse_offset, sizeof(verse_offset), 1, index); 00433 fclose(index); 00434 00435 long offset = ftell(fp); 00436 fseek(fp, verse_offset, SEEK_SET); 00437 char* last_verse = read_line(); 00438 delete [] last_verse; 00439 verse_offset = ftell(fp); 00440 fseek(fp, title_offset, SEEK_SET); 00441 int size = verse_offset-title_offset+1; 00442 char* text = new char[size]; 00443 fread(text, size-1, 1, fp); 00444 text[size-1] = 0; 00445 fseek(fp, offset, SEEK_SET); 00446 00447 return text; 00448 } 00449 00450 char* BibleIO::text_verse(short book, short chapter, short verse) 00451 { 00452 //console.printf("text_verse: book %hd, chapter %hd, verse %hd\n", book, chapter, verse); 00453 if (book > num_books) 00454 return 0; 00455 00456 char* fn = index_path(book, chapter); 00457 FILE* index = fopen(fn, "r"); 00458 delete [] fn; 00459 fn = 0; 00460 00461 if (index == 0) 00462 return 0; 00463 00464 fseek(index, 0, SEEK_END); 00465 long filesize = ftell(index); 00466 short num_verses = (filesize - sizeof(long)) / sizeof(chapter_index); 00467 if (verse >= num_verses || verse < 0) 00468 { 00469 fclose(index); 00470 return 0; 00471 } 00472 fseek(index, sizeof(long) + verse*sizeof(long), SEEK_SET); 00473 long verse_offset = -1; 00474 fread(&verse_offset, sizeof(verse_offset), 1, index); 00475 fclose(index); 00476 00477 long offset = ftell(fp); 00478 fseek(fp, verse_offset, SEEK_SET); 00479 char* text = read_line(); 00480 fseek(fp, offset, SEEK_SET); 00481 00482 //console.printf("text: %s\n", text); 00483 return text; 00484 } 00485 00486 bool BibleIO::read_verse(FILE* index, short book, short chapter, short verse) 00487 { 00488 long offset = ftell(fp); 00489 char* line = 0; 00490 00491 do 00492 { 00493 delete [] line; 00494 line = BibleIO::read_line(); 00495 } while (line != 0 && (*line == 0 || line[0] >= 'A' && line[0] <= 'Z' && line[strlen(line)-1] == '.')); 00496 00497 if (line == 0 || *line == 0 || atoi(line) == 0) 00498 { 00499 delete [] line; 00500 fseek(fp, offset, SEEK_SET); 00501 return false; 00502 } 00503 00504 short verse_num = atoi(line); 00505 delete [] line; 00506 00507 // !!! NOTE: this test fails at Philemon 1:2 because verses 1 & 2 are on the same line, for now ignore this test. Workaround is to edit text file to avoid error. 00508 // if (verse+1 != verse_num) 00509 // return false; 00510 00511 //console.printf("%d ", verse_num); 00512 00513 fwrite(&offset, sizeof(offset), 1, index); 00514 00515 return true; 00516 } 00517 00518 bool BibleIO::load_bookmarks() 00519 { 00520 delete [] bookmarks; 00521 bookmarks = 0; 00522 num_bookmarks = 0; 00523 00524 char* fn = index_path("marks"); 00525 FILE* index = fopen(fn, "r"); 00526 delete [] fn; 00527 fn = 0; 00528 00529 if (index == 0) 00530 return true; // okay it is not present yet, empty 00531 00532 fseek(index, 0, SEEK_END); 00533 long filesize = ftell(index); 00534 num_bookmarks = filesize / sizeof(position); 00535 fseek(index, 0, SEEK_SET); 00536 bookmarks = new position[num_bookmarks]; 00537 fread(bookmarks, sizeof(position), num_bookmarks, index); 00538 fclose(index); 00539 00540 return true; 00541 } 00542 00543 bool BibleIO::save_bookmarks() 00544 { 00545 char* fn = index_path("marks"); 00546 remove(fn); 00547 FILE* index = fopen(fn, "w"); 00548 delete [] fn; 00549 fn = 0; 00550 00551 if (index == 0) 00552 return false; 00553 00554 fwrite(bookmarks, sizeof(position), num_bookmarks, index); 00555 fclose(index); 00556 00557 return true; 00558 } 00559 00560 bool BibleIO::bookmark_add(short book, short chapter, short verse) 00561 { 00562 int i; 00563 for (i=0; i<num_bookmarks; ++i) 00564 { 00565 if (bookmarks[i].book == book && bookmarks[i].chapter == chapter && bookmarks[i].verse == verse) 00566 { 00567 return false; // already present 00568 } 00569 } 00570 00571 // resize list 00572 position* new_bookmarks = new position[num_bookmarks+1]; 00573 for (i=0; i<num_bookmarks; ++i) 00574 new_bookmarks[i] = bookmarks[i]; 00575 new_bookmarks[i].book = book; 00576 new_bookmarks[i].chapter = chapter; 00577 new_bookmarks[i].verse = verse; 00578 new_bookmarks[i].rsvd = 0; 00579 delete [] bookmarks; 00580 bookmarks = new_bookmarks; 00581 ++num_bookmarks; 00582 00583 return save_bookmarks(); 00584 } 00585 00586 bool BibleIO::bookmark_del(short book, short chapter, short verse) 00587 { 00588 // search for bookmark 00589 int i; 00590 for (i=0; i<num_bookmarks; ++i) 00591 if (bookmarks[i].book == book && bookmarks[i].chapter == chapter && bookmarks[i].verse == verse) 00592 break; 00593 if (i>=num_bookmarks) 00594 return false; // not found 00595 00596 // move previous entries down 00597 for (int j=i+1; j<num_bookmarks; ++j) 00598 bookmarks[j-1] = bookmarks[j]; 00599 00600 --num_bookmarks; 00601 00602 // rewrite to filesystem 00603 return save_bookmarks(); 00604 } 00605 00606 bool BibleIO::bookmark_prev(short &book, short &chapter, short &verse) 00607 { 00608 // search for bookmark 00609 int i; 00610 for (i=0; i<num_bookmarks; ++i) 00611 if (bookmarks[i].book == book && bookmarks[i].chapter == chapter && bookmarks[i].verse == verse) 00612 break; 00613 if (i==0) 00614 i=num_bookmarks; // wrap around 00615 00616 // previous 00617 --i; 00618 00619 if (i < 0 || i >= num_bookmarks) 00620 return false; 00621 00622 book = bookmarks[i].book; 00623 chapter = bookmarks[i].chapter; 00624 verse = bookmarks[i].verse; 00625 00626 return true; 00627 } 00628 00629 bool BibleIO::bookmark_next(short &book, short &chapter, short &verse) 00630 { 00631 // search for bookmark 00632 int i; 00633 for (i=0; i<num_bookmarks; ++i) 00634 if (bookmarks[i].book == book && bookmarks[i].chapter == chapter && bookmarks[i].verse == verse) 00635 break; 00636 // next 00637 if (++i >= num_bookmarks) 00638 i = 0; 00639 00640 if (i < 0 || i >= num_bookmarks) 00641 return false; 00642 00643 book = bookmarks[i].book; 00644 chapter = bookmarks[i].chapter; 00645 verse = bookmarks[i].verse; 00646 00647 return true; 00648 } 00649 00650 char* BibleIO::index_path() 00651 { 00652 char* path = index_path(""); 00653 path[strlen(path)-1] = 0; // remove trailing slash 00654 return path; 00655 } 00656 00657 char* BibleIO::index_path(char* name) 00658 { 00659 int base_len = strrchr(text_filename, '/') + 1 - text_filename; 00660 int index_len = base_len + strlen("index/") + strlen(name); 00661 char* index = new char[index_len+1]; 00662 memcpy(index, text_filename, base_len); 00663 index[base_len] = 0; 00664 strcat(index, "index/"); 00665 strcat(index, name); 00666 return index; 00667 } 00668 00669 char* BibleIO::index_path(short book) 00670 { 00671 char indexname[50]; 00672 sprintf(indexname, "%hd", book); 00673 return index_path(indexname); 00674 } 00675 00676 char* BibleIO::index_path(short book, short chapter) 00677 { 00678 char indexname[50]; 00679 sprintf(indexname, "%hd/%hd", book, chapter); 00680 return index_path(indexname); 00681 }
Generated on Sun Jul 24 2022 02:23:45 by
1.7.2